diff options
author | Gareth Stockwell <gareth.stockwell@sosco.com> | 2009-10-07 16:30:47 (GMT) |
---|---|---|
committer | Gareth Stockwell <gareth.stockwell@sosco.com> | 2009-10-09 07:07:53 (GMT) |
commit | 9371ae3ff036a622f578023377cfcacbc733b804 (patch) | |
tree | 3cdea47ed4143add16adf3369bd3980969fa7b07 /src/gui/kernel/qwidget_s60.cpp | |
parent | dda32cb904430e225566b047004b93c7be8ecca9 (diff) | |
download | Qt-9371ae3ff036a622f578023377cfcacbc733b804.zip Qt-9371ae3ff036a622f578023377cfcacbc733b804.tar.gz Qt-9371ae3ff036a622f578023377cfcacbc733b804.tar.bz2 |
Modified reparenting to correctly deal with native child widgets
Both reparenting and modification of window flags are done by calling
QWidget::setParent. If either the parent changes, or a non-top-level
widget becomes top-level (as a result of OR-ing Qt::Window into its
window flags), a new native window ID is created for the widget. The
Symbian implementation of setParent_sys had a flaw which manifested
itself in the following situation:
1. We start with a native widget X, and its child Y, which is also
native. There exist parent-child relationships between the associated
CCoeControl instances, and the native windows (represented by RWindow
handles).
2. X gets a new native window created as a result of a call to
setParent.
3. QWidgetPrivate::reparentChildren calls SetParent on Y's control, to
re-establish the parent-child relationship.
The problem is that the window owned by Y's control now has no parent,
so if we try to re-size the widget, the window server panics the client
thread (WSERV-52).
Because Symbian does not allow existing windows to be re-parented, and
nor does it allow a window-owning control to re-create a new window,
the only way to provide Y's window with a parent is to destroy the
control and create a new one, passing in X's new window to the
CCoeControl::CreateWindowL function.
The changes made are as follows:
a) QWidgetPrivate::reparentChildren is therefore modified to call
create_sys, with destroyOldWindow set to true.
b) QWidgetPrivate::create_sys is modified to take account of the value
of this flag in all cases. (Previously it only did so if a new WId was
passed in by the caller).
c) The call to setWinId is delayed until the control and window are
fully initialized. This is to allow us to emit a new event,
WinIdChanged, from setWinId, in order to inform the widget that its
winId has changed.
d) QWidgetPrivate::activateSymbianWindow is modified in order to
support this change of call ordering.
Note that QWidgetPrivate::create_sys requires some re-factoring in
order to remove the redundancy between the top-level and child widget
cases.
Task-number: QTBUG-4664
Reviewed-by: axis
Diffstat (limited to 'src/gui/kernel/qwidget_s60.cpp')
-rw-r--r-- | src/gui/kernel/qwidget_s60.cpp | 69 |
1 files changed, 47 insertions, 22 deletions
diff --git a/src/gui/kernel/qwidget_s60.cpp b/src/gui/kernel/qwidget_s60.cpp index 3328cee..5527cc8 100644 --- a/src/gui/kernel/qwidget_s60.cpp +++ b/src/gui/kernel/qwidget_s60.cpp @@ -318,8 +318,6 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de bool desktop = (type == Qt::Desktop); //bool tool = (type == Qt::Tool || type == Qt::Drawer); - WId id = 0; - if (popup) flags |= Qt::WindowStaysOnTopHint; // a popup stays on top @@ -341,13 +339,10 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de data.crect.setSize(QSize(width, height)); } - CCoeControl *destroyw = 0; + CCoeControl *const destroyw = destroyOldWindow ? data.winid : 0; createExtra(); if (window) { - if (destroyOldWindow) - destroyw = data.winid; - id = window; setWinId(window); TRect tr = window->Rect(); data.crect.setRect(tr.iTl.iX, tr.iTl.iY, tr.Width(), tr.Height()); @@ -355,10 +350,15 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de } else if (topLevel) { if (!q->testAttribute(Qt::WA_Moved) && !q->testAttribute(Qt::WA_DontShowOnScreen)) data.crect.moveTopLeft(QPoint(clientRect.iTl.iX, clientRect.iTl.iY)); - QSymbianControl *control= q_check_ptr(new QSymbianControl(q)); - id = (WId)control; - setWinId(id); - QT_TRAP_THROWING(control->ConstructL(true,desktop)); + + QScopedPointer<QSymbianControl> control( q_check_ptr(new QSymbianControl(q)) ); + QT_TRAP_THROWING(control->ConstructL(true, desktop)); + + // Symbian windows are always created in an inactive state + // We perform this assignment for the case where the window is being re-created + // as aa result of a call to setParent_sys, on either this widget or one of its + // ancestors. + extra->activated = 0; if (!desktop) { TInt stackingFlags; @@ -368,7 +368,7 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de stackingFlags = ECoeStackFlagStandard; } control->MakeVisible(false); - QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control, ECoeStackPriorityDefault, stackingFlags)); + QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control.data(), ECoeStackPriorityDefault, stackingFlags)); // Avoid keyboard focus to a hidden window. control->setFocusSafely(false); @@ -391,11 +391,22 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de int x, y, w, h; data.crect.getRect(&x, &y, &w, &h); control->SetRect(TRect(TPoint(x, y), TSize(w, h))); + + // We wait until the control is fully constructed before calling setWinId, because + // this generates a WinIdChanged event. + setWinId(control.take()); + } else if (q->testAttribute(Qt::WA_NativeWindow) || paintOnScreen()) { // create native child widget - QSymbianControl *control = new QSymbianControl(q); - setWinId(control); + + QScopedPointer<QSymbianControl> control( q_check_ptr(new QSymbianControl(q)) ); QT_TRAP_THROWING(control->ConstructL(!parentWidget)); + // Symbian windows are always created in an inactive state + // We perform this assignment for the case where the window is being re-created + // as aa result of a call to setParent_sys, on either this widget or one of its + // ancestors. + extra->activated = 0; + TInt stackingFlags; if ((q->windowType() & Qt::Popup) == Qt::Popup) { stackingFlags = ECoeStackFlagRefusesAllKeys | ECoeStackFlagRefusesFocus; @@ -403,7 +414,7 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de stackingFlags = ECoeStackFlagStandard; } control->MakeVisible(false); - QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control, ECoeStackPriorityDefault, stackingFlags)); + QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control.data(), ECoeStackPriorityDefault, stackingFlags)); // Avoid keyboard focus to a hidden window. control->setFocusSafely(false); @@ -418,7 +429,11 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de | EPointerFilterMove | EPointerFilterDrag, 0); if (q->isVisible() && q->testAttribute(Qt::WA_Mapped)) - activateSymbianWindow(); + activateSymbianWindow(control.data()); + + // We wait until the control is fully constructed before calling setWinId, because + // this generates a WinIdChanged event. + setWinId(control.take()); } if (destroyw) { @@ -434,7 +449,7 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de void QWidgetPrivate::show_sys() { Q_Q(QWidget); - + if (q->testAttribute(Qt::WA_OutsideWSRange)) return; @@ -468,7 +483,7 @@ void QWidgetPrivate::show_sys() invalidateBuffer(q->rect()); } -void QWidgetPrivate::activateSymbianWindow() +void QWidgetPrivate::activateSymbianWindow(WId wid) { Q_Q(QWidget); @@ -476,8 +491,12 @@ void QWidgetPrivate::activateSymbianWindow() Q_ASSERT(q->testAttribute(Qt::WA_Mapped)); Q_ASSERT(!extra->activated); - WId id = q->internalWinId(); - QT_TRAP_THROWING(id->ActivateL()); + if(!wid) + wid = q->internalWinId(); + + Q_ASSERT(wid); + + QT_TRAP_THROWING(wid->ActivateL()); extra->activated = 1; } @@ -566,8 +585,14 @@ void QWidgetPrivate::reparentChildren() w->d_func()->invalidateBuffer(w->rect()); WId parent = q->effectiveWinId(); WId child = w->effectiveWinId(); - if (parent != child) - child->SetParent(parent); + if (parent != child) { + // Child widget is native. Because Symbian windows cannot be + // re-parented, we must re-create the window. + const WId window = 0; + const bool initializeWindow = false; + const bool destroyOldWindow = true; + w->d_func()->create_sys(window, initializeWindow, destroyOldWindow); + } // ### TODO: We probably also need to update the component array here w->d_func()->reparentChildren(); } else { @@ -1253,7 +1278,7 @@ void QWidget::grabMouse() WId id = effectiveWinId(); id->SetPointerCapture(true); QWidgetPrivate::mouseGrabber = this; - + #ifndef QT_NO_CURSOR QApplication::setOverrideCursor(cursor()); #endif |