895bcc5de5bd51bdf5e317f86bb1964e1b46cd47
[profile/ivi/qtbase.git] / src / plugins / platforms / cocoa / qcocoaapplicationdelegate.mm
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 /****************************************************************************
43  **
44  ** Copyright (c) 2007-2008, Apple, Inc.
45  **
46  ** All rights reserved.
47  **
48  ** Redistribution and use in source and binary forms, with or without
49  ** modification, are permitted provided that the following conditions are met:
50  **
51  **   * Redistributions of source code must retain the above copyright notice,
52  **     this list of conditions and the following disclaimer.
53  **
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.
57  **
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.
61  **
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.
73  **
74  ****************************************************************************/
75
76
77 #import "qcocoaapplicationdelegate.h"
78 #import "qnswindowdelegate.h"
79 #import "qcocoamenuloader.h"
80 #include <qevent.h>
81 #include <qurl.h>
82 #include <qdebug.h>
83 #include <qguiapplication.h>
84 #include <private/qguiapplication_p.h>
85 #include "qt_mac_p.h"
86 #include <QtGui/qwindowsysteminterface.h>
87
88 QT_USE_NAMESPACE
89
90 static QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) *sharedCocoaApplicationDelegate = nil;
91
92 static void cleanupCocoaApplicationDelegate()
93 {
94     [sharedCocoaApplicationDelegate release];
95 }
96
97 @implementation QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate)
98
99 - (id)init
100 {
101     self = [super init];
102     if (self)
103         inLaunch = true;
104     return self;
105 }
106
107 - (void)dealloc
108 {
109     sharedCocoaApplicationDelegate = nil;
110     [dockMenu release];
111     [qtMenuLoader release];
112     if (reflectionDelegate) {
113         [NSApp setDelegate:reflectionDelegate];
114         [reflectionDelegate release];
115     }
116     [super dealloc];
117 }
118
119 + (id)allocWithZone:(NSZone *)zone
120 {
121     @synchronized(self) {
122         if (sharedCocoaApplicationDelegate == nil) {
123             sharedCocoaApplicationDelegate = [super allocWithZone:zone];
124             return sharedCocoaApplicationDelegate;
125             qAddPostRoutine(cleanupCocoaApplicationDelegate);
126         }
127     }
128     return nil;
129 }
130
131 + (QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate)*)sharedDelegate
132 {
133     @synchronized(self) {
134         if (sharedCocoaApplicationDelegate == nil)
135             [[self alloc] init];
136     }
137     return [[sharedCocoaApplicationDelegate retain] autorelease];
138 }
139
140 - (void)setDockMenu:(NSMenu*)newMenu
141 {
142     [newMenu retain];
143     [dockMenu release];
144     dockMenu = newMenu;
145 }
146
147 - (NSMenu *)applicationDockMenu
148 {
149     return [[dockMenu retain] autorelease];
150 }
151
152 - (void)setMenuLoader:(QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *)menuLoader
153 {
154     [menuLoader retain];
155     [qtMenuLoader release];
156     qtMenuLoader = menuLoader;
157 }
158
159 - (QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *)menuLoader
160 {
161     return [[qtMenuLoader retain] autorelease];
162 }
163
164 - (BOOL) canQuit
165 {
166     [[NSApp mainMenu] cancelTracking];
167
168     bool handle_quit = true;
169     NSMenuItem *quitMenuItem = [[[QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate] menuLoader] quitMenuItem];
170     if (!QGuiApplicationPrivate::instance()->modalWindowList.isEmpty()
171         && [quitMenuItem isEnabled]) {
172         int visible = 0;
173         const QWindowList tlws = QGuiApplication::topLevelWindows();
174         for (int i = 0; i < tlws.size(); ++i) {
175             if (tlws.at(i)->isVisible())
176                 ++visible;
177         }
178         handle_quit = (visible <= 1);
179     }
180
181     if (handle_quit) {
182         QCloseEvent ev;
183         QGuiApplication::sendEvent(qGuiApp, &ev);
184         if (ev.isAccepted()) {
185             return YES;
186         }
187     }
188
189     return NO;
190 }
191
192 // This function will only be called when NSApp is actually running.
193 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
194 {
195     // The reflection delegate gets precedence
196     if (reflectionDelegate
197         && [reflectionDelegate respondsToSelector:@selector(applicationShouldTerminate:)]) {
198         return [reflectionDelegate applicationShouldTerminate:sender];
199     }
200
201     if ([self canQuit]) {
202         if (!startedQuit) {
203             startedQuit = true;
204             QGuiApplication::exit(0);
205             startedQuit = false;
206         }
207     }
208
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
213         // terminate now:
214         return NSTerminateNow;
215     }
216
217     return NSTerminateCancel;
218 }
219
220 - (void) applicationWillFinishLaunching:(NSNotification *)notification
221 {
222     Q_UNUSED(notification);
223
224     /*
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."
230     */
231
232     /*
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.
237      */
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];
247 }
248
249 // called by QCocoaIntegration's destructor before resetting the application delegate to nil
250 - (void) removeAppleEventHandlers
251 {
252     NSAppleEventManager *eventManager = [NSAppleEventManager sharedAppleEventManager];
253     [eventManager removeEventHandlerForEventClass:kCoreEventClass andEventID:kAEQuitApplication];
254     [eventManager removeEventHandlerForEventClass:kInternetEventClass andEventID:kAEGetURL];
255 }
256
257 - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
258 {
259     Q_UNUSED(aNotification);
260     inLaunch = false;
261     // qt_release_apple_event_handler();
262
263
264     // Insert code here to initialize your application
265 }
266
267
268
269 - (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames
270 {
271     Q_UNUSED(filenames);
272     Q_UNUSED(sender);
273
274     for (NSString *fileName in filenames) {
275         QString qtFileName = QCFString::toQString(fileName);
276         if (inLaunch) {
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))
282                 continue;
283         }
284         QWindowSystemInterface::handleFileOpenEvent(qtFileName);
285     }
286
287     if (reflectionDelegate &&
288         [reflectionDelegate respondsToSelector:@selector(application:openFiles:)])
289         [reflectionDelegate application:sender openFiles:filenames];
290
291 }
292
293 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
294 {
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.
301 }
302
303
304 - (void)applicationDidBecomeActive:(NSNotification *)notification
305 {
306     Q_UNUSED(notification);
307 /*
308     if (reflectionDelegate
309         && [reflectionDelegate respondsToSelector:@selector(applicationDidBecomeActive:)])
310         [reflectionDelegate applicationDidBecomeActive:notification];
311
312     onApplicationChangedActivation(true);
313
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;
324     }
325 */
326 }
327
328 - (void)applicationDidResignActive:(NSNotification *)notification
329 {
330     Q_UNUSED(notification);
331 /*
332     if (reflectionDelegate
333         && [reflectionDelegate respondsToSelector:@selector(applicationDidResignActive:)])
334         [reflectionDelegate applicationDidResignActive:notification];
335
336     onApplicationChangedActivation(false);
337
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;
342     qt_button_down = 0;
343 */
344 }
345
346 - (void)applicationDidChangeScreenParameters:(NSNotification *)notification
347 {
348     Q_UNUSED(notification);
349     //QDesktopWidgetImplementation::instance()->onResize();
350 }
351
352 - (void)setReflectionDelegate:(NSObject <NSApplicationDelegate> *)oldDelegate
353 {
354     [oldDelegate retain];
355     [reflectionDelegate release];
356     reflectionDelegate = oldDelegate;
357 }
358
359 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
360 {
361     NSMethodSignature *result = [super methodSignatureForSelector:aSelector];
362     if (!result && reflectionDelegate) {
363         result = [reflectionDelegate methodSignatureForSelector:aSelector];
364     }
365     return result;
366 }
367
368 - (BOOL)respondsToSelector:(SEL)aSelector
369 {
370     BOOL result = [super respondsToSelector:aSelector];
371     if (!result && reflectionDelegate)
372         result = [reflectionDelegate respondsToSelector:aSelector];
373     return result;
374 }
375
376 - (void)forwardInvocation:(NSInvocation *)invocation
377 {
378     SEL invocationSelector = [invocation selector];
379     if (reflectionDelegate && [reflectionDelegate respondsToSelector:invocationSelector])
380         [invocation invokeWithTarget:reflectionDelegate];
381     else
382         [self doesNotRecognizeSelector:invocationSelector];
383 }
384
385 - (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
386 {
387     Q_UNUSED(replyEvent);
388     NSString *urlString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
389     QWindowSystemInterface::handleFileOpenEvent(QCFString::toQString(urlString));
390 }
391
392 - (void)appleEventQuit:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
393 {
394     Q_UNUSED(event);
395     Q_UNUSED(replyEvent);
396     [NSApp terminate:self];
397 }
398
399 - (void)qtDispatcherToQAction:(id)sender
400 {
401     Q_UNUSED(sender);
402     [qtMenuLoader qtDispatcherToQPAMenuItem:sender];
403 }
404
405 @end