diff options
Diffstat (limited to 'src/plugins/platforms/cocoa/qcocoaintegration.mm')
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoaintegration.mm | 254 |
1 files changed, 89 insertions, 165 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index b2698b05fe..2ce39ff897 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -1,41 +1,7 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include <AppKit/AppKit.h> #include "qcocoaintegration.h" @@ -55,31 +21,28 @@ #if QT_CONFIG(sessionmanager) # include "qcocoasessionmanager.h" #endif +#include "qcocoawindowmanager.h" #include <qpa/qplatforminputcontextfactory_p.h> #include <qpa/qplatformaccessibility.h> #include <qpa/qplatforminputcontextfactory_p.h> #include <qpa/qplatformoffscreensurface.h> #include <QtCore/qcoreapplication.h> +#include <QtGui/qpointingdevice.h> -#include <QtPlatformHeaders/qcocoanativecontext.h> - +#include <QtCore/private/qcore_mac_p.h> #include <QtGui/private/qcoregraphics_p.h> - -#include <QtFontDatabaseSupport/private/qfontengine_coretext_p.h> - -#if QT_CONFIG(opengl) -#include <QtPlatformCompositorSupport/qpa/qplatformbackingstoreopenglsupport.h> -#endif - -#ifdef QT_WIDGETS_LIB -#include <QtWidgets/qtwidgetsglobal.h> -#if QT_CONFIG(filedialog) -#include "qcocoafiledialoghelper.h" -#endif +#include <QtGui/private/qmacmimeregistry_p.h> +#ifndef QT_NO_OPENGL +# include <QtGui/private/qopenglcontext_p.h> #endif +#include <QtGui/private/qrhibackingstore_p.h> +#include <QtGui/private/qfontengine_coretext_p.h> #include <IOKit/graphics/IOGraphicsLib.h> +#include <UniformTypeIdentifiers/UTCoreTypes.h> + +#include <inttypes.h> static void initResources() { @@ -88,6 +51,8 @@ static void initResources() QT_BEGIN_NAMESPACE +using namespace Qt::StringLiterals; + Q_LOGGING_CATEGORY(lcQpa, "qt.qpa", QtWarningMsg); static void logVersionInformation() @@ -120,9 +85,9 @@ class QFontEngineFT; static QCocoaIntegration::Options parseOptions(const QStringList ¶mList) { QCocoaIntegration::Options options; - foreach (const QString ¶m, paramList) { + for (const QString ¶m : paramList) { #ifndef QT_NO_FREETYPE - if (param == QLatin1String("fontengine=freetype")) + if (param == "fontengine=freetype"_L1) options |= QCocoaIntegration::UseFreeTypeFontEngine; else #endif @@ -136,7 +101,7 @@ QCocoaIntegration *QCocoaIntegration::mInstance = nullptr; QCocoaIntegration::QCocoaIntegration(const QStringList ¶mList) : mOptions(parseOptions(paramList)) , mFontDb(nullptr) -#ifndef QT_NO_ACCESSIBILITY +#if QT_CONFIG(accessibility) , mAccessibility(new QCocoaAccessibility) #endif #ifndef QT_NO_CLIPBOARD @@ -145,7 +110,7 @@ QCocoaIntegration::QCocoaIntegration(const QStringList ¶mList) , mCocoaDrag(new QCocoaDrag) , mNativeInterface(new QCocoaNativeInterface) , mServices(new QCocoaServices) - , mKeyboardMapper(new QCocoaKeyMapper) + , mKeyboardMapper(new QAppleKeyMapper) { logVersionInformation(); @@ -160,9 +125,9 @@ QCocoaIntegration::QCocoaIntegration(const QStringList ¶mList) #endif mFontDb.reset(new QCoreTextFontDatabaseEngineFactory<QCoreTextFontEngine>); - QString icStr = QPlatformInputContextFactory::requested(); - icStr.isNull() ? mInputContext.reset(new QCocoaInputContext) - : mInputContext.reset(QPlatformInputContextFactory::create(icStr)); + auto icStrs = QPlatformInputContextFactory::requested(); + icStrs.isEmpty() ? mInputContext.reset(new QCocoaInputContext) + : mInputContext.reset(QPlatformInputContextFactory::create(icStrs)); initResources(); QMacAutoReleasePool pool; @@ -172,24 +137,13 @@ QCocoaIntegration::QCocoaIntegration(const QStringList ¶mList) if (qEnvironmentVariableIsEmpty("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM")) { // Applications launched from plain executables (without an app - // bundle) are "background" applications that does not take keybaord + // bundle) are "background" applications that does not take keyboard // focus or have a dock icon or task switcher entry. Qt Gui apps generally // wants to be foreground applications so change the process type. (But // see the function implementation for exceptions.) qt_mac_transformProccessToForegroundApplication(); - - // Move the application window to front to make it take focus, also when launching - // from the terminal. On 10.12+ this call has been moved to applicationDidFinishLauching - // to work around issues with loss of focus at startup. - if (QOperatingSystemVersion::current() < QOperatingSystemVersion::MacOSSierra) { - // Ignoring other apps is necessary (we must ignore the terminal), but makes - // Qt apps play slightly less nice with other apps when lanching from Finder - // (See the activateIgnoringOtherApps docs.) - [cocoaApplication activateIgnoringOtherApps : YES]; - } } - // ### For AA_MacPluginApplication we don't want to load the menu nib. // Qt 4 also does not set the application delegate, so that behavior // is matched here. if (!QCoreApplication::testAttribute(Qt::AA_PluginApplication)) { @@ -206,9 +160,11 @@ QCocoaIntegration::QCocoaIntegration(const QStringList ¶mList) QCocoaScreen::initializeScreens(); - QMacInternalPasteboardMime::initializeMimeTypes(); + QMacMimeRegistry::initializeMimeTypes(); QCocoaMimeTypes::initializeMimeTypes(); QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false); + QWindowSystemInterface::registerInputDevice(new QInputDevice(QString("keyboard"), 0, + QInputDevice::DeviceType::Keyboard, QString(), this)); connect(qGuiApp, &QGuiApplication::focusWindowChanged, this, &QCocoaIntegration::focusWindowChanged); @@ -229,17 +185,18 @@ QCocoaIntegration::~QCocoaIntegration() [[NSApplication sharedApplication] setDelegate:nil]; } + // Stop global mouse event and app activation monitoring + QCocoaWindow::removePopupMonitor(); + #ifndef QT_NO_CLIPBOARD // Delete the clipboard integration and destroy mime type converters. // Deleting the clipboard integration flushes promised pastes using // the mime converters - the ordering here is important. delete mCocoaClipboard; - QMacInternalPasteboardMime::destroyMimeTypes(); + QMacMimeRegistry::destroyMimeTypes(); #endif QCocoaScreen::cleanupScreens(); - - clearToolbars(); } QCocoaIntegration *QCocoaIntegration::instance() @@ -267,8 +224,8 @@ bool QCocoaIntegration::hasCapability(QPlatformIntegration::Capability cap) cons // AppKit expects rendering to happen on the main thread, and we can // easily end up in situations where rendering on secondary threads // will result in visual artifacts, bugs, or even deadlocks, when - // building with SDK 10.14 or higher which enbles view layer-backing. - return QMacVersion::buildSDK() < QOperatingSystemVersion(QOperatingSystemVersion::MacOSMojave); + // layer-backed. + return false; case OpenGL: case BufferQueueingOpenGL: #endif @@ -279,6 +236,7 @@ bool QCocoaIntegration::hasCapability(QPlatformIntegration::Capability cap) cons case RasterGLSurface: case ApplicationState: case ApplicationIcon: + case BackingStoreStaticContents: return true; default: return QPlatformIntegration::hasCapability(cap); @@ -318,6 +276,19 @@ QPlatformOpenGLContext *QCocoaIntegration::createPlatformOpenGLContext(QOpenGLCo { return new QCocoaGLContext(context); } + +QOpenGLContext *QCocoaIntegration::createOpenGLContext(NSOpenGLContext *nativeContext, QOpenGLContext *shareContext) const +{ + if (!nativeContext) + return nullptr; + + auto *context = new QOpenGLContext; + context->setShareContext(shareContext); + auto *contextPrivate = QOpenGLContextPrivate::get(context); + contextPrivate->adopt(new QCocoaGLContext(nativeContext)); + return context; +} + #endif QPlatformBackingStore *QCocoaIntegration::createPlatformBackingStore(QWindow *window) const @@ -328,16 +299,27 @@ QPlatformBackingStore *QCocoaIntegration::createPlatformBackingStore(QWindow *wi return nullptr; } - QPlatformBackingStore *backingStore = nullptr; - if (platformWindow->view().layer) - backingStore = new QCALayerBackingStore(window); - else - backingStore = new QNSWindowBackingStore(window); - -#if QT_CONFIG(opengl) - backingStore->setOpenGLSupport(new QPlatformBackingStoreOpenGLSupport(backingStore)); -#endif - return backingStore; + switch (window->surfaceType()) { + case QSurface::RasterSurface: + return new QCALayerBackingStore(window); + case QSurface::MetalSurface: + case QSurface::OpenGLSurface: + case QSurface::VulkanSurface: + // If the window is a widget window, we know that the QWidgetRepaintManager + // will explicitly use rhiFlush() for the window owning the backingstore, + // and any child window with the same surface format. This means we can + // safely return a QCALayerBackingStore here, to ensure that any plain + // flush() for child windows that don't have a matching surface format + // will still work, by setting the layer's contents property. + if (window->inherits("QWidgetWindow")) + return new QCALayerBackingStore(window); + + // Otherwise we return a QRhiBackingStore, that implements flush() in + // terms of rhiFlush(). + return new QRhiBackingStore(window); + default: + return nullptr; + } } QAbstractEventDispatcher *QCocoaIntegration::createEventDispatcher() const @@ -373,7 +355,7 @@ QPlatformInputContext *QCocoaIntegration::inputContext() const return mInputContext.data(); } -#ifndef QT_NO_ACCESSIBILITY +#if QT_CONFIG(accessibility) QCocoaAccessibility *QCocoaIntegration::accessibility() const { return mAccessibility.data(); @@ -394,12 +376,12 @@ QCocoaDrag *QCocoaIntegration::drag() const QStringList QCocoaIntegration::themeNames() const { - return QStringList(QLatin1String(QCocoaTheme::name)); + return QStringList(QLatin1StringView(QCocoaTheme::name)); } QPlatformTheme *QCocoaIntegration::createPlatformTheme(const QString &name) const { - if (name == QLatin1String(QCocoaTheme::name)) + if (name == QLatin1StringView(QCocoaTheme::name)) return new QCocoaTheme; return QPlatformIntegration::createPlatformTheme(name); } @@ -416,80 +398,29 @@ QVariant QCocoaIntegration::styleHint(StyleHint hint) const return QCoreTextFontEngine::fontSmoothingGamma(); case ShowShortcutsInContextMenus: return QVariant(false); + case ReplayMousePressOutsidePopup: + return QVariant(false); default: break; } return QPlatformIntegration::styleHint(hint); } -Qt::KeyboardModifiers QCocoaIntegration::queryKeyboardModifiers() const +QPlatformKeyMapper *QCocoaIntegration::keyMapper() const { - return QCocoaKeyMapper::queryKeyboardModifiers(); + return mKeyboardMapper.data(); } -QList<int> QCocoaIntegration::possibleKeys(const QKeyEvent *event) const -{ - return mKeyboardMapper->possibleKeys(event); -} - -void QCocoaIntegration::setToolbar(QWindow *window, NSToolbar *toolbar) -{ - if (NSToolbar *prevToolbar = mToolbars.value(window)) - [prevToolbar release]; - - [toolbar retain]; - mToolbars.insert(window, toolbar); -} - -NSToolbar *QCocoaIntegration::toolbar(QWindow *window) const -{ - return mToolbars.value(window); -} - -void QCocoaIntegration::clearToolbars() -{ - QHash<QWindow *, NSToolbar *>::const_iterator it = mToolbars.constBegin(); - while (it != mToolbars.constEnd()) { - [it.value() release]; - ++it; - } - mToolbars.clear(); -} - -void QCocoaIntegration::pushPopupWindow(QCocoaWindow *window) -{ - m_popupWindowStack.append(window); -} - -QCocoaWindow *QCocoaIntegration::popPopupWindow() -{ - if (m_popupWindowStack.isEmpty()) - return nullptr; - return m_popupWindowStack.takeLast(); -} - -QCocoaWindow *QCocoaIntegration::activePopupWindow() const -{ - if (m_popupWindowStack.isEmpty()) - return nullptr; - return m_popupWindowStack.front(); -} - -QList<QCocoaWindow *> *QCocoaIntegration::popupWindowStack() +void QCocoaIntegration::setApplicationIcon(const QIcon &icon) const { - return &m_popupWindowStack; + // Fall back to a size that looks good on the highest resolution screen available + auto fallbackSize = NSApp.dockTile.size.width * qGuiApp->devicePixelRatio(); + NSApp.applicationIconImage = [NSImage imageFromQIcon:icon withSize:fallbackSize]; } -void QCocoaIntegration::setApplicationIcon(const QIcon &icon) const +void QCocoaIntegration::setApplicationBadge(qint64 number) { - NSImage *image = nil; - if (!icon.isNull()) { - NSSize size = [[[NSApplication sharedApplication] dockTile] size]; - QPixmap pixmap = icon.pixmap(size.width, size.height); - image = static_cast<NSImage *>(qt_mac_create_nsimage(pixmap)); - } - [[NSApplication sharedApplication] setApplicationIconImage:image]; - [image release]; + NSApp.dockTile.badgeLabel = number ? [NSString stringWithFormat:@"%" PRId64, number] : nil; } void QCocoaIntegration::beep() const @@ -497,17 +428,10 @@ void QCocoaIntegration::beep() const NSBeep(); } -void QCocoaIntegration::closePopups(QWindow *forWindow) +void QCocoaIntegration::quit() const { - for (auto it = m_popupWindowStack.begin(); it != m_popupWindowStack.end();) { - auto *popup = *it; - if (!forWindow || popup->window()->transientParent() == forWindow) { - it = m_popupWindowStack.erase(it); - QWindowSystemInterface::handleCloseEvent<QWindowSystemInterface::SynchronousDelivery>(popup->window()); - } else { - ++it; - } - } + qCDebug(lcQpaApplication) << "Terminating application"; + [NSApp terminate:nil]; } void QCocoaIntegration::focusWindowChanged(QWindow *focusWindow) @@ -517,8 +441,8 @@ void QCocoaIntegration::focusWindowChanged(QWindow *focusWindow) return; static bool hasDefaultApplicationIcon = [](){ - NSImage *genericApplicationIcon = [[NSWorkspace sharedWorkspace] - iconForFileType:NSFileTypeForHFSTypeCode(kGenericApplicationIcon)]; + NSImage *genericApplicationIcon = [NSWorkspace.sharedWorkspace + iconForContentType:UTTypeApplicationBundle]; NSImage *applicationIcon = [NSImage imageNamed:NSImageNameApplicationIcon]; NSRect rect = NSMakeRect(0, 0, 32, 32); @@ -537,6 +461,6 @@ void QCocoaIntegration::focusWindowChanged(QWindow *focusWindow) setApplicationIcon(focusWindow->icon()); } -#include "moc_qcocoaintegration.cpp" - QT_END_NAMESPACE + +#include "moc_qcocoaintegration.cpp" |