From bccbb52b7a96b3cba4dc5c9977792ed0223d5a83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Thu, 28 Sep 2017 15:46:45 +0200 Subject: [PATCH] macOS: Tighten up window icon and represented filename handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Window icons on macOS are tied to document windows, and should not show up unless a represented filename has also been set according to the HIG. We follow this, and no longer create a document button based on the window title if one did no exists. We also fall back to using the filename of the file if a title has not been set, including being able to restore this default title after setting a custom title. The icon is no longer reset to nil after setting a QIcon(), which would remove the icon completely, but instead we restore the default behavior of showing the default filetype icon of the file. Finally, the two callbacks in QNSWindowDelegate dealing with the document icon/title popups and drags have been taught to look for spaces in the represented filename. This allows clients who really want the old behavior of setting an icon without caring about the filename to set the filename to a single space character, which will prevent the dropdowna and drag from occurring. The reason for not tying this behavior to the existence of the file in the filesystem is that being able to represent a file that is yet to be saved is a valid usecase. Task-number: QTBUG-63338 Change-Id: I7d4377c6358226fb6058f8c2b3c28588eec77ce5 Reviewed-by: Morten Johan Sørvig --- src/gui/kernel/qwindow.cpp | 7 +++- src/plugins/platforms/cocoa/qcocoawindow.h | 2 - src/plugins/platforms/cocoa/qcocoawindow.mm | 37 +++++++++++-------- .../platforms/cocoa/qnswindowdelegate.mm | 12 +++++- 4 files changed, 38 insertions(+), 20 deletions(-) diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 6dbba8b433b..b4e2b47c039 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -971,6 +971,11 @@ QString QWindow::filePath() const The window icon might be used by the windowing system for example to decorate the window, and/or in the task switcher. + + \note On \macos, the window title bar icon is meant for windows representing + documents, and will only show up if a file path is also set. + + \sa setFilePath() */ void QWindow::setIcon(const QIcon &icon) { @@ -983,7 +988,7 @@ void QWindow::setIcon(const QIcon &icon) } /*! - \brief Sets the window's icon in the windowing system + \brief Returns the window's icon in the windowing system \sa setIcon() */ diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index a93a391358f..3230c321337 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -285,8 +285,6 @@ public: // for QNSView }; QHash m_contentBorderAreas; // identifer -> uppper/lower QHash m_enabledContentBorderAreas; // identifer -> enabled state (true/false) - - bool m_hasWindowFilePath; }; #ifndef QT_NO_DEBUG_STREAM diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 217bfb36029..8f5b419f2a6 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -157,7 +157,6 @@ QCocoaWindow::QCocoaWindow(QWindow *win, WId nativeHandle) , m_drawContentBorderGradient(false) , m_topContentBorderThickness(0) , m_bottomContentBorderThickness(0) - , m_hasWindowFilePath(false) { qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::QCocoaWindow" << window(); @@ -594,6 +593,11 @@ void QCocoaWindow::setWindowTitle(const QString &title) QMacAutoReleasePool pool; m_view.window.title = title.toNSString(); + + if (title.isEmpty() && !window()->filePath().isEmpty()) { + // Clearing the title should restore the default filename + setWindowFilePath(window()->filePath()); + } } void QCocoaWindow::setWindowFilePath(const QString &filePath) @@ -602,9 +606,14 @@ void QCocoaWindow::setWindowFilePath(const QString &filePath) return; QMacAutoReleasePool pool; - QFileInfo fi(filePath); - [m_view.window setRepresentedFilename:fi.exists() ? filePath.toNSString() : @""]; - m_hasWindowFilePath = fi.exists(); + + if (window()->title().isNull()) + [m_view.window setTitleWithRepresentedFilename:filePath.toNSString()]; + else + m_view.window.representedFilename = filePath.toNSString(); + + // Changing the file path may affect icon visibility + setWindowIcon(window()->icon()); } void QCocoaWindow::setWindowIcon(const QIcon &icon) @@ -612,23 +621,21 @@ void QCocoaWindow::setWindowIcon(const QIcon &icon) if (!isContentView()) return; + NSButton *iconButton = [m_view.window standardWindowButton:NSWindowDocumentIconButton]; + if (!iconButton) { + // Window icons are only supported on macOS in combination with a document filePath + return; + } + QMacAutoReleasePool pool; - NSButton *iconButton = [m_view.window standardWindowButton:NSWindowDocumentIconButton]; - if (iconButton == nil) { - if (icon.isNull()) - return; - NSString *title = window()->title().toNSString(); - [m_view.window setRepresentedURL:[NSURL fileURLWithPath:title]]; - iconButton = [m_view.window standardWindowButton:NSWindowDocumentIconButton]; - } if (icon.isNull()) { - [iconButton setImage:nil]; + NSWorkspace *workspace = [NSWorkspace sharedWorkspace]; + [iconButton setImage:[workspace iconForFile:m_view.window.representedFilename]]; } else { QPixmap pixmap = icon.pixmap(QSize(22, 22)); NSImage *image = static_cast(qt_mac_create_nsimage(pixmap)); - [iconButton setImage:image]; - [image release]; + [iconButton setImage:[image autorelease]]; } } diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.mm b/src/plugins/platforms/cocoa/qnswindowdelegate.mm index 1224d138d9e..cdecd86dfb2 100644 --- a/src/plugins/platforms/cocoa/qnswindowdelegate.mm +++ b/src/plugins/platforms/cocoa/qnswindowdelegate.mm @@ -44,6 +44,8 @@ #include #include +static QRegExp whitespaceRegex = QRegExp(QStringLiteral("\\s*")); + @implementation QNSWindowDelegate - (id)initWithQCocoaWindow:(QCocoaWindow *)cocoaWindow @@ -98,7 +100,10 @@ { Q_UNUSED(window); Q_UNUSED(menu); - return m_cocoaWindow && m_cocoaWindow->m_hasWindowFilePath; + + // Only pop up document path if the filename is non-empty. We allow whitespace, to + // allow faking a window icon by setting the file path to a single space character. + return !whitespaceRegex.exactMatch(m_cocoaWindow->window()->filePath()); } - (BOOL)window:(NSWindow *)window shouldDragDocumentWithEvent:(NSEvent *)event from:(NSPoint)dragImageLocation withPasteboard:(NSPasteboard *)pasteboard @@ -107,6 +112,9 @@ Q_UNUSED(event); Q_UNUSED(dragImageLocation); Q_UNUSED(pasteboard); - return m_cocoaWindow && m_cocoaWindow->m_hasWindowFilePath; + + // Only allow drag if the filename is non-empty. We allow whitespace, to + // allow faking a window icon by setting the file path to a single space. + return !whitespaceRegex.exactMatch(m_cocoaWindow->window()->filePath()); } @end