1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
11 ** Licensees holding valid Qt Commercial licenses may use this file in
12 ** accordance with the Qt Commercial License Agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and Nokia.
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** GNU General Public License Usage
29 ** Alternatively, this file may be used under the terms of the GNU
30 ** General Public License version 3.0 as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL included in the
32 ** packaging of this file. Please review the following information to
33 ** ensure the GNU General Public License version 3.0 requirements will be
34 ** met: http://www.gnu.org/copyleft/gpl.html.
36 ** If you have questions regarding the use of this file, please contact
37 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 #include "qwidget_p.h"
43 #include "qdesktopwidget.h"
44 #include "qapplication.h"
45 #include "qapplication_p.h"
46 #include "private/qbackingstore_p.h"
51 #include "private/qwindowsurface_s60_p.h"
53 #include <qinputcontext.h>
60 // This is necessary in order to be able to perform delayed invocation on slots
61 // which take arguments of type WId. One example is
62 // QWidgetPrivate::_q_delayedDestroy, which is used to delay destruction of
63 // CCoeControl objects until after the CONE event handler has finished running.
64 Q_DECLARE_METATYPE(WId)
66 // Workaround for the fact that S60 SDKs 3.x do not contain the akntoolbar.h
67 // header, even though the documentation says that it should be there, and indeed
68 // it is present in the library.
69 class CAknToolbar : public CAknControl,
70 public MCoeControlObserver,
71 public MCoeControlBackground,
72 public MEikCommandObserver,
73 public MAknFadedComponent
76 IMPORT_C void SetToolbarVisibility(const TBool visible);
81 extern bool qt_nograb();
83 QWidget *QWidgetPrivate::mouseGrabber = 0;
84 QWidget *QWidgetPrivate::keyboardGrabber = 0;
85 CEikButtonGroupContainer *QS60Data::cba = 0;
87 static bool isEqual(const QList<QAction*>& a, const QList<QAction*>& b)
89 if ( a.count() != b.count())
92 while (index<a.count()) {
93 if (a.at(index)->softKeyRole() != b.at(index)->softKeyRole())
95 if (a.at(index)->text().compare(b.at(index)->text())!=0)
102 void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &)
104 // Note: based on x11 implementation
106 static const int XCOORD_MAX = 16383;
107 static const int WRECT_MAX = 16383;
111 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
114 There are up to four different coordinate systems here:
115 Qt coordinate system for this widget.
116 Symbian coordinate system for this widget (relative to wrect).
117 Qt coordinate system for parent
118 Symbian coordinate system for parent (relative to parent's wrect).
121 QRect validRange(-XCOORD_MAX,-XCOORD_MAX, 2*XCOORD_MAX, 2*XCOORD_MAX);
122 QRect wrectRange(-WRECT_MAX,-WRECT_MAX, 2*WRECT_MAX, 2*WRECT_MAX);
124 //xrect is the Symbian geometry of my widget. (starts out in parent's Qt coord sys, and ends up in parent's Symbian coord sys)
125 QRect xrect = data.crect;
127 const QWidget *const parent = q->parentWidget();
128 QRect parentWRect = parent->data->wrect;
130 if (parentWRect.isValid()) {
131 // parent is clipped, and we have to clip to the same limit as parent
132 if (!parentWRect.contains(xrect)) {
133 xrect &= parentWRect;
135 //translate from parent's to my Qt coord sys
136 wrect.translate(-data.crect.topLeft());
138 //translate from parent's Qt coords to parent's X coords
139 xrect.translate(-parentWRect.topLeft());
142 // parent is not clipped, we may or may not have to clip
144 if (data.wrect.isValid() && QRect(QPoint(),data.crect.size()).contains(data.wrect)) {
145 // This is where the main optimization is: we are already
146 // clipped, and if our clip is still valid, we can just
147 // move our window, and do not need to move or clip
150 QRect vrect = xrect & parent->rect();
151 vrect.translate(-data.crect.topLeft()); //the part of me that's visible through parent, in my Qt coords
152 if (data.wrect.contains(vrect)) {
154 xrect.translate(data.crect.topLeft());
156 data.winid->SetExtent(TPoint(xrect.x(), xrect.y()), TSize(xrect.width(), xrect.height()));
161 if (!validRange.contains(xrect)) {
162 // we are too big, and must clip
165 wrect.translate(-data.crect.topLeft());
166 //parent's X coord system is equal to parent's Qt coord
167 //sys, so we don't need to map xrect.
171 // unmap if we are outside the valid window system coord system
172 bool outsideRange = !xrect.isValid();
173 bool mapWindow = false;
174 if (q->testAttribute(Qt::WA_OutsideWSRange) != outsideRange) {
175 q->setAttribute(Qt::WA_OutsideWSRange, outsideRange);
178 data.winid->DrawableWindow()->SetVisible(EFalse);
179 q->setAttribute(Qt::WA_Mapped, false);
180 } else if (!q->isHidden()) {
188 bool jump = (data.wrect != wrect);
191 // and now recursively for all children...
192 for (int i = 0; i < children.size(); ++i) {
193 QObject *object = children.at(i);
194 if (object->isWidgetType()) {
195 QWidget *w = static_cast<QWidget *>(object);
196 if (!w->isWindow() && w->testAttribute(Qt::WA_WState_Created))
197 w->d_func()->setWSGeometry(jump);
202 // move ourselves to the new position and map (if necessary) after
203 // the movement. Rationale: moving unmapped windows is much faster
204 // than moving mapped windows
205 if (!parent->internalWinId())
206 xrect.translate(parent->mapTo(q->nativeParentWidget(), QPoint(0, 0)));
208 data.winid->SetExtent(TPoint(xrect.x(), xrect.y()), TSize(xrect.width(), xrect.height()));
211 if (mapWindow and !dontShow) {
212 q->setAttribute(Qt::WA_Mapped);
213 if (q->internalWinId())
214 q->internalWinId()->DrawableWindow()->SetVisible(ETrue);
217 if (jump && data.winid) {
218 RWindow *const window = static_cast<RWindow *>(data.winid->DrawableWindow());
219 window->Invalidate(TRect(0, 0, wrect.width(), wrect.height()));
223 void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove)
227 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
229 if ((q->windowType() == Qt::Desktop))
232 QPoint oldPos(q->pos());
233 QSize oldSize(q->size());
234 QRect oldGeom(data.crect);
236 // Lose maximized status if deliberate resize
237 if (w != oldSize.width() || h != oldSize.height())
238 data.window_state &= ~Qt::WindowMaximized;
240 if (extra) { // any size restrictions?
241 w = qMin(w,extra->maxw);
242 h = qMin(h,extra->maxh);
243 w = qMax(w,extra->minw);
244 h = qMax(h,extra->minh);
248 topData()->normalGeometry = QRect(0, 0, -1, -1);
250 uint s = data.window_state;
251 s &= ~(Qt::WindowMaximized | Qt::WindowFullScreen);
252 data.window_state = s;
255 bool isResize = w != oldSize.width() || h != oldSize.height();
256 if (!isMove && !isResize)
260 if (w == 0 || h == 0) {
261 q->setAttribute(Qt::WA_OutsideWSRange, true);
262 if (q->isVisible() && q->testAttribute(Qt::WA_Mapped))
264 data.crect = QRect(x, y, w, h);
265 data.window_state &= ~Qt::WindowFullScreen;
266 } else if (q->isVisible() && q->testAttribute(Qt::WA_OutsideWSRange)) {
267 q->setAttribute(Qt::WA_OutsideWSRange, false);
269 // put the window in its place and show it
270 q->internalWinId()->SetRect(TRect(TPoint(x, y), TSize(w, h)));
271 data.crect.setRect(x, y, w, h);
274 QRect r = QRect(x, y, w, h);
276 q->internalWinId()->SetRect(TRect(TPoint(x, y), TSize(w, h)));
277 topData()->normalGeometry = data.crect;
280 data.crect.setRect(x, y, w, h);
282 QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData();
283 const bool inTopLevelResize = tlwExtra ? tlwExtra->inTopLevelResize : false;
285 if (q->isVisible() && (!inTopLevelResize || q->internalWinId())) {
286 // Top-level resize optimization does not work for native child widgets;
287 // disable it for this particular widget.
288 if (inTopLevelResize)
289 tlwExtra->inTopLevelResize = false;
290 if (!isResize && maybeBackingStore())
291 moveRect(QRect(oldPos, oldSize), x - oldPos.x(), y - oldPos.y());
293 invalidateBuffer_resizeHelper(oldPos, oldSize);
295 if (inTopLevelResize)
296 tlwExtra->inTopLevelResize = true;
298 if (q->testAttribute(Qt::WA_WState_Created))
302 if (q->isVisible()) {
303 if (isMove && q->pos() != oldPos) {
304 QMoveEvent e(q->pos(), oldPos);
305 QApplication::sendEvent(q, &e);
308 bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt();
309 const bool setTopLevelResize = !slowResize && q->isWindow() && extra && extra->topextra
310 && !extra->topextra->inTopLevelResize;
311 if (setTopLevelResize)
312 extra->topextra->inTopLevelResize = true;
313 QResizeEvent e(q->size(), oldSize);
314 QApplication::sendEvent(q, &e);
315 if (!q->testAttribute(Qt::WA_StaticContents) && q->internalWinId())
316 q->internalWinId()->DrawDeferred();
317 if (setTopLevelResize)
318 extra->topextra->inTopLevelResize = false;
321 if (isMove && q->pos() != oldPos)
322 q->setAttribute(Qt::WA_PendingMoveEvent, true);
324 q->setAttribute(Qt::WA_PendingResizeEvent, true);
328 void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool destroyOldWindow)
332 Qt::WindowType type = q->windowType();
333 Qt::WindowFlags &flags = data.window_flags;
334 QWidget *parentWidget = q->parentWidget();
336 bool topLevel = (flags & Qt::Window);
337 bool popup = (type == Qt::Popup);
338 bool dialog = (type == Qt::Dialog
340 || (flags & Qt::MSWindowsFixedSizeDialogHint));
341 bool desktop = (type == Qt::Desktop);
342 //bool tool = (type == Qt::Tool || type == Qt::Drawer);
345 flags |= Qt::WindowStaysOnTopHint; // a popup stays on top
347 TRect clientRect = static_cast<CEikAppUi*>(S60->appUi())->ClientRect();
348 int sw = clientRect.Width();
349 int sh = clientRect.Height();
352 TSize screenSize = S60->screenDevice()->SizeInPixels();
353 data.crect.setRect(0, 0, screenSize.iWidth, screenSize.iHeight);
354 q->setAttribute(Qt::WA_DontShowOnScreen);
355 } else if (topLevel && !q->testAttribute(Qt::WA_Resized)){
359 width = qMax(qMin(width, extra->maxw), extra->minw);
360 height = qMax(qMin(height, extra->maxh), extra->minh);
362 data.crect.setSize(QSize(width, height));
365 CCoeControl *const destroyw = destroyOldWindow ? data.winid : 0;
370 TRect tr = window->Rect();
371 data.crect.setRect(tr.iTl.iX, tr.iTl.iY, tr.Width(), tr.Height());
373 } else if (topLevel) {
374 if (!q->testAttribute(Qt::WA_Moved) && !q->testAttribute(Qt::WA_DontShowOnScreen))
375 data.crect.moveTopLeft(QPoint(clientRect.iTl.iX, clientRect.iTl.iY));
377 QScopedPointer<QSymbianControl> control( q_check_ptr(new QSymbianControl(q)) );
378 QT_TRAP_THROWING(control->ConstructL(true, desktop));
379 control->SetMopParent(static_cast<CEikAppUi*>(S60->appUi()));
381 // Symbian windows are always created in an inactive state
382 // We perform this assignment for the case where the window is being re-created
383 // as a result of a call to setParent_sys, on either this widget or one of its
385 extra->activated = 0;
389 if ((q->windowType() & Qt::Popup) == Qt::Popup) {
390 stackingFlags = ECoeStackFlagRefusesAllKeys | ECoeStackFlagRefusesFocus;
392 stackingFlags = ECoeStackFlagStandard;
394 control->MakeVisible(false);
395 QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control.data(), ECoeStackPriorityDefault, stackingFlags));
396 // Avoid keyboard focus to a hidden window.
397 control->setFocusSafely(false);
399 RDrawableWindow *const drawableWindow = control->DrawableWindow();
400 // Request mouse move events.
401 drawableWindow->PointerFilter(EPointerFilterEnterExit
402 | EPointerFilterMove | EPointerFilterDrag, 0);
403 drawableWindow->EnableVisibilityChangeEvents();
407 q->setAttribute(Qt::WA_WState_Created);
410 data.crect.getRect(&x, &y, &w, &h);
411 control->SetRect(TRect(TPoint(x, y), TSize(w, h)));
413 // We wait until the control is fully constructed before calling setWinId, because
414 // this generates a WinIdChanged event.
415 setWinId(control.take());
418 s60UpdateIsOpaque(); // must be called after setWinId()
420 } else if (q->testAttribute(Qt::WA_NativeWindow) || paintOnScreen()) { // create native child widget
422 QScopedPointer<QSymbianControl> control( q_check_ptr(new QSymbianControl(q)) );
423 QT_TRAP_THROWING(control->ConstructL(!parentWidget));
425 // Symbian windows are always created in an inactive state
426 // We perform this assignment for the case where the window is being re-created
427 // as a result of a call to setParent_sys, on either this widget or one of its
429 extra->activated = 0;
432 if ((q->windowType() & Qt::Popup) == Qt::Popup) {
433 stackingFlags = ECoeStackFlagRefusesAllKeys | ECoeStackFlagRefusesFocus;
435 stackingFlags = ECoeStackFlagStandard;
437 control->MakeVisible(false);
438 QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control.data(), ECoeStackPriorityDefault, stackingFlags));
439 // Avoid keyboard focus to a hidden window.
440 control->setFocusSafely(false);
442 q->setAttribute(Qt::WA_WState_Created);
444 data.crect.getRect(&x, &y, &w, &h);
445 control->SetRect(TRect(TPoint(x, y), TSize(w, h)));
447 RDrawableWindow *const drawableWindow = control->DrawableWindow();
448 // Request mouse move events.
449 drawableWindow->PointerFilter(EPointerFilterEnterExit
450 | EPointerFilterMove | EPointerFilterDrag, 0);
451 drawableWindow->EnableVisibilityChangeEvents();
453 if (q->isVisible() && q->testAttribute(Qt::WA_Mapped)) {
454 activateSymbianWindow(control.data());
455 control->MakeVisible(true);
458 // We wait until the control is fully constructed before calling setWinId, because
459 // this generates a WinIdChanged event.
460 setWinId(control.take());
464 destroyw->ControlEnv()->AppUi()->RemoveFromStack(destroyw);
466 // Delay deletion of the control in case this function is called in the
467 // context of a CONE event handler such as
468 // CCoeControl::ProcessPointerEventL
469 QMetaObject::invokeMethod(q, "_q_delayedDestroy",
470 Qt::QueuedConnection, Q_ARG(WId, destroyw));
473 if (q->testAttribute(Qt::WA_AcceptTouchEvents))
474 registerTouchWindow();
478 void QWidgetPrivate::show_sys()
482 if (q->testAttribute(Qt::WA_OutsideWSRange))
485 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
487 q->setAttribute(Qt::WA_Mapped);
489 if (q->testAttribute(Qt::WA_DontShowOnScreen)) {
490 invalidateBuffer(q->rect());
494 if (q->internalWinId()) {
495 if (!extra->activated)
496 activateSymbianWindow();
498 QSymbianControl *id = static_cast<QSymbianControl *>(q->internalWinId());
499 const bool isFullscreen = q->windowState() & Qt::WindowFullScreen;
500 const TBool cbaRequested = q->windowFlags() & Qt::WindowSoftkeysVisibleHint;
503 // Lazily initialize the S60 screen furniture when the first window is shown.
504 if (q->isWindow() && !QApplication::testAttribute(Qt::AA_S60DontConstructApplicationPanes)
505 && !S60->buttonGroupContainer() && !S60->statusPane()) {
507 if (!q->testAttribute(Qt::WA_DontShowOnScreen)) {
509 // Create the status pane and CBA here
510 CEikAppUi *ui = static_cast<CEikAppUi *>(S60->appUi());
511 MEikAppUiFactory *factory = CEikonEnv::Static()->AppUiFactory();
514 factory->CreateResourceIndependentFurnitureL(ui);
516 TRect boundingRect = static_cast<CEikAppUi*>(S60->appUi())->ClientRect();
518 CEikButtonGroupContainer *cba = CEikButtonGroupContainer::NewL(CEikButtonGroupContainer::ECba,
519 CEikButtonGroupContainer::EHorizontal,ui,R_AVKON_SOFTKEYS_EMPTY_WITH_IDS);
520 if (isFullscreen && !cbaRequested)
521 cba->MakeVisible(false);
523 CEikButtonGroupContainer *oldCba = factory->SwapButtonGroup(cba);
525 S60->setButtonGroupContainer(cba);
527 // If the creation of the first widget is delayed, for example by doing it
528 // inside the event loop, S60 somehow "forgets" to set the visibility of the
529 // toolbar (the three middle softkeys) when you flip the phone over, so we
530 // need to do it ourselves to avoid a "hole" in the application, even though
531 // Qt itself does not use the toolbar directly..
532 CAknAppUi *appui = dynamic_cast<CAknAppUi *>(CEikonEnv::Static()->AppUi());
534 CAknToolbar *toolbar = appui->PopupToolbar();
535 if (toolbar && !toolbar->IsVisible())
536 toolbar->SetToolbarVisibility(ETrue);
539 CEikMenuBar *menuBar = new(ELeave) CEikMenuBar;
540 menuBar->ConstructL(ui, 0, R_AVKON_MENUPANE_EMPTY);
541 menuBar->SetMenuType(CEikMenuBar::EMenuOptions);
542 S60->appUi()->AddToStackL(menuBar,ECoeStackPriorityMenu,ECoeStackFlagRefusesFocus);
544 CEikMenuBar *oldMenu = factory->SwapMenuBar(menuBar);
548 if (S60->statusPane()) {
549 // Use QDesktopWidget as the status pane observer to proxy for the AppUi.
550 // Can't use AppUi directly because it privately inherits from MEikStatusPaneObserver.
551 QSymbianControl *desktopControl = static_cast<QSymbianControl *>(QApplication::desktop()->winId());
552 S60->statusPane()->SetObserver(desktopControl);
554 const bool cbaVisible = S60->buttonGroupContainer() && S60->buttonGroupContainer()->IsVisible();
555 S60->setStatusPaneAndButtonGroupVisibility(false, cbaVisible);
562 // Fill client area if maximized OR
563 // Put window below status pane unless the window has an explicit position.
565 if (q->windowState() & Qt::WindowMaximized) {
566 TRect r = static_cast<CEikAppUi*>(S60->appUi())->ClientRect();
567 id->SetExtent(r.iTl, r.Size());
568 } else if (!q->testAttribute(Qt::WA_Moved) && q->windowType() != Qt::Dialog) {
569 id->SetPosition(static_cast<CEikAppUi*>(S60->appUi())->ClientRect().iTl);
573 id->MakeVisible(true);
575 if(q->isWindow()&&!q->testAttribute(Qt::WA_ShowWithoutActivating))
576 id->setFocusSafely(true);
579 invalidateBuffer(q->rect());
582 void QWidgetPrivate::activateSymbianWindow(WId wid)
586 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
587 Q_ASSERT(q->testAttribute(Qt::WA_Mapped));
588 Q_ASSERT(!extra->activated);
591 wid = q->internalWinId();
595 QT_TRAP_THROWING(wid->ActivateL());
596 extra->activated = 1;
599 void QWidgetPrivate::hide_sys()
603 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
604 deactivateWidgetCleanup();
605 QSymbianControl *id = static_cast<QSymbianControl *>(q->internalWinId());
608 //Incorrect optimization - for popup windows, Qt's focus is moved before
609 //hide_sys is called, resulting in the popup window keeping its elevated
610 //position in the CONE control stack.
611 //This can result in keyboard focus being in an invisible widget in some
612 //conditions - e.g. QTBUG-4733
613 //if(id->IsFocused()) // Avoid unnecessary calls to FocusChanged()
614 id->setFocusSafely(false);
615 id->MakeVisible(false);
616 if (QWidgetBackingStore *bs = maybeBackingStore())
619 invalidateBuffer(q->rect());
622 q->setAttribute(Qt::WA_Mapped, false);
625 void QWidgetPrivate::setFocus_sys()
628 if (q->testAttribute(Qt::WA_WState_Created) && q->window()->windowType() != Qt::Popup)
629 if (!q->effectiveWinId()->IsFocused()) // Avoid unnecessry calls to FocusChanged()
630 static_cast<QSymbianControl *>(q->effectiveWinId())->setFocusSafely(true);
633 void QWidgetPrivate::raise_sys()
637 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
638 if (q->internalWinId()) {
639 q->internalWinId()->DrawableWindow()->SetOrdinalPosition(0);
641 // If toplevel widget, raise app to foreground
643 S60->wsSession().SetWindowGroupOrdinalPosition(S60->windowGroup().Identifier(), 0);
647 void QWidgetPrivate::lower_sys()
651 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
652 if (q->internalWinId()) {
653 // If toplevel widget, lower app to background
655 S60->wsSession().SetWindowGroupOrdinalPosition(S60->windowGroup().Identifier(), -1);
657 q->internalWinId()->DrawableWindow()->SetOrdinalPosition(-1);
661 invalidateBuffer(q->rect());
664 void QWidgetPrivate::setModal_sys()
669 void QWidgetPrivate::stackUnder_sys(QWidget* w)
672 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
674 if (q->internalWinId() && w->internalWinId()) {
675 RDrawableWindow *const thisWindow = q->internalWinId()->DrawableWindow();
676 RDrawableWindow *const otherWindow = w->internalWinId()->DrawableWindow();
677 thisWindow->SetOrdinalPosition(otherWindow->OrdinalPosition() + 1);
680 if (!q->isWindow() || !w->internalWinId())
681 invalidateBuffer(q->rect());
684 void QWidgetPrivate::reparentChildren()
688 QObjectList chlist = q->children();
689 for (int i = 0; i < chlist.size(); ++i) { // reparent children
690 QObject *obj = chlist.at(i);
691 if (obj->isWidgetType()) {
692 QWidget *w = (QWidget *)obj;
693 if (!w->testAttribute(Qt::WA_WState_Created))
695 if (!w->isWindow()) {
696 w->d_func()->invalidateBuffer(w->rect());
697 WId parent = q->effectiveWinId();
698 WId child = w->effectiveWinId();
699 if (parent != child) {
700 // Child widget is native. Because Symbian windows cannot be
701 // re-parented, we must re-create the window.
702 const WId window = 0;
703 const bool initializeWindow = false;
704 const bool destroyOldWindow = true;
705 w->d_func()->create_sys(window, initializeWindow, destroyOldWindow);
707 // ### TODO: We probably also need to update the component array here
708 w->d_func()->reparentChildren();
710 bool showIt = w->isVisible();
711 QPoint old_pos = w->pos();
712 w->setParent(q, w->windowFlags());
721 void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
725 bool wasCreated = q->testAttribute(Qt::WA_WState_Created);
727 if (q->isVisible() && q->parentWidget() && parent != q->parentWidget())
728 q->parentWidget()->d_func()->invalidateBuffer(q->geometry());
730 if (q->testAttribute(Qt::WA_DropSiteRegistered))
731 q->setAttribute(Qt::WA_DropSiteRegistered, false);
733 QSymbianControl *old_winid = static_cast<QSymbianControl *>(wasCreated ? data.winid : 0);
734 if ((q->windowType() == Qt::Desktop))
737 // old_winid may not have received a 'not visible' visibility
738 // changed event before being destroyed; make sure that it is
739 // removed from the backing store's list of visible windows.
741 S60->controlVisibilityChanged(old_winid, false);
745 // hide and reparent our own window away. Otherwise we might get
746 // destroyed when emitting the child remove event below. See QWorkspace.
747 if (wasCreated && old_winid) {
748 old_winid->MakeVisible(false);
749 if (old_winid->IsFocused()) // Avoid unnecessary calls to FocusChanged()
750 old_winid->setFocusSafely(false);
751 old_winid->SetParent(0);
754 QObjectPrivate::setParent_helper(parent);
755 bool explicitlyHidden = q->testAttribute(Qt::WA_WState_Hidden) && q->testAttribute(Qt::WA_WState_ExplicitShowHide);
757 data.window_flags = f;
758 data.fstrut_dirty = true;
759 q->setAttribute(Qt::WA_WState_Created, false);
760 q->setAttribute(Qt::WA_WState_Visible, false);
761 q->setAttribute(Qt::WA_WState_Hidden, false);
762 adjustFlags(data.window_flags, q);
763 // keep compatibility with previous versions, we need to preserve the created state
764 // (but we recreate the winId for the widget being reparented, again for compatibility)
765 if (wasCreated || (!q->isWindow() && parent->testAttribute(Qt::WA_WState_Created)))
767 if (q->isWindow() || (!parent || parent->isVisible()) || explicitlyHidden)
768 q->setAttribute(Qt::WA_WState_Hidden);
769 q->setAttribute(Qt::WA_WState_ExplicitShowHide, explicitlyHidden);
775 CBase::Delete(old_winid);
778 if (q->testAttribute(Qt::WA_AcceptDrops)
779 || (!q->isWindow() && q->parentWidget() && q->parentWidget()->testAttribute(Qt::WA_DropSiteRegistered)))
780 q->setAttribute(Qt::WA_DropSiteRegistered, true);
782 invalidateBuffer(q->rect());
785 void QWidgetPrivate::setConstraints_sys()
791 void QWidgetPrivate::s60UpdateIsOpaque()
795 if (!q->testAttribute(Qt::WA_WState_Created) || !q->testAttribute(Qt::WA_TranslucentBackground))
800 RWindow *const window = static_cast<RWindow *>(q->effectiveWinId()->DrawableWindow());
802 #ifdef Q_SYMBIAN_SEMITRANSPARENT_BG_SURFACE
803 window->SetSurfaceTransparency(!isOpaque);
804 extra->topextra->nativeWindowTransparencyEnabled = !isOpaque;
807 const TDisplayMode displayMode = static_cast<TDisplayMode>(window->SetRequiredDisplayMode(EColor16MA));
808 if (window->SetTransparencyAlphaChannel() == KErrNone) {
809 window->SetBackgroundColor(TRgb(255, 255, 255, 0));
810 extra->topextra->nativeWindowTransparencyEnabled = 1;
812 if (extra->topextra->backingStore.data() &&
813 QApplicationPrivate::graphics_system_name == QLatin1String("openvg")) {
814 // Semi-transparent EGL surfaces aren't supported. We need to
815 // recreate backing store to get translucent surface (raster surface).
816 extra->topextra->backingStore.create(q);
817 extra->topextra->backingStore.registerWidget(q);
820 } else if (extra->topextra->nativeWindowTransparencyEnabled) {
821 window->SetTransparentRegion(TRegionFix<1>());
822 extra->topextra->nativeWindowTransparencyEnabled = 0;
827 void QWidgetPrivate::setWindowIcon_sys(bool forceReset)
832 if (!q->testAttribute(Qt::WA_WState_Created) || !q->isWindow() )
835 QTLWExtra* topData = this->topData();
836 if (topData->iconPixmap && !forceReset)
841 TBool found = AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::EContextPane, cPaneRect );
842 CAknContextPane* contextPane = S60->contextPane();
843 if (found && contextPane) { // We have context pane with valid metrics
844 QIcon icon = q->windowIcon();
845 if (!icon.isNull()) {
846 // Valid icon -> set it as an context pane picture
847 QSize size = icon.actualSize(QSize(cPaneRect.Size().iWidth, cPaneRect.Size().iHeight));
848 QPixmap pm = icon.pixmap(size);
849 QBitmap mask = pm.mask();
851 mask = QBitmap(pm.size());
852 mask.fill(Qt::color1);
855 CFbsBitmap* nBitmap = pm.toSymbianCFbsBitmap();
856 CFbsBitmap* nMask = mask.toSymbianCFbsBitmap();
857 contextPane->SetPicture(nBitmap,nMask);
859 // Icon set to null -> set context pane picture to default
860 QT_TRAP_THROWING(contextPane->SetPictureToDefaultL());
863 // Context pane does not exist, try setting small icon to title pane
865 TBool found = AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::ETitlePane, titlePaneRect );
866 CAknTitlePane* titlePane = S60->titlePane();
867 if (found && titlePane) { // We have title pane with valid metrics
868 // The API to get title_pane graphics size is not public -> assume square space based
869 // on titlebar font height. CAknBitmap would be optimum, wihtout setting the size, since
870 // then title pane would automatically scale the bitmap. Unfortunately it is not public API
871 // Also this function is leaving, although it is not named as such.
873 QT_TRAP_THROWING(font = AknLayoutUtils::FontFromId(EAknLogicalFontTitleFont));
874 TSize iconSize(font->HeightInPixels(), font->HeightInPixels());
876 QIcon icon = q->windowIcon();
877 if (!icon.isNull()) {
878 // Valid icon -> set it as an title pane small picture
879 QSize size = icon.actualSize(QSize(iconSize.iWidth, iconSize.iHeight));
880 QPixmap pm = icon.pixmap(size);
881 QBitmap mask = pm.mask();
883 mask = QBitmap(pm.size());
884 mask.fill(Qt::color1);
887 CFbsBitmap* nBitmap = pm.toSymbianCFbsBitmap();
888 CFbsBitmap* nMask = mask.toSymbianCFbsBitmap();
889 titlePane->SetSmallPicture( nBitmap, nMask, ETrue );
891 // Icon set to null -> set context pane picture to default
892 titlePane->SetSmallPicture( NULL, NULL, EFalse );
902 void QWidgetPrivate::setWindowTitle_sys(const QString &caption)
907 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
908 CAknTitlePane* titlePane = S60->titlePane();
910 if (caption.isEmpty()) {
911 QT_TRAP_THROWING(titlePane->SetTextToDefaultL());
913 QT_TRAP_THROWING(titlePane->SetTextL(qt_QString2TPtrC(caption)));
922 void QWidgetPrivate::setWindowIconText_sys(const QString & /*iconText */)
927 void QWidgetPrivate::scroll_sys(int dx, int dy)
931 scrollChildren(dx, dy);
932 if (!paintOnScreen() || !q->internalWinId() || !q->internalWinId()->OwnsWindow()) {
933 scrollRect(q->rect(), dx, dy);
935 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
936 RDrawableWindow *const window = q->internalWinId()->DrawableWindow();
937 window->Scroll(TPoint(dx, dy));
941 void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r)
945 if (!paintOnScreen() || !q->internalWinId() || !q->internalWinId()->OwnsWindow()) {
946 scrollRect(r, dx, dy);
948 Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
949 RDrawableWindow *const window = q->internalWinId()->DrawableWindow();
950 window->Scroll(TPoint(dx, dy), qt_QRect2TRect(r));
955 For this function to work in the emulator, you must add:
957 To a line in the wsini.ini file.
959 void QWidgetPrivate::setWindowOpacity_sys(qreal)
961 // ### TODO: Implement uniform window transparency
964 void QWidgetPrivate::updateFrameStrut()
969 void QWidgetPrivate::updateSystemBackground()
974 void QWidgetPrivate::registerDropSite(bool /* on */)
979 void QWidgetPrivate::createTLSysExtra()
981 extra->topextra->inExpose = 0;
982 extra->topextra->nativeWindowTransparencyEnabled = 0;
985 void QWidgetPrivate::deleteTLSysExtra()
987 extra->topextra->backingStore.destroy();
990 void QWidgetPrivate::createSysExtra()
992 extra->activated = 0;
993 extra->nativePaintMode = QWExtra::Default;
994 extra->receiveNativePaintEvents = 0;
997 void QWidgetPrivate::deleteSysExtra()
999 // this should only be non-zero if destroy() has not run due to constructor fail
1001 data.winid->ControlEnv()->AppUi()->RemoveFromStack(data.winid);
1007 QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys()
1009 return new QS60WindowSurface(q_func());
1012 void QWidgetPrivate::setMask_sys(const QRegion& /* region */)
1017 void QWidgetPrivate::registerTouchWindow()
1019 #ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
1021 if (q->testAttribute(Qt::WA_WState_Created) && q->windowType() != Qt::Desktop) {
1022 RWindow *rwindow = static_cast<RWindow *>(q->effectiveWinId()->DrawableWindow());
1023 QSymbianControl *window = static_cast<QSymbianControl *>(q->effectiveWinId());
1024 //Enabling advanced pointer events for controls that already have active windows causes a panic.
1025 if (!window->isControlActive())
1026 rwindow->EnableAdvancedPointers();
1031 int QWidget::metric(PaintDeviceMetric m) const
1035 if (m == PdmWidth) {
1036 val = data->crect.width();
1037 } else if (m == PdmHeight) {
1038 val = data->crect.height();
1040 CWsScreenDevice *scr = S60->screenDevice();
1043 case PdmPhysicalDpiX:
1044 if (d->extra && d->extra->customDpiX) {
1045 val = d->extra->customDpiX;
1047 const QWidgetPrivate *p = d;
1049 p = static_cast<const QWidget *>(p->parent)->d_func();
1050 if (p->extra && p->extra->customDpiX) {
1051 val = p->extra->customDpiX;
1055 if (p == d || !(p->extra && p->extra->customDpiX))
1056 val = S60->defaultDpiX;
1060 case PdmPhysicalDpiY:
1061 if (d->extra && d->extra->customDpiY) {
1062 val = d->extra->customDpiY;
1064 const QWidgetPrivate *p = d;
1066 p = static_cast<const QWidget *>(p->parent)->d_func();
1067 if (p->extra && p->extra->customDpiY) {
1068 val = p->extra->customDpiY;
1072 if (p == d || !(p->extra && p->extra->customDpiY))
1073 val = S60->defaultDpiY;
1078 TInt twips = scr->HorizontalPixelsToTwips(data->crect.width());
1079 val = (int)(twips * (25.4/KTwipsPerInch));
1084 TInt twips = scr->VerticalPixelsToTwips(data->crect.height());
1085 val = (int)(twips * (25.4/KTwipsPerInch));
1089 val = TDisplayModeUtils::NumDisplayModeColors(scr->DisplayMode());
1092 val = TDisplayModeUtils::NumDisplayModeBitsPerPixel(scr->DisplayMode());
1096 qWarning("QWidget::metric: Invalid metric command");
1102 QPaintEngine *QWidget::paintEngine() const
1107 QPoint QWidget::mapToGlobal(const QPoint &pos) const
1110 if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) {
1112 QPoint p = pos + data->crect.topLeft();
1113 return (isWindow() || !parentWidget()) ? p : parentWidget()->mapToGlobal(p);
1115 } else if ((d->data.window_flags & Qt::Window) && internalWinId()) { //toplevel
1116 QPoint tp = geometry().topLeft();
1120 // Native window case
1121 const TPoint widgetScreenOffset = internalWinId()->PositionRelativeToScreen();
1122 const QPoint globalPos = QPoint(widgetScreenOffset.iX, widgetScreenOffset.iY) + pos;
1126 QPoint QWidget::mapFromGlobal(const QPoint &pos) const
1129 if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) {
1130 QPoint p = (isWindow() || !parentWidget()) ? pos : parentWidget()->mapFromGlobal(pos);
1131 return p - data->crect.topLeft();
1132 } else if ((d->data.window_flags & Qt::Window) && internalWinId()) { //toplevel
1133 QPoint tp = geometry().topLeft();
1137 // Native window case
1138 const TPoint widgetScreenOffset = internalWinId()->PositionRelativeToScreen();
1139 const QPoint widgetPos = pos - QPoint(widgetScreenOffset.iX, widgetScreenOffset.iY);
1143 static Qt::WindowStates effectiveState(Qt::WindowStates state)
1145 if (state & Qt::WindowMinimized)
1146 return Qt::WindowMinimized;
1147 else if (state & Qt::WindowFullScreen)
1148 return Qt::WindowFullScreen;
1149 else if (state & Qt::WindowMaximized)
1150 return Qt::WindowMaximized;
1151 return Qt::WindowNoState;
1154 void QWidget::setWindowState(Qt::WindowStates newstate)
1158 Qt::WindowStates oldstate = windowState();
1160 const TBool isFullscreen = newstate & Qt::WindowFullScreen;
1162 const TBool cbaRequested = windowFlags() & Qt::WindowSoftkeysVisibleHint;
1163 const TBool cbaVisible = CEikButtonGroupContainer::Current() ? true : false;
1164 const TBool softkeyVisibilityChange = isFullscreen && (cbaRequested != cbaVisible);
1166 if (oldstate == newstate && !softkeyVisibilityChange)
1172 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1174 const bool wasResized = testAttribute(Qt::WA_Resized);
1175 const bool wasMoved = testAttribute(Qt::WA_Moved);
1177 QSymbianControl *window = static_cast<QSymbianControl *>(effectiveWinId());
1178 if (window && newstate & Qt::WindowMinimized) {
1179 window->setFocusSafely(false);
1180 window->MakeVisible(false);
1181 } else if (window && oldstate & Qt::WindowMinimized) {
1182 window->setFocusSafely(true);
1183 window->MakeVisible(true);
1187 // Hide window decoration when switching to fullscreen / minimized otherwise show decoration.
1188 // The window decoration visibility has to be changed before doing actual window state
1189 // change since in that order the availableGeometry will return directly the right size and
1190 // we will avoid unnecessary redraws
1191 Qt::WindowStates comparisonState = newstate;
1192 QWidget *parentWindow = parentWidget();
1194 while (parentWindow->parentWidget())
1195 parentWindow = parentWindow->parentWidget();
1196 comparisonState = parentWindow->windowState();
1198 parentWindow = this;
1201 const bool decorationsVisible = !(comparisonState & (Qt::WindowFullScreen | Qt::WindowMinimized));
1202 const bool parentIsFullscreen = comparisonState & Qt::WindowFullScreen;
1203 const bool parentCbaVisibilityHint = parentWindow->windowFlags() & Qt::WindowSoftkeysVisibleHint;
1204 bool buttonGroupVisibility = (decorationsVisible || (parentIsFullscreen && parentCbaVisibilityHint));
1206 // For non-toplevel normal and maximized windows, show cba if window has softkey
1207 // actions even if topmost parent is not showing cba. Do the same for fullscreen
1208 // windows that request it.
1209 if (!buttonGroupVisibility
1211 && !(newstate & Qt::WindowMinimized)
1212 && ((windowFlags() & Qt::WindowSoftkeysVisibleHint) || !(newstate & Qt::WindowFullScreen))) {
1213 for (int i = 0; i < actions().size(); ++i) {
1214 if (actions().at(i)->softKeyRole() != QAction::NoSoftKey) {
1215 buttonGroupVisibility = true;
1220 S60->setStatusPaneAndButtonGroupVisibility(decorationsVisible, buttonGroupVisibility);
1224 // Ensure the initial size is valid, since we store it as normalGeometry below.
1225 if (!wasResized && !isVisible())
1228 QTLWExtra *top = d->topData();
1229 QRect normalGeometry = (top->normalGeometry.width() < 0) ? geometry() : top->normalGeometry;
1231 const bool cbaVisibilityHint = windowFlags() & Qt::WindowSoftkeysVisibleHint;
1232 if (newstate & Qt::WindowFullScreen && !cbaVisibilityHint) {
1233 setAttribute(Qt::WA_OutsideWSRange, false);
1234 window->SetExtentToWholeScreen();
1235 } else if (newstate & Qt::WindowMaximized || ((newstate & Qt::WindowFullScreen) && cbaVisibilityHint)) {
1236 setAttribute(Qt::WA_OutsideWSRange, false);
1237 TRect maxExtent = qt_QRect2TRect(qApp->desktop()->availableGeometry(this));
1238 window->SetExtent(maxExtent.iTl, maxExtent.Size());
1241 // With delayed creation of S60 app panes, the normalGeometry calculated above is not
1242 // accurate because it did not consider the status pane. This means that when returning
1243 // normal mode after showing the status pane, the geometry would overlap so we should
1244 // move it if it never had an explicit position.
1245 if (!wasMoved && S60->statusPane() && decorationsVisible) {
1246 TPoint tl = static_cast<CEikAppUi*>(S60->appUi())->ClientRect().iTl;
1247 normalGeometry.setTopLeft(QPoint(tl.iX, tl.iY));
1250 setGeometry(normalGeometry);
1253 //restore normal geometry
1254 top->normalGeometry = normalGeometry;
1257 // In some platforms, WA_Resized and WA_Moved are also not set when application window state is
1258 // anything else than normal. In Symbian we can restore them only for normal window state since
1259 // restoring for other modes, will make fluidlauncher to be launched in wrong size (200x100)
1260 if (effectiveState(newstate) == Qt::WindowNoState) {
1261 setAttribute(Qt::WA_Resized, wasResized);
1262 setAttribute(Qt::WA_Moved, wasMoved);
1266 data->window_state = newstate;
1268 if (newstate & Qt::WindowActive)
1271 QWindowStateChangeEvent e(oldstate);
1272 QApplication::sendEvent(this, &e);
1276 void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
1279 d->aboutToDestroy();
1280 if (!isWindow() && parentWidget())
1281 parentWidget()->d_func()->invalidateBuffer(geometry());
1282 d->deactivateWidgetCleanup();
1283 QSymbianControl *id = static_cast<QSymbianControl *>(internalWinId());
1284 if (testAttribute(Qt::WA_WState_Created)) {
1290 QInputContext *ic = QApplicationPrivate::inputContext;
1292 ic->widgetDestroyed(this);
1297 if (QWidgetPrivate::mouseGrabber == this)
1299 if (QWidgetPrivate::keyboardGrabber == this)
1301 setAttribute(Qt::WA_WState_Created, false);
1302 QObjectList childList = children();
1303 for (int i = 0; i < childList.size(); ++i) { // destroy all widget children
1304 register QObject *obj = childList.at(i);
1305 if (obj->isWidgetType())
1306 static_cast<QWidget*>(obj)->destroy(destroySubWindows,
1309 if (destroyWindow && !(windowType() == Qt::Desktop) && id) {
1310 if (id->IsFocused()) // Avoid unnecessry calls to FocusChanged()
1311 id->setFocusSafely(false);
1312 id->ControlEnv()->AppUi()->RemoveFromStack(id);
1318 } QT_CATCH (const std::bad_alloc &) {
1319 // swallow - destructors must not throw
1322 if (destroyWindow) {
1324 // At this point the backing store should already be destroyed
1325 // so we flush the command buffer to ensure that the freeing of
1326 // those resources and deleting the window can happen "atomically"
1328 S60->wsSession().Flush();
1332 QWidget *QWidget::mouseGrabber()
1334 return QWidgetPrivate::mouseGrabber;
1337 QWidget *QWidget::keyboardGrabber()
1339 return QWidgetPrivate::keyboardGrabber;
1342 void QWidget::grabKeyboard()
1345 if (QWidgetPrivate::keyboardGrabber && QWidgetPrivate::keyboardGrabber != this)
1346 QWidgetPrivate::keyboardGrabber->releaseKeyboard();
1348 // ### TODO: Native keyboard grab
1350 QWidgetPrivate::keyboardGrabber = this;
1354 void QWidget::releaseKeyboard()
1356 if (!qt_nograb() && QWidgetPrivate::keyboardGrabber == this) {
1357 // ### TODO: Native keyboard release
1358 QWidgetPrivate::keyboardGrabber = 0;
1362 void QWidget::grabMouse()
1364 if (isVisible() && !qt_nograb()) {
1365 if (QWidgetPrivate::mouseGrabber && QWidgetPrivate::mouseGrabber != this)
1366 QWidgetPrivate::mouseGrabber->releaseMouse();
1367 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1368 WId id = effectiveWinId();
1369 id->SetPointerCapture(true);
1370 QWidgetPrivate::mouseGrabber = this;
1372 #ifndef QT_NO_CURSOR
1373 QApplication::setOverrideCursor(cursor());
1378 #ifndef QT_NO_CURSOR
1379 void QWidget::grabMouse(const QCursor &cursor)
1381 if (isVisible() && !qt_nograb()) {
1382 if (QWidgetPrivate::mouseGrabber && QWidgetPrivate::mouseGrabber != this)
1383 QWidgetPrivate::mouseGrabber->releaseMouse();
1384 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1385 WId id = effectiveWinId();
1386 id->SetPointerCapture(true);
1387 QWidgetPrivate::mouseGrabber = this;
1389 QApplication::setOverrideCursor(cursor);
1394 void QWidget::releaseMouse()
1396 if (!qt_nograb() && QWidgetPrivate::mouseGrabber == this) {
1397 Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1398 if(!window()->isModal()) {
1399 WId id = effectiveWinId();
1400 id->SetPointerCapture(false);
1402 QWidgetPrivate::mouseGrabber = 0;
1403 #ifndef QT_NO_CURSOR
1404 QApplication::restoreOverrideCursor();
1409 void QWidget::activateWindow()
1413 QWidget *tlw = window();
1414 if (tlw->isVisible()) {
1415 window()->createWinId();
1416 QSymbianControl *id = static_cast<QSymbianControl *>(tlw->internalWinId());
1417 id->setFocusSafely(true);
1421 #ifndef QT_NO_CURSOR
1423 void QWidgetPrivate::setCursor_sys(const QCursor &cursor)
1427 qt_symbian_set_cursor(q, false);
1430 void QWidgetPrivate::unsetCursor_sys()
1433 qt_symbian_set_cursor(q, false);