src/gui/kernel/qwidget_mac.mm
changeset 7 f7bc934e204c
parent 3 41300fa6a67c
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
     1 /****************************************************************************
     1 /****************************************************************************
     2 **
     2 **
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     4 ** All rights reserved.
     4 ** All rights reserved.
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     6 **
     6 **
     7 ** This file is part of the QtGui module of the Qt Toolkit.
     7 ** This file is part of the QtGui module of the Qt Toolkit.
     8 **
     8 **
   108 
   108 
   109 #include "qwidget_p.h"
   109 #include "qwidget_p.h"
   110 #include "qevent_p.h"
   110 #include "qevent_p.h"
   111 #include "qdnd_p.h"
   111 #include "qdnd_p.h"
   112 #include <QtGui/qgraphicsproxywidget.h>
   112 #include <QtGui/qgraphicsproxywidget.h>
       
   113 #include "qmainwindow.h"
   113 
   114 
   114 QT_BEGIN_NAMESPACE
   115 QT_BEGIN_NAMESPACE
   115 
   116 
   116 #define XCOORD_MAX 16383
   117 #define XCOORD_MAX 16383
   117 #define WRECT_MAX 8191
   118 #define WRECT_MAX 8191
   149 
   150 
   150 static bool qt_mac_raise_process = true;
   151 static bool qt_mac_raise_process = true;
   151 static OSWindowRef qt_root_win = 0;
   152 static OSWindowRef qt_root_win = 0;
   152 QWidget *mac_mouse_grabber = 0;
   153 QWidget *mac_mouse_grabber = 0;
   153 QWidget *mac_keyboard_grabber = 0;
   154 QWidget *mac_keyboard_grabber = 0;
       
   155 extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp
   154 
   156 
   155 #ifndef QT_MAC_USE_COCOA
   157 #ifndef QT_MAC_USE_COCOA
   156 #ifdef QT_NAMESPACE
   158 #ifdef QT_NAMESPACE
   157 
   159 
   158 // produce the string "com.trolltech.qt-namespace.widget", where "namespace" is the contents of QT_NAMESPACE.
   160 // produce the string "com.trolltech.qt-namespace.widget", where "namespace" is the contents of QT_NAMESPACE.
   401     extern bool qt_mac_app_fullscreen; //qapplication_mac.mm
   403     extern bool qt_mac_app_fullscreen; //qapplication_mac.mm
   402     if(qt_mac_app_fullscreen == b)
   404     if(qt_mac_app_fullscreen == b)
   403         return;
   405         return;
   404     qt_mac_app_fullscreen = b;
   406     qt_mac_app_fullscreen = b;
   405     if (b) {
   407     if (b) {
   406         SetSystemUIMode(kUIModeAllSuppressed, 0);
   408         SetSystemUIMode(kUIModeAllHidden, kUIOptionAutoShowMenuBar);
   407     } else {
   409     } else {
   408         SetSystemUIMode(kUIModeNormal, 0);
   410         SetSystemUIMode(kUIModeNormal, 0);
   409     }
   411     }
   410 }
   412 }
   411 
   413 
   559     // In Qt, a popup is seen as a 'stay on top' window.
   561     // In Qt, a popup is seen as a 'stay on top' window.
   560     // Since new groups are created for 'stays on top' windows, the
   562     // Since new groups are created for 'stays on top' windows, the
   561     // same must be done for popups. Otherwise, popups would be drawn
   563     // same must be done for popups. Otherwise, popups would be drawn
   562     // below 'stays on top' windows. Add 1 to get above pure stay-on-top windows.
   564     // below 'stays on top' windows. Add 1 to get above pure stay-on-top windows.
   563     qt_mac_set_window_group(window, Qt::Popup, qt_mac_get_group_level(kOverlayWindowClass)+1);
   565     qt_mac_set_window_group(window, Qt::Popup, qt_mac_get_group_level(kOverlayWindowClass)+1);
       
   566 }
       
   567 #endif
       
   568 
       
   569 #ifdef QT_MAC_USE_COCOA
       
   570 void qt_mac_set_needs_display(QWidget *widget, QRegion region)
       
   571 {
       
   572     NSView *theNSView = qt_mac_nativeview_for(widget);
       
   573     if (region.isEmpty()) {
       
   574         [theNSView setNeedsDisplay:YES];
       
   575         return;
       
   576     }
       
   577 
       
   578     QVector<QRect> rects = region.rects();
       
   579     for (int i = 0; i<rects.count(); ++i) {
       
   580         const QRect &rect = rects.at(i);
       
   581         NSRect nsrect = NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height());
       
   582         [theNSView setNeedsDisplayInRect:nsrect];
       
   583     }
       
   584 
   564 }
   585 }
   565 #endif
   586 #endif
   566 
   587 
   567 inline static bool updateRedirectedToGraphicsProxyWidget(QWidget *widget, const QRect &rect)
   588 inline static bool updateRedirectedToGraphicsProxyWidget(QWidget *widget, const QRect &rect)
   568 {
   589 {
   844                 widget->data->window_state = widget->data->window_state | Qt::WindowMaximized;
   865                 widget->data->window_state = widget->data->window_state | Qt::WindowMaximized;
   845                 QWindowStateChangeEvent e(Qt::WindowStates(widget->data->window_state
   866                 QWindowStateChangeEvent e(Qt::WindowStates(widget->data->window_state
   846                                                            & ~Qt::WindowMaximized));
   867                                                            & ~Qt::WindowMaximized));
   847                 QApplication::sendSpontaneousEvent(widget, &e);
   868                 QApplication::sendSpontaneousEvent(widget, &e);
   848             }
   869             }
   849             extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp
       
   850             qt_button_down = 0;
   870             qt_button_down = 0;
   851         } else if(ekind == kEventWindowCollapsed) {
   871         } else if(ekind == kEventWindowCollapsed) {
   852             if (!widget->isMinimized()) {
   872             if (!widget->isMinimized()) {
   853                 widget->data->window_state = widget->data->window_state | Qt::WindowMinimized;
   873                 widget->data->window_state = widget->data->window_state | Qt::WindowMinimized;
   854                 QWindowStateChangeEvent e(Qt::WindowStates(widget->data->window_state & ~Qt::WindowMinimized));
   874                 QWindowStateChangeEvent e(Qt::WindowStates(widget->data->window_state & ~Qt::WindowMinimized));
   872             }
   892             }
   873 
   893 
   874             //we send a hide to be like X11/Windows
   894             //we send a hide to be like X11/Windows
   875             QEvent e(QEvent::Hide);
   895             QEvent e(QEvent::Hide);
   876             QApplication::sendSpontaneousEvent(widget, &e);
   896             QApplication::sendSpontaneousEvent(widget, &e);
   877             extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp
       
   878             qt_button_down = 0;
   897             qt_button_down = 0;
   879         } else if(ekind == kEventWindowToolbarSwitchMode) {
   898         } else if(ekind == kEventWindowToolbarSwitchMode) {
   880             macSendToolbarChangeEvent(widget);
   899             macSendToolbarChangeEvent(widget);
   881             HIToolbarRef toolbar;
   900             HIToolbarRef toolbar;
   882             if (GetWindowToolbar(wid, &toolbar) == noErr) {
   901             if (GetWindowToolbar(wid, &toolbar) == noErr) {
  1246                 }
  1265                 }
  1247 #endif
  1266 #endif
  1248                 if (widget->isVisible() && widget->updatesEnabled()) { //process the actual paint event.
  1267                 if (widget->isVisible() && widget->updatesEnabled()) { //process the actual paint event.
  1249                     if(widget->testAttribute(Qt::WA_WState_InPaintEvent))
  1268                     if(widget->testAttribute(Qt::WA_WState_InPaintEvent))
  1250                         qWarning("QWidget::repaint: Recursive repaint detected");
  1269                         qWarning("QWidget::repaint: Recursive repaint detected");
       
  1270                     if (widget->isWindow() && !widget->d_func()->isOpaque
       
  1271                         && !widget->testAttribute(Qt::WA_MacBrushedMetal)) {
       
  1272                         QRect qrgnRect = qrgn.boundingRect();
       
  1273                         CGContextClearRect(cg, CGRectMake(qrgnRect.x(), qrgnRect.y(), qrgnRect.width(), qrgnRect.height()));
       
  1274                     }
  1251 
  1275 
  1252                     QPoint redirectionOffset(0, 0);
  1276                     QPoint redirectionOffset(0, 0);
  1253                     QWidget *tl = widget->window();
  1277                     QWidget *tl = widget->window();
  1254                     if (tl) {
  1278                     if (tl) {
  1255                         Qt::WindowFlags flags = tl->windowFlags();
  1279                         Qt::WindowFlags flags = tl->windowFlags();
  1295                         }
  1319                         }
  1296                         p.end();
  1320                         p.end();
  1297                         if (!redirectionOffset.isNull())
  1321                         if (!redirectionOffset.isNull())
  1298                             widget->d_func()->restoreRedirected();
  1322                             widget->d_func()->restoreRedirected();
  1299                     }
  1323                     }
  1300 
       
  1301                     if (widget->isWindow() && !widget->d_func()->isOpaque
       
  1302                            && !widget->testAttribute(Qt::WA_MacBrushedMetal)) {
       
  1303                         QRect qrgnRect = qrgn.boundingRect();
       
  1304                         CGContextClearRect(cg, CGRectMake(qrgnRect.x(), qrgnRect.y(), qrgnRect.width(), qrgnRect.height()));
       
  1305                     }
       
  1306 
       
  1307 
  1324 
  1308                     if(!HIObjectIsOfClass((HIObjectRef)hiview, kObjectQWidget))
  1325                     if(!HIObjectIsOfClass((HIObjectRef)hiview, kObjectQWidget))
  1309                         CallNextEventHandler(er, event);
  1326                         CallNextEventHandler(er, event);
  1310 
  1327 
  1311                     //send the paint
  1328                     //send the paint
  1499         } else if (ekind == kEventControlVisibilityChanged) {
  1516         } else if (ekind == kEventControlVisibilityChanged) {
  1500             handled_event = false;
  1517             handled_event = false;
  1501             if (widget) {
  1518             if (widget) {
  1502                 qt_event_request_window_change(widget);
  1519                 qt_event_request_window_change(widget);
  1503                 if (!HIViewIsVisible(HIViewRef(widget->winId()))) {
  1520                 if (!HIViewIsVisible(HIViewRef(widget->winId()))) {
  1504                     extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp
       
  1505                     if (widget == qt_button_down)
  1521                     if (widget == qt_button_down)
  1506                         qt_button_down = 0;
  1522                         qt_button_down = 0;
  1507                 }
  1523                 }
  1508             }
  1524             }
  1509         }
  1525         }
  1510         break; }
  1526         break; }
  1511     case kEventClassMouse: {
  1527     case kEventClassMouse: {
  1512         bool send_to_app = false;
  1528         bool send_to_app = false;
  1513         extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp
       
  1514         if(qt_button_down)
  1529         if(qt_button_down)
  1515             send_to_app = true;
  1530             send_to_app = true;
  1516         if(send_to_app) {
  1531         if(send_to_app) {
  1517             OSStatus err = SendEventToApplication(event);
  1532             OSStatus err = SendEventToApplication(event);
  1518             if(err != noErr)
  1533             if(err != noErr)
  1719   QWidget member functions
  1734   QWidget member functions
  1720  *****************************************************************************/
  1735  *****************************************************************************/
  1721 void QWidgetPrivate::determineWindowClass()
  1736 void QWidgetPrivate::determineWindowClass()
  1722 {
  1737 {
  1723     Q_Q(QWidget);
  1738     Q_Q(QWidget);
       
  1739 #if !defined(QT_NO_MAINWINDOW) && !defined(QT_NO_TOOLBAR)
       
  1740     // Make sure that QMainWindow has the MacWindowToolBarButtonHint when the
       
  1741     // unifiedTitleAndToolBarOnMac property is ON. This is to avoid reentry of
       
  1742     // setParent() triggered by the QToolBar::event(QEvent::ParentChange).
       
  1743     QMainWindow *mainWindow = qobject_cast<QMainWindow *>(q);
       
  1744     if (mainWindow && mainWindow->unifiedTitleAndToolBarOnMac()) {
       
  1745         data.window_flags |= Qt::MacWindowToolBarButtonHint;
       
  1746     }
       
  1747 #endif
  1724 #ifndef QT_MAC_USE_COCOA
  1748 #ifndef QT_MAC_USE_COCOA
  1725 // ### COCOA:Interleave these better!
  1749 // ### COCOA:Interleave these better!
  1726 
  1750 
  1727     const Qt::WindowType type = q->windowType();
  1751     const Qt::WindowType type = q->windowType();
  1728     Qt::WindowFlags &flags = data.window_flags;
  1752     Qt::WindowFlags &flags = data.window_flags;
  2741         if (qt_mac_is_macdrawer(q)) {
  2765         if (qt_mac_is_macdrawer(q)) {
  2742             oldDrawer = qt_mac_drawer_for(q);
  2766             oldDrawer = qt_mac_drawer_for(q);
  2743         }
  2767         }
  2744         if (wasWindow) {
  2768         if (wasWindow) {
  2745             oldToolbar = [oldWindow toolbar];
  2769             oldToolbar = [oldWindow toolbar];
       
  2770             [oldToolbar retain];
  2746             oldToolbarVisible = [oldToolbar isVisible];
  2771             oldToolbarVisible = [oldToolbar isVisible];
       
  2772             [oldWindow setToolbar:nil];
  2747         }
  2773         }
  2748 #endif
  2774 #endif
  2749     }
  2775     }
  2750     QWidget* oldtlw = q->window();
  2776     QWidget* oldtlw = q->window();
  2751 
  2777 
  2785 #else
  2811 #else
  2786             // Simply transfer our toolbar over. Everything should stay put, unlike in Carbon.
  2812             // Simply transfer our toolbar over. Everything should stay put, unlike in Carbon.
  2787             if (oldToolbar && !(f & Qt::FramelessWindowHint)) {
  2813             if (oldToolbar && !(f & Qt::FramelessWindowHint)) {
  2788                 OSWindowRef newWindow = qt_mac_window_for(q);
  2814                 OSWindowRef newWindow = qt_mac_window_for(q);
  2789                 [newWindow setToolbar:oldToolbar];
  2815                 [newWindow setToolbar:oldToolbar];
       
  2816                 [oldToolbar release];
  2790                 [oldToolbar setVisible:oldToolbarVisible];
  2817                 [oldToolbar setVisible:oldToolbarVisible];
  2791             }
  2818             }
  2792 #endif
  2819 #endif
  2793         }
  2820         }
  2794     }
  2821     }
  3373 void QWidgetPrivate::hide_sys()
  3400 void QWidgetPrivate::hide_sys()
  3374 {
  3401 {
  3375     Q_Q(QWidget);
  3402     Q_Q(QWidget);
  3376     if((q->windowType() == Qt::Desktop)) //you can't hide the desktop!
  3403     if((q->windowType() == Qt::Desktop)) //you can't hide the desktop!
  3377         return;
  3404         return;
  3378 
       
  3379     QMacCocoaAutoReleasePool pool;
  3405     QMacCocoaAutoReleasePool pool;
  3380     if(q->isWindow()) {
  3406     if(q->isWindow()) {
  3381         OSWindowRef window = qt_mac_window_for(q);
  3407         OSWindowRef window = qt_mac_window_for(q);
  3382         if(qt_mac_is_macsheet(q)) {
  3408         if(qt_mac_is_macsheet(q)) {
  3383 #ifndef QT_MAC_USE_COCOA
  3409 #ifndef QT_MAC_USE_COCOA
  3399         } else {
  3425         } else {
  3400 #ifndef QT_MAC_USE_COCOA
  3426 #ifndef QT_MAC_USE_COCOA
  3401             ShowHide(window, false);
  3427             ShowHide(window, false);
  3402 #else
  3428 #else
  3403             [window orderOut:window];
  3429             [window orderOut:window];
       
  3430             // Unfortunately it is not as easy as just hiding the window, we need
       
  3431             // to find out if we were in full screen mode. If we were and this is
       
  3432             // the last window in full screen mode then we need to unset the full screen
       
  3433             // mode. If this is not the last visible window in full screen mode then we
       
  3434             // don't change the full screen mode.
       
  3435             if(q->isFullScreen())
       
  3436             {
       
  3437                 bool keepFullScreen = false;
       
  3438                 QWidgetList windowList = qApp->topLevelWidgets();
       
  3439                 int windowCount = windowList.count();
       
  3440                 for(int i = 0; i < windowCount; i++)
       
  3441                 {
       
  3442                     QWidget *w = windowList[i];
       
  3443                     // If it is the same window, we don't need to check :-)
       
  3444                     if(q == w)
       
  3445                         continue;
       
  3446                     // If they are not visible or if they are minimized then
       
  3447                     // we just ignore them.
       
  3448                     if(!w->isVisible() || w->isMinimized())
       
  3449                         continue;
       
  3450                     // Is it full screen?
       
  3451                     // Notice that if there is one window in full screen mode then we
       
  3452                     // cannot switch the full screen mode off, therefore we just abort.
       
  3453                     if(w->isFullScreen()) {
       
  3454                         keepFullScreen = true;
       
  3455                         break;
       
  3456                     }
       
  3457                 }
       
  3458                 // No windows in full screen mode, so let just unset that flag.
       
  3459                 if(!keepFullScreen)
       
  3460                     qt_mac_set_fullscreen_mode(false);
       
  3461             }
  3404 #endif
  3462 #endif
  3405             toggleDrawers(false);
  3463             toggleDrawers(false);
  3406 #ifndef QT_MAC_USE_COCOA
  3464 #ifndef QT_MAC_USE_COCOA
  3407             // Clear modality (because it seems something that we've always done).
  3465             // Clear modality (because it seems something that we've always done).
  3408             if (data.window_modality != Qt::NonModal) {
  3466             if (data.window_modality != Qt::NonModal) {
  3463 #endif
  3521 #endif
  3464     }
  3522     }
  3465 
  3523 
  3466     if (!QWidget::mouseGrabber()){
  3524     if (!QWidget::mouseGrabber()){
  3467         QWidget *enterWidget = QApplication::widgetAt(QCursor::pos());
  3525         QWidget *enterWidget = QApplication::widgetAt(QCursor::pos());
       
  3526         if (enterWidget && enterWidget->data->in_destructor)
       
  3527             enterWidget = 0;
  3468         QApplicationPrivate::dispatchEnterLeave(enterWidget, qt_mouseover);
  3528         QApplicationPrivate::dispatchEnterLeave(enterWidget, qt_mouseover);
  3469         qt_mouseover = enterWidget;
  3529         qt_mouseover = enterWidget;
  3470     }
  3530     }
  3471 
  3531 
  3472     qt_event_request_window_change(q);
  3532     qt_event_request_window_change(q);
  3669     Q_Q(QWidget);
  3729     Q_Q(QWidget);
  3670     if((q->windowType() == Qt::Desktop))
  3730     if((q->windowType() == Qt::Desktop))
  3671         return;
  3731         return;
  3672 
  3732 
  3673 #if QT_MAC_USE_COCOA
  3733 #if QT_MAC_USE_COCOA
       
  3734     QMacCocoaAutoReleasePool pool;
  3674     if (isRealWindow()) {
  3735     if (isRealWindow()) {
  3675         // Calling orderFront shows the window on Cocoa too.
  3736         // Calling orderFront shows the window on Cocoa too.
  3676         if (!q->testAttribute(Qt::WA_DontShowOnScreen) && q->isVisible()) {
  3737         if (!q->testAttribute(Qt::WA_DontShowOnScreen) && q->isVisible()) {
  3677             [qt_mac_window_for(q) orderFront:qt_mac_window_for(q)];
  3738             [qt_mac_window_for(q) orderFront:qt_mac_window_for(q)];
  3678         }
  3739         }
  4406             deltaXRect.size.width = -dx;
  4467             deltaXRect.size.width = -dx;
  4407             deltaXRect.origin.x = scrollRect.size.width + dx;
  4468             deltaXRect.origin.x = scrollRect.size.width + dx;
  4408         }
  4469         }
  4409     }
  4470     }
  4410 
  4471 
       
  4472     // ### Scroll the dirty regions as well, the following is not correct.
       
  4473     QRegion displayRegion = r.isNull() ? dirtyOnWidget : (dirtyOnWidget & r);
       
  4474     const QVector<QRect> &rects = dirtyOnWidget.rects();
       
  4475     const QVector<QRect>::const_iterator end = rects.end();
       
  4476     QVector<QRect>::const_iterator it = rects.begin();
       
  4477     while (it != end) {
       
  4478 	const QRect rect = *it;
       
  4479 	const NSRect dirtyRect = NSMakeRect(rect.x() + dx, rect.y() + dy,
       
  4480 		rect.width(), rect.height());
       
  4481 	[view setNeedsDisplayInRect:dirtyRect];
       
  4482 	++it;
       
  4483     }
       
  4484 
  4411     NSSize deltaSize = NSMakeSize(dx, dy);
  4485     NSSize deltaSize = NSMakeSize(dx, dy);
  4412     [view translateRectsNeedingDisplayInRect:scrollRect by:deltaSize];
       
  4413     [view scrollRect:scrollRect by:deltaSize];
  4486     [view scrollRect:scrollRect by:deltaSize];
  4414     [view setNeedsDisplayInRect:deltaXRect];
  4487     [view setNeedsDisplayInRect:deltaXRect];
  4415     [view setNeedsDisplayInRect:deltaYRect];
  4488     [view setNeedsDisplayInRect:deltaYRect];
  4416 #endif // QT_MAC_USE_COCOA
  4489 #endif // QT_MAC_USE_COCOA
  4417 }
  4490 }
  4491 }
  4564 }
  4492 
  4565 
  4493 void QWidgetPrivate::deleteTLSysExtra()
  4566 void QWidgetPrivate::deleteTLSysExtra()
  4494 {
  4567 {
  4495 #ifndef QT_MAC_USE_COCOA
  4568 #ifndef QT_MAC_USE_COCOA
  4496     if(extra->topextra->group) {
  4569     if (extra->topextra->group) {
  4497         qt_mac_release_window_group(extra->topextra->group);
  4570         qt_mac_release_window_group(extra->topextra->group);
  4498         extra->topextra->group = 0;
  4571         extra->topextra->group = 0;
       
  4572     }
       
  4573     if (extra->topextra->windowIcon) {
       
  4574         ReleaseIconRef(extra->topextra->windowIcon);
       
  4575         extra->topextra->windowIcon = 0;
  4499     }
  4576     }
  4500 #endif
  4577 #endif
  4501 }
  4578 }
  4502 
  4579 
  4503 void QWidgetPrivate::updateFrameStrut()
  4580 void QWidgetPrivate::updateFrameStrut()
  4603 {
  4680 {
  4604     Q_Q(QWidget);
  4681     Q_Q(QWidget);
  4605     if (!q->testAttribute(Qt::WA_WState_Created) || !extra)
  4682     if (!q->testAttribute(Qt::WA_WState_Created) || !extra)
  4606         return;
  4683         return;
  4607 
  4684 
  4608     if (extra->hasMask && extra->maskBits.size() != q->size()) {
  4685     if (extra->hasMask) {
  4609         extra->maskBits = QImage(q->size(), QImage::Format_Mono);
  4686         if(extra->maskBits.size() != q->size()) {
       
  4687             extra->maskBits = QImage(q->size(), QImage::Format_Mono);
       
  4688         }
  4610         extra->maskBits.fill(QColor(Qt::color1).rgba());
  4689         extra->maskBits.fill(QColor(Qt::color1).rgba());
  4611         extra->maskBits.setNumColors(2);
  4690         extra->maskBits.setNumColors(2);
  4612         extra->maskBits.setColor(0, QColor(Qt::color0).rgba());
  4691         extra->maskBits.setColor(0, QColor(Qt::color0).rgba());
  4613         extra->maskBits.setColor(1, QColor(Qt::color1).rgba());
  4692         extra->maskBits.setColor(1, QColor(Qt::color1).rgba());
  4614         QPainter painter(&extra->maskBits);
  4693         QPainter painter(&extra->maskBits);