/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ /**************************************************************************** ** ** Copyright (c) 2007-2008, Apple, Inc. ** ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are met: ** ** * Redistributions of source code must retain the above copyright notice, ** this list of conditions and the following disclaimer. ** ** * Redistributions in binary form must reproduce the above copyright notice, ** this list of conditions and the following disclaimer in the documentation ** and/or other materials provided with the distribution. ** ** * Neither the name of Apple, Inc. nor the names of its contributors ** may be used to endorse or promote products derived from this software ** without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR ** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ** ****************************************************************************/ #include #include #include "qapplication.h" #include "qapplication_p.h" #include "qbitmap.h" #include "qcursor.h" #include "qdesktopwidget.h" #include "qevent.h" #include "qfileinfo.h" #include "qimage.h" #include "qlayout.h" #include "qmenubar.h" #include #include #include #include "qpainter.h" #include "qstyle.h" #include "qtimer.h" #include "qfocusframe.h" #include "qdebug.h" #include #include #include #include #include #include #include #include #include #include #include "qwidget_p.h" #include "qevent_p.h" #include "qdnd_p.h" #include #include "qmainwindow.h" QT_BEGIN_NAMESPACE #define XCOORD_MAX 16383 #define WRECT_MAX 8191 #ifndef QT_MAC_USE_COCOA extern "C" { extern OSStatus _HIViewScrollRectWithOptions(HIViewRef, const HIRect *, CGFloat, CGFloat, OptionBits) __attribute__ ((weak)); } #define kHIViewScrollRectAdjustInvalid 1 #define kHIViewScrollRectDontInvalidateRevealedArea 2 #endif /***************************************************************************** QWidget debug facilities *****************************************************************************/ //#define DEBUG_WINDOW_RGNS //#define DEBUG_WINDOW_CREATE //#define DEBUG_WINDOW_STATE //#define DEBUG_WIDGET_PAINT /***************************************************************************** QWidget globals *****************************************************************************/ #ifndef QT_MAC_USE_COCOA typedef QHash WindowGroupHash; Q_GLOBAL_STATIC(WindowGroupHash, qt_mac_window_groups) const UInt32 kWidgetCreatorQt = kEventClassQt; enum { kWidgetPropertyQWidget = 'QWId' //QWidget * }; #endif static bool qt_mac_raise_process = true; static OSWindowRef qt_root_win = 0; QWidget *mac_mouse_grabber = 0; QWidget *mac_keyboard_grabber = 0; #ifndef QT_MAC_USE_COCOA #ifdef QT_NAMESPACE // produce the string "com.trolltech.qt-namespace.widget", where "namespace" is the contents of QT_NAMESPACE. #define SS(x) #x #define S0(x) SS(x) #define S "com.trolltech.qt-" S0(QT_NAMESPACE) ".widget" static CFStringRef kObjectQWidget = CFSTR(S); #undef SS #undef S0 #undef S #else static CFStringRef kObjectQWidget = CFSTR("com.trolltech.qt.widget"); #endif // QT_NAMESPACE #endif // QT_MAC_USE_COCOA /***************************************************************************** Externals *****************************************************************************/ extern QWidget *qt_mac_modal_blocked(QWidget *); //qapplication_mac.mm extern void qt_event_request_activate(QWidget *); //qapplication_mac.mm extern bool qt_event_remove_activate(); //qapplication_mac.mm extern void qt_mac_event_release(QWidget *w); //qapplication_mac.mm extern void qt_event_request_showsheet(QWidget *); //qapplication_mac.mm extern void qt_event_request_window_change(QWidget *); //qapplication_mac.mm extern QPointer qt_mouseover; //qapplication_mac.mm extern IconRef qt_mac_create_iconref(const QPixmap &); //qpixmap_mac.cpp extern void qt_mac_set_cursor(const QCursor *, const QPoint &); //qcursor_mac.mm extern void qt_mac_update_cursor(); //qcursor_mac.mm extern bool qt_nograb(); extern CGImageRef qt_mac_create_cgimage(const QPixmap &, bool); //qpixmap_mac.cpp extern RgnHandle qt_mac_get_rgn(); //qregion_mac.cpp extern QRegion qt_mac_convert_mac_region(RgnHandle rgn); //qregion_mac.cpp /***************************************************************************** QWidget utility functions *****************************************************************************/ void Q_GUI_EXPORT qt_mac_set_raise_process(bool b) { qt_mac_raise_process = b; } static QSize qt_mac_desktopSize() { int w = 0, h = 0; CGDisplayCount cg_count; CGGetActiveDisplayList(0, 0, &cg_count); QVector displays(cg_count); CGGetActiveDisplayList(cg_count, displays.data(), &cg_count); Q_ASSERT(cg_count == (CGDisplayCount)displays.size()); for(int i = 0; i < (int)cg_count; ++i) { CGRect r = CGDisplayBounds(displays.at(i)); w = qMax(w, qRound(r.origin.x + r.size.width)); h = qMax(h, qRound(r.origin.y + r.size.height)); } return QSize(w, h); } #ifdef QT_MAC_USE_COCOA static NSDrawer *qt_mac_drawer_for(const QWidget *widget) { // This only goes one level below the content view so start with the window. // This works fine for straight Qt stuff, but runs into problems if we are // embedding, but if that's the case, they probably want to be using // NSDrawer directly. NSView *widgetView = reinterpret_cast(widget->window()->winId()); NSArray *windows = [NSApp windows]; for (NSWindow *window in windows) { NSArray *drawers = [window drawers]; for (NSDrawer *drawer in drawers) { NSArray *views = [[drawer contentView] subviews]; for (NSView *view in views) { if (view == widgetView) return drawer; } } } return 0; } #endif static void qt_mac_destructView(OSViewRef view) { #ifdef QT_MAC_USE_COCOA [view removeFromSuperview]; [view release]; #else HIViewRemoveFromSuperview(view); CFRelease(view); #endif } static void qt_mac_destructWindow(OSWindowRef window) { #ifdef QT_MAC_USE_COCOA if ([window isVisible] && [window isSheet]){ [NSApp endSheet:window]; [window orderOut:window]; } [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] resignDelegateForWindow:window]; [window release]; #else // Remove property to clean up memory: RemoveWindowProperty(window, kWidgetCreatorQt, kWidgetPropertyQWidget); CFRelease(window); #endif } static void qt_mac_destructDrawer(NSDrawer *drawer) { #ifdef QT_MAC_USE_COCOA [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] resignDelegateForDrawer:drawer]; [drawer release]; #else Q_UNUSED(drawer); #endif } bool qt_mac_can_clickThrough(const QWidget *w) { static int qt_mac_carbon_clickthrough = -1; if (qt_mac_carbon_clickthrough < 0) qt_mac_carbon_clickthrough = !qgetenv("QT_MAC_NO_COCOA_CLICKTHROUGH").isEmpty(); bool ret = !qt_mac_carbon_clickthrough; for ( ; w; w = w->parentWidget()) { if (w->testAttribute(Qt::WA_MacNoClickThrough)) { ret = false; break; } } return ret; } bool qt_mac_is_macsheet(const QWidget *w) { if (!w) return false; Qt::WindowModality modality = w->windowModality(); if (modality == Qt::ApplicationModal) return false; return w->parentWidget() && (modality == Qt::WindowModal || w->windowType() == Qt::Sheet); } bool qt_mac_is_macdrawer(const QWidget *w) { return (w && w->parentWidget() && w->windowType() == Qt::Drawer); } bool qt_mac_insideKeyWindow(const QWidget *w) { #ifdef QT_MAC_USE_COCOA return [[reinterpret_cast(w->winId()) window] isKeyWindow]; #else Q_UNUSED(w); #endif return false; } bool qt_mac_set_drawer_preferred_edge(QWidget *w, Qt::DockWidgetArea where) //users of Qt for Mac OS X can use this.. { if(!qt_mac_is_macdrawer(w)) return false; #if QT_MAC_USE_COCOA NSDrawer *drawer = qt_mac_drawer_for(w); if (!drawer) return false; NSRectEdge edge; if (where & Qt::LeftDockWidgetArea) edge = NSMinXEdge; else if (where & Qt::RightDockWidgetArea) edge = NSMaxXEdge; else if (where & Qt::TopDockWidgetArea) edge = NSMaxYEdge; else if (where & Qt::BottomDockWidgetArea) edge = NSMinYEdge; else return false; if (edge == [drawer preferredEdge]) //no-op return false; if (w->isVisible()) { [drawer close]; [drawer openOnEdge:edge]; } [drawer setPreferredEdge:edge]; #else OSWindowRef window = qt_mac_window_for(w); OptionBits edge; if(where & Qt::LeftDockWidgetArea) edge = kWindowEdgeLeft; else if(where & Qt::RightDockWidgetArea) edge = kWindowEdgeRight; else if(where & Qt::TopDockWidgetArea) edge = kWindowEdgeTop; else if(where & Qt::BottomDockWidgetArea) edge = kWindowEdgeBottom; else return false; if(edge == GetDrawerPreferredEdge(window)) //no-op return false; //do it SetDrawerPreferredEdge(window, edge); if(w->isVisible()) { CloseDrawer(window, false); OpenDrawer(window, edge, true); } #endif return true; } #ifndef QT_MAC_USE_COCOA Q_GUI_EXPORT #endif QPoint qt_mac_posInWindow(const QWidget *w) { QPoint ret = w->data->wrect.topLeft(); while(w && !w->isWindow()) { ret += w->pos(); w = w->parentWidget(); } return ret; } //find a QWidget from a OSWindowRef QWidget *qt_mac_find_window(OSWindowRef window) { #ifdef QT_MAC_USE_COCOA return [window QT_MANGLE_NAMESPACE(qt_qwidget)]; #else if(!window) return 0; QWidget *ret; if(GetWindowProperty(window, kWidgetCreatorQt, kWidgetPropertyQWidget, sizeof(ret), 0, &ret) == noErr) return ret; return 0; #endif } inline static void qt_mac_set_fullscreen_mode(bool b) { extern bool qt_mac_app_fullscreen; //qapplication_mac.mm if(qt_mac_app_fullscreen == b) return; qt_mac_app_fullscreen = b; if (b) { SetSystemUIMode(kUIModeAllHidden, kUIOptionAutoShowMenuBar); } else { SetSystemUIMode(kUIModeNormal, 0); } } Q_GUI_EXPORT OSViewRef qt_mac_nativeview_for(const QWidget *w) { return reinterpret_cast(w->data->winid); } Q_GUI_EXPORT OSViewRef qt_mac_get_contentview_for(OSWindowRef w) { #ifdef QT_MAC_USE_COCOA return [w contentView]; #else HIViewRef contentView = 0; OSStatus err = GetRootControl(w, &contentView); // Returns the window's content view (Apple QA1214) if (err == errUnknownControl) { contentView = HIViewGetRoot(w); } else if (err != noErr) { qWarning("Qt:Could not get content or root view of window! %s:%d [%ld]", __FILE__, __LINE__, err); } return contentView; #endif } bool qt_mac_sendMacEventToWidget(QWidget *widget, EventRef ref) { return widget->macEvent(0, ref); } Q_GUI_EXPORT OSWindowRef qt_mac_window_for(OSViewRef view) { #ifdef QT_MAC_USE_COCOA if (view) return [view window]; return 0; #else return HIViewGetWindow(view); #endif } static bool qt_isGenuineQWidget(OSViewRef ref) { #ifdef QT_MAC_USE_COCOA return [ref isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaView) class]]; #else return HIObjectIsOfClass(HIObjectRef(ref), kObjectQWidget); #endif } bool qt_isGenuineQWidget(const QWidget *window) { return window && qt_isGenuineQWidget(OSViewRef(window->winId())); } Q_GUI_EXPORT OSWindowRef qt_mac_window_for(const QWidget *w) { OSViewRef hiview = qt_mac_nativeview_for(w); if (hiview){ OSWindowRef window = qt_mac_window_for(hiview); if (!window && qt_isGenuineQWidget(hiview)) { QWidget *myWindow = w->window(); // This is a workaround for NSToolbar. When a widget is hidden // by clicking the toolbar button, Cocoa reparents the widgets // to another window (but Qt doesn't know about it). // When we start showing them, it reparents back, // but at this point it's window is nil, but the window it's being brought // into (the Qt one) is for sure created. // This stops the hierarchy moving under our feet. if (myWindow != w && qt_mac_window_for(qt_mac_nativeview_for(myWindow))) return qt_mac_window_for(qt_mac_nativeview_for(myWindow)); myWindow->d_func()->createWindow_sys(); // Reget the hiview since the "create window could potentially move the view (I guess). hiview = qt_mac_nativeview_for(w); window = qt_mac_window_for(hiview); } return window; } return 0; } #ifndef QT_MAC_USE_COCOA /* Checks if the current group is a 'stay on top' group. If so, the group gets removed from the hash table */ static void qt_mac_release_stays_on_top_group(WindowGroupRef group) { for (WindowGroupHash::iterator it = qt_mac_window_groups()->begin(); it != qt_mac_window_groups()->end(); ++it) { if (it.value() == group) { qt_mac_window_groups()->remove(it.key()); return; } } } /* Use this function instead of ReleaseWindowGroup, this will be sure to release the stays on top window group (created with qt_mac_get_stays_on_top_group below) */ static void qt_mac_release_window_group(WindowGroupRef group) { ReleaseWindowGroup(group); if (GetWindowGroupRetainCount(group) == 0) qt_mac_release_stays_on_top_group(group); } #define ReleaseWindowGroup(x) Are you sure you wanted to do that? (you wanted qt_mac_release_window_group) SInt32 qt_mac_get_group_level(WindowClass wclass) { SInt32 group_level; CGWindowLevel tmpLevel; GetWindowGroupLevelOfType(GetWindowGroupOfClass(wclass), kWindowGroupLevelActive, &tmpLevel); group_level = tmpLevel; return group_level; } #endif #ifndef QT_MAC_USE_COCOA static void qt_mac_set_window_group(OSWindowRef window, Qt::WindowFlags flags, int level) { WindowGroupRef group = 0; if (qt_mac_window_groups()->contains(flags)) { group = qt_mac_window_groups()->value(flags); RetainWindowGroup(group); } else { CreateWindowGroup(kWindowActivationScopeNone, &group); SetWindowGroupLevel(group, level); SetWindowGroupParent(group, GetWindowGroupOfClass(kAllWindowClasses)); qt_mac_window_groups()->insert(flags, group); } SetWindowGroup(window, group); } inline static void qt_mac_set_window_group_to_stays_on_top(OSWindowRef window, Qt::WindowType type) { // We create one static stays on top window group so that // all stays on top (aka popups) will fall into the same // group and be able to be raise()'d with releation to one another (from // within the same window group). qt_mac_set_window_group(window, type|Qt::WindowStaysOnTopHint, qt_mac_get_group_level(kOverlayWindowClass)); } inline static void qt_mac_set_window_group_to_tooltip(OSWindowRef window) { // Since new groups are created for 'stays on top' windows, the // same must be done for tooltips. Otherwise, tooltips would be drawn // below 'stays on top' widgets even tough they are on the same level. // Also, add 'two' to the group level to make sure they also get on top of popups. qt_mac_set_window_group(window, Qt::ToolTip, qt_mac_get_group_level(kHelpWindowClass)+2); } inline static void qt_mac_set_window_group_to_popup(OSWindowRef window) { // In Qt, a popup is seen as a 'stay on top' window. // Since new groups are created for 'stays on top' windows, the // same must be done for popups. Otherwise, popups would be drawn // below 'stays on top' windows. Add 1 to get above pure stay-on-top windows. qt_mac_set_window_group(window, Qt::Popup, qt_mac_get_group_level(kOverlayWindowClass)+1); } #endif inline static bool updateRedirectedToGraphicsProxyWidget(QWidget *widget, const QRect &rect) { if (!widget) return false; #ifndef QT_NO_GRAPHICSVIEW QWidget *tlw = widget->window(); QWExtra *extra = qt_widget_private(tlw)->extra; if (extra && extra->proxyWidget) { extra->proxyWidget->update(rect.translated(widget->mapTo(tlw, QPoint()))); return true; } #endif return false; } inline static bool updateRedirectedToGraphicsProxyWidget(QWidget *widget, const QRegion &rgn) { if (!widget) return false; #ifndef QT_NO_GRAPHICSVIEW QWidget *tlw = widget->window(); QWExtra *extra = qt_widget_private(tlw)->extra; if (extra && extra->proxyWidget) { const QPoint offset(widget->mapTo(tlw, QPoint())); const QVector rects = rgn.rects(); for (int i = 0; i < rects.size(); ++i) extra->proxyWidget->update(rects.at(i).translated(offset)); return true; } #endif return false; } void QWidgetPrivate::macUpdateIsOpaque() { Q_Q(QWidget); if (!q->testAttribute(Qt::WA_WState_Created)) return; #ifndef QT_MAC_USE_COCOA HIViewFeatures bits; HIViewRef hiview = qt_mac_nativeview_for(q); HIViewGetFeatures(hiview, &bits); if ((bits & kHIViewIsOpaque) == isOpaque) return; if (isOpaque) { HIViewChangeFeatures(hiview, kHIViewIsOpaque, 0); } else { HIViewChangeFeatures(hiview, 0, kHIViewIsOpaque); } if (q->isVisible()) HIViewReshapeStructure(qt_mac_nativeview_for(q)); #else if (isRealWindow() && !q->testAttribute(Qt::WA_MacBrushedMetal)) { bool opaque = isOpaque; if (extra && extra->imageMask) opaque = false; // we are never opaque when we have a mask. [qt_mac_window_for(q) setOpaque:opaque]; } #endif } #ifdef QT_MAC_USE_COCOA static OSWindowRef qt_mac_create_window(QWidget *widget, WindowClass wclass, NSUInteger wattr, const QRect &crect) { // Determine if we need to add in our "custom window" attribute. Cocoa is rather clever // in deciding if we need the maximize button or not (i.e., it's resizeable, so you // must need a maximize button). So, the only buttons we have control over are the // close and minimize buttons. If someone wants to customize and NOT have the maximize // button, then we have to do our hack. We only do it for these cases because otherwise // the window looks different when activated. This "QtMacCustomizeWindow" attribute is // intruding on a public space and WILL BREAK in the future. // One can hope that there is a more public API available by that time. Qt::WindowFlags flags = widget ? widget->windowFlags() : Qt::WindowFlags(0); if ((flags & Qt::CustomizeWindowHint)) { if ((flags & (Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint | Qt::WindowMinimizeButtonHint | Qt::WindowTitleHint)) && !(flags & Qt::WindowMaximizeButtonHint)) wattr |= QtMacCustomizeWindow; } // If we haven't created the desktop widget, you have to pass the rectangle // in "cocoa coordinates" (i.e., top points to the lower left coordinate). // Otherwise, we do the conversion for you. Since we are the only ones that // create the desktop widget, this is OK (but confusing). NSRect geo = NSMakeRect(crect.left(), (qt_root_win != 0) ? flipYCoordinate(crect.bottom() + 1) : crect.top(), crect.width(), crect.height()); QMacCocoaAutoReleasePool pool; OSWindowRef window; switch (wclass) { case kMovableModalWindowClass: case kModalWindowClass: case kSheetWindowClass: case kFloatingWindowClass: case kOverlayWindowClass: case kHelpWindowClass: { NSPanel *panel; BOOL needFloating = NO; BOOL worksWhenModal = widget && (widget->windowType() == Qt::Popup); // Add in the extra flags if necessary. switch (wclass) { case kSheetWindowClass: wattr |= NSDocModalWindowMask; break; case kFloatingWindowClass: case kHelpWindowClass: needFloating = YES; wattr |= NSUtilityWindowMask; break; default: break; } panel = [[QT_MANGLE_NAMESPACE(QCocoaPanel) alloc] QT_MANGLE_NAMESPACE(qt_initWithQWidget):widget contentRect:geo styleMask:wattr]; [panel setFloatingPanel:needFloating]; [panel setWorksWhenModal:worksWhenModal]; window = panel; break; } case kDrawerWindowClass: { NSDrawer *drawer = [[NSDrawer alloc] initWithContentSize:geo.size preferredEdge:NSMinXEdge]; [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] becomeDelegateForDrawer:drawer widget:widget]; QWidget *parentWidget = widget->parentWidget(); if (parentWidget) [drawer setParentWindow:qt_mac_window_for(parentWidget)]; [drawer setLeadingOffset:0.0]; [drawer setTrailingOffset:25.0]; window = [[drawer contentView] window]; // Just to make sure we actually return a window break; } default: window = [[QT_MANGLE_NAMESPACE(QCocoaWindow) alloc] QT_MANGLE_NAMESPACE(qt_initWithQWidget):widget contentRect:geo styleMask:wattr]; break; } qt_syncCocoaTitleBarButtons(window, widget); return window; } #else static OSWindowRef qt_mac_create_window(QWidget *, WindowClass wclass, WindowAttributes wattr, const QRect &crect) { OSWindowRef window; Rect geo; SetRect(&geo, crect.left(), crect.top(), crect.right() + 1, crect.bottom() + 1); OSStatus err; if(geo.right <= geo.left) geo.right = geo.left + 1; if(geo.bottom <= geo.top) geo.bottom = geo.top + 1; Rect null_rect; SetRect(&null_rect, 0, 0, 1, 1); err = CreateNewWindow(wclass, wattr, &null_rect, &window); if(err == noErr) { err = SetWindowBounds(window, kWindowContentRgn, &geo); if(err != noErr) qWarning("QWidget: Internal error (%s:%d)", __FILE__, __LINE__); } return window; } #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6 /* We build the release package against the 10.4 SDK. So, to enable gestures for applications running on 10.6+, we define the missing constants here: */ enum { kEventClassGesture = 'gest', kEventGestureStarted = 1, kEventGestureEnded = 2, kEventGestureMagnify = 4, kEventGestureSwipe = 5, kEventGestureRotate = 6, kEventParamRotationAmount = 'rota', kEventParamSwipeDirection = 'swip', kEventParamMagnificationAmount = 'magn' }; #endif // window events static EventTypeSpec window_events[] = { { kEventClassWindow, kEventWindowClose }, { kEventClassWindow, kEventWindowExpanded }, { kEventClassWindow, kEventWindowHidden }, { kEventClassWindow, kEventWindowZoom }, { kEventClassWindow, kEventWindowZoomed }, { kEventClassWindow, kEventWindowCollapsed }, { kEventClassWindow, kEventWindowToolbarSwitchMode }, { kEventClassWindow, kEventWindowProxyBeginDrag }, { kEventClassWindow, kEventWindowProxyEndDrag }, { kEventClassWindow, kEventWindowResizeCompleted }, { kEventClassWindow, kEventWindowBoundsChanging }, { kEventClassWindow, kEventWindowGetRegion }, { kEventClassWindow, kEventWindowGetClickModality }, { kEventClassWindow, kEventWindowTransitionCompleted }, { kEventClassGesture, kEventGestureStarted }, { kEventClassGesture, kEventGestureEnded }, { kEventClassGesture, kEventGestureMagnify }, { kEventClassGesture, kEventGestureSwipe }, { kEventClassGesture, kEventGestureRotate }, { kEventClassMouse, kEventMouseDown } }; static EventHandlerUPP mac_win_eventUPP = 0; static void cleanup_win_eventUPP() { DisposeEventHandlerUPP(mac_win_eventUPP); mac_win_eventUPP = 0; } static const EventHandlerUPP make_win_eventUPP() { if(mac_win_eventUPP) return mac_win_eventUPP; qAddPostRoutine(cleanup_win_eventUPP); return mac_win_eventUPP = NewEventHandlerUPP(QWidgetPrivate::qt_window_event); } OSStatus QWidgetPrivate::qt_window_event(EventHandlerCallRef er, EventRef event, void *) { QScopedLoopLevelCounter loopLevelCounter(qApp->d_func()->threadData); bool handled_event = true; UInt32 ekind = GetEventKind(event), eclass = GetEventClass(event); switch(eclass) { case kEventClassWindow: { WindowRef wid = 0; GetEventParameter(event, kEventParamDirectObject, typeWindowRef, 0, sizeof(WindowRef), 0, &wid); QWidget *widget = qt_mac_find_window(wid); if(!widget) { handled_event = false; } else if(ekind == kEventWindowGetClickModality) { // Carbon will send us kEventWindowGetClickModality before every // mouse press / release event. By returning 'true', we tell Carbon // that we would like the event target to receive the mouse event even // if the target is modally shaddowed. In Qt, this makes sense when we // e.g. have a popup showing, as the popup will grab the event // and perhaps use it to close itself. // By also setting the current modal window back into the event, we // help Carbon determining which window is supposed to be raised. handled_event = qApp->activePopupWidget() ? true : false; } else if(ekind == kEventWindowClose) { widget->d_func()->close_helper(QWidgetPrivate::CloseWithSpontaneousEvent); QMenuBar::macUpdateMenuBar(); } else if (ekind == kEventWindowTransitionCompleted) { WindowTransitionAction transitionAction; GetEventParameter(event, kEventParamWindowTransitionAction, typeWindowTransitionAction, 0, sizeof(transitionAction), 0, &transitionAction); if (transitionAction == kWindowHideTransitionAction) widget->hide(); } else if(ekind == kEventWindowExpanded) { Qt::WindowStates currState = Qt::WindowStates(widget->data->window_state); Qt::WindowStates newState = currState; if (currState & Qt::WindowMinimized) newState &= ~Qt::WindowMinimized; if (!(currState & Qt::WindowActive)) newState |= Qt::WindowActive; if (newState != currState) { // newState will differ from currState if the window // was expanded after clicking on the jewels (as opposed // to calling QWidget::setWindowState) widget->data->window_state = newState; QWindowStateChangeEvent e(currState); QApplication::sendSpontaneousEvent(widget, &e); } QShowEvent qse; QApplication::sendSpontaneousEvent(widget, &qse); } else if(ekind == kEventWindowZoom) { widget->d_func()->topData()->normalGeometry = widget->geometry(); handled_event = false; } else if(ekind == kEventWindowZoomed) { WindowPartCode windowPart; GetEventParameter(event, kEventParamWindowPartCode, typeWindowPartCode, 0, sizeof(windowPart), 0, &windowPart); if(windowPart == inZoomIn && widget->isMaximized()) { widget->data->window_state = widget->data->window_state & ~Qt::WindowMaximized; QWindowStateChangeEvent e(Qt::WindowStates(widget->data->window_state | Qt::WindowMaximized)); QApplication::sendSpontaneousEvent(widget, &e); } else if(windowPart == inZoomOut && !widget->isMaximized()) { widget->data->window_state = widget->data->window_state | Qt::WindowMaximized; QWindowStateChangeEvent e(Qt::WindowStates(widget->data->window_state & ~Qt::WindowMaximized)); QApplication::sendSpontaneousEvent(widget, &e); } extern QPointer qt_button_down; //qapplication_mac.cpp qt_button_down = 0; } else if(ekind == kEventWindowCollapsed) { if (!widget->isMinimized()) { widget->data->window_state = widget->data->window_state | Qt::WindowMinimized; QWindowStateChangeEvent e(Qt::WindowStates(widget->data->window_state & ~Qt::WindowMinimized)); QApplication::sendSpontaneousEvent(widget, &e); } // Deactivate this window: if (widget->isActiveWindow() && !(widget->windowType() == Qt::Popup)) { QWidget *w = 0; if (widget->parentWidget()) w = widget->parentWidget()->window(); if (!w || (!w->isVisible() && !w->isMinimized())) { for (WindowPtr wp = GetFrontWindowOfClass(kDocumentWindowClass, true); wp; wp = GetNextWindowOfClass(wp, kDocumentWindowClass, true)) { if ((w = qt_mac_find_window(wp))) break; } } if(!(w && w->isVisible() && !w->isMinimized())) qApp->setActiveWindow(0); } //we send a hide to be like X11/Windows QEvent e(QEvent::Hide); QApplication::sendSpontaneousEvent(widget, &e); extern QPointer qt_button_down; //qapplication_mac.cpp qt_button_down = 0; } else if(ekind == kEventWindowToolbarSwitchMode) { macSendToolbarChangeEvent(widget); HIToolbarRef toolbar; if (GetWindowToolbar(wid, &toolbar) == noErr) { if (toolbar) { // Let HIToolbar do its thang, but things like the OpenGL context // needs to know about it. CallNextEventHandler(er, event); qt_event_request_window_change(widget); widget->data->fstrut_dirty = true; } } } else if(ekind == kEventWindowGetRegion) { WindowRef window; GetEventParameter(event, kEventParamDirectObject, typeWindowRef, 0, sizeof(window), 0, &window); WindowRegionCode wcode; GetEventParameter(event, kEventParamWindowRegionCode, typeWindowRegionCode, 0, sizeof(wcode), 0, &wcode); if (wcode != kWindowOpaqueRgn){ // If the region is kWindowOpaqueRgn, don't call next // event handler cause this will make the shadow of // masked windows become offset. Unfortunately, we're not sure why. CallNextEventHandler(er, event); } RgnHandle rgn; GetEventParameter(event, kEventParamRgnHandle, typeQDRgnHandle, 0, sizeof(rgn), 0, &rgn); if(QWidgetPrivate::qt_widget_rgn(qt_mac_find_window(window), wcode, rgn, false)) SetEventParameter(event, kEventParamRgnHandle, typeQDRgnHandle, sizeof(rgn), &rgn); } else if(ekind == kEventWindowProxyBeginDrag) { QIconDragEvent e; QApplication::sendSpontaneousEvent(widget, &e); } else if(ekind == kEventWindowResizeCompleted) { // Create a mouse up event, since such an event is not send by carbon to the // application event handler (while a mouse down is on kEventWindowResizeStarted) EventRef mouseUpEvent; CreateEvent(0, kEventClassMouse, kEventMouseUp, 0, kEventAttributeUserEvent, &mouseUpEvent); UInt16 mbutton = kEventMouseButtonPrimary; SetEventParameter(mouseUpEvent, kEventParamMouseButton, typeMouseButton, sizeof(mbutton), &mbutton); WindowRef window; GetEventParameter(event, kEventParamDirectObject, typeWindowRef, 0, sizeof(window), 0, &window); Rect dragRect; GetWindowBounds(window, kWindowGrowRgn, &dragRect); Point pos = {dragRect.bottom, dragRect.right}; SetEventParameter(mouseUpEvent, kEventParamMouseLocation, typeQDPoint, sizeof(pos), &pos); SendEventToApplication(mouseUpEvent); ReleaseEvent(mouseUpEvent); } else if(ekind == kEventWindowBoundsChanging) { UInt32 flags = 0; GetEventParameter(event, kEventParamAttributes, typeUInt32, 0, sizeof(flags), 0, &flags); Rect nr; GetEventParameter(event, kEventParamCurrentBounds, typeQDRectangle, 0, sizeof(nr), 0, &nr); QRect newRect(nr.left, nr.top, nr.right - nr.left, nr.bottom - nr.top); QTLWExtra * const tlwExtra = widget->d_func()->maybeTopData(); if (tlwExtra && tlwExtra->isSetGeometry == 1) { widget->d_func()->setGeometry_sys_helper(newRect.left(), newRect.top(), newRect.width(), newRect.height(), tlwExtra->isMove); } else { //implicitly removes the maximized bit if((widget->data->window_state & Qt::WindowMaximized) && IsWindowInStandardState(wid, 0, 0)) { widget->data->window_state &= ~Qt::WindowMaximized; QWindowStateChangeEvent e(Qt::WindowStates(widget->data->window_state | Qt::WindowMaximized)); QApplication::sendSpontaneousEvent(widget, &e); } handled_event = false; const QRect oldRect = widget->data->crect; if((flags & kWindowBoundsChangeOriginChanged)) { if(nr.left != oldRect.x() || nr.top != oldRect.y()) { widget->data->crect.moveTo(nr.left, nr.top); QMoveEvent qme(widget->data->crect.topLeft(), oldRect.topLeft()); QApplication::sendSpontaneousEvent(widget, &qme); } } if((flags & kWindowBoundsChangeSizeChanged)) { if (widget->isWindow()) { QSize newSize = QLayout::closestAcceptableSize(widget, newRect.size()); int dh = newSize.height() - newRect.height(); int dw = newSize.width() - newRect.width(); if (dw != 0 || dh != 0) { handled_event = true; // We want to change the bounds, so we handle the event // set the rect, so we can also do the resize down below (yes, we need to resize). newRect.setBottom(newRect.bottom() + dh); newRect.setRight(newRect.right() + dw); nr.left = newRect.x(); nr.top = newRect.y(); nr.right = nr.left + newRect.width(); nr.bottom = nr.top + newRect.height(); SetEventParameter(event, kEventParamCurrentBounds, typeQDRectangle, sizeof(Rect), &nr); } } if (oldRect.width() != newRect.width() || oldRect.height() != newRect.height()) { widget->data->crect.setSize(newRect.size()); HIRect bounds = CGRectMake(0, 0, newRect.width(), newRect.height()); // If the WA_StaticContents attribute is set we can optimize the resize // by only repainting the newly exposed area. We do this by disabling // painting when setting the size of the view. The OS will invalidate // the newly exposed area for us. const bool staticContents = widget->testAttribute(Qt::WA_StaticContents); const HIViewRef view = qt_mac_nativeview_for(widget); if (staticContents) HIViewSetDrawingEnabled(view, false); HIViewSetFrame(view, &bounds); if (staticContents) HIViewSetDrawingEnabled(view, true); QResizeEvent qre(newRect.size(), oldRect.size()); QApplication::sendSpontaneousEvent(widget, &qre); qt_event_request_window_change(widget); } } } } else if (ekind == kEventWindowHidden) { // Make sure that we also hide any visible sheets on our window. // Cocoa does the right thing for us. const QObjectList children = widget->children(); const int childCount = children.count(); for (int i = 0; i < childCount; ++i) { QObject *obj = children.at(i); if (obj->isWidgetType()) { QWidget *widget = static_cast(obj); if (qt_mac_is_macsheet(widget) && widget->isVisible()) widget->hide(); } } } else { handled_event = false; } break; } case kEventClassMouse: { #if 0 return SendEventToApplication(event); #endif bool send_to_app = false; { WindowPartCode wpc; if (GetEventParameter(event, kEventParamWindowPartCode, typeWindowPartCode, 0, sizeof(wpc), 0, &wpc) == noErr && wpc != inContent) send_to_app = true; } if(!send_to_app) { WindowRef window; if(GetEventParameter(event, kEventParamWindowRef, typeWindowRef, 0, sizeof(window), 0, &window) == noErr) { HIViewRef hiview; if(HIViewGetViewForMouseEvent(HIViewGetRoot(window), event, &hiview) == noErr) { if(QWidget *w = QWidget::find((WId)hiview)) { #if 0 send_to_app = !w->isActiveWindow(); #else Q_UNUSED(w); send_to_app = true; #endif } } } } if(send_to_app) return SendEventToApplication(event); handled_event = false; break; } case kEventClassGesture: { // First, find the widget that was under // the mouse when the gesture happened: HIPoint screenLocation; if (GetEventParameter(event, kEventParamMouseLocation, typeHIPoint, 0, sizeof(screenLocation), 0, &screenLocation) != noErr) { handled_event = false; break; } QWidget *widget = QApplication::widgetAt(screenLocation.x, screenLocation.y); if (!widget) { handled_event = false; break; } QNativeGestureEvent qNGEvent; qNGEvent.position = QPoint(screenLocation.x, screenLocation.y); switch (ekind) { case kEventGestureStarted: qNGEvent.gestureType = QNativeGestureEvent::GestureBegin; break; case kEventGestureEnded: qNGEvent.gestureType = QNativeGestureEvent::GestureEnd; break; case kEventGestureRotate: { CGFloat amount; if (GetEventParameter(event, kEventParamRotationAmount, 'cgfl', 0, sizeof(amount), 0, &amount) != noErr) { handled_event = false; break; } qNGEvent.gestureType = QNativeGestureEvent::Rotate; qNGEvent.percentage = float(-amount); break; } case kEventGestureSwipe: { HIPoint swipeDirection; if (GetEventParameter(event, kEventParamSwipeDirection, typeHIPoint, 0, sizeof(swipeDirection), 0, &swipeDirection) != noErr) { handled_event = false; break; } qNGEvent.gestureType = QNativeGestureEvent::Swipe; if (swipeDirection.x == 1) qNGEvent.angle = 180.0f; else if (swipeDirection.x == -1) qNGEvent.angle = 0.0f; else if (swipeDirection.y == 1) qNGEvent.angle = 90.0f; else if (swipeDirection.y == -1) qNGEvent.angle = 270.0f; break; } case kEventGestureMagnify: { CGFloat amount; if (GetEventParameter(event, kEventParamMagnificationAmount, 'cgfl', 0, sizeof(amount), 0, &amount) != noErr) { handled_event = false; break; } qNGEvent.gestureType = QNativeGestureEvent::Zoom; qNGEvent.percentage = float(amount); break; } } QApplication::sendSpontaneousEvent(widget, &qNGEvent); break; } default: handled_event = false; } if(!handled_event) //let the event go through return eventNotHandledErr; return noErr; //we eat the event } // widget events static HIObjectClassRef widget_class = 0; static EventTypeSpec widget_events[] = { { kEventClassHIObject, kEventHIObjectConstruct }, { kEventClassHIObject, kEventHIObjectDestruct }, { kEventClassControl, kEventControlDraw }, { kEventClassControl, kEventControlInitialize }, { kEventClassControl, kEventControlGetPartRegion }, { kEventClassControl, kEventControlGetClickActivation }, { kEventClassControl, kEventControlSetFocusPart }, { kEventClassControl, kEventControlDragEnter }, { kEventClassControl, kEventControlDragWithin }, { kEventClassControl, kEventControlDragLeave }, { kEventClassControl, kEventControlDragReceive }, { kEventClassControl, kEventControlOwningWindowChanged }, { kEventClassControl, kEventControlBoundsChanged }, { kEventClassControl, kEventControlGetSizeConstraints }, { kEventClassControl, kEventControlVisibilityChanged }, { kEventClassMouse, kEventMouseDown }, { kEventClassMouse, kEventMouseUp }, { kEventClassMouse, kEventMouseMoved }, { kEventClassMouse, kEventMouseDragged } }; static EventHandlerUPP mac_widget_eventUPP = 0; static void cleanup_widget_eventUPP() { DisposeEventHandlerUPP(mac_widget_eventUPP); mac_widget_eventUPP = 0; } static const EventHandlerUPP make_widget_eventUPP() { if(mac_widget_eventUPP) return mac_widget_eventUPP; qAddPostRoutine(cleanup_widget_eventUPP); return mac_widget_eventUPP = NewEventHandlerUPP(QWidgetPrivate::qt_widget_event); } OSStatus QWidgetPrivate::qt_widget_event(EventHandlerCallRef er, EventRef event, void *) { QScopedLoopLevelCounter loopLevelCounter(QApplicationPrivate::instance()->threadData); bool handled_event = true; UInt32 ekind = GetEventKind(event), eclass = GetEventClass(event); switch(eclass) { case kEventClassHIObject: { HIViewRef view = 0; GetEventParameter(event, kEventParamHIObjectInstance, typeHIObjectRef, 0, sizeof(view), 0, &view); if(ekind == kEventHIObjectConstruct) { if(view) { HIViewChangeFeatures(view, kHIViewAllowsSubviews, 0); SetEventParameter(event, kEventParamHIObjectInstance, typeVoidPtr, sizeof(view), &view); } } else if(ekind == kEventHIObjectDestruct) { //nothing to really do.. or is there? } else { handled_event = false; } break; } case kEventClassControl: { QWidget *widget = 0; HIViewRef hiview = 0; if(GetEventParameter(event, kEventParamDirectObject, typeControlRef, 0, sizeof(hiview), 0, &hiview) == noErr) widget = QWidget::find((WId)hiview); if (widget && widget->macEvent(er, event)) return noErr; if(ekind == kEventControlDraw) { if(widget && qt_isGenuineQWidget(hiview)) { // if there is a window change event pending for any gl child wigets, // send it immediately. (required for flicker-free resizing) extern void qt_mac_send_posted_gl_updates(QWidget *widget); qt_mac_send_posted_gl_updates(widget); if (QApplicationPrivate::graphicsSystem() && !widget->d_func()->paintOnScreen()) { widget->d_func()->syncBackingStore(); widget->d_func()->dirtyOnWidget = QRegion(); return noErr; } //requested rgn RgnHandle rgn; GetEventParameter(event, kEventParamRgnHandle, typeQDRgnHandle, 0, sizeof(rgn), 0, &rgn); QRegion qrgn(qt_mac_convert_mac_region(rgn)); //update handles GrafPtr qd = 0; CGContextRef cg = 0; if(GetEventParameter(event, kEventParamCGContextRef, typeCGContextRef, 0, sizeof(cg), 0, &cg) != noErr) { Q_ASSERT(false); } widget->d_func()->hd = cg; widget->d_func()->qd_hd = qd; CGContextSaveGState(cg); #ifdef DEBUG_WIDGET_PAINT const bool doDebug = true; if(doDebug) { qDebug("asked to draw %p[%p] [%s::%s] %p[%p] [%d] [%dx%d]", widget, hiview, widget->metaObject()->className(), widget->objectName().local8Bit().data(), widget->parentWidget(), (HIViewRef)(widget->parentWidget() ? qt_mac_nativeview_for(widget->parentWidget()) : (HIViewRef)0), HIViewIsCompositingEnabled(hiview), qt_mac_posInWindow(widget).x(), qt_mac_posInWindow(widget).y()); #if 0 QVector region_rects = qrgn.rects(); qDebug("Region! %d", region_rects.count()); for(int i = 0; i < region_rects.count(); i++) qDebug("%d %d %d %d", region_rects[i].x(), region_rects[i].y(), region_rects[i].width(), region_rects[i].height()); region_rects = widget->d_func()->clp.rects(); qDebug("Widget Region! %d", region_rects.count()); for(int i = 0; i < region_rects.count(); i++) qDebug("%d %d %d %d", region_rects[i].x(), region_rects[i].y(), region_rects[i].width(), region_rects[i].height()); #endif } #endif if (widget->isVisible() && widget->updatesEnabled()) { //process the actual paint event. if(widget->testAttribute(Qt::WA_WState_InPaintEvent)) qWarning("QWidget::repaint: Recursive repaint detected"); QPoint redirectionOffset(0, 0); QWidget *tl = widget->window(); if (tl) { Qt::WindowFlags flags = tl->windowFlags(); if (flags & Qt::FramelessWindowHint || (flags & Qt::CustomizeWindowHint && !(flags & Qt::WindowTitleHint))) { if(tl->d_func()->extra && !tl->d_func()->extra->mask.isEmpty()) redirectionOffset += tl->d_func()->extra->mask.boundingRect().topLeft(); } } //setup the context widget->setAttribute(Qt::WA_WState_InPaintEvent); QPaintEngine *engine = widget->paintEngine(); if (engine) engine->setSystemClip(qrgn); //handle the erase if (engine && (!widget->testAttribute(Qt::WA_NoSystemBackground) && (widget->isWindow() || widget->autoFillBackground()) || widget->testAttribute(Qt::WA_TintedBackground) || widget->testAttribute(Qt::WA_StyledBackground))) { #ifdef DEBUG_WIDGET_PAINT if(doDebug) qDebug(" Handling erase for [%s::%s]", widget->metaObject()->className(), widget->objectName().local8Bit().data()); #endif if (!redirectionOffset.isNull()) widget->d_func()->setRedirected(widget, redirectionOffset); bool was_unclipped = widget->testAttribute(Qt::WA_PaintUnclipped); widget->setAttribute(Qt::WA_PaintUnclipped, false); QPainter p(widget); p.setClipping(false); if(was_unclipped) widget->setAttribute(Qt::WA_PaintUnclipped); widget->d_func()->paintBackground(&p, qrgn, widget->isWindow() ? DrawAsRoot : 0); if (widget->testAttribute(Qt::WA_TintedBackground)) { QColor tint = widget->palette().window().color(); tint.setAlphaF(.6); const QVector &rects = qrgn.rects(); for (int i = 0; i < rects.size(); ++i) p.fillRect(rects.at(i), tint); } p.end(); if (!redirectionOffset.isNull()) widget->d_func()->restoreRedirected(); } if (widget->isWindow() && !widget->d_func()->isOpaque && !widget->testAttribute(Qt::WA_MacBrushedMetal)) { QRect qrgnRect = qrgn.boundingRect(); CGContextClearRect(cg, CGRectMake(qrgnRect.x(), qrgnRect.y(), qrgnRect.width(), qrgnRect.height())); } if(!HIObjectIsOfClass((HIObjectRef)hiview, kObjectQWidget)) CallNextEventHandler(er, event); //send the paint redirectionOffset += widget->data->wrect.topLeft(); // Map from system to qt coordinates if (!redirectionOffset.isNull()) widget->d_func()->setRedirected(widget, redirectionOffset); qrgn.translate(redirectionOffset); QPaintEvent e(qrgn); widget->d_func()->dirtyOnWidget = QRegion(); #ifdef QT3_SUPPORT e.setErased(true); #endif QApplication::sendSpontaneousEvent(widget, &e); if (!redirectionOffset.isNull()) widget->d_func()->restoreRedirected(); //cleanup if (engine) engine->setSystemClip(QRegion()); widget->setAttribute(Qt::WA_WState_InPaintEvent, false); if(!widget->testAttribute(Qt::WA_PaintOutsidePaintEvent) && widget->paintingActive()) qWarning("QWidget: It is dangerous to leave painters active on a widget outside of the PaintEvent"); } widget->d_func()->hd = 0; widget->d_func()->qd_hd = 0; CGContextRestoreGState(cg); } else if(!HIObjectIsOfClass((HIObjectRef)hiview, kObjectQWidget)) { CallNextEventHandler(er, event); } } else if(ekind == kEventControlInitialize) { if(HIObjectIsOfClass((HIObjectRef)hiview, kObjectQWidget)) { UInt32 features = kControlSupportsDragAndDrop | kControlSupportsClickActivation | kControlSupportsFocus; SetEventParameter(event, kEventParamControlFeatures, typeUInt32, sizeof(features), &features); } else { handled_event = false; } } else if(ekind == kEventControlSetFocusPart) { if(widget) { ControlPartCode part; GetEventParameter(event, kEventParamControlPart, typeControlPartCode, 0, sizeof(part), 0, &part); if(part == kControlFocusNoPart){ if (widget->hasFocus()) QApplicationPrivate::setFocusWidget(0, Qt::OtherFocusReason); } else widget->setFocus(); } if(!HIObjectIsOfClass((HIObjectRef)hiview, kObjectQWidget)) CallNextEventHandler(er, event); } else if(ekind == kEventControlGetClickActivation) { ClickActivationResult clickT = kActivateAndIgnoreClick; SetEventParameter(event, kEventParamClickActivation, typeClickActivationResult, sizeof(clickT), &clickT); } else if(ekind == kEventControlGetPartRegion) { handled_event = false; if(!HIObjectIsOfClass((HIObjectRef)hiview, kObjectQWidget) && CallNextEventHandler(er, event) == noErr) { handled_event = true; break; } if(widget && !widget->isWindow()) { ControlPartCode part; GetEventParameter(event, kEventParamControlPart, typeControlPartCode, 0, sizeof(part), 0, &part); if(part == kControlClickableMetaPart && widget->testAttribute(Qt::WA_TransparentForMouseEvents)) { RgnHandle rgn; GetEventParameter(event, kEventParamControlRegion, typeQDRgnHandle, 0, sizeof(rgn), 0, &rgn); SetEmptyRgn(rgn); handled_event = true; } else if(part == kControlStructureMetaPart || part == kControlClickableMetaPart) { RgnHandle rgn; GetEventParameter(event, kEventParamControlRegion, typeQDRgnHandle, 0, sizeof(rgn), 0, &rgn); SetRectRgn(rgn, 0, 0, widget->width(), widget->height()); if(QWidgetPrivate::qt_widget_rgn(widget, kWindowStructureRgn, rgn, false)) handled_event = true; } else if(part == kControlOpaqueMetaPart) { if(widget->d_func()->isOpaque) { RgnHandle rgn; GetEventParameter(event, kEventParamControlRegion, typeQDRgnHandle, 0, sizeof(RgnHandle), 0, &rgn); SetRectRgn(rgn, 0, 0, widget->width(), widget->height()); QWidgetPrivate::qt_widget_rgn(widget, kWindowStructureRgn, rgn, false); SetEventParameter(event, kEventParamControlRegion, typeQDRgnHandle, sizeof(RgnHandle), &rgn); handled_event = true; } } } } else if(ekind == kEventControlOwningWindowChanged) { if(!HIObjectIsOfClass((HIObjectRef)hiview, kObjectQWidget)) CallNextEventHandler(er, event); if(widget && qt_mac_window_for(hiview)) { WindowRef foo = 0; GetEventParameter(event, kEventParamControlCurrentOwningWindow, typeWindowRef, 0, sizeof(foo), 0, &foo); widget->d_func()->initWindowPtr(); } if (widget) qt_event_request_window_change(widget); } else if(ekind == kEventControlDragEnter || ekind == kEventControlDragWithin || ekind == kEventControlDragLeave || ekind == kEventControlDragReceive) { // dnd are really handled in qdnd_mac.cpp, // just modularize the code a little... DragRef drag; GetEventParameter(event, kEventParamDragRef, typeDragRef, 0, sizeof(drag), 0, &drag); handled_event = false; bool drag_allowed = false; QWidget *dropWidget = widget; if (qobject_cast(widget)){ // We might shadow widgets underneath the focus // frame, so stay interrested, and let the dnd through drag_allowed = true; handled_event = true; Point where; GetDragMouse(drag, &where, 0); dropWidget = QApplication::widgetAt(QPoint(where.h, where.v)); if (dropWidget != QDragManager::self()->currentTarget()) { // We have to 'fake' enter and leave events for the shaddowed widgets: if (ekind == kEventControlDragEnter) { if (QDragManager::self()->currentTarget()) QDragManager::self()->currentTarget()->d_func()->qt_mac_dnd_event(kEventControlDragLeave, drag); if (dropWidget) { dropWidget->d_func()->qt_mac_dnd_event(kEventControlDragEnter, drag); } // Set dropWidget to zero, so qt_mac_dnd_event // doesn't get called a second time below: dropWidget = 0; } else if (ekind == kEventControlDragLeave) { dropWidget = QDragManager::self()->currentTarget(); if (dropWidget) { dropWidget->d_func()->qt_mac_dnd_event(kEventControlDragLeave, drag); } // Set dropWidget to zero, so qt_mac_dnd_event // doesn't get called a second time below: dropWidget = 0; } } } // Send the dnd event to the widget: if (dropWidget && dropWidget->d_func()->qt_mac_dnd_event(ekind, drag)) { drag_allowed = true; handled_event = true; } if (ekind == kEventControlDragEnter) { // If we don't accept the enter event, we will // receive no more drag events for this widget const Boolean wouldAccept = drag_allowed ? true : false; SetEventParameter(event, kEventParamControlWouldAcceptDrop, typeBoolean, sizeof(wouldAccept), &wouldAccept); } } else if (ekind == kEventControlBoundsChanged) { if (!widget || widget->isWindow() || widget->testAttribute(Qt::WA_Moved) || widget->testAttribute(Qt::WA_Resized)) { handled_event = false; } else { // Sync our view in case some other (non-Qt) view is controlling us. handled_event = true; Rect newBounds; GetEventParameter(event, kEventParamCurrentBounds, typeQDRectangle, 0, sizeof(Rect), 0, &newBounds); QRect rect(newBounds.left, newBounds.top, newBounds.right - newBounds.left, newBounds.bottom - newBounds.top); bool moved = widget->testAttribute(Qt::WA_Moved); bool resized = widget->testAttribute(Qt::WA_Resized); widget->setGeometry(rect); widget->setAttribute(Qt::WA_Moved, moved); widget->setAttribute(Qt::WA_Resized, resized); qt_event_request_window_change(widget); } } else if (ekind == kEventControlGetSizeConstraints) { if (!widget || !qt_isGenuineQWidget(widget)) { handled_event = false; } else { handled_event = true; QWidgetItem item(widget); QSize size = item.minimumSize(); HISize hisize = { size.width(), size.height() }; SetEventParameter(event, kEventParamMinimumSize, typeHISize, sizeof(HISize), &hisize); size = item.maximumSize(); hisize.width = size.width() + 2; // ### shouldn't have to add 2 (but it works). hisize.height = size.height(); SetEventParameter(event, kEventParamMaximumSize, typeHISize, sizeof(HISize), &hisize); } } else if (ekind == kEventControlVisibilityChanged) { handled_event = false; if (widget) { qt_event_request_window_change(widget); if (!HIViewIsVisible(HIViewRef(widget->winId()))) { extern QPointer qt_button_down; //qapplication_mac.cpp if (widget == qt_button_down) qt_button_down = 0; } } } break; } case kEventClassMouse: { bool send_to_app = false; extern QPointer qt_button_down; //qapplication_mac.cpp if(qt_button_down) send_to_app = true; if(send_to_app) { OSStatus err = SendEventToApplication(event); if(err != noErr) handled_event = false; } else { CallNextEventHandler(er, event); } break; } default: handled_event = false; break; } if(!handled_event) //let the event go through return eventNotHandledErr; return noErr; //we eat the event } #endif OSViewRef qt_mac_create_widget(QWidget *widget, QWidgetPrivate *widgetPrivate, OSViewRef parent) { #ifdef QT_MAC_USE_COCOA QMacCocoaAutoReleasePool pool; QT_MANGLE_NAMESPACE(QCocoaView) *view = [[QT_MANGLE_NAMESPACE(QCocoaView) alloc] initWithQWidget:widget widgetPrivate:widgetPrivate]; if (view && parent) [parent addSubview:view]; return view; #else Q_UNUSED(widget); Q_UNUSED(widgetPrivate); if(!widget_class) { OSStatus err = HIObjectRegisterSubclass(kObjectQWidget, kHIViewClassID, 0, make_widget_eventUPP(), GetEventTypeCount(widget_events), widget_events, 0, &widget_class); if (err && err != hiObjectClassExistsErr) qWarning("QWidget: Internal error (%d)", __LINE__); } HIViewRef ret = 0; if(HIObjectCreate(kObjectQWidget, 0, (HIObjectRef*)&ret) != noErr) qWarning("QWidget: Internal error (%d)", __LINE__); if(ret && parent) HIViewAddSubview(parent, ret); return ret; #endif } void qt_mac_unregister_widget() { #ifndef QT_MAC_USE_COCOA HIObjectUnregisterClass(widget_class); widget_class = 0; #endif } void QWidgetPrivate::toggleDrawers(bool visible) { for (int i = 0; i < children.size(); ++i) { register QObject *object = children.at(i); if (!object->isWidgetType()) continue; QWidget *widget = static_cast(object); if(qt_mac_is_macdrawer(widget)) { if(visible) { if (!widget->testAttribute(Qt::WA_WState_ExplicitShowHide)) widget->show(); } else { widget->hide(); widget->setAttribute(Qt::WA_WState_ExplicitShowHide, false); } } } } /***************************************************************************** QWidgetPrivate member functions *****************************************************************************/ bool QWidgetPrivate::qt_mac_update_sizer(QWidget *w, int up) { // I'm not sure what "up" is if(!w || !w->isWindow()) return false; QTLWExtra *topData = w->d_func()->topData(); QWExtra *extraData = w->d_func()->extraData(); // topData->resizer is only 4 bits, so subtracting -1 from zero causes bad stuff // to happen, prevent that here (you really want the thing hidden). if (up >= 0 || topData->resizer != 0) topData->resizer += up; OSWindowRef windowRef = qt_mac_window_for(OSViewRef(w->winId())); { #ifndef QT_MAC_USE_COCOA WindowClass wclass; GetWindowClass(windowRef, &wclass); if(!(GetAvailableWindowAttributes(wclass) & kWindowResizableAttribute)) return true; #endif } bool remove_grip = (topData->resizer || (w->windowFlags() & Qt::FramelessWindowHint) || (extraData->maxw && extraData->maxh && extraData->maxw == extraData->minw && extraData->maxh == extraData->minh)); #ifndef QT_MAC_USE_COCOA WindowAttributes attr; GetWindowAttributes(windowRef, &attr); if(remove_grip) { if(attr & kWindowResizableAttribute) { ChangeWindowAttributes(qt_mac_window_for(w), kWindowNoAttributes, kWindowResizableAttribute); ReshapeCustomWindow(qt_mac_window_for(w)); } } else if(!(attr & kWindowResizableAttribute)) { ChangeWindowAttributes(windowRef, kWindowResizableAttribute, kWindowNoAttributes); ReshapeCustomWindow(windowRef); } #else [windowRef setShowsResizeIndicator:!remove_grip]; #endif return true; } void QWidgetPrivate::qt_clean_root_win() { #ifdef QT_MAC_USE_COCOA [qt_root_win release]; #else if(!qt_root_win) return; CFRelease(qt_root_win); #endif qt_root_win = 0; } bool QWidgetPrivate::qt_create_root_win() { if(qt_root_win) return false; const QSize desktopSize = qt_mac_desktopSize(); QRect desktopRect(QPoint(0, 0), desktopSize); #ifdef QT_MAC_USE_COCOA qt_root_win = qt_mac_create_window(0, kOverlayWindowClass, NSBorderlessWindowMask, desktopRect); #else WindowAttributes wattr = (kWindowCompositingAttribute | kWindowStandardHandlerAttribute); qt_root_win = qt_mac_create_window(0, kOverlayWindowClass, wattr, desktopRect); #endif if(!qt_root_win) return false; qAddPostRoutine(qt_clean_root_win); return true; } bool QWidgetPrivate::qt_widget_rgn(QWidget *widget, short wcode, RgnHandle rgn, bool force = false) { bool ret = false; #ifndef QT_MAC_USE_COCOA switch(wcode) { case kWindowStructureRgn: { if(widget) { if(widget->d_func()->extra && !widget->d_func()->extra->mask.isEmpty()) { QRegion rin = qt_mac_convert_mac_region(rgn); if(!rin.isEmpty()) { QPoint rin_tl = rin.boundingRect().topLeft(); //in offset rin.translate(-rin_tl.x(), -rin_tl.y()); //bring into same space as below QRegion mask = widget->d_func()->extra->mask; Qt::WindowFlags flags = widget->windowFlags(); if(widget->isWindow() && !(flags & Qt::FramelessWindowHint || (flags & Qt::CustomizeWindowHint && !(flags & Qt::WindowTitleHint)))) { QRegion title; { QMacSmartQuickDrawRegion rgn(qt_mac_get_rgn()); GetWindowRegion(qt_mac_window_for(widget), kWindowTitleBarRgn, rgn); title = qt_mac_convert_mac_region(rgn); } QRect br = title.boundingRect(); mask.translate(0, br.height()); //put the mask 'under' the title bar.. title.translate(-br.x(), -br.y()); mask += title; } QRegion cr = rin & mask; cr.translate(rin_tl.x(), rin_tl.y()); //translate back to incoming space CopyRgn(QMacSmartQuickDrawRegion(cr.toQDRgn()), rgn); } ret = true; } else if(force) { QRegion cr(widget->geometry()); CopyRgn(QMacSmartQuickDrawRegion(cr.toQDRgn()), rgn); ret = true; } } break; } default: break; } //qDebug() << widget << ret << wcode << qt_mac_convert_mac_region(rgn); #else Q_UNUSED(widget); Q_UNUSED(wcode); Q_UNUSED(rgn); Q_UNUSED(force); #endif return ret; } /***************************************************************************** QWidget member functions *****************************************************************************/ void QWidgetPrivate::determineWindowClass() { Q_Q(QWidget); #if !defined(QT_NO_MAINWINDOW) && !defined(QT_NO_TOOLBAR) // Make sure that QMainWindow has the MacWindowToolBarButtonHint when the // unifiedTitleAndToolBarOnMac property is ON. This is to avoid reentry of // setParent() triggered by the QToolBar::event(QEvent::ParentChange). QMainWindow *mainWindow = qobject_cast(q); if (mainWindow && mainWindow->unifiedTitleAndToolBarOnMac()) { data.window_flags |= Qt::MacWindowToolBarButtonHint; } #endif #ifndef QT_MAC_USE_COCOA // ### COCOA:Interleave these better! const Qt::WindowType type = q->windowType(); Qt::WindowFlags &flags = data.window_flags; const bool popup = (type == Qt::Popup); if (type == Qt::ToolTip || type == Qt::SplashScreen || popup) flags |= Qt::FramelessWindowHint; WindowClass wclass = kSheetWindowClass; if(qt_mac_is_macdrawer(q)) wclass = kDrawerWindowClass; else if (q->testAttribute(Qt::WA_ShowModal) && flags & Qt::CustomizeWindowHint) wclass = kDocumentWindowClass; else if(popup || (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5 && type == Qt::SplashScreen)) wclass = kModalWindowClass; else if(q->testAttribute(Qt::WA_ShowModal)) wclass = kMovableModalWindowClass; else if(type == Qt::ToolTip) wclass = kHelpWindowClass; else if(type == Qt::Tool || (QSysInfo::MacintoshVersion < QSysInfo::MV_10_5 && type == Qt::SplashScreen)) wclass = kFloatingWindowClass; else wclass = kDocumentWindowClass; WindowGroupRef grp = 0; WindowAttributes wattr = (kWindowCompositingAttribute | kWindowStandardHandlerAttribute); if (q->testAttribute(Qt::WA_MacFrameworkScaled)) wattr |= kWindowFrameworkScaledAttribute; if(qt_mac_is_macsheet(q)) { //grp = GetWindowGroupOfClass(kMovableModalWindowClass); wclass = kSheetWindowClass; } else { grp = GetWindowGroupOfClass(wclass); // Shift things around a bit to get the correct window class based on the presence // (or lack) of the border. bool customize = flags & Qt::CustomizeWindowHint; bool framelessWindow = (flags & Qt::FramelessWindowHint || (customize && !(flags & Qt::WindowTitleHint))); if (framelessWindow) { if(wclass == kDocumentWindowClass) { wattr |= kWindowNoTitleBarAttribute; } else if(wclass == kFloatingWindowClass) { wattr |= kWindowNoTitleBarAttribute; } else if (wclass == kMovableModalWindowClass) { wclass = kModalWindowClass; } } else { if(wclass != kModalWindowClass) wattr |= kWindowResizableAttribute; } // Only add extra decorations (well, buttons) for widgets that can have them // and have an actual border we can put them on. if(wclass != kModalWindowClass && wclass != kMovableModalWindowClass && wclass != kSheetWindowClass && wclass != kPlainWindowClass && !framelessWindow && wclass != kDrawerWindowClass && wclass != kHelpWindowClass) { if (flags & Qt::WindowMaximizeButtonHint) wattr |= kWindowFullZoomAttribute; if (flags & Qt::WindowMinimizeButtonHint) wattr |= kWindowCollapseBoxAttribute; if (flags & Qt::WindowSystemMenuHint || flags & Qt::WindowCloseButtonHint) wattr |= kWindowCloseBoxAttribute; if (flags & Qt::MacWindowToolBarButtonHint) wattr |= kWindowToolbarButtonAttribute; } else { // Clear these hints so that we aren't call them on invalid windows flags &= ~(Qt::WindowMaximizeButtonHint | Qt::WindowMinimizeButtonHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint); } } if((popup || type == Qt::Tool) && !q->isModal()) wattr |= kWindowHideOnSuspendAttribute; wattr |= kWindowLiveResizeAttribute; #ifdef DEBUG_WINDOW_CREATE #define ADD_DEBUG_WINDOW_NAME(x) { x, #x } struct { UInt32 tag; const char *name; } known_attribs[] = { ADD_DEBUG_WINDOW_NAME(kWindowCompositingAttribute), ADD_DEBUG_WINDOW_NAME(kWindowStandardHandlerAttribute), ADD_DEBUG_WINDOW_NAME(kWindowMetalAttribute), ADD_DEBUG_WINDOW_NAME(kWindowHideOnSuspendAttribute), ADD_DEBUG_WINDOW_NAME(kWindowStandardHandlerAttribute), ADD_DEBUG_WINDOW_NAME(kWindowCollapseBoxAttribute), ADD_DEBUG_WINDOW_NAME(kWindowHorizontalZoomAttribute), ADD_DEBUG_WINDOW_NAME(kWindowVerticalZoomAttribute), ADD_DEBUG_WINDOW_NAME(kWindowResizableAttribute), ADD_DEBUG_WINDOW_NAME(kWindowNoActivatesAttribute), ADD_DEBUG_WINDOW_NAME(kWindowNoUpdatesAttribute), ADD_DEBUG_WINDOW_NAME(kWindowOpaqueForEventsAttribute), ADD_DEBUG_WINDOW_NAME(kWindowLiveResizeAttribute), ADD_DEBUG_WINDOW_NAME(kWindowCloseBoxAttribute), ADD_DEBUG_WINDOW_NAME(kWindowHideOnSuspendAttribute), { 0, 0 } }, known_classes[] = { ADD_DEBUG_WINDOW_NAME(kHelpWindowClass), ADD_DEBUG_WINDOW_NAME(kPlainWindowClass), ADD_DEBUG_WINDOW_NAME(kDrawerWindowClass), ADD_DEBUG_WINDOW_NAME(kUtilityWindowClass), ADD_DEBUG_WINDOW_NAME(kToolbarWindowClass), ADD_DEBUG_WINDOW_NAME(kSheetWindowClass), ADD_DEBUG_WINDOW_NAME(kFloatingWindowClass), ADD_DEBUG_WINDOW_NAME(kUtilityWindowClass), ADD_DEBUG_WINDOW_NAME(kDocumentWindowClass), ADD_DEBUG_WINDOW_NAME(kToolbarWindowClass), ADD_DEBUG_WINDOW_NAME(kMovableModalWindowClass), ADD_DEBUG_WINDOW_NAME(kModalWindowClass), { 0, 0 } }; qDebug("Qt: internal: ************* Creating new window %p (%s::%s)", q, q->metaObject()->className(), q->objectName().toLocal8Bit().constData()); bool found_class = false; for(int i = 0; known_classes[i].name; i++) { if(wclass == known_classes[i].tag) { found_class = true; qDebug("Qt: internal: ** Class: %s", known_classes[i].name); break; } } if(!found_class) qDebug("Qt: internal: !! Class: Unknown! (%d)", (int)wclass); if(wattr) { WindowAttributes tmp_wattr = wattr; qDebug("Qt: internal: ** Attributes:"); for(int i = 0; tmp_wattr && known_attribs[i].name; i++) { if((tmp_wattr & known_attribs[i].tag) == known_attribs[i].tag) { tmp_wattr ^= known_attribs[i].tag; qDebug("Qt: internal: * %s %s", known_attribs[i].name, (GetAvailableWindowAttributes(wclass) & known_attribs[i].tag) ? "" : "(*)"); } } if(tmp_wattr) qDebug("Qt: internal: !! Attributes: Unknown (%d)", (int)tmp_wattr); } #endif /* Just to be extra careful we will change to the kUtilityWindowClass if the requested attributes cannot be used */ if((GetAvailableWindowAttributes(wclass) & wattr) != wattr) { WindowClass tmp_class = wclass; if(wclass == kToolbarWindowClass || wclass == kUtilityWindowClass) wclass = kFloatingWindowClass; if(tmp_class != wclass) { if(!grp) grp = GetWindowGroupOfClass(wclass); wclass = tmp_class; } } topData()->wclass = wclass; topData()->wattr = wattr; #else const Qt::WindowType type = q->windowType(); Qt::WindowFlags &flags = data.window_flags; const bool popup = (type == Qt::Popup); if (type == Qt::ToolTip || type == Qt::SplashScreen || popup) flags |= Qt::FramelessWindowHint; WindowClass wclass = kSheetWindowClass; if(qt_mac_is_macdrawer(q)) wclass = kDrawerWindowClass; else if (q->testAttribute(Qt::WA_ShowModal) && flags & Qt::CustomizeWindowHint) wclass = kDocumentWindowClass; else if(popup || (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5 && type == Qt::SplashScreen)) wclass = kModalWindowClass; else if(q->testAttribute(Qt::WA_ShowModal) || type == Qt::Dialog) wclass = kMovableModalWindowClass; else if(type == Qt::ToolTip) wclass = kHelpWindowClass; else if(type == Qt::Tool || (QSysInfo::MacintoshVersion < QSysInfo::MV_10_5 && type == Qt::SplashScreen)) wclass = kFloatingWindowClass; else wclass = kDocumentWindowClass; WindowAttributes wattr = NSBorderlessWindowMask; if(qt_mac_is_macsheet(q)) { //grp = GetWindowGroupOfClass(kMovableModalWindowClass); wclass = kSheetWindowClass; wattr = NSTitledWindowMask | NSResizableWindowMask; } else { #ifndef QT_MAC_USE_COCOA grp = GetWindowGroupOfClass(wclass); #endif // Shift things around a bit to get the correct window class based on the presence // (or lack) of the border. bool customize = flags & Qt::CustomizeWindowHint; bool framelessWindow = (flags & Qt::FramelessWindowHint || (customize && !(flags & Qt::WindowTitleHint))); if (framelessWindow) { if (wclass == kDocumentWindowClass) { wclass = kSimpleWindowClass; } else if (wclass == kFloatingWindowClass) { wclass = kToolbarWindowClass; } else if (wclass == kMovableModalWindowClass) { wclass = kModalWindowClass; } } else { wattr |= NSTitledWindowMask; if (wclass != kModalWindowClass) wattr |= NSResizableWindowMask; } // Only add extra decorations (well, buttons) for widgets that can have them // and have an actual border we can put them on. if (wclass != kModalWindowClass && wclass != kSheetWindowClass && wclass != kPlainWindowClass && !framelessWindow && wclass != kDrawerWindowClass && wclass != kHelpWindowClass) { if (flags & Qt::WindowMinimizeButtonHint) wattr |= NSMiniaturizableWindowMask; if (flags & Qt::WindowSystemMenuHint || flags & Qt::WindowCloseButtonHint) wattr |= NSClosableWindowMask; } else { // Clear these hints so that we aren't call them on invalid windows flags &= ~(Qt::WindowMaximizeButtonHint | Qt::WindowMinimizeButtonHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint); } } if (q->testAttribute(Qt::WA_MacBrushedMetal)) wattr |= NSTexturedBackgroundWindowMask; #ifdef DEBUG_WINDOW_CREATE #define ADD_DEBUG_WINDOW_NAME(x) { x, #x } struct { UInt32 tag; const char *name; } known_attribs[] = { ADD_DEBUG_WINDOW_NAME(kWindowCompositingAttribute), ADD_DEBUG_WINDOW_NAME(kWindowStandardHandlerAttribute), ADD_DEBUG_WINDOW_NAME(kWindowMetalAttribute), ADD_DEBUG_WINDOW_NAME(kWindowHideOnSuspendAttribute), ADD_DEBUG_WINDOW_NAME(kWindowStandardHandlerAttribute), ADD_DEBUG_WINDOW_NAME(kWindowCollapseBoxAttribute), ADD_DEBUG_WINDOW_NAME(kWindowHorizontalZoomAttribute), ADD_DEBUG_WINDOW_NAME(kWindowVerticalZoomAttribute), ADD_DEBUG_WINDOW_NAME(kWindowResizableAttribute), ADD_DEBUG_WINDOW_NAME(kWindowNoActivatesAttribute), ADD_DEBUG_WINDOW_NAME(kWindowNoUpdatesAttribute), ADD_DEBUG_WINDOW_NAME(kWindowOpaqueForEventsAttribute), ADD_DEBUG_WINDOW_NAME(kWindowLiveResizeAttribute), ADD_DEBUG_WINDOW_NAME(kWindowCloseBoxAttribute), ADD_DEBUG_WINDOW_NAME(kWindowHideOnSuspendAttribute), { 0, 0 } }, known_classes[] = { ADD_DEBUG_WINDOW_NAME(kHelpWindowClass), ADD_DEBUG_WINDOW_NAME(kPlainWindowClass), ADD_DEBUG_WINDOW_NAME(kDrawerWindowClass), ADD_DEBUG_WINDOW_NAME(kUtilityWindowClass), ADD_DEBUG_WINDOW_NAME(kToolbarWindowClass), ADD_DEBUG_WINDOW_NAME(kSheetWindowClass), ADD_DEBUG_WINDOW_NAME(kFloatingWindowClass), ADD_DEBUG_WINDOW_NAME(kUtilityWindowClass), ADD_DEBUG_WINDOW_NAME(kDocumentWindowClass), ADD_DEBUG_WINDOW_NAME(kToolbarWindowClass), ADD_DEBUG_WINDOW_NAME(kMovableModalWindowClass), ADD_DEBUG_WINDOW_NAME(kModalWindowClass), { 0, 0 } }; qDebug("Qt: internal: ************* Creating new window %p (%s::%s)", q, q->metaObject()->className(), q->objectName().toLocal8Bit().constData()); bool found_class = false; for(int i = 0; known_classes[i].name; i++) { if(wclass == known_classes[i].tag) { found_class = true; qDebug("Qt: internal: ** Class: %s", known_classes[i].name); break; } } if(!found_class) qDebug("Qt: internal: !! Class: Unknown! (%d)", (int)wclass); if(wattr) { WindowAttributes tmp_wattr = wattr; qDebug("Qt: internal: ** Attributes:"); for(int i = 0; tmp_wattr && known_attribs[i].name; i++) { if((tmp_wattr & known_attribs[i].tag) == known_attribs[i].tag) { tmp_wattr ^= known_attribs[i].tag; qDebug("Qt: internal: * %s %s", known_attribs[i].name, (GetAvailableWindowAttributes(wclass) & known_attribs[i].tag) ? "" : "(*)"); } } if(tmp_wattr) qDebug("Qt: internal: !! Attributes: Unknown (%d)", (int)tmp_wattr); } #endif #ifndef QT_MAC_USE_COCOA /* Just to be extra careful we will change to the kUtilityWindowClass if the requested attributes cannot be used */ if((GetAvailableWindowAttributes(wclass) & wattr) != wattr) { WindowClass tmp_class = wclass; if(wclass == kToolbarWindowClass || wclass == kUtilityWindowClass) wclass = kFloatingWindowClass; if(tmp_class != wclass) { if(!grp) grp = GetWindowGroupOfClass(wclass); wclass = tmp_class; } } #endif #endif topData()->wclass = wclass; topData()->wattr = wattr; } #ifndef QT_MAC_USE_COCOA // This is handled in Cocoa via our category. void QWidgetPrivate::initWindowPtr() { Q_Q(QWidget); OSWindowRef windowRef = qt_mac_window_for(qt_mac_nativeview_for(q)); //do not create! if(!windowRef) return; QWidget *window = q->window(), *oldWindow = 0; if(GetWindowProperty(windowRef, kWidgetCreatorQt, kWidgetPropertyQWidget, sizeof(oldWindow), 0, &oldWindow) == noErr) { Q_ASSERT(window == oldWindow); return; } if(SetWindowProperty(windowRef, kWidgetCreatorQt, kWidgetPropertyQWidget, sizeof(window), &window) != noErr) qWarning("Qt:Internal error (%s:%d)", __FILE__, __LINE__); //no real way to recover if(!q->windowType() != Qt::Desktop) { //setup an event callback handler on the window InstallWindowEventHandler(windowRef, make_win_eventUPP(), GetEventTypeCount(window_events), window_events, static_cast(qApp), &window_event); } } void QWidgetPrivate::finishCreateWindow_sys_Carbon(OSWindowRef windowRef) { Q_Q(QWidget); const Qt::WindowType type = q->windowType(); Qt::WindowFlags &flags = data.window_flags; QWidget *parentWidget = q->parentWidget(); const bool desktop = (type == Qt::Desktop); const bool dialog = (type == Qt::Dialog || type == Qt::Sheet || type == Qt::Drawer || (flags & Qt::MSWindowsFixedSizeDialogHint)); QTLWExtra *topExtra = topData(); quint32 wattr = topExtra->wattr; if (!desktop) SetAutomaticControlDragTrackingEnabledForWindow(windowRef, true); HIWindowChangeFeatures(windowRef, kWindowCanCollapse, 0); if (wattr & kWindowHideOnSuspendAttribute) HIWindowChangeAvailability(windowRef, kHIWindowExposeHidden, 0); else HIWindowChangeAvailability(windowRef, 0, kHIWindowExposeHidden); if ((flags & Qt::WindowStaysOnTopHint)) ChangeWindowAttributes(windowRef, kWindowNoAttributes, kWindowHideOnSuspendAttribute); if (qt_mac_is_macdrawer(q) && parentWidget) SetDrawerParent(windowRef, qt_mac_window_for (parentWidget)); if (topExtra->group) { qt_mac_release_window_group(topExtra->group); topExtra->group = 0; } if (type == Qt::ToolTip) qt_mac_set_window_group_to_tooltip(windowRef); else if (type == Qt::Popup && (flags & Qt::WindowStaysOnTopHint)) qt_mac_set_window_group_to_popup(windowRef); else if (flags & Qt::WindowStaysOnTopHint) qt_mac_set_window_group_to_stays_on_top(windowRef, type); else if (dialog) SetWindowGroup(windowRef, GetWindowGroupOfClass(kMovableModalWindowClass)); #ifdef DEBUG_WINDOW_CREATE if (WindowGroupRef grpf = GetWindowGroup(windowRef)) { QCFString cfname; CopyWindowGroupName(grpf, &cfname); SInt32 lvl; GetWindowGroupLevel(grpf, &lvl); const char *from = "Default"; if (topExtra && grpf == topData()->group) from = "Created"; else if (grpf == grp) from = "Copied"; qDebug("Qt: internal: With window group '%s' [%p] @ %d: %s", static_cast(cfname).toLatin1().constData(), grpf, (int)lvl, from); } else { qDebug("Qt: internal: No window group!!!"); } HIWindowAvailability hi_avail = 0; if (HIWindowGetAvailability(windowRef, &hi_avail) == noErr) { struct { UInt32 tag; const char *name; } known_avail[] = { ADD_DEBUG_WINDOW_NAME(kHIWindowExposeHidden), { 0, 0 } }; qDebug("Qt: internal: ** HIWindowAvailibility:"); for (int i = 0; hi_avail && known_avail[i].name; i++) { if ((hi_avail & known_avail[i].tag) == known_avail[i].tag) { hi_avail ^= known_avail[i].tag; qDebug("Qt: internal: * %s", known_avail[i].name); } } if (hi_avail) qDebug("Qt: internal: !! Attributes: Unknown (%d)", (int)hi_avail); } #undef ADD_DEBUG_WINDOW_NAME #endif if (extra && !extra->mask.isEmpty()) ReshapeCustomWindow(windowRef); SetWindowModality(windowRef, kWindowModalityNone, 0); if (qt_mac_is_macdrawer(q)) SetDrawerOffsets(windowRef, 0.0, 25.0); data.fstrut_dirty = true; // when we create a toplevel widget, the frame strut should be dirty HIViewRef hiview = (HIViewRef)data.winid; HIViewRef window_hiview = qt_mac_get_contentview_for(windowRef); if(!hiview) { hiview = qt_mac_create_widget(q, this, window_hiview); setWinId((WId)hiview); } else { HIViewAddSubview(window_hiview, hiview); } if (hiview) { Rect win_rect; GetWindowBounds(qt_mac_window_for (window_hiview), kWindowContentRgn, &win_rect); HIRect bounds = CGRectMake(0, 0, win_rect.right-win_rect.left, win_rect.bottom-win_rect.top); HIViewSetFrame(hiview, &bounds); HIViewSetVisible(hiview, true); if (q->testAttribute(Qt::WA_DropSiteRegistered)) registerDropSite(true); transferChildren(); } initWindowPtr(); if (topExtra->posFromMove) { updateFrameStrut(); const QRect &fStrut = frameStrut(); Rect r; SetRect(&r, data.crect.left(), data.crect.top(), data.crect.right() + 1, data.crect.bottom() + 1); SetRect(&r, r.left + fStrut.left(), r.top + fStrut.top(), (r.left + fStrut.left() + data.crect.width()) - fStrut.right(), (r.top + fStrut.top() + data.crect.height()) - fStrut.bottom()); SetWindowBounds(windowRef, kWindowContentRgn, &r); topExtra->posFromMove = false; } if (q->testAttribute(Qt::WA_WState_WindowOpacitySet)){ q->setWindowOpacity(topExtra->opacity / 255.0f); } else if (qt_mac_is_macsheet(q)){ SetThemeWindowBackground(qt_mac_window_for(q), kThemeBrushSheetBackgroundTransparent, true); CGFloat alpha = 0; GetWindowAlpha(qt_mac_window_for(q), &alpha); if (alpha == 1){ // For some reason the 'SetThemeWindowBackground' does not seem // to work. So we do this little hack until it hopefully starts to // work in newer versions of mac OS. q->setWindowOpacity(0.95f); q->setAttribute(Qt::WA_WState_WindowOpacitySet, false); } } else{ // If the window has been recreated after beeing e.g. a sheet, // make sure that we don't report a faulty opacity: q->setWindowOpacity(1.0f); q->setAttribute(Qt::WA_WState_WindowOpacitySet, false); } // Since we only now have a window, sync our state. macUpdateHideOnSuspend(); macUpdateOpaqueSizeGrip(); macUpdateMetalAttribute(); macUpdateIgnoreMouseEvents(); setWindowTitle_helper(extra->topextra->caption); setWindowIconText_helper(extra->topextra->iconText); setWindowFilePath_helper(extra->topextra->filePath); setWindowModified_sys(q->isWindowModified()); updateFrameStrut(); qt_mac_update_sizer(q); applyMaxAndMinSizeOnWindow(); } #else // QT_MAC_USE_COCOA void QWidgetPrivate::finishCreateWindow_sys_Cocoa(void * /*NSWindow * */ voidWindowRef) { Q_Q(QWidget); QMacCocoaAutoReleasePool pool; NSWindow *windowRef = static_cast(voidWindowRef); const Qt::WindowType type = q->windowType(); Qt::WindowFlags &flags = data.window_flags; QWidget *parentWidget = q->parentWidget(); const bool popup = (type == Qt::Popup); const bool dialog = (type == Qt::Dialog || type == Qt::Sheet || type == Qt::Drawer || (flags & Qt::MSWindowsFixedSizeDialogHint)); QTLWExtra *topExtra = topData(); if ((popup || type == Qt::Tool || type == Qt::ToolTip) && !q->isModal()) { [windowRef setHidesOnDeactivate:YES]; } else { [windowRef setHidesOnDeactivate:NO]; } [windowRef setHasShadow:YES]; Q_UNUSED(parentWidget); Q_UNUSED(dialog); data.fstrut_dirty = true; // when we create a toplevel widget, the frame strut should be dirty OSViewRef nsview = (OSViewRef)data.winid; OSViewRef window_contentview = qt_mac_get_contentview_for(windowRef); if (!nsview) { nsview = qt_mac_create_widget(q, this, window_contentview); setWinId(WId(nsview)); } else { [window_contentview addSubview:nsview]; } if (nsview) { NSRect bounds = [window_contentview bounds]; [nsview setFrame:bounds]; [nsview setHidden:NO]; if (q->testAttribute(Qt::WA_DropSiteRegistered)) registerDropSite(true); transferChildren(); } if (topExtra->posFromMove) { updateFrameStrut(); const QRect &fStrut = frameStrut(); const QRect &crect = data.crect; const QRect frameRect(QPoint(crect.left(), crect.top()), QSize(fStrut.left() + fStrut.right() + crect.width(), fStrut.top() + fStrut.bottom() + crect.height())); NSRect cocoaFrameRect = NSMakeRect(frameRect.x(), flipYCoordinate(frameRect.bottom() + 1), frameRect.width(), frameRect.height()); [windowRef setFrame:cocoaFrameRect display:NO]; topExtra->posFromMove = false; } if (q->testAttribute(Qt::WA_WState_WindowOpacitySet)){ q->setWindowOpacity(topExtra->opacity / 255.0f); } else if (qt_mac_is_macsheet(q)){ CGFloat alpha = [qt_mac_window_for(q) alphaValue]; if (alpha >= 1.0) { q->setWindowOpacity(0.95f); q->setAttribute(Qt::WA_WState_WindowOpacitySet, false); } } else{ // If the window has been recreated after beeing e.g. a sheet, // make sure that we don't report a faulty opacity: q->setWindowOpacity(1.0f); q->setAttribute(Qt::WA_WState_WindowOpacitySet, false); } macUpdateHideOnSuspend(); macUpdateOpaqueSizeGrip(); macUpdateIgnoreMouseEvents(); setWindowTitle_helper(extra->topextra->caption); setWindowIconText_helper(extra->topextra->iconText); setWindowModified_sys(q->isWindowModified()); updateFrameStrut(); syncCocoaMask(); macUpdateIsOpaque(); qt_mac_update_sizer(q); applyMaxAndMinSizeOnWindow(); } #endif // QT_MAC_USE_COCOA /* Recreates widget window. Useful if immutable properties for it has changed. */ void QWidgetPrivate::recreateMacWindow() { Q_Q(QWidget); OSViewRef myView = qt_mac_nativeview_for(q); OSWindowRef oldWindow = qt_mac_window_for(myView); #ifndef QT_MAC_USE_COCOA HIViewRemoveFromSuperview(myView); determineWindowClass(); createWindow_sys(); if (QMainWindowLayout *mwl = qobject_cast(q->layout())) { mwl->updateHIToolBarStatus(); } if (IsWindowVisible(oldWindow)) show_sys(); #else QMacCocoaAutoReleasePool pool; [myView removeFromSuperview]; determineWindowClass(); createWindow_sys(); if (NSToolbar *toolbar = [oldWindow toolbar]) { OSWindowRef newWindow = qt_mac_window_for(myView); [newWindow setToolbar:toolbar]; [toolbar setVisible:[toolbar isVisible]]; } if ([oldWindow isVisible]){ if ([oldWindow isSheet]) [NSApp endSheet:oldWindow]; [oldWindow orderOut:oldWindow]; show_sys(); } #endif // QT_MAC_USE_COCOA // Release the window after creating the new window, because releasing it early // may cause the app to quit ("close on last window closed attribute") qt_mac_destructWindow(oldWindow); } void QWidgetPrivate::createWindow_sys() { Q_Q(QWidget); Qt::WindowFlags &flags = data.window_flags; QWidget *parentWidget = q->parentWidget(); QTLWExtra *topExtra = topData(); if (topExtra->embedded) return; // Simply return because this view "is" the top window. quint32 wattr = topExtra->wattr; if(parentWidget && (parentWidget->window()->windowFlags() & Qt::WindowStaysOnTopHint)) // If our parent has Qt::WStyle_StaysOnTop, so must we flags |= Qt::WindowStaysOnTopHint; data.fstrut_dirty = true; OSWindowRef windowRef = qt_mac_create_window(q, topExtra->wclass, wattr, data.crect); if (windowRef == 0) qWarning("QWidget: Internal error: %s:%d: If you reach this error please contact Qt Support and include the\n" " WidgetFlags used in creating the widget.", __FILE__, __LINE__); #ifndef QT_MAC_USE_COCOA finishCreateWindow_sys_Carbon(windowRef); #else finishCreateWindow_sys_Cocoa(windowRef); #endif } void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyOldWindow) { Q_Q(QWidget); OSViewRef destroyid = 0; #ifndef QT_MAC_USE_COCOA window_event = 0; #endif Qt::WindowType type = q->windowType(); Qt::WindowFlags flags = data.window_flags; QWidget *parentWidget = q->parentWidget(); bool topLevel = (flags & Qt::Window); bool popup = (type == Qt::Popup); bool dialog = (type == Qt::Dialog || type == Qt::Sheet || type == Qt::Drawer || (flags & Qt::MSWindowsFixedSizeDialogHint)); bool desktop = (type == Qt::Desktop); // Determine this early for top-levels so, we can use it later. if (topLevel) determineWindowClass(); if (desktop) { QSize desktopSize = qt_mac_desktopSize(); q->setAttribute(Qt::WA_WState_Visible); data.crect.setRect(0, 0, desktopSize.width(), desktopSize.height()); dialog = popup = false; // force these flags off } else { q->setAttribute(Qt::WA_WState_Visible, false); if (topLevel && (type != Qt::Drawer)) { if (QDesktopWidget *dsk = QApplication::desktop()) { // calc pos/size from screen const bool wasResized = q->testAttribute(Qt::WA_Resized); const bool wasMoved = q->testAttribute(Qt::WA_Moved); int deskn = dsk->primaryScreen(); if (parentWidget && parentWidget->windowType() != Qt::Desktop) deskn = dsk->screenNumber(parentWidget); QRect screenGeo = dsk->screenGeometry(deskn); if (!wasResized) { #ifndef QT_MAC_USE_COCOA data.crect.setSize(QSize(screenGeo.width()/2, 4*screenGeo.height()/10)); #else NSRect newRect = [NSWindow frameRectForContentRect:NSMakeRect(0, 0, screenGeo.width() / 2., 4 * screenGeo.height() / 10.) styleMask:topData()->wattr]; data.crect.setSize(QSize(newRect.size.width, newRect.size.height)); #endif // Constrain to minimums and maximums we've set if (extra->minw > 0) data.crect.setWidth(qMax(extra->minw, data.crect.width())); if (extra->minh > 0) data.crect.setHeight(qMax(extra->minh, data.crect.height())); if (extra->maxw > 0) data.crect.setWidth(qMin(extra->maxw, data.crect.width())); if (extra->maxh > 0) data.crect.setHeight(qMin(extra->maxh, data.crect.height())); } if (!wasMoved && !q->testAttribute(Qt::WA_DontShowOnScreen)) data.crect.moveTopLeft(QPoint(screenGeo.width()/4, 3 * screenGeo.height() / 10)); } } } if(!window) // always initialize initializeWindow=true; hd = 0; if(window) { // override the old window (with a new NSView) OSViewRef nativeView = OSViewRef(window); OSViewRef parent = 0; #ifndef QT_MAC_USE_COCOA CFRetain(nativeView); #else [nativeView retain]; #endif if (destroyOldWindow) destroyid = qt_mac_nativeview_for(q); bool transfer = false; setWinId((WId)nativeView); #ifndef QT_MAC_USE_COCOA #ifndef HIViewInstallEventHandler // Macro taken from the CarbonEvents Header on Tiger #define HIViewInstallEventHandler( target, handler, numTypes, list, userData, outHandlerRef ) \ InstallEventHandler( HIObjectGetEventTarget( (HIObjectRef) (target) ), (handler), (numTypes), (list), (userData), (outHandlerRef) ) #endif HIViewInstallEventHandler(nativeView, make_widget_eventUPP(), GetEventTypeCount(widget_events), widget_events, 0, 0); #endif if(topLevel) { for(int i = 0; i < 2; ++i) { if(i == 1) { if(!initializeWindow) break; createWindow_sys(); } if(OSWindowRef windowref = qt_mac_window_for(nativeView)) { #ifndef QT_MAC_USE_COCOA CFRetain(windowref); #else [windowref retain]; #endif if (initializeWindow) { parent = qt_mac_get_contentview_for(windowref); } else { #ifndef QT_MAC_USE_COCOA parent = HIViewGetSuperview(nativeView); #else parent = [nativeView superview]; #endif } break; } } if(!parent) transfer = true; } else if (parentWidget) { // I need to be added to my parent, therefore my parent needs an NSView parentWidget->createWinId(); parent = qt_mac_nativeview_for(parentWidget); } if(parent != nativeView && parent) { #ifndef QT_MAC_USE_COCOA HIViewAddSubview(parent, nativeView); #else [parent addSubview:nativeView]; #endif } if(transfer) transferChildren(); data.fstrut_dirty = true; // we'll re calculate this later q->setAttribute(Qt::WA_WState_Visible, #ifndef QT_MAC_USE_COCOA HIViewIsVisible(nativeView) #else ![nativeView isHidden] #endif ); if(initializeWindow) { #ifndef QT_MAC_USE_COCOA HIRect bounds = CGRectMake(data.crect.x(), data.crect.y(), data.crect.width(), data.crect.height()); HIViewSetFrame(nativeView, &bounds); q->setAttribute(Qt::WA_WState_Visible, HIViewIsVisible(nativeView)); #else NSRect bounds = NSMakeRect(data.crect.x(), data.crect.y(), data.crect.width(), data.crect.height()); [nativeView setFrame:bounds]; q->setAttribute(Qt::WA_WState_Visible, [nativeView isHidden]); #endif } #ifndef QT_MAC_USE_COCOA initWindowPtr(); #endif } else if (desktop) { // desktop widget if (!qt_root_win) QWidgetPrivate::qt_create_root_win(); Q_ASSERT(qt_root_win); WId rootWinID = 0; #ifndef QT_MAC_USE_COCOA CFRetain(qt_root_win); if(HIViewRef rootContentView = HIViewGetRoot(qt_root_win)) { rootWinID = (WId)rootContentView; CFRetain(rootContentView); } #else [qt_root_win retain]; if (OSViewRef rootContentView = [qt_root_win contentView]) { rootWinID = (WId)rootContentView; [rootContentView retain]; } #endif setWinId(rootWinID); } else if (topLevel) { determineWindowClass(); if(OSViewRef osview = qt_mac_create_widget(q, this, 0)) { #ifndef QT_MAC_USE_COCOA HIRect bounds = CGRectMake(data.crect.x(), data.crect.y(), data.crect.width(), data.crect.height()); HIViewSetFrame(osview, &bounds); #else NSRect bounds = NSMakeRect(data.crect.x(), flipYCoordinate(data.crect.y()), data.crect.width(), data.crect.height()); [osview setFrame:bounds]; #endif setWinId((WId)osview); } } else { data.fstrut_dirty = false; // non-toplevel widgets don't have a frame, so no need to update the strut if(OSViewRef osview = qt_mac_create_widget(q, this, qt_mac_nativeview_for(parentWidget))) { #ifndef QT_MAC_USE_COCOA HIRect bounds = CGRectMake(data.crect.x(), data.crect.y(), data.crect.width(), data.crect.height()); HIViewSetFrame(osview, &bounds); setWinId((WId)osview); #else NSRect bounds = NSMakeRect(data.crect.x(), data.crect.y(), data.crect.width(), data.crect.height()); [osview setFrame:bounds]; setWinId((WId)osview); #endif if (q->testAttribute(Qt::WA_DropSiteRegistered)) registerDropSite(true); } } updateIsOpaque(); if (q->hasFocus()) setFocus_sys(); if (!topLevel && initializeWindow) setWSGeometry(); if (destroyid) qt_mac_destructView(destroyid); if (q->testAttribute(Qt::WA_AcceptTouchEvents)) registerTouchWindow(); } /*! Returns the QuickDraw handle of the widget. Use of this function is not portable. This function will return 0 if QuickDraw is not supported, or if the handle could not be created. \warning This function is only available on Mac OS X. */ Qt::HANDLE QWidget::macQDHandle() const { #ifndef QT_MAC_USE_COCOA return d_func()->qd_hd; #else return 0; #endif } /*! Returns the CoreGraphics handle of the widget. Use of this function is not portable. This function will return 0 if no painter context can be established, or if the handle could not be created. \warning This function is only available on Mac OS X. */ Qt::HANDLE QWidget::macCGHandle() const { return handle(); } void QWidget::destroy(bool destroyWindow, bool destroySubWindows) { Q_D(QWidget); if (!isWindow() && parentWidget()) parentWidget()->d_func()->invalidateBuffer(d->effectiveRectFor(geometry())); d->deactivateWidgetCleanup(); qt_mac_event_release(this); if(testAttribute(Qt::WA_WState_Created)) { QMacCocoaAutoReleasePool pool; setAttribute(Qt::WA_WState_Created, false); QObjectList chldrn = children(); for(int i = 0; i < chldrn.size(); i++) { // destroy all widget children QObject *obj = chldrn.at(i); if(obj->isWidgetType()) static_cast(obj)->destroy(destroySubWindows, destroySubWindows); } if(mac_mouse_grabber == this) releaseMouse(); if(mac_keyboard_grabber == this) releaseKeyboard(); if(testAttribute(Qt::WA_ShowModal)) // just be sure we leave modal QApplicationPrivate::leaveModal(this); else if((windowType() == Qt::Popup)) qApp->d_func()->closePopup(this); if (destroyWindow) { if(OSViewRef hiview = qt_mac_nativeview_for(this)) { OSWindowRef window = 0; NSDrawer *drawer = nil; #ifdef QT_MAC_USE_COCOA if (qt_mac_is_macdrawer(this)) { drawer = qt_mac_drawer_for(this); } else #endif if (isWindow()) window = qt_mac_window_for(hiview); // Because of how "destruct" works, we have to do just a normal release for the root_win. if (window && window == qt_root_win) { #ifndef QT_MAC_USE_COCOA CFRelease(hiview); #else [hiview release]; #endif } else { qt_mac_destructView(hiview); } if (drawer) qt_mac_destructDrawer(drawer); if (window) qt_mac_destructWindow(window); } } QT_TRY { d->setWinId(0); } QT_CATCH (const std::bad_alloc &) { // swallow - destructors must not throw } } } void QWidgetPrivate::transferChildren() { Q_Q(QWidget); if (!q->testAttribute(Qt::WA_WState_Created)) return; // Can't add any views anyway QObjectList chlist = q->children(); for (int i = 0; i < chlist.size(); ++i) { QObject *obj = chlist.at(i); if (obj->isWidgetType()) { QWidget *w = (QWidget *)obj; if (!w->isWindow()) { // This seems weird, no need to call it in a loop right? if (!topData()->caption.isEmpty()) setWindowTitle_helper(extra->topextra->caption); if (w->testAttribute(Qt::WA_WState_Created)) { #ifndef QT_MAC_USE_COCOA HIViewAddSubview(qt_mac_nativeview_for(q), qt_mac_nativeview_for(w)); #else // New NSWindows get an extra reference when drops are // registered (at least in 10.5) which means that we may // access the window later and get a crash (becasue our // widget is dead). Work around this be having the drop // site disabled until it is part of the new hierarchy. bool oldRegistered = w->testAttribute(Qt::WA_DropSiteRegistered); w->setAttribute(Qt::WA_DropSiteRegistered, false); [qt_mac_nativeview_for(w) retain]; [qt_mac_nativeview_for(w) removeFromSuperview]; [qt_mac_nativeview_for(q) addSubview:qt_mac_nativeview_for(w)]; [qt_mac_nativeview_for(w) release]; w->setAttribute(Qt::WA_DropSiteRegistered, oldRegistered); #endif } } } } } void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f) { Q_Q(QWidget); QMacCocoaAutoReleasePool pool; QTLWExtra *topData = maybeTopData(); bool wasCreated = q->testAttribute(Qt::WA_WState_Created); #ifdef QT_MAC_USE_COCOA bool wasWindow = q->isWindow(); #endif OSViewRef old_id = 0; if (q->isVisible() && q->parentWidget() && parent != q->parentWidget()) q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(q->geometry())); // Maintain the glWidgets list on parent change: remove "our" gl widgets // from the list on the old parent and grandparents. if (glWidgets.isEmpty() == false) { QWidget *current = q->parentWidget(); while (current) { for (QList::const_iterator it = glWidgets.constBegin(); it != glWidgets.constEnd(); ++it) current->d_func()->glWidgets.removeAll(*it); if (current->isWindow()) break; current = current->parentWidget(); } } #ifndef QT_MAC_USE_COCOA EventHandlerRef old_window_event = 0; #else bool oldToolbarVisible = false; NSDrawer *oldDrawer = nil; NSToolbar *oldToolbar = 0; #endif if (wasCreated && !(q->windowType() == Qt::Desktop)) { old_id = qt_mac_nativeview_for(q); #ifndef QT_MAC_USE_COCOA old_window_event = window_event; #else OSWindowRef oldWindow = qt_mac_window_for(old_id); if (qt_mac_is_macdrawer(q)) { oldDrawer = qt_mac_drawer_for(q); } if (wasWindow) { oldToolbar = [oldWindow toolbar]; [oldToolbar retain]; oldToolbarVisible = [oldToolbar isVisible]; [oldWindow setToolbar:nil]; } #endif } QWidget* oldtlw = q->window(); if (q->testAttribute(Qt::WA_DropSiteRegistered)) q->setAttribute(Qt::WA_DropSiteRegistered, false); //recreate and setup flags QObjectPrivate::setParent_helper(parent); QPoint pt = q->pos(); bool explicitlyHidden = q->testAttribute(Qt::WA_WState_Hidden) && q->testAttribute(Qt::WA_WState_ExplicitShowHide); if (wasCreated && !qt_isGenuineQWidget(q)) return; if ((data.window_flags & Qt::Sheet) && topData && topData->opacity == 242) q->setWindowOpacity(1.0f); setWinId(0); //do after the above because they may want the id data.window_flags = f; q->setAttribute(Qt::WA_WState_Created, false); q->setAttribute(Qt::WA_WState_Visible, false); q->setAttribute(Qt::WA_WState_Hidden, false); adjustFlags(data.window_flags, q); // keep compatibility with previous versions, we need to preserve the created state // (but we recreate the winId for the widget being reparented, again for compatibility) if (wasCreated || (!q->isWindow() && parent->testAttribute(Qt::WA_WState_Created))) { createWinId(); if (q->isWindow()) { #ifndef QT_MAC_USE_COCOA // We do this down below for wasCreated, so avoid doing this twice // (only for performance, it gets called a lot anyway). if (!wasCreated) { if (QMainWindowLayout *mwl = qobject_cast(q->layout())) { mwl->updateHIToolBarStatus(); } } #else // Simply transfer our toolbar over. Everything should stay put, unlike in Carbon. if (oldToolbar && !(f & Qt::FramelessWindowHint)) { OSWindowRef newWindow = qt_mac_window_for(q); [newWindow setToolbar:oldToolbar]; [oldToolbar release]; [oldToolbar setVisible:oldToolbarVisible]; } #endif } } if (q->isWindow() || (!parent || parent->isVisible()) || explicitlyHidden) q->setAttribute(Qt::WA_WState_Hidden); q->setAttribute(Qt::WA_WState_ExplicitShowHide, explicitlyHidden); if (wasCreated) { transferChildren(); #ifndef QT_MAC_USE_COCOA // If we were a unified window, We just transfered our toolbars out of the unified toolbar. // So redo the status one more time. It apparently is not an issue with Cocoa. if (q->isWindow()) { if (QMainWindowLayout *mwl = qobject_cast(q->layout())) { mwl->updateHIToolBarStatus(); } } #endif if (topData && (!topData->caption.isEmpty() || !topData->filePath.isEmpty())) setWindowTitle_helper(q->windowTitle()); } if (q->testAttribute(Qt::WA_AcceptDrops) || (!q->isWindow() && q->parentWidget() && q->parentWidget()->testAttribute(Qt::WA_DropSiteRegistered))) q->setAttribute(Qt::WA_DropSiteRegistered, true); //cleanup #ifndef QT_MAC_USE_COCOA if (old_window_event) RemoveEventHandler(old_window_event); #endif if (old_id) { //don't need old window anymore OSWindowRef window = (oldtlw == q) ? qt_mac_window_for(old_id) : 0; qt_mac_destructView(old_id); #ifdef QT_MAC_USE_COCOA if (oldDrawer) { qt_mac_destructDrawer(oldDrawer); } else #endif if (window) qt_mac_destructWindow(window); } // Maintain the glWidgets list on parent change: add "our" gl widgets // to the list on the new parent and grandparents. if (glWidgets.isEmpty() == false) { QWidget *current = q->parentWidget(); while (current) { current->d_func()->glWidgets += glWidgets; if (current->isWindow()) break; current = current->parentWidget(); } } invalidateBuffer(q->rect()); qt_event_request_window_change(q); } QPoint QWidget::mapToGlobal(const QPoint &pos) const { Q_D(const QWidget); if (!testAttribute(Qt::WA_WState_Created)) { QPoint p = pos + data->crect.topLeft(); return isWindow() ? p : parentWidget()->mapToGlobal(p); } #ifndef QT_MAC_USE_COCOA QPoint tmp = d->mapToWS(pos); HIPoint hi_pos = CGPointMake(tmp.x(), tmp.y()); HIViewConvertPoint(&hi_pos, qt_mac_nativeview_for(this), 0); Rect win_rect; GetWindowBounds(qt_mac_window_for(this), kWindowStructureRgn, &win_rect); return QPoint((int)hi_pos.x+win_rect.left, (int)hi_pos.y+win_rect.top); #else QPoint tmp = d->mapToWS(pos); NSPoint hi_pos = NSMakePoint(tmp.x(), tmp.y()); hi_pos = [qt_mac_nativeview_for(this) convertPoint:hi_pos toView:nil]; NSRect win_rect = [qt_mac_window_for(this) frame]; hi_pos.x += win_rect.origin.x; hi_pos.y += win_rect.origin.y; // If we aren't the desktop we need to flip, if you flip the desktop on itself, you get the other problem. return ((window()->windowFlags() & Qt::Desktop) == Qt::Desktop) ? QPointF(hi_pos.x, hi_pos.y).toPoint() : flipPoint(hi_pos).toPoint(); #endif } QPoint QWidget::mapFromGlobal(const QPoint &pos) const { Q_D(const QWidget); if (!testAttribute(Qt::WA_WState_Created)) { QPoint p = isWindow() ? pos : parentWidget()->mapFromGlobal(pos); return p - data->crect.topLeft(); } #ifndef QT_MAC_USE_COCOA Rect win_rect; GetWindowBounds(qt_mac_window_for(this), kWindowStructureRgn, &win_rect); HIPoint hi_pos = CGPointMake(pos.x()-win_rect.left, pos.y()-win_rect.top); HIViewConvertPoint(&hi_pos, 0, qt_mac_nativeview_for(this)); return d->mapFromWS(QPoint((int)hi_pos.x, (int)hi_pos.y)); #else NSRect win_rect = [qt_mac_window_for(this) frame]; // The Window point is in "Cocoa coordinates," but the view is in "Qt coordinates" // so make sure to keep them in sync. NSPoint hi_pos = NSMakePoint(pos.x()-win_rect.origin.x, flipYCoordinate(pos.y())-win_rect.origin.y); hi_pos = [qt_mac_nativeview_for(this) convertPoint:hi_pos fromView:0]; return d->mapFromWS(QPoint(qRound(hi_pos.x), qRound(hi_pos.y))); #endif } void QWidgetPrivate::updateSystemBackground() { } void QWidgetPrivate::setCursor_sys(const QCursor &) { #ifndef QT_MAC_USE_COCOA qt_mac_update_cursor(); #else Q_Q(QWidget); if (q->testAttribute(Qt::WA_WState_Created)) { QMacCocoaAutoReleasePool pool; [qt_mac_window_for(q) invalidateCursorRectsForView:qt_mac_nativeview_for(q)]; } #endif } void QWidgetPrivate::unsetCursor_sys() { #ifndef QT_MAC_USE_COCOA qt_mac_update_cursor(); #else Q_Q(QWidget); if (q->testAttribute(Qt::WA_WState_Created)) { QMacCocoaAutoReleasePool pool; [qt_mac_window_for(q) invalidateCursorRectsForView:qt_mac_nativeview_for(q)]; } #endif } void QWidgetPrivate::setWindowTitle_sys(const QString &caption) { Q_Q(QWidget); if (q->isWindow()) { #ifndef QT_MAC_USE_COCOA SetWindowTitleWithCFString(qt_mac_window_for(q), QCFString(caption)); #else QMacCocoaAutoReleasePool pool; [qt_mac_window_for(q) setTitle:qt_mac_QStringToNSString(caption)]; #endif } } void QWidgetPrivate::setWindowModified_sys(bool mod) { Q_Q(QWidget); if (q->isWindow() && q->testAttribute(Qt::WA_WState_Created)) { #ifndef QT_MAC_USE_COCOA SetWindowModified(qt_mac_window_for(q), mod); #else [qt_mac_window_for(q) setDocumentEdited:mod]; #endif } } void QWidgetPrivate::setWindowFilePath_sys(const QString &filePath) { Q_Q(QWidget); #ifdef QT_MAC_USE_COCOA QMacCocoaAutoReleasePool pool; QFileInfo fi(filePath); [qt_mac_window_for(q) setRepresentedFilename:fi.exists() ? qt_mac_QStringToNSString(filePath) : @""]; #else bool validRef = false; FSRef ref; bzero(&ref, sizeof(ref)); OSStatus status; if (!filePath.isEmpty()) { status = FSPathMakeRef(reinterpret_cast(filePath.toUtf8().constData()), &ref, 0); validRef = (status == noErr); } // Set the proxy regardless, since this is our way of clearing it as well, but ignore the // return value as well. if (validRef) { status = HIWindowSetProxyFSRef(qt_mac_window_for(q), &ref); } else { status = RemoveWindowProxy(qt_mac_window_for(q)); } if (status != noErr) qWarning("QWidget::setWindowFilePath: Error setting proxyicon for path (%s):%ld", qPrintable(filePath), status); #endif } void QWidgetPrivate::setWindowIcon_sys(bool forceReset) { Q_Q(QWidget); if (!q->testAttribute(Qt::WA_WState_Created)) return; QTLWExtra *topData = this->topData(); if (topData->iconPixmap && !forceReset) // already set return; QIcon icon = q->windowIcon(); QPixmap *pm = 0; if (!icon.isNull()) { // now create the extra if (!topData->iconPixmap) { pm = new QPixmap(icon.pixmap(QSize(22, 22))); topData->iconPixmap = pm; } else { pm = topData->iconPixmap; } } if (q->isWindow()) { #ifndef QT_MAC_USE_COCOA IconRef previousIcon = 0; if (icon.isNull()) { RemoveWindowProxy(qt_mac_window_for(q)); previousIcon = topData->windowIcon; topData->windowIcon = 0; } else { WindowClass wclass; GetWindowClass(qt_mac_window_for(q), &wclass); if (wclass == kDocumentWindowClass) { IconRef newIcon = qt_mac_create_iconref(*pm); previousIcon = topData->windowIcon; topData->windowIcon = newIcon; SetWindowProxyIcon(qt_mac_window_for(q), newIcon); } } // Release the previous icon if it was set by this function. if (previousIcon != 0) ReleaseIconRef(previousIcon); #else QMacCocoaAutoReleasePool pool; NSButton *iconButton = [qt_mac_window_for(q) standardWindowButton:NSWindowDocumentIconButton]; if (iconButton == nil) { QCFString string(q->windowTitle()); const NSString *tmpString = reinterpret_cast((CFStringRef)string); [qt_mac_window_for(q) setRepresentedURL:[NSURL fileURLWithPath:tmpString]]; iconButton = [qt_mac_window_for(q) standardWindowButton:NSWindowDocumentIconButton]; } if (icon.isNull()) { [iconButton setImage:nil]; } else { QPixmap scaled = pm->scaled(QSize(16,16), Qt::KeepAspectRatio, Qt::SmoothTransformation); NSImage *image = static_cast(qt_mac_create_nsimage(scaled)); [iconButton setImage:image]; [image release]; } #endif } } void QWidgetPrivate::setWindowIconText_sys(const QString &iconText) { Q_Q(QWidget); if(q->isWindow() && !iconText.isEmpty()) { #ifndef QT_MAC_USE_COCOA SetWindowAlternateTitle(qt_mac_window_for(q), QCFString(iconText)); #else QMacCocoaAutoReleasePool pool; [qt_mac_window_for(q) setMiniwindowTitle:qt_mac_QStringToNSString(iconText)]; #endif } } void QWidget::grabMouse() { if(isVisible() && !qt_nograb()) { if(mac_mouse_grabber) mac_mouse_grabber->releaseMouse(); mac_mouse_grabber=this; } } #ifndef QT_NO_CURSOR void QWidget::grabMouse(const QCursor &) { if(isVisible() && !qt_nograb()) { if(mac_mouse_grabber) mac_mouse_grabber->releaseMouse(); mac_mouse_grabber=this; } } #endif void QWidget::releaseMouse() { if(!qt_nograb() && mac_mouse_grabber == this) mac_mouse_grabber = 0; } void QWidget::grabKeyboard() { if(!qt_nograb()) { if(mac_keyboard_grabber) mac_keyboard_grabber->releaseKeyboard(); mac_keyboard_grabber = this; } } void QWidget::releaseKeyboard() { if(!qt_nograb() && mac_keyboard_grabber == this) mac_keyboard_grabber = 0; } QWidget *QWidget::mouseGrabber() { return mac_mouse_grabber; } QWidget *QWidget::keyboardGrabber() { return mac_keyboard_grabber; } void QWidget::activateWindow() { QWidget *tlw = window(); if(!tlw->isVisible() || !tlw->isWindow() || (tlw->windowType() == Qt::Desktop)) return; qt_event_remove_activate(); QWidget *fullScreenWidget = tlw; QWidget *parentW = tlw; // Find the oldest parent or the parent with fullscreen, whichever comes first. while (parentW) { fullScreenWidget = parentW->window(); if (fullScreenWidget->windowState() & Qt::WindowFullScreen) break; parentW = fullScreenWidget->parentWidget(); } if (fullScreenWidget->windowType() != Qt::ToolTip) { qt_mac_set_fullscreen_mode((fullScreenWidget->windowState() & Qt::WindowFullScreen) && qApp->desktop()->screenNumber(this) == 0); } bool windowActive; OSWindowRef win = qt_mac_window_for(tlw); #ifndef QT_MAC_USE_COCOA windowActive = IsWindowActive(win); #else QMacCocoaAutoReleasePool pool; windowActive = [win isKeyWindow]; #endif if ((tlw->windowType() == Qt::Popup) || (tlw->windowType() == Qt::Tool) || qt_mac_is_macdrawer(tlw) || windowActive) { #ifndef QT_MAC_USE_COCOA ActivateWindow(win, true); #else [win makeKeyWindow]; #endif qApp->setActiveWindow(tlw); } else if(!isMinimized()) { #ifndef QT_MAC_USE_COCOA SelectWindow(win); #else [win makeKeyAndOrderFront:win]; #endif } } QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys() { return new QMacWindowSurface(q_func()); } void QWidgetPrivate::update_sys(const QRect &r) { Q_Q(QWidget); if (r == q->rect()) { if (updateRedirectedToGraphicsProxyWidget(q, r)) return; dirtyOnWidget += r; #ifndef QT_MAC_USE_COCOA HIViewSetNeedsDisplay(qt_mac_nativeview_for(q), true); #else [qt_mac_nativeview_for(q) setNeedsDisplay:YES]; #endif return; } int x = r.x(), y = r.y(), w = r.width(), h = r.height(); if (w < 0) w = q->data->crect.width() - x; if (h < 0) h = q->data->crect.height() - y; if (w && h) { const QRect updateRect = QRect(x, y, w, h); if (updateRedirectedToGraphicsProxyWidget(q, updateRect)) return; #ifndef QT_MAC_USE_COCOA dirtyOnWidget += updateRect; HIRect r = CGRectMake(x, y, w, h); HIViewSetNeedsDisplayInRect(qt_mac_nativeview_for(q), &r, true); #else [qt_mac_nativeview_for(q) setNeedsDisplayInRect:NSMakeRect(x, y, w, h)]; #endif } } void QWidgetPrivate::update_sys(const QRegion &rgn) { Q_Q(QWidget); if (updateRedirectedToGraphicsProxyWidget(q, rgn)) return; dirtyOnWidget += rgn; #ifndef QT_MAC_USE_COCOA RgnHandle rgnHandle = rgn.toQDRgnForUpdate_sys(); if (rgnHandle) HIViewSetNeedsDisplayInRegion(qt_mac_nativeview_for(q), QMacSmartQuickDrawRegion(rgnHandle), true); else { HIViewSetNeedsDisplay(qt_mac_nativeview_for(q), true); // do a complete repaint on overflow. } #else // Cocoa doesn't do regions, it seems more efficient to just update the bounding rect instead of a potential number of message passes for each rect. const QRect &boundingRect = rgn.boundingRect(); [qt_mac_nativeview_for(q) setNeedsDisplayInRect:NSMakeRect(boundingRect.x(), boundingRect.y(), boundingRect.width(), boundingRect.height())]; #endif } bool QWidgetPrivate::isRealWindow() const { return q_func()->isWindow() && !topData()->embedded; } void QWidgetPrivate::show_sys() { Q_Q(QWidget); if ((q->windowType() == Qt::Desktop)) //desktop is always visible return; invalidateBuffer(q->rect()); if (q->testAttribute(Qt::WA_OutsideWSRange)) return; QMacCocoaAutoReleasePool pool; q->setAttribute(Qt::WA_Mapped); if (q->testAttribute(Qt::WA_DontShowOnScreen)) return; bool realWindow = isRealWindow(); if (realWindow && !q->testAttribute(Qt::WA_Moved)) { q->createWinId(); if (QWidget *p = q->parentWidget()) { p->createWinId(); #ifndef QT_MAC_USE_COCOA RepositionWindow(qt_mac_window_for(q), qt_mac_window_for(p), kWindowCenterOnParentWindow); #else CGRect parentFrame = NSRectToCGRect([qt_mac_window_for(p) frame]); OSWindowRef windowRef = qt_mac_window_for(q); NSRect windowFrame = [windowRef frame]; NSPoint parentCenter = NSMakePoint(CGRectGetMidX(parentFrame), CGRectGetMidY(parentFrame)); [windowRef setFrameTopLeftPoint:NSMakePoint(parentCenter.x - (windowFrame.size.width / 2), (parentCenter.y + (windowFrame.size.height / 2)))]; #endif } else { #ifndef QT_MAC_USE_COCOA RepositionWindow(qt_mac_window_for(q), 0, kWindowCenterOnMainScreen); #else // Ideally we would do a "center" here, but NSWindow's center is more equivalent to // kWindowAlertPositionOnMainScreen instead of kWindowCenterOnMainScreen. QRect availGeo = QApplication::desktop()->availableGeometry(q); // Center the content only. data.crect.moveCenter(availGeo.center()); QRect fStrut = frameStrut(); QRect frameRect(data.crect.x() - fStrut.left(), data.crect.y() - fStrut.top(), fStrut.left() + fStrut.right() + data.crect.width(), fStrut.top() + fStrut.bottom() + data.crect.height()); NSRect cocoaFrameRect = NSMakeRect(frameRect.x(), flipYCoordinate(frameRect.bottom() + 1), frameRect.width(), frameRect.height()); [qt_mac_window_for(q) setFrame:cocoaFrameRect display:NO]; #endif } } data.fstrut_dirty = true; if (realWindow) { // Delegates can change window state, so record some things earlier. bool isCurrentlyMinimized = (q->windowState() & Qt::WindowMinimized); setModal_sys(); OSWindowRef window = qt_mac_window_for(q); #ifndef QT_MAC_USE_COCOA SizeWindow(window, q->width(), q->height(), true); #endif #ifdef QT_MAC_USE_COCOA // Make sure that we end up sending a repaint event to // the widget if the window has been visible one before: [qt_mac_get_contentview_for(window) setNeedsDisplay:YES]; #endif if(qt_mac_is_macsheet(q)) { qt_event_request_showsheet(q); } else if(qt_mac_is_macdrawer(q)) { #ifndef QT_MAC_USE_COCOA OpenDrawer(window, kWindowEdgeDefault, false); #else NSDrawer *drawer = qt_mac_drawer_for(q); [drawer openOnEdge:[drawer preferredEdge]]; #endif } else { #ifndef QT_MAC_USE_COCOA ShowHide(window, true); #else // sync the opacity value back (in case of a fade). [window setAlphaValue:q->windowOpacity()]; [window makeKeyAndOrderFront:window]; // If this window is app modal, we need to start spinning // a modal session for it. Interrupting // the event dispatcher will make this happend: if (data.window_modality == Qt::ApplicationModal) QEventDispatcherMac::instance()->interrupt(); #endif if (q->windowType() == Qt::Popup) { if (q->focusWidget()) q->focusWidget()->d_func()->setFocus_sys(); else setFocus_sys(); } toggleDrawers(true); } if (isCurrentlyMinimized) { //show in collapsed state #ifndef QT_MAC_USE_COCOA CollapseWindow(window, true); #else [window miniaturize:window]; #endif } else if (!q->testAttribute(Qt::WA_ShowWithoutActivating)) { #ifndef QT_MAC_USE_COCOA qt_event_request_activate(q); #else [qt_mac_window_for(q) makeKeyWindow]; #endif } } else if(topData()->embedded || !q->parentWidget() || q->parentWidget()->isVisible()) { #ifndef QT_MAC_USE_COCOA HIViewSetVisible(qt_mac_nativeview_for(q), true); #else [qt_mac_nativeview_for(q) setHidden:NO]; #endif } if (!QWidget::mouseGrabber()){ QWidget *enterWidget = QApplication::widgetAt(QCursor::pos()); QApplicationPrivate::dispatchEnterLeave(enterWidget, qt_mouseover); qt_mouseover = enterWidget; } qt_event_request_window_change(q); } QPoint qt_mac_nativeMapFromParent(const QWidget *child, const QPoint &pt) { #ifndef QT_MAC_USE_COCOA CGPoint nativePoint = CGPointMake(pt.x(), pt.y()); HIViewConvertPoint(&nativePoint, qt_mac_nativeview_for(child->parentWidget()), qt_mac_nativeview_for(child)); #else NSPoint nativePoint = [qt_mac_nativeview_for(child) convertPoint:NSMakePoint(pt.x(), pt.y()) fromView:qt_mac_nativeview_for(child->parentWidget())]; #endif return QPoint(nativePoint.x, nativePoint.y); } void QWidgetPrivate::hide_sys() { Q_Q(QWidget); if((q->windowType() == Qt::Desktop)) //you can't hide the desktop! return; QMacCocoaAutoReleasePool pool; if(q->isWindow()) { OSWindowRef window = qt_mac_window_for(q); if(qt_mac_is_macsheet(q)) { #ifndef QT_MAC_USE_COCOA WindowRef parent = 0; if(GetSheetWindowParent(window, &parent) != noErr || !parent) ShowHide(window, false); else HideSheetWindow(window); #else [NSApp endSheet:window]; [window orderOut:window]; #endif } else if(qt_mac_is_macdrawer(q)) { #ifndef QT_MAC_USE_COCOA CloseDrawer(window, false); #else [qt_mac_drawer_for(q) close]; #endif } else { #ifndef QT_MAC_USE_COCOA ShowHide(window, false); #else [window orderOut:window]; // Unfortunately it is not as easy as just hiding the window, we need // to find out if we were in full screen mode. If we were and this is // the last window in full screen mode then we need to unset the full screen // mode. If this is not the last visible window in full screen mode then we // don't change the full screen mode. if(q->isFullScreen()) { bool keepFullScreen = false; QWidgetList windowList = qApp->topLevelWidgets(); int windowCount = windowList.count(); for(int i = 0; i < windowCount; i++) { QWidget *w = windowList[i]; // If it is the same window, we don't need to check :-) if(q == w) continue; // If they are not visible or if they are minimized then // we just ignore them. if(!w->isVisible() || w->isMinimized()) continue; // Is it full screen? // Notice that if there is one window in full screen mode then we // cannot switch the full screen mode off, therefore we just abort. if(w->isFullScreen()) { keepFullScreen = true; break; } } // No windows in full screen mode, so let just unset that flag. if(!keepFullScreen) qt_mac_set_fullscreen_mode(false); } #endif toggleDrawers(false); #ifndef QT_MAC_USE_COCOA // Clear modality (because it seems something that we've always done). if (data.window_modality != Qt::NonModal) { SetWindowModality(window, kWindowModalityNone, q->parentWidget() ? qt_mac_window_for(q->parentWidget()->window()) : 0); } #endif } if(q->isActiveWindow() && !(q->windowType() == Qt::Popup)) { QWidget *w = 0; if(q->parentWidget()) w = q->parentWidget()->window(); if(!w || (!w->isVisible() && !w->isMinimized())) { #ifndef QT_MAC_USE_COCOA for (WindowPtr wp = GetFrontWindowOfClass(kMovableModalWindowClass, true); wp; wp = GetNextWindowOfClass(wp, kMovableModalWindowClass, true)) { if((w = qt_mac_find_window(wp))) break; } if (!w){ for (WindowPtr wp = GetFrontWindowOfClass(kDocumentWindowClass, true); wp; wp = GetNextWindowOfClass(wp, kDocumentWindowClass, true)) { if((w = qt_mac_find_window(wp))) break; } } if (!w){ for(WindowPtr wp = GetFrontWindowOfClass(kSimpleWindowClass, true); wp; wp = GetNextWindowOfClass(wp, kSimpleWindowClass, true)) { if((w = qt_mac_find_window(wp))) break; } } #else NSArray *windows = [NSApp windows]; NSUInteger totalWindows = [windows count]; for (NSUInteger i = 0; i < totalWindows; ++i) { OSWindowRef wp = [windows objectAtIndex:i]; if ((w = qt_mac_find_window(wp))) break; } #endif } if(w && w->isVisible() && !w->isMinimized()) { #ifndef QT_MAC_USE_COCOA qt_event_request_activate(w); #else [qt_mac_window_for(w) makeKeyWindow]; #endif } } } else { invalidateBuffer(q->rect()); #ifndef QT_MAC_USE_COCOA HIViewSetVisible(qt_mac_nativeview_for(q), false); #else [qt_mac_nativeview_for(q) setHidden:YES]; #endif } if (!QWidget::mouseGrabber()){ QWidget *enterWidget = QApplication::widgetAt(QCursor::pos()); QApplicationPrivate::dispatchEnterLeave(enterWidget, qt_mouseover); qt_mouseover = enterWidget; } qt_event_request_window_change(q); deactivateWidgetCleanup(); qt_mac_event_release(q); } void QWidget::setWindowState(Qt::WindowStates newstate) { Q_D(QWidget); bool needShow = false; Qt::WindowStates oldstate = windowState(); if (oldstate == newstate) return; #ifdef QT_MAC_USE_COCOA QMacCocoaAutoReleasePool pool; #endif bool needSendStateChange = true; if(isWindow()) { if((oldstate & Qt::WindowFullScreen) != (newstate & Qt::WindowFullScreen)) { if(newstate & Qt::WindowFullScreen) { if(QTLWExtra *tlextra = d->topData()) { if(tlextra->normalGeometry.width() < 0) { if(!testAttribute(Qt::WA_Resized)) adjustSize(); tlextra->normalGeometry = geometry(); } tlextra->savedFlags = windowFlags(); } needShow = isVisible(); const QRect fullscreen(qApp->desktop()->screenGeometry(qApp->desktop()->screenNumber(this))); setParent(parentWidget(), Qt::Window | Qt::FramelessWindowHint | (windowFlags() & 0xffff0000)); //save setGeometry(fullscreen); if(!qApp->desktop()->screenNumber(this)) qt_mac_set_fullscreen_mode(true); } else { needShow = isVisible(); if(!qApp->desktop()->screenNumber(this)) qt_mac_set_fullscreen_mode(false); setParent(parentWidget(), d->topData()->savedFlags); setGeometry(d->topData()->normalGeometry); d->topData()->normalGeometry.setRect(0, 0, -1, -1); } } d->createWinId(); OSWindowRef window = qt_mac_window_for(this); if((oldstate & Qt::WindowMinimized) != (newstate & Qt::WindowMinimized)) { if (newstate & Qt::WindowMinimized) { #ifndef QT_MAC_USE_COCOA CollapseWindow(window, true); #else [window miniaturize:window]; #endif } else { #ifndef QT_MAC_USE_COCOA CollapseWindow(window, false); #else [window deminiaturize:window]; #endif } needSendStateChange = oldstate == windowState(); // Collapse didn't change our flags. } if((newstate & Qt::WindowMaximized) && !((newstate & Qt::WindowFullScreen))) { if(QTLWExtra *tlextra = d->topData()) { if(tlextra->normalGeometry.width() < 0) { if(!testAttribute(Qt::WA_Resized)) adjustSize(); tlextra->normalGeometry = geometry(); } } } else if(!(newstate & Qt::WindowFullScreen)) { // d->topData()->normalGeometry = QRect(0, 0, -1, -1); } #ifdef DEBUG_WINDOW_STATE #define WSTATE(x) qDebug("%s -- %s --> %s", #x, (oldstate & x) ? "true" : "false", (newstate & x) ? "true" : "false") WSTATE(Qt::WindowMinimized); WSTATE(Qt::WindowMaximized); WSTATE(Qt::WindowFullScreen); #undef WSTATE #endif if(!(newstate & (Qt::WindowMinimized|Qt::WindowFullScreen)) && ((oldstate & Qt::WindowFullScreen) || (oldstate & Qt::WindowMinimized) || (oldstate & Qt::WindowMaximized) != (newstate & Qt::WindowMaximized))) { if(newstate & Qt::WindowMaximized) { data->fstrut_dirty = true; #ifndef QT_MAC_USE_COCOA HIToolbarRef toolbarRef; if (GetWindowToolbar(window, &toolbarRef) == noErr && toolbarRef && !isVisible() && !IsWindowToolbarVisible(window)) { // HIToolbar, needs to be shown so that it's in the structure window // Typically this is part of a main window and will get shown // during the show, but it's will make the maximize all wrong. ShowHideWindowToolbar(window, true, false); d->updateFrameStrut(); // In theory the dirty would work, but it's optimized out if the window is not visible :( } Rect bounds; QDesktopWidget *dsk = QApplication::desktop(); QRect avail = dsk->availableGeometry(dsk->screenNumber(this)); SetRect(&bounds, avail.x(), avail.y(), avail.x() + avail.width(), avail.y() + avail.height()); if(QWExtra *extra = d->extraData()) { if(bounds.right - bounds.left > extra->maxw) bounds.right = bounds.left + extra->maxw; if(bounds.bottom - bounds.top > extra->maxh) bounds.bottom = bounds.top + extra->maxh; } if(d->topData()) { QRect fs = d->frameStrut(); bounds.left += fs.left(); if(bounds.right < avail.x()+avail.width()) bounds.right = qMin((uint)avail.x()+avail.width(), bounds.right+fs.left()); if(bounds.bottom < avail.y()+avail.height()) bounds.bottom = qMin((uint)avail.y()+avail.height(), bounds.bottom+fs.top()); bounds.top += fs.top(); bounds.right -= fs.right(); bounds.bottom -= fs.bottom(); } QRect orect(geometry().x(), geometry().y(), width(), height()), nrect(bounds.left, bounds.top, bounds.right - bounds.left, bounds.bottom - bounds.top); if(orect != nrect) { // the new rect differ from the old Point idealSize = { nrect.height(), nrect.width() }; ZoomWindowIdeal(window, inZoomOut, &idealSize); } #else NSToolbar *toolbarRef = [window toolbar]; if (toolbarRef && !isVisible() && ![toolbarRef isVisible]) { // HIToolbar, needs to be shown so that it's in the structure window // Typically this is part of a main window and will get shown // during the show, but it's will make the maximize all wrong. // ### Not sure this is right for NSToolbar... [toolbarRef setVisible:true]; // ShowHideWindowToolbar(window, true, false); d->updateFrameStrut(); // In theory the dirty would work, but it's optimized out if the window is not visible :( } // Everything should be handled by Cocoa. [window zoom:window]; #endif needSendStateChange = oldstate == windowState(); // Zoom didn't change flags. } else if(oldstate & Qt::WindowMaximized && !(oldstate & Qt::WindowFullScreen)) { #ifndef QT_MAC_USE_COCOA Point idealSize; ZoomWindowIdeal(window, inZoomIn, &idealSize); #else [window zoom:window]; #endif if(QTLWExtra *tlextra = d->topData()) { setGeometry(tlextra->normalGeometry); tlextra->normalGeometry.setRect(0, 0, -1, -1); } } } } data->window_state = newstate; if(needShow) show(); if(newstate & Qt::WindowActive) activateWindow(); qt_event_request_window_change(this); if (needSendStateChange) { QWindowStateChangeEvent e(oldstate); QApplication::sendEvent(this, &e); } } void QWidgetPrivate::setFocus_sys() { Q_Q(QWidget); if (q->testAttribute(Qt::WA_WState_Created)) { #ifdef QT_MAC_USE_COCOA QMacCocoaAutoReleasePool pool; NSView *view = qt_mac_nativeview_for(q); [[view window] makeFirstResponder:view]; #else SetKeyboardFocus(qt_mac_window_for(q), qt_mac_nativeview_for(q), 1); #endif } } NSComparisonResult compareViews2Raise(id view1, id view2, void *context) { id topView = reinterpret_cast(context); if (view1 == topView) return NSOrderedDescending; if (view2 == topView) return NSOrderedAscending; return NSOrderedSame; } void QWidgetPrivate::raise_sys() { Q_Q(QWidget); if((q->windowType() == Qt::Desktop)) return; #if QT_MAC_USE_COCOA QMacCocoaAutoReleasePool pool; if (isRealWindow()) { // Calling orderFront shows the window on Cocoa too. if (!q->testAttribute(Qt::WA_DontShowOnScreen) && q->isVisible()) { [qt_mac_window_for(q) orderFront:qt_mac_window_for(q)]; } if (qt_mac_raise_process) { //we get to be the active process now ProcessSerialNumber psn; GetCurrentProcess(&psn); SetFrontProcessWithOptions(&psn, kSetFrontProcessFrontWindowOnly); } } else { NSView *view = qt_mac_nativeview_for(q); NSView *parentView = [view superview]; [parentView sortSubviewsUsingFunction:compareViews2Raise context:reinterpret_cast(view)]; } #else if(q->isWindow()) { //raise this window BringToFront(qt_mac_window_for(q)); if(qt_mac_raise_process) { //we get to be the active process now ProcessSerialNumber psn; GetCurrentProcess(&psn); SetFrontProcessWithOptions(&psn, kSetFrontProcessFrontWindowOnly); } } else if(q->parentWidget()) { HIViewSetZOrder(qt_mac_nativeview_for(q), kHIViewZOrderAbove, 0); qt_event_request_window_change(q); } #endif } NSComparisonResult compareViews2Lower(id view1, id view2, void *context) { id topView = reinterpret_cast(context); if (view1 == topView) return NSOrderedAscending; if (view2 == topView) return NSOrderedDescending; return NSOrderedSame; } void QWidgetPrivate::lower_sys() { Q_Q(QWidget); if((q->windowType() == Qt::Desktop)) return; #ifdef QT_MAC_USE_COCOA if (isRealWindow()) { OSWindowRef window = qt_mac_window_for(q); [window orderBack:window]; } else { NSView *view = qt_mac_nativeview_for(q); NSView *parentView = [view superview]; [parentView sortSubviewsUsingFunction:compareViews2Lower context:reinterpret_cast(view)]; } #else if(q->isWindow()) { SendBehind(qt_mac_window_for(q), 0); } else if(q->parentWidget()) { invalidateBuffer(q->rect()); HIViewSetZOrder(qt_mac_nativeview_for(q), kHIViewZOrderBelow, 0); qt_event_request_window_change(q); } #endif } NSComparisonResult compareViews2StackUnder(id view1, id view2, void *context) { const QHash &viewOrder = *reinterpret_cast *>(context); if (viewOrder[view1] < viewOrder[view2]) return NSOrderedAscending; if (viewOrder[view1] > viewOrder[view2]) return NSOrderedDescending; return NSOrderedSame; } void QWidgetPrivate::stackUnder_sys(QWidget *w) { // stackUnder Q_Q(QWidget); if(!w || q->isWindow() || (q->windowType() == Qt::Desktop)) return; #ifdef QT_MAC_USE_COCOA // Do the same trick as lower_sys() and put this widget before the widget passed in. NSView *myView = qt_mac_nativeview_for(q); NSView *wView = qt_mac_nativeview_for(w); QHash viewOrder; NSView *parentView = [myView superview]; NSArray *subviews = [parentView subviews]; NSUInteger index = 1; // make a hash of view->zorderindex and make sure z-value is always odd, // so that when we modify the order we create a new (even) z-value which // will not interfere with others. for (NSView *subview in subviews) { viewOrder.insert(subview, index * 2); ++index; } viewOrder[myView] = viewOrder[wView] - 1; [parentView sortSubviewsUsingFunction:compareViews2StackUnder context:reinterpret_cast(&viewOrder)]; #else QWidget *p = q->parentWidget(); if(!p || p != w->parentWidget()) return; invalidateBuffer(q->rect()); HIViewSetZOrder(qt_mac_nativeview_for(q), kHIViewZOrderBelow, qt_mac_nativeview_for(w)); qt_event_request_window_change(q); #endif } /* Modifies the bounds for a widgets backing HIView during moves and resizes. Also updates the widget, either by scrolling its contents or repainting, depending on the WA_StaticContents flag */ static void qt_mac_update_widget_posisiton(QWidget *q, QRect oldRect, QRect newRect) { #ifndef QT_MAC_USE_COCOA HIRect bounds = CGRectMake(newRect.x(), newRect.y(), newRect.width(), newRect.height()); const HIViewRef view = qt_mac_nativeview_for(q); const bool isMove = (oldRect.topLeft() != newRect.topLeft()); const bool isResize = (oldRect.size() != newRect.size()); // qDebug() << oldRect << newRect << isMove << isResize << q->testAttribute(Qt::WA_OpaquePaintEvent) << q->testAttribute(Qt::WA_StaticContents); QWidgetPrivate *qd = qt_widget_private(q); // Perform a normal (complete repaint) update in some cases: if ( // always repaint on move. (isMove) || // limited update on resize requires WA_StaticContents. (isResize && q->testAttribute(Qt::WA_StaticContents) == false) || // one of the rects are invalid (oldRect.isValid() == false || newRect.isValid() == false) || // the position update is a part of a drag-and-drop operation QDragManager::self()->object || // we are on Panther (no HIViewSetNeedsDisplayInRect) QSysInfo::MacintoshVersion < QSysInfo::MV_10_4 ){ HIViewSetFrame(view, &bounds); return; } const int dx = newRect.x() - oldRect.x(); const int dy = newRect.y() - oldRect.y(); if (isMove) { // HIViewScrollRect silently fails if we try to scroll anything under the grow box. // Check if there's one present within the widget rect, and if there is fall back // to repainting the entire widget. QWidget const * const parentWidget = q->parentWidget(); const HIViewRef parentView = qt_mac_nativeview_for(parentWidget); HIViewRef nativeSizeGrip = 0; if (q->testAttribute(Qt::WA_WState_Created)) HIViewFindByID(HIViewGetRoot(HIViewGetWindow(HIViewRef(q->winId()))), kHIViewWindowGrowBoxID, &nativeSizeGrip); if (nativeSizeGrip) { QWidget * const window = q->window(); const int sizeGripSize = 20; const QRect oldWidgetRect = QRect(q->mapTo(window, QPoint(0, 0)), QSize(oldRect.width(), oldRect.height())); const QRect newWidgetRect = QRect(q->mapTo(window, QPoint(0, 0)), QSize(newRect.width(), newRect.height())); const QRect sizeGripRect = QRect(window->rect().bottomRight() - QPoint(sizeGripSize, sizeGripSize), window->rect().bottomRight()); if (sizeGripRect.intersects(oldWidgetRect) || sizeGripRect.intersects(newWidgetRect)) { HIViewSetFrame(view, &bounds); return; } } // Don't scroll anything outside the parent widget rect. const QRect scrollRect = (oldRect | newRect) & parentWidget->rect(); const HIRect scrollBounds = CGRectMake(scrollRect.x(), scrollRect.y(), scrollRect.width(), scrollRect.height()); // We cannot scroll when the widget has a mask as that would // scroll the masked out areas too if (qd->extra && qd->extra->hasMask) { HIViewMoveBy(view, dx, dy); return; } OSStatus err = HIViewScrollRect(parentView, &scrollBounds, dx, dy); if (err != noErr) { HIViewSetNeedsDisplay(view, true); qWarning("QWidget: Internal error (%s:%d)", __FILE__, __LINE__); } } // Set the view bounds with drawing disabled to prevent repaints. HIViewSetDrawingEnabled(view, false); HIViewSetFrame(view, &bounds); HIViewSetDrawingEnabled(view, true); // Update any newly exposed areas due to resizing. const int startx = oldRect.width(); const int stopx = newRect.width(); const int starty = oldRect.height(); const int stopy = newRect.height(); const HIRect verticalSlice = CGRectMake(startx, 0, stopx , stopy); HIViewSetNeedsDisplayInRect(view, &verticalSlice, true); const HIRect horizontalSlice = CGRectMake(0, starty, startx, stopy); HIViewSetNeedsDisplayInRect(view, &horizontalSlice, true); #else Q_UNUSED(oldRect); NSRect bounds = NSMakeRect(newRect.x(), newRect.y(), newRect.width(), newRect.height()); [qt_mac_nativeview_for(q) setFrame:bounds]; #endif } /* Helper function for non-toplevel widgets. Helps to map Qt's 32bit coordinate system to OS X's 16bit coordinate system. Sets the geometry of the widget to data.crect, but clipped to sizes that OS X can handle. Unmaps widgets that are completely outside the valid range. Maintains data.wrect, which is the geometry of the OS X widget, measured in this widget's coordinate system. if the parent is not clipped, parentWRect is empty, otherwise parentWRect is the geometry of the parent's OS X rect, measured in parent's coord sys */ void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &oldRect) { Q_Q(QWidget); Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); Q_UNUSED(oldRect); /* There are up to four different coordinate systems here: Qt coordinate system for this widget. X coordinate system for this widget (relative to wrect). Qt coordinate system for parent X coordinate system for parent (relative to parent's wrect). */ QRect wrect; //xrect is the X geometry of my X widget. (starts out in parent's Qt coord sys, and ends up in parent's X coord sys) QRect xrect = data.crect; QRect parentWRect; if (q->isWindow() && topData()->embedded) { #ifndef QT_MAC_USE_COCOA HIViewRef parentView = HIViewGetSuperview(qt_mac_nativeview_for(q)); #else NSView *parentView = [qt_mac_nativeview_for(q) superview]; #endif if (parentView) { #ifndef QT_MAC_USE_COCOA HIRect tmpRect; HIViewGetFrame(parentView, &tmpRect); #else NSRect tmpRect = [parentView frame]; #endif parentWRect = QRect(tmpRect.origin.x, tmpRect.origin.y, tmpRect.size.width, tmpRect.size.height); } else { const QRect wrectRange(-WRECT_MAX,-WRECT_MAX, 2*WRECT_MAX, 2*WRECT_MAX); parentWRect = wrectRange; } } else { parentWRect = q->parentWidget()->data->wrect; } if (parentWRect.isValid()) { // parent is clipped, and we have to clip to the same limit as parent if (!parentWRect.contains(xrect)) { xrect &= parentWRect; wrect = xrect; //translate from parent's to my Qt coord sys wrect.translate(-data.crect.topLeft()); } //translate from parent's Qt coords to parent's X coords xrect.translate(-parentWRect.topLeft()); } else { // parent is not clipped, we may or may not have to clip if (data.wrect.isValid() && QRect(QPoint(),data.crect.size()).contains(data.wrect)) { // This is where the main optimization is: we are already // clipped, and if our clip is still valid, we can just // move our window, and do not need to move or clip // children QRect vrect = xrect & q->parentWidget()->rect(); vrect.translate(-data.crect.topLeft()); //the part of me that's visible through parent, in my Qt coords if (data.wrect.contains(vrect)) { xrect = data.wrect; xrect.translate(data.crect.topLeft()); #ifndef QT_MAC_USE_COCOA HIRect bounds = CGRectMake(xrect.x(), xrect.y(), xrect.width(), xrect.height()); HIViewSetFrame(qt_mac_nativeview_for(q), &bounds); #else NSRect bounds = NSMakeRect(xrect.x(), xrect.y(), xrect.width(), xrect.height()); [qt_mac_nativeview_for(q) setFrame:bounds]; #endif if (q->testAttribute(Qt::WA_OutsideWSRange)) { q->setAttribute(Qt::WA_OutsideWSRange, false); if (!dontShow) { q->setAttribute(Qt::WA_Mapped); #ifndef QT_MAC_USE_COCOA HIViewSetVisible(qt_mac_nativeview_for(q), true); #else [qt_mac_nativeview_for(q) setHidden:NO]; #endif } } return; } } const QRect validRange(-XCOORD_MAX,-XCOORD_MAX, 2*XCOORD_MAX, 2*XCOORD_MAX); if (!validRange.contains(xrect)) { // we are too big, and must clip QPoint screenOffset(0, 0); // offset of the part being on screen const QWidget *parentWidget = q->parentWidget(); while (parentWidget && !parentWidget->isWindow()) { screenOffset -= parentWidget->data->crect.topLeft(); parentWidget = parentWidget->parentWidget(); } QRect cropRect(screenOffset.x() - WRECT_MAX, screenOffset.y() - WRECT_MAX, 2*WRECT_MAX, 2*WRECT_MAX); xrect &=cropRect; wrect = xrect; wrect.translate(-data.crect.topLeft()); // translate wrect in my Qt coordinates } } // unmap if we are outside the valid window system coord system bool outsideRange = !xrect.isValid(); bool mapWindow = false; if (q->testAttribute(Qt::WA_OutsideWSRange) != outsideRange) { q->setAttribute(Qt::WA_OutsideWSRange, outsideRange); if (outsideRange) { #ifndef QT_MAC_USE_COCOA HIViewSetVisible(qt_mac_nativeview_for(q), false); #else [qt_mac_nativeview_for(q) setHidden:YES]; #endif q->setAttribute(Qt::WA_Mapped, false); } else if (!q->isHidden()) { mapWindow = true; } } if (outsideRange) return; bool jump = (data.wrect != wrect); data.wrect = wrect; // and now recursively for all children... // ### can be optimized for (int i = 0; i < children.size(); ++i) { QObject *object = children.at(i); if (object->isWidgetType()) { QWidget *w = static_cast(object); if (!w->isWindow() && w->testAttribute(Qt::WA_WState_Created)) w->d_func()->setWSGeometry(); } } qt_mac_update_widget_posisiton(q, oldRect, xrect); if (jump) q->update(); if (mapWindow && !dontShow) { q->setAttribute(Qt::WA_Mapped); #ifndef QT_MAC_USE_COCOA HIViewSetVisible(qt_mac_nativeview_for(q), true); #else [qt_mac_nativeview_for(q) setHidden:NO]; #endif } } void QWidgetPrivate::adjustWithinMaxAndMinSize(int &w, int &h) { if (QWExtra *extra = extraData()) { w = qMin(w, extra->maxw); h = qMin(h, extra->maxh); w = qMax(w, extra->minw); h = qMax(h, extra->minh); // Deal with size increment if (QTLWExtra *top = topData()) { if(top->incw) { w = w/top->incw; w *= top->incw; } if(top->inch) { h = h/top->inch; h *= top->inch; } } } if (isRealWindow()) { w = qMax(0, w); h = qMax(0, h); } } void QWidgetPrivate::applyMaxAndMinSizeOnWindow() { Q_Q(QWidget); const float max_f(20000); #ifndef QT_MAC_USE_COCOA #define SF(x) ((x > max_f) ? max_f : x) HISize max = CGSizeMake(SF(extra->maxw), SF(extra->maxh)); HISize min = CGSizeMake(SF(extra->minw), SF(extra->minh)); #undef SF SetWindowResizeLimits(qt_mac_window_for(q), &min, &max); #else #define SF(x) ((x > max_f) ? max_f : x) NSSize max = NSMakeSize(SF(extra->maxw), SF(extra->maxh)); NSSize min = NSMakeSize(SF(extra->minw), SF(extra->minh)); #undef SF [qt_mac_window_for(q) setContentMinSize:min]; [qt_mac_window_for(q) setContentMaxSize:max]; #endif } void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove) { Q_Q(QWidget); Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); if(q->windowType() == Qt::Desktop) return; QMacCocoaAutoReleasePool pool; bool realWindow = isRealWindow(); if (realWindow && !q->testAttribute(Qt::WA_DontShowOnScreen)){ adjustWithinMaxAndMinSize(w, h); #ifndef QT_MAC_USE_COCOA if (w != 0 && h != 0) { topData()->isSetGeometry = 1; topData()->isMove = isMove; Rect r; SetRect(&r, x, y, x + w, y + h); SetWindowBounds(qt_mac_window_for(q), kWindowContentRgn, &r); topData()->isSetGeometry = 0; } else { setGeometry_sys_helper(x, y, w, h, isMove); } #else QSize olds = q->size(); const bool isResize = (olds != QSize(w, h)); NSWindow *window = qt_mac_window_for(q); const QRect &fStrut = frameStrut(); const QRect frameRect(QPoint(x - fStrut.left(), y - fStrut.top()), QSize(fStrut.left() + fStrut.right() + w, fStrut.top() + fStrut.bottom() + h)); NSRect cocoaFrameRect = NSMakeRect(frameRect.x(), flipYCoordinate(frameRect.bottom() + 1), frameRect.width(), frameRect.height()); // The setFrame call will trigger a 'windowDidResize' notification for the corresponding // NSWindow. The pending flag is set, so that the resize event can be send as non-spontaneous. if (isResize) q->setAttribute(Qt::WA_PendingResizeEvent); QPoint currTopLeft = data.crect.topLeft(); if (currTopLeft.x() == x && currTopLeft.y() == y && cocoaFrameRect.size.width != 0 && cocoaFrameRect.size.height != 0) { [window setFrame:cocoaFrameRect display:NO]; } else { // The window is moved and resized (or resized to zero). // Since Cocoa usually only sends us a resize callback after // setting a window frame, we issue an explicit move as // well. To stop Cocoa from optimize away the move (since the move // would have the same origin as the setFrame call) we shift the // window back and forth inbetween. cocoaFrameRect.origin.y += 1; [window setFrame:cocoaFrameRect display:NO]; cocoaFrameRect.origin.y -= 1; [window setFrameOrigin:cocoaFrameRect.origin]; } #endif } else { setGeometry_sys_helper(x, y, w, h, isMove); } } void QWidgetPrivate::setGeometry_sys_helper(int x, int y, int w, int h, bool isMove) { Q_Q(QWidget); bool realWindow = isRealWindow(); QPoint oldp = q->pos(); QSize olds = q->size(); const bool isResize = (olds != QSize(w, h)); if (!realWindow && !isResize && QPoint(x, y) == oldp) return; if (isResize) data.window_state = data.window_state & ~Qt::WindowMaximized; const bool visible = q->isVisible(); data.crect = QRect(x, y, w, h); if (realWindow) { adjustWithinMaxAndMinSize(w, h); qt_mac_update_sizer(q); #ifndef QT_MAC_USE_COCOA if (q->windowFlags() & Qt::WindowMaximizeButtonHint) { OSWindowRef window = qt_mac_window_for(q); if (extra->maxw && extra->maxh && extra->maxw == extra->minw && extra->maxh == extra->minh) { ChangeWindowAttributes(window, kWindowNoAttributes, kWindowFullZoomAttribute); } else { ChangeWindowAttributes(window, kWindowFullZoomAttribute, kWindowNoAttributes); } } HIRect bounds = CGRectMake(0, 0, w, h); HIViewSetFrame(qt_mac_nativeview_for(q), &bounds); #else [qt_mac_nativeview_for(q) setFrame:NSMakeRect(0, 0, w, h)]; #endif } else { const QRect oldRect(oldp, olds); if (!isResize && QApplicationPrivate::graphicsSystem()) moveRect(oldRect, x - oldp.x(), y - oldp.y()); setWSGeometry(false, oldRect); if (isResize && QApplicationPrivate::graphicsSystem()) { invalidateBuffer(q->rect()); if (extra && !graphicsEffect && !extra->mask.isEmpty()) { QRegion oldRegion(extra->mask.translated(oldp)); oldRegion &= oldRect; q->parentWidget()->d_func()->invalidateBuffer(oldRegion); } else { q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(oldRect)); } } } if(isMove || isResize) { if(!visible) { if(isMove && q->pos() != oldp) q->setAttribute(Qt::WA_PendingMoveEvent, true); if(isResize) q->setAttribute(Qt::WA_PendingResizeEvent, true); } else { if(isResize) { //send the resize event.. QResizeEvent e(q->size(), olds); QApplication::sendEvent(q, &e); } if(isMove && q->pos() != oldp) { //send the move event.. QMoveEvent e(q->pos(), oldp); QApplication::sendEvent(q, &e); } } } qt_event_request_window_change(q); } void QWidgetPrivate::setConstraints_sys() { updateMaximizeButton_sys(); applyMaxAndMinSizeOnWindow(); } void QWidgetPrivate::updateMaximizeButton_sys() { Q_Q(QWidget); if (q->data->window_flags & Qt::CustomizeWindowHint) return; OSWindowRef window = qt_mac_window_for(q); QTLWExtra * tlwExtra = topData(); #ifdef QT_MAC_USE_COCOA QMacCocoaAutoReleasePool pool; NSButton *maximizeButton = [window standardWindowButton:NSWindowZoomButton]; #endif if (extra->maxw && extra->maxh && extra->maxw == extra->minw && extra->maxh == extra->minh) { // The window has a fixed size, so gray out the maximize button: if (!tlwExtra->savedWindowAttributesFromMaximized) { #ifndef QT_MAC_USE_COCOA GetWindowAttributes(window, (WindowAttributes*)&extra->topextra->savedWindowAttributesFromMaximized); #else tlwExtra->savedWindowAttributesFromMaximized = (![maximizeButton isHidden] && [maximizeButton isEnabled]); #endif } #ifndef QT_MAC_USE_COCOA ChangeWindowAttributes(window, kWindowNoAttributes, kWindowFullZoomAttribute); #else [maximizeButton setEnabled:NO]; #endif } else { if (tlwExtra->savedWindowAttributesFromMaximized) { #ifndef QT_MAC_USE_COCOA ChangeWindowAttributes(window, extra->topextra->savedWindowAttributesFromMaximized, kWindowNoAttributes); #else [maximizeButton setEnabled:YES]; #endif tlwExtra->savedWindowAttributesFromMaximized = 0; } } } void QWidgetPrivate::scroll_sys(int dx, int dy) { if (QApplicationPrivate::graphicsSystem() && !paintOnScreen()) { scrollChildren(dx, dy); scrollRect(q_func()->rect(), dx, dy); } else { scroll_sys(dx, dy, QRect()); } } void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r) { Q_Q(QWidget); if (QApplicationPrivate::graphicsSystem() && !paintOnScreen()) { scrollRect(r, dx, dy); return; } const bool valid_rect = r.isValid(); if (!q->updatesEnabled() && (valid_rect || q->children().isEmpty())) return; qt_event_request_window_change(q); #ifdef QT_MAC_USE_COCOA QMacCocoaAutoReleasePool pool; #endif if(!valid_rect) { // scroll children QPoint pd(dx, dy); QWidgetList moved; QObjectList chldrn = q->children(); for(int i = 0; i < chldrn.size(); i++) { //first move all children QObject *obj = chldrn.at(i); if(obj->isWidgetType()) { QWidget *w = (QWidget*)obj; if(!w->isWindow()) { w->data->crect = QRect(w->pos() + pd, w->size()); if (w->testAttribute(Qt::WA_WState_Created)) { #ifndef QT_MAC_USE_COCOA HIRect bounds = CGRectMake(w->data->crect.x(), w->data->crect.y(), w->data->crect.width(), w->data->crect.height()); HIViewRef hiview = qt_mac_nativeview_for(w); const bool opaque = q->testAttribute(Qt::WA_OpaquePaintEvent); if (opaque) HIViewSetDrawingEnabled(hiview, false); HIViewSetFrame(hiview, &bounds); if (opaque) HIViewSetDrawingEnabled(hiview, true); #else [qt_mac_nativeview_for(w) setFrame:NSMakeRect(w->data->crect.x(), w->data->crect.y(), w->data->crect.width(), w->data->crect.height())]; #endif } moved.append(w); } } } //now send move events (do not do this in the above loop, breaks QAquaFocusWidget) for(int i = 0; i < moved.size(); i++) { QWidget *w = moved.at(i); QMoveEvent e(w->pos(), w->pos() - pd); QApplication::sendEvent(w, &e); } } if (!q->testAttribute(Qt::WA_WState_Created) || !q->isVisible()) return; OSViewRef view = qt_mac_nativeview_for(q); #ifndef QT_MAC_USE_COCOA HIRect scrollrect = CGRectMake(r.x(), r.y(), r.width(), r.height()); OSStatus err = _HIViewScrollRectWithOptions(view, valid_rect ? &scrollrect : 0, dx, dy, kHIViewScrollRectAdjustInvalid); if (err) { // The only parameter that can go wrong, is the rect. qWarning("QWidget::scroll: Your rectangle was too big for the widget, clipping rect"); scrollrect = CGRectMake(qMax(r.x(), 0), qMax(r.y(), 0), qMin(r.width(), q->width()), qMin(r.height(), q->height())); _HIViewScrollRectWithOptions(view, valid_rect ? &scrollrect : 0, dx, dy, kHIViewScrollRectAdjustInvalid); } #else NSRect scrollRect = valid_rect ? NSMakeRect(r.x(), r.y(), r.width(), r.height()) : NSMakeRect(0, 0, q->width(), q->height()); // calc the updateRect NSRect deltaXRect = { {0, 0}, {0, 0} }; NSRect deltaYRect = { {0, 0}, {0, 0} }; if (dy != 0) { deltaYRect.size.width = scrollRect.size.width; if (dy > 0) { deltaYRect.size.height = dy; } else { deltaYRect.size.height = -dy; deltaYRect.origin.y = scrollRect.size.height + dy; } } if (dx != 0) { deltaXRect.size.height = scrollRect.size.height; if (dx > 0) { deltaXRect.size.width = dx; } else { deltaXRect.size.width = -dx; deltaXRect.origin.x = scrollRect.size.width + dx; } } NSSize deltaSize = NSMakeSize(dx, dy); [view translateRectsNeedingDisplayInRect:scrollRect by:deltaSize]; [view scrollRect:scrollRect by:deltaSize]; [view setNeedsDisplayInRect:deltaXRect]; [view setNeedsDisplayInRect:deltaYRect]; #endif // QT_MAC_USE_COCOA } int QWidget::metric(PaintDeviceMetric m) const { switch(m) { case PdmHeightMM: return qRound(metric(PdmHeight) * 25.4 / qreal(metric(PdmDpiY))); case PdmWidthMM: return qRound(metric(PdmWidth) * 25.4 / qreal(metric(PdmDpiX))); case PdmHeight: case PdmWidth: { #ifndef QT_MAC_USE_COCOA HIRect rect; HIViewGetFrame(qt_mac_nativeview_for(this), &rect); #else NSRect rect = [qt_mac_nativeview_for(this) frame]; #endif if(m == PdmWidth) return (int)rect.size.width; return (int)rect.size.height; } case PdmDepth: return 32; case PdmNumColors: return INT_MAX; case PdmDpiX: case PdmPhysicalDpiX: { Q_D(const QWidget); if (d->extra && d->extra->customDpiX) return d->extra->customDpiX; else if (d->parent) return static_cast(d->parent)->metric(m); extern float qt_mac_defaultDpi_x(); //qpaintdevice_mac.cpp return int(qt_mac_defaultDpi_x()); } case PdmDpiY: case PdmPhysicalDpiY: { Q_D(const QWidget); if (d->extra && d->extra->customDpiY) return d->extra->customDpiY; else if (d->parent) return static_cast(d->parent)->metric(m); extern float qt_mac_defaultDpi_y(); //qpaintdevice_mac.cpp return int(qt_mac_defaultDpi_y()); } default: //leave this so the compiler complains when new ones are added qWarning("QWidget::metric: Unhandled parameter %d", m); return QPaintDevice::metric(m); } return 0; } void QWidgetPrivate::createSysExtra() { #ifdef QT_MAC_USE_COCOA extra->imageMask = 0; #endif } void QWidgetPrivate::deleteSysExtra() { #ifdef QT_MAC_USE_COCOA if (extra->imageMask) CFRelease(extra->imageMask); #endif } void QWidgetPrivate::createTLSysExtra() { extra->topextra->resizer = 0; extra->topextra->isSetGeometry = 0; extra->topextra->isMove = 0; extra->topextra->wattr = 0; extra->topextra->wclass = 0; extra->topextra->group = 0; extra->topextra->windowIcon = 0; extra->topextra->savedWindowAttributesFromMaximized = 0; } void QWidgetPrivate::deleteTLSysExtra() { #ifndef QT_MAC_USE_COCOA if (extra->topextra->group) { qt_mac_release_window_group(extra->topextra->group); extra->topextra->group = 0; } if (extra->topextra->windowIcon) { ReleaseIconRef(extra->topextra->windowIcon); extra->topextra->windowIcon = 0; } #endif } void QWidgetPrivate::updateFrameStrut() { Q_Q(QWidget); QWidgetPrivate *that = const_cast(this); that->data.fstrut_dirty = false; QTLWExtra *top = that->topData(); #if QT_MAC_USE_COCOA // 1 Get the window frame OSWindowRef oswnd = qt_mac_window_for(q); NSRect frameW = [oswnd frame]; // 2 Get the content frame - so now NSRect frameC = [oswnd contentRectForFrameRect:frameW]; top->frameStrut.setCoords(frameC.origin.x - frameW.origin.x, (frameW.origin.y + frameW.size.height) - (frameC.origin.y + frameC.size.height), (frameW.origin.x + frameW.size.width) - (frameC.origin.x + frameC.size.width), frameC.origin.y - frameW.origin.y); #else Rect window_r; GetWindowStructureWidths(qt_mac_window_for(q), &window_r); top->frameStrut.setCoords(window_r.left, window_r.top, window_r.right, window_r.bottom); #endif } void QWidgetPrivate::registerDropSite(bool on) { Q_Q(QWidget); if (!q->testAttribute(Qt::WA_WState_Created)) return; #ifndef QT_MAC_USE_COCOA SetControlDragTrackingEnabled(qt_mac_nativeview_for(q), on); #else NSView *view = qt_mac_nativeview_for(q); if (on && [view isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaView) class]]) { [static_cast(view) registerDragTypes]; } #endif } void QWidgetPrivate::registerTouchWindow() { #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_6) return; Q_Q(QWidget); if (!q->testAttribute(Qt::WA_WState_Created)) return; #ifndef QT_MAC_USE_COCOA // Needs implementation! #else NSView *view = qt_mac_nativeview_for(q); [view setAcceptsTouchEvents:YES]; #endif #endif } void QWidgetPrivate::setMask_sys(const QRegion ®ion) { Q_UNUSED(region); #ifndef QT_MAC_USE_COCOA Q_Q(QWidget); if (q->isWindow()) ReshapeCustomWindow(qt_mac_window_for(q)); else HIViewReshapeStructure(qt_mac_nativeview_for(q)); #else if (extra->mask.isEmpty()) { extra->maskBits = QImage(); finishCocoaMaskSetup(); } else { syncCocoaMask(); } #endif } void QWidgetPrivate::setWindowOpacity_sys(qreal level) { Q_Q(QWidget); if (!q->isWindow()) return; level = qBound(0.0, level, 1.0); topData()->opacity = (uchar)(level * 255); if (!q->testAttribute(Qt::WA_WState_Created)) return; OSWindowRef oswindow = qt_mac_window_for(q); #if QT_MAC_USE_COCOA [oswindow setAlphaValue:level]; #else SetWindowAlpha(oswindow, level); #endif } #ifdef QT_MAC_USE_COCOA void QWidgetPrivate::syncCocoaMask() { Q_Q(QWidget); if (!q->testAttribute(Qt::WA_WState_Created) || !extra) return; if (extra->hasMask && extra->maskBits.size() != q->size()) { extra->maskBits = QImage(q->size(), QImage::Format_Mono); extra->maskBits.fill(QColor(Qt::color1).rgba()); extra->maskBits.setNumColors(2); extra->maskBits.setColor(0, QColor(Qt::color0).rgba()); extra->maskBits.setColor(1, QColor(Qt::color1).rgba()); QPainter painter(&extra->maskBits); painter.setBrush(Qt::color1); painter.setPen(Qt::NoPen); painter.drawRects(extra->mask.rects()); painter.end(); finishCocoaMaskSetup(); } } void QWidgetPrivate::finishCocoaMaskSetup() { Q_Q(QWidget); if (!q->testAttribute(Qt::WA_WState_Created) || !extra) return; // Technically this is too late to release, because the data behind the image // has already been released. But it's more tidy to do it here. // If you are seeing a crash, consider doing a CFRelease before changing extra->maskBits. if (extra->imageMask) { CFRelease(extra->imageMask); extra->imageMask = 0; } if (!extra->maskBits.isNull()) { QCFType dataProvider = CGDataProviderCreateWithData(0, extra->maskBits.bits(), extra->maskBits.numBytes(), 0); // shouldn't need to release. CGFloat decode[2] = {1, 0}; extra->imageMask = CGImageMaskCreate(extra->maskBits.width(), extra->maskBits.height(), 1, 1, extra->maskBits.bytesPerLine(), dataProvider, decode, false); } if (q->isWindow()) { NSWindow *window = qt_mac_window_for(q); [window setOpaque:(extra->imageMask == 0)]; [window invalidateShadow]; } [qt_mac_nativeview_for(q) setNeedsDisplay:YES]; } #endif struct QPaintEngineCleanupHandler { inline QPaintEngineCleanupHandler() : engine(0) {} inline ~QPaintEngineCleanupHandler() { delete engine; } QPaintEngine *engine; }; Q_GLOBAL_STATIC(QPaintEngineCleanupHandler, engineHandler) QPaintEngine *QWidget::paintEngine() const { QPaintEngine *&pe = engineHandler()->engine; if (!pe) pe = new QCoreGraphicsPaintEngine(); if (pe->isActive()) { QPaintEngine *engine = new QCoreGraphicsPaintEngine(); engine->setAutoDestruct(true); return engine; } return pe; } void QWidgetPrivate::setModal_sys() { Q_Q(QWidget); if (!q->testAttribute(Qt::WA_WState_Created) || !q->isWindow()) return; const QWidget * const windowParent = q->window()->parentWidget(); const QWidget * const primaryWindow = windowParent ? windowParent->window() : 0; OSWindowRef windowRef = qt_mac_window_for(q); #ifdef QT_MAC_USE_COCOA QMacCocoaAutoReleasePool pool; bool alreadySheet = [windowRef styleMask] & NSDocModalWindowMask; if (windowParent && q->windowModality() == Qt::WindowModal){ // Window should be window-modal, which implies a sheet. if (!alreadySheet) { // NB: the following call will call setModal_sys recursivly: recreateMacWindow(); windowRef = qt_mac_window_for(q); } if ([windowRef isKindOfClass:[NSPanel class]]){ // If the primary window of the sheet parent is a child of a modal dialog, // the sheet parent should not be modally shaddowed. // This goes for the sheet as well: OSWindowRef ref = primaryWindow ? qt_mac_window_for(primaryWindow) : 0; bool isDialog = ref ? [ref isKindOfClass:[NSPanel class]] : false; bool worksWhenModal = isDialog ? [static_cast(ref) worksWhenModal] : false; if (worksWhenModal) [static_cast(windowRef) setWorksWhenModal:YES]; } } else { // Window shold not be window-modal, and as such, not a sheet. if (alreadySheet){ // NB: the following call will call setModal_sys recursivly: recreateMacWindow(); windowRef = qt_mac_window_for(q); } if (q->windowModality() == Qt::ApplicationModal) { [windowRef setLevel:NSModalPanelWindowLevel]; } else if (primaryWindow && primaryWindow->windowModality() == Qt::ApplicationModal) { // INVARIANT: Our window is a dialog that has a dialog parent that is // application modal, or . This means that q is supposed to be on top of this // dialog and not be modally shaddowed: [windowRef setLevel:NSModalPanelWindowLevel]; if ([windowRef isKindOfClass:[NSPanel class]]) [static_cast(windowRef) setWorksWhenModal:YES]; } else { // INVARIANT: q should not be modal. NSInteger winLevel = -1; if (q->windowType() == Qt::Popup) { winLevel = NSPopUpMenuWindowLevel; // Popup should be in at least the same level as its parent. if (primaryWindow) { OSWindowRef parentRef = qt_mac_window_for(primaryWindow); winLevel = qMax([parentRef level], winLevel); } } else if (q->windowType() == Qt::Tool) { winLevel = NSFloatingWindowLevel; } else if (q->windowType() == Qt::Dialog) { winLevel = NSModalPanelWindowLevel; } // StayOnTop window should appear above Tool windows. if (data.window_flags & Qt::WindowStaysOnTopHint) winLevel = NSPopUpMenuWindowLevel; // Tooltips should appear above StayOnTop windows. if (q->windowType() == Qt::ToolTip) winLevel = NSScreenSaverWindowLevel; // All other types are Normal level. if (winLevel == -1) winLevel = NSNormalWindowLevel; [windowRef setLevel:winLevel]; } } #else const bool primaryWindowModal = primaryWindow ? primaryWindow->testAttribute(Qt::WA_ShowModal) : false; const bool modal = q->testAttribute(Qt::WA_ShowModal); WindowClass old_wclass; GetWindowClass(windowRef, &old_wclass); if (modal || primaryWindowModal) { if (q->windowModality() == Qt::WindowModal || (primaryWindow && primaryWindow->windowModality() == Qt::WindowModal)){ // Window should be window-modal (which implies a sheet). if (old_wclass != kSheetWindowClass){ // We cannot convert a created window to a sheet. // So we recreate the window: recreateMacWindow(); return; } } else { // Window should be application-modal (which implies NOT using a sheet). if (old_wclass == kSheetWindowClass){ // We cannot convert a sheet to a window. // So we recreate the window: recreateMacWindow(); return; } else if (!(q->data->window_flags & Qt::CustomizeWindowHint)) { if (old_wclass == kDocumentWindowClass || old_wclass == kFloatingWindowClass || old_wclass == kUtilityWindowClass){ // Only change the class to kMovableModalWindowClass if the no explicit jewels // are set (kMovableModalWindowClass can't contain them), and the current window class // can be converted to modal (according to carbon doc). Mind the order of // HIWindowChangeClass and ChangeWindowAttributes. WindowGroupRef group = GetWindowGroup(windowRef); HIWindowChangeClass(windowRef, kMovableModalWindowClass); quint32 tmpWattr = kWindowCloseBoxAttribute | kWindowHorizontalZoomAttribute; ChangeWindowAttributes(windowRef, tmpWattr, kWindowNoAttributes); ChangeWindowAttributes(windowRef, kWindowNoAttributes, tmpWattr); // If the window belongs to a qt-created group, set that group once more: if (data.window_flags & Qt::WindowStaysOnTopHint || q->windowType() == Qt::Popup || q->windowType() == Qt::ToolTip) SetWindowGroup(windowRef, group); } // Popups are usually handled "special" and are never modal. Qt::WindowType winType = q->windowType(); if (winType != Qt::Popup && winType != Qt::ToolTip) SetWindowModality(windowRef, kWindowModalityAppModal, 0); } } } else if (windowRef) { if (old_wclass == kSheetWindowClass){ // Converting a sheet to a window is complex. It's easier to recreate: recreateMacWindow(); return; } SetWindowModality(windowRef, kWindowModalityNone, 0); if (!(q->data->window_flags & Qt::CustomizeWindowHint)) { if (q->window()->d_func()->topData()->wattr |= kWindowCloseBoxAttribute) ChangeWindowAttributes(windowRef, kWindowCloseBoxAttribute, kWindowNoAttributes); if (q->window()->d_func()->topData()->wattr |= kWindowHorizontalZoomAttribute) ChangeWindowAttributes(windowRef, kWindowHorizontalZoomAttribute, kWindowNoAttributes); if (q->window()->d_func()->topData()->wattr |= kWindowCollapseBoxAttribute) ChangeWindowAttributes(windowRef, kWindowCollapseBoxAttribute, kWindowNoAttributes); } WindowClass newClass = q->window()->d_func()->topData()->wclass; if (old_wclass != newClass && newClass != 0){ WindowGroupRef group = GetWindowGroup(windowRef); HIWindowChangeClass(windowRef, newClass); // If the window belongs to a qt-created group, set that group once more: if (data.window_flags & Qt::WindowStaysOnTopHint || q->windowType() == Qt::Popup || q->windowType() == Qt::ToolTip) SetWindowGroup(windowRef, group); } } // Make sure that HIWindowChangeClass didn't remove drag support // or reset the opaque size grip setting: SetAutomaticControlDragTrackingEnabledForWindow(windowRef, true); macUpdateOpaqueSizeGrip(); #endif } void QWidgetPrivate::macUpdateHideOnSuspend() { Q_Q(QWidget); if (!q->testAttribute(Qt::WA_WState_Created) || !q->isWindow() || q->windowType() != Qt::Tool) return; #ifndef QT_MAC_USE_COCOA if(q->testAttribute(Qt::WA_MacAlwaysShowToolWindow)) ChangeWindowAttributes(qt_mac_window_for(q), 0, kWindowHideOnSuspendAttribute); else ChangeWindowAttributes(qt_mac_window_for(q), kWindowHideOnSuspendAttribute, 0); #else if(q->testAttribute(Qt::WA_MacAlwaysShowToolWindow)) [qt_mac_window_for(q) setHidesOnDeactivate:NO]; else [qt_mac_window_for(q) setHidesOnDeactivate:YES]; #endif } void QWidgetPrivate::macUpdateOpaqueSizeGrip() { Q_Q(QWidget); if (!q->testAttribute(Qt::WA_WState_Created) || !q->isWindow()) return; #ifndef QT_MAC_USE_COCOA // Growbox is always transparent on Cocoa. Can emulate with setting a QSizeGrip HIViewRef growBox; HIViewFindByID(HIViewGetRoot(qt_mac_window_for(q)), kHIViewWindowGrowBoxID, &growBox); if (!growBox) return; HIGrowBoxViewSetTransparent(growBox, !q->testAttribute(Qt::WA_MacOpaqueSizeGrip)); #endif } void QWidgetPrivate::macUpdateSizeAttribute() { Q_Q(QWidget); QEvent event(QEvent::MacSizeChange); QApplication::sendEvent(q, &event); for (int i = 0; i < children.size(); ++i) { QWidget *w = qobject_cast(children.at(i)); if (w && (!w->isWindow() || w->testAttribute(Qt::WA_WindowPropagation)) && !q->testAttribute(Qt::WA_MacMiniSize) // no attribute set? inherit from parent && !w->testAttribute(Qt::WA_MacSmallSize) && !w->testAttribute(Qt::WA_MacNormalSize)) w->d_func()->macUpdateSizeAttribute(); } resolveFont(); } void QWidgetPrivate::macUpdateIgnoreMouseEvents() { #ifndef QT_MAC_USE_COCOA // This is handled inside the mouse handler on Cocoa. Q_Q(QWidget); if (!q->testAttribute(Qt::WA_WState_Created)) return; if(q->isWindow()) { if(q->testAttribute(Qt::WA_TransparentForMouseEvents)) ChangeWindowAttributes(qt_mac_window_for(q), kWindowIgnoreClicksAttribute, 0); else ChangeWindowAttributes(qt_mac_window_for(q), 0, kWindowIgnoreClicksAttribute); ReshapeCustomWindow(qt_mac_window_for(q)); } else { #ifndef kHIViewFeatureIgnoresClicks #define kHIViewFeatureIgnoresClicks kHIViewIgnoresClicks #endif if(q->testAttribute(Qt::WA_TransparentForMouseEvents)) HIViewChangeFeatures(qt_mac_nativeview_for(q), kHIViewFeatureIgnoresClicks, 0); else HIViewChangeFeatures(qt_mac_nativeview_for(q), 0, kHIViewFeatureIgnoresClicks); HIViewReshapeStructure(qt_mac_nativeview_for(q)); } #endif } void QWidgetPrivate::macUpdateMetalAttribute() { Q_Q(QWidget); bool realWindow = isRealWindow(); if (!q->testAttribute(Qt::WA_WState_Created) || !realWindow) return; if (realWindow) { #if QT_MAC_USE_COCOA // Cocoa doesn't let us change the style mask once it's been changed // So, that means we need to recreate the window. OSWindowRef cocoaWindow = qt_mac_window_for(q); if ([cocoaWindow styleMask] & NSTexturedBackgroundWindowMask) return; recreateMacWindow(); #else QMainWindowLayout *layout = qobject_cast(q->layout()); if (q->testAttribute(Qt::WA_MacBrushedMetal)) { if (layout) layout->updateHIToolBarStatus(); ChangeWindowAttributes(qt_mac_window_for(q), kWindowMetalAttribute, 0); ChangeWindowAttributes(qt_mac_window_for(q), kWindowMetalNoContentSeparatorAttribute, 0); } else { ChangeWindowAttributes(qt_mac_window_for(q), 0, kWindowMetalNoContentSeparatorAttribute); ChangeWindowAttributes(qt_mac_window_for(q), 0, kWindowMetalAttribute); if (layout) layout->updateHIToolBarStatus(); } #endif } } void QWidgetPrivate::setEnabled_helper_sys(bool enable) { #ifdef QT_MAC_USE_COCOA Q_Q(QWidget); NSView *view = qt_mac_nativeview_for(q); if ([view isKindOfClass:[NSControl class]]) [static_cast(view) setEnabled:enable]; #else Q_UNUSED(enable); #endif } QT_END_NAMESPACE