Qt 6.x
The Qt SDK
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
44#include <inttypes.h>
45
46static void initResources()
47{
48 Q_INIT_RESOURCE(qcocoaresources);
49}
50
52
53using namespace Qt::StringLiterals;
54
56
58{
59 if (!lcQpa().isInfoEnabled())
60 return;
61
62 auto osVersion = QMacVersion::currentRuntime();
67
68 qCInfo(lcQpa, "Loading macOS (Cocoa) platform plugin for Qt " QT_VERSION_STR ", running on macOS %d.%d.%d\n\n" \
69 " Component SDK version Deployment target \n" \
70 " ------------- ------------- -------------------\n" \
71 " Qt " QT_VERSION_STR " %d.%d.%d %d.%d.%d\n" \
72 " Application %d.%d.%d %d.%d.%d\n",
73 osVersion.majorVersion(), osVersion.minorVersion(), osVersion.microVersion(),
74 qtBuildSDK.majorVersion(), qtBuildSDK.minorVersion(), qtBuildSDK.microVersion(),
75 qtDeploymentTarget.majorVersion(), qtDeploymentTarget.minorVersion(), qtDeploymentTarget.microVersion(),
76 appBuildSDK.majorVersion(), appBuildSDK.minorVersion(), appBuildSDK.microVersion(),
77 appDeploymentTarget.majorVersion(), appDeploymentTarget.minorVersion(), appDeploymentTarget.microVersion());
78}
79
80
82class QFontEngineFT;
83
84static QCocoaIntegration::Options parseOptions(const QStringList &paramList)
85{
86 QCocoaIntegration::Options options;
87 for (const QString &param : paramList) {
88#ifndef QT_NO_FREETYPE
89 if (param == "fontengine=freetype"_L1)
91 else
92#endif
93 qWarning() << "Unknown option" << param;
94 }
95 return options;
96}
97
98QCocoaIntegration *QCocoaIntegration::mInstance = nullptr;
99
101 : mOptions(parseOptions(paramList))
102 , mFontDb(nullptr)
103#if QT_CONFIG(accessibility)
104 , mAccessibility(new QCocoaAccessibility)
105#endif
106#ifndef QT_NO_CLIPBOARD
107 , mCocoaClipboard(new QCocoaClipboard)
108#endif
109 , mCocoaDrag(new QCocoaDrag)
110 , mNativeInterface(new QCocoaNativeInterface)
111 , mServices(new QCocoaServices)
112 , mKeyboardMapper(new QAppleKeyMapper)
113{
115
116 if (mInstance)
117 qWarning("Creating multiple Cocoa platform integrations is not supported");
118 mInstance = this;
119
120#ifndef QT_NO_FREETYPE
121 if (mOptions.testFlag(UseFreeTypeFontEngine))
123 else
124#endif
126
128 icStr.isNull() ? mInputContext.reset(new QCocoaInputContext)
129 : mInputContext.reset(QPlatformInputContextFactory::create(icStr));
130
133
134 NSApplication *cocoaApplication = [QNSApplication sharedApplication];
136
137 if (qEnvironmentVariableIsEmpty("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM")) {
138 // Applications launched from plain executables (without an app
139 // bundle) are "background" applications that does not take keyboard
140 // focus or have a dock icon or task switcher entry. Qt Gui apps generally
141 // wants to be foreground applications so change the process type. (But
142 // see the function implementation for exceptions.)
144
145 // Move the application window to front to make it take focus, also when launching
146 // from the terminal. On 10.12+ this call has been moved to applicationDidFinishLauching
147 // to work around issues with loss of focus at startup.
149 // Ignoring other apps is necessary (we must ignore the terminal), but makes
150 // Qt apps play slightly less nice with other apps when lanching from Finder
151 // (See the activateIgnoringOtherApps docs.)
152 [cocoaApplication activateIgnoringOtherApps : YES];
153 }
154 }
155
156 // Qt 4 also does not set the application delegate, so that behavior
157 // is matched here.
159
160 // Set app delegate, link to the current delegate (if any)
161 QCocoaApplicationDelegate *newDelegate = [QCocoaApplicationDelegate sharedDelegate];
162 [newDelegate setReflectionDelegate:[cocoaApplication delegate]];
163 [cocoaApplication setDelegate:newDelegate];
164
165 // Load the application menu. This menu contains Preferences, Hide, Quit.
166 QCocoaMenuLoader *qtMenuLoader = [QCocoaMenuLoader sharedMenuLoader];
167 [cocoaApplication setMenu:[qtMenuLoader menu]];
168 }
169
170 QCocoaScreen::initializeScreens();
171
177
179 this, &QCocoaIntegration::focusWindowChanged);
180}
181
183{
184 mInstance = nullptr;
185
187
190 // remove the apple event handlers installed by QCocoaApplicationDelegate
191 QCocoaApplicationDelegate *delegate = [QCocoaApplicationDelegate sharedDelegate];
192 [delegate removeAppleEventHandlers];
193 // reset the application delegate
194 [[NSApplication sharedApplication] setDelegate:nil];
195 }
196
197#ifndef QT_NO_CLIPBOARD
198 // Delete the clipboard integration and destroy mime type converters.
199 // Deleting the clipboard integration flushes promised pastes using
200 // the mime converters - the ordering here is important.
201 delete mCocoaClipboard;
203#endif
204
205 QCocoaScreen::cleanupScreens();
206}
207
209{
210 return mInstance;
211}
212
213QCocoaIntegration::Options QCocoaIntegration::options() const
214{
215 return mOptions;
216}
217
218#if QT_CONFIG(sessionmanager)
220{
221 return new QCocoaSessionManager(id, key);
222}
223#endif
224
226{
227 switch (cap) {
228#ifndef QT_NO_OPENGL
229 case ThreadedOpenGL:
230 // AppKit expects rendering to happen on the main thread, and we can
231 // easily end up in situations where rendering on secondary threads
232 // will result in visual artifacts, bugs, or even deadlocks, when
233 // layer-backed.
234 return false;
235 case OpenGL:
237#endif
238 case ThreadedPixmaps:
239 case WindowMasks:
240 case MultipleWindows:
241 case ForeignWindows:
242 case RasterGLSurface:
243 case ApplicationState:
244 case ApplicationIcon:
245 return true;
246 default:
248 }
249}
250
252{
253 return new QCocoaWindow(window);
254}
255
257{
258 return new QCocoaWindow(window, nativeHandle);
259}
260
262{
263public:
265
266 QSurfaceFormat format() const override
267 {
270 }
271 bool isValid() const override { return true; }
272};
273
275{
276 return new QCocoaOffscreenSurface(surface);
277}
278
279#ifndef QT_NO_OPENGL
281{
282 return new QCocoaGLContext(context);
283}
284
285QOpenGLContext *QCocoaIntegration::createOpenGLContext(NSOpenGLContext *nativeContext, QOpenGLContext *shareContext) const
286{
287 if (!nativeContext)
288 return nullptr;
289
290 auto *context = new QOpenGLContext;
291 context->setShareContext(shareContext);
292 auto *contextPrivate = QOpenGLContextPrivate::get(context);
293 contextPrivate->adopt(new QCocoaGLContext(nativeContext));
294 return context;
295}
296
297#endif
298
300{
301 QCocoaWindow *platformWindow = static_cast<QCocoaWindow*>(window->handle());
302 if (!platformWindow) {
303 qWarning() << window << "must be created before being used with a backingstore";
304 return nullptr;
305 }
306
307 switch (window->surfaceType()) {
309 return new QCALayerBackingStore(window);
312 return new QRhiBackingStore(window);
313 default:
314 return nullptr;
315 }
316}
317
319{
320 return new QCocoaEventDispatcher;
321}
322
323#if QT_CONFIG(vulkan)
324QPlatformVulkanInstance *QCocoaIntegration::createPlatformVulkanInstance(QVulkanInstance *instance) const
325{
326 mCocoaVulkanInstance = new QCocoaVulkanInstance(instance);
327 return mCocoaVulkanInstance;
328}
329
330QCocoaVulkanInstance *QCocoaIntegration::getCocoaVulkanInstance() const
331{
332 return mCocoaVulkanInstance;
333}
334#endif
335
337{
338 return mFontDb.data();
339}
340
342{
343 return mNativeInterface.data();
344}
345
347{
348 return mInputContext.data();
349}
350
351#if QT_CONFIG(accessibility)
352QCocoaAccessibility *QCocoaIntegration::accessibility() const
353{
354 return mAccessibility.data();
355}
356#endif
357
358#ifndef QT_NO_CLIPBOARD
360{
361 return mCocoaClipboard;
362}
363#endif
364
366{
367 return mCocoaDrag.data();
368}
369
371{
373}
374
376{
378 return new QCocoaTheme;
380}
381
383{
384 return mServices.data();
385}
386
388{
389 switch (hint) {
393 return QVariant(false);
395 return QVariant(false);
396 default: break;
397 }
398
400}
401
402Qt::KeyboardModifiers QCocoaIntegration::queryKeyboardModifiers() const
403{
405}
406
408{
409 return mKeyboardMapper->possibleKeys(event);
410}
411
413{
414 // Fall back to a size that looks good on the highest resolution screen available
415 auto fallbackSize = NSApp.dockTile.size.width * qGuiApp->devicePixelRatio();
416 NSApp.applicationIconImage = [NSImage imageFromQIcon:icon withSize:fallbackSize];
417}
418
420{
421 NSApp.dockTile.badgeLabel = number ? [NSString stringWithFormat:@"%" PRId64, number] : nil;
422}
423
425{
426 NSBeep();
427}
428
430{
431 qCDebug(lcQpaApplication) << "Terminating application";
432 [NSApp terminate:nil];
433}
434
435void QCocoaIntegration::focusWindowChanged(QWindow *focusWindow)
436{
437 // Don't revert icon just because we lost focus
438 if (!focusWindow)
439 return;
440
441 static bool hasDefaultApplicationIcon = [](){
442 NSImage *genericApplicationIcon = [[NSWorkspace sharedWorkspace]
443 iconForFileType:NSFileTypeForHFSTypeCode(kGenericApplicationIcon)];
444 NSImage *applicationIcon = [NSImage imageNamed:NSImageNameApplicationIcon];
445
446 NSRect rect = NSMakeRect(0, 0, 32, 32);
447 return [applicationIcon CGImageForProposedRect:&rect context:nil hints:nil]
448 == [genericApplicationIcon CGImageForProposedRect:&rect context:nil hints:nil];
449 }();
450
451 // Don't let the window icon override an explicit application icon set in the Info.plist
452 if (!hasDefaultApplicationIcon)
453 return;
454
455 // Or an explicit application icon set on QGuiApplication
456 if (!qGuiApp->windowIcon().isNull())
457 return;
458
459 setApplicationIcon(focusWindow->icon());
460}
461
463
464#include "moc_qcocoaintegration.cpp"
QList< int > possibleKeys(const QKeyEvent *event) const
static Qt::KeyboardModifiers queryKeyboardModifiers()
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
QList< int > possibleKeys(const QKeyEvent *event) const override
Should be used to obtain a list of possible shortcuts for the given key event.
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
Qt::KeyboardModifiers queryKeyboardModifiers() const override
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
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:44
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.
The QKeyEvent class describes a key event.
Definition qevent.h:423
Definition qlist.h:74
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:2823
\inmodule QtGui
QSurfaceFormat requestedFormat() const
Returns the requested surfaceformat of this offscreen surface.
static QOpenGLContextPrivate * get(QOpenGLContext *context)
\inmodule QtGui
static constexpr QOperatingSystemVersionBase MacOSSierra
\variable QOperatingSystemVersion::MacOSSierra
static QOperatingSystemVersion current()
[0]
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:127
bool isNull() const
Returns true if this string is null; otherwise returns false.
Definition qstring.h:898
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
\inmodule QtCore
Definition qvariant.h:64
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:429
static void * context
QT_BEGIN_NAMESPACE void qt_redirectNSApplicationSendEvent()
void qt_resetNSApplicationSendEvent()
void qt_mac_transformProccessToForegroundApplication()
static void initResources()
static void logVersionInformation()
#define qGuiApp
@ QtWarningMsg
Definition qlogging.h:31
#define qWarning
Definition qlogging.h:162
#define Q_LOGGING_CATEGORY(name,...)
#define qCInfo(category,...)
#define qCDebug(category,...)
GLuint64 key
GLenum const GLint * param
GLuint name
struct _cl_event * event
GLenum cap
static void initResources()
Definition qpdf.cpp:38
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
static QT_BEGIN_NAMESPACE QVariant hint(QPlatformIntegration::StyleHint h)
Options parseOptions()
Definition main.cpp:367
#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:55
if(qFloatDistance(a, b)<(1<< 7))
[0]
QObject::connect nullptr
aWidget window() -> setWindowTitle("New Window Title")
[2]
QMenu menu
[5]