diff options
author | Richard Moe Gustavsen <richard.gustavsen@nokia.com> | 2010-10-15 11:48:51 (GMT) |
---|---|---|
committer | Richard Moe Gustavsen <richard.gustavsen@nokia.com> | 2010-10-15 12:44:32 (GMT) |
commit | 534ba3c7314820604ba5aeeffa6051c91e7c1d09 (patch) | |
tree | 793ce3694998bd0777c91a7c491fa79e0931c401 /src/gui | |
parent | b44ca15776227c8d04e88e1c343a87fd6c54fee0 (diff) | |
download | Qt-534ba3c7314820604ba5aeeffa6051c91e7c1d09.zip Qt-534ba3c7314820604ba5aeeffa6051c91e7c1d09.tar.gz Qt-534ba3c7314820604ba5aeeffa6051c91e7c1d09.tar.bz2 |
Cocoa: fix child window issues (QTBUG 13867, 14420, 13126)
The main problem behind these issues is the fact that when two
windows exists in a parent-child relationship (using
the [NSWindow addChild] API), Cocoa will automatically hide both
windows even when just hiding one of them. This turns out really bad
when the child is a tool window, because those will automatically be
hidden when the application becomes deactivated. And as such, the
parent will hide as well, tool or not.
So after a LOT of investigation, involving manually trying to level windows
rather than using the addChild API, the conclusing is that we cannot do
it; Cocoa and Qt just tries to outsmart each other. So instead, we now
say that only normal windows and dialogs can be part of a parent-child
relationship (which seems to be how Apple intended it as well). The
rest, and in particular tool windows, we just ignore.
This will differ from some other platforms, but at the same time, since
tool windows are on a level above other windows on mac from before, and
the docs specifies that this can be different from platform to platform,
we see it as acceptable.
Rev-By: prasanth
Rev-By: msorvig
Diffstat (limited to 'src/gui')
-rw-r--r-- | src/gui/kernel/qwidget_mac.mm | 47 |
1 files changed, 33 insertions, 14 deletions
diff --git a/src/gui/kernel/qwidget_mac.mm b/src/gui/kernel/qwidget_mac.mm index 1e2aa9f..b3b9183 100644 --- a/src/gui/kernel/qwidget_mac.mm +++ b/src/gui/kernel/qwidget_mac.mm @@ -2794,19 +2794,36 @@ void QWidgetPrivate::transferChildren() #ifdef QT_MAC_USE_COCOA void QWidgetPrivate::setSubWindowStacking(bool set) { + // This will set/remove a visual relationship between parent and child on screen. + // The reason for doing this is to ensure that a child always stacks infront of + // its parent. Unfortunatly is turns out that [NSWindow addChildWindow] has + // several unwanted side-effects, one of them being the moving of a child when + // moving the parent, which we choose to accept. A way tougher side-effect is + // that Cocoa will hide the parent if you hide the child. And in the case of + // a tool window, since it will normally hide when you deactivate the + // application, Cocoa will hide the parent upon deactivate as well. The result often + // being no more visible windows on screen. So, to make a long story short, we only + // allow parent-child relationships between windows that both are on the NSNormalWindowLevel + // (because Cocoa will also use the window level to decide upon strange behaviour). + Q_Q(QWidget); - if (!q->isWindow() || !q->testAttribute(Qt::WA_WState_Created)) + if (!q->isWindow()) + return; + NSWindow *qwin = [qt_mac_nativeview_for(q) window]; + if (!qwin) + return; + if (set && [qwin level] != NSNormalWindowLevel) + return; + if (set && ![qwin isVisible]) return; if (QWidget *parent = q->parentWidget()) { - if (parent->testAttribute(Qt::WA_WState_Created)) { + if (NSWindow *pwin = [qt_mac_nativeview_for(parent) window]) { if (set) { - if (parent->isVisible()) { - NSWindow *childwin = qt_mac_window_for(q); - [qt_mac_window_for(parent) addChildWindow:childwin ordered:NSWindowAbove]; - } + if ([pwin isVisible] && [pwin level] == NSNormalWindowLevel && ![qwin parentWindow]) + [pwin addChildWindow:qwin ordered:NSWindowAbove]; } else { - [qt_mac_window_for(parent) removeChildWindow:qt_mac_window_for(q)]; + [pwin removeChildWindow:qwin]; } } } @@ -2814,12 +2831,14 @@ void QWidgetPrivate::setSubWindowStacking(bool set) QList<QWidget *> widgets = q->findChildren<QWidget *>(); for (int i=0; i<widgets.size(); ++i) { QWidget *child = widgets.at(i); - if (child->isWindow() && child->testAttribute(Qt::WA_WState_Created) && child->isVisibleTo(q)) { - if (set) { - NSWindow *childwin = qt_mac_window_for(child); - [qt_mac_window_for(q) addChildWindow:childwin ordered:NSWindowAbove]; - } else { - [qt_mac_window_for(q) removeChildWindow:qt_mac_window_for(child)]; + if (child && child->isWindow()) { + if (NSWindow *cwin = [qt_mac_nativeview_for(child) window]) { + if (set) { + if ([cwin isVisible] && [cwin level] == NSNormalWindowLevel && ![cwin parentWindow]) + [qwin addChildWindow:cwin ordered:NSWindowAbove]; + } else { + [qwin removeChildWindow:qt_mac_window_for(child)]; + } } } } @@ -3442,7 +3461,6 @@ void QWidgetPrivate::show_sys() #else // sync the opacity value back (in case of a fade). [window setAlphaValue:q->windowOpacity()]; - setSubWindowStacking(true); QWidget *top = 0; if (QApplicationPrivate::tryModalHelper(q, &top)) { @@ -3461,6 +3479,7 @@ void QWidgetPrivate::show_sys() [modalWin orderFront:window]; } } + setSubWindowStacking(true); #endif if (q->windowType() == Qt::Popup) { if (q->focusWidget()) |