source: trunk/src/gui/kernel/qcocoawindowdelegate_mac.mm@ 677

Last change on this file since 677 was 651, checked in by Dmitry A. Kuminov, 16 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 14.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#import "private/qcocoawindowdelegate_mac_p.h"
43#ifdef QT_MAC_USE_COCOA
44#include <private/qwidget_p.h>
45#include <private/qapplication_p.h>
46#include <private/qt_cocoa_helpers_mac_p.h>
47#include <qevent.h>
48#include <qlayout.h>
49#include <qcoreapplication.h>
50#include <qmenubar.h>
51
52QT_BEGIN_NAMESPACE
53extern QWidgetData *qt_qwidget_data(QWidget *); // qwidget.cpp
54extern void onApplicationWindowChangedActivation(QWidget *, bool); //qapplication_mac.mm
55extern bool qt_sendSpontaneousEvent(QObject *, QEvent *); // qapplication.cpp
56QT_END_NAMESPACE
57
58QT_USE_NAMESPACE
59
60static QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) *sharedCocoaWindowDelegate = nil;
61
62// This is a singleton, but unlike most Cocoa singletons, it lives in a library and could be
63// pontentially loaded and unloaded. This means we should at least attempt to do the
64// memory management correctly.
65
66static void cleanupCocoaWindowDelegate()
67{
68 [sharedCocoaWindowDelegate release];
69}
70
71@implementation QT_MANGLE_NAMESPACE(QCocoaWindowDelegate)
72
73- (id)init
74{
75 self = [super init];
76 if (self != nil) {
77 m_windowHash = new QHash<NSWindow *, QWidget *>();
78 m_drawerHash = new QHash<NSDrawer *, QWidget *>();
79 }
80 return self;
81}
82
83- (void)dealloc
84{
85 sharedCocoaWindowDelegate = nil;
86 QHash<NSWindow *, QWidget *>::const_iterator windowIt = m_windowHash->constBegin();
87 while (windowIt != m_windowHash->constEnd()) {
88 [windowIt.key() setDelegate:nil];
89 ++windowIt;
90 }
91 delete m_windowHash;
92 QHash<NSDrawer *, QWidget *>::const_iterator drawerIt = m_drawerHash->constBegin();
93 while (drawerIt != m_drawerHash->constEnd()) {
94 [drawerIt.key() setDelegate:nil];
95 ++drawerIt;
96 }
97 delete m_drawerHash;
98 [super dealloc];
99}
100
101+ (id)allocWithZone:(NSZone *)zone
102{
103 @synchronized(self) {
104 if (sharedCocoaWindowDelegate == nil) {
105 sharedCocoaWindowDelegate = [super allocWithZone:zone];
106 return sharedCocoaWindowDelegate;
107 qAddPostRoutine(cleanupCocoaWindowDelegate);
108 }
109 }
110 return nil;
111}
112
113+ (QT_MANGLE_NAMESPACE(QCocoaWindowDelegate)*)sharedDelegate
114{
115 @synchronized(self) {
116 if (sharedCocoaWindowDelegate == nil)
117 [[self alloc] init];
118 }
119 return [[sharedCocoaWindowDelegate retain] autorelease];
120}
121
122-(void)syncSizeForWidget:(QWidget *)qwidget toSize:(const QSize &)newSize fromSize:(const QSize &)oldSize
123{
124 qt_qwidget_data(qwidget)->crect.setSize(newSize);
125 // ### static contents optimization needs to go here
126 const OSViewRef view = qt_mac_nativeview_for(qwidget);
127 [view setFrameSize:NSMakeSize(newSize.width(), newSize.height())];
128 if (!qwidget->isVisible()) {
129 qwidget->setAttribute(Qt::WA_PendingResizeEvent, true);
130 } else {
131 QResizeEvent qre(newSize, oldSize);
132 if (qwidget->testAttribute(Qt::WA_PendingResizeEvent)) {
133 qwidget->setAttribute(Qt::WA_PendingResizeEvent, false);
134 QApplication::sendEvent(qwidget, &qre);
135 } else {
136 qt_sendSpontaneousEvent(qwidget, &qre);
137 }
138 }
139}
140
141- (void)dumpMaximizedStateforWidget:(QWidget*)qwidget window:(NSWindow *)window;
142{
143 if (!window)
144 return; // Nothing to do.
145 QWidgetData *widgetData = qt_qwidget_data(qwidget);
146 if ((widgetData->window_state & Qt::WindowMaximized) && ![window isZoomed]) {
147 widgetData->window_state &= ~Qt::WindowMaximized;
148 QWindowStateChangeEvent e(Qt::WindowState(widgetData->window_state | Qt::WindowMaximized));
149 qt_sendSpontaneousEvent(qwidget, &e);
150 }
151}
152
153- (NSSize)closestAcceptableSizeForWidget:(QWidget *)qwidget window:(NSWindow *)window
154 withNewSize:(NSSize)proposedSize
155{
156 [self dumpMaximizedStateforWidget:qwidget window:window];
157 QSize newSize = QLayout::closestAcceptableSize(qwidget,
158 QSize(proposedSize.width, proposedSize.height));
159 return [NSWindow frameRectForContentRect:
160 NSMakeRect(0., 0., newSize.width(), newSize.height())
161 styleMask:[window styleMask]].size;
162}
163
164- (NSSize)windowWillResize:(NSWindow *)windowToResize toSize:(NSSize)proposedFrameSize
165{
166 QWidget *qwidget = m_windowHash->value(windowToResize);
167 return [self closestAcceptableSizeForWidget:qwidget window:windowToResize
168 withNewSize:[NSWindow contentRectForFrameRect:
169 NSMakeRect(0, 0,
170 proposedFrameSize.width,
171 proposedFrameSize.height)
172 styleMask:[windowToResize styleMask]].size];
173}
174
175- (NSSize)drawerWillResizeContents:(NSDrawer *)sender toSize:(NSSize)contentSize
176{
177 QWidget *qwidget = m_drawerHash->value(sender);
178 return [self closestAcceptableSizeForWidget:qwidget window:nil withNewSize:contentSize];
179}
180
181-(void)windowDidMiniaturize:(NSNotification*)notification
182{
183 QWidget *qwidget = m_windowHash->value([notification object]);
184 if (!qwidget->isMinimized()) {
185 QWidgetData *widgetData = qt_qwidget_data(qwidget);
186 widgetData->window_state = widgetData->window_state | Qt::WindowMinimized;
187 QWindowStateChangeEvent e(Qt::WindowStates(widgetData->window_state & ~Qt::WindowMinimized));
188 qt_sendSpontaneousEvent(qwidget, &e);
189 }
190 // Send hide to match Qt on X11 and Windows
191 QEvent e(QEvent::Hide);
192 qt_sendSpontaneousEvent(qwidget, &e);
193}
194
195- (void)windowDidResize:(NSNotification *)notification
196{
197 NSWindow *window = [notification object];
198 QWidget *qwidget = m_windowHash->value(window);
199 QWidgetData *widgetData = qt_qwidget_data(qwidget);
200 if (!(qwidget->windowState() & (Qt::WindowMaximized | Qt::WindowFullScreen)) && [window isZoomed]) {
201 widgetData->window_state = widgetData->window_state | Qt::WindowMaximized;
202 QWindowStateChangeEvent e(Qt::WindowStates(widgetData->window_state
203 & ~Qt::WindowMaximized));
204 qt_sendSpontaneousEvent(qwidget, &e);
205 }
206 NSRect rect = [[window contentView] frame];
207 const QSize newSize(rect.size.width, rect.size.height);
208 const QSize &oldSize = widgetData->crect.size();
209 if (newSize != oldSize) {
210 QWidgetPrivate::qt_mac_update_sizer(qwidget);
211 [self syncSizeForWidget:qwidget toSize:newSize fromSize:oldSize];
212 }
213}
214
215- (void)windowDidMove:(NSNotification *)notification
216{
217 // The code underneath needs to translate the window location
218 // from bottom left (which is the origin used by Cocoa) to
219 // upper left (which is the origin used by Qt):
220 NSWindow *window = [notification object];
221 NSRect newRect = [window frame];
222 QWidget *qwidget = m_windowHash->value(window);
223 QPoint qtPoint = flipPoint(NSMakePoint(newRect.origin.x,
224 newRect.origin.y + newRect.size.height)).toPoint();
225 const QRect &oldRect = qwidget->frameGeometry();
226
227 if (qtPoint.x() != oldRect.x() || qtPoint.y() != oldRect.y()) {
228 QWidgetData *widgetData = qt_qwidget_data(qwidget);
229 QRect oldCRect = widgetData->crect;
230 QWidgetPrivate *widgetPrivate = qt_widget_private(qwidget);
231 const QRect &fStrut = widgetPrivate->frameStrut();
232 widgetData->crect.moveTo(qtPoint.x() + fStrut.left(), qtPoint.y() + fStrut.top());
233 if (!qwidget->isVisible()) {
234 qwidget->setAttribute(Qt::WA_PendingMoveEvent, true);
235 } else {
236 QMoveEvent qme(qtPoint, oldRect.topLeft());
237 qt_sendSpontaneousEvent(qwidget, &qme);
238 }
239 }
240}
241
242-(BOOL)windowShouldClose:(id)windowThatWantsToClose
243{
244 QWidget *qwidget = m_windowHash->value(windowThatWantsToClose);
245 QScopedLoopLevelCounter counter(qt_widget_private(qwidget)->threadData);
246 return qt_widget_private(qwidget)->close_helper(QWidgetPrivate::CloseWithSpontaneousEvent);
247}
248
249-(void)windowDidDeminiaturize:(NSNotification *)notification
250{
251 QWidget *qwidget = m_windowHash->value([notification object]);
252 QWidgetData *widgetData = qt_qwidget_data(qwidget);
253 Qt::WindowStates currState = Qt::WindowStates(widgetData->window_state);
254 Qt::WindowStates newState = currState;
255 if (currState & Qt::WindowMinimized)
256 newState &= ~Qt::WindowMinimized;
257 if (!(currState & Qt::WindowActive))
258 newState |= Qt::WindowActive;
259 if (newState != currState) {
260 widgetData->window_state = newState;
261 QWindowStateChangeEvent e(currState);
262 qt_sendSpontaneousEvent(qwidget, &e);
263 }
264 QShowEvent qse;
265 qt_sendSpontaneousEvent(qwidget, &qse);
266}
267
268-(void)windowDidBecomeMain:(NSNotification*)notification
269{
270 QWidget *qwidget = m_windowHash->value([notification object]);
271 Q_ASSERT(qwidget);
272 if (qwidget->isActiveWindow())
273 return; // Widget is already active, no need to go through re-activation.
274
275 onApplicationWindowChangedActivation(qwidget, true);
276}
277
278-(void)windowDidResignMain:(NSNotification*)notification
279{
280 QWidget *qwidget = m_windowHash->value([notification object]);
281 Q_ASSERT(qwidget);
282 onApplicationWindowChangedActivation(qwidget, false);
283}
284
285// These are the same as main, but they are probably better to keep separate since there is a
286// tiny difference between main and key windows.
287-(void)windowDidBecomeKey:(NSNotification*)notification
288{
289 QWidget *qwidget = m_windowHash->value([notification object]);
290 Q_ASSERT(qwidget);
291 if (qwidget->isActiveWindow())
292 return; // Widget is already active, no need to go through re-activation
293
294
295 onApplicationWindowChangedActivation(qwidget, true);
296}
297
298-(void)windowDidResignKey:(NSNotification*)notification
299{
300 QWidget *qwidget = m_windowHash->value([notification object]);
301 Q_ASSERT(qwidget);
302 onApplicationWindowChangedActivation(qwidget, false);
303}
304
305-(QWidget *)qt_qwidgetForWindow:(NSWindow *)window
306{
307 return m_windowHash->value(window);
308}
309
310- (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame
311{
312 Q_UNUSED(newFrame);
313 // saving the current window geometry before the window is maximized
314 QWidget *qwidget = m_windowHash->value(window);
315 if (qwidget->isWindow() && !(qwidget->windowState() & Qt::WindowMaximized)) {
316 QWidgetPrivate *widgetPrivate = qt_widget_private(qwidget);
317 widgetPrivate->topData()->normalGeometry = qwidget->geometry();
318 }
319 return YES;
320}
321
322- (NSRect)windowWillUseStandardFrame:(NSWindow *)window defaultFrame:(NSRect)defaultFrame
323{
324 NSRect frameToReturn = defaultFrame;
325 QWidget *qwidget = m_windowHash->value(window);
326 QSizeF size = qwidget->maximumSize();
327 NSRect windowFrameRect = [window frame];
328 NSRect viewFrameRect = [[window contentView] frame];
329 // consider additional size required for titlebar & frame
330 frameToReturn.size.width = qMin<CGFloat>(frameToReturn.size.width,
331 size.width()+(windowFrameRect.size.width - viewFrameRect.size.width));
332 frameToReturn.size.height = qMin<CGFloat>(frameToReturn.size.height,
333 size.height()+(windowFrameRect.size.height - viewFrameRect.size.height));
334 return frameToReturn;
335}
336
337- (void)becomeDelegteForWindow:(NSWindow *)window widget:(QWidget *)widget
338{
339 m_windowHash->insert(window, widget);
340 [window setDelegate:self];
341}
342
343- (void)resignDelegateForWindow:(NSWindow *)window
344{
345 [window setDelegate:nil];
346 m_windowHash->remove(window);
347}
348
349- (void)becomeDelegateForDrawer:(NSDrawer *)drawer widget:(QWidget *)widget
350{
351 m_drawerHash->insert(drawer, widget);
352 [drawer setDelegate:self];
353 NSWindow *window = [[drawer contentView] window];
354 [self becomeDelegteForWindow:window widget:widget];
355}
356
357- (void)resignDelegateForDrawer:(NSDrawer *)drawer
358{
359 QWidget *widget = m_drawerHash->value(drawer);
360 [drawer setDelegate:nil];
361 if (widget)
362 [self resignDelegateForWindow:[[drawer contentView] window]];
363 m_drawerHash->remove(drawer);
364}
365
366- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu
367{
368 Q_UNUSED(menu);
369 QWidget *qwidget = m_windowHash->value(window);
370 if (qwidget && !qwidget->windowFilePath().isEmpty()) {
371 return YES;
372 }
373 return NO;
374}
375
376- (BOOL)window:(NSWindow *)window shouldDragDocumentWithEvent:(NSEvent *)event
377 from:(NSPoint)dragImageLocation
378 withPasteboard:(NSPasteboard *)pasteboard
379{
380 Q_UNUSED(event);
381 Q_UNUSED(dragImageLocation);
382 Q_UNUSED(pasteboard);
383 QWidget *qwidget = m_windowHash->value(window);
384 if (qwidget && !qwidget->windowFilePath().isEmpty()) {
385 return YES;
386 }
387 return NO;
388}
389@end
390#endif// QT_MAC_USE_COCOA
Note: See TracBrowser for help on using the repository browser.