6#include <AppKit/AppKit.h>
17#if QT_CONFIG(sessionmanager)
18# include "qcocoasessionmanager.h"
24#include <qguiapplication.h>
25#include <qpa/qwindowsysteminterface.h>
26#include <qwindowdefs.h>
28#include <QtCore/private/qdarwinsecurityscopedfileengine_p.h>
32@implementation QCocoaApplicationDelegate {
33 NSObject <NSApplicationDelegate> *reflectionDelegate;
37+ (instancetype)sharedDelegate
39 static QCocoaApplicationDelegate *shared = nil;
40 static dispatch_once_t onceToken;
41 dispatch_once(&onceToken, ^{
42 shared = [[self alloc] init];
63 if (reflectionDelegate) {
64 [[NSApplication sharedApplication] setDelegate:reflectionDelegate];
65 [reflectionDelegate release];
67 [[NSNotificationCenter defaultCenter] removeObserver:self];
72- (
NSMenu *)applicationDockMenu:(NSApplication *)sender
77 [self.dockMenu.delegate menuWillOpen:self.dockMenu];
78 return [[self.dockMenu retain] autorelease];
82- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
84 if ([reflectionDelegate respondsToSelector:_cmd])
85 return [reflectionDelegate applicationShouldTerminate:sender];
87 if (QGuiApplicationPrivate::instance()->threadData.loadRelaxed()->eventLoops.isEmpty()) {
91 qCDebug(lcQpaApplication) <<
"No running event loops, terminating now";
92 return NSTerminateNow;
95#if QT_CONFIG(sessionmanager)
96 QCocoaSessionManager *cocoaSessionManager = QCocoaSessionManager::instance();
97 cocoaSessionManager->resetCancellation();
98 cocoaSessionManager->appCommitData();
100 if (cocoaSessionManager->wasCanceled()) {
101 qCDebug(lcQpaApplication) <<
"Session management canceled application termination";
102 return NSTerminateCancel;
106 if (!QWindowSystemInterface::handleApplicationTermination<QWindowSystemInterface::SynchronousDelivery>()) {
107 qCDebug(lcQpaApplication) <<
"Application termination canceled";
108 return NSTerminateCancel;
115 qCDebug(lcQpaApplication) <<
"Termination accepted, but returning to runloop for exit through main()";
116 return NSTerminateCancel;
119- (
void)applicationWillFinishLaunching:(NSNotification *)notification
121 if ([reflectionDelegate respondsToSelector:_cmd])
122 [reflectionDelegate applicationWillFinishLaunching:notification];
125
126
127
128
129
130
133
134
135
136
137
138 NSAppleEventManager *eventManager = [NSAppleEventManager sharedAppleEventManager];
139 [eventManager setEventHandler:self
140 andSelector:@selector(getUrl:withReplyEvent:)
141 forEventClass:kInternetEventClass
142 andEventID:kAEGetURL];
146- (
void)removeAppleEventHandlers
148 NSAppleEventManager *eventManager = [NSAppleEventManager sharedAppleEventManager];
149 [eventManager removeEventHandlerForEventClass:kInternetEventClass andEventID:kAEGetURL];
157- (
void)applicationDidFinishLaunching:(NSNotification *)aNotification
159 if ([reflectionDelegate respondsToSelector:_cmd])
160 [reflectionDelegate applicationDidFinishLaunching:aNotification];
164 if (qEnvironmentVariableIsEmpty(
"QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM")) {
165 auto currentApplication = NSRunningApplication.currentApplication;
166 if (!currentApplication.active) {
174 auto frontmostApplication = NSWorkspace.sharedWorkspace.frontmostApplication;
175 qCDebug(lcQpaApplication) <<
"Launched with" << frontmostApplication
176 <<
"as frontmost application. Activating" << currentApplication <<
"instead.";
177 [NSApplication.sharedApplication activateIgnoringOtherApps:YES];
180 if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSSonoma) {
192 [currentApplication activateWithOptions:NSApplicationActivateAllWindows];
196 QCocoaMenuBar::insertWindowMenu();
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216- (
void)application:(NSApplication *)sender openFiles:(NSArray *)filenames
221 for (NSString *fileName in filenames) {
222 QString qtFileName = QString::fromNSString(fileName);
228 if (
qApp->arguments().contains(qtFileName))
231 QUrl url = qt_apple_urlFromPossiblySecurityScopedURL([NSURL fileURLWithPath:fileName]);
232 QWindowSystemInterface::handleFileOpenEvent(url);
237 if ([reflectionDelegate respondsToSelector:_cmd])
238 [reflectionDelegate application:sender openFiles:filenames];
242- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
244 if ([reflectionDelegate respondsToSelector:_cmd])
245 return [reflectionDelegate applicationShouldTerminateAfterLastWindowClosed:sender];
250- (
void)applicationDidBecomeActive:(NSNotification *)notification
252 if ([reflectionDelegate respondsToSelector:_cmd])
253 [reflectionDelegate applicationDidBecomeActive:notification];
255 QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive);
257 if (QCocoaWindow::s_windowUnderMouse) {
260 QNSView *view = qnsview_cast(QCocoaWindow::s_windowUnderMouse->m_view);
261 [view convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
262 QWindow *windowUnderMouse = QCocoaWindow::s_windowUnderMouse->window();
263 qCInfo(lcQpaMouse) <<
"Application activated with mouse at" << windowPoint <<
"; sending" << QEvent::Enter <<
"to" << windowUnderMouse;
264 QWindowSystemInterface::handleEnterEvent(windowUnderMouse, windowPoint, screenPoint);
268- (
void)applicationDidResignActive:(NSNotification *)notification
270 if ([reflectionDelegate respondsToSelector:_cmd])
271 [reflectionDelegate applicationDidResignActive:notification];
273 QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive);
275 if (QCocoaWindow::s_windowUnderMouse) {
276 QWindow *windowUnderMouse = QCocoaWindow::s_windowUnderMouse->window();
277 qCInfo(lcQpaMouse) <<
"Application deactivated; sending" << QEvent::Leave <<
"to" << windowUnderMouse;
278 QWindowSystemInterface::handleLeaveEvent(windowUnderMouse);
283
284
285
286
287
288
289
290
291
292
293- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag
295 if ([reflectionDelegate respondsToSelector:_cmd])
296 return [reflectionDelegate applicationShouldHandleReopen:theApplication hasVisibleWindows:flag];
299
300
301
302
303
304
305 QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive,
true );
310- (
void)setReflectionDelegate:(NSObject <NSApplicationDelegate> *)oldDelegate
312 [oldDelegate retain];
313 [reflectionDelegate release];
314 reflectionDelegate = oldDelegate;
317- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
319 NSMethodSignature *result = [super methodSignatureForSelector:aSelector];
320 if (!result && reflectionDelegate) {
321 result = [reflectionDelegate methodSignatureForSelector:aSelector];
326- (BOOL)respondsToSelector:(SEL)aSelector
328 return [super respondsToSelector:aSelector] || [reflectionDelegate respondsToSelector:aSelector];
331- (
void)forwardInvocation:(NSInvocation *)invocation
333 SEL invocationSelector = [invocation selector];
334 if ([reflectionDelegate respondsToSelector:invocationSelector])
335 [invocation invokeWithTarget:reflectionDelegate];
337 [self doesNotRecognizeSelector:invocationSelector];
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359- (BOOL)application:(NSApplication *)application continueUserActivity:(NSUserActivity *)userActivity
360 restorationHandler:(
void(^)(NSArray<id<NSUserActivityRestoring>> *restorableObjects))restorationHandler
363 if ([reflectionDelegate respondsToSelector:_cmd]
364 && [reflectionDelegate application:application continueUserActivity:userActivity
365 restorationHandler:restorationHandler] == YES) {
369 if (!QGuiApplication::instance())
372 if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) {
373 QCocoaIntegration *cocoaIntegration = QCocoaIntegration::instance();
374 Q_ASSERT(cocoaIntegration);
375 return cocoaIntegration->services()->handleUrl(QUrl::fromNSURL(userActivity.webpageURL));
382
383
384
385
386
387
388
389
390
391
392
393- (
void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
395 Q_UNUSED(replyEvent);
397 NSString *urlString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
398 const QString qurlString = QString::fromNSString(urlString);
400 if (event.eventClass == kInternetEventClass && event.eventID == kAEGetURL) {
402 if (!QGuiApplication::instance())
404 QCocoaIntegration *cocoaIntegration = QCocoaIntegration::instance();
405 Q_ASSERT(cocoaIntegration);
406 if (cocoaIntegration->services()->handleUrl(QUrl(qurlString)))
415 if (
const QUrl url(qurlString); url.isValid())
416 QWindowSystemInterface::handleFileOpenEvent(url);
418 QWindowSystemInterface::handleFileOpenEvent(qurlString);
421- (BOOL)applicationSupportsSecureRestorableState:(NSApplication *)application
423 if ([reflectionDelegate respondsToSelector:_cmd])
424 return [reflectionDelegate applicationSupportsSecureRestorableState:application];
437@implementation QCocoaApplicationDelegate (Menus)
439- (BOOL)validateMenuItem:(NSMenuItem*)item
441 qCDebug(lcQpaMenus) <<
"Validating" << item <<
"for" << self;
443 auto *nativeItem = qt_objc_cast<QCocoaNSMenuItem *>(item);
447 auto *platformItem = nativeItem.platformMenuItem;
449 return item.hasSubmenu || (item.enabled && (item.action != @selector(qt_itemFired:)));
452 if (platformItem->menu())
455 return platformItem->isEnabled();
460@implementation QCocoaApplicationDelegate (MenuAPI)
462- (
void)qt_itemFired:(QCocoaNSMenuItem *)item
464 qCDebug(lcQpaMenus) <<
"Activating" << item;
469 auto *nativeItem = qt_objc_cast<QCocoaNSMenuItem *>(item);
470 Q_ASSERT_X(nativeItem, qPrintable(
__FUNCTION__),
"Triggered menu item is not a QCocoaNSMenuItem.");
471 auto *platformItem = nativeItem.platformMenuItem;
474 if (!platformItem || platformItem->menu())
477 QGuiApplicationPrivate::modifier_buttons = QAppleKeyMapper::fromCocoaModifiers([NSEvent modifierFlags]);
479 static QMetaMethod activatedSignal = QMetaMethod::fromSignal(&QCocoaMenuItem::activated);
480 activatedSignal.invoke(platformItem, Qt::QueuedConnection);