1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 /****************************************************************************
44 ** Copyright (c) 2007-2008, Apple, Inc.
46 ** All rights reserved.
48 ** Redistribution and use in source and binary forms, with or without
49 ** modification, are permitted provided that the following conditions are met:
51 ** * Redistributions of source code must retain the above copyright notice,
52 ** this list of conditions and the following disclaimer.
54 ** * Redistributions in binary form must reproduce the above copyright notice,
55 ** this list of conditions and the following disclaimer in the documentation
56 ** and/or other materials provided with the distribution.
58 ** * Neither the name of Apple, Inc. nor the names of its contributors
59 ** may be used to endorse or promote products derived from this software
60 ** without specific prior written permission.
62 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
63 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
64 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
65 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
66 ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
67 ** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
68 ** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
69 ** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
70 ** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
71 ** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
72 ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
74 ****************************************************************************/
76 #include <private/qt_mac_p.h>
77 #include <private/qeventdispatcher_mac_p.h>
79 #include "qapplication.h"
80 #include "qapplication_p.h"
83 #include "qdesktopwidget.h"
85 #include "qfileinfo.h"
89 #include <private/qbackingstore_p.h>
90 #include <private/qwindowsurface_mac_p.h>
91 #include <private/qpaintengine_mac_p.h>
95 #include "qfocusframe.h"
97 #include <private/qmainwindowlayout_p.h>
99 #include <private/qabstractscrollarea_p.h>
100 #include <qabstractscrollarea.h>
101 #include <ApplicationServices/ApplicationServices.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>
109 #include "qwidget_p.h"
110 #include "qevent_p.h"
112 #include <QtGui/qgraphicsproxywidget.h>
113 #include "qmainwindow.h"
118 extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *window);
120 #define XCOORD_MAX 16383
121 #define WRECT_MAX 8191
125 /*****************************************************************************
126 QWidget debug facilities
127 *****************************************************************************/
128 //#define DEBUG_WINDOW_RGNS
129 //#define DEBUG_WINDOW_CREATE
130 //#define DEBUG_WINDOW_STATE
131 //#define DEBUG_WIDGET_PAINT
133 /*****************************************************************************
135 *****************************************************************************/
137 static bool qt_mac_raise_process = true;
138 static OSWindowRef qt_root_win = 0;
139 QWidget *mac_mouse_grabber = 0;
140 QWidget *mac_keyboard_grabber = 0;
143 /*****************************************************************************
145 *****************************************************************************/
146 extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp
147 extern QWidget *qt_mac_modal_blocked(QWidget *); //qapplication_mac.mm
148 extern void qt_event_request_activate(QWidget *); //qapplication_mac.mm
149 extern bool qt_event_remove_activate(); //qapplication_mac.mm
150 extern void qt_mac_event_release(QWidget *w); //qapplication_mac.mm
151 extern void qt_event_request_showsheet(QWidget *); //qapplication_mac.mm
152 extern void qt_event_request_window_change(QWidget *); //qapplication_mac.mm
153 extern QPointer<QWidget> qt_last_mouse_receiver; //qapplication_mac.mm
154 extern QPointer<QWidget> qt_last_native_mouse_receiver; //qt_cocoa_helpers_mac.mm
155 extern IconRef qt_mac_create_iconref(const QPixmap &); //qpixmap_mac.cpp
156 extern void qt_mac_set_cursor(const QCursor *, const QPoint &); //qcursor_mac.mm
157 extern void qt_mac_update_cursor(); //qcursor_mac.mm
158 extern bool qt_nograb();
159 extern CGImageRef qt_mac_create_cgimage(const QPixmap &, bool); //qpixmap_mac.cpp
160 extern RgnHandle qt_mac_get_rgn(); //qregion_mac.cpp
161 extern QRegion qt_mac_convert_mac_region(RgnHandle rgn); //qregion_mac.cpp
162 extern void qt_mac_setMouseGrabCursor(bool set, QCursor *cursor = 0); // qcursor_mac.mm
163 extern QPointer<QWidget> topLevelAt_cache; // qapplication_mac.mm
164 /*****************************************************************************
165 QWidget utility functions
166 *****************************************************************************/
167 void Q_GUI_EXPORT qt_mac_set_raise_process(bool b) { qt_mac_raise_process = b; }
168 static QSize qt_mac_desktopSize()
171 CGDisplayCount cg_count;
172 CGGetActiveDisplayList(0, 0, &cg_count);
173 QVector<CGDirectDisplayID> displays(cg_count);
174 CGGetActiveDisplayList(cg_count, displays.data(), &cg_count);
175 Q_ASSERT(cg_count == (CGDisplayCount)displays.size());
176 for(int i = 0; i < (int)cg_count; ++i) {
177 CGRect r = CGDisplayBounds(displays.at(i));
178 w = qMax<int>(w, qRound(r.origin.x + r.size.width));
179 h = qMax<int>(h, qRound(r.origin.y + r.size.height));
184 static NSDrawer *qt_mac_drawer_for(const QWidget *widget)
186 NSView *widgetView = reinterpret_cast<NSView *>(widget->window()->effectiveWinId());
187 NSArray *windows = [NSApp windows];
188 for (NSWindow *window in windows) {
189 NSArray *drawers = [window drawers];
190 for (NSDrawer *drawer in drawers) {
191 if ([drawer contentView] == widgetView)
198 static void qt_mac_destructView(OSViewRef view)
200 NSWindow *window = [view window];
201 if ([window contentView] == view)
202 [window setContentView:[[NSView alloc] initWithFrame:[view bounds]]];
203 [view removeFromSuperview];
207 static void qt_mac_destructWindow(OSWindowRef window)
209 if ([window isVisible] && [window isSheet]){
210 [NSApp endSheet:window];
211 [window orderOut:window];
214 [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] resignDelegateForWindow:window];
218 static void qt_mac_destructDrawer(NSDrawer *drawer)
220 [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] resignDelegateForDrawer:drawer];
224 bool qt_mac_can_clickThrough(const QWidget *w)
226 static int qt_mac_carbon_clickthrough = -1;
227 if (qt_mac_carbon_clickthrough < 0)
228 qt_mac_carbon_clickthrough = !qgetenv("QT_MAC_NO_COCOA_CLICKTHROUGH").isEmpty();
229 bool ret = !qt_mac_carbon_clickthrough;
230 for ( ; w; w = w->parentWidget()) {
231 if (w->testAttribute(Qt::WA_MacNoClickThrough)) {
239 bool qt_mac_is_macsheet(const QWidget *w)
244 Qt::WindowModality modality = w->windowModality();
245 if (modality == Qt::ApplicationModal)
247 return w->parentWidget() && (modality == Qt::WindowModal || w->windowType() == Qt::Sheet);
250 bool qt_mac_is_macdrawer(const QWidget *w)
252 return (w && w->parentWidget() && w->windowType() == Qt::Drawer);
255 bool qt_mac_insideKeyWindow(const QWidget *w)
257 return [[reinterpret_cast<NSView *>(w->effectiveWinId()) window] isKeyWindow];
261 bool qt_mac_set_drawer_preferred_edge(QWidget *w, Qt::DockWidgetArea where) //users of Qt for Mac OS X can use this..
263 if(!qt_mac_is_macdrawer(w))
266 NSDrawer *drawer = qt_mac_drawer_for(w);
270 if (where & Qt::LeftDockWidgetArea)
272 else if (where & Qt::RightDockWidgetArea)
274 else if (where & Qt::TopDockWidgetArea)
276 else if (where & Qt::BottomDockWidgetArea)
281 if (edge == [drawer preferredEdge]) //no-op
284 if (w->isVisible()) {
286 [drawer openOnEdge:edge];
288 [drawer setPreferredEdge:edge];
292 QPoint qt_mac_posInWindow(const QWidget *w)
294 QPoint ret = w->data->wrect.topLeft();
295 while(w && !w->isWindow()) {
297 w = w->parentWidget();
302 //find a QWidget from a OSWindowRef
303 QWidget *qt_mac_find_window(OSWindowRef window)
305 return [window QT_MANGLE_NAMESPACE(qt_qwidget)];
308 inline static void qt_mac_set_fullscreen_mode(bool b)
310 extern bool qt_mac_app_fullscreen; //qapplication_mac.mm
311 if(qt_mac_app_fullscreen == b)
313 qt_mac_app_fullscreen = b;
315 SetSystemUIMode(kUIModeAllHidden, kUIOptionAutoShowMenuBar);
317 SetSystemUIMode(kUIModeNormal, 0);
321 Q_GUI_EXPORT OSViewRef qt_mac_nativeview_for(const QWidget *w)
323 return reinterpret_cast<OSViewRef>(w->internalWinId());
326 Q_GUI_EXPORT OSViewRef qt_mac_effectiveview_for(const QWidget *w)
328 // Get the first non-alien (parent) widget for
329 // w, and return its NSView (if it has one):
330 return reinterpret_cast<OSViewRef>(w->effectiveWinId());
333 Q_GUI_EXPORT OSViewRef qt_mac_get_contentview_for(OSWindowRef w)
335 return [w contentView];
338 bool qt_mac_sendMacEventToWidget(QWidget *widget, EventRef ref)
340 return widget->macEvent(0, ref);
343 Q_GUI_EXPORT OSWindowRef qt_mac_window_for(OSViewRef view)
346 return [view window];
350 static bool qt_isGenuineQWidget(OSViewRef ref)
352 return [ref isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaView) class]];
355 bool qt_isGenuineQWidget(const QWidget *window)
360 if (!window->internalWinId())
363 return qt_isGenuineQWidget(OSViewRef(window->internalWinId()));
366 Q_GUI_EXPORT OSWindowRef qt_mac_window_for(const QWidget *w)
368 if (OSViewRef hiview = qt_mac_effectiveview_for(w)) {
369 OSWindowRef window = qt_mac_window_for(hiview);
373 if (qt_isGenuineQWidget(hiview)) {
374 // This is a workaround for NSToolbar. When a widget is hidden
375 // by clicking the toolbar button, Cocoa reparents the widgets
376 // to another window (but Qt doesn't know about it).
377 // When we start showing them, it reparents back,
378 // but at this point it's window is nil, but the window it's being brought
379 // into (the Qt one) is for sure created.
380 // This stops the hierarchy moving under our feet.
381 QWidget *toplevel = w->window();
383 hiview = qt_mac_nativeview_for(toplevel);
384 if (OSWindowRef w = qt_mac_window_for(hiview))
388 toplevel->d_func()->createWindow_sys();
389 // Reget the hiview since "create window" could potentially move the view (I guess).
390 hiview = qt_mac_nativeview_for(toplevel);
391 return qt_mac_window_for(hiview);
399 inline static bool updateRedirectedToGraphicsProxyWidget(QWidget *widget, const QRect &rect)
404 #ifndef QT_NO_GRAPHICSVIEW
405 QWidget *tlw = widget->window();
406 QWExtra *extra = qt_widget_private(tlw)->extra;
407 if (extra && extra->proxyWidget) {
408 extra->proxyWidget->update(rect.translated(widget->mapTo(tlw, QPoint())));
416 inline static bool updateRedirectedToGraphicsProxyWidget(QWidget *widget, const QRegion &rgn)
421 #ifndef QT_NO_GRAPHICSVIEW
422 QWidget *tlw = widget->window();
423 QWExtra *extra = qt_widget_private(tlw)->extra;
424 if (extra && extra->proxyWidget) {
425 const QPoint offset(widget->mapTo(tlw, QPoint()));
426 const QVector<QRect> rects = rgn.rects();
427 for (int i = 0; i < rects.size(); ++i)
428 extra->proxyWidget->update(rects.at(i).translated(offset));
436 void QWidgetPrivate::macSetNeedsDisplay(QRegion region)
439 if (NSView *nativeView = qt_mac_nativeview_for(q)) {
440 // INVARIANT: q is _not_ alien. So we can optimize a little:
441 if (region.isEmpty()) {
442 [nativeView setNeedsDisplay:YES];
444 QVector<QRect> rects = region.rects();
445 for (int i = 0; i<rects.count(); ++i) {
446 const QRect &rect = rects.at(i);
447 NSRect nsrect = NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height());
448 [nativeView setNeedsDisplayInRect:nsrect];
451 } else if (QWidget *effectiveWidget = q->nativeParentWidget()) {
452 // INVARIANT: q is alien, and effectiveWidget is native.
453 if (NSView *effectiveView = qt_mac_nativeview_for(effectiveWidget)) {
454 if (region.isEmpty()) {
455 const QRect &rect = q->rect();
456 QPoint p = q->mapTo(effectiveWidget, rect.topLeft());
457 NSRect nsrect = NSMakeRect(p.x(), p.y(), rect.width(), rect.height());
458 [effectiveView setNeedsDisplayInRect:nsrect];
460 QVector<QRect> rects = region.rects();
461 for (int i = 0; i<rects.count(); ++i) {
462 const QRect &rect = rects.at(i);
463 QPoint p = q->mapTo(effectiveWidget, rect.topLeft());
464 NSRect nsrect = NSMakeRect(p.x(), p.y(), rect.width(), rect.height());
465 [effectiveView setNeedsDisplayInRect:nsrect];
472 void QWidgetPrivate::macUpdateIsOpaque()
475 if (!q->testAttribute(Qt::WA_WState_Created))
477 if (isRealWindow() && !q->testAttribute(Qt::WA_MacBrushedMetal)) {
478 bool opaque = isOpaque;
479 if (extra && extra->imageMask)
480 opaque = false; // we are never opaque when we have a mask.
481 [qt_mac_window_for(q) setOpaque:opaque];
484 static OSWindowRef qt_mac_create_window(QWidget *widget, WindowClass wclass,
485 NSUInteger wattr, const QRect &crect)
487 // Determine if we need to add in our "custom window" attribute. Cocoa is rather clever
488 // in deciding if we need the maximize button or not (i.e., it's resizeable, so you
489 // must need a maximize button). So, the only buttons we have control over are the
490 // close and minimize buttons. If someone wants to customize and NOT have the maximize
491 // button, then we have to do our hack. We only do it for these cases because otherwise
492 // the window looks different when activated. This "QtMacCustomizeWindow" attribute is
493 // intruding on a public space and WILL BREAK in the future.
494 // One can hope that there is a more public API available by that time.
495 Qt::WindowFlags flags = widget ? widget->windowFlags() : Qt::WindowFlags(0);
496 if ((flags & Qt::CustomizeWindowHint)) {
497 if ((flags & (Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint
498 | Qt::WindowMinimizeButtonHint | Qt::WindowTitleHint))
499 && !(flags & Qt::WindowMaximizeButtonHint))
500 wattr |= QtMacCustomizeWindow;
503 // If we haven't created the desktop widget, you have to pass the rectangle
504 // in "cocoa coordinates" (i.e., top points to the lower left coordinate).
505 // Otherwise, we do the conversion for you. Since we are the only ones that
506 // create the desktop widget, this is OK (but confusing).
507 NSRect geo = NSMakeRect(crect.left(),
508 (qt_root_win != 0) ? flipYCoordinate(crect.bottom() + 1) : crect.top(),
509 crect.width(), crect.height());
510 QMacCocoaAutoReleasePool pool;
513 case kMovableModalWindowClass:
514 case kModalWindowClass:
515 case kSheetWindowClass:
516 case kFloatingWindowClass:
517 case kOverlayWindowClass:
518 case kHelpWindowClass: {
520 BOOL needFloating = NO;
521 BOOL worksWhenModal = widget && (widget->windowType() == Qt::Popup);
522 // Add in the extra flags if necessary.
524 case kSheetWindowClass:
525 wattr |= NSDocModalWindowMask;
527 case kFloatingWindowClass:
528 case kHelpWindowClass:
530 wattr |= NSUtilityWindowMask;
535 panel = [[QT_MANGLE_NAMESPACE(QCocoaPanel) alloc] QT_MANGLE_NAMESPACE(qt_initWithQWidget):widget contentRect:geo styleMask:wattr];
536 [panel setFloatingPanel:needFloating];
537 [panel setWorksWhenModal:worksWhenModal];
541 case kDrawerWindowClass: {
542 NSDrawer *drawer = [[NSDrawer alloc] initWithContentSize:geo.size preferredEdge:NSMinXEdge];
543 [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] becomeDelegateForDrawer:drawer widget:widget];
544 QWidget *parentWidget = widget->parentWidget();
546 [drawer setParentWindow:qt_mac_window_for(parentWidget)];
547 [drawer setLeadingOffset:0.0];
548 [drawer setTrailingOffset:25.0];
549 window = [[drawer contentView] window]; // Just to make sure we actually return a window
553 window = [[QT_MANGLE_NAMESPACE(QCocoaWindow) alloc] QT_MANGLE_NAMESPACE(qt_initWithQWidget):widget contentRect:geo styleMask:wattr];
556 qt_syncCocoaTitleBarButtons(window, widget);
560 OSViewRef qt_mac_create_widget(QWidget *widget, QWidgetPrivate *widgetPrivate, OSViewRef parent)
562 QMacCocoaAutoReleasePool pool;
563 QT_MANGLE_NAMESPACE(QCocoaView) *view = [[QT_MANGLE_NAMESPACE(QCocoaView) alloc] initWithQWidget:widget widgetPrivate:widgetPrivate];
566 qDebug() << "Creating NSView for" << widget;
570 [parent addSubview:view];
574 void qt_mac_unregister_widget()
578 void QWidgetPrivate::toggleDrawers(bool visible)
580 for (int i = 0; i < children.size(); ++i) {
581 register QObject *object = children.at(i);
582 if (!object->isWidgetType())
584 QWidget *widget = static_cast<QWidget*>(object);
585 if(qt_mac_is_macdrawer(widget)) {
586 bool oldState = widget->testAttribute(Qt::WA_WState_ExplicitShowHide);
588 if (!widget->testAttribute(Qt::WA_WState_ExplicitShowHide))
593 widget->setAttribute(Qt::WA_WState_ExplicitShowHide, false);
599 /*****************************************************************************
600 QWidgetPrivate member functions
601 *****************************************************************************/
602 bool QWidgetPrivate::qt_mac_update_sizer(QWidget *w, int up)
604 // I'm not sure what "up" is
605 if(!w || !w->isWindow())
608 QTLWExtra *topData = w->d_func()->topData();
609 QWExtra *extraData = w->d_func()->extraData();
610 // topData->resizer is only 4 bits, so subtracting -1 from zero causes bad stuff
611 // to happen, prevent that here (you really want the thing hidden).
612 if (up >= 0 || topData->resizer != 0)
613 topData->resizer += up;
614 OSWindowRef windowRef = qt_mac_window_for(OSViewRef(w->effectiveWinId()));
617 bool remove_grip = (topData->resizer || (w->windowFlags() & Qt::FramelessWindowHint)
618 || (extraData->maxw && extraData->maxh &&
619 extraData->maxw == extraData->minw && extraData->maxh == extraData->minh));
620 [windowRef setShowsResizeIndicator:!remove_grip];
624 void QWidgetPrivate::qt_clean_root_win()
626 QMacCocoaAutoReleasePool pool;
627 [qt_root_win release];
631 bool QWidgetPrivate::qt_create_root_win()
635 const QSize desktopSize = qt_mac_desktopSize();
636 QRect desktopRect(QPoint(0, 0), desktopSize);
637 qt_root_win = qt_mac_create_window(0, kOverlayWindowClass, NSBorderlessWindowMask, desktopRect);
640 qAddPostRoutine(qt_clean_root_win);
644 bool QWidgetPrivate::qt_widget_rgn(QWidget *widget, short wcode, RgnHandle rgn, bool force = false)
654 /*****************************************************************************
655 QWidget member functions
656 *****************************************************************************/
657 void QWidgetPrivate::determineWindowClass()
660 #if !defined(QT_NO_MAINWINDOW) && !defined(QT_NO_TOOLBAR)
661 // Make sure that QMainWindow has the MacWindowToolBarButtonHint when the
662 // unifiedTitleAndToolBarOnMac property is ON. This is to avoid reentry of
663 // setParent() triggered by the QToolBar::event(QEvent::ParentChange).
664 QMainWindow *mainWindow = qobject_cast<QMainWindow *>(q);
665 if (mainWindow && mainWindow->unifiedTitleAndToolBarOnMac()) {
666 data.window_flags |= Qt::MacWindowToolBarButtonHint;
670 const Qt::WindowType type = q->windowType();
671 Qt::WindowFlags &flags = data.window_flags;
672 const bool popup = (type == Qt::Popup);
673 if (type == Qt::ToolTip || type == Qt::SplashScreen || popup)
674 flags |= Qt::FramelessWindowHint;
676 WindowClass wclass = kSheetWindowClass;
677 if(qt_mac_is_macdrawer(q))
678 wclass = kDrawerWindowClass;
679 else if (q->testAttribute(Qt::WA_ShowModal) && flags & Qt::CustomizeWindowHint)
680 wclass = kDocumentWindowClass;
681 else if(popup || (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5 && type == Qt::SplashScreen))
682 wclass = kModalWindowClass;
683 else if(type == Qt::Dialog)
684 wclass = kMovableModalWindowClass;
685 else if(type == Qt::ToolTip)
686 wclass = kHelpWindowClass;
687 else if(type == Qt::Tool || (QSysInfo::MacintoshVersion < QSysInfo::MV_10_5
688 && type == Qt::SplashScreen))
689 wclass = kFloatingWindowClass;
690 else if(q->testAttribute(Qt::WA_ShowModal))
691 wclass = kMovableModalWindowClass;
693 wclass = kDocumentWindowClass;
695 WindowAttributes wattr = NSBorderlessWindowMask;
696 if(qt_mac_is_macsheet(q)) {
697 //grp = GetWindowGroupOfClass(kMovableModalWindowClass);
698 wclass = kSheetWindowClass;
699 wattr = NSTitledWindowMask | NSResizableWindowMask;
701 // Shift things around a bit to get the correct window class based on the presence
702 // (or lack) of the border.
703 bool customize = flags & Qt::CustomizeWindowHint;
704 bool framelessWindow = (flags & Qt::FramelessWindowHint || (customize && !(flags & Qt::WindowTitleHint)));
705 if (framelessWindow) {
706 if (wclass == kDocumentWindowClass) {
707 wclass = kSimpleWindowClass;
708 } else if (wclass == kFloatingWindowClass) {
709 wclass = kToolbarWindowClass;
710 } else if (wclass == kMovableModalWindowClass) {
711 wclass = kModalWindowClass;
714 wattr |= NSTitledWindowMask;
715 if (wclass != kModalWindowClass)
716 wattr |= NSResizableWindowMask;
718 // Only add extra decorations (well, buttons) for widgets that can have them
719 // and have an actual border we can put them on.
720 if (wclass != kModalWindowClass
721 && wclass != kSheetWindowClass && wclass != kPlainWindowClass
722 && !framelessWindow && wclass != kDrawerWindowClass
723 && wclass != kHelpWindowClass) {
724 if (flags & Qt::WindowMinimizeButtonHint)
725 wattr |= NSMiniaturizableWindowMask;
726 if (flags & Qt::WindowSystemMenuHint || flags & Qt::WindowCloseButtonHint)
727 wattr |= NSClosableWindowMask;
729 // Clear these hints so that we aren't call them on invalid windows
730 flags &= ~(Qt::WindowMaximizeButtonHint | Qt::WindowMinimizeButtonHint
731 | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint);
734 if (q->testAttribute(Qt::WA_MacBrushedMetal))
735 wattr |= NSTexturedBackgroundWindowMask;
737 #ifdef DEBUG_WINDOW_CREATE
738 #define ADD_DEBUG_WINDOW_NAME(x) { x, #x }
742 } known_attribs[] = {
743 ADD_DEBUG_WINDOW_NAME(kWindowCompositingAttribute),
744 ADD_DEBUG_WINDOW_NAME(kWindowStandardHandlerAttribute),
745 ADD_DEBUG_WINDOW_NAME(kWindowMetalAttribute),
746 ADD_DEBUG_WINDOW_NAME(kWindowHideOnSuspendAttribute),
747 ADD_DEBUG_WINDOW_NAME(kWindowStandardHandlerAttribute),
748 ADD_DEBUG_WINDOW_NAME(kWindowCollapseBoxAttribute),
749 ADD_DEBUG_WINDOW_NAME(kWindowHorizontalZoomAttribute),
750 ADD_DEBUG_WINDOW_NAME(kWindowVerticalZoomAttribute),
751 ADD_DEBUG_WINDOW_NAME(kWindowResizableAttribute),
752 ADD_DEBUG_WINDOW_NAME(kWindowNoActivatesAttribute),
753 ADD_DEBUG_WINDOW_NAME(kWindowNoUpdatesAttribute),
754 ADD_DEBUG_WINDOW_NAME(kWindowOpaqueForEventsAttribute),
755 ADD_DEBUG_WINDOW_NAME(kWindowLiveResizeAttribute),
756 ADD_DEBUG_WINDOW_NAME(kWindowCloseBoxAttribute),
757 ADD_DEBUG_WINDOW_NAME(kWindowHideOnSuspendAttribute),
759 }, known_classes[] = {
760 ADD_DEBUG_WINDOW_NAME(kHelpWindowClass),
761 ADD_DEBUG_WINDOW_NAME(kPlainWindowClass),
762 ADD_DEBUG_WINDOW_NAME(kDrawerWindowClass),
763 ADD_DEBUG_WINDOW_NAME(kUtilityWindowClass),
764 ADD_DEBUG_WINDOW_NAME(kToolbarWindowClass),
765 ADD_DEBUG_WINDOW_NAME(kSheetWindowClass),
766 ADD_DEBUG_WINDOW_NAME(kFloatingWindowClass),
767 ADD_DEBUG_WINDOW_NAME(kUtilityWindowClass),
768 ADD_DEBUG_WINDOW_NAME(kDocumentWindowClass),
769 ADD_DEBUG_WINDOW_NAME(kToolbarWindowClass),
770 ADD_DEBUG_WINDOW_NAME(kMovableModalWindowClass),
771 ADD_DEBUG_WINDOW_NAME(kModalWindowClass),
774 qDebug("Qt: internal: ************* Creating new window %p (%s::%s)", q, q->metaObject()->className(),
775 q->objectName().toLocal8Bit().constData());
776 bool found_class = false;
777 for(int i = 0; known_classes[i].name; i++) {
778 if(wclass == known_classes[i].tag) {
780 qDebug("Qt: internal: ** Class: %s", known_classes[i].name);
785 qDebug("Qt: internal: !! Class: Unknown! (%d)", (int)wclass);
787 WindowAttributes tmp_wattr = wattr;
788 qDebug("Qt: internal: ** Attributes:");
789 for(int i = 0; tmp_wattr && known_attribs[i].name; i++) {
790 if((tmp_wattr & known_attribs[i].tag) == known_attribs[i].tag) {
791 tmp_wattr ^= known_attribs[i].tag;
795 qDebug("Qt: internal: !! Attributes: Unknown (%d)", (int)tmp_wattr);
799 topData()->wclass = wclass;
800 topData()->wattr = wattr;
803 #undef ADD_DEBUG_WINDOW_NAME
805 void QWidgetPrivate::setWindowLevel()
808 const QWidget * const windowParent = q->window()->parentWidget();
809 const QWidget * const primaryWindow = windowParent ? windowParent->window() : 0;
810 NSInteger winLevel = -1;
812 if (q->windowType() == Qt::Popup) {
813 winLevel = NSPopUpMenuWindowLevel;
814 // Popup should be in at least the same level as its parent.
816 OSWindowRef parentRef = qt_mac_window_for(primaryWindow);
817 winLevel = qMax([parentRef level], winLevel);
819 } else if (q->windowType() == Qt::Tool) {
820 winLevel = NSFloatingWindowLevel;
821 } else if (q->windowType() == Qt::Dialog) {
822 // Correct modality level (NSModalPanelWindowLevel) will be
823 // set by cocoa when creating a modal session later.
824 winLevel = NSNormalWindowLevel;
827 // StayOnTop window should appear above Tool windows.
828 if (data.window_flags & Qt::WindowStaysOnTopHint)
829 winLevel = NSPopUpMenuWindowLevel;
830 // Tooltips should appear above StayOnTop windows.
831 if (q->windowType() == Qt::ToolTip)
832 winLevel = NSScreenSaverWindowLevel;
833 // All other types are Normal level.
835 winLevel = NSNormalWindowLevel;
836 [qt_mac_window_for(q) setLevel:winLevel];
839 void QWidgetPrivate::finishCreateWindow_sys_Cocoa(void * /*NSWindow * */ voidWindowRef)
842 QMacCocoaAutoReleasePool pool;
843 NSWindow *windowRef = static_cast<NSWindow *>(voidWindowRef);
844 const Qt::WindowType type = q->windowType();
845 Qt::WindowFlags &flags = data.window_flags;
846 QWidget *parentWidget = q->parentWidget();
848 const bool popup = (type == Qt::Popup);
849 const bool dialog = (type == Qt::Dialog
851 || type == Qt::Drawer
852 || (flags & Qt::MSWindowsFixedSizeDialogHint));
853 QTLWExtra *topExtra = topData();
855 if ((popup || type == Qt::Tool || type == Qt::ToolTip) && !q->isModal()) {
856 [windowRef setHidesOnDeactivate:YES];
858 [windowRef setHidesOnDeactivate:NO];
860 if (q->testAttribute(Qt::WA_MacNoShadow))
861 [windowRef setHasShadow:NO];
863 [windowRef setHasShadow:YES];
864 Q_UNUSED(parentWidget);
867 data.fstrut_dirty = true; // when we create a toplevel widget, the frame strut should be dirty
869 OSViewRef nsview = (OSViewRef)data.winid;
871 nsview = qt_mac_create_widget(q, this, 0);
872 setWinId(WId(nsview));
874 [windowRef setContentView:nsview];
875 [nsview setHidden:NO];
878 // Tell Cocoa explicit that we wan't the view to receive key events
879 // (regardless of focus policy) because this is how it works on other
880 // platforms (and in the carbon port):
881 [windowRef makeFirstResponder:nsview];
883 if (topExtra->posFromMove) {
886 const QRect &fStrut = frameStrut();
887 const QRect &crect = data.crect;
888 const QRect frameRect(QPoint(crect.left(), crect.top()),
889 QSize(fStrut.left() + fStrut.right() + crect.width(),
890 fStrut.top() + fStrut.bottom() + crect.height()));
891 NSRect cocoaFrameRect = NSMakeRect(frameRect.x(), flipYCoordinate(frameRect.bottom() + 1),
892 frameRect.width(), frameRect.height());
893 [windowRef setFrame:cocoaFrameRect display:NO];
894 topExtra->posFromMove = false;
897 if (q->testAttribute(Qt::WA_WState_WindowOpacitySet)){
898 q->setWindowOpacity(topExtra->opacity / 255.0f);
899 } else if (qt_mac_is_macsheet(q)){
900 CGFloat alpha = [qt_mac_window_for(q) alphaValue];
902 q->setWindowOpacity(0.95f);
903 q->setAttribute(Qt::WA_WState_WindowOpacitySet, false);
906 // If the window has been recreated after beeing e.g. a sheet,
907 // make sure that we don't report a faulty opacity:
908 q->setWindowOpacity(1.0f);
909 q->setAttribute(Qt::WA_WState_WindowOpacitySet, false);
912 // Its more performant to handle the mouse cursor
913 // ourselves, expecially when using alien widgets:
914 [windowRef disableCursorRects];
917 macUpdateHideOnSuspend();
918 macUpdateOpaqueSizeGrip();
919 macUpdateIgnoreMouseEvents();
920 setWindowTitle_helper(extra->topextra->caption);
921 setWindowIconText_helper(extra->topextra->iconText);
922 setWindowModified_sys(q->isWindowModified());
926 qt_mac_update_sizer(q);
927 applyMaxAndMinSizeOnWindow();
932 Recreates widget window. Useful if immutable
933 properties for it has changed.
935 void QWidgetPrivate::recreateMacWindow()
938 OSViewRef myView = qt_mac_nativeview_for(q);
939 OSWindowRef oldWindow = qt_mac_window_for(myView);
940 QMacCocoaAutoReleasePool pool;
941 [myView removeFromSuperview];
942 determineWindowClass();
944 if (NSToolbar *toolbar = [oldWindow toolbar]) {
945 OSWindowRef newWindow = qt_mac_window_for(myView);
946 [newWindow setToolbar:toolbar];
947 [toolbar setVisible:[toolbar isVisible]];
949 if ([oldWindow isVisible]){
950 if ([oldWindow isSheet])
951 [NSApp endSheet:oldWindow];
952 [oldWindow orderOut:oldWindow];
956 // Release the window after creating the new window, because releasing it early
957 // may cause the app to quit ("close on last window closed attribute")
958 qt_mac_destructWindow(oldWindow);
961 void QWidgetPrivate::createWindow_sys()
964 Qt::WindowFlags &flags = data.window_flags;
965 QWidget *parentWidget = q->parentWidget();
967 QTLWExtra *topExtra = topData();
968 if (topExtra->embedded)
969 return; // Simply return because this view "is" the top window.
970 quint32 wattr = topExtra->wattr;
972 if(parentWidget && (parentWidget->window()->windowFlags() & Qt::WindowStaysOnTopHint)) // If our parent has Qt::WStyle_StaysOnTop, so must we
973 flags |= Qt::WindowStaysOnTopHint;
975 data.fstrut_dirty = true;
977 OSWindowRef windowRef = qt_mac_create_window(q, topExtra->wclass, wattr, data.crect);
979 qWarning("QWidget: Internal error: %s:%d: If you reach this error please contact Qt Support and include the\n"
980 " WidgetFlags used in creating the widget.", __FILE__, __LINE__);
981 finishCreateWindow_sys_Cocoa(windowRef);
984 void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyOldWindow)
987 QMacCocoaAutoReleasePool pool;
989 OSViewRef destroyid = 0;
991 Qt::WindowType type = q->windowType();
992 Qt::WindowFlags flags = data.window_flags;
993 QWidget *parentWidget = q->parentWidget();
995 bool topLevel = (flags & Qt::Window);
996 bool popup = (type == Qt::Popup);
997 bool dialog = (type == Qt::Dialog
999 || type == Qt::Drawer
1000 || (flags & Qt::MSWindowsFixedSizeDialogHint));
1001 bool desktop = (type == Qt::Desktop);
1003 // Determine this early for top-levels so, we can use it later.
1005 determineWindowClass();
1008 QSize desktopSize = qt_mac_desktopSize();
1009 q->setAttribute(Qt::WA_WState_Visible);
1010 data.crect.setRect(0, 0, desktopSize.width(), desktopSize.height());
1011 dialog = popup = false; // force these flags off
1013 if (topLevel && (type != Qt::Drawer)) {
1014 if (QDesktopWidget *dsk = QApplication::desktop()) { // calc pos/size from screen
1015 const bool wasResized = q->testAttribute(Qt::WA_Resized);
1016 const bool wasMoved = q->testAttribute(Qt::WA_Moved);
1017 int deskn = dsk->primaryScreen();
1018 if (parentWidget && parentWidget->windowType() != Qt::Desktop)
1019 deskn = dsk->screenNumber(parentWidget);
1020 QRect screenGeo = dsk->screenGeometry(deskn);
1022 NSRect newRect = [NSWindow frameRectForContentRect:NSMakeRect(0, 0,
1023 screenGeo.width() / 2.,
1024 4 * screenGeo.height() / 10.)
1025 styleMask:topData()->wattr];
1026 data.crect.setSize(QSize(newRect.size.width, newRect.size.height));
1027 // Constrain to minimums and maximums we've set
1028 if (extra->minw > 0)
1029 data.crect.setWidth(qMax(extra->minw, data.crect.width()));
1030 if (extra->minh > 0)
1031 data.crect.setHeight(qMax(extra->minh, data.crect.height()));
1032 if (extra->maxw > 0)
1033 data.crect.setWidth(qMin(extra->maxw, data.crect.width()));
1034 if (extra->maxh > 0)
1035 data.crect.setHeight(qMin(extra->maxh, data.crect.height()));
1037 if (!wasMoved && !q->testAttribute(Qt::WA_DontShowOnScreen))
1038 data.crect.moveTopLeft(QPoint(screenGeo.width()/4,
1039 3 * screenGeo.height() / 10));
1045 if(!window) // always initialize
1046 initializeWindow=true;
1049 if(window) { // override the old window (with a new NSView)
1050 OSViewRef nativeView = OSViewRef(window);
1051 OSViewRef parent = 0;
1052 [nativeView retain];
1053 if (destroyOldWindow)
1054 destroyid = qt_mac_nativeview_for(q);
1055 bool transfer = false;
1056 setWinId((WId)nativeView);
1058 for(int i = 0; i < 2; ++i) {
1060 if(!initializeWindow)
1064 if(OSWindowRef windowref = qt_mac_window_for(nativeView)) {
1066 if (initializeWindow) {
1067 parent = qt_mac_get_contentview_for(windowref);
1069 parent = [nativeView superview];
1076 } else if (parentWidget) {
1077 // I need to be added to my parent, therefore my parent needs an NSView
1078 // Alien note: a 'window' was supplied as argument, meaning this widget
1079 // is not alien. So therefore the parent cannot be alien either.
1080 parentWidget->createWinId();
1081 parent = qt_mac_nativeview_for(parentWidget);
1083 if(parent != nativeView && parent) {
1084 [parent addSubview:nativeView];
1088 data.fstrut_dirty = true; // we'll re calculate this later
1089 q->setAttribute(Qt::WA_WState_Visible,
1090 ![nativeView isHidden]
1092 if(initializeWindow) {
1093 NSRect bounds = NSMakeRect(data.crect.x(), data.crect.y(), data.crect.width(), data.crect.height());
1094 [nativeView setFrame:bounds];
1095 q->setAttribute(Qt::WA_WState_Visible, [nativeView isHidden]);
1097 } else if (desktop) { // desktop widget
1099 QWidgetPrivate::qt_create_root_win();
1100 Q_ASSERT(qt_root_win);
1102 [qt_root_win retain];
1103 if (OSViewRef rootContentView = [qt_root_win contentView]) {
1104 rootWinID = (WId)rootContentView;
1105 [rootContentView retain];
1107 setWinId(rootWinID);
1108 } else if (topLevel) {
1109 determineWindowClass();
1110 if(OSViewRef osview = qt_mac_create_widget(q, this, 0)) {
1111 NSRect bounds = NSMakeRect(data.crect.x(), flipYCoordinate(data.crect.y()),
1112 data.crect.width(), data.crect.height());
1113 [osview setFrame:bounds];
1114 setWinId((WId)osview);
1117 data.fstrut_dirty = false; // non-toplevel widgets don't have a frame, so no need to update the strut
1119 if (q->testAttribute(Qt::WA_NativeWindow) == false || q->internalWinId() != 0) {
1120 // INVARIANT: q is Alien, and we should not create an NSView to back it up.
1122 if (OSViewRef osview = qt_mac_create_widget(q, this, qt_mac_nativeview_for(parentWidget))) {
1123 NSRect bounds = NSMakeRect(data.crect.x(), data.crect.y(), data.crect.width(), data.crect.height());
1124 [osview setFrame:bounds];
1125 setWinId((WId)osview);
1126 if (q->isVisible()) {
1127 // If q were Alien before, but now became native (e.g. if a call to
1128 // winId was done from somewhere), we need to show the view immidiatly:
1129 QMacCocoaAutoReleasePool pool;
1130 [osview setHidden:NO];
1137 if (q->testAttribute(Qt::WA_DropSiteRegistered))
1138 registerDropSite(true);
1141 if (!topLevel && initializeWindow)
1144 qt_mac_destructView(destroyid);
1148 Returns the QuickDraw handle of the widget. Use of this function is not
1149 portable. This function will return 0 if QuickDraw is not supported, or
1150 if the handle could not be created.
1152 \warning This function is only available on Mac OS X.
1156 QWidget::macQDHandle() const
1162 Returns the CoreGraphics handle of the widget. Use of this function is
1163 not portable. This function will return 0 if no painter context can be
1164 established, or if the handle could not be created.
1166 \warning This function is only available on Mac OS X.
1169 QWidget::macCGHandle() const
1174 void qt_mac_updateParentUnderAlienWidget(QWidget *alienWidget)
1176 QWidget *nativeParent = alienWidget->nativeParentWidget();
1180 QPoint globalPos = alienWidget->mapToGlobal(QPoint(0, 0));
1181 QRect dirtyRect = QRect(nativeParent->mapFromGlobal(globalPos), alienWidget->size());
1182 nativeParent->update(dirtyRect);
1185 void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
1188 QMacCocoaAutoReleasePool pool;
1189 d->aboutToDestroy();
1190 if (!isWindow() && parentWidget())
1191 parentWidget()->d_func()->invalidateBuffer(d->effectiveRectFor(geometry()));
1192 if (!internalWinId())
1193 qt_mac_updateParentUnderAlienWidget(this);
1194 d->deactivateWidgetCleanup();
1195 qt_mac_event_release(this);
1196 if(testAttribute(Qt::WA_WState_Created)) {
1197 setAttribute(Qt::WA_WState_Created, false);
1198 QObjectList chldrn = children();
1199 for(int i = 0; i < chldrn.size(); i++) { // destroy all widget children
1200 QObject *obj = chldrn.at(i);
1201 if(obj->isWidgetType())
1202 static_cast<QWidget*>(obj)->destroy(destroySubWindows, destroySubWindows);
1204 if(mac_mouse_grabber == this)
1206 if(mac_keyboard_grabber == this)
1209 if(testAttribute(Qt::WA_ShowModal)) // just be sure we leave modal
1210 QApplicationPrivate::leaveModal(this);
1211 else if((windowType() == Qt::Popup))
1212 qApp->d_func()->closePopup(this);
1213 if (destroyWindow) {
1214 if(OSViewRef hiview = qt_mac_nativeview_for(this)) {
1215 OSWindowRef window = 0;
1216 NSDrawer *drawer = nil;
1217 if (qt_mac_is_macdrawer(this)) {
1218 drawer = qt_mac_drawer_for(this);
1221 window = qt_mac_window_for(hiview);
1223 // Because of how "destruct" works, we have to do just a normal release for the root_win.
1224 if (window && window == qt_root_win) {
1227 qt_mac_destructView(hiview);
1230 qt_mac_destructDrawer(drawer);
1232 qt_mac_destructWindow(window);
1237 } QT_CATCH (const std::bad_alloc &) {
1238 // swallow - destructors must not throw
1243 void QWidgetPrivate::transferChildren()
1246 if (!q->internalWinId())
1247 return; // Can't add any views anyway
1249 QObjectList chlist = q->children();
1250 for (int i = 0; i < chlist.size(); ++i) {
1251 QObject *obj = chlist.at(i);
1252 if (obj->isWidgetType()) {
1253 QWidget *w = (QWidget *)obj;
1254 if (!w->isWindow()) {
1255 // This seems weird, no need to call it in a loop right?
1256 if (!topData()->caption.isEmpty())
1257 setWindowTitle_helper(extra->topextra->caption);
1258 if (w->internalWinId()) {
1259 // New NSWindows get an extra reference when drops are
1260 // registered (at least in 10.5) which means that we may
1261 // access the window later and get a crash (becasue our
1262 // widget is dead). Work around this be having the drop
1263 // site disabled until it is part of the new hierarchy.
1264 bool oldRegistered = w->testAttribute(Qt::WA_DropSiteRegistered);
1265 w->setAttribute(Qt::WA_DropSiteRegistered, false);
1266 [qt_mac_nativeview_for(w) retain];
1267 [qt_mac_nativeview_for(w) removeFromSuperview];
1268 [qt_mac_nativeview_for(q) addSubview:qt_mac_nativeview_for(w)];
1269 [qt_mac_nativeview_for(w) release];
1270 w->setAttribute(Qt::WA_DropSiteRegistered, oldRegistered);
1277 void QWidgetPrivate::setSubWindowStacking(bool set)
1279 // After hitting too many unforeseen bugs trying to put Qt on top of the cocoa child
1280 // window API, we have decided to revert this behaviour as much as we can. We
1281 // therefore now only allow child windows to exist for children of modal dialogs.
1282 static bool use_behaviour_qt473 = !qgetenv("QT_MAC_USE_CHILDWINDOWS").isEmpty();
1284 // This will set/remove a visual relationship between parent and child on screen.
1285 // The reason for doing this is to ensure that a child always stacks infront of
1286 // its parent. Unfortunatly is turns out that [NSWindow addChildWindow] has
1287 // several unwanted side-effects, one of them being the moving of a child when
1288 // moving the parent, which we choose to accept. A way tougher side-effect is
1289 // that Cocoa will hide the parent if you hide the child. And in the case of
1290 // a tool window, since it will normally hide when you deactivate the
1291 // application, Cocoa will hide the parent upon deactivate as well. The result often
1292 // being no more visible windows on screen. So, to make a long story short, we only
1293 // allow parent-child relationships between windows that both are either a plain window
1299 NSWindow *qwin = [qt_mac_nativeview_for(q) window];
1302 Qt::WindowType qtype = q->windowType();
1303 if (set && !(qtype == Qt::Window || qtype == Qt::Dialog))
1305 if (set && ![qwin isVisible])
1308 if (QWidget *parent = q->parentWidget()) {
1309 if (NSWindow *pwin = [qt_mac_nativeview_for(parent) window]) {
1311 Qt::WindowType ptype = parent->window()->windowType();
1312 if ([pwin isVisible]
1313 && (ptype == Qt::Window || ptype == Qt::Dialog)
1314 && ![qwin parentWindow]
1315 && (use_behaviour_qt473 || parent->windowModality() == Qt::ApplicationModal)) {
1316 NSInteger level = [qwin level];
1317 [pwin addChildWindow:qwin ordered:NSWindowAbove];
1318 if ([qwin level] < level)
1319 [qwin setLevel:level];
1322 [pwin removeChildWindow:qwin];
1327 // Only set-up child windows for q if q is modal:
1328 if (set && !use_behaviour_qt473 && q->windowModality() != Qt::ApplicationModal)
1331 QObjectList widgets = q->children();
1332 for (int i=0; i<widgets.size(); ++i) {
1333 QWidget *child = qobject_cast<QWidget *>(widgets.at(i));
1334 if (child && child->isWindow()) {
1335 if (NSWindow *cwin = [qt_mac_nativeview_for(child) window]) {
1337 Qt::WindowType ctype = child->window()->windowType();
1338 if ([cwin isVisible] && (ctype == Qt::Window || ctype == Qt::Dialog) && ![cwin parentWindow]) {
1339 NSInteger level = [cwin level];
1340 [qwin addChildWindow:cwin ordered:NSWindowAbove];
1341 if ([cwin level] < level)
1342 [cwin setLevel:level];
1345 [qwin removeChildWindow:qt_mac_window_for(child)];
1352 void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
1355 QMacCocoaAutoReleasePool pool;
1356 QTLWExtra *topData = maybeTopData();
1357 bool wasCreated = q->testAttribute(Qt::WA_WState_Created);
1358 bool wasWindow = q->isWindow();
1359 OSViewRef old_id = 0;
1361 if (q->isVisible() && q->parentWidget() && parent != q->parentWidget())
1362 q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(q->geometry()));
1364 // Maintain the glWidgets list on parent change: remove "our" gl widgets
1365 // from the list on the old parent and grandparents.
1366 if (glWidgets.isEmpty() == false) {
1367 QWidget *current = q->parentWidget();
1369 for (QList<QWidgetPrivate::GlWidgetInfo>::const_iterator it = glWidgets.constBegin();
1370 it != glWidgets.constEnd(); ++it)
1371 current->d_func()->glWidgets.removeAll(*it);
1373 if (current->isWindow())
1375 current = current->parentWidget();
1379 bool oldToolbarVisible = false;
1380 NSDrawer *oldDrawer = nil;
1381 NSToolbar *oldToolbar = 0;
1382 if (wasCreated && !(q->windowType() == Qt::Desktop)) {
1383 old_id = qt_mac_nativeview_for(q);
1384 if (qt_mac_is_macdrawer(q)) {
1385 oldDrawer = qt_mac_drawer_for(q);
1388 OSWindowRef oldWindow = qt_mac_window_for(old_id);
1389 oldToolbar = [oldWindow toolbar];
1391 [oldToolbar retain];
1392 oldToolbarVisible = [oldToolbar isVisible];
1393 [oldWindow setToolbar:nil];
1397 QWidget* oldtlw = q->window();
1399 if (q->testAttribute(Qt::WA_DropSiteRegistered))
1400 q->setAttribute(Qt::WA_DropSiteRegistered, false);
1402 //recreate and setup flags
1403 QObjectPrivate::setParent_helper(parent);
1404 bool explicitlyHidden = q->testAttribute(Qt::WA_WState_Hidden) && q->testAttribute(Qt::WA_WState_ExplicitShowHide);
1405 if (wasCreated && !qt_isGenuineQWidget(q))
1408 if (!q->testAttribute(Qt::WA_WState_WindowOpacitySet)) {
1409 q->setWindowOpacity(1.0f);
1410 q->setAttribute(Qt::WA_WState_WindowOpacitySet, false);
1413 setWinId(0); //do after the above because they may want the id
1415 data.window_flags = f;
1416 q->setAttribute(Qt::WA_WState_Created, false);
1417 q->setAttribute(Qt::WA_WState_Visible, false);
1418 q->setAttribute(Qt::WA_WState_Hidden, false);
1419 adjustFlags(data.window_flags, q);
1420 // keep compatibility with previous versions, we need to preserve the created state.
1421 // (but we recreate the winId for the widget being reparented, again for compatibility,
1422 // unless this is an alien widget. )
1423 const bool nonWindowWithCreatedParent = !q->isWindow() && parent->testAttribute(Qt::WA_WState_Created);
1424 const bool nativeWidget = q->internalWinId() != 0;
1425 if (wasCreated || (nativeWidget && nonWindowWithCreatedParent)) {
1427 if (q->isWindow()) {
1428 // Simply transfer our toolbar over. Everything should stay put, unlike in Carbon.
1429 if (oldToolbar && !(f & Qt::FramelessWindowHint)) {
1430 OSWindowRef newWindow = qt_mac_window_for(q);
1431 [newWindow setToolbar:oldToolbar];
1432 [oldToolbar release];
1433 [oldToolbar setVisible:oldToolbarVisible];
1437 if (q->isWindow() || (!parent || parent->isVisible()) || explicitlyHidden)
1438 q->setAttribute(Qt::WA_WState_Hidden);
1439 q->setAttribute(Qt::WA_WState_ExplicitShowHide, explicitlyHidden);
1445 (!topData->caption.isEmpty() || !topData->filePath.isEmpty()))
1446 setWindowTitle_helper(q->windowTitle());
1449 if (q->testAttribute(Qt::WA_AcceptDrops)
1450 || (!q->isWindow() && q->parentWidget()
1451 && q->parentWidget()->testAttribute(Qt::WA_DropSiteRegistered)))
1452 q->setAttribute(Qt::WA_DropSiteRegistered, true);
1455 if (old_id) { //don't need old window anymore
1456 OSWindowRef window = (oldtlw == q) ? qt_mac_window_for(old_id) : 0;
1457 qt_mac_destructView(old_id);
1460 qt_mac_destructDrawer(oldDrawer);
1463 qt_mac_destructWindow(window);
1466 // Maintain the glWidgets list on parent change: add "our" gl widgets
1467 // to the list on the new parent and grandparents.
1468 if (glWidgets.isEmpty() == false) {
1469 QWidget *current = q->parentWidget();
1471 current->d_func()->glWidgets += glWidgets;
1472 if (current->isWindow())
1474 current = current->parentWidget();
1477 invalidateBuffer(q->rect());
1478 qt_event_request_window_change(q);
1481 QPoint QWidget::mapToGlobal(const QPoint &pos) const
1484 if (!internalWinId()) {
1485 QPoint p = pos + data->crect.topLeft();
1486 return isWindow() ? p : parentWidget()->mapToGlobal(p);
1488 QPoint tmp = d->mapToWS(pos);
1489 NSPoint hi_pos = NSMakePoint(tmp.x(), tmp.y());
1490 hi_pos = [qt_mac_nativeview_for(this) convertPoint:hi_pos toView:nil];
1491 NSRect win_rect = [qt_mac_window_for(this) frame];
1492 hi_pos.x += win_rect.origin.x;
1493 hi_pos.y += win_rect.origin.y;
1494 // If we aren't the desktop we need to flip, if you flip the desktop on itself, you get the other problem.
1495 return ((window()->windowFlags() & Qt::Desktop) == Qt::Desktop) ? QPointF(hi_pos.x, hi_pos.y).toPoint()
1496 : flipPoint(hi_pos).toPoint();
1499 QPoint QWidget::mapFromGlobal(const QPoint &pos) const
1502 if (!internalWinId()) {
1503 QPoint p = isWindow() ? pos : parentWidget()->mapFromGlobal(pos);
1504 return p - data->crect.topLeft();
1506 NSRect win_rect = [qt_mac_window_for(this) frame];
1507 // The Window point is in "Cocoa coordinates," but the view is in "Qt coordinates"
1508 // so make sure to keep them in sync.
1509 NSPoint hi_pos = NSMakePoint(pos.x()-win_rect.origin.x,
1510 flipYCoordinate(pos.y())-win_rect.origin.y);
1511 hi_pos = [qt_mac_nativeview_for(this) convertPoint:hi_pos fromView:0];
1512 return d->mapFromWS(QPoint(qRound(hi_pos.x), qRound(hi_pos.y)));
1515 void QWidgetPrivate::updateSystemBackground()
1519 void QWidgetPrivate::setCursor_sys(const QCursor &)
1521 qt_mac_update_cursor();
1524 void QWidgetPrivate::unsetCursor_sys()
1526 qt_mac_update_cursor();
1529 void QWidgetPrivate::setWindowTitle_sys(const QString &caption)
1532 if (q->isWindow()) {
1533 QMacCocoaAutoReleasePool pool;
1534 [qt_mac_window_for(q) setTitle:qt_mac_QStringToNSString(caption)];
1538 void QWidgetPrivate::setWindowModified_sys(bool mod)
1541 if (q->isWindow() && q->testAttribute(Qt::WA_WState_Created)) {
1542 [qt_mac_window_for(q) setDocumentEdited:mod];
1546 void QWidgetPrivate::setWindowFilePath_sys(const QString &filePath)
1549 QMacCocoaAutoReleasePool pool;
1550 QFileInfo fi(filePath);
1551 [qt_mac_window_for(q) setRepresentedFilename:fi.exists() ? qt_mac_QStringToNSString(filePath) : @""];
1554 void QWidgetPrivate::setWindowIcon_sys(bool forceReset)
1558 if (!q->testAttribute(Qt::WA_WState_Created))
1561 QTLWExtra *topData = this->topData();
1562 if (topData->iconPixmap && !forceReset) // already set
1565 QIcon icon = q->windowIcon();
1567 if (!icon.isNull()) {
1568 // now create the extra
1569 if (!topData->iconPixmap) {
1570 pm = new QPixmap(icon.pixmap(QSize(22, 22)));
1571 topData->iconPixmap = pm;
1573 pm = topData->iconPixmap;
1576 if (q->isWindow()) {
1577 QMacCocoaAutoReleasePool pool;
1580 NSButton *iconButton = [qt_mac_window_for(q) standardWindowButton:NSWindowDocumentIconButton];
1581 if (iconButton == nil) {
1582 QCFString string(q->windowTitle());
1583 const NSString *tmpString = reinterpret_cast<const NSString *>((CFStringRef)string);
1584 [qt_mac_window_for(q) setRepresentedURL:[NSURL fileURLWithPath:const_cast<NSString *>(tmpString)]];
1585 iconButton = [qt_mac_window_for(q) standardWindowButton:NSWindowDocumentIconButton];
1587 if (icon.isNull()) {
1588 [iconButton setImage:nil];
1590 QPixmap scaled = pm->scaled(QSize(16,16), Qt::KeepAspectRatio, Qt::SmoothTransformation);
1591 NSImage *image = static_cast<NSImage *>(qt_mac_create_nsimage(scaled));
1592 [iconButton setImage:image];
1598 void QWidgetPrivate::setWindowIconText_sys(const QString &iconText)
1601 if(q->isWindow() && !iconText.isEmpty()) {
1602 QMacCocoaAutoReleasePool pool;
1603 [qt_mac_window_for(q) setMiniwindowTitle:qt_mac_QStringToNSString(iconText)];
1607 void QWidget::grabMouse()
1609 if(isVisible() && !qt_nograb()) {
1610 if(mac_mouse_grabber)
1611 mac_mouse_grabber->releaseMouse();
1612 mac_mouse_grabber=this;
1613 qt_mac_setMouseGrabCursor(true);
1617 #ifndef QT_NO_CURSOR
1618 void QWidget::grabMouse(const QCursor &cursor)
1620 if(isVisible() && !qt_nograb()) {
1621 if(mac_mouse_grabber)
1622 mac_mouse_grabber->releaseMouse();
1623 mac_mouse_grabber=this;
1624 qt_mac_setMouseGrabCursor(true, const_cast<QCursor *>(&cursor));
1629 void QWidget::releaseMouse()
1631 if(!qt_nograb() && mac_mouse_grabber == this) {
1632 mac_mouse_grabber = 0;
1633 qt_mac_setMouseGrabCursor(false);
1637 void QWidget::grabKeyboard()
1640 if(mac_keyboard_grabber)
1641 mac_keyboard_grabber->releaseKeyboard();
1642 mac_keyboard_grabber = this;
1646 void QWidget::releaseKeyboard()
1648 if(!qt_nograb() && mac_keyboard_grabber == this)
1649 mac_keyboard_grabber = 0;
1652 QWidget *QWidget::mouseGrabber()
1654 return mac_mouse_grabber;
1657 QWidget *QWidget::keyboardGrabber()
1659 return mac_keyboard_grabber;
1662 void QWidget::activateWindow()
1664 QWidget *tlw = window();
1665 if(!tlw->isVisible() || !tlw->isWindow() || (tlw->windowType() == Qt::Desktop))
1667 qt_event_remove_activate();
1669 QWidget *fullScreenWidget = tlw;
1670 QWidget *parentW = tlw;
1671 // Find the oldest parent or the parent with fullscreen, whichever comes first.
1673 fullScreenWidget = parentW->window();
1674 if (fullScreenWidget->windowState() & Qt::WindowFullScreen)
1676 parentW = fullScreenWidget->parentWidget();
1679 if (fullScreenWidget->windowType() != Qt::ToolTip) {
1680 qt_mac_set_fullscreen_mode((fullScreenWidget->windowState() & Qt::WindowFullScreen) &&
1681 qApp->desktop()->screenNumber(this) == 0);
1685 OSWindowRef win = qt_mac_window_for(tlw);
1686 QMacCocoaAutoReleasePool pool;
1687 windowActive = [win isKeyWindow];
1688 if ((tlw->windowType() == Qt::Popup)
1689 || (tlw->windowType() == Qt::Tool)
1690 || qt_mac_is_macdrawer(tlw)
1692 [win makeKeyWindow];
1693 } else if(!isMinimized()) {
1694 [win makeKeyAndOrderFront:win];
1698 QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys()
1700 return new QMacWindowSurface(q_func());
1703 void QWidgetPrivate::update_sys(const QRect &r)
1706 if (updateRedirectedToGraphicsProxyWidget(q, r))
1709 macSetNeedsDisplay(r != q->rect() ? r : QRegion());
1712 void QWidgetPrivate::update_sys(const QRegion &rgn)
1715 if (updateRedirectedToGraphicsProxyWidget(q, rgn))
1717 dirtyOnWidget += rgn;
1718 macSetNeedsDisplay(rgn);
1721 bool QWidgetPrivate::isRealWindow() const
1723 return q_func()->isWindow() && !topData()->embedded;
1726 void QWidgetPrivate::show_sys()
1729 if ((q->windowType() == Qt::Desktop)) //desktop is always visible
1732 invalidateBuffer(q->rect());
1733 if (q->testAttribute(Qt::WA_OutsideWSRange))
1735 QMacCocoaAutoReleasePool pool;
1736 q->setAttribute(Qt::WA_Mapped);
1737 if (q->testAttribute(Qt::WA_DontShowOnScreen))
1740 bool realWindow = isRealWindow();
1742 data.fstrut_dirty = true;
1744 bool isCurrentlyMinimized = (q->windowState() & Qt::WindowMinimized);
1746 OSWindowRef window = qt_mac_window_for(q);
1748 // Make sure that we end up sending a repaint event to
1749 // the widget if the window has been visible one before:
1750 [qt_mac_get_contentview_for(window) setNeedsDisplay:YES];
1751 if(qt_mac_is_macsheet(q)) {
1752 qt_event_request_showsheet(q);
1753 } else if(qt_mac_is_macdrawer(q)) {
1754 NSDrawer *drawer = qt_mac_drawer_for(q);
1755 [drawer openOnEdge:[drawer preferredEdge]];
1757 // sync the opacity value back (in case of a fade).
1758 [window setAlphaValue:q->windowOpacity()];
1761 if (QApplicationPrivate::tryModalHelper(q, &top)) {
1762 [window makeKeyAndOrderFront:window];
1763 // If this window is app modal, we need to start spinning
1764 // a modal session for it. Interrupting
1765 // the event dispatcher will make this happend:
1766 if (data.window_modality == Qt::ApplicationModal)
1767 QEventDispatcherMac::instance()->interrupt();
1769 // The window is modally shaddowed, so we need to make
1770 // sure that we don't pop in front of the modal window:
1771 [window orderFront:window];
1772 if (!top->testAttribute(Qt::WA_DontShowOnScreen)) {
1773 if (NSWindow *modalWin = qt_mac_window_for(top))
1774 [modalWin orderFront:window];
1777 setSubWindowStacking(true);
1778 qt_mac_update_cursor();
1779 if (q->windowType() == Qt::Popup) {
1781 if (q->focusWidget())
1782 q->focusWidget()->d_func()->setFocus_sys();
1786 toggleDrawers(true);
1788 if (isCurrentlyMinimized) { //show in collapsed state
1789 [window miniaturize:window];
1790 } else if (!q->testAttribute(Qt::WA_ShowWithoutActivating)) {
1792 } else if(topData()->embedded || !q->parentWidget() || q->parentWidget()->isVisible()) {
1793 if (NSView *view = qt_mac_nativeview_for(q)) {
1794 // INVARIANT: q is native. Just show the view:
1795 [view setHidden:NO];
1797 // INVARIANT: q is alien. Update q instead:
1802 if ([NSApp isActive] && !qt_button_down && !QWidget::mouseGrabber()){
1803 // Update enter/leave immidiatly, don't wait for a move event. But only
1804 // if no grab exists (even if the grab points to this widget, it seems, ref X11)
1805 QPoint qlocal, qglobal;
1806 QWidget *widgetUnderMouse = 0;
1807 qt_mac_getTargetForMouseEvent(0, QEvent::Enter, qlocal, qglobal, 0, &widgetUnderMouse);
1808 QApplicationPrivate::dispatchEnterLeave(widgetUnderMouse, qt_last_mouse_receiver);
1809 qt_last_mouse_receiver = widgetUnderMouse;
1810 qt_last_native_mouse_receiver = widgetUnderMouse ?
1811 (widgetUnderMouse->internalWinId() ? widgetUnderMouse : widgetUnderMouse->nativeParentWidget()) : 0;
1814 topLevelAt_cache = 0;
1815 qt_event_request_window_change(q);
1818 QPoint qt_mac_nativeMapFromParent(const QWidget *child, const QPoint &pt)
1820 NSPoint nativePoint = [qt_mac_nativeview_for(child) convertPoint:NSMakePoint(pt.x(), pt.y()) fromView:qt_mac_nativeview_for(child->parentWidget())];
1821 return QPoint(nativePoint.x, nativePoint.y);
1825 void QWidgetPrivate::hide_sys()
1828 if((q->windowType() == Qt::Desktop)) //you can't hide the desktop!
1830 QMacCocoaAutoReleasePool pool;
1832 setSubWindowStacking(false);
1833 OSWindowRef window = qt_mac_window_for(q);
1834 if(qt_mac_is_macsheet(q)) {
1835 [NSApp endSheet:window];
1836 [window orderOut:window];
1837 } else if(qt_mac_is_macdrawer(q)) {
1838 [qt_mac_drawer_for(q) close];
1840 [window orderOut:window];
1841 // Unfortunately it is not as easy as just hiding the window, we need
1842 // to find out if we were in full screen mode. If we were and this is
1843 // the last window in full screen mode then we need to unset the full screen
1844 // mode. If this is not the last visible window in full screen mode then we
1845 // don't change the full screen mode.
1846 if(q->isFullScreen())
1848 bool keepFullScreen = false;
1849 QWidgetList windowList = qApp->topLevelWidgets();
1850 int windowCount = windowList.count();
1851 for(int i = 0; i < windowCount; i++)
1853 QWidget *w = windowList[i];
1854 // If it is the same window, we don't need to check :-)
1857 // If they are not visible or if they are minimized then
1858 // we just ignore them.
1859 if(!w->isVisible() || w->isMinimized())
1861 // Is it full screen?
1862 // Notice that if there is one window in full screen mode then we
1863 // cannot switch the full screen mode off, therefore we just abort.
1864 if(w->isFullScreen()) {
1865 keepFullScreen = true;
1869 // No windows in full screen mode, so let just unset that flag.
1871 qt_mac_set_fullscreen_mode(false);
1873 toggleDrawers(false);
1874 qt_mac_update_cursor();
1877 invalidateBuffer(q->rect());
1878 if (NSView *view = qt_mac_nativeview_for(q)) {
1879 // INVARIANT: q is native. Just hide the view:
1880 [view setHidden:YES];
1882 // INVARIANT: q is alien. Repaint where q is placed instead:
1883 qt_mac_updateParentUnderAlienWidget(q);
1887 if ([NSApp isActive] && !qt_button_down && !QWidget::mouseGrabber()){
1888 // Update enter/leave immidiatly, don't wait for a move event. But only
1889 // if no grab exists (even if the grab points to this widget, it seems, ref X11)
1890 QPoint qlocal, qglobal;
1891 QWidget *widgetUnderMouse = 0;
1892 qt_mac_getTargetForMouseEvent(0, QEvent::Leave, qlocal, qglobal, 0, &widgetUnderMouse);
1893 QApplicationPrivate::dispatchEnterLeave(widgetUnderMouse, qt_last_native_mouse_receiver);
1894 qt_last_mouse_receiver = widgetUnderMouse;
1895 qt_last_native_mouse_receiver = widgetUnderMouse ?
1896 (widgetUnderMouse->internalWinId() ? widgetUnderMouse : widgetUnderMouse->nativeParentWidget()) : 0;
1899 topLevelAt_cache = 0;
1900 qt_event_request_window_change(q);
1901 deactivateWidgetCleanup();
1902 qt_mac_event_release(q);
1905 void QWidget::setWindowState(Qt::WindowStates newstate)
1908 bool needShow = false;
1909 Qt::WindowStates oldstate = windowState();
1910 if (oldstate == newstate)
1913 QMacCocoaAutoReleasePool pool;
1914 bool needSendStateChange = true;
1916 if((oldstate & Qt::WindowFullScreen) != (newstate & Qt::WindowFullScreen)) {
1917 if(newstate & Qt::WindowFullScreen) {
1918 if(QTLWExtra *tlextra = d->topData()) {
1919 if(tlextra->normalGeometry.width() < 0) {
1920 if(!testAttribute(Qt::WA_Resized))
1922 tlextra->normalGeometry = geometry();
1924 tlextra->savedFlags = windowFlags();
1926 needShow = isVisible();
1927 const QRect fullscreen(qApp->desktop()->screenGeometry(qApp->desktop()->screenNumber(this)));
1928 setParent(parentWidget(), Qt::Window | Qt::FramelessWindowHint | (windowFlags() & 0xffff0000)); //save
1929 setGeometry(fullscreen);
1930 if(!qApp->desktop()->screenNumber(this))
1931 qt_mac_set_fullscreen_mode(true);
1933 needShow = isVisible();
1934 if(!qApp->desktop()->screenNumber(this))
1935 qt_mac_set_fullscreen_mode(false);
1936 setParent(parentWidget(), d->topData()->savedFlags);
1937 setGeometry(d->topData()->normalGeometry);
1938 d->topData()->normalGeometry.setRect(0, 0, -1, -1);
1944 OSWindowRef window = qt_mac_window_for(this);
1945 if((oldstate & Qt::WindowMinimized) != (newstate & Qt::WindowMinimized)) {
1946 if (newstate & Qt::WindowMinimized) {
1947 [window miniaturize:window];
1949 [window deminiaturize:window];
1951 needSendStateChange = oldstate == windowState(); // Collapse didn't change our flags.
1954 if((newstate & Qt::WindowMaximized) && !((newstate & Qt::WindowFullScreen))) {
1955 if(QTLWExtra *tlextra = d->topData()) {
1956 if(tlextra->normalGeometry.width() < 0) {
1957 if(!testAttribute(Qt::WA_Resized))
1959 tlextra->normalGeometry = geometry();
1962 } else if(!(newstate & Qt::WindowFullScreen)) {
1963 // d->topData()->normalGeometry = QRect(0, 0, -1, -1);
1966 #ifdef DEBUG_WINDOW_STATE
1967 #define WSTATE(x) qDebug("%s -- %s --> %s", #x, (oldstate & x) ? "true" : "false", (newstate & x) ? "true" : "false")
1968 WSTATE(Qt::WindowMinimized);
1969 WSTATE(Qt::WindowMaximized);
1970 WSTATE(Qt::WindowFullScreen);
1973 if(!(newstate & (Qt::WindowMinimized|Qt::WindowFullScreen)) &&
1974 ((oldstate & Qt::WindowFullScreen) || (oldstate & Qt::WindowMinimized) ||
1975 (oldstate & Qt::WindowMaximized) != (newstate & Qt::WindowMaximized))) {
1976 if(newstate & Qt::WindowMaximized) {
1977 data->fstrut_dirty = true;
1978 NSToolbar *toolbarRef = [window toolbar];
1979 if (toolbarRef && !isVisible() && ![toolbarRef isVisible]) {
1980 // HIToolbar, needs to be shown so that it's in the structure window
1981 // Typically this is part of a main window and will get shown
1982 // during the show, but it's will make the maximize all wrong.
1983 // ### Not sure this is right for NSToolbar...
1984 [toolbarRef setVisible:true];
1985 // ShowHideWindowToolbar(window, true, false);
1986 d->updateFrameStrut(); // In theory the dirty would work, but it's optimized out if the window is not visible :(
1988 // Everything should be handled by Cocoa.
1989 [window zoom:window];
1990 needSendStateChange = oldstate == windowState(); // Zoom didn't change flags.
1991 } else if(oldstate & Qt::WindowMaximized && !(oldstate & Qt::WindowFullScreen)) {
1992 [window zoom:window];
1993 if(QTLWExtra *tlextra = d->topData()) {
1994 setGeometry(tlextra->normalGeometry);
1995 tlextra->normalGeometry.setRect(0, 0, -1, -1);
2001 data->window_state = newstate;
2006 if(newstate & Qt::WindowActive)
2009 qt_event_request_window_change(this);
2010 if (needSendStateChange) {
2011 QWindowStateChangeEvent e(oldstate);
2012 QApplication::sendEvent(this, &e);
2016 void QWidgetPrivate::setFocus_sys()
2019 if (q->testAttribute(Qt::WA_WState_Created)) {
2020 QMacCocoaAutoReleasePool pool;
2021 NSView *view = qt_mac_nativeview_for(q);
2022 [[view window] makeFirstResponder:view];
2026 NSComparisonResult compareViews2Raise(id view1, id view2, void *context)
2028 id topView = reinterpret_cast<id>(context);
2029 if (view1 == topView)
2030 return NSOrderedDescending;
2031 if (view2 == topView)
2032 return NSOrderedAscending;
2033 return NSOrderedSame;
2036 void QWidgetPrivate::raise_sys()
2039 if((q->windowType() == Qt::Desktop))
2042 QMacCocoaAutoReleasePool pool;
2043 if (isRealWindow()) {
2044 // With the introduction of spaces it is not as simple as just raising the window.
2045 // First we need to check if we are in the right space. If we are, then we just continue
2046 // as usual. The problem comes when we are not in the active space. There are two main cases:
2047 // 1. Our parent was moved to a new space. In this case we want the window to be raised
2048 // in the same space as its parent.
2049 // 2. We don't have a parent. For this case we will just raise the window and let Cocoa
2050 // switch to the corresponding space.
2051 // NOTICE: There are a lot of corner cases here. We are keeping this simple for now, if
2052 // required we will introduce special handling for some of them.
2053 if (!q->testAttribute(Qt::WA_DontShowOnScreen) && q->isVisible()) {
2054 OSWindowRef window = qt_mac_window_for(q);
2055 // isOnActiveSpace is available only from 10.6 onwards, so we need to check if it is
2056 // available before calling it.
2057 if([window respondsToSelector:@selector(isOnActiveSpace)]) {
2058 if(![window performSelector:@selector(isOnActiveSpace)]) {
2059 QWidget *parentWidget = q->parentWidget();
2061 OSWindowRef parentWindow = qt_mac_window_for(parentWidget);
2062 if(parentWindow && [parentWindow respondsToSelector:@selector(isOnActiveSpace)]) {
2063 if ([parentWindow performSelector:@selector(isOnActiveSpace)]) {
2064 // The window was created in a different space. Therefore if we want
2065 // to show it in the current space we need to recreate it in the new
2067 recreateMacWindow();
2068 window = qt_mac_window_for(q);
2074 [window orderFront:window];
2076 if (qt_mac_raise_process) { //we get to be the active process now
2077 ProcessSerialNumber psn;
2078 GetCurrentProcess(&psn);
2079 SetFrontProcessWithOptions(&psn, kSetFrontProcessFrontWindowOnly);
2082 NSView *view = qt_mac_nativeview_for(q);
2083 NSView *parentView = [view superview];
2084 [parentView sortSubviewsUsingFunction:compareViews2Raise context:reinterpret_cast<void *>(view)];
2086 topLevelAt_cache = 0;
2089 NSComparisonResult compareViews2Lower(id view1, id view2, void *context)
2091 id topView = reinterpret_cast<id>(context);
2092 if (view1 == topView)
2093 return NSOrderedAscending;
2094 if (view2 == topView)
2095 return NSOrderedDescending;
2096 return NSOrderedSame;
2099 void QWidgetPrivate::lower_sys()
2102 if((q->windowType() == Qt::Desktop))
2104 if (isRealWindow()) {
2105 OSWindowRef window = qt_mac_window_for(q);
2106 [window orderBack:window];
2108 NSView *view = qt_mac_nativeview_for(q);
2109 NSView *parentView = [view superview];
2110 [parentView sortSubviewsUsingFunction:compareViews2Lower context:reinterpret_cast<void *>(view)];
2112 topLevelAt_cache = 0;
2115 NSComparisonResult compareViews2StackUnder(id view1, id view2, void *context)
2117 const QHash<NSView *, int> &viewOrder = *reinterpret_cast<QHash<NSView *, int> *>(context);
2118 if (viewOrder[view1] < viewOrder[view2])
2119 return NSOrderedAscending;
2120 if (viewOrder[view1] > viewOrder[view2])
2121 return NSOrderedDescending;
2122 return NSOrderedSame;
2125 void QWidgetPrivate::stackUnder_sys(QWidget *w)
2129 if(!w || q->isWindow() || (q->windowType() == Qt::Desktop))
2131 // Do the same trick as lower_sys() and put this widget before the widget passed in.
2132 NSView *myView = qt_mac_nativeview_for(q);
2133 NSView *wView = qt_mac_nativeview_for(w);
2135 QHash<NSView *, int> viewOrder;
2136 NSView *parentView = [myView superview];
2137 NSArray *subviews = [parentView subviews];
2138 NSUInteger index = 1;
2139 // make a hash of view->zorderindex and make sure z-value is always odd,
2140 // so that when we modify the order we create a new (even) z-value which
2141 // will not interfere with others.
2142 for (NSView *subview in subviews) {
2143 viewOrder.insert(subview, index * 2);
2146 viewOrder[myView] = viewOrder[wView] - 1;
2148 [parentView sortSubviewsUsingFunction:compareViews2StackUnder context:reinterpret_cast<void *>(&viewOrder)];
2153 Helper function for non-toplevel widgets. Helps to map Qt's 32bit
2154 coordinate system to OS X's 16bit coordinate system.
2156 Sets the geometry of the widget to data.crect, but clipped to sizes
2157 that OS X can handle. Unmaps widgets that are completely outside the
2160 Maintains data.wrect, which is the geometry of the OS X widget,
2161 measured in this widget's coordinate system.
2163 if the parent is not clipped, parentWRect is empty, otherwise
2164 parentWRect is the geometry of the parent's OS X rect, measured in
2167 void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &oldRect)
2170 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
2172 if (!q->internalWinId() && QApplicationPrivate::graphicsSystem() != 0) {
2173 // We have no view to move, and no paint engine that
2174 // we can update dirty regions on. So just return:
2178 QMacCocoaAutoReleasePool pool;
2181 There are up to four different coordinate systems here:
2182 Qt coordinate system for this widget.
2183 X coordinate system for this widget (relative to wrect).
2184 Qt coordinate system for parent
2185 X coordinate system for parent (relative to parent's wrect).
2188 // wrect is the same as crect, except that it is
2189 // clipped to fit inside parent (and screen):
2192 // wrectInParentCoordSys will be the same as wrect, except that it is
2193 // originated in q's parent rather than q itself. It starts out in
2194 // parent's Qt coord system, and ends up in parent's coordinate system:
2195 QRect wrectInParentCoordSys = data.crect;
2197 // If q's parent has been clipped, parentWRect will
2198 // be filled with the parents clipped crect:
2201 // Embedded have different meaning on each platform, and on
2202 // Mac, it means that q is a QMacNativeWidget.
2203 bool isEmbeddedWindow = (q->isWindow() && topData()->embedded);
2204 NSView *nsview = qt_mac_nativeview_for(q);
2205 if (!isEmbeddedWindow) {
2206 parentWRect = q->parentWidget()->data->wrect;
2208 // INVARIANT: q's parent view is not owned by Qt. So we need to
2209 // do some extra calls to get the clipped rect of the parent view:
2210 NSView *parentView = [qt_mac_nativeview_for(q) superview];
2212 NSRect tmpRect = [parentView frame];
2213 parentWRect = QRect(tmpRect.origin.x, tmpRect.origin.y,
2214 tmpRect.size.width, tmpRect.size.height);
2216 const QRect wrectRange(-WRECT_MAX,-WRECT_MAX, 2*WRECT_MAX, 2*WRECT_MAX);
2217 parentWRect = wrectRange;
2221 if (parentWRect.isValid()) {
2222 // INVARIANT: q's parent has been clipped.
2223 // So we fit our own wrects inside it:
2224 if (!parentWRect.contains(wrectInParentCoordSys) && !isEmbeddedWindow) {
2225 wrectInParentCoordSys &= parentWRect;
2226 wrect = wrectInParentCoordSys;
2227 // Make sure wrect is originated in q's coordinate system:
2228 wrect.translate(-data.crect.topLeft());
2230 // // Make sure wrectInParentCoordSys originated in q's parent coordinate system:
2231 wrectInParentCoordSys.translate(-parentWRect.topLeft());
2233 // INVARIANT: we dont know yet the clipping rect of q's parent.
2234 // So we may or may not have to adjust our wrects:
2236 if (data.wrect.isValid() && QRect(QPoint(),data.crect.size()).contains(data.wrect)) {
2237 // This is where the main optimization is: we have an old wrect from an earlier
2238 // setGeometry call, and the new crect is smaller than it. If the final wrect is
2239 // also inside the old wrect, we can just move q and its children to the new
2240 // location without any clipping:
2242 // vrect will be the part of q that's will be visible inside
2243 // q's parent. If it inside the old wrect, then we can just move:
2244 QRect vrect = wrectInParentCoordSys & q->parentWidget()->rect();
2245 vrect.translate(-data.crect.topLeft());
2247 if (data.wrect.contains(vrect)) {
2248 wrectInParentCoordSys = data.wrect;
2249 wrectInParentCoordSys.translate(data.crect.topLeft());
2251 // INVARIANT: q is native. Set view frame:
2252 NSRect bounds = NSMakeRect(wrectInParentCoordSys.x(), wrectInParentCoordSys.y(),
2253 wrectInParentCoordSys.width(), wrectInParentCoordSys.height());
2254 [nsview setFrame:bounds];
2256 // INVARIANT: q is alien. Repaint wrect instead (includes old and new wrect):
2257 QWidget *parent = q->parentWidget();
2258 QPoint globalPosWRect = parent->mapToGlobal(data.wrect.topLeft());
2260 QWidget *nativeParent = q->nativeParentWidget();
2261 QRect dirtyWRect = QRect(nativeParent->mapFromGlobal(globalPosWRect), data.wrect.size());
2263 nativeParent->update(dirtyWRect);
2265 if (q->testAttribute(Qt::WA_OutsideWSRange)) {
2266 q->setAttribute(Qt::WA_OutsideWSRange, false);
2268 q->setAttribute(Qt::WA_Mapped);
2269 // If q is Alien, the following call does nothing:
2270 [nsview setHidden:NO];
2279 // unmap if we are outside the valid window system coord system
2280 bool outsideRange = !wrectInParentCoordSys.isValid();
2281 bool mapWindow = false;
2282 if (q->testAttribute(Qt::WA_OutsideWSRange) != outsideRange) {
2283 q->setAttribute(Qt::WA_OutsideWSRange, outsideRange);
2285 // If q is Alien, the following call does nothing:
2286 [nsview setHidden:YES];
2287 q->setAttribute(Qt::WA_Mapped, false);
2288 } else if (!q->isHidden()) {
2296 // Store the new clipped rect:
2297 bool jump = (data.wrect != wrect);
2300 // and now recursively for all children...
2301 // ### can be optimized
2302 for (int i = 0; i < children.size(); ++i) {
2303 QObject *object = children.at(i);
2304 if (object->isWidgetType()) {
2305 QWidget *w = static_cast<QWidget *>(object);
2306 if (!w->isWindow() && w->testAttribute(Qt::WA_WState_Created))
2307 w->d_func()->setWSGeometry();
2312 // INVARIANT: q is native. Move the actual NSView:
2313 NSRect bounds = NSMakeRect(
2314 wrectInParentCoordSys.x(), wrectInParentCoordSys.y(),
2315 wrectInParentCoordSys.width(), wrectInParentCoordSys.height());
2316 [nsview setFrame:bounds];
2319 } else if (QApplicationPrivate::graphicsSystem() == 0){
2320 // INVARIANT: q is alien and we use native paint engine.
2321 // Schedule updates where q is moved from and to:
2322 const QWidget *parent = q->parentWidget();
2323 const QPoint globalPosOldWRect = parent->mapToGlobal(oldRect.topLeft());
2324 const QPoint globalPosNewWRect = parent->mapToGlobal(wrectInParentCoordSys.topLeft());
2326 QWidget *nativeParent = q->nativeParentWidget();
2327 const QRegion dirtyOldWRect = QRect(nativeParent->mapFromGlobal(globalPosOldWRect), oldRect.size());
2328 const QRegion dirtyNewWRect = QRect(nativeParent->mapFromGlobal(globalPosNewWRect), wrectInParentCoordSys.size());
2330 const bool sizeUnchanged = oldRect.size() == wrectInParentCoordSys.size();
2331 const bool posUnchanged = oldRect.topLeft() == wrectInParentCoordSys.topLeft();
2333 // Resolve/minimize the region that needs to update:
2334 if (sizeUnchanged && q->testAttribute(Qt::WA_OpaquePaintEvent)) {
2335 // INVARIANT: q is opaque, and is only moved (not resized). So in theory we only
2336 // need to blit pixels, and skip a repaint. But we can only make this work if we
2337 // had access to the backbuffer, so we need to update all:
2338 nativeParent->update(dirtyOldWRect | dirtyNewWRect);
2339 } else if (posUnchanged && q->testAttribute(Qt::WA_StaticContents)) {
2340 // We only need to redraw exposed areas:
2341 nativeParent->update(dirtyNewWRect - dirtyOldWRect);
2343 nativeParent->update(dirtyOldWRect | dirtyNewWRect);
2347 if (mapWindow && !dontShow) {
2348 q->setAttribute(Qt::WA_Mapped);
2349 // If q is Alien, the following call does nothing:
2350 [nsview setHidden:NO];
2354 void QWidgetPrivate::adjustWithinMaxAndMinSize(int &w, int &h)
2356 if (QWExtra *extra = extraData()) {
2357 w = qMin(w, extra->maxw);
2358 h = qMin(h, extra->maxh);
2359 w = qMax(w, extra->minw);
2360 h = qMax(h, extra->minh);
2362 // Deal with size increment
2363 if (QTLWExtra *top = topData()) {
2375 if (isRealWindow()) {
2381 void QWidgetPrivate::applyMaxAndMinSizeOnWindow()
2384 QMacCocoaAutoReleasePool pool;
2386 const float max_f(20000);
2387 #define SF(x) ((x > max_f) ? max_f : x)
2388 NSSize max = NSMakeSize(SF(extra->maxw), SF(extra->maxh));
2389 NSSize min = NSMakeSize(SF(extra->minw), SF(extra->minh));
2391 [qt_mac_window_for(q) setContentMinSize:min];
2392 [qt_mac_window_for(q) setContentMaxSize:max];
2395 void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove)
2398 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
2400 if(q->windowType() == Qt::Desktop)
2403 QMacCocoaAutoReleasePool pool;
2404 bool realWindow = isRealWindow();
2406 if (realWindow && !q->testAttribute(Qt::WA_DontShowOnScreen)){
2407 adjustWithinMaxAndMinSize(w, h);
2408 if (!isMove && !q->testAttribute(Qt::WA_Moved) && !q->isVisible()) {
2409 // INVARIANT: The location of the window has not yet been set. The default will
2410 // instead be to center it on the desktop, or over the parent, if any. Since we now
2411 // resize the window, we need to adjust the top left position to keep the window
2412 // centeralized. And we need to to this now (and before show) in case the positioning
2413 // of other windows (e.g. sub-windows) depend on this position:
2414 if (QWidget *p = q->parentWidget()) {
2415 x = p->geometry().center().x() - (w / 2);
2416 y = p->geometry().center().y() - (h / 2);
2418 QRect availGeo = QApplication::desktop()->availableGeometry(q);
2419 x = availGeo.center().x() - (w / 2);
2420 y = availGeo.center().y() - (h / 2);
2424 QSize olds = q->size();
2425 const bool isResize = (olds != QSize(w, h));
2426 NSWindow *window = qt_mac_window_for(q);
2427 const QRect &fStrut = frameStrut();
2428 const QRect frameRect(QPoint(x - fStrut.left(), y - fStrut.top()),
2429 QSize(fStrut.left() + fStrut.right() + w,
2430 fStrut.top() + fStrut.bottom() + h));
2431 NSRect cocoaFrameRect = NSMakeRect(frameRect.x(), flipYCoordinate(frameRect.bottom() + 1),
2432 frameRect.width(), frameRect.height());
2433 // The setFrame call will trigger a 'windowDidResize' notification for the corresponding
2434 // NSWindow. The pending flag is set, so that the resize event can be send as non-spontaneous.
2436 q->setAttribute(Qt::WA_PendingResizeEvent);
2437 QPoint currTopLeft = data.crect.topLeft();
2438 if (currTopLeft.x() == x && currTopLeft.y() == y
2439 && cocoaFrameRect.size.width != 0
2440 && cocoaFrameRect.size.height != 0) {
2441 [window setFrame:cocoaFrameRect display:realWindow];
2443 // The window is moved and resized (or resized to zero).
2444 // Since Cocoa usually only sends us a resize callback after
2445 // setting a window frame, we issue an explicit move as
2446 // well. To stop Cocoa from optimize away the move (since the move
2447 // would have the same origin as the setFrame call) we shift the
2448 // window back and forth inbetween.
2449 cocoaFrameRect.origin.y += 1;
2450 [window setFrame:cocoaFrameRect display:realWindow];
2451 cocoaFrameRect.origin.y -= 1;
2452 [window setFrameOrigin:cocoaFrameRect.origin];
2455 setGeometry_sys_helper(x, y, w, h, isMove);
2458 topLevelAt_cache = 0;
2461 void QWidgetPrivate::setGeometry_sys_helper(int x, int y, int w, int h, bool isMove)
2464 bool realWindow = isRealWindow();
2466 QPoint oldp = q->pos();
2467 QSize olds = q->size();
2468 // Apply size restrictions, applicable for Windows & Widgets.
2469 if (QWExtra *extra = extraData()) {
2470 w = qBound(extra->minw, w, extra->maxw);
2471 h = qBound(extra->minh, h, extra->maxh);
2473 const bool isResize = (olds != QSize(w, h));
2475 if (!realWindow && !isResize && QPoint(x, y) == oldp)
2479 data.window_state = data.window_state & ~Qt::WindowMaximized;
2481 const bool visible = q->isVisible();
2482 data.crect = QRect(x, y, w, h);
2485 adjustWithinMaxAndMinSize(w, h);
2486 qt_mac_update_sizer(q);
2488 [qt_mac_nativeview_for(q) setFrame:NSMakeRect(0, 0, w, h)];
2490 const QRect oldRect(oldp, olds);
2491 if (!isResize && QApplicationPrivate::graphicsSystem())
2492 moveRect(oldRect, x - oldp.x(), y - oldp.y());
2494 setWSGeometry(false, oldRect);
2496 if (isResize && QApplicationPrivate::graphicsSystem())
2497 invalidateBuffer_resizeHelper(oldp, olds);
2500 if(isMove || isResize) {
2502 if(isMove && q->pos() != oldp)
2503 q->setAttribute(Qt::WA_PendingMoveEvent, true);
2505 q->setAttribute(Qt::WA_PendingResizeEvent, true);
2507 if(isResize) { //send the resize event..
2508 QResizeEvent e(q->size(), olds);
2509 QApplication::sendEvent(q, &e);
2511 if(isMove && q->pos() != oldp) { //send the move event..
2512 QMoveEvent e(q->pos(), oldp);
2513 QApplication::sendEvent(q, &e);
2517 qt_event_request_window_change(q);
2520 void QWidgetPrivate::setConstraints_sys()
2522 updateMaximizeButton_sys();
2523 applyMaxAndMinSizeOnWindow();
2526 void QWidgetPrivate::updateMaximizeButton_sys()
2529 if (q->data->window_flags & Qt::CustomizeWindowHint)
2532 OSWindowRef window = qt_mac_window_for(q);
2533 QTLWExtra * tlwExtra = topData();
2534 QMacCocoaAutoReleasePool pool;
2535 NSButton *maximizeButton = [window standardWindowButton:NSWindowZoomButton];
2536 if (extra->maxw && extra->maxh
2537 && extra->maxw == extra->minw
2538 && extra->maxh == extra->minh) {
2539 // The window has a fixed size, so gray out the maximize button:
2540 if (!tlwExtra->savedWindowAttributesFromMaximized) {
2541 tlwExtra->savedWindowAttributesFromMaximized = (![maximizeButton isHidden] && [maximizeButton isEnabled]);
2543 [maximizeButton setEnabled:NO];
2547 if (tlwExtra->savedWindowAttributesFromMaximized) {
2548 [maximizeButton setEnabled:YES];
2549 tlwExtra->savedWindowAttributesFromMaximized = 0;
2556 void QWidgetPrivate::scroll_sys(int dx, int dy)
2558 if (QApplicationPrivate::graphicsSystem() && !paintOnScreen()) {
2559 // INVARIANT: Alien paint engine
2560 scrollChildren(dx, dy);
2561 scrollRect(q_func()->rect(), dx, dy);
2563 scroll_sys(dx, dy, QRect());
2567 void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &qscrollRect)
2569 if (QMacScrollOptimization::delayScroll(this, dx, dy, qscrollRect))
2573 if (QApplicationPrivate::graphicsSystem() && !paintOnScreen()) {
2574 // INVARIANT: Alien paint engine
2575 scrollRect(qscrollRect, dx, dy);
2579 static int accelEnv = -1;
2580 if (accelEnv == -1) {
2581 accelEnv = qgetenv("QT_NO_FAST_SCROLL").toInt() == 0;
2584 // Scroll the whole widget if qscrollRect is not valid:
2585 QRect validScrollRect = qscrollRect.isValid() ? qscrollRect : q->rect();
2586 validScrollRect &= clipRect();
2588 // If q is overlapped by other widgets, we cannot just blit pixels since
2589 // this will move overlapping widgets as well. In case we just update:
2590 const bool overlapped = isOverlapped(validScrollRect.translated(data.crect.topLeft()));
2591 const bool accelerateScroll = accelEnv && isOpaque && !overlapped;
2592 const bool isAlien = (q->internalWinId() == 0);
2593 const QPoint scrollDelta(dx, dy);
2595 // If qscrollRect is valid, we are _not_ supposed to scroll q's children (as documented).
2596 // But we do scroll children (and the whole of q) if qscrollRect is invalid. This case is
2597 // documented as undefined, but we exploit it to help factor our code into one function.
2598 const bool scrollChildren = !qscrollRect.isValid();
2600 if (!q->updatesEnabled()) {
2601 // We are told not to update anything on q at this point. So unless
2602 // we are supposed to scroll children, we bail out early:
2603 if (!scrollChildren || q->children().isEmpty())
2607 if (!accelerateScroll) {
2609 QRegion region(validScrollRect);
2610 subtractOpaqueSiblings(region);
2613 update_sys(qscrollRect);
2618 QMacCocoaAutoReleasePool pool;
2620 // First move all native children. Alien children will indirectly be
2621 // moved when the parent is scrolled. All directly or indirectly moved
2622 // children will receive a move event before the function call returns.
2623 QWidgetList movedChildren;
2624 if (scrollChildren) {
2625 QObjectList children = q->children();
2627 for (int i=0; i<children.size(); i++) {
2628 QObject *obj = children.at(i);
2629 if (QWidget *w = qobject_cast<QWidget*>(obj)) {
2630 if (!w->isWindow()) {
2631 w->data->crect = QRect(w->pos() + scrollDelta, w->size());
2632 if (NSView *view = qt_mac_nativeview_for(w)) {
2633 // INVARIANT: w is not alien
2634 [view setFrame:NSMakeRect(
2635 w->data->crect.x(), w->data->crect.y(),
2636 w->data->crect.width(), w->data->crect.height())];
2638 movedChildren.append(w);
2644 if (q->testAttribute(Qt::WA_WState_Created) && q->isVisible()) {
2645 // Scroll q itself according to the qscrollRect, and
2646 // call update on any exposed areas so that they get redrawn:
2649 QWidget *nativeWidget = isAlien ? q->nativeParentWidget() : q;
2652 OSViewRef view = qt_mac_nativeview_for(nativeWidget);
2656 // Calculate the rectangles that needs to be redrawn
2657 // after the scroll. This will be source rect minus destination rect:
2660 deltaXRect.setY(validScrollRect.y());
2661 deltaXRect.setHeight(validScrollRect.height());
2663 deltaXRect.setX(validScrollRect.x());
2664 deltaXRect.setWidth(dx);
2666 deltaXRect.setX(validScrollRect.x() + validScrollRect.width() + dx);
2667 deltaXRect.setWidth(-dx);
2673 deltaYRect.setX(validScrollRect.x());
2674 deltaYRect.setWidth(validScrollRect.width());
2676 deltaYRect.setY(validScrollRect.y());
2677 deltaYRect.setHeight(dy);
2679 deltaYRect.setY(validScrollRect.y() + validScrollRect.height() + dy);
2680 deltaYRect.setHeight(-dy);
2685 // Adjust the scroll rect to the location as seen from the native parent:
2686 QPoint scrollTopLeftInsideNative = nativeWidget->mapFromGlobal(q->mapToGlobal(validScrollRect.topLeft()));
2687 validScrollRect.moveTo(scrollTopLeftInsideNative);
2690 // Make the pixel copy rect within the validScrollRect bounds:
2691 NSRect nsscrollRect = NSMakeRect(
2692 validScrollRect.x() + (dx < 0 ? -dx : 0),
2693 validScrollRect.y() + (dy < 0 ? -dy : 0),
2694 validScrollRect.width() + (dx > 0 ? -dx : 0),
2695 validScrollRect.height() + (dy > 0 ? -dy : 0));
2697 NSSize deltaSize = NSMakeSize(dx, dy);
2698 [view scrollRect:nsscrollRect by:deltaSize];
2700 // Some areas inside the scroll rect might have been marked as dirty from before, which
2701 // means that they are scheduled to be redrawn. But as we now scroll, those dirty rects
2702 // should also move along to ensure that q receives repaints on the correct places.
2703 // Since some of the dirty rects might lay outside, or only intersect with, the scroll
2704 // rect, the old calls to setNeedsDisplay still makes sense.
2705 // NB: Using [view translateRectsNeedingDisplayInRect:nsscrollRect by:deltaSize] have
2706 // so far not been proven fruitful to solve this problem.
2707 const QVector<QRect> &dirtyRectsToScroll = dirtyOnWidget.rects();
2708 for (int i=0; i<dirtyRectsToScroll.size(); ++i) {
2709 QRect qdirtyRect = dirtyRectsToScroll[i];
2710 qdirtyRect.translate(dx, dy);
2711 update_sys(qdirtyRect);
2714 // Update newly exposed areas. This will generate new dirty areas on
2715 // q, and therefore, we do it after updating the old dirty rects above:
2717 update_sys(deltaXRect);
2719 update_sys(deltaYRect);
2723 for (int i=0; i<movedChildren.size(); i++) {
2724 QWidget *w = movedChildren.at(i);
2725 QMoveEvent e(w->pos(), w->pos() - scrollDelta);
2726 QApplication::sendEvent(w, &e);
2730 int QWidget::metric(PaintDeviceMetric m) const
2734 return qRound(metric(PdmHeight) * 25.4 / qreal(metric(PdmDpiY)));
2736 return qRound(metric(PdmWidth) * 25.4 / qreal(metric(PdmDpiX)));
2740 return data->crect.width();
2742 return data->crect.height();
2748 case PdmPhysicalDpiX: {
2750 if (d->extra && d->extra->customDpiX)
2751 return d->extra->customDpiX;
2753 return static_cast<QWidget *>(d->parent)->metric(m);
2754 extern float qt_mac_defaultDpi_x(); //qpaintdevice_mac.cpp
2755 return int(qt_mac_defaultDpi_x()); }
2757 case PdmPhysicalDpiY: {
2759 if (d->extra && d->extra->customDpiY)
2760 return d->extra->customDpiY;
2762 return static_cast<QWidget *>(d->parent)->metric(m);
2763 extern float qt_mac_defaultDpi_y(); //qpaintdevice_mac.cpp
2764 return int(qt_mac_defaultDpi_y()); }
2765 default: //leave this so the compiler complains when new ones are added
2766 qWarning("QWidget::metric: Unhandled parameter %d", m);
2767 return QPaintDevice::metric(m);
2772 void QWidgetPrivate::createSysExtra()
2774 extra->imageMask = 0;
2777 void QWidgetPrivate::deleteSysExtra()
2779 if (extra->imageMask)
2780 CFRelease(extra->imageMask);
2783 void QWidgetPrivate::createTLSysExtra()
2785 extra->topextra->resizer = 0;
2786 extra->topextra->isSetGeometry = 0;
2787 extra->topextra->isMove = 0;
2788 extra->topextra->wattr = 0;
2789 extra->topextra->wclass = 0;
2790 extra->topextra->group = 0;
2791 extra->topextra->windowIcon = 0;
2792 extra->topextra->savedWindowAttributesFromMaximized = 0;
2795 void QWidgetPrivate::deleteTLSysExtra()
2799 void QWidgetPrivate::updateFrameStrut()
2803 QWidgetPrivate *that = const_cast<QWidgetPrivate*>(this);
2805 that->data.fstrut_dirty = false;
2806 QTLWExtra *top = that->topData();
2808 // 1 Get the window frame
2809 OSWindowRef oswnd = qt_mac_window_for(q);
2810 NSRect frameW = [oswnd frame];
2811 // 2 Get the content frame - so now
2812 NSRect frameC = [oswnd contentRectForFrameRect:frameW];
2813 top->frameStrut.setCoords(frameC.origin.x - frameW.origin.x,
2814 (frameW.origin.y + frameW.size.height) - (frameC.origin.y + frameC.size.height),
2815 (frameW.origin.x + frameW.size.width) - (frameC.origin.x + frameC.size.width),
2816 frameC.origin.y - frameW.origin.y);
2819 void QWidgetPrivate::registerDropSite(bool on)
2822 if (!q->testAttribute(Qt::WA_WState_Created))
2824 NSWindow *win = qt_mac_window_for(q);
2826 if ([win isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaWindow) class]])
2827 [static_cast<QT_MANGLE_NAMESPACE(QCocoaWindow) *>(win) registerDragTypes];
2828 else if ([win isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaPanel) class]])
2829 [static_cast<QT_MANGLE_NAMESPACE(QCocoaPanel) *>(win) registerDragTypes];
2833 void QWidgetPrivate::registerTouchWindow(bool enable)
2836 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2837 if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_6)
2841 if (enable == touchEventsEnabled)
2844 QT_MANGLE_NAMESPACE(QCocoaView) *view = static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(qt_mac_effectiveview_for(q));
2849 ++view->alienTouchCount;
2850 if (view->alienTouchCount == 1) {
2851 touchEventsEnabled = true;
2852 [view setAcceptsTouchEvents:YES];
2855 --view->alienTouchCount;
2856 if (view->alienTouchCount == 0) {
2857 touchEventsEnabled = false;
2858 [view setAcceptsTouchEvents:NO];
2864 void QWidgetPrivate::setMask_sys(const QRegion ®ion)
2869 if (!q->internalWinId())
2872 if (extra->mask.isEmpty()) {
2873 extra->maskBits = QImage();
2874 finishCocoaMaskSetup();
2879 topLevelAt_cache = 0;
2882 void QWidgetPrivate::setWindowOpacity_sys(qreal level)
2889 level = qBound(0.0, level, 1.0);
2890 topData()->opacity = (uchar)(level * 255);
2891 if (!q->testAttribute(Qt::WA_WState_Created))
2894 OSWindowRef oswindow = qt_mac_window_for(q);
2895 [oswindow setAlphaValue:level];
2898 void QWidgetPrivate::syncCocoaMask()
2901 if (!q->testAttribute(Qt::WA_WState_Created) || !extra)
2904 if (extra->hasMask) {
2905 if(extra->maskBits.size() != q->size()) {
2906 extra->maskBits = QImage(q->size(), QImage::Format_Mono);
2908 extra->maskBits.fill(QColor(Qt::color1).rgba());
2909 extra->maskBits.setNumColors(2);
2910 extra->maskBits.setColor(0, QColor(Qt::color0).rgba());
2911 extra->maskBits.setColor(1, QColor(Qt::color1).rgba());
2912 QPainter painter(&extra->maskBits);
2913 painter.setBrush(Qt::color1);
2914 painter.setPen(Qt::NoPen);
2915 painter.drawRects(extra->mask.rects());
2917 finishCocoaMaskSetup();
2921 void QWidgetPrivate::finishCocoaMaskSetup()
2925 if (!q->testAttribute(Qt::WA_WState_Created) || !extra)
2928 // Technically this is too late to release, because the data behind the image
2929 // has already been released. But it's more tidy to do it here.
2930 // If you are seeing a crash, consider doing a CFRelease before changing extra->maskBits.
2931 if (extra->imageMask) {
2932 CFRelease(extra->imageMask);
2933 extra->imageMask = 0;
2936 if (!extra->maskBits.isNull()) {
2937 QCFType<CGDataProviderRef> dataProvider = CGDataProviderCreateWithData(0,
2938 extra->maskBits.bits(),
2939 extra->maskBits.numBytes(),
2940 0); // shouldn't need to release.
2941 CGFloat decode[2] = {1, 0};
2942 extra->imageMask = CGImageMaskCreate(extra->maskBits.width(), extra->maskBits.height(),
2943 1, 1, extra->maskBits.bytesPerLine(), dataProvider,
2946 if (q->isWindow()) {
2947 NSWindow *window = qt_mac_window_for(q);
2948 [window setOpaque:(extra->imageMask == 0)];
2949 [window invalidateShadow];
2951 macSetNeedsDisplay(QRegion());
2954 struct QPaintEngineCleanupHandler
2956 inline QPaintEngineCleanupHandler() : engine(0) {}
2957 inline ~QPaintEngineCleanupHandler() { delete engine; }
2958 QPaintEngine *engine;
2961 Q_GLOBAL_STATIC(QPaintEngineCleanupHandler, engineHandler)
2963 QPaintEngine *QWidget::paintEngine() const
2965 QPaintEngine *&pe = engineHandler()->engine;
2967 pe = new QCoreGraphicsPaintEngine();
2968 if (pe->isActive()) {
2969 QPaintEngine *engine = new QCoreGraphicsPaintEngine();
2970 engine->setAutoDestruct(true);
2976 void QWidgetPrivate::setModal_sys()
2979 if (!q->testAttribute(Qt::WA_WState_Created) || !q->isWindow())
2981 const QWidget * const windowParent = q->window()->parentWidget();
2982 const QWidget * const primaryWindow = windowParent ? windowParent->window() : 0;
2983 OSWindowRef windowRef = qt_mac_window_for(q);
2985 QMacCocoaAutoReleasePool pool;
2986 bool alreadySheet = [windowRef styleMask] & NSDocModalWindowMask;
2988 if (windowParent && q->windowModality() == Qt::WindowModal){
2989 // INVARIANT: Window should be window-modal (which implies a sheet).
2990 if (!alreadySheet) {
2991 // NB: the following call will call setModal_sys recursivly:
2992 recreateMacWindow();
2993 windowRef = qt_mac_window_for(q);
2995 if ([windowRef isKindOfClass:[NSPanel class]]){
2996 // If the primary window of the sheet parent is a child of a modal dialog,
2997 // the sheet parent should not be modally shaddowed.
2998 // This goes for the sheet as well:
2999 OSWindowRef ref = primaryWindow ? qt_mac_window_for(primaryWindow) : 0;
3000 bool isDialog = ref ? [ref isKindOfClass:[NSPanel class]] : false;
3001 bool worksWhenModal = isDialog ? [static_cast<NSPanel *>(ref) worksWhenModal] : false;
3003 [static_cast<NSPanel *>(windowRef) setWorksWhenModal:YES];
3006 // INVARIANT: Window shold _not_ be window-modal (and as such, not a sheet).
3008 // NB: the following call will call setModal_sys recursivly:
3009 recreateMacWindow();
3010 windowRef = qt_mac_window_for(q);
3012 if (q->windowModality() == Qt::NonModal
3013 && primaryWindow && primaryWindow->windowModality() == Qt::ApplicationModal) {
3014 // INVARIANT: Our window has a parent that is application modal.
3015 // This means that q is supposed to be on top of this window and
3016 // not be modally shaddowed:
3017 if ([windowRef isKindOfClass:[NSPanel class]])
3018 [static_cast<NSPanel *>(windowRef) setWorksWhenModal:YES];
3024 void QWidgetPrivate::macUpdateHideOnSuspend()
3027 if (!q->testAttribute(Qt::WA_WState_Created) || !q->isWindow() || q->windowType() != Qt::Tool)
3029 if(q->testAttribute(Qt::WA_MacAlwaysShowToolWindow))
3030 [qt_mac_window_for(q) setHidesOnDeactivate:NO];
3032 [qt_mac_window_for(q) setHidesOnDeactivate:YES];
3035 void QWidgetPrivate::macUpdateOpaqueSizeGrip()
3039 if (!q->testAttribute(Qt::WA_WState_Created) || !q->isWindow())
3044 void QWidgetPrivate::macUpdateSizeAttribute()
3047 QEvent event(QEvent::MacSizeChange);
3048 QApplication::sendEvent(q, &event);
3049 for (int i = 0; i < children.size(); ++i) {
3050 QWidget *w = qobject_cast<QWidget *>(children.at(i));
3051 if (w && (!w->isWindow() || w->testAttribute(Qt::WA_WindowPropagation))
3052 && !q->testAttribute(Qt::WA_MacMiniSize) // no attribute set? inherit from parent
3053 && !w->testAttribute(Qt::WA_MacSmallSize)
3054 && !w->testAttribute(Qt::WA_MacNormalSize))
3055 w->d_func()->macUpdateSizeAttribute();
3060 void QWidgetPrivate::macUpdateIgnoreMouseEvents()
3064 void QWidgetPrivate::macUpdateMetalAttribute()
3067 bool realWindow = isRealWindow();
3068 if (!q->testAttribute(Qt::WA_WState_Created) || !realWindow)
3072 // Cocoa doesn't let us change the style mask once it's been changed
3073 // So, that means we need to recreate the window.
3074 OSWindowRef cocoaWindow = qt_mac_window_for(q);
3075 if ([cocoaWindow styleMask] & NSTexturedBackgroundWindowMask)
3077 recreateMacWindow();
3081 void QWidgetPrivate::setEnabled_helper_sys(bool enable)
3084 NSView *view = qt_mac_nativeview_for(q);
3085 if ([view isKindOfClass:[NSControl class]])
3086 [static_cast<NSControl *>(view) setEnabled:enable];