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); |