1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the plugins of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 /****************************************************************************
44 ** Copyright (c) 2007-2008, Apple, Inc.
46 ** All rights reserved.
48 ** Redistribution and use in source and binary forms, with or without
49 ** modification, are permitted provided that the following conditions are met:
51 ** * Redistributions of source code must retain the above copyright notice,
52 ** this list of conditions and the following disclaimer.
54 ** * Redistributions in binary form must reproduce the above copyright notice,
55 ** this list of conditions and the following disclaimer in the documentation
56 ** and/or other materials provided with the distribution.
58 ** * Neither the name of Apple, Inc. nor the names of its contributors
59 ** may be used to endorse or promote products derived from this software
60 ** without specific prior written permission.
62 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
63 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
64 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
65 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
66 ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
67 ** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
68 ** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
69 ** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
70 ** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
71 ** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
72 ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
74 ****************************************************************************/
77 #import "qcocoaapplicationdelegate.h"
78 #import "qnswindowdelegate.h"
79 #import "qcocoamenuloader.h"
83 #include <qguiapplication.h>
84 #include <private/qguiapplication_p.h>
86 #include <QtGui/qwindowsysteminterface.h>
90 static QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) *sharedCocoaApplicationDelegate = nil;
92 static void cleanupCocoaApplicationDelegate()
94 [sharedCocoaApplicationDelegate release];
97 @implementation QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate)
109 sharedCocoaApplicationDelegate = nil;
111 [qtMenuLoader release];
112 if (reflectionDelegate) {
113 [NSApp setDelegate:reflectionDelegate];
114 [reflectionDelegate release];
119 + (id)allocWithZone:(NSZone *)zone
121 @synchronized(self) {
122 if (sharedCocoaApplicationDelegate == nil) {
123 sharedCocoaApplicationDelegate = [super allocWithZone:zone];
124 return sharedCocoaApplicationDelegate;
125 qAddPostRoutine(cleanupCocoaApplicationDelegate);
131 + (QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate)*)sharedDelegate
133 @synchronized(self) {
134 if (sharedCocoaApplicationDelegate == nil)
137 return [[sharedCocoaApplicationDelegate retain] autorelease];
140 - (void)setDockMenu:(NSMenu*)newMenu
147 - (NSMenu *)applicationDockMenu
149 return [[dockMenu retain] autorelease];
152 - (void)setMenuLoader:(QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *)menuLoader
155 [qtMenuLoader release];
156 qtMenuLoader = menuLoader;
159 - (QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *)menuLoader
161 return [[qtMenuLoader retain] autorelease];
166 [[NSApp mainMenu] cancelTracking];
168 bool handle_quit = true;
169 NSMenuItem *quitMenuItem = [[[QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate] menuLoader] quitMenuItem];
170 if (!QGuiApplicationPrivate::instance()->modalWindowList.isEmpty()
171 && [quitMenuItem isEnabled]) {
173 const QWindowList tlws = QGuiApplication::topLevelWindows();
174 for (int i = 0; i < tlws.size(); ++i) {
175 if (tlws.at(i)->isVisible())
178 handle_quit = (visible <= 1);
183 QGuiApplication::sendEvent(qGuiApp, &ev);
184 if (ev.isAccepted()) {
192 // This function will only be called when NSApp is actually running.
193 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
195 // The reflection delegate gets precedence
196 if (reflectionDelegate
197 && [reflectionDelegate respondsToSelector:@selector(applicationShouldTerminate:)]) {
198 return [reflectionDelegate applicationShouldTerminate:sender];
201 if ([self canQuit]) {
204 QGuiApplication::exit(0);
209 if (QGuiApplicationPrivate::instance()->threadData->eventLoops.isEmpty()) {
210 // INVARIANT: No event loop is executing. This probably
211 // means that Qt is used as a plugin, or as a part of a native
212 // Cocoa application. In any case it should be fine to
214 return NSTerminateNow;
217 return NSTerminateCancel;
220 - (void) applicationWillFinishLaunching:(NSNotification *)notification
222 Q_UNUSED(notification);
225 From the Cocoa documentation: "A good place to install event handlers
226 is in the applicationWillFinishLaunching: method of the application
227 delegate. At that point, the Application Kit has installed its default
228 event handlers, so if you install a handler for one of the same events,
229 it will replace the Application Kit version."
233 If Qt is used as a plugin, we let the 3rd party application handle
234 events like quit and open file events. Otherwise, if we install our own
235 handlers, we easily end up breaking functionality the 3rd party
236 application depends on.
238 NSAppleEventManager *eventManager = [NSAppleEventManager sharedAppleEventManager];
239 [eventManager setEventHandler:self
240 andSelector:@selector(appleEventQuit:withReplyEvent:)
241 forEventClass:kCoreEventClass
242 andEventID:kAEQuitApplication];
243 [eventManager setEventHandler:self
244 andSelector:@selector(getUrl:withReplyEvent:)
245 forEventClass:kInternetEventClass
246 andEventID:kAEGetURL];
249 // called by QCocoaIntegration's destructor before resetting the application delegate to nil
250 - (void) removeAppleEventHandlers
252 NSAppleEventManager *eventManager = [NSAppleEventManager sharedAppleEventManager];
253 [eventManager removeEventHandlerForEventClass:kCoreEventClass andEventID:kAEQuitApplication];
254 [eventManager removeEventHandlerForEventClass:kInternetEventClass andEventID:kAEGetURL];
257 - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
259 Q_UNUSED(aNotification);
261 // qt_release_apple_event_handler();
264 // Insert code here to initialize your application
269 - (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames
274 for (NSString *fileName in filenames) {
275 QString qtFileName = QCFString::toQString(fileName);
277 // We need to be careful because Cocoa will be nice enough to take
278 // command line arguments and send them to us as events. Given the history
279 // of Qt Applications, this will result in behavior people don't want, as
280 // they might be doing the opening themselves with the command line parsing.
281 if (qApp->arguments().contains(qtFileName))
284 QWindowSystemInterface::handleFileOpenEvent(qtFileName);
287 if (reflectionDelegate &&
288 [reflectionDelegate respondsToSelector:@selector(application:openFiles:)])
289 [reflectionDelegate application:sender openFiles:filenames];
293 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
295 // If we have a reflection delegate, that will get to call the shots.
296 if (reflectionDelegate
297 && [reflectionDelegate respondsToSelector:
298 @selector(applicationShouldTerminateAfterLastWindowClosed:)])
299 return [reflectionDelegate applicationShouldTerminateAfterLastWindowClosed:sender];
300 return NO; // Someday qApp->quitOnLastWindowClosed(); when QApp and NSApp work closer together.
304 - (void)applicationDidBecomeActive:(NSNotification *)notification
306 Q_UNUSED(notification);
308 if (reflectionDelegate
309 && [reflectionDelegate respondsToSelector:@selector(applicationDidBecomeActive:)])
310 [reflectionDelegate applicationDidBecomeActive:notification];
312 onApplicationChangedActivation(true);
314 if (!QWidget::mouseGrabber()){
315 // Update enter/leave immidiatly, don't wait for a move event. But only
316 // if no grab exists (even if the grab points to this widget, it seems, ref X11)
317 QPoint qlocal, qglobal;
318 QWidget *widgetUnderMouse = 0;
319 qt_mac_getTargetForMouseEvent(0, QEvent::Enter, qlocal, qglobal, 0, &widgetUnderMouse);
320 QApplicationPrivate::dispatchEnterLeave(widgetUnderMouse, 0);
321 qt_last_mouse_receiver = widgetUnderMouse;
322 qt_last_native_mouse_receiver = widgetUnderMouse ?
323 (widgetUnderMouse->internalWinId() ? widgetUnderMouse : widgetUnderMouse->nativeParentWidget()) : 0;
328 - (void)applicationDidResignActive:(NSNotification *)notification
330 Q_UNUSED(notification);
332 if (reflectionDelegate
333 && [reflectionDelegate respondsToSelector:@selector(applicationDidResignActive:)])
334 [reflectionDelegate applicationDidResignActive:notification];
336 onApplicationChangedActivation(false);
338 if (!QWidget::mouseGrabber())
339 QApplicationPrivate::dispatchEnterLeave(0, qt_last_mouse_receiver);
340 qt_last_mouse_receiver = 0;
341 qt_last_native_mouse_receiver = 0;
346 - (void)applicationDidChangeScreenParameters:(NSNotification *)notification
348 Q_UNUSED(notification);
349 //QDesktopWidgetImplementation::instance()->onResize();
352 - (void)setReflectionDelegate:(NSObject <NSApplicationDelegate> *)oldDelegate
354 [oldDelegate retain];
355 [reflectionDelegate release];
356 reflectionDelegate = oldDelegate;
359 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
361 NSMethodSignature *result = [super methodSignatureForSelector:aSelector];
362 if (!result && reflectionDelegate) {
363 result = [reflectionDelegate methodSignatureForSelector:aSelector];
368 - (BOOL)respondsToSelector:(SEL)aSelector
370 BOOL result = [super respondsToSelector:aSelector];
371 if (!result && reflectionDelegate)
372 result = [reflectionDelegate respondsToSelector:aSelector];
376 - (void)forwardInvocation:(NSInvocation *)invocation
378 SEL invocationSelector = [invocation selector];
379 if (reflectionDelegate && [reflectionDelegate respondsToSelector:invocationSelector])
380 [invocation invokeWithTarget:reflectionDelegate];
382 [self doesNotRecognizeSelector:invocationSelector];
385 - (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
387 Q_UNUSED(replyEvent);
388 NSString *urlString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
389 QWindowSystemInterface::handleFileOpenEvent(QCFString::toQString(urlString));
392 - (void)appleEventQuit:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
395 Q_UNUSED(replyEvent);
396 [NSApp terminate:self];
399 - (void)qtDispatcherToQAction:(id)sender
402 [qtMenuLoader qtDispatcherToQPAMenuItem:sender];