source: trunk/src/gui/kernel/qwidget_mac.mm

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 199.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
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 qt-info@nokia.com.
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 <private/qt_mac_p.h>
77#include <private/qeventdispatcher_mac_p.h>
78
79#include "qapplication.h"
80#include "qapplication_p.h"
81#include "qbitmap.h"
82#include "qcursor.h"
83#include "qdesktopwidget.h"
84#include "qevent.h"
85#include "qfileinfo.h"
86#include "qimage.h"
87#include "qlayout.h"
88#include "qmenubar.h"
89#include <private/qbackingstore_p.h>
90#include <private/qwindowsurface_mac_p.h>
91#include <private/qpaintengine_mac_p.h>
92#include "qpainter.h"
93#include "qstyle.h"
94#include "qtimer.h"
95#include "qfocusframe.h"
96#include "qdebug.h"
97#include <private/qmainwindowlayout_p.h>
98
99#include <private/qabstractscrollarea_p.h>
100#include <qabstractscrollarea.h>
101#include <ApplicationServices/ApplicationServices.h>
102#include <limits.h>
103#include <private/qt_cocoa_helpers_mac_p.h>
104#include <private/qcocoaview_mac_p.h>
105#include <private/qcocoawindow_mac_p.h>
106#include <private/qcocoawindowdelegate_mac_p.h>
107#include <private/qcocoapanel_mac_p.h>
108
109#include "qwidget_p.h"
110#include "qevent_p.h"
111#include "qdnd_p.h"
112#include <QtGui/qgraphicsproxywidget.h>
113#include "qmainwindow.h"
114
115QT_BEGIN_NAMESPACE
116
117// qmainwindow.cpp
118extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *window);
119
120#define XCOORD_MAX 16383
121#define WRECT_MAX 8191
122
123#ifndef QT_MAC_USE_COCOA
124
125extern "C" {
126 extern OSStatus _HIViewScrollRectWithOptions(HIViewRef, const HIRect *, CGFloat, CGFloat,
127 OptionBits) __attribute__ ((weak));
128}
129#define kHIViewScrollRectAdjustInvalid 1
130#define kHIViewScrollRectDontInvalidateRevealedArea 2
131#endif
132
133
134/*****************************************************************************
135 QWidget debug facilities
136 *****************************************************************************/
137//#define DEBUG_WINDOW_RGNS
138//#define DEBUG_WINDOW_CREATE
139//#define DEBUG_WINDOW_STATE
140//#define DEBUG_WIDGET_PAINT
141
142/*****************************************************************************
143 QWidget globals
144 *****************************************************************************/
145#ifndef QT_MAC_USE_COCOA
146typedef QHash<Qt::WindowFlags, WindowGroupRef> WindowGroupHash;
147Q_GLOBAL_STATIC(WindowGroupHash, qt_mac_window_groups)
148const UInt32 kWidgetCreatorQt = kEventClassQt;
149enum {
150 kWidgetPropertyQWidget = 'QWId' //QWidget *
151};
152#endif
153
154static bool qt_mac_raise_process = true;
155static OSWindowRef qt_root_win = 0;
156QWidget *mac_mouse_grabber = 0;
157QWidget *mac_keyboard_grabber = 0;
158extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp
159
160#ifndef QT_MAC_USE_COCOA
161#ifdef QT_NAMESPACE
162
163// produce the string "com.trolltech.qt-namespace.widget", where "namespace" is the contents of QT_NAMESPACE.
164#define SS(x) #x
165#define S0(x) SS(x)
166#define S "com.trolltech.qt-" S0(QT_NAMESPACE) ".widget"
167
168static CFStringRef kObjectQWidget = CFSTR(S);
169
170#undef SS
171#undef S0
172#undef S
173
174#else
175static CFStringRef kObjectQWidget = CFSTR("com.trolltech.qt.widget");
176#endif // QT_NAMESPACE
177#endif // QT_MAC_USE_COCOA
178
179/*****************************************************************************
180 Externals
181 *****************************************************************************/
182extern QWidget *qt_mac_modal_blocked(QWidget *); //qapplication_mac.mm
183extern void qt_event_request_activate(QWidget *); //qapplication_mac.mm
184extern bool qt_event_remove_activate(); //qapplication_mac.mm
185extern void qt_mac_event_release(QWidget *w); //qapplication_mac.mm
186extern void qt_event_request_showsheet(QWidget *); //qapplication_mac.mm
187extern void qt_event_request_window_change(QWidget *); //qapplication_mac.mm
188extern QPointer<QWidget> qt_mouseover; //qapplication_mac.mm
189extern IconRef qt_mac_create_iconref(const QPixmap &); //qpixmap_mac.cpp
190extern void qt_mac_set_cursor(const QCursor *, const QPoint &); //qcursor_mac.mm
191extern void qt_mac_update_cursor(); //qcursor_mac.mm
192extern bool qt_nograb();
193extern CGImageRef qt_mac_create_cgimage(const QPixmap &, bool); //qpixmap_mac.cpp
194extern RgnHandle qt_mac_get_rgn(); //qregion_mac.cpp
195extern QRegion qt_mac_convert_mac_region(RgnHandle rgn); //qregion_mac.cpp
196
197/*****************************************************************************
198 QWidget utility functions
199 *****************************************************************************/
200void Q_GUI_EXPORT qt_mac_set_raise_process(bool b) { qt_mac_raise_process = b; }
201static QSize qt_mac_desktopSize()
202{
203 int w = 0, h = 0;
204 CGDisplayCount cg_count;
205 CGGetActiveDisplayList(0, 0, &cg_count);
206 QVector<CGDirectDisplayID> displays(cg_count);
207 CGGetActiveDisplayList(cg_count, displays.data(), &cg_count);
208 Q_ASSERT(cg_count == (CGDisplayCount)displays.size());
209 for(int i = 0; i < (int)cg_count; ++i) {
210 CGRect r = CGDisplayBounds(displays.at(i));
211 w = qMax<int>(w, qRound(r.origin.x + r.size.width));
212 h = qMax<int>(h, qRound(r.origin.y + r.size.height));
213 }
214 return QSize(w, h);
215}
216
217#ifdef QT_MAC_USE_COCOA
218static NSDrawer *qt_mac_drawer_for(const QWidget *widget)
219{
220 // This only goes one level below the content view so start with the window.
221 // This works fine for straight Qt stuff, but runs into problems if we are
222 // embedding, but if that's the case, they probably want to be using
223 // NSDrawer directly.
224 NSView *widgetView = reinterpret_cast<NSView *>(widget->window()->winId());
225 NSArray *windows = [NSApp windows];
226 for (NSWindow *window in windows) {
227 NSArray *drawers = [window drawers];
228 for (NSDrawer *drawer in drawers) {
229 NSArray *views = [[drawer contentView] subviews];
230 for (NSView *view in views) {
231 if (view == widgetView)
232 return drawer;
233 }
234 }
235 }
236 return 0;
237}
238#endif
239
240static void qt_mac_destructView(OSViewRef view)
241{
242#ifdef QT_MAC_USE_COCOA
243 [view removeFromSuperview];
244 [view release];
245#else
246 HIViewRemoveFromSuperview(view);
247 CFRelease(view);
248#endif
249}
250
251static void qt_mac_destructWindow(OSWindowRef window)
252{
253#ifdef QT_MAC_USE_COCOA
254 if ([window isVisible] && [window isSheet]){
255 [NSApp endSheet:window];
256 [window orderOut:window];
257 }
258
259 [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] resignDelegateForWindow:window];
260 [window release];
261#else
262 // Remove property to clean up memory:
263 RemoveWindowProperty(window, kWidgetCreatorQt, kWidgetPropertyQWidget);
264 CFRelease(window);
265#endif
266}
267
268static void qt_mac_destructDrawer(NSDrawer *drawer)
269{
270#ifdef QT_MAC_USE_COCOA
271 [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] resignDelegateForDrawer:drawer];
272 [drawer release];
273#else
274 Q_UNUSED(drawer);
275#endif
276}
277
278bool qt_mac_can_clickThrough(const QWidget *w)
279{
280 static int qt_mac_carbon_clickthrough = -1;
281 if (qt_mac_carbon_clickthrough < 0)
282 qt_mac_carbon_clickthrough = !qgetenv("QT_MAC_NO_COCOA_CLICKTHROUGH").isEmpty();
283 bool ret = !qt_mac_carbon_clickthrough;
284 for ( ; w; w = w->parentWidget()) {
285 if (w->testAttribute(Qt::WA_MacNoClickThrough)) {
286 ret = false;
287 break;
288 }
289 }
290 return ret;
291}
292
293bool qt_mac_is_macsheet(const QWidget *w)
294{
295 if (!w)
296 return false;
297
298 Qt::WindowModality modality = w->windowModality();
299 if (modality == Qt::ApplicationModal)
300 return false;
301 return w->parentWidget() && (modality == Qt::WindowModal || w->windowType() == Qt::Sheet);
302}
303
304bool qt_mac_is_macdrawer(const QWidget *w)
305{
306 return (w && w->parentWidget() && w->windowType() == Qt::Drawer);
307}
308
309bool qt_mac_insideKeyWindow(const QWidget *w)
310{
311#ifdef QT_MAC_USE_COCOA
312 return [[reinterpret_cast<NSView *>(w->winId()) window] isKeyWindow];
313#else
314 Q_UNUSED(w);
315#endif
316 return false;
317}
318
319bool qt_mac_set_drawer_preferred_edge(QWidget *w, Qt::DockWidgetArea where) //users of Qt for Mac OS X can use this..
320{
321 if(!qt_mac_is_macdrawer(w))
322 return false;
323
324#if QT_MAC_USE_COCOA
325 NSDrawer *drawer = qt_mac_drawer_for(w);
326 if (!drawer)
327 return false;
328 NSRectEdge edge;
329 if (where & Qt::LeftDockWidgetArea)
330 edge = NSMinXEdge;
331 else if (where & Qt::RightDockWidgetArea)
332 edge = NSMaxXEdge;
333 else if (where & Qt::TopDockWidgetArea)
334 edge = NSMaxYEdge;
335 else if (where & Qt::BottomDockWidgetArea)
336 edge = NSMinYEdge;
337 else
338 return false;
339
340 if (edge == [drawer preferredEdge]) //no-op
341 return false;
342
343 if (w->isVisible()) {
344 [drawer close];
345 [drawer openOnEdge:edge];
346 }
347 [drawer setPreferredEdge:edge];
348#else
349 OSWindowRef window = qt_mac_window_for(w);
350 OptionBits edge;
351 if(where & Qt::LeftDockWidgetArea)
352 edge = kWindowEdgeLeft;
353 else if(where & Qt::RightDockWidgetArea)
354 edge = kWindowEdgeRight;
355 else if(where & Qt::TopDockWidgetArea)
356 edge = kWindowEdgeTop;
357 else if(where & Qt::BottomDockWidgetArea)
358 edge = kWindowEdgeBottom;
359 else
360 return false;
361
362 if(edge == GetDrawerPreferredEdge(window)) //no-op
363 return false;
364
365 //do it
366 SetDrawerPreferredEdge(window, edge);
367 if(w->isVisible()) {
368 CloseDrawer(window, false);
369 OpenDrawer(window, edge, true);
370 }
371#endif
372 return true;
373}
374
375#ifndef QT_MAC_USE_COCOA
376Q_GUI_EXPORT
377#endif
378QPoint qt_mac_posInWindow(const QWidget *w)
379{
380 QPoint ret = w->data->wrect.topLeft();
381 while(w && !w->isWindow()) {
382 ret += w->pos();
383 w = w->parentWidget();
384 }
385 return ret;
386}
387
388//find a QWidget from a OSWindowRef
389QWidget *qt_mac_find_window(OSWindowRef window)
390{
391#ifdef QT_MAC_USE_COCOA
392 return [window QT_MANGLE_NAMESPACE(qt_qwidget)];
393#else
394 if(!window)
395 return 0;
396
397 QWidget *ret;
398 if(GetWindowProperty(window, kWidgetCreatorQt, kWidgetPropertyQWidget, sizeof(ret), 0, &ret) == noErr)
399 return ret;
400 return 0;
401#endif
402}
403
404inline static void qt_mac_set_fullscreen_mode(bool b)
405{
406 extern bool qt_mac_app_fullscreen; //qapplication_mac.mm
407 if(qt_mac_app_fullscreen == b)
408 return;
409 qt_mac_app_fullscreen = b;
410 if (b) {
411 SetSystemUIMode(kUIModeAllHidden, kUIOptionAutoShowMenuBar);
412 } else {
413 SetSystemUIMode(kUIModeNormal, 0);
414 }
415}
416
417Q_GUI_EXPORT OSViewRef qt_mac_nativeview_for(const QWidget *w)
418{
419 return reinterpret_cast<OSViewRef>(w->data->winid);
420}
421
422Q_GUI_EXPORT OSViewRef qt_mac_get_contentview_for(OSWindowRef w)
423{
424#ifdef QT_MAC_USE_COCOA
425 return [w contentView];
426#else
427 HIViewRef contentView = 0;
428 OSStatus err = GetRootControl(w, &contentView); // Returns the window's content view (Apple QA1214)
429 if (err == errUnknownControl) {
430 contentView = HIViewGetRoot(w);
431 } else if (err != noErr) {
432 qWarning("Qt:Could not get content or root view of window! %s:%d [%ld]",
433 __FILE__, __LINE__, err);
434 }
435 return contentView;
436#endif
437}
438
439bool qt_mac_sendMacEventToWidget(QWidget *widget, EventRef ref)
440{
441 return widget->macEvent(0, ref);
442}
443
444Q_GUI_EXPORT OSWindowRef qt_mac_window_for(OSViewRef view)
445{
446#ifdef QT_MAC_USE_COCOA
447 if (view)
448 return [view window];
449 return 0;
450#else
451 return HIViewGetWindow(view);
452#endif
453}
454
455static bool qt_isGenuineQWidget(OSViewRef ref)
456{
457#ifdef QT_MAC_USE_COCOA
458 return [ref isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaView) class]];
459#else
460 return HIObjectIsOfClass(HIObjectRef(ref), kObjectQWidget);
461#endif
462}
463
464bool qt_isGenuineQWidget(const QWidget *window)
465{
466 if (!window)
467 return false;
468
469 if (!window->internalWinId())
470 return true; //alien
471
472 return qt_isGenuineQWidget(OSViewRef(window->internalWinId()));
473}
474
475Q_GUI_EXPORT OSWindowRef qt_mac_window_for(const QWidget *w)
476{
477 OSViewRef hiview = qt_mac_nativeview_for(w);
478 if (hiview){
479 OSWindowRef window = qt_mac_window_for(hiview);
480 if (!window && qt_isGenuineQWidget(hiview)) {
481 QWidget *myWindow = w->window();
482 // This is a workaround for NSToolbar. When a widget is hidden
483 // by clicking the toolbar button, Cocoa reparents the widgets
484 // to another window (but Qt doesn't know about it).
485 // When we start showing them, it reparents back,
486 // but at this point it's window is nil, but the window it's being brought
487 // into (the Qt one) is for sure created.
488 // This stops the hierarchy moving under our feet.
489 if (myWindow != w && qt_mac_window_for(qt_mac_nativeview_for(myWindow)))
490 return qt_mac_window_for(qt_mac_nativeview_for(myWindow));
491
492 myWindow->d_func()->createWindow_sys();
493 // Reget the hiview since the "create window could potentially move the view (I guess).
494 hiview = qt_mac_nativeview_for(w);
495 window = qt_mac_window_for(hiview);
496 }
497 return window;
498 }
499 return 0;
500}
501#ifndef QT_MAC_USE_COCOA
502/* Checks if the current group is a 'stay on top' group. If so, the
503 group gets removed from the hash table */
504static void qt_mac_release_stays_on_top_group(WindowGroupRef group)
505{
506 for (WindowGroupHash::iterator it = qt_mac_window_groups()->begin(); it != qt_mac_window_groups()->end(); ++it) {
507 if (it.value() == group) {
508 qt_mac_window_groups()->remove(it.key());
509 return;
510 }
511 }
512}
513
514/* Use this function instead of ReleaseWindowGroup, this will be sure to release the
515 stays on top window group (created with qt_mac_get_stays_on_top_group below) */
516static void qt_mac_release_window_group(WindowGroupRef group)
517{
518 ReleaseWindowGroup(group);
519 if (GetWindowGroupRetainCount(group) == 0)
520 qt_mac_release_stays_on_top_group(group);
521}
522#define ReleaseWindowGroup(x) Are you sure you wanted to do that? (you wanted qt_mac_release_window_group)
523
524SInt32 qt_mac_get_group_level(WindowClass wclass)
525{
526 SInt32 group_level;
527 CGWindowLevel tmpLevel;
528 GetWindowGroupLevelOfType(GetWindowGroupOfClass(wclass), kWindowGroupLevelActive, &tmpLevel);
529 group_level = tmpLevel;
530 return group_level;
531}
532#endif
533
534#ifndef QT_MAC_USE_COCOA
535static void qt_mac_set_window_group(OSWindowRef window, Qt::WindowFlags flags, int level)
536{
537 WindowGroupRef group = 0;
538 if (qt_mac_window_groups()->contains(flags)) {
539 group = qt_mac_window_groups()->value(flags);
540 RetainWindowGroup(group);
541 } else {
542 CreateWindowGroup(kWindowActivationScopeNone, &group);
543 SetWindowGroupLevel(group, level);
544 SetWindowGroupParent(group, GetWindowGroupOfClass(kAllWindowClasses));
545 qt_mac_window_groups()->insert(flags, group);
546 }
547 SetWindowGroup(window, group);
548}
549
550inline static void qt_mac_set_window_group_to_stays_on_top(OSWindowRef window, Qt::WindowType type)
551{
552 // We create one static stays on top window group so that
553 // all stays on top (aka popups) will fall into the same
554 // group and be able to be raise()'d with releation to one another (from
555 // within the same window group).
556 qt_mac_set_window_group(window, type|Qt::WindowStaysOnTopHint, qt_mac_get_group_level(kOverlayWindowClass));
557}
558
559inline static void qt_mac_set_window_group_to_tooltip(OSWindowRef window)
560{
561 // Since new groups are created for 'stays on top' windows, the
562 // same must be done for tooltips. Otherwise, tooltips would be drawn
563 // below 'stays on top' widgets even tough they are on the same level.
564 // Also, add 'two' to the group level to make sure they also get on top of popups.
565 qt_mac_set_window_group(window, Qt::ToolTip, qt_mac_get_group_level(kHelpWindowClass)+2);
566}
567
568inline static void qt_mac_set_window_group_to_popup(OSWindowRef window)
569{
570 // In Qt, a popup is seen as a 'stay on top' window.
571 // Since new groups are created for 'stays on top' windows, the
572 // same must be done for popups. Otherwise, popups would be drawn
573 // below 'stays on top' windows. Add 1 to get above pure stay-on-top windows.
574 qt_mac_set_window_group(window, Qt::Popup, qt_mac_get_group_level(kOverlayWindowClass)+1);
575}
576#endif
577
578#ifdef QT_MAC_USE_COCOA
579void qt_mac_set_needs_display(QWidget *widget, QRegion region)
580{
581 NSView *theNSView = qt_mac_nativeview_for(widget);
582 if (region.isEmpty()) {
583 [theNSView setNeedsDisplay:YES];
584 return;
585 }
586
587 QVector<QRect> rects = region.rects();
588 for (int i = 0; i<rects.count(); ++i) {
589 const QRect &rect = rects.at(i);
590 NSRect nsrect = NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height());
591 [theNSView setNeedsDisplayInRect:nsrect];
592 }
593
594}
595#endif
596
597inline static bool updateRedirectedToGraphicsProxyWidget(QWidget *widget, const QRect &rect)
598{
599 if (!widget)
600 return false;
601
602#ifndef QT_NO_GRAPHICSVIEW
603 QWidget *tlw = widget->window();
604 QWExtra *extra = qt_widget_private(tlw)->extra;
605 if (extra && extra->proxyWidget) {
606 extra->proxyWidget->update(rect.translated(widget->mapTo(tlw, QPoint())));
607 return true;
608 }
609#endif
610
611 return false;
612}
613
614inline static bool updateRedirectedToGraphicsProxyWidget(QWidget *widget, const QRegion &rgn)
615{
616 if (!widget)
617 return false;
618
619#ifndef QT_NO_GRAPHICSVIEW
620 QWidget *tlw = widget->window();
621 QWExtra *extra = qt_widget_private(tlw)->extra;
622 if (extra && extra->proxyWidget) {
623 const QPoint offset(widget->mapTo(tlw, QPoint()));
624 const QVector<QRect> rects = rgn.rects();
625 for (int i = 0; i < rects.size(); ++i)
626 extra->proxyWidget->update(rects.at(i).translated(offset));
627 return true;
628 }
629#endif
630
631 return false;
632}
633
634void QWidgetPrivate::macUpdateIsOpaque()
635{
636 Q_Q(QWidget);
637 if (!q->testAttribute(Qt::WA_WState_Created))
638 return;
639#ifndef QT_MAC_USE_COCOA
640 HIViewFeatures bits;
641 HIViewRef hiview = qt_mac_nativeview_for(q);
642 HIViewGetFeatures(hiview, &bits);
643 if ((bits & kHIViewIsOpaque) == isOpaque)
644 return;
645 if (isOpaque) {
646 HIViewChangeFeatures(hiview, kHIViewIsOpaque, 0);
647 } else {
648 HIViewChangeFeatures(hiview, 0, kHIViewIsOpaque);
649 }
650 if (q->isVisible())
651 HIViewReshapeStructure(qt_mac_nativeview_for(q));
652#else
653 if (isRealWindow() && !q->testAttribute(Qt::WA_MacBrushedMetal)) {
654 bool opaque = isOpaque;
655 if (extra && extra->imageMask)
656 opaque = false; // we are never opaque when we have a mask.
657 [qt_mac_window_for(q) setOpaque:opaque];
658 }
659#endif
660}
661#ifdef QT_MAC_USE_COCOA
662static OSWindowRef qt_mac_create_window(QWidget *widget, WindowClass wclass,
663 NSUInteger wattr, const QRect &crect)
664{
665 // Determine if we need to add in our "custom window" attribute. Cocoa is rather clever
666 // in deciding if we need the maximize button or not (i.e., it's resizeable, so you
667 // must need a maximize button). So, the only buttons we have control over are the
668 // close and minimize buttons. If someone wants to customize and NOT have the maximize
669 // button, then we have to do our hack. We only do it for these cases because otherwise
670 // the window looks different when activated. This "QtMacCustomizeWindow" attribute is
671 // intruding on a public space and WILL BREAK in the future.
672 // One can hope that there is a more public API available by that time.
673 Qt::WindowFlags flags = widget ? widget->windowFlags() : Qt::WindowFlags(0);
674 if ((flags & Qt::CustomizeWindowHint)) {
675 if ((flags & (Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint
676 | Qt::WindowMinimizeButtonHint | Qt::WindowTitleHint))
677 && !(flags & Qt::WindowMaximizeButtonHint))
678 wattr |= QtMacCustomizeWindow;
679 }
680
681 // If we haven't created the desktop widget, you have to pass the rectangle
682 // in "cocoa coordinates" (i.e., top points to the lower left coordinate).
683 // Otherwise, we do the conversion for you. Since we are the only ones that
684 // create the desktop widget, this is OK (but confusing).
685 NSRect geo = NSMakeRect(crect.left(),
686 (qt_root_win != 0) ? flipYCoordinate(crect.bottom() + 1) : crect.top(),
687 crect.width(), crect.height());
688 QMacCocoaAutoReleasePool pool;
689 OSWindowRef window;
690 switch (wclass) {
691 case kMovableModalWindowClass:
692 case kModalWindowClass:
693 case kSheetWindowClass:
694 case kFloatingWindowClass:
695 case kOverlayWindowClass:
696 case kHelpWindowClass: {
697 NSPanel *panel;
698 BOOL needFloating = NO;
699 BOOL worksWhenModal = widget && (widget->windowType() == Qt::Popup);
700 // Add in the extra flags if necessary.
701 switch (wclass) {
702 case kSheetWindowClass:
703 wattr |= NSDocModalWindowMask;
704 break;
705 case kFloatingWindowClass:
706 case kHelpWindowClass:
707 needFloating = YES;
708 wattr |= NSUtilityWindowMask;
709 break;
710 default:
711 break;
712 }
713 panel = [[QT_MANGLE_NAMESPACE(QCocoaPanel) alloc] QT_MANGLE_NAMESPACE(qt_initWithQWidget):widget contentRect:geo styleMask:wattr];
714 [panel setFloatingPanel:needFloating];
715 [panel setWorksWhenModal:worksWhenModal];
716 window = panel;
717 break;
718 }
719 case kDrawerWindowClass: {
720 NSDrawer *drawer = [[NSDrawer alloc] initWithContentSize:geo.size preferredEdge:NSMinXEdge];
721 [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] becomeDelegateForDrawer:drawer widget:widget];
722 QWidget *parentWidget = widget->parentWidget();
723 if (parentWidget)
724 [drawer setParentWindow:qt_mac_window_for(parentWidget)];
725 [drawer setLeadingOffset:0.0];
726 [drawer setTrailingOffset:25.0];
727 window = [[drawer contentView] window]; // Just to make sure we actually return a window
728 break;
729 }
730 default:
731 window = [[QT_MANGLE_NAMESPACE(QCocoaWindow) alloc] QT_MANGLE_NAMESPACE(qt_initWithQWidget):widget contentRect:geo styleMask:wattr];
732 break;
733 }
734 qt_syncCocoaTitleBarButtons(window, widget);
735 return window;
736}
737#else
738static OSWindowRef qt_mac_create_window(QWidget *, WindowClass wclass, WindowAttributes wattr,
739 const QRect &crect)
740{
741 OSWindowRef window;
742 Rect geo;
743 SetRect(&geo, crect.left(), crect.top(), crect.right() + 1, crect.bottom() + 1);
744 OSStatus err;
745 if(geo.right <= geo.left) geo.right = geo.left + 1;
746 if(geo.bottom <= geo.top) geo.bottom = geo.top + 1;
747 Rect null_rect;
748 SetRect(&null_rect, 0, 0, 1, 1);
749 err = CreateNewWindow(wclass, wattr, &null_rect, &window);
750 if(err == noErr) {
751 err = SetWindowBounds(window, kWindowContentRgn, &geo);
752 if(err != noErr)
753 qWarning("QWidget: Internal error (%s:%d)", __FILE__, __LINE__);
754 }
755 return window;
756}
757
758#ifndef QT_NO_GESTURES
759#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
760/* We build the release package against the 10.4 SDK.
761 So, to enable gestures for applications running on
762 10.6+, we define the missing constants here: */
763enum {
764 kEventClassGesture = 'gest',
765 kEventGestureStarted = 1,
766 kEventGestureEnded = 2,
767 kEventGestureMagnify = 4,
768 kEventGestureSwipe = 5,
769 kEventGestureRotate = 6,
770 kEventParamRotationAmount = 'rota',
771 kEventParamSwipeDirection = 'swip',
772 kEventParamMagnificationAmount = 'magn'
773};
774#endif
775#endif // QT_NO_GESTURES
776
777// window events
778static EventTypeSpec window_events[] = {
779 { kEventClassWindow, kEventWindowClose },
780 { kEventClassWindow, kEventWindowExpanded },
781 { kEventClassWindow, kEventWindowHidden },
782 { kEventClassWindow, kEventWindowZoom },
783 { kEventClassWindow, kEventWindowZoomed },
784 { kEventClassWindow, kEventWindowCollapsed },
785 { kEventClassWindow, kEventWindowToolbarSwitchMode },
786 { kEventClassWindow, kEventWindowProxyBeginDrag },
787 { kEventClassWindow, kEventWindowProxyEndDrag },
788 { kEventClassWindow, kEventWindowResizeCompleted },
789 { kEventClassWindow, kEventWindowBoundsChanging },
790 { kEventClassWindow, kEventWindowGetRegion },
791 { kEventClassWindow, kEventWindowGetClickModality },
792 { kEventClassWindow, kEventWindowTransitionCompleted },
793 { kEventClassGesture, kEventGestureStarted },
794 { kEventClassGesture, kEventGestureEnded },
795 { kEventClassGesture, kEventGestureMagnify },
796 { kEventClassGesture, kEventGestureSwipe },
797 { kEventClassGesture, kEventGestureRotate },
798 { kEventClassMouse, kEventMouseDown }
799};
800static EventHandlerUPP mac_win_eventUPP = 0;
801static void cleanup_win_eventUPP()
802{
803 DisposeEventHandlerUPP(mac_win_eventUPP);
804 mac_win_eventUPP = 0;
805}
806static const EventHandlerUPP make_win_eventUPP()
807{
808 if(mac_win_eventUPP)
809 return mac_win_eventUPP;
810 qAddPostRoutine(cleanup_win_eventUPP);
811 return mac_win_eventUPP = NewEventHandlerUPP(QWidgetPrivate::qt_window_event);
812}
813OSStatus QWidgetPrivate::qt_window_event(EventHandlerCallRef er, EventRef event, void *)
814{
815 QScopedLoopLevelCounter loopLevelCounter(qApp->d_func()->threadData);
816 bool handled_event = true;
817 UInt32 ekind = GetEventKind(event), eclass = GetEventClass(event);
818 switch(eclass) {
819 case kEventClassWindow: {
820 WindowRef wid = 0;
821 GetEventParameter(event, kEventParamDirectObject, typeWindowRef, 0,
822 sizeof(WindowRef), 0, &wid);
823 QWidget *widget = qt_mac_find_window(wid);
824 if(!widget) {
825 handled_event = false;
826 } else if(ekind == kEventWindowGetClickModality) {
827 // Carbon will send us kEventWindowGetClickModality before every
828 // mouse press / release event. By returning 'true', we tell Carbon
829 // that we would like the event target to receive the mouse event even
830 // if the target is modally shaddowed. In Qt, this makes sense when we
831 // e.g. have a popup showing, as the popup will grab the event
832 // and perhaps use it to close itself.
833 // By also setting the current modal window back into the event, we
834 // help Carbon determining which window is supposed to be raised.
835 handled_event = qApp->activePopupWidget() ? true : false;
836 } else if(ekind == kEventWindowClose) {
837 widget->d_func()->close_helper(QWidgetPrivate::CloseWithSpontaneousEvent);
838 QMenuBar::macUpdateMenuBar();
839 } else if (ekind == kEventWindowTransitionCompleted) {
840 WindowTransitionAction transitionAction;
841 GetEventParameter(event, kEventParamWindowTransitionAction, typeWindowTransitionAction,
842 0, sizeof(transitionAction), 0, &transitionAction);
843 if (transitionAction == kWindowHideTransitionAction)
844 widget->hide();
845 } else if(ekind == kEventWindowExpanded) {
846 Qt::WindowStates currState = Qt::WindowStates(widget->data->window_state);
847 Qt::WindowStates newState = currState;
848 if (currState & Qt::WindowMinimized)
849 newState &= ~Qt::WindowMinimized;
850 if (!(currState & Qt::WindowActive))
851 newState |= Qt::WindowActive;
852 if (newState != currState) {
853 // newState will differ from currState if the window
854 // was expanded after clicking on the jewels (as opposed
855 // to calling QWidget::setWindowState)
856 widget->data->window_state = newState;
857 QWindowStateChangeEvent e(currState);
858 QApplication::sendSpontaneousEvent(widget, &e);
859 }
860
861 QShowEvent qse;
862 QApplication::sendSpontaneousEvent(widget, &qse);
863 } else if(ekind == kEventWindowZoom) {
864 widget->d_func()->topData()->normalGeometry = widget->geometry();
865 handled_event = false;
866 } else if(ekind == kEventWindowZoomed) {
867 WindowPartCode windowPart;
868 GetEventParameter(event, kEventParamWindowPartCode,
869 typeWindowPartCode, 0, sizeof(windowPart), 0, &windowPart);
870 if(windowPart == inZoomIn && widget->isMaximized()) {
871
872 widget->data->window_state = widget->data->window_state & ~Qt::WindowMaximized;
873 QWindowStateChangeEvent e(Qt::WindowStates(widget->data->window_state | Qt::WindowMaximized));
874 QApplication::sendSpontaneousEvent(widget, &e);
875 } else if(windowPart == inZoomOut && !widget->isMaximized()) {
876 widget->data->window_state = widget->data->window_state | Qt::WindowMaximized;
877 QWindowStateChangeEvent e(Qt::WindowStates(widget->data->window_state
878 & ~Qt::WindowMaximized));
879 QApplication::sendSpontaneousEvent(widget, &e);
880 }
881 qt_button_down = 0;
882 } else if(ekind == kEventWindowCollapsed) {
883 if (!widget->isMinimized()) {
884 widget->data->window_state = widget->data->window_state | Qt::WindowMinimized;
885 QWindowStateChangeEvent e(Qt::WindowStates(widget->data->window_state & ~Qt::WindowMinimized));
886 QApplication::sendSpontaneousEvent(widget, &e);
887 }
888
889 // Deactivate this window:
890 if (widget->isActiveWindow() && !(widget->windowType() == Qt::Popup)) {
891 QWidget *w = 0;
892 if (widget->parentWidget())
893 w = widget->parentWidget()->window();
894 if (!w || (!w->isVisible() && !w->isMinimized())) {
895 for (WindowPtr wp = GetFrontWindowOfClass(kDocumentWindowClass, true);
896 wp; wp = GetNextWindowOfClass(wp, kDocumentWindowClass, true)) {
897 if ((w = qt_mac_find_window(wp)))
898 break;
899 }
900 }
901 if(!(w && w->isVisible() && !w->isMinimized()))
902 qApp->setActiveWindow(0);
903 }
904
905 //we send a hide to be like X11/Windows
906 QEvent e(QEvent::Hide);
907 QApplication::sendSpontaneousEvent(widget, &e);
908 qt_button_down = 0;
909 } else if(ekind == kEventWindowToolbarSwitchMode) {
910 macSendToolbarChangeEvent(widget);
911 HIToolbarRef toolbar;
912 if (GetWindowToolbar(wid, &toolbar) == noErr) {
913 if (toolbar) {
914 // Let HIToolbar do its thang, but things like the OpenGL context
915 // needs to know about it.
916 CallNextEventHandler(er, event);
917 qt_event_request_window_change(widget);
918 widget->data->fstrut_dirty = true;
919 }
920 }
921 } else if(ekind == kEventWindowGetRegion) {
922 WindowRef window;
923 GetEventParameter(event, kEventParamDirectObject, typeWindowRef, 0,
924 sizeof(window), 0, &window);
925 WindowRegionCode wcode;
926 GetEventParameter(event, kEventParamWindowRegionCode, typeWindowRegionCode, 0,
927 sizeof(wcode), 0, &wcode);
928 if (wcode != kWindowOpaqueRgn){
929 // If the region is kWindowOpaqueRgn, don't call next
930 // event handler cause this will make the shadow of
931 // masked windows become offset. Unfortunately, we're not sure why.
932 CallNextEventHandler(er, event);
933 }
934 RgnHandle rgn;
935 GetEventParameter(event, kEventParamRgnHandle, typeQDRgnHandle, 0,
936 sizeof(rgn), 0, &rgn);
937
938 if(QWidgetPrivate::qt_widget_rgn(qt_mac_find_window(window), wcode, rgn, false))
939 SetEventParameter(event, kEventParamRgnHandle, typeQDRgnHandle, sizeof(rgn), &rgn);
940 } else if(ekind == kEventWindowProxyBeginDrag) {
941 QIconDragEvent e;
942 QApplication::sendSpontaneousEvent(widget, &e);
943 } else if(ekind == kEventWindowResizeCompleted) {
944 // Create a mouse up event, since such an event is not send by carbon to the
945 // application event handler (while a mouse down <b>is</b> on kEventWindowResizeStarted)
946 EventRef mouseUpEvent;
947 CreateEvent(0, kEventClassMouse, kEventMouseUp, 0, kEventAttributeUserEvent, &mouseUpEvent);
948 UInt16 mbutton = kEventMouseButtonPrimary;
949 SetEventParameter(mouseUpEvent, kEventParamMouseButton, typeMouseButton, sizeof(mbutton), &mbutton);
950 WindowRef window;
951 GetEventParameter(event, kEventParamDirectObject, typeWindowRef, 0, sizeof(window), 0, &window);
952 Rect dragRect;
953 GetWindowBounds(window, kWindowGrowRgn, &dragRect);
954 Point pos = {dragRect.bottom, dragRect.right};
955 SetEventParameter(mouseUpEvent, kEventParamMouseLocation, typeQDPoint, sizeof(pos), &pos);
956 SendEventToApplication(mouseUpEvent);
957 ReleaseEvent(mouseUpEvent);
958 } else if(ekind == kEventWindowBoundsChanging) {
959 UInt32 flags = 0;
960 GetEventParameter(event, kEventParamAttributes, typeUInt32, 0,
961 sizeof(flags), 0, &flags);
962 Rect nr;
963 GetEventParameter(event, kEventParamCurrentBounds, typeQDRectangle, 0,
964 sizeof(nr), 0, &nr);
965
966 QRect newRect(nr.left, nr.top, nr.right - nr.left, nr.bottom - nr.top);
967
968 QTLWExtra * const tlwExtra = widget->d_func()->maybeTopData();
969 if (tlwExtra && tlwExtra->isSetGeometry == 1) {
970 widget->d_func()->setGeometry_sys_helper(newRect.left(), newRect.top(), newRect.width(), newRect.height(), tlwExtra->isMove);
971 } else {
972 //implicitly removes the maximized bit
973 if((widget->data->window_state & Qt::WindowMaximized) &&
974 IsWindowInStandardState(wid, 0, 0)) {
975 widget->data->window_state &= ~Qt::WindowMaximized;
976 QWindowStateChangeEvent e(Qt::WindowStates(widget->data->window_state
977 | Qt::WindowMaximized));
978 QApplication::sendSpontaneousEvent(widget, &e);
979
980 }
981
982 handled_event = false;
983 const QRect oldRect = widget->data->crect;
984 if((flags & kWindowBoundsChangeOriginChanged)) {
985 if(nr.left != oldRect.x() || nr.top != oldRect.y()) {
986 widget->data->crect.moveTo(nr.left, nr.top);
987 QMoveEvent qme(widget->data->crect.topLeft(), oldRect.topLeft());
988 QApplication::sendSpontaneousEvent(widget, &qme);
989 }
990 }
991 if((flags & kWindowBoundsChangeSizeChanged)) {
992 if (widget->isWindow()) {
993 QSize newSize = QLayout::closestAcceptableSize(widget, newRect.size());
994 int dh = newSize.height() - newRect.height();
995 int dw = newSize.width() - newRect.width();
996 if (dw != 0 || dh != 0) {
997 handled_event = true; // We want to change the bounds, so we handle the event
998
999 // set the rect, so we can also do the resize down below (yes, we need to resize).
1000 newRect.setBottom(newRect.bottom() + dh);
1001 newRect.setRight(newRect.right() + dw);
1002
1003 nr.left = newRect.x();
1004 nr.top = newRect.y();
1005 nr.right = nr.left + newRect.width();
1006 nr.bottom = nr.top + newRect.height();
1007 SetEventParameter(event, kEventParamCurrentBounds, typeQDRectangle, sizeof(Rect), &nr);
1008 }
1009 }
1010
1011 if (oldRect.width() != newRect.width() || oldRect.height() != newRect.height()) {
1012 widget->data->crect.setSize(newRect.size());
1013 HIRect bounds = CGRectMake(0, 0, newRect.width(), newRect.height());
1014
1015 // If the WA_StaticContents attribute is set we can optimize the resize
1016 // by only repainting the newly exposed area. We do this by disabling
1017 // painting when setting the size of the view. The OS will invalidate
1018 // the newly exposed area for us.
1019 const bool staticContents = widget->testAttribute(Qt::WA_StaticContents);
1020 const HIViewRef view = qt_mac_nativeview_for(widget);
1021 if (staticContents)
1022 HIViewSetDrawingEnabled(view, false);
1023 HIViewSetFrame(view, &bounds);
1024 if (staticContents)
1025 HIViewSetDrawingEnabled(view, true);
1026
1027 QResizeEvent qre(newRect.size(), oldRect.size());
1028 QApplication::sendSpontaneousEvent(widget, &qre);
1029 qt_event_request_window_change(widget);
1030 }
1031 }
1032 }
1033 } else if (ekind == kEventWindowHidden) {
1034 // Make sure that we also hide any visible sheets on our window.
1035 // Cocoa does the right thing for us.
1036 const QObjectList children = widget->children();
1037 const int childCount = children.count();
1038 for (int i = 0; i < childCount; ++i) {
1039 QObject *obj = children.at(i);
1040 if (obj->isWidgetType()) {
1041 QWidget *widget = static_cast<QWidget *>(obj);
1042 if (qt_mac_is_macsheet(widget) && widget->isVisible())
1043 widget->hide();
1044 }
1045 }
1046 } else {
1047 handled_event = false;
1048 }
1049 break; }
1050 case kEventClassMouse: {
1051#if 0
1052 return SendEventToApplication(event);
1053#endif
1054
1055 bool send_to_app = false;
1056 {
1057 WindowPartCode wpc;
1058 if (GetEventParameter(event, kEventParamWindowPartCode, typeWindowPartCode, 0,
1059 sizeof(wpc), 0, &wpc) == noErr && wpc != inContent)
1060 send_to_app = true;
1061 }
1062 if(!send_to_app) {
1063 WindowRef window;
1064 if(GetEventParameter(event, kEventParamWindowRef, typeWindowRef, 0,
1065 sizeof(window), 0, &window) == noErr) {
1066 HIViewRef hiview;
1067 if(HIViewGetViewForMouseEvent(HIViewGetRoot(window), event, &hiview) == noErr) {
1068 if(QWidget *w = QWidget::find((WId)hiview)) {
1069#if 0
1070 send_to_app = !w->isActiveWindow();
1071#else
1072 Q_UNUSED(w);
1073 send_to_app = true;
1074#endif
1075 }
1076 }
1077 }
1078 }
1079 if(send_to_app)
1080 return SendEventToApplication(event);
1081 handled_event = false;
1082 break; }
1083
1084#ifndef QT_NO_GESTURES
1085 case kEventClassGesture: {
1086 // First, find the widget that was under
1087 // the mouse when the gesture happened:
1088 HIPoint screenLocation;
1089 if (GetEventParameter(event, kEventParamMouseLocation, typeHIPoint, 0,
1090 sizeof(screenLocation), 0, &screenLocation) != noErr) {
1091 handled_event = false;
1092 break;
1093 }
1094 QWidget *widget = QApplication::widgetAt(screenLocation.x, screenLocation.y);
1095 if (!widget) {
1096 handled_event = false;
1097 break;
1098 }
1099
1100 QNativeGestureEvent qNGEvent;
1101 qNGEvent.position = QPoint(screenLocation.x, screenLocation.y);
1102
1103 switch (ekind) {
1104 case kEventGestureStarted:
1105 qNGEvent.gestureType = QNativeGestureEvent::GestureBegin;
1106 break;
1107 case kEventGestureEnded:
1108 qNGEvent.gestureType = QNativeGestureEvent::GestureEnd;
1109 break;
1110 case kEventGestureRotate: {
1111 CGFloat amount;
1112 if (GetEventParameter(event, kEventParamRotationAmount, 'cgfl', 0,
1113 sizeof(amount), 0, &amount) != noErr) {
1114 handled_event = false;
1115 break;
1116 }
1117 qNGEvent.gestureType = QNativeGestureEvent::Rotate;
1118 qNGEvent.percentage = float(-amount);
1119 break; }
1120 case kEventGestureSwipe: {
1121 HIPoint swipeDirection;
1122 if (GetEventParameter(event, kEventParamSwipeDirection, typeHIPoint, 0,
1123 sizeof(swipeDirection), 0, &swipeDirection) != noErr) {
1124 handled_event = false;
1125 break;
1126 }
1127 qNGEvent.gestureType = QNativeGestureEvent::Swipe;
1128 if (swipeDirection.x == 1)
1129 qNGEvent.angle = 180.0f;
1130 else if (swipeDirection.x == -1)
1131 qNGEvent.angle = 0.0f;
1132 else if (swipeDirection.y == 1)
1133 qNGEvent.angle = 90.0f;
1134 else if (swipeDirection.y == -1)
1135 qNGEvent.angle = 270.0f;
1136 break; }
1137 case kEventGestureMagnify: {
1138 CGFloat amount;
1139 if (GetEventParameter(event, kEventParamMagnificationAmount, 'cgfl', 0,
1140 sizeof(amount), 0, &amount) != noErr) {
1141 handled_event = false;
1142 break;
1143 }
1144 qNGEvent.gestureType = QNativeGestureEvent::Zoom;
1145 qNGEvent.percentage = float(amount);
1146 break; }
1147 }
1148
1149 QApplication::sendSpontaneousEvent(widget, &qNGEvent);
1150 break; }
1151#endif // QT_NO_GESTURES
1152
1153 default:
1154 handled_event = false;
1155 }
1156 if(!handled_event) //let the event go through
1157 return eventNotHandledErr;
1158 return noErr; //we eat the event
1159}
1160
1161// widget events
1162static HIObjectClassRef widget_class = 0;
1163static EventTypeSpec widget_events[] = {
1164 { kEventClassHIObject, kEventHIObjectConstruct },
1165 { kEventClassHIObject, kEventHIObjectDestruct },
1166
1167 { kEventClassControl, kEventControlDraw },
1168 { kEventClassControl, kEventControlInitialize },
1169 { kEventClassControl, kEventControlGetPartRegion },
1170 { kEventClassControl, kEventControlGetClickActivation },
1171 { kEventClassControl, kEventControlSetFocusPart },
1172 { kEventClassControl, kEventControlDragEnter },
1173 { kEventClassControl, kEventControlDragWithin },
1174 { kEventClassControl, kEventControlDragLeave },
1175 { kEventClassControl, kEventControlDragReceive },
1176 { kEventClassControl, kEventControlOwningWindowChanged },
1177 { kEventClassControl, kEventControlBoundsChanged },
1178 { kEventClassControl, kEventControlGetSizeConstraints },
1179 { kEventClassControl, kEventControlVisibilityChanged },
1180
1181 { kEventClassMouse, kEventMouseDown },
1182 { kEventClassMouse, kEventMouseUp },
1183 { kEventClassMouse, kEventMouseMoved },
1184 { kEventClassMouse, kEventMouseDragged }
1185};
1186static EventHandlerUPP mac_widget_eventUPP = 0;
1187static void cleanup_widget_eventUPP()
1188{
1189 DisposeEventHandlerUPP(mac_widget_eventUPP);
1190 mac_widget_eventUPP = 0;
1191}
1192static const EventHandlerUPP make_widget_eventUPP()
1193{
1194 if(mac_widget_eventUPP)
1195 return mac_widget_eventUPP;
1196 qAddPostRoutine(cleanup_widget_eventUPP);
1197 return mac_widget_eventUPP = NewEventHandlerUPP(QWidgetPrivate::qt_widget_event);
1198}
1199OSStatus QWidgetPrivate::qt_widget_event(EventHandlerCallRef er, EventRef event, void *)
1200{
1201 QScopedLoopLevelCounter loopLevelCounter(QApplicationPrivate::instance()->threadData);
1202
1203 bool handled_event = true;
1204 UInt32 ekind = GetEventKind(event), eclass = GetEventClass(event);
1205 switch(eclass) {
1206 case kEventClassHIObject: {
1207 HIViewRef view = 0;
1208 GetEventParameter(event, kEventParamHIObjectInstance, typeHIObjectRef,
1209 0, sizeof(view), 0, &view);
1210 if(ekind == kEventHIObjectConstruct) {
1211 if(view) {
1212 HIViewChangeFeatures(view, kHIViewAllowsSubviews, 0);
1213 SetEventParameter(event, kEventParamHIObjectInstance,
1214 typeVoidPtr, sizeof(view), &view);
1215 }
1216 } else if(ekind == kEventHIObjectDestruct) {
1217 //nothing to really do.. or is there?
1218 } else {
1219 handled_event = false;
1220 }
1221 break; }
1222 case kEventClassControl: {
1223 QWidget *widget = 0;
1224 HIViewRef hiview = 0;
1225 if(GetEventParameter(event, kEventParamDirectObject, typeControlRef,
1226 0, sizeof(hiview), 0, &hiview) == noErr)
1227 widget = QWidget::find((WId)hiview);
1228 if (widget && widget->macEvent(er, event))
1229 return noErr;
1230 if(ekind == kEventControlDraw) {
1231 if(widget && qt_isGenuineQWidget(hiview)) {
1232
1233 // if there is a window change event pending for any gl child wigets,
1234 // send it immediately. (required for flicker-free resizing)
1235 extern void qt_mac_send_posted_gl_updates(QWidget *widget);
1236 qt_mac_send_posted_gl_updates(widget);
1237
1238 if (QApplicationPrivate::graphicsSystem() && !widget->d_func()->paintOnScreen()) {
1239 widget->d_func()->syncBackingStore();
1240 widget->d_func()->dirtyOnWidget = QRegion();
1241 return noErr;
1242 }
1243
1244 //requested rgn
1245 RgnHandle rgn;
1246 GetEventParameter(event, kEventParamRgnHandle, typeQDRgnHandle, 0, sizeof(rgn), 0, &rgn);
1247 QRegion qrgn(qt_mac_convert_mac_region(rgn));
1248
1249 //update handles
1250 GrafPtr qd = 0;
1251 CGContextRef cg = 0;
1252 if(GetEventParameter(event, kEventParamCGContextRef, typeCGContextRef, 0, sizeof(cg), 0, &cg) != noErr) {
1253 Q_ASSERT(false);
1254 }
1255 widget->d_func()->hd = cg;
1256 widget->d_func()->qd_hd = qd;
1257 CGContextSaveGState(cg);
1258
1259#ifdef DEBUG_WIDGET_PAINT
1260 const bool doDebug = true;
1261 if(doDebug) {
1262 qDebug("asked to draw %p[%p] [%s::%s] %p[%p] [%d] [%dx%d]", widget, hiview, widget->metaObject()->className(),
1263 widget->objectName().local8Bit().data(), widget->parentWidget(),
1264 (HIViewRef)(widget->parentWidget() ? qt_mac_nativeview_for(widget->parentWidget()) : (HIViewRef)0),
1265 HIViewIsCompositingEnabled(hiview), qt_mac_posInWindow(widget).x(), qt_mac_posInWindow(widget).y());
1266#if 0
1267 QVector<QRect> region_rects = qrgn.rects();
1268 qDebug("Region! %d", region_rects.count());
1269 for(int i = 0; i < region_rects.count(); i++)
1270 qDebug("%d %d %d %d", region_rects[i].x(), region_rects[i].y(),
1271 region_rects[i].width(), region_rects[i].height());
1272 region_rects = widget->d_func()->clp.rects();
1273 qDebug("Widget Region! %d", region_rects.count());
1274 for(int i = 0; i < region_rects.count(); i++)
1275 qDebug("%d %d %d %d", region_rects[i].x(), region_rects[i].y(),
1276 region_rects[i].width(), region_rects[i].height());
1277#endif
1278 }
1279#endif
1280 if (widget->isVisible() && widget->updatesEnabled()) { //process the actual paint event.
1281 if(widget->testAttribute(Qt::WA_WState_InPaintEvent))
1282 qWarning("QWidget::repaint: Recursive repaint detected");
1283 if (widget->isWindow() && !widget->d_func()->isOpaque
1284 && !widget->testAttribute(Qt::WA_MacBrushedMetal)) {
1285 QRect qrgnRect = qrgn.boundingRect();
1286 CGContextClearRect(cg, CGRectMake(qrgnRect.x(), qrgnRect.y(), qrgnRect.width(), qrgnRect.height()));
1287 }
1288
1289 QPoint redirectionOffset(0, 0);
1290 QWidget *tl = widget->window();
1291 if (tl) {
1292 Qt::WindowFlags flags = tl->windowFlags();
1293 if (flags & Qt::FramelessWindowHint
1294 || (flags & Qt::CustomizeWindowHint && !(flags & Qt::WindowTitleHint))) {
1295 if(tl->d_func()->extra && !tl->d_func()->extra->mask.isEmpty())
1296 redirectionOffset += tl->d_func()->extra->mask.boundingRect().topLeft();
1297 }
1298 }
1299
1300 //setup the context
1301 widget->setAttribute(Qt::WA_WState_InPaintEvent);
1302 QPaintEngine *engine = widget->paintEngine();
1303 if (engine)
1304 engine->setSystemClip(qrgn);
1305
1306 //handle the erase
1307 if (engine && (!widget->testAttribute(Qt::WA_NoSystemBackground)
1308 && (widget->isWindow() || widget->autoFillBackground())
1309 || widget->testAttribute(Qt::WA_TintedBackground)
1310 || widget->testAttribute(Qt::WA_StyledBackground))) {
1311#ifdef DEBUG_WIDGET_PAINT
1312 if(doDebug)
1313 qDebug(" Handling erase for [%s::%s]", widget->metaObject()->className(),
1314 widget->objectName().local8Bit().data());
1315#endif
1316 if (!redirectionOffset.isNull())
1317 widget->d_func()->setRedirected(widget, redirectionOffset);
1318
1319 bool was_unclipped = widget->testAttribute(Qt::WA_PaintUnclipped);
1320 widget->setAttribute(Qt::WA_PaintUnclipped, false);
1321 QPainter p(widget);
1322 p.setClipping(false);
1323 if(was_unclipped)
1324 widget->setAttribute(Qt::WA_PaintUnclipped);
1325 widget->d_func()->paintBackground(&p, qrgn, widget->isWindow() ? DrawAsRoot : 0);
1326 if (widget->testAttribute(Qt::WA_TintedBackground)) {
1327 QColor tint = widget->palette().window().color();
1328 tint.setAlphaF(.6);
1329 const QVector<QRect> &rects = qrgn.rects();
1330 for (int i = 0; i < rects.size(); ++i)
1331 p.fillRect(rects.at(i), tint);
1332 }
1333 p.end();
1334 if (!redirectionOffset.isNull())
1335 widget->d_func()->restoreRedirected();
1336 }
1337
1338 if(!HIObjectIsOfClass((HIObjectRef)hiview, kObjectQWidget))
1339 CallNextEventHandler(er, event);
1340
1341 //send the paint
1342 redirectionOffset += widget->data->wrect.topLeft(); // Map from system to qt coordinates
1343 if (!redirectionOffset.isNull())
1344 widget->d_func()->setRedirected(widget, redirectionOffset);
1345 qrgn.translate(redirectionOffset);
1346 QPaintEvent e(qrgn);
1347 widget->d_func()->dirtyOnWidget = QRegion();
1348#ifdef QT3_SUPPORT
1349 e.setErased(true);
1350#endif
1351 QApplication::sendSpontaneousEvent(widget, &e);
1352 if (!redirectionOffset.isNull())
1353 widget->d_func()->restoreRedirected();
1354
1355 //cleanup
1356 if (engine)
1357 engine->setSystemClip(QRegion());
1358
1359 widget->setAttribute(Qt::WA_WState_InPaintEvent, false);
1360 if(!widget->testAttribute(Qt::WA_PaintOutsidePaintEvent) && widget->paintingActive())
1361 qWarning("QWidget: It is dangerous to leave painters active on a widget outside of the PaintEvent");
1362 }
1363
1364 widget->d_func()->hd = 0;
1365 widget->d_func()->qd_hd = 0;
1366 CGContextRestoreGState(cg);
1367 } else if(!HIObjectIsOfClass((HIObjectRef)hiview, kObjectQWidget)) {
1368 CallNextEventHandler(er, event);
1369 }
1370 } else if(ekind == kEventControlInitialize) {
1371 if(HIObjectIsOfClass((HIObjectRef)hiview, kObjectQWidget)) {
1372 UInt32 features = kControlSupportsDragAndDrop | kControlSupportsClickActivation | kControlSupportsFocus;
1373 SetEventParameter(event, kEventParamControlFeatures, typeUInt32, sizeof(features), &features);
1374 } else {
1375 handled_event = false;
1376 }
1377 } else if(ekind == kEventControlSetFocusPart) {
1378 if(widget) {
1379 ControlPartCode part;
1380 GetEventParameter(event, kEventParamControlPart, typeControlPartCode, 0,
1381 sizeof(part), 0, &part);
1382 if(part == kControlFocusNoPart){
1383 if (widget->hasFocus())
1384 QApplicationPrivate::setFocusWidget(0, Qt::OtherFocusReason);
1385 } else
1386 widget->setFocus();
1387 }
1388 if(!HIObjectIsOfClass((HIObjectRef)hiview, kObjectQWidget))
1389 CallNextEventHandler(er, event);
1390 } else if(ekind == kEventControlGetClickActivation) {
1391 ClickActivationResult clickT = kActivateAndIgnoreClick;
1392 SetEventParameter(event, kEventParamClickActivation, typeClickActivationResult,
1393 sizeof(clickT), &clickT);
1394 } else if(ekind == kEventControlGetPartRegion) {
1395 handled_event = false;
1396 if(!HIObjectIsOfClass((HIObjectRef)hiview, kObjectQWidget) && CallNextEventHandler(er, event) == noErr) {
1397 handled_event = true;
1398 break;
1399 }
1400 if(widget && !widget->isWindow()) {
1401 ControlPartCode part;
1402 GetEventParameter(event, kEventParamControlPart, typeControlPartCode, 0,
1403 sizeof(part), 0, &part);
1404 if(part == kControlClickableMetaPart && widget->testAttribute(Qt::WA_TransparentForMouseEvents)) {
1405 RgnHandle rgn;
1406 GetEventParameter(event, kEventParamControlRegion, typeQDRgnHandle, 0,
1407 sizeof(rgn), 0, &rgn);
1408 SetEmptyRgn(rgn);
1409 handled_event = true;
1410 } else if(part == kControlStructureMetaPart || part == kControlClickableMetaPart) {
1411 RgnHandle rgn;
1412 GetEventParameter(event, kEventParamControlRegion, typeQDRgnHandle, 0,
1413 sizeof(rgn), 0, &rgn);
1414 SetRectRgn(rgn, 0, 0, widget->width(), widget->height());
1415 if(QWidgetPrivate::qt_widget_rgn(widget, kWindowStructureRgn, rgn, false))
1416 handled_event = true;
1417 } else if(part == kControlOpaqueMetaPart) {
1418 if(widget->d_func()->isOpaque) {
1419 RgnHandle rgn;
1420 GetEventParameter(event, kEventParamControlRegion, typeQDRgnHandle, 0,
1421 sizeof(RgnHandle), 0, &rgn);
1422 SetRectRgn(rgn, 0, 0, widget->width(), widget->height());
1423 QWidgetPrivate::qt_widget_rgn(widget, kWindowStructureRgn, rgn, false);
1424 SetEventParameter(event, kEventParamControlRegion, typeQDRgnHandle,
1425 sizeof(RgnHandle), &rgn);
1426 handled_event = true;
1427 }
1428 }
1429 }
1430 } else if(ekind == kEventControlOwningWindowChanged) {
1431 if(!HIObjectIsOfClass((HIObjectRef)hiview, kObjectQWidget))
1432 CallNextEventHandler(er, event);
1433 if(widget && qt_mac_window_for(hiview)) {
1434 WindowRef foo = 0;
1435 GetEventParameter(event, kEventParamControlCurrentOwningWindow, typeWindowRef, 0,
1436 sizeof(foo), 0, &foo);
1437 widget->d_func()->initWindowPtr();
1438 }
1439 if (widget)
1440 qt_event_request_window_change(widget);
1441 } else if(ekind == kEventControlDragEnter || ekind == kEventControlDragWithin ||
1442 ekind == kEventControlDragLeave || ekind == kEventControlDragReceive) {
1443 // dnd are really handled in qdnd_mac.cpp,
1444 // just modularize the code a little...
1445 DragRef drag;
1446 GetEventParameter(event, kEventParamDragRef, typeDragRef, 0, sizeof(drag), 0, &drag);
1447 handled_event = false;
1448 bool drag_allowed = false;
1449
1450 QWidget *dropWidget = widget;
1451 if (qobject_cast<QFocusFrame *>(widget)){
1452 // We might shadow widgets underneath the focus
1453 // frame, so stay interrested, and let the dnd through
1454 drag_allowed = true;
1455 handled_event = true;
1456 Point where;
1457 GetDragMouse(drag, &where, 0);
1458 dropWidget = QApplication::widgetAt(QPoint(where.h, where.v));
1459
1460 if (dropWidget != QDragManager::self()->currentTarget()) {
1461 // We have to 'fake' enter and leave events for the shaddowed widgets:
1462 if (ekind == kEventControlDragEnter) {
1463 if (QDragManager::self()->currentTarget())
1464 QDragManager::self()->currentTarget()->d_func()->qt_mac_dnd_event(kEventControlDragLeave, drag);
1465 if (dropWidget) {
1466 dropWidget->d_func()->qt_mac_dnd_event(kEventControlDragEnter, drag);
1467 }
1468 // Set dropWidget to zero, so qt_mac_dnd_event
1469 // doesn't get called a second time below:
1470 dropWidget = 0;
1471 } else if (ekind == kEventControlDragLeave) {
1472 dropWidget = QDragManager::self()->currentTarget();
1473 if (dropWidget) {
1474 dropWidget->d_func()->qt_mac_dnd_event(kEventControlDragLeave, drag);
1475 }
1476 // Set dropWidget to zero, so qt_mac_dnd_event
1477 // doesn't get called a second time below:
1478 dropWidget = 0;
1479 }
1480 }
1481 }
1482
1483 // Send the dnd event to the widget:
1484 if (dropWidget && dropWidget->d_func()->qt_mac_dnd_event(ekind, drag)) {
1485 drag_allowed = true;
1486 handled_event = true;
1487 }
1488
1489 if (ekind == kEventControlDragEnter) {
1490 // If we don't accept the enter event, we will
1491 // receive no more drag events for this widget
1492 const Boolean wouldAccept = drag_allowed ? true : false;
1493 SetEventParameter(event, kEventParamControlWouldAcceptDrop, typeBoolean,
1494 sizeof(wouldAccept), &wouldAccept);
1495 }
1496 } else if (ekind == kEventControlBoundsChanged) {
1497 if (!widget || widget->isWindow() || widget->testAttribute(Qt::WA_Moved) || widget->testAttribute(Qt::WA_Resized)) {
1498 handled_event = false;
1499 } else {
1500 // Sync our view in case some other (non-Qt) view is controlling us.
1501 handled_event = true;
1502 Rect newBounds;
1503 GetEventParameter(event, kEventParamCurrentBounds,
1504 typeQDRectangle, 0, sizeof(Rect), 0, &newBounds);
1505 QRect rect(newBounds.left, newBounds.top,
1506 newBounds.right - newBounds.left, newBounds.bottom - newBounds.top);
1507
1508 bool moved = widget->testAttribute(Qt::WA_Moved);
1509 bool resized = widget->testAttribute(Qt::WA_Resized);
1510 widget->setGeometry(rect);
1511 widget->setAttribute(Qt::WA_Moved, moved);
1512 widget->setAttribute(Qt::WA_Resized, resized);
1513 qt_event_request_window_change(widget);
1514 }
1515 } else if (ekind == kEventControlGetSizeConstraints) {
1516 if (!widget || !qt_isGenuineQWidget(widget)) {
1517 handled_event = false;
1518 } else {
1519 handled_event = true;
1520 QWidgetItem item(widget);
1521 QSize size = item.minimumSize();
1522 HISize hisize = { size.width(), size.height() };
1523 SetEventParameter(event, kEventParamMinimumSize, typeHISize, sizeof(HISize), &hisize);
1524 size = item.maximumSize();
1525 hisize.width = size.width() + 2; // ### shouldn't have to add 2 (but it works).
1526 hisize.height = size.height();
1527 SetEventParameter(event, kEventParamMaximumSize, typeHISize, sizeof(HISize), &hisize);
1528 }
1529 } else if (ekind == kEventControlVisibilityChanged) {
1530 handled_event = false;
1531 if (widget) {
1532 qt_event_request_window_change(widget);
1533 if (!HIViewIsVisible(HIViewRef(widget->winId()))) {
1534 if (widget == qt_button_down)
1535 qt_button_down = 0;
1536 }
1537 }
1538 }
1539 break; }
1540 case kEventClassMouse: {
1541 bool send_to_app = false;
1542 if(qt_button_down)
1543 send_to_app = true;
1544 if(send_to_app) {
1545 OSStatus err = SendEventToApplication(event);
1546 if(err != noErr)
1547 handled_event = false;
1548 } else {
1549 CallNextEventHandler(er, event);
1550 }
1551 break; }
1552 default:
1553 handled_event = false;
1554 break;
1555 }
1556 if(!handled_event) //let the event go through
1557 return eventNotHandledErr;
1558 return noErr; //we eat the event
1559}
1560#endif
1561
1562OSViewRef qt_mac_create_widget(QWidget *widget, QWidgetPrivate *widgetPrivate, OSViewRef parent)
1563{
1564#ifdef QT_MAC_USE_COCOA
1565 QMacCocoaAutoReleasePool pool;
1566 QT_MANGLE_NAMESPACE(QCocoaView) *view = [[QT_MANGLE_NAMESPACE(QCocoaView) alloc] initWithQWidget:widget widgetPrivate:widgetPrivate];
1567 if (view && parent)
1568 [parent addSubview:view];
1569 return view;
1570#else
1571 Q_UNUSED(widget);
1572 Q_UNUSED(widgetPrivate);
1573 if(!widget_class) {
1574 OSStatus err = HIObjectRegisterSubclass(kObjectQWidget, kHIViewClassID, 0, make_widget_eventUPP(),
1575 GetEventTypeCount(widget_events), widget_events,
1576 0, &widget_class);
1577 if (err && err != hiObjectClassExistsErr)
1578 qWarning("QWidget: Internal error (%d)", __LINE__);
1579 }
1580 HIViewRef ret = 0;
1581 if(HIObjectCreate(kObjectQWidget, 0, (HIObjectRef*)&ret) != noErr)
1582 qWarning("QWidget: Internal error (%d)", __LINE__);
1583 if(ret && parent)
1584 HIViewAddSubview(parent, ret);
1585 return ret;
1586#endif
1587}
1588
1589void qt_mac_unregister_widget()
1590{
1591#ifndef QT_MAC_USE_COCOA
1592 HIObjectUnregisterClass(widget_class);
1593 widget_class = 0;
1594#endif
1595}
1596
1597void QWidgetPrivate::toggleDrawers(bool visible)
1598{
1599 for (int i = 0; i < children.size(); ++i) {
1600 register QObject *object = children.at(i);
1601 if (!object->isWidgetType())
1602 continue;
1603 QWidget *widget = static_cast<QWidget*>(object);
1604 if(qt_mac_is_macdrawer(widget)) {
1605 bool oldState = widget->testAttribute(Qt::WA_WState_ExplicitShowHide);
1606 if(visible) {
1607 if (!widget->testAttribute(Qt::WA_WState_ExplicitShowHide))
1608 widget->show();
1609 } else {
1610 widget->hide();
1611 if(!oldState)
1612 widget->setAttribute(Qt::WA_WState_ExplicitShowHide, false);
1613 }
1614 }
1615 }
1616}
1617
1618/*****************************************************************************
1619 QWidgetPrivate member functions
1620 *****************************************************************************/
1621bool QWidgetPrivate::qt_mac_update_sizer(QWidget *w, int up)
1622{
1623 // I'm not sure what "up" is
1624 if(!w || !w->isWindow())
1625 return false;
1626
1627 QTLWExtra *topData = w->d_func()->topData();
1628 QWExtra *extraData = w->d_func()->extraData();
1629 // topData->resizer is only 4 bits, so subtracting -1 from zero causes bad stuff
1630 // to happen, prevent that here (you really want the thing hidden).
1631 if (up >= 0 || topData->resizer != 0)
1632 topData->resizer += up;
1633 OSWindowRef windowRef = qt_mac_window_for(OSViewRef(w->winId()));
1634 {
1635#ifndef QT_MAC_USE_COCOA
1636 WindowClass wclass;
1637 GetWindowClass(windowRef, &wclass);
1638 if(!(GetAvailableWindowAttributes(wclass) & kWindowResizableAttribute))
1639 return true;
1640#endif
1641 }
1642 bool remove_grip = (topData->resizer || (w->windowFlags() & Qt::FramelessWindowHint)
1643 || (extraData->maxw && extraData->maxh &&
1644 extraData->maxw == extraData->minw && extraData->maxh == extraData->minh));
1645#ifndef QT_MAC_USE_COCOA
1646 WindowAttributes attr;
1647 GetWindowAttributes(windowRef, &attr);
1648 if(remove_grip) {
1649 if(attr & kWindowResizableAttribute) {
1650 ChangeWindowAttributes(qt_mac_window_for(w), kWindowNoAttributes,
1651 kWindowResizableAttribute);
1652 ReshapeCustomWindow(qt_mac_window_for(w));
1653 }
1654 } else if(!(attr & kWindowResizableAttribute)) {
1655 ChangeWindowAttributes(windowRef, kWindowResizableAttribute,
1656 kWindowNoAttributes);
1657 ReshapeCustomWindow(windowRef);
1658 }
1659#else
1660 [windowRef setShowsResizeIndicator:!remove_grip];
1661#endif
1662 return true;
1663}
1664
1665void QWidgetPrivate::qt_clean_root_win()
1666{
1667#ifdef QT_MAC_USE_COCOA
1668 [qt_root_win release];
1669#else
1670 if(!qt_root_win)
1671 return;
1672 CFRelease(qt_root_win);
1673#endif
1674 qt_root_win = 0;
1675}
1676
1677bool QWidgetPrivate::qt_create_root_win()
1678{
1679 if(qt_root_win)
1680 return false;
1681 const QSize desktopSize = qt_mac_desktopSize();
1682 QRect desktopRect(QPoint(0, 0), desktopSize);
1683#ifdef QT_MAC_USE_COCOA
1684 qt_root_win = qt_mac_create_window(0, kOverlayWindowClass, NSBorderlessWindowMask, desktopRect);
1685#else
1686 WindowAttributes wattr = (kWindowCompositingAttribute | kWindowStandardHandlerAttribute);
1687 qt_root_win = qt_mac_create_window(0, kOverlayWindowClass, wattr, desktopRect);
1688#endif
1689 if(!qt_root_win)
1690 return false;
1691 qAddPostRoutine(qt_clean_root_win);
1692 return true;
1693}
1694
1695bool QWidgetPrivate::qt_widget_rgn(QWidget *widget, short wcode, RgnHandle rgn, bool force = false)
1696{
1697 bool ret = false;
1698#ifndef QT_MAC_USE_COCOA
1699 switch(wcode) {
1700 case kWindowStructureRgn: {
1701 if(widget) {
1702 if(widget->d_func()->extra && !widget->d_func()->extra->mask.isEmpty()) {
1703 QRegion rin = qt_mac_convert_mac_region(rgn);
1704 if(!rin.isEmpty()) {
1705 QPoint rin_tl = rin.boundingRect().topLeft(); //in offset
1706 rin.translate(-rin_tl.x(), -rin_tl.y()); //bring into same space as below
1707 QRegion mask = widget->d_func()->extra->mask;
1708 Qt::WindowFlags flags = widget->windowFlags();
1709 if(widget->isWindow()
1710 && !(flags & Qt::FramelessWindowHint
1711 || (flags & Qt::CustomizeWindowHint && !(flags & Qt::WindowTitleHint)))) {
1712 QRegion title;
1713 {
1714 QMacSmartQuickDrawRegion rgn(qt_mac_get_rgn());
1715 GetWindowRegion(qt_mac_window_for(widget), kWindowTitleBarRgn, rgn);
1716 title = qt_mac_convert_mac_region(rgn);
1717 }
1718 QRect br = title.boundingRect();
1719 mask.translate(0, br.height()); //put the mask 'under' the title bar..
1720 title.translate(-br.x(), -br.y());
1721 mask += title;
1722 }
1723
1724 QRegion cr = rin & mask;
1725 cr.translate(rin_tl.x(), rin_tl.y()); //translate back to incoming space
1726 CopyRgn(QMacSmartQuickDrawRegion(cr.toQDRgn()), rgn);
1727 }
1728 ret = true;
1729 } else if(force) {
1730 QRegion cr(widget->geometry());
1731 CopyRgn(QMacSmartQuickDrawRegion(cr.toQDRgn()), rgn);
1732 ret = true;
1733 }
1734 }
1735 break; }
1736 default: break;
1737 }
1738 //qDebug() << widget << ret << wcode << qt_mac_convert_mac_region(rgn);
1739#else
1740 Q_UNUSED(widget);
1741 Q_UNUSED(wcode);
1742 Q_UNUSED(rgn);
1743 Q_UNUSED(force);
1744#endif
1745 return ret;
1746}
1747
1748/*****************************************************************************
1749 QWidget member functions
1750 *****************************************************************************/
1751void QWidgetPrivate::determineWindowClass()
1752{
1753 Q_Q(QWidget);
1754#if !defined(QT_NO_MAINWINDOW) && !defined(QT_NO_TOOLBAR)
1755 // Make sure that QMainWindow has the MacWindowToolBarButtonHint when the
1756 // unifiedTitleAndToolBarOnMac property is ON. This is to avoid reentry of
1757 // setParent() triggered by the QToolBar::event(QEvent::ParentChange).
1758 QMainWindow *mainWindow = qobject_cast<QMainWindow *>(q);
1759 if (mainWindow && mainWindow->unifiedTitleAndToolBarOnMac()) {
1760 data.window_flags |= Qt::MacWindowToolBarButtonHint;
1761 }
1762#endif
1763#ifndef QT_MAC_USE_COCOA
1764// ### COCOA:Interleave these better!
1765
1766 const Qt::WindowType type = q->windowType();
1767 Qt::WindowFlags &flags = data.window_flags;
1768 const bool popup = (type == Qt::Popup);
1769 if (type == Qt::ToolTip || type == Qt::SplashScreen || popup)
1770 flags |= Qt::FramelessWindowHint;
1771
1772 WindowClass wclass = kSheetWindowClass;
1773 if(qt_mac_is_macdrawer(q))
1774 wclass = kDrawerWindowClass;
1775 else if (q->testAttribute(Qt::WA_ShowModal) && flags & Qt::CustomizeWindowHint)
1776 wclass = kDocumentWindowClass;
1777 else if(popup || (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5 && type == Qt::SplashScreen))
1778 wclass = kModalWindowClass;
1779 else if(q->testAttribute(Qt::WA_ShowModal))
1780 wclass = kMovableModalWindowClass;
1781 else if(type == Qt::ToolTip)
1782 wclass = kHelpWindowClass;
1783 else if(type == Qt::Tool || (QSysInfo::MacintoshVersion < QSysInfo::MV_10_5
1784 && type == Qt::SplashScreen))
1785 wclass = kFloatingWindowClass;
1786 else
1787 wclass = kDocumentWindowClass;
1788
1789 WindowGroupRef grp = 0;
1790 WindowAttributes wattr = (kWindowCompositingAttribute | kWindowStandardHandlerAttribute);
1791 if (q->testAttribute(Qt::WA_MacFrameworkScaled))
1792 wattr |= kWindowFrameworkScaledAttribute;
1793 if(qt_mac_is_macsheet(q)) {
1794 //grp = GetWindowGroupOfClass(kMovableModalWindowClass);
1795 wclass = kSheetWindowClass;
1796 } else {
1797 grp = GetWindowGroupOfClass(wclass);
1798 // Shift things around a bit to get the correct window class based on the presence
1799 // (or lack) of the border.
1800 bool customize = flags & Qt::CustomizeWindowHint;
1801 bool framelessWindow = (flags & Qt::FramelessWindowHint || (customize && !(flags & Qt::WindowTitleHint)));
1802 if (framelessWindow) {
1803 if(wclass == kDocumentWindowClass) {
1804 wattr |= kWindowNoTitleBarAttribute;
1805 } else if(wclass == kFloatingWindowClass) {
1806 wattr |= kWindowNoTitleBarAttribute;
1807 } else if (wclass == kMovableModalWindowClass) {
1808 wclass = kModalWindowClass;
1809 }
1810 } else {
1811 if(wclass != kModalWindowClass)
1812 wattr |= kWindowResizableAttribute;
1813 }
1814 // Only add extra decorations (well, buttons) for widgets that can have them
1815 // and have an actual border we can put them on.
1816 if(wclass != kModalWindowClass && wclass != kMovableModalWindowClass
1817 && wclass != kSheetWindowClass && wclass != kPlainWindowClass
1818 && !framelessWindow && wclass != kDrawerWindowClass
1819 && wclass != kHelpWindowClass) {
1820 if (flags & Qt::WindowMaximizeButtonHint)
1821 wattr |= kWindowFullZoomAttribute;
1822 if (flags & Qt::WindowMinimizeButtonHint)
1823 wattr |= kWindowCollapseBoxAttribute;
1824 if (flags & Qt::WindowSystemMenuHint || flags & Qt::WindowCloseButtonHint)
1825 wattr |= kWindowCloseBoxAttribute;
1826 if (flags & Qt::MacWindowToolBarButtonHint)
1827 wattr |= kWindowToolbarButtonAttribute;
1828 } else {
1829 // Clear these hints so that we aren't call them on invalid windows
1830 flags &= ~(Qt::WindowMaximizeButtonHint | Qt::WindowMinimizeButtonHint
1831 | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint);
1832 }
1833 }
1834 if((popup || type == Qt::Tool) && !q->isModal())
1835 wattr |= kWindowHideOnSuspendAttribute;
1836 wattr |= kWindowLiveResizeAttribute;
1837
1838#ifdef DEBUG_WINDOW_CREATE
1839#define ADD_DEBUG_WINDOW_NAME(x) { x, #x }
1840 struct {
1841 UInt32 tag;
1842 const char *name;
1843 } known_attribs[] = {
1844 ADD_DEBUG_WINDOW_NAME(kWindowCompositingAttribute),
1845 ADD_DEBUG_WINDOW_NAME(kWindowStandardHandlerAttribute),
1846 ADD_DEBUG_WINDOW_NAME(kWindowMetalAttribute),
1847 ADD_DEBUG_WINDOW_NAME(kWindowHideOnSuspendAttribute),
1848 ADD_DEBUG_WINDOW_NAME(kWindowStandardHandlerAttribute),
1849 ADD_DEBUG_WINDOW_NAME(kWindowCollapseBoxAttribute),
1850 ADD_DEBUG_WINDOW_NAME(kWindowHorizontalZoomAttribute),
1851 ADD_DEBUG_WINDOW_NAME(kWindowVerticalZoomAttribute),
1852 ADD_DEBUG_WINDOW_NAME(kWindowResizableAttribute),
1853 ADD_DEBUG_WINDOW_NAME(kWindowNoActivatesAttribute),
1854 ADD_DEBUG_WINDOW_NAME(kWindowNoUpdatesAttribute),
1855 ADD_DEBUG_WINDOW_NAME(kWindowOpaqueForEventsAttribute),
1856 ADD_DEBUG_WINDOW_NAME(kWindowLiveResizeAttribute),
1857 ADD_DEBUG_WINDOW_NAME(kWindowCloseBoxAttribute),
1858 ADD_DEBUG_WINDOW_NAME(kWindowHideOnSuspendAttribute),
1859 { 0, 0 }
1860 }, known_classes[] = {
1861 ADD_DEBUG_WINDOW_NAME(kHelpWindowClass),
1862 ADD_DEBUG_WINDOW_NAME(kPlainWindowClass),
1863 ADD_DEBUG_WINDOW_NAME(kDrawerWindowClass),
1864 ADD_DEBUG_WINDOW_NAME(kUtilityWindowClass),
1865 ADD_DEBUG_WINDOW_NAME(kToolbarWindowClass),
1866 ADD_DEBUG_WINDOW_NAME(kSheetWindowClass),
1867 ADD_DEBUG_WINDOW_NAME(kFloatingWindowClass),
1868 ADD_DEBUG_WINDOW_NAME(kUtilityWindowClass),
1869 ADD_DEBUG_WINDOW_NAME(kDocumentWindowClass),
1870 ADD_DEBUG_WINDOW_NAME(kToolbarWindowClass),
1871 ADD_DEBUG_WINDOW_NAME(kMovableModalWindowClass),
1872 ADD_DEBUG_WINDOW_NAME(kModalWindowClass),
1873 { 0, 0 }
1874 };
1875 qDebug("Qt: internal: ************* Creating new window %p (%s::%s)", q, q->metaObject()->className(),
1876 q->objectName().toLocal8Bit().constData());
1877 bool found_class = false;
1878 for(int i = 0; known_classes[i].name; i++) {
1879 if(wclass == known_classes[i].tag) {
1880 found_class = true;
1881 qDebug("Qt: internal: ** Class: %s", known_classes[i].name);
1882 break;
1883 }
1884 }
1885 if(!found_class)
1886 qDebug("Qt: internal: !! Class: Unknown! (%d)", (int)wclass);
1887 if(wattr) {
1888 WindowAttributes tmp_wattr = wattr;
1889 qDebug("Qt: internal: ** Attributes:");
1890 for(int i = 0; tmp_wattr && known_attribs[i].name; i++) {
1891 if((tmp_wattr & known_attribs[i].tag) == known_attribs[i].tag) {
1892 tmp_wattr ^= known_attribs[i].tag;
1893 qDebug("Qt: internal: * %s %s", known_attribs[i].name,
1894 (GetAvailableWindowAttributes(wclass) & known_attribs[i].tag) ? "" : "(*)");
1895 }
1896 }
1897 if(tmp_wattr)
1898 qDebug("Qt: internal: !! Attributes: Unknown (%d)", (int)tmp_wattr);
1899 }
1900#endif
1901
1902 /* Just to be extra careful we will change to the kUtilityWindowClass if the
1903 requested attributes cannot be used */
1904 if((GetAvailableWindowAttributes(wclass) & wattr) != wattr) {
1905 WindowClass tmp_class = wclass;
1906 if(wclass == kToolbarWindowClass || wclass == kUtilityWindowClass)
1907 wclass = kFloatingWindowClass;
1908 if(tmp_class != wclass) {
1909 if(!grp)
1910 grp = GetWindowGroupOfClass(wclass);
1911 wclass = tmp_class;
1912 }
1913 }
1914 topData()->wclass = wclass;
1915 topData()->wattr = wattr;
1916#else
1917 const Qt::WindowType type = q->windowType();
1918 Qt::WindowFlags &flags = data.window_flags;
1919 const bool popup = (type == Qt::Popup);
1920 if (type == Qt::ToolTip || type == Qt::SplashScreen || popup)
1921 flags |= Qt::FramelessWindowHint;
1922
1923 WindowClass wclass = kSheetWindowClass;
1924 if(qt_mac_is_macdrawer(q))
1925 wclass = kDrawerWindowClass;
1926 else if (q->testAttribute(Qt::WA_ShowModal) && flags & Qt::CustomizeWindowHint)
1927 wclass = kDocumentWindowClass;
1928 else if(popup || (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5 && type == Qt::SplashScreen))
1929 wclass = kModalWindowClass;
1930 else if(type == Qt::Dialog)
1931 wclass = kMovableModalWindowClass;
1932 else if(type == Qt::ToolTip)
1933 wclass = kHelpWindowClass;
1934 else if(type == Qt::Tool || (QSysInfo::MacintoshVersion < QSysInfo::MV_10_5
1935 && type == Qt::SplashScreen))
1936 wclass = kFloatingWindowClass;
1937 else if(q->testAttribute(Qt::WA_ShowModal))
1938 wclass = kMovableModalWindowClass;
1939 else
1940 wclass = kDocumentWindowClass;
1941
1942 WindowAttributes wattr = NSBorderlessWindowMask;
1943 if(qt_mac_is_macsheet(q)) {
1944 //grp = GetWindowGroupOfClass(kMovableModalWindowClass);
1945 wclass = kSheetWindowClass;
1946 wattr = NSTitledWindowMask | NSResizableWindowMask;
1947 } else {
1948#ifndef QT_MAC_USE_COCOA
1949 grp = GetWindowGroupOfClass(wclass);
1950#endif
1951 // Shift things around a bit to get the correct window class based on the presence
1952 // (or lack) of the border.
1953 bool customize = flags & Qt::CustomizeWindowHint;
1954 bool framelessWindow = (flags & Qt::FramelessWindowHint || (customize && !(flags & Qt::WindowTitleHint)));
1955 if (framelessWindow) {
1956 if (wclass == kDocumentWindowClass) {
1957 wclass = kSimpleWindowClass;
1958 } else if (wclass == kFloatingWindowClass) {
1959 wclass = kToolbarWindowClass;
1960 } else if (wclass == kMovableModalWindowClass) {
1961 wclass = kModalWindowClass;
1962 }
1963 } else {
1964 wattr |= NSTitledWindowMask;
1965 if (wclass != kModalWindowClass)
1966 wattr |= NSResizableWindowMask;
1967 }
1968 // Only add extra decorations (well, buttons) for widgets that can have them
1969 // and have an actual border we can put them on.
1970 if (wclass != kModalWindowClass
1971 && wclass != kSheetWindowClass && wclass != kPlainWindowClass
1972 && !framelessWindow && wclass != kDrawerWindowClass
1973 && wclass != kHelpWindowClass) {
1974 if (flags & Qt::WindowMinimizeButtonHint)
1975 wattr |= NSMiniaturizableWindowMask;
1976 if (flags & Qt::WindowSystemMenuHint || flags & Qt::WindowCloseButtonHint)
1977 wattr |= NSClosableWindowMask;
1978 } else {
1979 // Clear these hints so that we aren't call them on invalid windows
1980 flags &= ~(Qt::WindowMaximizeButtonHint | Qt::WindowMinimizeButtonHint
1981 | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint);
1982 }
1983 }
1984 if (q->testAttribute(Qt::WA_MacBrushedMetal))
1985 wattr |= NSTexturedBackgroundWindowMask;
1986
1987#ifdef DEBUG_WINDOW_CREATE
1988#define ADD_DEBUG_WINDOW_NAME(x) { x, #x }
1989 struct {
1990 UInt32 tag;
1991 const char *name;
1992 } known_attribs[] = {
1993 ADD_DEBUG_WINDOW_NAME(kWindowCompositingAttribute),
1994 ADD_DEBUG_WINDOW_NAME(kWindowStandardHandlerAttribute),
1995 ADD_DEBUG_WINDOW_NAME(kWindowMetalAttribute),
1996 ADD_DEBUG_WINDOW_NAME(kWindowHideOnSuspendAttribute),
1997 ADD_DEBUG_WINDOW_NAME(kWindowStandardHandlerAttribute),
1998 ADD_DEBUG_WINDOW_NAME(kWindowCollapseBoxAttribute),
1999 ADD_DEBUG_WINDOW_NAME(kWindowHorizontalZoomAttribute),
2000 ADD_DEBUG_WINDOW_NAME(kWindowVerticalZoomAttribute),
2001 ADD_DEBUG_WINDOW_NAME(kWindowResizableAttribute),
2002 ADD_DEBUG_WINDOW_NAME(kWindowNoActivatesAttribute),
2003 ADD_DEBUG_WINDOW_NAME(kWindowNoUpdatesAttribute),
2004 ADD_DEBUG_WINDOW_NAME(kWindowOpaqueForEventsAttribute),
2005 ADD_DEBUG_WINDOW_NAME(kWindowLiveResizeAttribute),
2006 ADD_DEBUG_WINDOW_NAME(kWindowCloseBoxAttribute),
2007 ADD_DEBUG_WINDOW_NAME(kWindowHideOnSuspendAttribute),
2008 { 0, 0 }
2009 }, known_classes[] = {
2010 ADD_DEBUG_WINDOW_NAME(kHelpWindowClass),
2011 ADD_DEBUG_WINDOW_NAME(kPlainWindowClass),
2012 ADD_DEBUG_WINDOW_NAME(kDrawerWindowClass),
2013 ADD_DEBUG_WINDOW_NAME(kUtilityWindowClass),
2014 ADD_DEBUG_WINDOW_NAME(kToolbarWindowClass),
2015 ADD_DEBUG_WINDOW_NAME(kSheetWindowClass),
2016 ADD_DEBUG_WINDOW_NAME(kFloatingWindowClass),
2017 ADD_DEBUG_WINDOW_NAME(kUtilityWindowClass),
2018 ADD_DEBUG_WINDOW_NAME(kDocumentWindowClass),
2019 ADD_DEBUG_WINDOW_NAME(kToolbarWindowClass),
2020 ADD_DEBUG_WINDOW_NAME(kMovableModalWindowClass),
2021 ADD_DEBUG_WINDOW_NAME(kModalWindowClass),
2022 { 0, 0 }
2023 };
2024 qDebug("Qt: internal: ************* Creating new window %p (%s::%s)", q, q->metaObject()->className(),
2025 q->objectName().toLocal8Bit().constData());
2026 bool found_class = false;
2027 for(int i = 0; known_classes[i].name; i++) {
2028 if(wclass == known_classes[i].tag) {
2029 found_class = true;
2030 qDebug("Qt: internal: ** Class: %s", known_classes[i].name);
2031 break;
2032 }
2033 }
2034 if(!found_class)
2035 qDebug("Qt: internal: !! Class: Unknown! (%d)", (int)wclass);
2036 if(wattr) {
2037 WindowAttributes tmp_wattr = wattr;
2038 qDebug("Qt: internal: ** Attributes:");
2039 for(int i = 0; tmp_wattr && known_attribs[i].name; i++) {
2040 if((tmp_wattr & known_attribs[i].tag) == known_attribs[i].tag) {
2041 tmp_wattr ^= known_attribs[i].tag;
2042 }
2043 }
2044 if(tmp_wattr)
2045 qDebug("Qt: internal: !! Attributes: Unknown (%d)", (int)tmp_wattr);
2046 }
2047#endif
2048
2049#ifndef QT_MAC_USE_COCOA
2050 /* Just to be extra careful we will change to the kUtilityWindowClass if the
2051 requested attributes cannot be used */
2052 if((GetAvailableWindowAttributes(wclass) & wattr) != wattr) {
2053 WindowClass tmp_class = wclass;
2054 if(wclass == kToolbarWindowClass || wclass == kUtilityWindowClass)
2055 wclass = kFloatingWindowClass;
2056 if(tmp_class != wclass) {
2057 if(!grp)
2058 grp = GetWindowGroupOfClass(wclass);
2059 wclass = tmp_class;
2060 }
2061 }
2062#endif
2063#endif
2064 topData()->wclass = wclass;
2065 topData()->wattr = wattr;
2066}
2067
2068#ifndef QT_MAC_USE_COCOA // This is handled in Cocoa via our category.
2069void QWidgetPrivate::initWindowPtr()
2070{
2071 Q_Q(QWidget);
2072 OSWindowRef windowRef = qt_mac_window_for(qt_mac_nativeview_for(q)); //do not create!
2073 if(!windowRef)
2074 return;
2075 QWidget *window = q->window(), *oldWindow = 0;
2076 if(GetWindowProperty(windowRef, kWidgetCreatorQt, kWidgetPropertyQWidget, sizeof(oldWindow), 0, &oldWindow) == noErr) {
2077 Q_ASSERT(window == oldWindow);
2078 return;
2079 }
2080
2081 if(SetWindowProperty(windowRef, kWidgetCreatorQt, kWidgetPropertyQWidget, sizeof(window), &window) != noErr)
2082 qWarning("Qt:Internal error (%s:%d)", __FILE__, __LINE__); //no real way to recover
2083 if(!q->windowType() != Qt::Desktop) { //setup an event callback handler on the window
2084 InstallWindowEventHandler(windowRef, make_win_eventUPP(), GetEventTypeCount(window_events),
2085 window_events, static_cast<void *>(qApp), &window_event);
2086 }
2087}
2088
2089void QWidgetPrivate::finishCreateWindow_sys_Carbon(OSWindowRef windowRef)
2090{
2091 Q_Q(QWidget);
2092 const Qt::WindowType type = q->windowType();
2093 Qt::WindowFlags &flags = data.window_flags;
2094 QWidget *parentWidget = q->parentWidget();
2095
2096 const bool desktop = (type == Qt::Desktop);
2097 const bool dialog = (type == Qt::Dialog
2098 || type == Qt::Sheet
2099 || type == Qt::Drawer
2100 || (flags & Qt::MSWindowsFixedSizeDialogHint));
2101 QTLWExtra *topExtra = topData();
2102 quint32 wattr = topExtra->wattr;
2103 if (!desktop)
2104 SetAutomaticControlDragTrackingEnabledForWindow(windowRef, true);
2105 HIWindowChangeFeatures(windowRef, kWindowCanCollapse, 0);
2106 if (wattr & kWindowHideOnSuspendAttribute)
2107 HIWindowChangeAvailability(windowRef, kHIWindowExposeHidden, 0);
2108 else
2109 HIWindowChangeAvailability(windowRef, 0, kHIWindowExposeHidden);
2110 if ((flags & Qt::WindowStaysOnTopHint))
2111 ChangeWindowAttributes(windowRef, kWindowNoAttributes, kWindowHideOnSuspendAttribute);
2112 if (qt_mac_is_macdrawer(q) && parentWidget)
2113 SetDrawerParent(windowRef, qt_mac_window_for (parentWidget));
2114 if (topExtra->group) {
2115 qt_mac_release_window_group(topExtra->group);
2116 topExtra->group = 0;
2117 }
2118 if (type == Qt::ToolTip)
2119 qt_mac_set_window_group_to_tooltip(windowRef);
2120 else if (type == Qt::Popup && (flags & Qt::WindowStaysOnTopHint))
2121 qt_mac_set_window_group_to_popup(windowRef);
2122 else if (flags & Qt::WindowStaysOnTopHint)
2123 qt_mac_set_window_group_to_stays_on_top(windowRef, type);
2124 else if (dialog)
2125 SetWindowGroup(windowRef, GetWindowGroupOfClass(kMovableModalWindowClass));
2126
2127#ifdef DEBUG_WINDOW_CREATE
2128 if (WindowGroupRef grpf = GetWindowGroup(windowRef)) {
2129 QCFString cfname;
2130 CopyWindowGroupName(grpf, &cfname);
2131 SInt32 lvl;
2132 GetWindowGroupLevel(grpf, &lvl);
2133 const char *from = "Default";
2134 if (topExtra && grpf == topData()->group)
2135 from = "Created";
2136 else if (grpf == grp)
2137 from = "Copied";
2138 qDebug("Qt: internal: With window group '%s' [%p] @ %d: %s",
2139 static_cast<QString>(cfname).toLatin1().constData(), grpf, (int)lvl, from);
2140 } else {
2141 qDebug("Qt: internal: No window group!!!");
2142 }
2143 HIWindowAvailability hi_avail = 0;
2144 if (HIWindowGetAvailability(windowRef, &hi_avail) == noErr) {
2145 struct {
2146 UInt32 tag;
2147 const char *name;
2148 } known_avail[] = {
2149 ADD_DEBUG_WINDOW_NAME(kHIWindowExposeHidden),
2150 { 0, 0 }
2151 };
2152 qDebug("Qt: internal: ** HIWindowAvailibility:");
2153 for (int i = 0; hi_avail && known_avail[i].name; i++) {
2154 if ((hi_avail & known_avail[i].tag) == known_avail[i].tag) {
2155 hi_avail ^= known_avail[i].tag;
2156 qDebug("Qt: internal: * %s", known_avail[i].name);
2157 }
2158 }
2159 if (hi_avail)
2160 qDebug("Qt: internal: !! Attributes: Unknown (%d)", (int)hi_avail);
2161 }
2162#undef ADD_DEBUG_WINDOW_NAME
2163#endif
2164 if (extra && !extra->mask.isEmpty())
2165 ReshapeCustomWindow(windowRef);
2166 SetWindowModality(windowRef, kWindowModalityNone, 0);
2167 if (qt_mac_is_macdrawer(q))
2168 SetDrawerOffsets(windowRef, 0.0, 25.0);
2169 data.fstrut_dirty = true; // when we create a toplevel widget, the frame strut should be dirty
2170 HIViewRef hiview = (HIViewRef)data.winid;
2171 HIViewRef window_hiview = qt_mac_get_contentview_for(windowRef);
2172 if(!hiview) {
2173 hiview = qt_mac_create_widget(q, this, window_hiview);
2174 setWinId((WId)hiview);
2175 } else {
2176 HIViewAddSubview(window_hiview, hiview);
2177 }
2178 if (hiview) {
2179 Rect win_rect;
2180 GetWindowBounds(qt_mac_window_for (window_hiview), kWindowContentRgn, &win_rect);
2181 HIRect bounds = CGRectMake(0, 0, win_rect.right-win_rect.left, win_rect.bottom-win_rect.top);
2182 HIViewSetFrame(hiview, &bounds);
2183 HIViewSetVisible(hiview, true);
2184 if (q->testAttribute(Qt::WA_DropSiteRegistered))
2185 registerDropSite(true);
2186 transferChildren();
2187 }
2188 initWindowPtr();
2189
2190 if (topExtra->posFromMove) {
2191 updateFrameStrut();
2192 const QRect &fStrut = frameStrut();
2193 Rect r;
2194 SetRect(&r, data.crect.left(), data.crect.top(), data.crect.right() + 1, data.crect.bottom() + 1);
2195 SetRect(&r, r.left + fStrut.left(), r.top + fStrut.top(),
2196 (r.left + fStrut.left() + data.crect.width()) - fStrut.right(),
2197 (r.top + fStrut.top() + data.crect.height()) - fStrut.bottom());
2198 SetWindowBounds(windowRef, kWindowContentRgn, &r);
2199 topExtra->posFromMove = false;
2200 }
2201
2202 if (q->testAttribute(Qt::WA_WState_WindowOpacitySet)){
2203 q->setWindowOpacity(topExtra->opacity / 255.0f);
2204 } else if (qt_mac_is_macsheet(q)){
2205 SetThemeWindowBackground(qt_mac_window_for(q), kThemeBrushSheetBackgroundTransparent, true);
2206 CGFloat alpha = 0;
2207 GetWindowAlpha(qt_mac_window_for(q), &alpha);
2208 if (alpha == 1){
2209 // For some reason the 'SetThemeWindowBackground' does not seem
2210 // to work. So we do this little hack until it hopefully starts to
2211 // work in newer versions of mac OS.
2212 q->setWindowOpacity(0.95f);
2213 q->setAttribute(Qt::WA_WState_WindowOpacitySet, false);
2214 }
2215 } else{
2216 // If the window has been recreated after beeing e.g. a sheet,
2217 // make sure that we don't report a faulty opacity:
2218 q->setWindowOpacity(1.0f);
2219 q->setAttribute(Qt::WA_WState_WindowOpacitySet, false);
2220 }
2221
2222 // Since we only now have a window, sync our state.
2223 macUpdateHideOnSuspend();
2224 macUpdateOpaqueSizeGrip();
2225 macUpdateMetalAttribute();
2226 macUpdateIgnoreMouseEvents();
2227 setWindowTitle_helper(extra->topextra->caption);
2228 setWindowIconText_helper(extra->topextra->iconText);
2229 setWindowFilePath_helper(extra->topextra->filePath);
2230 setWindowModified_sys(q->isWindowModified());
2231 updateFrameStrut();
2232 qt_mac_update_sizer(q);
2233 applyMaxAndMinSizeOnWindow();
2234}
2235#else // QT_MAC_USE_COCOA
2236
2237void QWidgetPrivate::setWindowLevel()
2238{
2239 Q_Q(QWidget);
2240 const QWidget * const windowParent = q->window()->parentWidget();
2241 const QWidget * const primaryWindow = windowParent ? windowParent->window() : 0;
2242 NSInteger winLevel = -1;
2243
2244 if (q->windowType() == Qt::Popup) {
2245 winLevel = NSPopUpMenuWindowLevel;
2246 // Popup should be in at least the same level as its parent.
2247 if (primaryWindow) {
2248 OSWindowRef parentRef = qt_mac_window_for(primaryWindow);
2249 winLevel = qMax([parentRef level], winLevel);
2250 }
2251 } else if (q->windowType() == Qt::Tool) {
2252 winLevel = NSFloatingWindowLevel;
2253 } else if (q->windowType() == Qt::Dialog) {
2254 // Correct modality level (NSModalPanelWindowLevel) will be
2255 // set by cocoa when creating a modal session later.
2256 winLevel = NSNormalWindowLevel;
2257 }
2258
2259 // StayOnTop window should appear above Tool windows.
2260 if (data.window_flags & Qt::WindowStaysOnTopHint)
2261 winLevel = NSPopUpMenuWindowLevel;
2262 // Tooltips should appear above StayOnTop windows.
2263 if (q->windowType() == Qt::ToolTip)
2264 winLevel = NSScreenSaverWindowLevel;
2265 // All other types are Normal level.
2266 if (winLevel == -1)
2267 winLevel = NSNormalWindowLevel;
2268 [qt_mac_window_for(q) setLevel:winLevel];
2269}
2270
2271void QWidgetPrivate::finishCreateWindow_sys_Cocoa(void * /*NSWindow * */ voidWindowRef)
2272{
2273 Q_Q(QWidget);
2274 QMacCocoaAutoReleasePool pool;
2275 NSWindow *windowRef = static_cast<NSWindow *>(voidWindowRef);
2276 const Qt::WindowType type = q->windowType();
2277 Qt::WindowFlags &flags = data.window_flags;
2278 QWidget *parentWidget = q->parentWidget();
2279
2280 const bool popup = (type == Qt::Popup);
2281 const bool dialog = (type == Qt::Dialog
2282 || type == Qt::Sheet
2283 || type == Qt::Drawer
2284 || (flags & Qt::MSWindowsFixedSizeDialogHint));
2285 QTLWExtra *topExtra = topData();
2286
2287 if ((popup || type == Qt::Tool || type == Qt::ToolTip) && !q->isModal()) {
2288 [windowRef setHidesOnDeactivate:YES];
2289 } else {
2290 [windowRef setHidesOnDeactivate:NO];
2291 }
2292 [windowRef setHasShadow:YES];
2293 Q_UNUSED(parentWidget);
2294 Q_UNUSED(dialog);
2295
2296 data.fstrut_dirty = true; // when we create a toplevel widget, the frame strut should be dirty
2297 OSViewRef nsview = (OSViewRef)data.winid;
2298 OSViewRef window_contentview = qt_mac_get_contentview_for(windowRef);
2299 if (!nsview) {
2300 nsview = qt_mac_create_widget(q, this, window_contentview);
2301 setWinId(WId(nsview));
2302 } else {
2303 [window_contentview addSubview:nsview];
2304 }
2305 if (nsview) {
2306 NSRect bounds = [window_contentview bounds];
2307 [nsview setFrame:bounds];
2308 [nsview setHidden:NO];
2309 if (q->testAttribute(Qt::WA_DropSiteRegistered))
2310 registerDropSite(true);
2311 transferChildren();
2312
2313 // Tell Cocoa explicit that we wan't the view to receive key events
2314 // (regardless of focus policy) because this is how it works on other
2315 // platforms (and in the carbon port):
2316 if (!qApp->focusWidget())
2317 [windowRef makeFirstResponder:nsview];
2318 }
2319
2320 if (topExtra->posFromMove) {
2321 updateFrameStrut();
2322
2323 const QRect &fStrut = frameStrut();
2324 const QRect &crect = data.crect;
2325 const QRect frameRect(QPoint(crect.left(), crect.top()),
2326 QSize(fStrut.left() + fStrut.right() + crect.width(),
2327 fStrut.top() + fStrut.bottom() + crect.height()));
2328 NSRect cocoaFrameRect = NSMakeRect(frameRect.x(), flipYCoordinate(frameRect.bottom() + 1),
2329 frameRect.width(), frameRect.height());
2330 [windowRef setFrame:cocoaFrameRect display:NO];
2331 topExtra->posFromMove = false;
2332 }
2333
2334 if (q->testAttribute(Qt::WA_WState_WindowOpacitySet)){
2335 q->setWindowOpacity(topExtra->opacity / 255.0f);
2336 } else if (qt_mac_is_macsheet(q)){
2337 CGFloat alpha = [qt_mac_window_for(q) alphaValue];
2338 if (alpha >= 1.0) {
2339 q->setWindowOpacity(0.95f);
2340 q->setAttribute(Qt::WA_WState_WindowOpacitySet, false);
2341 }
2342 } else{
2343 // If the window has been recreated after beeing e.g. a sheet,
2344 // make sure that we don't report a faulty opacity:
2345 q->setWindowOpacity(1.0f);
2346 q->setAttribute(Qt::WA_WState_WindowOpacitySet, false);
2347 }
2348
2349 if (qApp->overrideCursor())
2350 [windowRef disableCursorRects];
2351
2352 setWindowLevel();
2353 macUpdateHideOnSuspend();
2354 macUpdateOpaqueSizeGrip();
2355 macUpdateIgnoreMouseEvents();
2356 setWindowTitle_helper(extra->topextra->caption);
2357 setWindowIconText_helper(extra->topextra->iconText);
2358 setWindowModified_sys(q->isWindowModified());
2359 updateFrameStrut();
2360 syncCocoaMask();
2361 macUpdateIsOpaque();
2362 qt_mac_update_sizer(q);
2363 applyMaxAndMinSizeOnWindow();
2364}
2365
2366#endif // QT_MAC_USE_COCOA
2367
2368/*
2369 Recreates widget window. Useful if immutable
2370 properties for it has changed.
2371 */
2372void QWidgetPrivate::recreateMacWindow()
2373{
2374 Q_Q(QWidget);
2375 OSViewRef myView = qt_mac_nativeview_for(q);
2376 OSWindowRef oldWindow = qt_mac_window_for(myView);
2377#ifndef QT_MAC_USE_COCOA
2378 HIViewRemoveFromSuperview(myView);
2379 determineWindowClass();
2380 createWindow_sys();
2381
2382 if (QMainWindowLayout *mwl = qt_mainwindow_layout(qobject_cast<QMainWindow *>(q))) {
2383 mwl->updateHIToolBarStatus();
2384 }
2385
2386 if (IsWindowVisible(oldWindow))
2387 show_sys();
2388#else
2389 QMacCocoaAutoReleasePool pool;
2390 [myView removeFromSuperview];
2391 determineWindowClass();
2392 createWindow_sys();
2393 if (NSToolbar *toolbar = [oldWindow toolbar]) {
2394 OSWindowRef newWindow = qt_mac_window_for(myView);
2395 [newWindow setToolbar:toolbar];
2396 [toolbar setVisible:[toolbar isVisible]];
2397 }
2398 if ([oldWindow isVisible]){
2399 if ([oldWindow isSheet])
2400 [NSApp endSheet:oldWindow];
2401 [oldWindow orderOut:oldWindow];
2402 show_sys();
2403 }
2404#endif // QT_MAC_USE_COCOA
2405
2406 // Release the window after creating the new window, because releasing it early
2407 // may cause the app to quit ("close on last window closed attribute")
2408 qt_mac_destructWindow(oldWindow);
2409}
2410
2411void QWidgetPrivate::createWindow_sys()
2412{
2413 Q_Q(QWidget);
2414 Qt::WindowFlags &flags = data.window_flags;
2415 QWidget *parentWidget = q->parentWidget();
2416
2417 QTLWExtra *topExtra = topData();
2418 if (topExtra->embedded)
2419 return; // Simply return because this view "is" the top window.
2420 quint32 wattr = topExtra->wattr;
2421
2422 if(parentWidget && (parentWidget->window()->windowFlags() & Qt::WindowStaysOnTopHint)) // If our parent has Qt::WStyle_StaysOnTop, so must we
2423 flags |= Qt::WindowStaysOnTopHint;
2424
2425 data.fstrut_dirty = true;
2426
2427 OSWindowRef windowRef = qt_mac_create_window(q, topExtra->wclass, wattr, data.crect);
2428 if (windowRef == 0)
2429 qWarning("QWidget: Internal error: %s:%d: If you reach this error please contact Qt Support and include the\n"
2430 " WidgetFlags used in creating the widget.", __FILE__, __LINE__);
2431#ifndef QT_MAC_USE_COCOA
2432 finishCreateWindow_sys_Carbon(windowRef);
2433#else
2434 finishCreateWindow_sys_Cocoa(windowRef);
2435#endif
2436}
2437
2438void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyOldWindow)
2439{
2440 Q_Q(QWidget);
2441 OSViewRef destroyid = 0;
2442#ifndef QT_MAC_USE_COCOA
2443 window_event = 0;
2444#endif
2445
2446 Qt::WindowType type = q->windowType();
2447 Qt::WindowFlags flags = data.window_flags;
2448 QWidget *parentWidget = q->parentWidget();
2449
2450 bool topLevel = (flags & Qt::Window);
2451 bool popup = (type == Qt::Popup);
2452 bool dialog = (type == Qt::Dialog
2453 || type == Qt::Sheet
2454 || type == Qt::Drawer
2455 || (flags & Qt::MSWindowsFixedSizeDialogHint));
2456 bool desktop = (type == Qt::Desktop);
2457
2458 // Determine this early for top-levels so, we can use it later.
2459 if (topLevel)
2460 determineWindowClass();
2461
2462 if (desktop) {
2463 QSize desktopSize = qt_mac_desktopSize();
2464 q->setAttribute(Qt::WA_WState_Visible);
2465 data.crect.setRect(0, 0, desktopSize.width(), desktopSize.height());
2466 dialog = popup = false; // force these flags off
2467 } else {
2468 q->setAttribute(Qt::WA_WState_Visible, false);
2469
2470 if (topLevel && (type != Qt::Drawer)) {
2471 if (QDesktopWidget *dsk = QApplication::desktop()) { // calc pos/size from screen
2472 const bool wasResized = q->testAttribute(Qt::WA_Resized);
2473 const bool wasMoved = q->testAttribute(Qt::WA_Moved);
2474 int deskn = dsk->primaryScreen();
2475 if (parentWidget && parentWidget->windowType() != Qt::Desktop)
2476 deskn = dsk->screenNumber(parentWidget);
2477 QRect screenGeo = dsk->screenGeometry(deskn);
2478 if (!wasResized) {
2479#ifndef QT_MAC_USE_COCOA
2480 data.crect.setSize(QSize(screenGeo.width()/2, 4*screenGeo.height()/10));
2481#else
2482 NSRect newRect = [NSWindow frameRectForContentRect:NSMakeRect(0, 0,
2483 screenGeo.width() / 2.,
2484 4 * screenGeo.height() / 10.)
2485 styleMask:topData()->wattr];
2486 data.crect.setSize(QSize(newRect.size.width, newRect.size.height));
2487#endif
2488 // Constrain to minimums and maximums we've set
2489 if (extra->minw > 0)
2490 data.crect.setWidth(qMax(extra->minw, data.crect.width()));
2491 if (extra->minh > 0)
2492 data.crect.setHeight(qMax(extra->minh, data.crect.height()));
2493 if (extra->maxw > 0)
2494 data.crect.setWidth(qMin(extra->maxw, data.crect.width()));
2495 if (extra->maxh > 0)
2496 data.crect.setHeight(qMin(extra->maxh, data.crect.height()));
2497 }
2498 if (!wasMoved && !q->testAttribute(Qt::WA_DontShowOnScreen))
2499 data.crect.moveTopLeft(QPoint(screenGeo.width()/4,
2500 3 * screenGeo.height() / 10));
2501 }
2502 }
2503 }
2504
2505
2506 if(!window) // always initialize
2507 initializeWindow=true;
2508
2509 hd = 0;
2510 if(window) { // override the old window (with a new NSView)
2511 OSViewRef nativeView = OSViewRef(window);
2512 OSViewRef parent = 0;
2513#ifndef QT_MAC_USE_COCOA
2514 CFRetain(nativeView);
2515#else
2516 [nativeView retain];
2517#endif
2518 if (destroyOldWindow)
2519 destroyid = qt_mac_nativeview_for(q);
2520 bool transfer = false;
2521 setWinId((WId)nativeView);
2522#ifndef QT_MAC_USE_COCOA
2523#ifndef HIViewInstallEventHandler
2524 // Macro taken from the CarbonEvents Header on Tiger
2525#define HIViewInstallEventHandler( target, handler, numTypes, list, userData, outHandlerRef ) \
2526 InstallEventHandler( HIObjectGetEventTarget( (HIObjectRef) (target) ), (handler), (numTypes), (list), (userData), (outHandlerRef) )
2527#endif
2528 HIViewInstallEventHandler(nativeView, make_widget_eventUPP(), GetEventTypeCount(widget_events), widget_events, 0, 0);
2529#endif
2530 if(topLevel) {
2531 for(int i = 0; i < 2; ++i) {
2532 if(i == 1) {
2533 if(!initializeWindow)
2534 break;
2535 createWindow_sys();
2536 }
2537 if(OSWindowRef windowref = qt_mac_window_for(nativeView)) {
2538#ifndef QT_MAC_USE_COCOA
2539 CFRetain(windowref);
2540#else
2541 [windowref retain];
2542#endif
2543 if (initializeWindow) {
2544 parent = qt_mac_get_contentview_for(windowref);
2545 } else {
2546#ifndef QT_MAC_USE_COCOA
2547 parent = HIViewGetSuperview(nativeView);
2548#else
2549 parent = [nativeView superview];
2550#endif
2551 }
2552 break;
2553 }
2554 }
2555 if(!parent)
2556 transfer = true;
2557 } else if (parentWidget) {
2558 // I need to be added to my parent, therefore my parent needs an NSView
2559 parentWidget->createWinId();
2560 parent = qt_mac_nativeview_for(parentWidget);
2561 }
2562 if(parent != nativeView && parent) {
2563#ifndef QT_MAC_USE_COCOA
2564 HIViewAddSubview(parent, nativeView);
2565#else
2566 [parent addSubview:nativeView];
2567#endif
2568 }
2569 if(transfer)
2570 transferChildren();
2571 data.fstrut_dirty = true; // we'll re calculate this later
2572 q->setAttribute(Qt::WA_WState_Visible,
2573#ifndef QT_MAC_USE_COCOA
2574 HIViewIsVisible(nativeView)
2575#else
2576 ![nativeView isHidden]
2577#endif
2578 );
2579 if(initializeWindow) {
2580#ifndef QT_MAC_USE_COCOA
2581 HIRect bounds = CGRectMake(data.crect.x(), data.crect.y(), data.crect.width(), data.crect.height());
2582 HIViewSetFrame(nativeView, &bounds);
2583 q->setAttribute(Qt::WA_WState_Visible, HIViewIsVisible(nativeView));
2584#else
2585 NSRect bounds = NSMakeRect(data.crect.x(), data.crect.y(), data.crect.width(), data.crect.height());
2586 [nativeView setFrame:bounds];
2587 q->setAttribute(Qt::WA_WState_Visible, [nativeView isHidden]);
2588#endif
2589 }
2590#ifndef QT_MAC_USE_COCOA
2591 initWindowPtr();
2592#endif
2593 } else if (desktop) { // desktop widget
2594 if (!qt_root_win)
2595 QWidgetPrivate::qt_create_root_win();
2596 Q_ASSERT(qt_root_win);
2597 WId rootWinID = 0;
2598#ifndef QT_MAC_USE_COCOA
2599 CFRetain(qt_root_win);
2600 if(HIViewRef rootContentView = HIViewGetRoot(qt_root_win)) {
2601 rootWinID = (WId)rootContentView;
2602 CFRetain(rootContentView);
2603 }
2604#else
2605 [qt_root_win retain];
2606 if (OSViewRef rootContentView = [qt_root_win contentView]) {
2607 rootWinID = (WId)rootContentView;
2608 [rootContentView retain];
2609 }
2610#endif
2611 setWinId(rootWinID);
2612 } else if (topLevel) {
2613 determineWindowClass();
2614 if(OSViewRef osview = qt_mac_create_widget(q, this, 0)) {
2615#ifndef QT_MAC_USE_COCOA
2616 HIRect bounds = CGRectMake(data.crect.x(), data.crect.y(),
2617 data.crect.width(), data.crect.height());
2618 HIViewSetFrame(osview, &bounds);
2619#else
2620 NSRect bounds = NSMakeRect(data.crect.x(), flipYCoordinate(data.crect.y()),
2621 data.crect.width(), data.crect.height());
2622 [osview setFrame:bounds];
2623#endif
2624 setWinId((WId)osview);
2625 }
2626 } else {
2627 data.fstrut_dirty = false; // non-toplevel widgets don't have a frame, so no need to update the strut
2628
2629#ifdef QT_MAC_USE_COCOA
2630 if (q->testAttribute(Qt::WA_NativeWindow) == false ||
2631 q->internalWinId() != 0) {
2632#ifdef ALIEN_DEBUG
2633 qDebug() << "Skipping native widget creation for" << this;
2634#endif
2635 } else
2636#endif
2637 if (OSViewRef osview = qt_mac_create_widget(q, this, qt_mac_nativeview_for(parentWidget))) {
2638#ifndef QT_MAC_USE_COCOA
2639 HIRect bounds = CGRectMake(data.crect.x(), data.crect.y(), data.crect.width(), data.crect.height());
2640 HIViewSetFrame(osview, &bounds);
2641 setWinId((WId)osview);
2642#else
2643 NSRect bounds = NSMakeRect(data.crect.x(), data.crect.y(), data.crect.width(), data.crect.height());
2644 [osview setFrame:bounds];
2645 setWinId((WId)osview);
2646#endif
2647 if (q->testAttribute(Qt::WA_DropSiteRegistered))
2648 registerDropSite(true);
2649 }
2650 }
2651
2652 updateIsOpaque();
2653 if (q->hasFocus())
2654 setFocus_sys();
2655 if (!topLevel && initializeWindow)
2656 setWSGeometry();
2657 if (destroyid)
2658 qt_mac_destructView(destroyid);
2659 if (q->testAttribute(Qt::WA_AcceptTouchEvents))
2660 registerTouchWindow();
2661}
2662
2663/*!
2664 Returns the QuickDraw handle of the widget. Use of this function is not
2665 portable. This function will return 0 if QuickDraw is not supported, or
2666 if the handle could not be created.
2667
2668 \warning This function is only available on Mac OS X.
2669*/
2670
2671Qt::HANDLE
2672QWidget::macQDHandle() const
2673{
2674#ifndef QT_MAC_USE_COCOA
2675 return d_func()->qd_hd;
2676#else
2677 return 0;
2678#endif
2679}
2680
2681/*!
2682 Returns the CoreGraphics handle of the widget. Use of this function is
2683 not portable. This function will return 0 if no painter context can be
2684 established, or if the handle could not be created.
2685
2686 \warning This function is only available on Mac OS X.
2687*/
2688Qt::HANDLE
2689QWidget::macCGHandle() const
2690{
2691 return handle();
2692}
2693
2694void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
2695{
2696 Q_D(QWidget);
2697 d->aboutToDestroy();
2698 if (!isWindow() && parentWidget())
2699 parentWidget()->d_func()->invalidateBuffer(d->effectiveRectFor(geometry()));
2700 d->deactivateWidgetCleanup();
2701 qt_mac_event_release(this);
2702 if(testAttribute(Qt::WA_WState_Created)) {
2703 QMacCocoaAutoReleasePool pool;
2704 setAttribute(Qt::WA_WState_Created, false);
2705 QObjectList chldrn = children();
2706 for(int i = 0; i < chldrn.size(); i++) { // destroy all widget children
2707 QObject *obj = chldrn.at(i);
2708 if(obj->isWidgetType())
2709 static_cast<QWidget*>(obj)->destroy(destroySubWindows, destroySubWindows);
2710 }
2711 if(mac_mouse_grabber == this)
2712 releaseMouse();
2713 if(mac_keyboard_grabber == this)
2714 releaseKeyboard();
2715
2716 if(testAttribute(Qt::WA_ShowModal)) // just be sure we leave modal
2717 QApplicationPrivate::leaveModal(this);
2718 else if((windowType() == Qt::Popup))
2719 qApp->d_func()->closePopup(this);
2720 if (destroyWindow) {
2721 if(OSViewRef hiview = qt_mac_nativeview_for(this)) {
2722 OSWindowRef window = 0;
2723 NSDrawer *drawer = nil;
2724#ifdef QT_MAC_USE_COCOA
2725 if (qt_mac_is_macdrawer(this)) {
2726 drawer = qt_mac_drawer_for(this);
2727 } else
2728#endif
2729 if (isWindow())
2730 window = qt_mac_window_for(hiview);
2731
2732 // Because of how "destruct" works, we have to do just a normal release for the root_win.
2733 if (window && window == qt_root_win) {
2734#ifndef QT_MAC_USE_COCOA
2735 CFRelease(hiview);
2736#else
2737 [hiview release];
2738#endif
2739 } else {
2740 qt_mac_destructView(hiview);
2741 }
2742 if (drawer)
2743 qt_mac_destructDrawer(drawer);
2744 if (window)
2745 qt_mac_destructWindow(window);
2746 }
2747 }
2748 QT_TRY {
2749 d->setWinId(0);
2750 } QT_CATCH (const std::bad_alloc &) {
2751 // swallow - destructors must not throw
2752 }
2753 }
2754}
2755
2756void QWidgetPrivate::transferChildren()
2757{
2758 Q_Q(QWidget);
2759 if (!q->testAttribute(Qt::WA_WState_Created))
2760 return; // Can't add any views anyway
2761
2762 QObjectList chlist = q->children();
2763 for (int i = 0; i < chlist.size(); ++i) {
2764 QObject *obj = chlist.at(i);
2765 if (obj->isWidgetType()) {
2766 QWidget *w = (QWidget *)obj;
2767 if (!w->isWindow()) {
2768 // This seems weird, no need to call it in a loop right?
2769 if (!topData()->caption.isEmpty())
2770 setWindowTitle_helper(extra->topextra->caption);
2771 if (w->testAttribute(Qt::WA_WState_Created)) {
2772#ifndef QT_MAC_USE_COCOA
2773 HIViewAddSubview(qt_mac_nativeview_for(q), qt_mac_nativeview_for(w));
2774#else
2775 // New NSWindows get an extra reference when drops are
2776 // registered (at least in 10.5) which means that we may
2777 // access the window later and get a crash (becasue our
2778 // widget is dead). Work around this be having the drop
2779 // site disabled until it is part of the new hierarchy.
2780 bool oldRegistered = w->testAttribute(Qt::WA_DropSiteRegistered);
2781 w->setAttribute(Qt::WA_DropSiteRegistered, false);
2782 [qt_mac_nativeview_for(w) retain];
2783 [qt_mac_nativeview_for(w) removeFromSuperview];
2784 [qt_mac_nativeview_for(q) addSubview:qt_mac_nativeview_for(w)];
2785 [qt_mac_nativeview_for(w) release];
2786 w->setAttribute(Qt::WA_DropSiteRegistered, oldRegistered);
2787#endif
2788 }
2789 }
2790 }
2791 }
2792}
2793
2794#ifdef QT_MAC_USE_COCOA
2795void QWidgetPrivate::setSubWindowStacking(bool set)
2796{
2797 // This will set/remove a visual relationship between parent and child on screen.
2798 // The reason for doing this is to ensure that a child always stacks infront of
2799 // its parent. Unfortunatly is turns out that [NSWindow addChildWindow] has
2800 // several unwanted side-effects, one of them being the moving of a child when
2801 // moving the parent, which we choose to accept. A way tougher side-effect is
2802 // that Cocoa will hide the parent if you hide the child. And in the case of
2803 // a tool window, since it will normally hide when you deactivate the
2804 // application, Cocoa will hide the parent upon deactivate as well. The result often
2805 // being no more visible windows on screen. So, to make a long story short, we only
2806 // allow parent-child relationships between windows that both are either a plain window
2807 // or a dialog.
2808
2809 Q_Q(QWidget);
2810 if (!q->isWindow())
2811 return;
2812 NSWindow *qwin = [qt_mac_nativeview_for(q) window];
2813 if (!qwin)
2814 return;
2815 Qt::WindowType qtype = q->windowType();
2816 if (set && !(qtype == Qt::Window || qtype == Qt::Dialog))
2817 return;
2818 if (set && ![qwin isVisible])
2819 return;
2820
2821 if (QWidget *parent = q->parentWidget()) {
2822 if (NSWindow *pwin = [qt_mac_nativeview_for(parent) window]) {
2823 if (set) {
2824 Qt::WindowType ptype = parent->window()->windowType();
2825 if ([pwin isVisible] && (ptype == Qt::Window || ptype == Qt::Dialog) && ![qwin parentWindow]) {
2826 NSInteger level = [qwin level];
2827 [pwin addChildWindow:qwin ordered:NSWindowAbove];
2828 if ([qwin level] < level)
2829 [qwin setLevel:level];
2830 }
2831 } else {
2832 [pwin removeChildWindow:qwin];
2833 }
2834 }
2835 }
2836
2837 QObjectList widgets = q->children();
2838 for (int i=0; i<widgets.size(); ++i) {
2839 QWidget *child = qobject_cast<QWidget *>(widgets.at(i));
2840 if (child && child->isWindow()) {
2841 if (NSWindow *cwin = [qt_mac_nativeview_for(child) window]) {
2842 if (set) {
2843 Qt::WindowType ctype = child->window()->windowType();
2844 if ([cwin isVisible] && (ctype == Qt::Window || ctype == Qt::Dialog) && ![cwin parentWindow]) {
2845 NSInteger level = [cwin level];
2846 [qwin addChildWindow:cwin ordered:NSWindowAbove];
2847 if ([cwin level] < level)
2848 [cwin setLevel:level];
2849 }
2850 } else {
2851 [qwin removeChildWindow:qt_mac_window_for(child)];
2852 }
2853 }
2854 }
2855 }
2856}
2857#endif
2858
2859void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
2860{
2861 Q_Q(QWidget);
2862 QMacCocoaAutoReleasePool pool;
2863 QTLWExtra *topData = maybeTopData();
2864 bool wasCreated = q->testAttribute(Qt::WA_WState_Created);
2865#ifdef QT_MAC_USE_COCOA
2866 bool wasWindow = q->isWindow();
2867#endif
2868 OSViewRef old_id = 0;
2869
2870 if (q->isVisible() && q->parentWidget() && parent != q->parentWidget())
2871 q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(q->geometry()));
2872
2873 // Maintain the glWidgets list on parent change: remove "our" gl widgets
2874 // from the list on the old parent and grandparents.
2875 if (glWidgets.isEmpty() == false) {
2876 QWidget *current = q->parentWidget();
2877 while (current) {
2878 for (QList<QWidgetPrivate::GlWidgetInfo>::const_iterator it = glWidgets.constBegin();
2879 it != glWidgets.constEnd(); ++it)
2880 current->d_func()->glWidgets.removeAll(*it);
2881
2882 if (current->isWindow())
2883 break;
2884 current = current->parentWidget();
2885 }
2886 }
2887
2888#ifndef QT_MAC_USE_COCOA
2889 EventHandlerRef old_window_event = 0;
2890#else
2891 bool oldToolbarVisible = false;
2892 NSDrawer *oldDrawer = nil;
2893 NSToolbar *oldToolbar = 0;
2894#endif
2895 if (wasCreated && !(q->windowType() == Qt::Desktop)) {
2896 old_id = qt_mac_nativeview_for(q);
2897#ifndef QT_MAC_USE_COCOA
2898 old_window_event = window_event;
2899#else
2900 OSWindowRef oldWindow = qt_mac_window_for(old_id);
2901 if (qt_mac_is_macdrawer(q)) {
2902 oldDrawer = qt_mac_drawer_for(q);
2903 }
2904 if (wasWindow) {
2905 oldToolbar = [oldWindow toolbar];
2906 if (oldToolbar) {
2907 [oldToolbar retain];
2908 oldToolbarVisible = [oldToolbar isVisible];
2909 [oldWindow setToolbar:nil];
2910 }
2911 }
2912#endif
2913 }
2914 QWidget* oldtlw = q->window();
2915
2916 if (q->testAttribute(Qt::WA_DropSiteRegistered))
2917 q->setAttribute(Qt::WA_DropSiteRegistered, false);
2918
2919 //recreate and setup flags
2920 QObjectPrivate::setParent_helper(parent);
2921 bool explicitlyHidden = q->testAttribute(Qt::WA_WState_Hidden) && q->testAttribute(Qt::WA_WState_ExplicitShowHide);
2922 if (wasCreated && !qt_isGenuineQWidget(q))
2923 return;
2924
2925 if (!q->testAttribute(Qt::WA_WState_WindowOpacitySet)) {
2926 q->setWindowOpacity(1.0f);
2927 q->setAttribute(Qt::WA_WState_WindowOpacitySet, false);
2928 }
2929
2930 setWinId(0); //do after the above because they may want the id
2931
2932 data.window_flags = f;
2933 q->setAttribute(Qt::WA_WState_Created, false);
2934 q->setAttribute(Qt::WA_WState_Visible, false);
2935 q->setAttribute(Qt::WA_WState_Hidden, false);
2936 adjustFlags(data.window_flags, q);
2937 // keep compatibility with previous versions, we need to preserve the created state.
2938 // (but we recreate the winId for the widget being reparented, again for compatibility,
2939 // unless this is an alien widget. )
2940 const bool nonWindowWithCreatedParent = !q->isWindow() && parent->testAttribute(Qt::WA_WState_Created);
2941 const bool nativeWidget = q->internalWinId() != 0;
2942 if (wasCreated || nativeWidget && nonWindowWithCreatedParent) {
2943 createWinId();
2944 if (q->isWindow()) {
2945#ifndef QT_MAC_USE_COCOA
2946 // We do this down below for wasCreated, so avoid doing this twice
2947 // (only for performance, it gets called a lot anyway).
2948 if (!wasCreated) {
2949 if (QMainWindowLayout *mwl = qt_mainwindow_layout(qobject_cast<QMainWindow *>(q))) {
2950 mwl->updateHIToolBarStatus();
2951 }
2952 }
2953#else
2954 // Simply transfer our toolbar over. Everything should stay put, unlike in Carbon.
2955 if (oldToolbar && !(f & Qt::FramelessWindowHint)) {
2956 OSWindowRef newWindow = qt_mac_window_for(q);
2957 [newWindow setToolbar:oldToolbar];
2958 [oldToolbar release];
2959 [oldToolbar setVisible:oldToolbarVisible];
2960 }
2961#endif
2962 }
2963 }
2964 if (q->isWindow() || (!parent || parent->isVisible()) || explicitlyHidden)
2965 q->setAttribute(Qt::WA_WState_Hidden);
2966 q->setAttribute(Qt::WA_WState_ExplicitShowHide, explicitlyHidden);
2967
2968 if (wasCreated) {
2969 transferChildren();
2970#ifndef QT_MAC_USE_COCOA
2971 // If we were a unified window, We just transfered our toolbars out of the unified toolbar.
2972 // So redo the status one more time. It apparently is not an issue with Cocoa.
2973 if (q->isWindow()) {
2974 if (QMainWindowLayout *mwl = qt_mainwindow_layout(qobject_cast<QMainWindow *>(q))) {
2975 mwl->updateHIToolBarStatus();
2976 }
2977 }
2978#endif
2979
2980 if (topData &&
2981 (!topData->caption.isEmpty() || !topData->filePath.isEmpty()))
2982 setWindowTitle_helper(q->windowTitle());
2983 }
2984
2985 if (q->testAttribute(Qt::WA_AcceptDrops)
2986 || (!q->isWindow() && q->parentWidget()
2987 && q->parentWidget()->testAttribute(Qt::WA_DropSiteRegistered)))
2988 q->setAttribute(Qt::WA_DropSiteRegistered, true);
2989
2990 //cleanup
2991#ifndef QT_MAC_USE_COCOA
2992 if (old_window_event)
2993 RemoveEventHandler(old_window_event);
2994#endif
2995 if (old_id) { //don't need old window anymore
2996 OSWindowRef window = (oldtlw == q) ? qt_mac_window_for(old_id) : 0;
2997 qt_mac_destructView(old_id);
2998
2999#ifdef QT_MAC_USE_COCOA
3000 if (oldDrawer) {
3001 qt_mac_destructDrawer(oldDrawer);
3002 } else
3003#endif
3004 if (window)
3005 qt_mac_destructWindow(window);
3006 }
3007
3008 // Maintain the glWidgets list on parent change: add "our" gl widgets
3009 // to the list on the new parent and grandparents.
3010 if (glWidgets.isEmpty() == false) {
3011 QWidget *current = q->parentWidget();
3012 while (current) {
3013 current->d_func()->glWidgets += glWidgets;
3014 if (current->isWindow())
3015 break;
3016 current = current->parentWidget();
3017 }
3018 }
3019 invalidateBuffer(q->rect());
3020 qt_event_request_window_change(q);
3021}
3022
3023QPoint QWidget::mapToGlobal(const QPoint &pos) const
3024{
3025 Q_D(const QWidget);
3026 if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) {
3027 QPoint p = pos + data->crect.topLeft();
3028 return isWindow() ? p : parentWidget()->mapToGlobal(p);
3029 }
3030#ifndef QT_MAC_USE_COCOA
3031 QPoint tmp = d->mapToWS(pos);
3032 HIPoint hi_pos = CGPointMake(tmp.x(), tmp.y());
3033 HIViewConvertPoint(&hi_pos, qt_mac_nativeview_for(this), 0);
3034 Rect win_rect;
3035 GetWindowBounds(qt_mac_window_for(this), kWindowStructureRgn, &win_rect);
3036 return QPoint((int)hi_pos.x+win_rect.left, (int)hi_pos.y+win_rect.top);
3037#else
3038 QPoint tmp = d->mapToWS(pos);
3039 NSPoint hi_pos = NSMakePoint(tmp.x(), tmp.y());
3040 hi_pos = [qt_mac_nativeview_for(this) convertPoint:hi_pos toView:nil];
3041 NSRect win_rect = [qt_mac_window_for(this) frame];
3042 hi_pos.x += win_rect.origin.x;
3043 hi_pos.y += win_rect.origin.y;
3044 // If we aren't the desktop we need to flip, if you flip the desktop on itself, you get the other problem.
3045 return ((window()->windowFlags() & Qt::Desktop) == Qt::Desktop) ? QPointF(hi_pos.x, hi_pos.y).toPoint()
3046 : flipPoint(hi_pos).toPoint();
3047#endif
3048}
3049
3050QPoint QWidget::mapFromGlobal(const QPoint &pos) const
3051{
3052 Q_D(const QWidget);
3053 if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) {
3054 QPoint p = isWindow() ? pos : parentWidget()->mapFromGlobal(pos);
3055 return p - data->crect.topLeft();
3056 }
3057#ifndef QT_MAC_USE_COCOA
3058 Rect win_rect;
3059 GetWindowBounds(qt_mac_window_for(this), kWindowStructureRgn, &win_rect);
3060 HIPoint hi_pos = CGPointMake(pos.x()-win_rect.left, pos.y()-win_rect.top);
3061 HIViewConvertPoint(&hi_pos, 0, qt_mac_nativeview_for(this));
3062 return d->mapFromWS(QPoint((int)hi_pos.x, (int)hi_pos.y));
3063#else
3064 NSRect win_rect = [qt_mac_window_for(this) frame];
3065 // The Window point is in "Cocoa coordinates," but the view is in "Qt coordinates"
3066 // so make sure to keep them in sync.
3067 NSPoint hi_pos = NSMakePoint(pos.x()-win_rect.origin.x,
3068 flipYCoordinate(pos.y())-win_rect.origin.y);
3069 hi_pos = [qt_mac_nativeview_for(this) convertPoint:hi_pos fromView:0];
3070 return d->mapFromWS(QPoint(qRound(hi_pos.x), qRound(hi_pos.y)));
3071#endif
3072}
3073
3074void QWidgetPrivate::updateSystemBackground()
3075{
3076}
3077
3078void QWidgetPrivate::setCursor_sys(const QCursor &)
3079{
3080#ifndef QT_MAC_USE_COCOA
3081 qt_mac_update_cursor();
3082#else
3083 Q_Q(QWidget);
3084 if (q->testAttribute(Qt::WA_WState_Created)) {
3085 QMacCocoaAutoReleasePool pool;
3086 [qt_mac_window_for(q) invalidateCursorRectsForView:qt_mac_nativeview_for(q)];
3087 }
3088#endif
3089}
3090
3091void QWidgetPrivate::unsetCursor_sys()
3092{
3093#ifndef QT_MAC_USE_COCOA
3094 qt_mac_update_cursor();
3095#else
3096 Q_Q(QWidget);
3097 if (q->testAttribute(Qt::WA_WState_Created)) {
3098 QMacCocoaAutoReleasePool pool;
3099 [qt_mac_window_for(q) invalidateCursorRectsForView:qt_mac_nativeview_for(q)];
3100 }
3101#endif
3102}
3103
3104void QWidgetPrivate::setWindowTitle_sys(const QString &caption)
3105{
3106 Q_Q(QWidget);
3107 if (q->isWindow()) {
3108#ifndef QT_MAC_USE_COCOA
3109 SetWindowTitleWithCFString(qt_mac_window_for(q), QCFString(caption));
3110#else
3111 QMacCocoaAutoReleasePool pool;
3112 [qt_mac_window_for(q) setTitle:qt_mac_QStringToNSString(caption)];
3113#endif
3114 }
3115}
3116
3117void QWidgetPrivate::setWindowModified_sys(bool mod)
3118{
3119 Q_Q(QWidget);
3120 if (q->isWindow() && q->testAttribute(Qt::WA_WState_Created)) {
3121#ifndef QT_MAC_USE_COCOA
3122 SetWindowModified(qt_mac_window_for(q), mod);
3123#else
3124 [qt_mac_window_for(q) setDocumentEdited:mod];
3125#endif
3126 }
3127}
3128
3129void QWidgetPrivate::setWindowFilePath_sys(const QString &filePath)
3130{
3131 Q_Q(QWidget);
3132#ifdef QT_MAC_USE_COCOA
3133 QMacCocoaAutoReleasePool pool;
3134 QFileInfo fi(filePath);
3135 [qt_mac_window_for(q) setRepresentedFilename:fi.exists() ? qt_mac_QStringToNSString(filePath) : @""];
3136#else
3137 bool validRef = false;
3138 FSRef ref;
3139 bzero(&ref, sizeof(ref));
3140 OSStatus status;
3141
3142 if (!filePath.isEmpty()) {
3143 status = FSPathMakeRef(reinterpret_cast<const UInt8 *>(filePath.toUtf8().constData()), &ref, 0);
3144 validRef = (status == noErr);
3145 }
3146 // Set the proxy regardless, since this is our way of clearing it as well, but ignore the
3147 // return value as well.
3148 if (validRef) {
3149 status = HIWindowSetProxyFSRef(qt_mac_window_for(q), &ref);
3150 } else {
3151 status = RemoveWindowProxy(qt_mac_window_for(q));
3152 }
3153 if (status != noErr)
3154 qWarning("QWidget::setWindowFilePath: Error setting proxyicon for path (%s):%ld",
3155 qPrintable(filePath), status);
3156#endif
3157}
3158
3159void QWidgetPrivate::setWindowIcon_sys(bool forceReset)
3160{
3161 Q_Q(QWidget);
3162
3163 if (!q->testAttribute(Qt::WA_WState_Created))
3164 return;
3165
3166 QTLWExtra *topData = this->topData();
3167 if (topData->iconPixmap && !forceReset) // already set
3168 return;
3169
3170 QIcon icon = q->windowIcon();
3171 QPixmap *pm = 0;
3172 if (!icon.isNull()) {
3173 // now create the extra
3174 if (!topData->iconPixmap) {
3175 pm = new QPixmap(icon.pixmap(QSize(22, 22)));
3176 topData->iconPixmap = pm;
3177 } else {
3178 pm = topData->iconPixmap;
3179 }
3180 }
3181 if (q->isWindow()) {
3182#ifndef QT_MAC_USE_COCOA
3183 IconRef previousIcon = 0;
3184 if (icon.isNull()) {
3185 RemoveWindowProxy(qt_mac_window_for(q));
3186 previousIcon = topData->windowIcon;
3187 topData->windowIcon = 0;
3188 } else {
3189 WindowClass wclass;
3190 GetWindowClass(qt_mac_window_for(q), &wclass);
3191
3192 if (wclass == kDocumentWindowClass) {
3193 IconRef newIcon = qt_mac_create_iconref(*pm);
3194 previousIcon = topData->windowIcon;
3195 topData->windowIcon = newIcon;
3196 SetWindowProxyIcon(qt_mac_window_for(q), newIcon);
3197 }
3198 }
3199
3200 // Release the previous icon if it was set by this function.
3201 if (previousIcon != 0)
3202 ReleaseIconRef(previousIcon);
3203#else
3204 QMacCocoaAutoReleasePool pool;
3205 NSButton *iconButton = [qt_mac_window_for(q) standardWindowButton:NSWindowDocumentIconButton];
3206 if (iconButton == nil) {
3207 QCFString string(q->windowTitle());
3208 const NSString *tmpString = reinterpret_cast<const NSString *>((CFStringRef)string);
3209 [qt_mac_window_for(q) setRepresentedURL:[NSURL fileURLWithPath:tmpString]];
3210 iconButton = [qt_mac_window_for(q) standardWindowButton:NSWindowDocumentIconButton];
3211 }
3212 if (icon.isNull()) {
3213 [iconButton setImage:nil];
3214 } else {
3215 QPixmap scaled = pm->scaled(QSize(16,16), Qt::KeepAspectRatio, Qt::SmoothTransformation);
3216 NSImage *image = static_cast<NSImage *>(qt_mac_create_nsimage(scaled));
3217 [iconButton setImage:image];
3218 [image release];
3219 }
3220#endif
3221 }
3222}
3223
3224void QWidgetPrivate::setWindowIconText_sys(const QString &iconText)
3225{
3226 Q_Q(QWidget);
3227 if(q->isWindow() && !iconText.isEmpty()) {
3228#ifndef QT_MAC_USE_COCOA
3229 SetWindowAlternateTitle(qt_mac_window_for(q), QCFString(iconText));
3230#else
3231 QMacCocoaAutoReleasePool pool;
3232 [qt_mac_window_for(q) setMiniwindowTitle:qt_mac_QStringToNSString(iconText)];
3233#endif
3234 }
3235}
3236
3237void QWidget::grabMouse()
3238{
3239 if(isVisible() && !qt_nograb()) {
3240 if(mac_mouse_grabber)
3241 mac_mouse_grabber->releaseMouse();
3242 mac_mouse_grabber=this;
3243 }
3244}
3245
3246#ifndef QT_NO_CURSOR
3247void QWidget::grabMouse(const QCursor &)
3248{
3249 if(isVisible() && !qt_nograb()) {
3250 if(mac_mouse_grabber)
3251 mac_mouse_grabber->releaseMouse();
3252 mac_mouse_grabber=this;
3253 }
3254}
3255#endif
3256
3257void QWidget::releaseMouse()
3258{
3259 if(!qt_nograb() && mac_mouse_grabber == this)
3260 mac_mouse_grabber = 0;
3261}
3262
3263void QWidget::grabKeyboard()
3264{
3265 if(!qt_nograb()) {
3266 if(mac_keyboard_grabber)
3267 mac_keyboard_grabber->releaseKeyboard();
3268 mac_keyboard_grabber = this;
3269 }
3270}
3271
3272void QWidget::releaseKeyboard()
3273{
3274 if(!qt_nograb() && mac_keyboard_grabber == this)
3275 mac_keyboard_grabber = 0;
3276}
3277
3278QWidget *QWidget::mouseGrabber()
3279{
3280 return mac_mouse_grabber;
3281}
3282
3283QWidget *QWidget::keyboardGrabber()
3284{
3285 return mac_keyboard_grabber;
3286}
3287
3288void QWidget::activateWindow()
3289{
3290 QWidget *tlw = window();
3291 if(!tlw->isVisible() || !tlw->isWindow() || (tlw->windowType() == Qt::Desktop))
3292 return;
3293 qt_event_remove_activate();
3294
3295 QWidget *fullScreenWidget = tlw;
3296 QWidget *parentW = tlw;
3297 // Find the oldest parent or the parent with fullscreen, whichever comes first.
3298 while (parentW) {
3299 fullScreenWidget = parentW->window();
3300 if (fullScreenWidget->windowState() & Qt::WindowFullScreen)
3301 break;
3302 parentW = fullScreenWidget->parentWidget();
3303 }
3304
3305 if (fullScreenWidget->windowType() != Qt::ToolTip) {
3306 qt_mac_set_fullscreen_mode((fullScreenWidget->windowState() & Qt::WindowFullScreen) &&
3307 qApp->desktop()->screenNumber(this) == 0);
3308 }
3309
3310 bool windowActive;
3311 OSWindowRef win = qt_mac_window_for(tlw);
3312#ifndef QT_MAC_USE_COCOA
3313 windowActive = IsWindowActive(win);
3314#else
3315 QMacCocoaAutoReleasePool pool;
3316 windowActive = [win isKeyWindow];
3317#endif
3318 if ((tlw->windowType() == Qt::Popup)
3319 || (tlw->windowType() == Qt::Tool)
3320 || qt_mac_is_macdrawer(tlw)
3321 || windowActive) {
3322#ifndef QT_MAC_USE_COCOA
3323 ActivateWindow(win, true);
3324 qApp->setActiveWindow(tlw);
3325#else
3326 [win makeKeyWindow];
3327#endif
3328 } else if(!isMinimized()) {
3329#ifndef QT_MAC_USE_COCOA
3330 SelectWindow(win);
3331#else
3332 [win makeKeyAndOrderFront:win];
3333#endif
3334 }
3335}
3336
3337QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys()
3338{
3339 return new QMacWindowSurface(q_func());
3340}
3341
3342void QWidgetPrivate::update_sys(const QRect &r)
3343{
3344 Q_Q(QWidget);
3345 if (r == q->rect()) {
3346 if (updateRedirectedToGraphicsProxyWidget(q, r))
3347 return;
3348 dirtyOnWidget += r;
3349#ifndef QT_MAC_USE_COCOA
3350 HIViewSetNeedsDisplay(qt_mac_nativeview_for(q), true);
3351#else
3352 qt_mac_set_needs_display(q, QRegion());
3353#endif
3354 return;
3355 }
3356
3357 int x = r.x(), y = r.y(), w = r.width(), h = r.height();
3358 if (w < 0)
3359 w = q->data->crect.width() - x;
3360 if (h < 0)
3361 h = q->data->crect.height() - y;
3362 if (w && h) {
3363 const QRect updateRect = QRect(x, y, w, h);
3364 if (updateRedirectedToGraphicsProxyWidget(q, updateRect))
3365 return;
3366#ifndef QT_MAC_USE_COCOA
3367 dirtyOnWidget += updateRect;
3368 HIRect r = CGRectMake(x, y, w, h);
3369 HIViewSetNeedsDisplayInRect(qt_mac_nativeview_for(q), &r, true);
3370#else
3371 [qt_mac_nativeview_for(q) setNeedsDisplayInRect:NSMakeRect(x, y, w, h)];
3372#endif
3373 }
3374}
3375
3376void QWidgetPrivate::update_sys(const QRegion &rgn)
3377{
3378 Q_Q(QWidget);
3379 if (updateRedirectedToGraphicsProxyWidget(q, rgn))
3380 return;
3381 dirtyOnWidget += rgn;
3382#ifndef QT_MAC_USE_COCOA
3383 RgnHandle rgnHandle = rgn.toQDRgnForUpdate_sys();
3384 if (rgnHandle)
3385 HIViewSetNeedsDisplayInRegion(qt_mac_nativeview_for(q), QMacSmartQuickDrawRegion(rgnHandle), true);
3386 else {
3387 HIViewSetNeedsDisplay(qt_mac_nativeview_for(q), true); // do a complete repaint on overflow.
3388 }
3389#else
3390 // Alien support: get the first native ancestor widget (will be q itself in the non-alien case),
3391 // map the coordinates from q space to NSView space and invalidate the rect.
3392 QWidget *nativeParent = q->internalWinId() ? q : q->nativeParentWidget();
3393 if (nativeParent == 0)
3394 return;
3395
3396 QVector<QRect> rects = rgn.rects();
3397 for (int i = 0; i < rects.count(); ++i) {
3398 const QRect &rect = rects.at(i);
3399
3400 const QRect nativeBoundingRect = QRect(
3401 QPoint(q->mapTo(nativeParent, rect.topLeft())),
3402 QSize(rect.size()));
3403
3404 [qt_mac_nativeview_for(nativeParent) setNeedsDisplayInRect:NSMakeRect(nativeBoundingRect.x(),
3405 nativeBoundingRect.y(), nativeBoundingRect.width(),
3406 nativeBoundingRect.height())];
3407 }
3408#endif
3409}
3410
3411bool QWidgetPrivate::isRealWindow() const
3412{
3413 return q_func()->isWindow() && !topData()->embedded;
3414}
3415
3416void QWidgetPrivate::show_sys()
3417{
3418 Q_Q(QWidget);
3419 if ((q->windowType() == Qt::Desktop)) //desktop is always visible
3420 return;
3421
3422 invalidateBuffer(q->rect());
3423 if (q->testAttribute(Qt::WA_OutsideWSRange))
3424 return;
3425 QMacCocoaAutoReleasePool pool;
3426 q->setAttribute(Qt::WA_Mapped);
3427 if (q->testAttribute(Qt::WA_DontShowOnScreen))
3428 return;
3429
3430 bool realWindow = isRealWindow();
3431#ifndef QT_MAC_USE_COCOA
3432 if (realWindow && !q->testAttribute(Qt::WA_Moved)) {
3433 if (qt_mac_is_macsheet(q))
3434 recreateMacWindow();
3435 q->createWinId();
3436 if (QWidget *p = q->parentWidget()) {
3437 p->createWinId();
3438 RepositionWindow(qt_mac_window_for(q), qt_mac_window_for(p), kWindowCenterOnParentWindow);
3439 } else {
3440 RepositionWindow(qt_mac_window_for(q), 0, kWindowCenterOnMainScreen);
3441 }
3442 }
3443#endif
3444
3445 data.fstrut_dirty = true;
3446 if (realWindow) {
3447 // Delegates can change window state, so record some things earlier.
3448 bool isCurrentlyMinimized = (q->windowState() & Qt::WindowMinimized);
3449 setModal_sys();
3450 OSWindowRef window = qt_mac_window_for(q);
3451#ifndef QT_MAC_USE_COCOA
3452 SizeWindow(window, q->width(), q->height(), true);
3453#endif
3454
3455#ifdef QT_MAC_USE_COCOA
3456 // Make sure that we end up sending a repaint event to
3457 // the widget if the window has been visible one before:
3458 [qt_mac_get_contentview_for(window) setNeedsDisplay:YES];
3459#endif
3460 if(qt_mac_is_macsheet(q)) {
3461 qt_event_request_showsheet(q);
3462 } else if(qt_mac_is_macdrawer(q)) {
3463#ifndef QT_MAC_USE_COCOA
3464 OpenDrawer(window, kWindowEdgeDefault, false);
3465#else
3466 NSDrawer *drawer = qt_mac_drawer_for(q);
3467 [drawer openOnEdge:[drawer preferredEdge]];
3468#endif
3469 } else {
3470#ifndef QT_MAC_USE_COCOA
3471 ShowHide(window, true);
3472#else
3473 // sync the opacity value back (in case of a fade).
3474 [window setAlphaValue:q->windowOpacity()];
3475
3476 QWidget *top = 0;
3477 if (QApplicationPrivate::tryModalHelper(q, &top)) {
3478 [window makeKeyAndOrderFront:window];
3479 // If this window is app modal, we need to start spinning
3480 // a modal session for it. Interrupting
3481 // the event dispatcher will make this happend:
3482 if (data.window_modality == Qt::ApplicationModal)
3483 QEventDispatcherMac::instance()->interrupt();
3484 } else {
3485 // The window is modally shaddowed, so we need to make
3486 // sure that we don't pop in front of the modal window:
3487 [window orderFront:window];
3488 if (!top->testAttribute(Qt::WA_DontShowOnScreen)) {
3489 if (NSWindow *modalWin = qt_mac_window_for(top))
3490 [modalWin orderFront:window];
3491 }
3492 }
3493 setSubWindowStacking(true);
3494#endif
3495 if (q->windowType() == Qt::Popup) {
3496 if (q->focusWidget())
3497 q->focusWidget()->d_func()->setFocus_sys();
3498 else
3499 setFocus_sys();
3500 }
3501 toggleDrawers(true);
3502 }
3503 if (isCurrentlyMinimized) { //show in collapsed state
3504#ifndef QT_MAC_USE_COCOA
3505 CollapseWindow(window, true);
3506#else
3507 [window miniaturize:window];
3508#endif
3509 } else if (!q->testAttribute(Qt::WA_ShowWithoutActivating)) {
3510#ifndef QT_MAC_USE_COCOA
3511 qt_event_request_activate(q);
3512#endif
3513 }
3514 } else if(topData()->embedded || !q->parentWidget() || q->parentWidget()->isVisible()) {
3515#ifndef QT_MAC_USE_COCOA
3516 HIViewSetVisible(qt_mac_nativeview_for(q), true);
3517#else
3518 [qt_mac_nativeview_for(q) setHidden:NO];
3519
3520#endif
3521 }
3522
3523 if (!QWidget::mouseGrabber()){
3524 QWidget *enterWidget = QApplication::widgetAt(QCursor::pos());
3525 QApplicationPrivate::dispatchEnterLeave(enterWidget, qt_mouseover);
3526 qt_mouseover = enterWidget;
3527 }
3528
3529 qt_event_request_window_change(q);
3530}
3531
3532
3533QPoint qt_mac_nativeMapFromParent(const QWidget *child, const QPoint &pt)
3534{
3535#ifndef QT_MAC_USE_COCOA
3536 CGPoint nativePoint = CGPointMake(pt.x(), pt.y());
3537 HIViewConvertPoint(&nativePoint, qt_mac_nativeview_for(child->parentWidget()),
3538 qt_mac_nativeview_for(child));
3539#else
3540 NSPoint nativePoint = [qt_mac_nativeview_for(child) convertPoint:NSMakePoint(pt.x(), pt.y()) fromView:qt_mac_nativeview_for(child->parentWidget())];
3541#endif
3542 return QPoint(nativePoint.x, nativePoint.y);
3543}
3544
3545
3546void QWidgetPrivate::hide_sys()
3547{
3548 Q_Q(QWidget);
3549 if((q->windowType() == Qt::Desktop)) //you can't hide the desktop!
3550 return;
3551 QMacCocoaAutoReleasePool pool;
3552 if(q->isWindow()) {
3553#ifdef QT_MAC_USE_COCOA
3554 setSubWindowStacking(false);
3555#endif
3556 OSWindowRef window = qt_mac_window_for(q);
3557 if(qt_mac_is_macsheet(q)) {
3558#ifndef QT_MAC_USE_COCOA
3559 WindowRef parent = 0;
3560 if(GetSheetWindowParent(window, &parent) != noErr || !parent)
3561 ShowHide(window, false);
3562 else
3563 HideSheetWindow(window);
3564#else
3565 [NSApp endSheet:window];
3566 [window orderOut:window];
3567#endif
3568 } else if(qt_mac_is_macdrawer(q)) {
3569#ifndef QT_MAC_USE_COCOA
3570 CloseDrawer(window, false);
3571#else
3572 [qt_mac_drawer_for(q) close];
3573#endif
3574 } else {
3575#ifndef QT_MAC_USE_COCOA
3576 ShowHide(window, false);
3577#else
3578 [window orderOut:window];
3579 // Unfortunately it is not as easy as just hiding the window, we need
3580 // to find out if we were in full screen mode. If we were and this is
3581 // the last window in full screen mode then we need to unset the full screen
3582 // mode. If this is not the last visible window in full screen mode then we
3583 // don't change the full screen mode.
3584 if(q->isFullScreen())
3585 {
3586 bool keepFullScreen = false;
3587 QWidgetList windowList = qApp->topLevelWidgets();
3588 int windowCount = windowList.count();
3589 for(int i = 0; i < windowCount; i++)
3590 {
3591 QWidget *w = windowList[i];
3592 // If it is the same window, we don't need to check :-)
3593 if(q == w)
3594 continue;
3595 // If they are not visible or if they are minimized then
3596 // we just ignore them.
3597 if(!w->isVisible() || w->isMinimized())
3598 continue;
3599 // Is it full screen?
3600 // Notice that if there is one window in full screen mode then we
3601 // cannot switch the full screen mode off, therefore we just abort.
3602 if(w->isFullScreen()) {
3603 keepFullScreen = true;
3604 break;
3605 }
3606 }
3607 // No windows in full screen mode, so let just unset that flag.
3608 if(!keepFullScreen)
3609 qt_mac_set_fullscreen_mode(false);
3610 }
3611#endif
3612 toggleDrawers(false);
3613#ifndef QT_MAC_USE_COCOA
3614 // Clear modality (because it seems something that we've always done).
3615 if (data.window_modality != Qt::NonModal) {
3616 SetWindowModality(window, kWindowModalityNone,
3617 q->parentWidget() ? qt_mac_window_for(q->parentWidget()->window()) : 0);
3618 }
3619#endif
3620 }
3621#ifndef QT_MAC_USE_COCOA
3622 // If the window we now hide was the active window, we need
3623 // to find, and activate another window on screen. NB: Cocoa takes care of this
3624 // logic for us (and distinquishes between main windows and key windows)
3625 if (q->isActiveWindow() && !(q->windowType() == Qt::Popup)) {
3626 QWidget *w = 0;
3627 if(q->parentWidget())
3628 w = q->parentWidget()->window();
3629 if(!w || (!w->isVisible() && !w->isMinimized())) {
3630 for (WindowPtr wp = GetFrontWindowOfClass(kMovableModalWindowClass, true);
3631 wp; wp = GetNextWindowOfClass(wp, kMovableModalWindowClass, true)) {
3632 if((w = qt_mac_find_window(wp)))
3633 break;
3634 }
3635 if (!w){
3636 for (WindowPtr wp = GetFrontWindowOfClass(kDocumentWindowClass, true);
3637 wp; wp = GetNextWindowOfClass(wp, kDocumentWindowClass, true)) {
3638 if((w = qt_mac_find_window(wp)))
3639 break;
3640 }
3641 }
3642 if (!w){
3643 for(WindowPtr wp = GetFrontWindowOfClass(kSimpleWindowClass, true);
3644 wp; wp = GetNextWindowOfClass(wp, kSimpleWindowClass, true)) {
3645 if((w = qt_mac_find_window(wp)))
3646 break;
3647 }
3648 }
3649 }
3650 if(w && w->isVisible() && !w->isMinimized()) {
3651 qt_event_request_activate(w);
3652 }
3653 }
3654#endif
3655 } else {
3656 invalidateBuffer(q->rect());
3657#ifndef QT_MAC_USE_COCOA
3658 HIViewSetVisible(qt_mac_nativeview_for(q), false);
3659#else
3660 [qt_mac_nativeview_for(q) setHidden:YES];
3661#endif
3662 }
3663
3664 if (!QWidget::mouseGrabber()){
3665 QWidget *enterWidget = QApplication::widgetAt(QCursor::pos());
3666 if (enterWidget && enterWidget->data->in_destructor)
3667 enterWidget = 0;
3668 QApplicationPrivate::dispatchEnterLeave(enterWidget, qt_mouseover);
3669 qt_mouseover = enterWidget;
3670 }
3671
3672 qt_event_request_window_change(q);
3673 deactivateWidgetCleanup();
3674 qt_mac_event_release(q);
3675}
3676
3677void QWidget::setWindowState(Qt::WindowStates newstate)
3678{
3679 Q_D(QWidget);
3680 bool needShow = false;
3681 Qt::WindowStates oldstate = windowState();
3682 if (oldstate == newstate)
3683 return;
3684
3685#ifdef QT_MAC_USE_COCOA
3686 QMacCocoaAutoReleasePool pool;
3687#endif
3688 bool needSendStateChange = true;
3689 if(isWindow()) {
3690 if((oldstate & Qt::WindowFullScreen) != (newstate & Qt::WindowFullScreen)) {
3691 if(newstate & Qt::WindowFullScreen) {
3692 if(QTLWExtra *tlextra = d->topData()) {
3693 if(tlextra->normalGeometry.width() < 0) {
3694 if(!testAttribute(Qt::WA_Resized))
3695 adjustSize();
3696 tlextra->normalGeometry = geometry();
3697 }
3698 tlextra->savedFlags = windowFlags();
3699 }
3700 needShow = isVisible();
3701 const QRect fullscreen(qApp->desktop()->screenGeometry(qApp->desktop()->screenNumber(this)));
3702 setParent(parentWidget(), Qt::Window | Qt::FramelessWindowHint | (windowFlags() & 0xffff0000)); //save
3703 setGeometry(fullscreen);
3704 if(!qApp->desktop()->screenNumber(this))
3705 qt_mac_set_fullscreen_mode(true);
3706 } else {
3707 needShow = isVisible();
3708 if(!qApp->desktop()->screenNumber(this))
3709 qt_mac_set_fullscreen_mode(false);
3710 setParent(parentWidget(), d->topData()->savedFlags);
3711 setGeometry(d->topData()->normalGeometry);
3712 d->topData()->normalGeometry.setRect(0, 0, -1, -1);
3713 }
3714 }
3715
3716 d->createWinId();
3717
3718 OSWindowRef window = qt_mac_window_for(this);
3719 if((oldstate & Qt::WindowMinimized) != (newstate & Qt::WindowMinimized)) {
3720 if (newstate & Qt::WindowMinimized) {
3721#ifndef QT_MAC_USE_COCOA
3722 CollapseWindow(window, true);
3723#else
3724 [window miniaturize:window];
3725#endif
3726 } else {
3727#ifndef QT_MAC_USE_COCOA
3728 CollapseWindow(window, false);
3729#else
3730 [window deminiaturize:window];
3731#endif
3732 }
3733 needSendStateChange = oldstate == windowState(); // Collapse didn't change our flags.
3734 }
3735
3736 if((newstate & Qt::WindowMaximized) && !((newstate & Qt::WindowFullScreen))) {
3737 if(QTLWExtra *tlextra = d->topData()) {
3738 if(tlextra->normalGeometry.width() < 0) {
3739 if(!testAttribute(Qt::WA_Resized))
3740 adjustSize();
3741 tlextra->normalGeometry = geometry();
3742 }
3743 }
3744 } else if(!(newstate & Qt::WindowFullScreen)) {
3745// d->topData()->normalGeometry = QRect(0, 0, -1, -1);
3746 }
3747
3748#ifdef DEBUG_WINDOW_STATE
3749#define WSTATE(x) qDebug("%s -- %s --> %s", #x, (oldstate & x) ? "true" : "false", (newstate & x) ? "true" : "false")
3750 WSTATE(Qt::WindowMinimized);
3751 WSTATE(Qt::WindowMaximized);
3752 WSTATE(Qt::WindowFullScreen);
3753#undef WSTATE
3754#endif
3755 if(!(newstate & (Qt::WindowMinimized|Qt::WindowFullScreen)) &&
3756 ((oldstate & Qt::WindowFullScreen) || (oldstate & Qt::WindowMinimized) ||
3757 (oldstate & Qt::WindowMaximized) != (newstate & Qt::WindowMaximized))) {
3758 if(newstate & Qt::WindowMaximized) {
3759 data->fstrut_dirty = true;
3760#ifndef QT_MAC_USE_COCOA
3761 HIToolbarRef toolbarRef;
3762 if (GetWindowToolbar(window, &toolbarRef) == noErr && toolbarRef
3763 && !isVisible() && !IsWindowToolbarVisible(window)) {
3764 // HIToolbar, needs to be shown so that it's in the structure window
3765 // Typically this is part of a main window and will get shown
3766 // during the show, but it's will make the maximize all wrong.
3767 ShowHideWindowToolbar(window, true, false);
3768 d->updateFrameStrut(); // In theory the dirty would work, but it's optimized out if the window is not visible :(
3769 }
3770 Rect bounds;
3771 QDesktopWidget *dsk = QApplication::desktop();
3772 QRect avail = dsk->availableGeometry(dsk->screenNumber(this));
3773 SetRect(&bounds, avail.x(), avail.y(), avail.x() + avail.width(), avail.y() + avail.height());
3774 if(QWExtra *extra = d->extraData()) {
3775 if(bounds.right - bounds.left > extra->maxw)
3776 bounds.right = bounds.left + extra->maxw;
3777 if(bounds.bottom - bounds.top > extra->maxh)
3778 bounds.bottom = bounds.top + extra->maxh;
3779 }
3780 if(d->topData()) {
3781 QRect fs = d->frameStrut();
3782 bounds.left += fs.left();
3783 if(bounds.right < avail.x()+avail.width())
3784 bounds.right = qMin<short>((uint)avail.x()+avail.width(), bounds.right+fs.left());
3785 if(bounds.bottom < avail.y()+avail.height())
3786 bounds.bottom = qMin<short>((uint)avail.y()+avail.height(), bounds.bottom+fs.top());
3787 bounds.top += fs.top();
3788 bounds.right -= fs.right();
3789 bounds.bottom -= fs.bottom();
3790 }
3791 QRect orect(geometry().x(), geometry().y(), width(), height()),
3792 nrect(bounds.left, bounds.top, bounds.right - bounds.left,
3793 bounds.bottom - bounds.top);
3794 if(orect != nrect) { // the new rect differ from the old
3795 Point idealSize = { nrect.height(), nrect.width() };
3796 ZoomWindowIdeal(window, inZoomOut, &idealSize);
3797 }
3798#else
3799 NSToolbar *toolbarRef = [window toolbar];
3800 if (toolbarRef && !isVisible() && ![toolbarRef isVisible]) {
3801 // HIToolbar, needs to be shown so that it's in the structure window
3802 // Typically this is part of a main window and will get shown
3803 // during the show, but it's will make the maximize all wrong.
3804 // ### Not sure this is right for NSToolbar...
3805 [toolbarRef setVisible:true];
3806// ShowHideWindowToolbar(window, true, false);
3807 d->updateFrameStrut(); // In theory the dirty would work, but it's optimized out if the window is not visible :(
3808 }
3809 // Everything should be handled by Cocoa.
3810 [window zoom:window];
3811#endif
3812 needSendStateChange = oldstate == windowState(); // Zoom didn't change flags.
3813 } else if(oldstate & Qt::WindowMaximized && !(oldstate & Qt::WindowFullScreen)) {
3814#ifndef QT_MAC_USE_COCOA
3815 Point idealSize;
3816 ZoomWindowIdeal(window, inZoomIn, &idealSize);
3817#else
3818 [window zoom:window];
3819#endif
3820 if(QTLWExtra *tlextra = d->topData()) {
3821 setGeometry(tlextra->normalGeometry);
3822 tlextra->normalGeometry.setRect(0, 0, -1, -1);
3823 }
3824 }
3825 }
3826 }
3827
3828 data->window_state = newstate;
3829
3830 if(needShow)
3831 show();
3832
3833 if(newstate & Qt::WindowActive)
3834 activateWindow();
3835
3836 qt_event_request_window_change(this);
3837 if (needSendStateChange) {
3838 QWindowStateChangeEvent e(oldstate);
3839 QApplication::sendEvent(this, &e);
3840 }
3841}
3842
3843void QWidgetPrivate::setFocus_sys()
3844{
3845 Q_Q(QWidget);
3846 if (q->testAttribute(Qt::WA_WState_Created)) {
3847#ifdef QT_MAC_USE_COCOA
3848 QMacCocoaAutoReleasePool pool;
3849 NSView *view = qt_mac_nativeview_for(q);
3850 [[view window] makeFirstResponder:view];
3851#else
3852 SetKeyboardFocus(qt_mac_window_for(q), qt_mac_nativeview_for(q), 1);
3853#endif
3854 }
3855}
3856
3857NSComparisonResult compareViews2Raise(id view1, id view2, void *context)
3858{
3859 id topView = reinterpret_cast<id>(context);
3860 if (view1 == topView)
3861 return NSOrderedDescending;
3862 if (view2 == topView)
3863 return NSOrderedAscending;
3864 return NSOrderedSame;
3865}
3866
3867void QWidgetPrivate::raise_sys()
3868{
3869 Q_Q(QWidget);
3870 if((q->windowType() == Qt::Desktop))
3871 return;
3872
3873#if QT_MAC_USE_COCOA
3874 QMacCocoaAutoReleasePool pool;
3875 if (isRealWindow()) {
3876 // With the introduction of spaces it is not as simple as just raising the window.
3877 // First we need to check if we are in the right space. If we are, then we just continue
3878 // as usual. The problem comes when we are not in the active space. There are two main cases:
3879 // 1. Our parent was moved to a new space. In this case we want the window to be raised
3880 // in the same space as its parent.
3881 // 2. We don't have a parent. For this case we will just raise the window and let Cocoa
3882 // switch to the corresponding space.
3883 // NOTICE: There are a lot of corner cases here. We are keeping this simple for now, if
3884 // required we will introduce special handling for some of them.
3885 if (!q->testAttribute(Qt::WA_DontShowOnScreen) && q->isVisible()) {
3886 OSWindowRef window = qt_mac_window_for(q);
3887 // isOnActiveSpace is available only from 10.6 onwards, so we need to check if it is
3888 // available before calling it.
3889 if([window respondsToSelector:@selector(isOnActiveSpace)]) {
3890 if(![window performSelector:@selector(isOnActiveSpace)]) {
3891 QWidget *parentWidget = q->parentWidget();
3892 if(parentWidget) {
3893 OSWindowRef parentWindow = qt_mac_window_for(parentWidget);
3894 if(parentWindow && [parentWindow isOnActiveSpace]) {
3895 // The window was created in a different space. Therefore if we want
3896 // to show it in the current space we need to recreate it in the new
3897 // space.
3898 recreateMacWindow();
3899 window = qt_mac_window_for(q);
3900 }
3901 }
3902 }
3903 }
3904 [window orderFront:window];
3905 }
3906 if (qt_mac_raise_process) { //we get to be the active process now
3907 ProcessSerialNumber psn;
3908 GetCurrentProcess(&psn);
3909 SetFrontProcessWithOptions(&psn, kSetFrontProcessFrontWindowOnly);
3910 }
3911 } else {
3912 NSView *view = qt_mac_nativeview_for(q);
3913 NSView *parentView = [view superview];
3914 [parentView sortSubviewsUsingFunction:compareViews2Raise context:reinterpret_cast<void *>(view)];
3915 }
3916#else
3917 if(q->isWindow()) {
3918 //raise this window
3919 BringToFront(qt_mac_window_for(q));
3920 if(qt_mac_raise_process) { //we get to be the active process now
3921 ProcessSerialNumber psn;
3922 GetCurrentProcess(&psn);
3923 SetFrontProcessWithOptions(&psn, kSetFrontProcessFrontWindowOnly);
3924 }
3925 } else if(q->parentWidget()) {
3926 HIViewSetZOrder(qt_mac_nativeview_for(q), kHIViewZOrderAbove, 0);
3927 qt_event_request_window_change(q);
3928 }
3929#endif
3930}
3931
3932NSComparisonResult compareViews2Lower(id view1, id view2, void *context)
3933{
3934 id topView = reinterpret_cast<id>(context);
3935 if (view1 == topView)
3936 return NSOrderedAscending;
3937 if (view2 == topView)
3938 return NSOrderedDescending;
3939 return NSOrderedSame;
3940}
3941
3942void QWidgetPrivate::lower_sys()
3943{
3944 Q_Q(QWidget);
3945 if((q->windowType() == Qt::Desktop))
3946 return;
3947#ifdef QT_MAC_USE_COCOA
3948 if (isRealWindow()) {
3949 OSWindowRef window = qt_mac_window_for(q);
3950 [window orderBack:window];
3951 } else {
3952 NSView *view = qt_mac_nativeview_for(q);
3953 NSView *parentView = [view superview];
3954 [parentView sortSubviewsUsingFunction:compareViews2Lower context:reinterpret_cast<void *>(view)];
3955 }
3956#else
3957 if(q->isWindow()) {
3958 SendBehind(qt_mac_window_for(q), 0);
3959 } else if(q->parentWidget()) {
3960 invalidateBuffer(q->rect());
3961 HIViewSetZOrder(qt_mac_nativeview_for(q), kHIViewZOrderBelow, 0);
3962 qt_event_request_window_change(q);
3963 }
3964#endif
3965}
3966
3967NSComparisonResult compareViews2StackUnder(id view1, id view2, void *context)
3968{
3969 const QHash<NSView *, int> &viewOrder = *reinterpret_cast<QHash<NSView *, int> *>(context);
3970 if (viewOrder[view1] < viewOrder[view2])
3971 return NSOrderedAscending;
3972 if (viewOrder[view1] > viewOrder[view2])
3973 return NSOrderedDescending;
3974 return NSOrderedSame;
3975}
3976
3977void QWidgetPrivate::stackUnder_sys(QWidget *w)
3978{
3979 // stackUnder
3980 Q_Q(QWidget);
3981 if(!w || q->isWindow() || (q->windowType() == Qt::Desktop))
3982 return;
3983#ifdef QT_MAC_USE_COCOA
3984 // Do the same trick as lower_sys() and put this widget before the widget passed in.
3985 NSView *myView = qt_mac_nativeview_for(q);
3986 NSView *wView = qt_mac_nativeview_for(w);
3987
3988 QHash<NSView *, int> viewOrder;
3989 NSView *parentView = [myView superview];
3990 NSArray *subviews = [parentView subviews];
3991 NSUInteger index = 1;
3992 // make a hash of view->zorderindex and make sure z-value is always odd,
3993 // so that when we modify the order we create a new (even) z-value which
3994 // will not interfere with others.
3995 for (NSView *subview in subviews) {
3996 viewOrder.insert(subview, index * 2);
3997 ++index;
3998 }
3999 viewOrder[myView] = viewOrder[wView] - 1;
4000
4001 [parentView sortSubviewsUsingFunction:compareViews2StackUnder context:reinterpret_cast<void *>(&viewOrder)];
4002#else
4003 QWidget *p = q->parentWidget();
4004 if(!p || p != w->parentWidget())
4005 return;
4006 invalidateBuffer(q->rect());
4007 HIViewSetZOrder(qt_mac_nativeview_for(q), kHIViewZOrderBelow, qt_mac_nativeview_for(w));
4008 qt_event_request_window_change(q);
4009#endif
4010}
4011
4012/*
4013 Modifies the bounds for a widgets backing HIView during moves and resizes. Also updates the
4014 widget, either by scrolling its contents or repainting, depending on the WA_StaticContents
4015 flag
4016*/
4017static void qt_mac_update_widget_position(QWidget *q, QRect oldRect, QRect newRect)
4018{
4019#ifndef QT_MAC_USE_COCOA
4020 HIRect bounds = CGRectMake(newRect.x(), newRect.y(),
4021 newRect.width(), newRect.height());
4022
4023 const HIViewRef view = qt_mac_nativeview_for(q);
4024 const bool isMove = (oldRect.topLeft() != newRect.topLeft());
4025 const bool isResize = (oldRect.size() != newRect.size());
4026
4027// qDebug() << oldRect << newRect << isMove << isResize << q->testAttribute(Qt::WA_OpaquePaintEvent) << q->testAttribute(Qt::WA_StaticContents);
4028 QWidgetPrivate *qd = qt_widget_private(q);
4029
4030 // Perform a normal (complete repaint) update in some cases:
4031 if (
4032 // always repaint on move.
4033 (isMove) ||
4034
4035 // limited update on resize requires WA_StaticContents.
4036 (isResize && q->testAttribute(Qt::WA_StaticContents) == false) ||
4037
4038 // one of the rects are invalid
4039 (oldRect.isValid() == false || newRect.isValid() == false) ||
4040
4041 // the position update is a part of a drag-and-drop operation
4042 QDragManager::self()->object ||
4043
4044 // we are on Panther (no HIViewSetNeedsDisplayInRect)
4045 QSysInfo::MacintoshVersion < QSysInfo::MV_10_4
4046 ){
4047 HIViewSetFrame(view, &bounds);
4048 return;
4049 }
4050
4051 const int dx = newRect.x() - oldRect.x();
4052 const int dy = newRect.y() - oldRect.y();
4053
4054 if (isMove) {
4055 // HIViewScrollRect silently fails if we try to scroll anything under the grow box.
4056 // Check if there's one present within the widget rect, and if there is fall back
4057 // to repainting the entire widget.
4058 QWidget const * const parentWidget = q->parentWidget();
4059 const HIViewRef parentView = qt_mac_nativeview_for(parentWidget);
4060 HIViewRef nativeSizeGrip = 0;
4061 if (q->testAttribute(Qt::WA_WState_Created))
4062 HIViewFindByID(HIViewGetRoot(HIViewGetWindow(HIViewRef(q->winId()))), kHIViewWindowGrowBoxID, &nativeSizeGrip);
4063 if (nativeSizeGrip) {
4064 QWidget * const window = q->window();
4065
4066 const int sizeGripSize = 20;
4067 const QRect oldWidgetRect = QRect(q->mapTo(window, QPoint(0, 0)), QSize(oldRect.width(), oldRect.height()));
4068 const QRect newWidgetRect = QRect(q->mapTo(window, QPoint(0, 0)), QSize(newRect.width(), newRect.height()));
4069 const QRect sizeGripRect = QRect(window->rect().bottomRight() - QPoint(sizeGripSize, sizeGripSize),
4070 window->rect().bottomRight());
4071
4072 if (sizeGripRect.intersects(oldWidgetRect) || sizeGripRect.intersects(newWidgetRect)) {
4073 HIViewSetFrame(view, &bounds);
4074 return;
4075 }
4076 }
4077
4078 // Don't scroll anything outside the parent widget rect.
4079 const QRect scrollRect = (oldRect | newRect) & parentWidget->rect();
4080 const HIRect scrollBounds =
4081 CGRectMake(scrollRect.x(), scrollRect.y(), scrollRect.width(), scrollRect.height());
4082
4083 // We cannot scroll when the widget has a mask as that would
4084 // scroll the masked out areas too
4085 if (qd->extra && qd->extra->hasMask) {
4086 HIViewMoveBy(view, dx, dy);
4087 return;
4088 }
4089
4090 OSStatus err = HIViewScrollRect(parentView, &scrollBounds, dx, dy);
4091 if (err != noErr) {
4092 HIViewSetNeedsDisplay(view, true);
4093 qWarning("QWidget: Internal error (%s:%d)", __FILE__, __LINE__);
4094 }
4095 }
4096 // Set the view bounds with drawing disabled to prevent repaints.
4097 HIViewSetDrawingEnabled(view, false);
4098 HIViewSetFrame(view, &bounds);
4099 HIViewSetDrawingEnabled(view, true);
4100
4101 // Update any newly exposed areas due to resizing.
4102 const int startx = oldRect.width();
4103 const int stopx = newRect.width();
4104 const int starty = oldRect.height();
4105 const int stopy = newRect.height();
4106
4107 const HIRect verticalSlice = CGRectMake(startx, 0, stopx , stopy);
4108 HIViewSetNeedsDisplayInRect(view, &verticalSlice, true);
4109 const HIRect horizontalSlice = CGRectMake(0, starty, startx, stopy);
4110 HIViewSetNeedsDisplayInRect(view, &horizontalSlice, true);
4111#else
4112 Q_UNUSED(oldRect);
4113 NSRect bounds = NSMakeRect(newRect.x(), newRect.y(),
4114 newRect.width(), newRect.height());
4115 [qt_mac_nativeview_for(q) setFrame:bounds];
4116#endif
4117}
4118
4119/*
4120 Helper function for non-toplevel widgets. Helps to map Qt's 32bit
4121 coordinate system to OS X's 16bit coordinate system.
4122
4123 Sets the geometry of the widget to data.crect, but clipped to sizes
4124 that OS X can handle. Unmaps widgets that are completely outside the
4125 valid range.
4126
4127 Maintains data.wrect, which is the geometry of the OS X widget,
4128 measured in this widget's coordinate system.
4129
4130 if the parent is not clipped, parentWRect is empty, otherwise
4131 parentWRect is the geometry of the parent's OS X rect, measured in
4132 parent's coord sys
4133*/
4134void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &oldRect)
4135{
4136 Q_Q(QWidget);
4137 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
4138 Q_UNUSED(oldRect);
4139 /*
4140 There are up to four different coordinate systems here:
4141 Qt coordinate system for this widget.
4142 X coordinate system for this widget (relative to wrect).
4143 Qt coordinate system for parent
4144 X coordinate system for parent (relative to parent's wrect).
4145 */
4146 QRect wrect;
4147 //xrect is the X geometry of my X widget. (starts out in parent's Qt coord sys, and ends up in parent's X coord sys)
4148 QRect xrect = data.crect;
4149
4150 QRect parentWRect;
4151 bool isEmbeddedWindow = (q->isWindow() && topData()->embedded);
4152 if (isEmbeddedWindow) {
4153#ifndef QT_MAC_USE_COCOA
4154 HIViewRef parentView = HIViewGetSuperview(qt_mac_nativeview_for(q));
4155#else
4156 NSView *parentView = [qt_mac_nativeview_for(q) superview];
4157#endif
4158 if (parentView) {
4159#ifndef QT_MAC_USE_COCOA
4160 HIRect tmpRect;
4161 HIViewGetFrame(parentView, &tmpRect);
4162#else
4163 NSRect tmpRect = [parentView frame];
4164#endif
4165 parentWRect = QRect(tmpRect.origin.x, tmpRect.origin.y,
4166 tmpRect.size.width, tmpRect.size.height);
4167 } else {
4168 const QRect wrectRange(-WRECT_MAX,-WRECT_MAX, 2*WRECT_MAX, 2*WRECT_MAX);
4169 parentWRect = wrectRange;
4170 }
4171 } else {
4172 parentWRect = q->parentWidget()->data->wrect;
4173 }
4174
4175 if (parentWRect.isValid()) {
4176 // parent is clipped, and we have to clip to the same limit as parent
4177 if (!parentWRect.contains(xrect) && !isEmbeddedWindow) {
4178 xrect &= parentWRect;
4179 wrect = xrect;
4180 //translate from parent's to my Qt coord sys
4181 wrect.translate(-data.crect.topLeft());
4182 }
4183 //translate from parent's Qt coords to parent's X coords
4184 xrect.translate(-parentWRect.topLeft());
4185
4186 } else {
4187 // parent is not clipped, we may or may not have to clip
4188
4189 if (data.wrect.isValid() && QRect(QPoint(),data.crect.size()).contains(data.wrect)) {
4190 // This is where the main optimization is: we are already
4191 // clipped, and if our clip is still valid, we can just
4192 // move our window, and do not need to move or clip
4193 // children
4194
4195 QRect vrect = xrect & q->parentWidget()->rect();
4196 vrect.translate(-data.crect.topLeft()); //the part of me that's visible through parent, in my Qt coords
4197 if (data.wrect.contains(vrect)) {
4198 xrect = data.wrect;
4199 xrect.translate(data.crect.topLeft());
4200#ifndef QT_MAC_USE_COCOA
4201 HIRect bounds = CGRectMake(xrect.x(), xrect.y(),
4202 xrect.width(), xrect.height());
4203 HIViewSetFrame(qt_mac_nativeview_for(q), &bounds);
4204#else
4205 NSRect bounds = NSMakeRect(xrect.x(), xrect.y(),
4206 xrect.width(), xrect.height());
4207 [qt_mac_nativeview_for(q) setFrame:bounds];
4208#endif
4209 if (q->testAttribute(Qt::WA_OutsideWSRange)) {
4210 q->setAttribute(Qt::WA_OutsideWSRange, false);
4211 if (!dontShow) {
4212 q->setAttribute(Qt::WA_Mapped);
4213#ifndef QT_MAC_USE_COCOA
4214 HIViewSetVisible(qt_mac_nativeview_for(q), true);
4215#else
4216 [qt_mac_nativeview_for(q) setHidden:NO];
4217#endif
4218 }
4219 }
4220 return;
4221 }
4222 }
4223
4224 const QRect validRange(-XCOORD_MAX,-XCOORD_MAX, 2*XCOORD_MAX, 2*XCOORD_MAX);
4225 if (!validRange.contains(xrect)) {
4226 // we are too big, and must clip
4227 QPoint screenOffset(0, 0); // offset of the part being on screen
4228 const QWidget *parentWidget = q->parentWidget();
4229 while (parentWidget && !parentWidget->isWindow()) {
4230 screenOffset -= parentWidget->data->crect.topLeft();
4231 parentWidget = parentWidget->parentWidget();
4232 }
4233 QRect cropRect(screenOffset.x() - WRECT_MAX,
4234 screenOffset.y() - WRECT_MAX,
4235 2*WRECT_MAX,
4236 2*WRECT_MAX);
4237
4238 xrect &=cropRect;
4239 wrect = xrect;
4240 wrect.translate(-data.crect.topLeft()); // translate wrect in my Qt coordinates
4241 }
4242 }
4243
4244 // unmap if we are outside the valid window system coord system
4245 bool outsideRange = !xrect.isValid();
4246 bool mapWindow = false;
4247 if (q->testAttribute(Qt::WA_OutsideWSRange) != outsideRange) {
4248 q->setAttribute(Qt::WA_OutsideWSRange, outsideRange);
4249 if (outsideRange) {
4250#ifndef QT_MAC_USE_COCOA
4251 HIViewSetVisible(qt_mac_nativeview_for(q), false);
4252#else
4253 [qt_mac_nativeview_for(q) setHidden:YES];
4254#endif
4255 q->setAttribute(Qt::WA_Mapped, false);
4256 } else if (!q->isHidden()) {
4257 mapWindow = true;
4258 }
4259 }
4260
4261 if (outsideRange)
4262 return;
4263
4264 bool jump = (data.wrect != wrect);
4265 data.wrect = wrect;
4266
4267
4268 // and now recursively for all children...
4269 // ### can be optimized
4270 for (int i = 0; i < children.size(); ++i) {
4271 QObject *object = children.at(i);
4272 if (object->isWidgetType()) {
4273 QWidget *w = static_cast<QWidget *>(object);
4274 if (!w->isWindow() && w->testAttribute(Qt::WA_WState_Created))
4275 w->d_func()->setWSGeometry();
4276 }
4277 }
4278
4279 qt_mac_update_widget_position(q, oldRect, xrect);
4280
4281 if (jump)
4282 q->update();
4283
4284 if (mapWindow && !dontShow) {
4285 q->setAttribute(Qt::WA_Mapped);
4286#ifndef QT_MAC_USE_COCOA
4287 HIViewSetVisible(qt_mac_nativeview_for(q), true);
4288#else
4289 [qt_mac_nativeview_for(q) setHidden:NO];
4290#endif
4291 }
4292}
4293
4294void QWidgetPrivate::adjustWithinMaxAndMinSize(int &w, int &h)
4295{
4296 if (QWExtra *extra = extraData()) {
4297 w = qMin(w, extra->maxw);
4298 h = qMin(h, extra->maxh);
4299 w = qMax(w, extra->minw);
4300 h = qMax(h, extra->minh);
4301
4302 // Deal with size increment
4303 if (QTLWExtra *top = topData()) {
4304 if(top->incw) {
4305 w = w/top->incw;
4306 w *= top->incw;
4307 }
4308 if(top->inch) {
4309 h = h/top->inch;
4310 h *= top->inch;
4311 }
4312 }
4313 }
4314
4315 if (isRealWindow()) {
4316 w = qMax(0, w);
4317 h = qMax(0, h);
4318 }
4319}
4320
4321void QWidgetPrivate::applyMaxAndMinSizeOnWindow()
4322{
4323 Q_Q(QWidget);
4324 const float max_f(20000);
4325#ifndef QT_MAC_USE_COCOA
4326#define SF(x) ((x > max_f) ? max_f : x)
4327 HISize max = CGSizeMake(SF(extra->maxw), SF(extra->maxh));
4328 HISize min = CGSizeMake(SF(extra->minw), SF(extra->minh));
4329#undef SF
4330 SetWindowResizeLimits(qt_mac_window_for(q), &min, &max);
4331#else
4332#define SF(x) ((x > max_f) ? max_f : x)
4333 NSSize max = NSMakeSize(SF(extra->maxw), SF(extra->maxh));
4334 NSSize min = NSMakeSize(SF(extra->minw), SF(extra->minh));
4335#undef SF
4336 [qt_mac_window_for(q) setContentMinSize:min];
4337 [qt_mac_window_for(q) setContentMaxSize:max];
4338#endif
4339}
4340
4341void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove)
4342{
4343 Q_Q(QWidget);
4344 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
4345
4346 if(q->windowType() == Qt::Desktop)
4347 return;
4348
4349 QMacCocoaAutoReleasePool pool;
4350 bool realWindow = isRealWindow();
4351 BOOL needDisplay = realWindow ? YES : NO;
4352
4353 if (realWindow && !q->testAttribute(Qt::WA_DontShowOnScreen)){
4354 adjustWithinMaxAndMinSize(w, h);
4355#ifndef QT_MAC_USE_COCOA
4356 if (w != 0 && h != 0) {
4357 topData()->isSetGeometry = 1;
4358 topData()->isMove = isMove;
4359 Rect r; SetRect(&r, x, y, x + w, y + h);
4360 SetWindowBounds(qt_mac_window_for(q), kWindowContentRgn, &r);
4361 topData()->isSetGeometry = 0;
4362 } else {
4363 setGeometry_sys_helper(x, y, w, h, isMove);
4364 }
4365#else
4366 if (!isMove && !q->testAttribute(Qt::WA_Moved) && !q->isVisible()) {
4367 // INVARIANT: The location of the window has not yet been set. The default will
4368 // instead be to center it on the desktop, or over the parent, if any. Since we now
4369 // resize the window, we need to adjust the top left position to keep the window
4370 // centeralized. And we need to to this now (and before show) in case the positioning
4371 // of other windows (e.g. sub-windows) depend on this position:
4372 if (QWidget *p = q->parentWidget()) {
4373 x = p->geometry().center().x() - (w / 2);
4374 y = p->geometry().center().y() - (h / 2);
4375 } else {
4376 QRect availGeo = QApplication::desktop()->availableGeometry(q);
4377 x = availGeo.center().x() - (w / 2);
4378 y = availGeo.center().y() - (h / 2);
4379 }
4380 }
4381
4382 QSize olds = q->size();
4383 const bool isResize = (olds != QSize(w, h));
4384 NSWindow *window = qt_mac_window_for(q);
4385 const QRect &fStrut = frameStrut();
4386 const QRect frameRect(QPoint(x - fStrut.left(), y - fStrut.top()),
4387 QSize(fStrut.left() + fStrut.right() + w,
4388 fStrut.top() + fStrut.bottom() + h));
4389 NSRect cocoaFrameRect = NSMakeRect(frameRect.x(), flipYCoordinate(frameRect.bottom() + 1),
4390 frameRect.width(), frameRect.height());
4391 // The setFrame call will trigger a 'windowDidResize' notification for the corresponding
4392 // NSWindow. The pending flag is set, so that the resize event can be send as non-spontaneous.
4393 if (isResize)
4394 q->setAttribute(Qt::WA_PendingResizeEvent);
4395 QPoint currTopLeft = data.crect.topLeft();
4396 if (currTopLeft.x() == x && currTopLeft.y() == y
4397 && cocoaFrameRect.size.width != 0
4398 && cocoaFrameRect.size.height != 0) {
4399 [window setFrame:cocoaFrameRect display:needDisplay];
4400 } else {
4401 // The window is moved and resized (or resized to zero).
4402 // Since Cocoa usually only sends us a resize callback after
4403 // setting a window frame, we issue an explicit move as
4404 // well. To stop Cocoa from optimize away the move (since the move
4405 // would have the same origin as the setFrame call) we shift the
4406 // window back and forth inbetween.
4407 cocoaFrameRect.origin.y += 1;
4408 [window setFrame:cocoaFrameRect display:needDisplay];
4409 cocoaFrameRect.origin.y -= 1;
4410 [window setFrameOrigin:cocoaFrameRect.origin];
4411 }
4412#endif
4413 } else {
4414 setGeometry_sys_helper(x, y, w, h, isMove);
4415 }
4416}
4417
4418void QWidgetPrivate::setGeometry_sys_helper(int x, int y, int w, int h, bool isMove)
4419{
4420 Q_Q(QWidget);
4421 bool realWindow = isRealWindow();
4422
4423 QPoint oldp = q->pos();
4424 QSize olds = q->size();
4425 const bool isResize = (olds != QSize(w, h));
4426
4427 if (!realWindow && !isResize && QPoint(x, y) == oldp)
4428 return;
4429
4430 if (isResize)
4431 data.window_state = data.window_state & ~Qt::WindowMaximized;
4432
4433 const bool visible = q->isVisible();
4434 // Apply size restrictions, applicable for Windows & Widgets.
4435 if (QWExtra *extra = extraData()) {
4436 w = qMin(w, extra->maxw);
4437 h = qMin(h, extra->maxh);
4438 w = qMax(w, extra->minw);
4439 h = qMax(h, extra->minh);
4440 }
4441 data.crect = QRect(x, y, w, h);
4442
4443 if (realWindow) {
4444 adjustWithinMaxAndMinSize(w, h);
4445 qt_mac_update_sizer(q);
4446
4447#ifndef QT_MAC_USE_COCOA
4448 if (q->windowFlags() & Qt::WindowMaximizeButtonHint) {
4449 OSWindowRef window = qt_mac_window_for(q);
4450 if (extra->maxw && extra->maxh && extra->maxw == extra->minw
4451 && extra->maxh == extra->minh) {
4452 ChangeWindowAttributes(window, kWindowNoAttributes, kWindowFullZoomAttribute);
4453 } else {
4454 ChangeWindowAttributes(window, kWindowFullZoomAttribute, kWindowNoAttributes);
4455 }
4456 }
4457 HIRect bounds = CGRectMake(0, 0, w, h);
4458 HIViewSetFrame(qt_mac_nativeview_for(q), &bounds);
4459#else
4460 [qt_mac_nativeview_for(q) setFrame:NSMakeRect(0, 0, w, h)];
4461#endif
4462 } else {
4463 const QRect oldRect(oldp, olds);
4464 if (!isResize && QApplicationPrivate::graphicsSystem())
4465 moveRect(oldRect, x - oldp.x(), y - oldp.y());
4466 setWSGeometry(false, oldRect);
4467 if (isResize && QApplicationPrivate::graphicsSystem()) {
4468 invalidateBuffer(q->rect());
4469 if (extra && !graphicsEffect && !extra->mask.isEmpty()) {
4470 QRegion oldRegion(extra->mask.translated(oldp));
4471 oldRegion &= oldRect;
4472 q->parentWidget()->d_func()->invalidateBuffer(oldRegion);
4473 } else {
4474 q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(oldRect));
4475 }
4476 }
4477 }
4478
4479 if(isMove || isResize) {
4480 if(!visible) {
4481 if(isMove && q->pos() != oldp)
4482 q->setAttribute(Qt::WA_PendingMoveEvent, true);
4483 if(isResize)
4484 q->setAttribute(Qt::WA_PendingResizeEvent, true);
4485 } else {
4486 if(isResize) { //send the resize event..
4487 QResizeEvent e(q->size(), olds);
4488 QApplication::sendEvent(q, &e);
4489 }
4490 if(isMove && q->pos() != oldp) { //send the move event..
4491 QMoveEvent e(q->pos(), oldp);
4492 QApplication::sendEvent(q, &e);
4493 }
4494 }
4495 }
4496 qt_event_request_window_change(q);
4497}
4498
4499void QWidgetPrivate::setConstraints_sys()
4500{
4501 updateMaximizeButton_sys();
4502 applyMaxAndMinSizeOnWindow();
4503}
4504
4505void QWidgetPrivate::updateMaximizeButton_sys()
4506{
4507 Q_Q(QWidget);
4508 if (q->data->window_flags & Qt::CustomizeWindowHint)
4509 return;
4510
4511 OSWindowRef window = qt_mac_window_for(q);
4512 QTLWExtra * tlwExtra = topData();
4513#ifdef QT_MAC_USE_COCOA
4514 QMacCocoaAutoReleasePool pool;
4515 NSButton *maximizeButton = [window standardWindowButton:NSWindowZoomButton];
4516#endif
4517 if (extra->maxw && extra->maxh
4518 && extra->maxw == extra->minw
4519 && extra->maxh == extra->minh) {
4520 // The window has a fixed size, so gray out the maximize button:
4521 if (!tlwExtra->savedWindowAttributesFromMaximized) {
4522#ifndef QT_MAC_USE_COCOA
4523 GetWindowAttributes(window,
4524 (WindowAttributes*)&extra->topextra->savedWindowAttributesFromMaximized);
4525
4526#else
4527 tlwExtra->savedWindowAttributesFromMaximized = (![maximizeButton isHidden] && [maximizeButton isEnabled]);
4528#endif
4529 }
4530#ifndef QT_MAC_USE_COCOA
4531 ChangeWindowAttributes(window, kWindowNoAttributes, kWindowFullZoomAttribute);
4532#else
4533 [maximizeButton setEnabled:NO];
4534#endif
4535
4536
4537 } else {
4538 if (tlwExtra->savedWindowAttributesFromMaximized) {
4539#ifndef QT_MAC_USE_COCOA
4540 ChangeWindowAttributes(window,
4541 extra->topextra->savedWindowAttributesFromMaximized,
4542 kWindowNoAttributes);
4543#else
4544 [maximizeButton setEnabled:YES];
4545#endif
4546 tlwExtra->savedWindowAttributesFromMaximized = 0;
4547 }
4548 }
4549
4550
4551}
4552
4553void QWidgetPrivate::scroll_sys(int dx, int dy)
4554{
4555 if (QApplicationPrivate::graphicsSystem() && !paintOnScreen()) {
4556 scrollChildren(dx, dy);
4557 scrollRect(q_func()->rect(), dx, dy);
4558 } else {
4559 scroll_sys(dx, dy, QRect());
4560 }
4561}
4562
4563void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r)
4564{
4565 Q_Q(QWidget);
4566
4567 if (QApplicationPrivate::graphicsSystem() && !paintOnScreen()) {
4568 scrollRect(r, dx, dy);
4569 return;
4570 }
4571
4572 const bool valid_rect = r.isValid();
4573 if (!q->updatesEnabled() && (valid_rect || q->children().isEmpty()))
4574 return;
4575
4576 qt_event_request_window_change(q);
4577
4578#ifdef QT_MAC_USE_COCOA
4579 QMacCocoaAutoReleasePool pool;
4580#endif
4581
4582 if(!valid_rect) { // scroll children
4583 QPoint pd(dx, dy);
4584 QWidgetList moved;
4585 QObjectList chldrn = q->children();
4586 for(int i = 0; i < chldrn.size(); i++) { //first move all children
4587 QObject *obj = chldrn.at(i);
4588 if(obj->isWidgetType()) {
4589 QWidget *w = (QWidget*)obj;
4590 if(!w->isWindow()) {
4591 w->data->crect = QRect(w->pos() + pd, w->size());
4592 if (w->testAttribute(Qt::WA_WState_Created)) {
4593#ifndef QT_MAC_USE_COCOA
4594 HIRect bounds = CGRectMake(w->data->crect.x(), w->data->crect.y(),
4595 w->data->crect.width(), w->data->crect.height());
4596 HIViewRef hiview = qt_mac_nativeview_for(w);
4597 const bool opaque = q->testAttribute(Qt::WA_OpaquePaintEvent);
4598
4599 if (opaque)
4600 HIViewSetDrawingEnabled(hiview, false);
4601 HIViewSetFrame(hiview, &bounds);
4602 if (opaque)
4603 HIViewSetDrawingEnabled(hiview, true);
4604#else
4605 [qt_mac_nativeview_for(w)
4606 setFrame:NSMakeRect(w->data->crect.x(), w->data->crect.y(),
4607 w->data->crect.width(), w->data->crect.height())];
4608#endif
4609 }
4610 moved.append(w);
4611 }
4612 }
4613 }
4614 //now send move events (do not do this in the above loop, breaks QAquaFocusWidget)
4615 for(int i = 0; i < moved.size(); i++) {
4616 QWidget *w = moved.at(i);
4617 QMoveEvent e(w->pos(), w->pos() - pd);
4618 QApplication::sendEvent(w, &e);
4619 }
4620 }
4621
4622 if (!q->testAttribute(Qt::WA_WState_Created) || !q->isVisible())
4623 return;
4624
4625 OSViewRef view = qt_mac_nativeview_for(q);
4626#ifndef QT_MAC_USE_COCOA
4627 HIRect scrollrect = CGRectMake(r.x(), r.y(), r.width(), r.height());
4628 OSStatus err = _HIViewScrollRectWithOptions(view, valid_rect ? &scrollrect : 0, dx, dy, kHIViewScrollRectAdjustInvalid);
4629 if (err) {
4630 // The only parameter that can go wrong, is the rect.
4631 qWarning("QWidget::scroll: Your rectangle was too big for the widget, clipping rect");
4632 scrollrect = CGRectMake(qMax(r.x(), 0), qMax(r.y(), 0),
4633 qMin(r.width(), q->width()), qMin(r.height(), q->height()));
4634 _HIViewScrollRectWithOptions(view, valid_rect ? &scrollrect : 0, dx, dy, kHIViewScrollRectAdjustInvalid);
4635 }
4636#else
4637 NSRect scrollRect = valid_rect ? NSMakeRect(r.x(), r.y(), r.width(), r.height())
4638 : NSMakeRect(0, 0, q->width(), q->height());
4639
4640
4641 // calc the updateRect
4642 NSRect deltaXRect = { {0, 0}, {0, 0} };
4643 NSRect deltaYRect = { {0, 0}, {0, 0} };
4644 if (dy != 0) {
4645 deltaYRect.size.width = scrollRect.size.width;
4646 if (dy > 0) {
4647 deltaYRect.size.height = dy;
4648 } else {
4649 deltaYRect.size.height = -dy;
4650 deltaYRect.origin.y = scrollRect.size.height + dy;
4651 }
4652 }
4653 if (dx != 0) {
4654 deltaXRect.size.height = scrollRect.size.height;
4655 if (dx > 0) {
4656 deltaXRect.size.width = dx;
4657 } else {
4658 deltaXRect.size.width = -dx;
4659 deltaXRect.origin.x = scrollRect.size.width + dx;
4660 }
4661 }
4662
4663 // ### Scroll the dirty regions as well, the following is not correct.
4664 QRegion displayRegion = r.isNull() ? dirtyOnWidget : (dirtyOnWidget & r);
4665 const QVector<QRect> &rects = dirtyOnWidget.rects();
4666 const QVector<QRect>::const_iterator end = rects.end();
4667 QVector<QRect>::const_iterator it = rects.begin();
4668 while (it != end) {
4669 const QRect rect = *it;
4670 const NSRect dirtyRect = NSMakeRect(rect.x() + dx, rect.y() + dy,
4671 rect.width(), rect.height());
4672 [view setNeedsDisplayInRect:dirtyRect];
4673 ++it;
4674 }
4675
4676 NSSize deltaSize = NSMakeSize(dx, dy);
4677 [view scrollRect:scrollRect by:deltaSize];
4678 [view setNeedsDisplayInRect:deltaXRect];
4679 [view setNeedsDisplayInRect:deltaYRect];
4680#endif // QT_MAC_USE_COCOA
4681}
4682
4683int QWidget::metric(PaintDeviceMetric m) const
4684{
4685 switch(m) {
4686 case PdmHeightMM:
4687 return qRound(metric(PdmHeight) * 25.4 / qreal(metric(PdmDpiY)));
4688 case PdmWidthMM:
4689 return qRound(metric(PdmWidth) * 25.4 / qreal(metric(PdmDpiX)));
4690 case PdmHeight:
4691 case PdmWidth: {
4692#ifndef QT_MAC_USE_COCOA
4693 HIRect rect;
4694 HIViewGetFrame(qt_mac_nativeview_for(this), &rect);
4695#else
4696 NSRect rect = [qt_mac_nativeview_for(this) frame];
4697#endif
4698 if(m == PdmWidth)
4699 return (int)rect.size.width;
4700 return (int)rect.size.height; }
4701 case PdmDepth:
4702 return 32;
4703 case PdmNumColors:
4704 return INT_MAX;
4705 case PdmDpiX:
4706 case PdmPhysicalDpiX: {
4707 Q_D(const QWidget);
4708 if (d->extra && d->extra->customDpiX)
4709 return d->extra->customDpiX;
4710 else if (d->parent)
4711 return static_cast<QWidget *>(d->parent)->metric(m);
4712 extern float qt_mac_defaultDpi_x(); //qpaintdevice_mac.cpp
4713 return int(qt_mac_defaultDpi_x()); }
4714 case PdmDpiY:
4715 case PdmPhysicalDpiY: {
4716 Q_D(const QWidget);
4717 if (d->extra && d->extra->customDpiY)
4718 return d->extra->customDpiY;
4719 else if (d->parent)
4720 return static_cast<QWidget *>(d->parent)->metric(m);
4721 extern float qt_mac_defaultDpi_y(); //qpaintdevice_mac.cpp
4722 return int(qt_mac_defaultDpi_y()); }
4723 default: //leave this so the compiler complains when new ones are added
4724 qWarning("QWidget::metric: Unhandled parameter %d", m);
4725 return QPaintDevice::metric(m);
4726 }
4727 return 0;
4728}
4729
4730void QWidgetPrivate::createSysExtra()
4731{
4732#ifdef QT_MAC_USE_COCOA
4733 extra->imageMask = 0;
4734#endif
4735}
4736
4737void QWidgetPrivate::deleteSysExtra()
4738{
4739#ifdef QT_MAC_USE_COCOA
4740 if (extra->imageMask)
4741 CFRelease(extra->imageMask);
4742#endif
4743}
4744
4745void QWidgetPrivate::createTLSysExtra()
4746{
4747 extra->topextra->resizer = 0;
4748 extra->topextra->isSetGeometry = 0;
4749 extra->topextra->isMove = 0;
4750 extra->topextra->wattr = 0;
4751 extra->topextra->wclass = 0;
4752 extra->topextra->group = 0;
4753 extra->topextra->windowIcon = 0;
4754 extra->topextra->savedWindowAttributesFromMaximized = 0;
4755}
4756
4757void QWidgetPrivate::deleteTLSysExtra()
4758{
4759#ifndef QT_MAC_USE_COCOA
4760 if (extra->topextra->group) {
4761 qt_mac_release_window_group(extra->topextra->group);
4762 extra->topextra->group = 0;
4763 }
4764 if (extra->topextra->windowIcon) {
4765 ReleaseIconRef(extra->topextra->windowIcon);
4766 extra->topextra->windowIcon = 0;
4767 }
4768#endif
4769}
4770
4771void QWidgetPrivate::updateFrameStrut()
4772{
4773 Q_Q(QWidget);
4774
4775 QWidgetPrivate *that = const_cast<QWidgetPrivate*>(this);
4776
4777 that->data.fstrut_dirty = false;
4778 QTLWExtra *top = that->topData();
4779
4780#if QT_MAC_USE_COCOA
4781 // 1 Get the window frame
4782 OSWindowRef oswnd = qt_mac_window_for(q);
4783 NSRect frameW = [oswnd frame];
4784 // 2 Get the content frame - so now
4785 NSRect frameC = [oswnd contentRectForFrameRect:frameW];
4786 top->frameStrut.setCoords(frameC.origin.x - frameW.origin.x,
4787 (frameW.origin.y + frameW.size.height) - (frameC.origin.y + frameC.size.height),
4788 (frameW.origin.x + frameW.size.width) - (frameC.origin.x + frameC.size.width),
4789 frameC.origin.y - frameW.origin.y);
4790#else
4791 Rect window_r;
4792 GetWindowStructureWidths(qt_mac_window_for(q), &window_r);
4793 top->frameStrut.setCoords(window_r.left, window_r.top, window_r.right, window_r.bottom);
4794#endif
4795}
4796
4797void QWidgetPrivate::registerDropSite(bool on)
4798{
4799 Q_Q(QWidget);
4800 if (!q->testAttribute(Qt::WA_WState_Created))
4801 return;
4802#ifndef QT_MAC_USE_COCOA
4803 SetControlDragTrackingEnabled(qt_mac_nativeview_for(q), on);
4804#else
4805 NSWindow *win = qt_mac_window_for(q);
4806 if (on) {
4807 if ([win isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaWindow) class]])
4808 [static_cast<QT_MANGLE_NAMESPACE(QCocoaWindow) *>(win) registerDragTypes];
4809 else if ([win isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaPanel) class]])
4810 [static_cast<QT_MANGLE_NAMESPACE(QCocoaPanel) *>(win) registerDragTypes];
4811 }
4812#endif
4813}
4814
4815void QWidgetPrivate::registerTouchWindow()
4816{
4817#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
4818 if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_6)
4819 return;
4820 Q_Q(QWidget);
4821 if (!q->testAttribute(Qt::WA_WState_Created))
4822 return;
4823#ifndef QT_MAC_USE_COCOA
4824 // Needs implementation!
4825#else
4826 NSView *view = qt_mac_nativeview_for(q);
4827 [view setAcceptsTouchEvents:YES];
4828#endif
4829#endif
4830}
4831
4832void QWidgetPrivate::setMask_sys(const QRegion &region)
4833{
4834 Q_UNUSED(region);
4835#ifndef QT_MAC_USE_COCOA
4836 Q_Q(QWidget);
4837 if (q->isWindow())
4838 ReshapeCustomWindow(qt_mac_window_for(q));
4839 else
4840 HIViewReshapeStructure(qt_mac_nativeview_for(q));
4841#else
4842 if (extra->mask.isEmpty()) {
4843 extra->maskBits = QImage();
4844 finishCocoaMaskSetup();
4845 } else {
4846 syncCocoaMask();
4847 }
4848
4849#endif
4850}
4851
4852void QWidgetPrivate::setWindowOpacity_sys(qreal level)
4853{
4854 Q_Q(QWidget);
4855
4856 if (!q->isWindow())
4857 return;
4858
4859 level = qBound(0.0, level, 1.0);
4860 topData()->opacity = (uchar)(level * 255);
4861 if (!q->testAttribute(Qt::WA_WState_Created))
4862 return;
4863
4864 OSWindowRef oswindow = qt_mac_window_for(q);
4865#if QT_MAC_USE_COCOA
4866 [oswindow setAlphaValue:level];
4867#else
4868 SetWindowAlpha(oswindow, level);
4869#endif
4870}
4871
4872#ifdef QT_MAC_USE_COCOA
4873void QWidgetPrivate::syncCocoaMask()
4874{
4875 Q_Q(QWidget);
4876 if (!q->testAttribute(Qt::WA_WState_Created) || !extra)
4877 return;
4878
4879 if (extra->hasMask) {
4880 if(extra->maskBits.size() != q->size()) {
4881 extra->maskBits = QImage(q->size(), QImage::Format_Mono);
4882 }
4883 extra->maskBits.fill(QColor(Qt::color1).rgba());
4884 extra->maskBits.setNumColors(2);
4885 extra->maskBits.setColor(0, QColor(Qt::color0).rgba());
4886 extra->maskBits.setColor(1, QColor(Qt::color1).rgba());
4887 QPainter painter(&extra->maskBits);
4888 painter.setBrush(Qt::color1);
4889 painter.setPen(Qt::NoPen);
4890 painter.drawRects(extra->mask.rects());
4891 painter.end();
4892 finishCocoaMaskSetup();
4893 }
4894}
4895
4896void QWidgetPrivate::finishCocoaMaskSetup()
4897{
4898 Q_Q(QWidget);
4899
4900 if (!q->testAttribute(Qt::WA_WState_Created) || !extra)
4901 return;
4902
4903 // Technically this is too late to release, because the data behind the image
4904 // has already been released. But it's more tidy to do it here.
4905 // If you are seeing a crash, consider doing a CFRelease before changing extra->maskBits.
4906 if (extra->imageMask) {
4907 CFRelease(extra->imageMask);
4908 extra->imageMask = 0;
4909 }
4910
4911 if (!extra->maskBits.isNull()) {
4912 QCFType<CGDataProviderRef> dataProvider = CGDataProviderCreateWithData(0,
4913 extra->maskBits.bits(),
4914 extra->maskBits.numBytes(),
4915 0); // shouldn't need to release.
4916 CGFloat decode[2] = {1, 0};
4917 extra->imageMask = CGImageMaskCreate(extra->maskBits.width(), extra->maskBits.height(),
4918 1, 1, extra->maskBits.bytesPerLine(), dataProvider,
4919 decode, false);
4920 }
4921 if (q->isWindow()) {
4922 NSWindow *window = qt_mac_window_for(q);
4923 [window setOpaque:(extra->imageMask == 0)];
4924 [window invalidateShadow];
4925 }
4926 qt_mac_set_needs_display(q, QRegion());
4927}
4928#endif
4929
4930struct QPaintEngineCleanupHandler
4931{
4932 inline QPaintEngineCleanupHandler() : engine(0) {}
4933 inline ~QPaintEngineCleanupHandler() { delete engine; }
4934 QPaintEngine *engine;
4935};
4936
4937Q_GLOBAL_STATIC(QPaintEngineCleanupHandler, engineHandler)
4938
4939QPaintEngine *QWidget::paintEngine() const
4940{
4941 QPaintEngine *&pe = engineHandler()->engine;
4942 if (!pe)
4943 pe = new QCoreGraphicsPaintEngine();
4944 if (pe->isActive()) {
4945 QPaintEngine *engine = new QCoreGraphicsPaintEngine();
4946 engine->setAutoDestruct(true);
4947 return engine;
4948 }
4949 return pe;
4950}
4951
4952void QWidgetPrivate::setModal_sys()
4953{
4954 Q_Q(QWidget);
4955 if (!q->testAttribute(Qt::WA_WState_Created) || !q->isWindow())
4956 return;
4957 const QWidget * const windowParent = q->window()->parentWidget();
4958 const QWidget * const primaryWindow = windowParent ? windowParent->window() : 0;
4959 OSWindowRef windowRef = qt_mac_window_for(q);
4960
4961#ifdef QT_MAC_USE_COCOA
4962 QMacCocoaAutoReleasePool pool;
4963 bool alreadySheet = [windowRef styleMask] & NSDocModalWindowMask;
4964
4965 if (windowParent && q->windowModality() == Qt::WindowModal){
4966 // INVARIANT: Window should be window-modal (which implies a sheet).
4967 if (!alreadySheet) {
4968 // NB: the following call will call setModal_sys recursivly:
4969 recreateMacWindow();
4970 windowRef = qt_mac_window_for(q);
4971 }
4972 if ([windowRef isKindOfClass:[NSPanel class]]){
4973 // If the primary window of the sheet parent is a child of a modal dialog,
4974 // the sheet parent should not be modally shaddowed.
4975 // This goes for the sheet as well:
4976 OSWindowRef ref = primaryWindow ? qt_mac_window_for(primaryWindow) : 0;
4977 bool isDialog = ref ? [ref isKindOfClass:[NSPanel class]] : false;
4978 bool worksWhenModal = isDialog ? [static_cast<NSPanel *>(ref) worksWhenModal] : false;
4979 if (worksWhenModal)
4980 [static_cast<NSPanel *>(windowRef) setWorksWhenModal:YES];
4981 }
4982 } else {
4983 // INVARIANT: Window shold _not_ be window-modal (and as such, not a sheet).
4984 if (alreadySheet){
4985 // NB: the following call will call setModal_sys recursivly:
4986 recreateMacWindow();
4987 windowRef = qt_mac_window_for(q);
4988 }
4989 if (q->windowModality() == Qt::NonModal
4990 && primaryWindow && primaryWindow->windowModality() == Qt::ApplicationModal) {
4991 // INVARIANT: Our window has a parent that is application modal.
4992 // This means that q is supposed to be on top of this window and
4993 // not be modally shaddowed:
4994 if ([windowRef isKindOfClass:[NSPanel class]])
4995 [static_cast<NSPanel *>(windowRef) setWorksWhenModal:YES];
4996 }
4997 }
4998
4999#else
5000 const bool primaryWindowModal = primaryWindow ? primaryWindow->testAttribute(Qt::WA_ShowModal) : false;
5001 const bool modal = q->testAttribute(Qt::WA_ShowModal);
5002
5003 WindowClass old_wclass;
5004 GetWindowClass(windowRef, &old_wclass);
5005
5006 if (modal || primaryWindowModal) {
5007 if (q->windowModality() == Qt::WindowModal
5008 || (primaryWindow && primaryWindow->windowModality() == Qt::WindowModal)){
5009 // Window should be window-modal (which implies a sheet).
5010 if (old_wclass != kSheetWindowClass){
5011 // We cannot convert a created window to a sheet.
5012 // So we recreate the window:
5013 recreateMacWindow();
5014 return;
5015 }
5016 } else {
5017 // Window should be application-modal (which implies NOT using a sheet).
5018 if (old_wclass == kSheetWindowClass){
5019 // We cannot convert a sheet to a window.
5020 // So we recreate the window:
5021 recreateMacWindow();
5022 return;
5023 } else if (!(q->data->window_flags & Qt::CustomizeWindowHint)) {
5024 if (old_wclass == kDocumentWindowClass || old_wclass == kFloatingWindowClass || old_wclass == kUtilityWindowClass){
5025 // Only change the class to kMovableModalWindowClass if the no explicit jewels
5026 // are set (kMovableModalWindowClass can't contain them), and the current window class
5027 // can be converted to modal (according to carbon doc). Mind the order of
5028 // HIWindowChangeClass and ChangeWindowAttributes.
5029 WindowGroupRef group = GetWindowGroup(windowRef);
5030 HIWindowChangeClass(windowRef, kMovableModalWindowClass);
5031 quint32 tmpWattr = kWindowCloseBoxAttribute | kWindowHorizontalZoomAttribute;
5032 ChangeWindowAttributes(windowRef, tmpWattr, kWindowNoAttributes);
5033 ChangeWindowAttributes(windowRef, kWindowNoAttributes, tmpWattr);
5034 // If the window belongs to a qt-created group, set that group once more:
5035 if (data.window_flags & Qt::WindowStaysOnTopHint
5036 || q->windowType() == Qt::Popup
5037 || q->windowType() == Qt::ToolTip)
5038 SetWindowGroup(windowRef, group);
5039 }
5040 // Popups are usually handled "special" and are never modal.
5041 Qt::WindowType winType = q->windowType();
5042 if (winType != Qt::Popup && winType != Qt::ToolTip)
5043 SetWindowModality(windowRef, kWindowModalityAppModal, 0);
5044 }
5045 }
5046 } else if (windowRef) {
5047 if (old_wclass == kSheetWindowClass){
5048 // Converting a sheet to a window is complex. It's easier to recreate:
5049 recreateMacWindow();
5050 return;
5051 }
5052
5053 SetWindowModality(windowRef, kWindowModalityNone, 0);
5054 if (!(q->data->window_flags & Qt::CustomizeWindowHint)) {
5055 if (q->window()->d_func()->topData()->wattr |= kWindowCloseBoxAttribute)
5056 ChangeWindowAttributes(windowRef, kWindowCloseBoxAttribute, kWindowNoAttributes);
5057 if (q->window()->d_func()->topData()->wattr |= kWindowHorizontalZoomAttribute)
5058 ChangeWindowAttributes(windowRef, kWindowHorizontalZoomAttribute, kWindowNoAttributes);
5059 if (q->window()->d_func()->topData()->wattr |= kWindowCollapseBoxAttribute)
5060 ChangeWindowAttributes(windowRef, kWindowCollapseBoxAttribute, kWindowNoAttributes);
5061 }
5062
5063 WindowClass newClass = q->window()->d_func()->topData()->wclass;
5064 if (old_wclass != newClass && newClass != 0){
5065 WindowGroupRef group = GetWindowGroup(windowRef);
5066 HIWindowChangeClass(windowRef, newClass);
5067 // If the window belongs to a qt-created group, set that group once more:
5068 if (data.window_flags & Qt::WindowStaysOnTopHint
5069 || q->windowType() == Qt::Popup
5070 || q->windowType() == Qt::ToolTip)
5071 SetWindowGroup(windowRef, group);
5072 }
5073 }
5074
5075 // Make sure that HIWindowChangeClass didn't remove drag support
5076 // or reset the opaque size grip setting:
5077 SetAutomaticControlDragTrackingEnabledForWindow(windowRef, true);
5078 macUpdateOpaqueSizeGrip();
5079#endif
5080}
5081
5082void QWidgetPrivate::macUpdateHideOnSuspend()
5083{
5084 Q_Q(QWidget);
5085 if (!q->testAttribute(Qt::WA_WState_Created) || !q->isWindow() || q->windowType() != Qt::Tool)
5086 return;
5087#ifndef QT_MAC_USE_COCOA
5088 if(q->testAttribute(Qt::WA_MacAlwaysShowToolWindow))
5089 ChangeWindowAttributes(qt_mac_window_for(q), 0, kWindowHideOnSuspendAttribute);
5090 else
5091 ChangeWindowAttributes(qt_mac_window_for(q), kWindowHideOnSuspendAttribute, 0);
5092#else
5093 if(q->testAttribute(Qt::WA_MacAlwaysShowToolWindow))
5094 [qt_mac_window_for(q) setHidesOnDeactivate:NO];
5095 else
5096 [qt_mac_window_for(q) setHidesOnDeactivate:YES];
5097#endif
5098}
5099
5100void QWidgetPrivate::macUpdateOpaqueSizeGrip()
5101{
5102 Q_Q(QWidget);
5103
5104 if (!q->testAttribute(Qt::WA_WState_Created) || !q->isWindow())
5105 return;
5106
5107#ifndef QT_MAC_USE_COCOA // Growbox is always transparent on Cocoa. Can emulate with setting a QSizeGrip
5108 HIViewRef growBox;
5109 HIViewFindByID(HIViewGetRoot(qt_mac_window_for(q)), kHIViewWindowGrowBoxID, &growBox);
5110 if (!growBox)
5111 return;
5112 HIGrowBoxViewSetTransparent(growBox, !q->testAttribute(Qt::WA_MacOpaqueSizeGrip));
5113#endif
5114}
5115
5116void QWidgetPrivate::macUpdateSizeAttribute()
5117{
5118 Q_Q(QWidget);
5119 QEvent event(QEvent::MacSizeChange);
5120 QApplication::sendEvent(q, &event);
5121 for (int i = 0; i < children.size(); ++i) {
5122 QWidget *w = qobject_cast<QWidget *>(children.at(i));
5123 if (w && (!w->isWindow() || w->testAttribute(Qt::WA_WindowPropagation))
5124 && !q->testAttribute(Qt::WA_MacMiniSize) // no attribute set? inherit from parent
5125 && !w->testAttribute(Qt::WA_MacSmallSize)
5126 && !w->testAttribute(Qt::WA_MacNormalSize))
5127 w->d_func()->macUpdateSizeAttribute();
5128 }
5129 resolveFont();
5130}
5131
5132void QWidgetPrivate::macUpdateIgnoreMouseEvents()
5133{
5134#ifndef QT_MAC_USE_COCOA // This is handled inside the mouse handler on Cocoa.
5135 Q_Q(QWidget);
5136 if (!q->testAttribute(Qt::WA_WState_Created))
5137 return;
5138
5139 if(q->isWindow())
5140 {
5141 if(q->testAttribute(Qt::WA_TransparentForMouseEvents))
5142 ChangeWindowAttributes(qt_mac_window_for(q), kWindowIgnoreClicksAttribute, 0);
5143 else
5144 ChangeWindowAttributes(qt_mac_window_for(q), 0, kWindowIgnoreClicksAttribute);
5145 ReshapeCustomWindow(qt_mac_window_for(q));
5146 } else {
5147#ifndef kHIViewFeatureIgnoresClicks
5148#define kHIViewFeatureIgnoresClicks kHIViewIgnoresClicks
5149#endif
5150 if(q->testAttribute(Qt::WA_TransparentForMouseEvents))
5151 HIViewChangeFeatures(qt_mac_nativeview_for(q), kHIViewFeatureIgnoresClicks, 0);
5152 else
5153 HIViewChangeFeatures(qt_mac_nativeview_for(q), 0, kHIViewFeatureIgnoresClicks);
5154 HIViewReshapeStructure(qt_mac_nativeview_for(q));
5155 }
5156#endif
5157}
5158
5159void QWidgetPrivate::macUpdateMetalAttribute()
5160{
5161 Q_Q(QWidget);
5162 bool realWindow = isRealWindow();
5163 if (!q->testAttribute(Qt::WA_WState_Created) || !realWindow)
5164 return;
5165
5166 if (realWindow) {
5167#if QT_MAC_USE_COCOA
5168 // Cocoa doesn't let us change the style mask once it's been changed
5169 // So, that means we need to recreate the window.
5170 OSWindowRef cocoaWindow = qt_mac_window_for(q);
5171 if ([cocoaWindow styleMask] & NSTexturedBackgroundWindowMask)
5172 return;
5173 recreateMacWindow();
5174#else
5175 QMainWindowLayout *layout = qt_mainwindow_layout(qobject_cast<QMainWindow *>(q));
5176 if (q->testAttribute(Qt::WA_MacBrushedMetal)) {
5177 if (layout)
5178 layout->updateHIToolBarStatus();
5179 ChangeWindowAttributes(qt_mac_window_for(q), kWindowMetalAttribute, 0);
5180 ChangeWindowAttributes(qt_mac_window_for(q), kWindowMetalNoContentSeparatorAttribute, 0);
5181 } else {
5182 ChangeWindowAttributes(qt_mac_window_for(q), 0, kWindowMetalNoContentSeparatorAttribute);
5183 ChangeWindowAttributes(qt_mac_window_for(q), 0, kWindowMetalAttribute);
5184 if (layout)
5185 layout->updateHIToolBarStatus();
5186 }
5187#endif
5188 }
5189}
5190
5191void QWidgetPrivate::setEnabled_helper_sys(bool enable)
5192{
5193#ifdef QT_MAC_USE_COCOA
5194 Q_Q(QWidget);
5195 NSView *view = qt_mac_nativeview_for(q);
5196 if ([view isKindOfClass:[NSControl class]])
5197 [static_cast<NSControl *>(view) setEnabled:enable];
5198#else
5199 Q_UNUSED(enable);
5200#endif
5201}
5202
5203QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.