Qt 4.8
qcocoaapplicationdelegate_mac.mm
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
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 #include "qmacdefines_mac.h"
77 #ifdef QT_MAC_USE_COCOA
78 
79 #import <private/qcocoaapplicationdelegate_mac_p.h>
80 #import <private/qcocoamenuloader_mac_p.h>
81 #import <private/qcocoaapplication_mac_p.h>
82 #include <private/qapplication_p.h>
83 #include <private/qt_mac_p.h>
84 #include <private/qt_cocoa_helpers_mac_p.h>
85 #include <private/qdesktopwidget_mac_p.h>
86 #include <qevent.h>
87 #include <qurl.h>
88 #include <qapplication.h>
89 
91 extern void onApplicationChangedActivation(bool); // qapplication_mac.mm
92 extern void qt_release_apple_event_handler(); //qapplication_mac.mm
93 extern QPointer<QWidget> qt_last_mouse_receiver; // qapplication_mac.cpp
94 extern QPointer<QWidget> qt_last_native_mouse_receiver; // qt_cocoa_helpers_mac.mm
95 extern QPointer<QWidget> qt_button_down; // qapplication_mac.cpp
96 
98 
101 
102 static QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) *sharedCocoaApplicationDelegate = nil;
103 
104 static void cleanupCocoaApplicationDelegate()
105 {
106  [sharedCocoaApplicationDelegate release];
107 }
108 
109 @implementation QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate)
110 
111 - (id)init
112 {
113  self = [super init];
114  if (self)
115  inLaunch = true;
116  return self;
117 }
118 
119 - (void)dealloc
120 {
121  sharedCocoaApplicationDelegate = nil;
122  [dockMenu release];
123  [qtMenuLoader release];
124  if (reflectionDelegate) {
125  [NSApp setDelegate:reflectionDelegate];
126  [reflectionDelegate release];
127  }
128  [super dealloc];
129 }
130 
131 + (id)allocWithZone:(NSZone *)zone
132 {
133  @synchronized(self) {
134  if (sharedCocoaApplicationDelegate == nil) {
135  sharedCocoaApplicationDelegate = [super allocWithZone:zone];
136  return sharedCocoaApplicationDelegate;
137  qAddPostRoutine(cleanupCocoaApplicationDelegate);
138  }
139  }
140  return nil;
141 }
142 
143 + (QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate)*)sharedDelegate
144 {
145  @synchronized(self) {
146  if (sharedCocoaApplicationDelegate == nil)
147  [[self alloc] init];
148  }
149  return [[sharedCocoaApplicationDelegate retain] autorelease];
150 }
151 
152 - (void)setDockMenu:(NSMenu*)newMenu
153 {
154  [newMenu retain];
155  [dockMenu release];
156  dockMenu = newMenu;
157 }
158 
159 - (NSMenu *)applicationDockMenu
160 {
161  return [[dockMenu retain] autorelease];
162 }
163 
164 - (QApplicationPrivate *)qAppPrivate
165 {
166  return qtPrivate;
167 }
168 
169 - (void)setQtPrivate:(QApplicationPrivate *)value
170 {
171  qtPrivate = value;
172 }
173 
174 - (void)setMenuLoader:(QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *)menuLoader
175 {
176  [menuLoader retain];
177  [qtMenuLoader release];
178  qtMenuLoader = menuLoader;
179 }
180 
181 - (QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *)menuLoader
182 {
183  return [[qtMenuLoader retain] autorelease];
184 }
185 
186 // This function will only be called when NSApp is actually running. Before
187 // that, the kAEQuitApplication Apple event will be sent to
188 // QApplicationPrivate::globalAppleEventProcessor in qapplication_mac.mm
189 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
190 {
191  Q_UNUSED(sender);
192  // The reflection delegate gets precedence
193  if (reflectionDelegate
194  && [reflectionDelegate respondsToSelector:@selector(applicationShouldTerminate:)]) {
195  return [reflectionDelegate applicationShouldTerminate:sender];
196  }
197 
198  if (qtPrivate->canQuit()) {
199  if (!startedQuit) {
200  startedQuit = true;
201  qAppInstance()->quit();
202  startedQuit = false;
203  }
204  }
205 
206  if (qtPrivate->threadData->eventLoops.size() == 0) {
207  // INVARIANT: No event loop is executing. This probably
208  // means that Qt is used as a plugin, or as a part of a native
209  // Cocoa application. In any case it should be fine to
210  // terminate now:
211  return NSTerminateNow;
212  }
213 
214  return NSTerminateCancel;
215 }
216 
217 - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
218 {
219  Q_UNUSED(aNotification);
220  inLaunch = false;
222 }
223 
224 - (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames
225 {
226  for (NSString *fileName in filenames) {
227  QString qtFileName = qt_mac_NSStringToQString(fileName);
228  if (inLaunch) {
229  // We need to be careful because Cocoa will be nice enough to take
230  // command line arguments and send them to us as events. Given the history
231  // of Qt Applications, this will result in behavior people don't want, as
232  // they might be doing the opening themselves with the command line parsing.
233  if (qApp->arguments().contains(qtFileName))
234  continue;
235  }
236  QFileOpenEvent foe(qtFileName);
238  }
239 
240  if (reflectionDelegate &&
241  [reflectionDelegate respondsToSelector:@selector(application:openFiles:)])
242  [reflectionDelegate application:sender openFiles:filenames];
243 }
244 
245 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
246 {
247  // If we have a reflection delegate, that will get to call the shots.
248  if (reflectionDelegate
249  && [reflectionDelegate respondsToSelector:
250  @selector(applicationShouldTerminateAfterLastWindowClosed:)])
251  return [reflectionDelegate applicationShouldTerminateAfterLastWindowClosed:sender];
252  return NO; // Someday qApp->quitOnLastWindowClosed(); when QApp and NSApp work closer together.
253 }
254 
255 
256 - (void)applicationDidBecomeActive:(NSNotification *)notification
257 {
258  if (reflectionDelegate
259  && [reflectionDelegate respondsToSelector:@selector(applicationDidBecomeActive:)])
260  [reflectionDelegate applicationDidBecomeActive:notification];
261 
263 
264  if (!QWidget::mouseGrabber()){
265  // Update enter/leave immidiatly, don't wait for a move event. But only
266  // if no grab exists (even if the grab points to this widget, it seems, ref X11)
267  QPoint qlocal, qglobal;
268  QWidget *widgetUnderMouse = 0;
269  qt_mac_getTargetForMouseEvent(0, QEvent::Enter, qlocal, qglobal, 0, &widgetUnderMouse);
270  QApplicationPrivate::dispatchEnterLeave(widgetUnderMouse, 0);
271  qt_last_mouse_receiver = widgetUnderMouse;
272  qt_last_native_mouse_receiver = widgetUnderMouse ?
273  (widgetUnderMouse->internalWinId() ? widgetUnderMouse : widgetUnderMouse->nativeParentWidget()) : 0;
274  }
275 }
276 
277 - (void)applicationDidResignActive:(NSNotification *)notification
278 {
279  if (reflectionDelegate
280  && [reflectionDelegate respondsToSelector:@selector(applicationDidResignActive:)])
281  [reflectionDelegate applicationDidResignActive:notification];
282 
284 
285  if (!QWidget::mouseGrabber())
286  QApplicationPrivate::dispatchEnterLeave(0, qt_last_mouse_receiver);
287  qt_last_mouse_receiver = 0;
288  qt_last_native_mouse_receiver = 0;
289  qt_button_down = 0;
290 }
291 
292 - (void)applicationDidChangeScreenParameters:(NSNotification *)notification
293 {
294  Q_UNUSED(notification);
296 }
297 
298 - (void)setReflectionDelegate:(NSObject <NSApplicationDelegate> *)oldDelegate
299 {
300  [oldDelegate retain];
301  [reflectionDelegate release];
302  reflectionDelegate = oldDelegate;
303 }
304 
305 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
306 {
307  NSMethodSignature *result = [super methodSignatureForSelector:aSelector];
308  if (!result && reflectionDelegate) {
309  result = [reflectionDelegate methodSignatureForSelector:aSelector];
310  }
311  return result;
312 }
313 
314 - (BOOL)respondsToSelector:(SEL)aSelector
315 {
316  BOOL result = [super respondsToSelector:aSelector];
317  if (!result && reflectionDelegate)
318  result = [reflectionDelegate respondsToSelector:aSelector];
319  return result;
320 }
321 
322 - (void)forwardInvocation:(NSInvocation *)invocation
323 {
324  SEL invocationSelector = [invocation selector];
325  if (reflectionDelegate && [reflectionDelegate respondsToSelector:invocationSelector])
326  [invocation invokeWithTarget:reflectionDelegate];
327  else
328  [self doesNotRecognizeSelector:invocationSelector];
329 }
330 
331 - (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
332 {
333  Q_UNUSED(replyEvent);
334 
335  NSString *urlString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
336  QUrl url(qt_mac_NSStringToQString(urlString));
337  QFileOpenEvent qtEvent(url);
339 }
340 
341 - (void)appleEventQuit:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
342 {
343  Q_UNUSED(event);
344  Q_UNUSED(replyEvent);
345  [NSApp terminate:self];
346 }
347 
348 - (void)qtDispatcherToQAction:(id)sender
349 {
350  [[NSApp QT_MANGLE_NAMESPACE(qt_qcocoamenuLoader)] qtDispatcherToQAction:sender];
351 }
352 
353 @end
354 #endif
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
void qAddPostRoutine(QtCleanUpFunction p)
The QWidget class is the base class of all user interface objects.
Definition: qwidget.h:150
The QUrl class provides a convenient interface for working with URLs.
Definition: qurl.h:61
The QString class provides a Unicode character string.
Definition: qstring.h:83
QPointer< QWidget > qt_last_mouse_receiver
static QDesktopWidgetImplementation * instance()
static void quit()
Tells the application to exit with return code 0 (success).
#define QT_FORWARD_DECLARE_CLASS(name)
Definition: qglobal.h:95
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
QWidget * nativeParentWidget() const
Returns the native parent for this widget, i.
Definition: qwidget.cpp:4514
static QWidget * mouseGrabber()
Returns the widget that is currently grabbing the mouse input.
#define qApp
static bool init
QApplication * qAppInstance()
void onApplicationChangedActivation(bool activated)
#define QT_MANGLE_NAMESPACE(name)
Definition: qglobal.h:106
QPointer< QWidget > qt_last_native_mouse_receiver
bool qt_sendSpontaneousEvent(QObject *, QEvent *)
The QPoint class defines a point in the plane using integer precision.
Definition: qpoint.h:53
WId internalWinId() const
Returns the window system identifier of the widget, or 0 if the widget is not created yet...
Definition: qwidget.h:244
static void dispatchEnterLeave(QWidget *enter, QWidget *leave)
#define QT_USE_NAMESPACE
This macro expands to using QT_NAMESPACE if QT_NAMESPACE is defined and nothing otherwise.
Definition: qglobal.h:88
QWidget * qt_button_down
void qt_release_apple_event_handler()
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
static QString fileName(const QString &fileUrl)
qt_mac_getTargetForMouseEvent(event, QEvent::Gesture, qlocal, qglobal, 0, &widgetToGetTouch)
The QFileOpenEvent class provides an event that will be sent when there is a request to open a file o...
Definition: qevent.h:644