Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qcocoaintegration.mm
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <AppKit/AppKit.h>
5
6#include "qcocoaintegration.h"
7
8#include "qcocoawindow.h"
11#include "qcocoamenuloader.h"
13#include "qcocoahelpers.h"
14#include "qcocoaapplication.h"
16#include "qcocoatheme.h"
17#include "qcocoainputcontext.h"
18#include "qcocoamimetypes.h"
19#include "qcocoaaccessibility.h"
20#include "qcocoascreen.h"
21#if QT_CONFIG(sessionmanager)
22# include "qcocoasessionmanager.h"
23#endif
24#include "qcocoawindowmanager.h"
25
26#include <qpa/qplatforminputcontextfactory_p.h>
27#include <qpa/qplatformaccessibility.h>
28#include <qpa/qplatforminputcontextfactory_p.h>
29#include <qpa/qplatformoffscreensurface.h>
30#include <QtCore/qcoreapplication.h>
31#include <QtGui/qpointingdevice.h>
32
33#include <QtCore/private/qcore_mac_p.h>
34#include <QtGui/private/qcoregraphics_p.h>
35#include <QtGui/private/qmacmimeregistry_p.h>
36#ifndef QT_NO_OPENGL
37# include <QtGui/private/qopenglcontext_p.h>
38#endif
39#include <QtGui/private/qrhibackingstore_p.h>
40#include <QtGui/private/qfontengine_coretext_p.h>
41
42#include <IOKit/graphics/IOGraphicsLib.h>
43#include <UniformTypeIdentifiers/UTCoreTypes.h>
44
45#include <inttypes.h>
46
47static void initResources()
48{
49 Q_INIT_RESOURCE(qcocoaresources);
50}
51
53
54using namespace Qt::StringLiterals;
55
57
59{
60 if (!lcQpa().isInfoEnabled())
61 return;
62
63 auto osVersion = QMacVersion::currentRuntime();
68
69 qCInfo(lcQpa, "Loading macOS (Cocoa) platform plugin for Qt " QT_VERSION_STR ", running on macOS %d.%d.%d\n\n" \
70 " Component SDK version Deployment target \n" \
71 " ------------- ------------- -------------------\n" \
72 " Qt " QT_VERSION_STR " %d.%d.%d %d.%d.%d\n" \
73 " Application %d.%d.%d %d.%d.%d\n",
74 osVersion.majorVersion(), osVersion.minorVersion(), osVersion.microVersion(),
75 qtBuildSDK.majorVersion(), qtBuildSDK.minorVersion(), qtBuildSDK.microVersion(),
76 qtDeploymentTarget.majorVersion(), qtDeploymentTarget.minorVersion(), qtDeploymentTarget.microVersion(),
77 appBuildSDK.majorVersion(), appBuildSDK.minorVersion(), appBuildSDK.microVersion(),
78 appDeploymentTarget.majorVersion(), appDeploymentTarget.minorVersion(), appDeploymentTarget.microVersion());
79}
80
81
83class QFontEngineFT;
84
85static QCocoaIntegration::Options parseOptions(const QStringList &paramList)
86{
87 QCocoaIntegration::Options options;
88 for (const QString &param : paramList) {
89#ifndef QT_NO_FREETYPE
90 if (param == "fontengine=freetype"_L1)
92 else
93#endif
94 qWarning() << "Unknown option" << param;
95 }
96 return options;
97}
98
99QCocoaIntegration *QCocoaIntegration::mInstance = nullptr;
100
102 : mOptions(parseOptions(paramList))
103 , mFontDb(nullptr)
104#if QT_CONFIG(accessibility)
105 , mAccessibility(new QCocoaAccessibility)
106#endif
107#ifndef QT_NO_CLIPBOARD
108 , mCocoaClipboard(new QCocoaClipboard)
109#endif
110 , mCocoaDrag(new QCocoaDrag)
111 , mNativeInterface(new QCocoaNativeInterface)
112 , mServices(new QCocoaServices)
113 , mKeyboardMapper(new QAppleKeyMapper)
114{
116
117 if (mInstance)
118 qWarning("Creating multiple Cocoa platform integrations is not supported");
119 mInstance = this;
120
121#ifndef QT_NO_FREETYPE
122 if (mOptions.testFlag(UseFreeTypeFontEngine))
123 mFontDb.reset(new QCoreTextFontDatabaseEngineFactory<QFontEngineFT>);
124 else
125#endif
126 mFontDb.reset(new QCoreTextFontDatabaseEngineFactory<QCoreTextFontEngine>);
127
129 icStrs.isEmpty() ? mInputContext.reset(new QCocoaInputContext)
130 : mInputContext.reset(QPlatformInputContextFactory::create(icStrs));
131
134
135 NSApplication *cocoaApplication = [QNSApplication sharedApplication];
137
138 if (qEnvironmentVariableIsEmpty("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM")) {
139 // Applications launched from plain executables (without an app
140 // bundle) are "background" applications that does not take keyboard
141 // focus or have a dock icon or task switcher entry. Qt Gui apps generally
142 // wants to be foreground applications so change the process type. (But
143 // see the function implementation for exceptions.)
145 }
146
147 // Qt 4 also does not set the application delegate, so that behavior
148 // is matched here.
150
151 // Set app delegate, link to the current delegate (if any)
152 QCocoaApplicationDelegate *newDelegate = [QCocoaApplicationDelegate sharedDelegate];
153 [newDelegate setReflectionDelegate:[cocoaApplication delegate]];
154 [cocoaApplication setDelegate:newDelegate];
155
156 // Load the application menu. This menu contains Preferences, Hide, Quit.
157 QCocoaMenuLoader *qtMenuLoader = [QCocoaMenuLoader sharedMenuLoader];
158 [cocoaApplication setMenu:[qtMenuLoader menu]];
159 }
160
161 QCocoaScreen::initializeScreens();
162
168
170 this, &QCocoaIntegration::focusWindowChanged);
171}
172
174{
175 mInstance = nullptr;
176
178
181 // remove the apple event handlers installed by QCocoaApplicationDelegate
182 QCocoaApplicationDelegate *delegate = [QCocoaApplicationDelegate sharedDelegate];
183 [delegate removeAppleEventHandlers];
184 // reset the application delegate
185 [[NSApplication sharedApplication] setDelegate:nil];
186 }
187
188 // Stop global mouse event and app activation monitoring
190
191#ifndef QT_NO_CLIPBOARD
192 // Delete the clipboard integration and destroy mime type converters.
193 // Deleting the clipboard integration flushes promised pastes using
194 // the mime converters - the ordering here is important.
195 delete mCocoaClipboard;
197#endif
198
199 QCocoaScreen::cleanupScreens();
200}
201
203{
204 return mInstance;
205}
206
207QCocoaIntegration::Options QCocoaIntegration::options() const
208{
209 return mOptions;
210}
211
212#if QT_CONFIG(sessionmanager)
214{
215 return new QCocoaSessionManager(id, key);
216}
217#endif
218
220{
221 switch (cap) {
222#ifndef QT_NO_OPENGL
223 case ThreadedOpenGL:
224 // AppKit expects rendering to happen on the main thread, and we can
225 // easily end up in situations where rendering on secondary threads
226 // will result in visual artifacts, bugs, or even deadlocks, when
227 // layer-backed.
228 return false;
229 case OpenGL:
231#endif
232 case ThreadedPixmaps:
233 case WindowMasks:
234 case MultipleWindows:
235 case ForeignWindows:
236 case RasterGLSurface:
237 case ApplicationState:
238 case ApplicationIcon:
240 return true;
241 default:
243 }
244}
245
250
252{
253 return new QCocoaWindow(window, nativeHandle);
254}
255
268
273
274#ifndef QT_NO_OPENGL
279
280QOpenGLContext *QCocoaIntegration::createOpenGLContext(NSOpenGLContext *nativeContext, QOpenGLContext *shareContext) const
281{
282 if (!nativeContext)
283 return nullptr;
284
285 auto *context = new QOpenGLContext;
286 context->setShareContext(shareContext);
287 auto *contextPrivate = QOpenGLContextPrivate::get(context);
288 contextPrivate->adopt(new QCocoaGLContext(nativeContext));
289 return context;
290}
291
292#endif
293
295{
296 QCocoaWindow *platformWindow = static_cast<QCocoaWindow*>(window->handle());
297 if (!platformWindow) {
298 qWarning() << window << "must be created before being used with a backingstore";
299 return nullptr;
300 }
301
302 switch (window->surfaceType()) {
304 return new QCALayerBackingStore(window);
308 // If the window is a widget window, we know that the QWidgetRepaintManager
309 // will explicitly use rhiFlush() for the window owning the backingstore,
310 // and any child window with the same surface format. This means we can
311 // safely return a QCALayerBackingStore here, to ensure that any plain
312 // flush() for child windows that don't have a matching surface format
313 // will still work, by setting the layer's contents property.
314 if (window->inherits("QWidgetWindow"))
315 return new QCALayerBackingStore(window);
316
317 // Otherwise we return a QRhiBackingStore, that implements flush() in
318 // terms of rhiFlush().
319 return new QRhiBackingStore(window);
320 default:
321 return nullptr;
322 }
323}
324
329
330#if QT_CONFIG(vulkan)
331QPlatformVulkanInstance *QCocoaIntegration::createPlatformVulkanInstance(QVulkanInstance *instance) const
332{
333 mCocoaVulkanInstance = new QCocoaVulkanInstance(instance);
334 return mCocoaVulkanInstance;
335}
336
337QCocoaVulkanInstance *QCocoaIntegration::getCocoaVulkanInstance() const
338{
339 return mCocoaVulkanInstance;
340}
341#endif
342
344{
345 return mFontDb.data();
346}
347
349{
350 return mNativeInterface.data();
351}
352
354{
355 return mInputContext.data();
356}
357
358#if QT_CONFIG(accessibility)
359QCocoaAccessibility *QCocoaIntegration::accessibility() const
360{
361 return mAccessibility.data();
362}
363#endif
364
365#ifndef QT_NO_CLIPBOARD
367{
368 return mCocoaClipboard;
369}
370#endif
371
373{
374 return mCocoaDrag.data();
375}
376
381
388
390{
391 return mServices.data();
392}
393
395{
396 switch (hint) {
400 return QVariant(false);
402 return QVariant(false);
403 default: break;
404 }
405
407}
408
410{
411 return mKeyboardMapper.data();
412}
413
415{
416 // Fall back to a size that looks good on the highest resolution screen available
417 auto fallbackSize = NSApp.dockTile.size.width * qGuiApp->devicePixelRatio();
418 NSApp.applicationIconImage = [NSImage imageFromQIcon:icon withSize:fallbackSize];
419}
420
422{
423 NSApp.dockTile.badgeLabel = number ? [NSString stringWithFormat:@"%" PRId64, number] : nil;
424}
425
427{
428 NSBeep();
429}
430
432{
433 qCDebug(lcQpaApplication) << "Terminating application";
434 [NSApp terminate:nil];
435}
436
437void QCocoaIntegration::focusWindowChanged(QWindow *focusWindow)
438{
439 // Don't revert icon just because we lost focus
440 if (!focusWindow)
441 return;
442
443 static bool hasDefaultApplicationIcon = [](){
444 NSImage *genericApplicationIcon = [NSWorkspace.sharedWorkspace
445 iconForContentType:UTTypeApplicationBundle];
446 NSImage *applicationIcon = [NSImage imageNamed:NSImageNameApplicationIcon];
447
448 NSRect rect = NSMakeRect(0, 0, 32, 32);
449 return [applicationIcon CGImageForProposedRect:&rect context:nil hints:nil]
450 == [genericApplicationIcon CGImageForProposedRect:&rect context:nil hints:nil];
451 }();
452
453 // Don't let the window icon override an explicit application icon set in the Info.plist
454 if (!hasDefaultApplicationIcon)
455 return;
456
457 // Or an explicit application icon set on QGuiApplication
458 if (!qGuiApp->windowIcon().isNull())
459 return;
460
461 setApplicationIcon(focusWindow->icon());
462}
463
465
466#include "moc_qcocoaintegration.cpp"
Cocoa Input context implementation.
QPlatformWindow * createForeignWindow(QWindow *window, WId nativeHandle) const override
QPlatformBackingStore * createPlatformBackingStore(QWindow *widget) const override
Factory function for QPlatformBackingStore.
QVariant styleHint(StyleHint hint) const override
static QCocoaIntegration * instance()
bool hasCapability(QPlatformIntegration::Capability cap) const override
void setApplicationIcon(const QIcon &icon) const override
QPlatformOpenGLContext * createPlatformOpenGLContext(QOpenGLContext *context) const override
Factory function for QPlatformOpenGLContext.
QCocoaClipboard * clipboard() const override
Accessor for the platform integration's clipboard.
QCocoaServices * services() const override
QCocoaDrag * drag() const override
void quit() const override
void setApplicationBadge(qint64 number) override
Options options() const
QOpenGLContext * createOpenGLContext(NSOpenGLContext *, QOpenGLContext *shareContext) const override
QPlatformOffscreenSurface * createPlatformOffscreenSurface(QOffscreenSurface *surface) const override
Factory function for QOffscreenSurface.
QPlatformWindow * createPlatformWindow(QWindow *window) const override
Factory function for QPlatformWindow.
void beep() const override
QAbstractEventDispatcher * createEventDispatcher() const override
Factory function for the GUI event dispatcher.
QPlatformTheme * createPlatformTheme(const QString &name) const override
QPlatformInputContext * inputContext() const override
Returns the platforms input context.
QCocoaNativeInterface * nativeInterface() const override
QPlatformKeyMapper * keyMapper() const override
Accessor for the platform integration's key mapper.
QCocoaIntegration(const QStringList &paramList)
QStringList themeNames() const override
QCoreTextFontDatabase * fontDatabase() const override
Accessor for the platform integration's fontdatabase.
static void initializeMimeTypes()
bool isValid() const override
Returns true if the platform offscreen surface has been allocated.
QSurfaceFormat format() const override
Returns the actual surface format of the offscreen surface.
QCocoaOffscreenSurface(QOffscreenSurface *offscreenSurface)
static const char * name
Definition qcocoatheme.h:45
static void removePopupMonitor()
static bool testAttribute(Qt::ApplicationAttribute attribute)
Returns true if attribute attribute is set; otherwise returns false.
static qreal fontSmoothingGamma()
void focusWindowChanged(QWindow *focusWindow)
This signal is emitted when the focused window changes.
The QIcon class provides scalable icons in different modes and states.
Definition qicon.h:20
The QInputDevice class describes a device from which a QInputEvent originates.
static QOperatingSystemVersion deploymentTarget(VersionTarget target=ApplicationBinary)
static QOperatingSystemVersion currentRuntime()
static QOperatingSystemVersion buildSDK(VersionTarget target=ApplicationBinary)
Native interface for QPlatformWindow on \macos. \inmodule QtGui.
Native interface to an NSOpenGLContext on \macos.
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
\inmodule QtGui
QSurfaceFormat requestedFormat() const
Returns the requested surfaceformat of this offscreen surface.
static QOpenGLContextPrivate * get(QOpenGLContext *context)
\inmodule QtGui
The QPlatformBackingStore class provides the drawing area for top-level windows.
static QPlatformInputContext * create()
The QPlatformInputContext class abstracts the input method dependent data and composing state.
virtual QPlatformSessionManager * createPlatformSessionManager(const QString &id, const QString &key) const
virtual QVariant styleHint(StyleHint hint) const
virtual bool hasCapability(Capability cap) const
virtual QPlatformTheme * createPlatformTheme(const QString &name) const
Capability
Capabilities are used to determine specific features of a platform integration.
QOffscreenSurface * offscreenSurface() const
The QPlatformOpenGLContext class provides an abstraction for native GL contexts.
The QPlatformTheme class allows customizing the UI based on themes.
The QPlatformVulkanInstance class provides an abstraction for Vulkan instances.
The QPlatformWindow class provides an abstraction for top-level windows.
T * data() const noexcept
Returns the value of the pointer referenced by this object.
void reset(T *other=nullptr) noexcept(noexcept(Cleanup::cleanup(std::declval< T * >())))
Deletes the existing object it is pointing to (if any), and sets its pointer to other.
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
The QSurfaceFormat class represents the format of a QSurface. \inmodule QtGui.
@ RasterSurface
Definition qsurface.h:31
@ OpenGLSurface
Definition qsurface.h:32
@ MetalSurface
Definition qsurface.h:36
@ VulkanSurface
Definition qsurface.h:35
\inmodule QtCore
Definition qvariant.h:65
The QVulkanInstance class represents a native Vulkan instance, enabling Vulkan rendering onto a QSurf...
static void registerInputDevice(const QInputDevice *device)
\inmodule QtGui
Definition qwindow.h:63
rect
[4]
Combined button and popup list for selecting options.
@ AA_PluginApplication
Definition qnamespace.h:430
static void * context
QT_BEGIN_NAMESPACE void qt_redirectNSApplicationSendEvent()
void qt_resetNSApplicationSendEvent()
void qt_mac_transformProccessToForegroundApplication()
static void initResources()
static void logVersionInformation()
QList< QString > QStringList
Constructs a string list that contains the given string, str.
#define qGuiApp
@ QtWarningMsg
Definition qlogging.h:31
#define qWarning
Definition qlogging.h:166
#define Q_LOGGING_CATEGORY(name,...)
#define qCInfo(category,...)
#define qCDebug(category,...)
GLuint64 key
GLenum const GLint * param
GLuint name
GLenum cap
static void initResources()
Definition qpdf.cpp:39
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
static QT_BEGIN_NAMESPACE QVariant hint(QPlatformIntegration::StyleHint h)
Options parseOptions()
Definition main.cpp:369
#define QT_CONFIG(feature)
Q_CORE_EXPORT bool qEnvironmentVariableIsEmpty(const char *varName) noexcept
#define Q_INIT_RESOURCE(name)
Definition qtresource.h:14
long long qint64
Definition qtypes.h:60
if(qFloatDistance(a, b)<(1<< 7))
[0]
QObject::connect nullptr
aWidget window() -> setWindowTitle("New Window Title")
[2]
QMenu menu
[5]