Fixed a bug where the softkeys would leave a see-through "hole".
[qt:qt.git] / src / gui / kernel / qwidget_s60.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtGui module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
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.
23 **
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.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qwidget_p.h"
43 #include "qdesktopwidget.h"
44 #include "qapplication.h"
45 #include "qapplication_p.h"
46 #include "private/qbackingstore_p.h"
47 #include "qevent.h"
48 #include "qt_s60_p.h"
49
50 #include "qbitmap.h"
51 #include "private/qwindowsurface_s60_p.h"
52
53 #include <qinputcontext.h>
54
55 #ifdef Q_WS_S60
56 #include <aknappui.h>
57 #include <akntoolbar.h>
58 #include <eikbtgpc.h>
59 #endif
60
61 // This is necessary in order to be able to perform delayed invocation on slots
62 // which take arguments of type WId.  One example is
63 // QWidgetPrivate::_q_delayedDestroy, which is used to delay destruction of
64 // CCoeControl objects until after the CONE event handler has finished running.
65 Q_DECLARE_METATYPE(WId)
66
67 QT_BEGIN_NAMESPACE
68
69 extern bool qt_nograb();
70
71 QWidget *QWidgetPrivate::mouseGrabber = 0;
72 QWidget *QWidgetPrivate::keyboardGrabber = 0;
73 CEikButtonGroupContainer *QS60Data::cba = 0;
74
75 static bool isEqual(const QList<QAction*>& a, const QList<QAction*>& b)
76 {
77     if ( a.count() != b.count())
78         return false;
79     int index=0;
80     while (index<a.count()) {
81         if (a.at(index)->softKeyRole() != b.at(index)->softKeyRole())
82             return false;
83         if (a.at(index)->text().compare(b.at(index)->text())!=0)
84             return false;
85         index++;
86     }
87     return true;
88 }
89
90 void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &)
91 {
92     // Note: based on x11 implementation
93
94     static const int XCOORD_MAX = 16383;
95     static const int WRECT_MAX = 16383;
96
97     Q_Q(QWidget);
98
99     Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
100
101     /*
102       There are up to four different coordinate systems here:
103       Qt coordinate system for this widget.
104       Symbian coordinate system for this widget (relative to wrect).
105       Qt coordinate system for parent
106       Symbian coordinate system for parent (relative to parent's wrect).
107      */
108
109     QRect validRange(-XCOORD_MAX,-XCOORD_MAX, 2*XCOORD_MAX, 2*XCOORD_MAX);
110     QRect wrectRange(-WRECT_MAX,-WRECT_MAX, 2*WRECT_MAX, 2*WRECT_MAX);
111     QRect wrect;
112     //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)
113     QRect xrect = data.crect;
114
115     const QWidget *const parent = q->parentWidget();
116     QRect parentWRect = parent->data->wrect;
117
118     if (parentWRect.isValid()) {
119         // parent is clipped, and we have to clip to the same limit as parent
120         if (!parentWRect.contains(xrect)) {
121             xrect &= parentWRect;
122             wrect = xrect;
123             //translate from parent's to my Qt coord sys
124             wrect.translate(-data.crect.topLeft());
125         }
126         //translate from parent's Qt coords to parent's X coords
127         xrect.translate(-parentWRect.topLeft());
128
129     } else {
130         // parent is not clipped, we may or may not have to clip
131
132         if (data.wrect.isValid() && QRect(QPoint(),data.crect.size()).contains(data.wrect)) {
133             // This is where the main optimization is: we are already
134             // clipped, and if our clip is still valid, we can just
135             // move our window, and do not need to move or clip
136             // children
137
138             QRect vrect = xrect & parent->rect();
139             vrect.translate(-data.crect.topLeft()); //the part of me that's visible through parent, in my Qt coords
140             if (data.wrect.contains(vrect)) {
141                 xrect = data.wrect;
142                 xrect.translate(data.crect.topLeft());
143                 if (data.winid)
144                     data.winid->SetExtent(TPoint(xrect.x(), xrect.y()), TSize(xrect.width(), xrect.height()));
145                 return;
146             }
147         }
148
149         if (!validRange.contains(xrect)) {
150             // we are too big, and must clip
151             xrect &=wrectRange;
152             wrect = xrect;
153             wrect.translate(-data.crect.topLeft());
154             //parent's X coord system is equal to parent's Qt coord
155             //sys, so we don't need to map xrect.
156         }
157     }
158
159     // unmap if we are outside the valid window system coord system
160     bool outsideRange = !xrect.isValid();
161     bool mapWindow = false;
162     if (q->testAttribute(Qt::WA_OutsideWSRange) != outsideRange) {
163         q->setAttribute(Qt::WA_OutsideWSRange, outsideRange);
164         if (outsideRange) {
165             if (data.winid)
166                 data.winid->DrawableWindow()->SetVisible(EFalse);
167             q->setAttribute(Qt::WA_Mapped, false);
168         } else if (!q->isHidden()) {
169             mapWindow = true;
170         }
171     }
172
173     if (outsideRange)
174         return;
175
176     bool jump = (data.wrect != wrect);
177     data.wrect = wrect;
178
179     // and now recursively for all children...
180     for (int i = 0; i < children.size(); ++i) {
181         QObject *object = children.at(i);
182         if (object->isWidgetType()) {
183             QWidget *w = static_cast<QWidget *>(object);
184             if (!w->isWindow() && w->testAttribute(Qt::WA_WState_Created))
185                 w->d_func()->setWSGeometry(jump);
186         }
187     }
188
189     if (data.winid) {
190         // move ourselves to the new position and map (if necessary) after
191         // the movement. Rationale: moving unmapped windows is much faster
192         // than moving mapped windows
193         if (!parent->internalWinId())
194             xrect.translate(parent->mapTo(q->nativeParentWidget(), QPoint(0, 0)));
195
196         data.winid->SetExtent(TPoint(xrect.x(), xrect.y()), TSize(xrect.width(), xrect.height()));
197     }
198
199     if (mapWindow and !dontShow) {
200         q->setAttribute(Qt::WA_Mapped);
201         if (q->internalWinId())
202             q->internalWinId()->DrawableWindow()->SetVisible(ETrue);
203     }
204
205     if  (jump && data.winid) {
206         RWindow *const window = static_cast<RWindow *>(data.winid->DrawableWindow());
207         window->Invalidate(TRect(0, 0, wrect.width(), wrect.height()));
208     }
209 }
210
211 void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove)
212 {
213     Q_Q(QWidget);
214
215     Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
216
217     if ((q->windowType() == Qt::Desktop))
218         return;
219
220     QPoint oldPos(q->pos());
221     QSize oldSize(q->size());
222     QRect oldGeom(data.crect);
223
224     // Lose maximized status if deliberate resize
225     if (w != oldSize.width() || h != oldSize.height())
226         data.window_state &= ~Qt::WindowMaximized;
227
228     if (extra) {                                // any size restrictions?
229         w = qMin(w,extra->maxw);
230         h = qMin(h,extra->maxh);
231         w = qMax(w,extra->minw);
232         h = qMax(h,extra->minh);
233     }
234
235     if (q->isWindow())
236         topData()->normalGeometry = QRect(0, 0, -1, -1);
237     else {
238         uint s = data.window_state;
239         s &= ~(Qt::WindowMaximized | Qt::WindowFullScreen);
240         data.window_state = s;
241     }
242
243     bool isResize = w != oldSize.width() || h != oldSize.height();
244     if (!isMove && !isResize)
245         return;
246
247     if (q->isWindow()) {
248         if (w == 0 || h == 0) {
249             q->setAttribute(Qt::WA_OutsideWSRange, true);
250             if (q->isVisible() && q->testAttribute(Qt::WA_Mapped))
251                 hide_sys();
252             data.crect = QRect(x, y, w, h);
253             data.window_state &= ~Qt::WindowFullScreen;
254         } else if (q->isVisible() && q->testAttribute(Qt::WA_OutsideWSRange)) {
255             q->setAttribute(Qt::WA_OutsideWSRange, false);
256
257             // put the window in its place and show it
258             q->internalWinId()->SetRect(TRect(TPoint(x, y), TSize(w, h)));
259             data.crect.setRect(x, y, w, h);
260             show_sys();
261         } else {
262             QRect r = QRect(x, y, w, h);
263             data.crect = r;
264             q->internalWinId()->SetRect(TRect(TPoint(x, y), TSize(w, h)));
265             topData()->normalGeometry = data.crect;
266         }
267     } else {
268         data.crect.setRect(x, y, w, h);
269
270         QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData();
271         const bool inTopLevelResize = tlwExtra ? tlwExtra->inTopLevelResize : false;
272
273         if (q->isVisible() && (!inTopLevelResize || q->internalWinId())) {
274             // Top-level resize optimization does not work for native child widgets;
275             // disable it for this particular widget.
276             if (inTopLevelResize)
277                 tlwExtra->inTopLevelResize = false;
278             if (!isResize && maybeBackingStore())
279                 moveRect(QRect(oldPos, oldSize), x - oldPos.x(), y - oldPos.y());
280             else
281                 invalidateBuffer_resizeHelper(oldPos, oldSize);
282
283             if (inTopLevelResize)
284                 tlwExtra->inTopLevelResize = true;
285         }
286         if (q->testAttribute(Qt::WA_WState_Created))
287             setWSGeometry();
288     }
289
290     if (q->isVisible()) {
291         if (isMove && q->pos() != oldPos) {
292             QMoveEvent e(q->pos(), oldPos);
293             QApplication::sendEvent(q, &e);
294         }
295         if (isResize) {
296             bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt();
297             const bool setTopLevelResize = !slowResize && q->isWindow() && extra && extra->topextra
298                                            && !extra->topextra->inTopLevelResize;
299             if (setTopLevelResize)
300                 extra->topextra->inTopLevelResize = true;
301             QResizeEvent e(q->size(), oldSize);
302             QApplication::sendEvent(q, &e);
303             if (!q->testAttribute(Qt::WA_StaticContents) && q->internalWinId())
304                 q->internalWinId()->DrawDeferred();
305             if (setTopLevelResize)
306                 extra->topextra->inTopLevelResize = false;
307         }
308     } else {
309         if (isMove && q->pos() != oldPos)
310             q->setAttribute(Qt::WA_PendingMoveEvent, true);
311         if (isResize)
312             q->setAttribute(Qt::WA_PendingResizeEvent, true);
313     }
314 }
315
316 void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool destroyOldWindow)
317 {
318     Q_Q(QWidget);
319
320     Qt::WindowType type = q->windowType();
321     Qt::WindowFlags &flags = data.window_flags;
322     QWidget *parentWidget = q->parentWidget();
323
324     bool topLevel = (flags & Qt::Window);
325     bool popup = (type == Qt::Popup);
326     bool dialog = (type == Qt::Dialog
327                    || type == Qt::Sheet
328                    || (flags & Qt::MSWindowsFixedSizeDialogHint));
329     bool desktop = (type == Qt::Desktop);
330     //bool tool = (type == Qt::Tool || type == Qt::Drawer);
331
332     if (popup)
333         flags |= Qt::WindowStaysOnTopHint; // a popup stays on top
334
335     TRect clientRect = static_cast<CEikAppUi*>(S60->appUi())->ClientRect();
336     int sw = clientRect.Width();
337     int sh = clientRect.Height();
338
339     if (desktop) {
340         TSize screenSize = S60->screenDevice()->SizeInPixels();
341         data.crect.setRect(0, 0, screenSize.iWidth, screenSize.iHeight);
342         q->setAttribute(Qt::WA_DontShowOnScreen);
343     } else if (topLevel && !q->testAttribute(Qt::WA_Resized)){
344         int width = sw;
345         int height = sh;
346         if (extra) {
347             width = qMax(qMin(width, extra->maxw), extra->minw);
348             height = qMax(qMin(height, extra->maxh), extra->minh);
349         }
350         data.crect.setSize(QSize(width, height));
351     }
352
353     CCoeControl *const destroyw = destroyOldWindow ? data.winid : 0;
354
355     createExtra();
356     if (window) {
357         setWinId(window);
358         TRect tr = window->Rect();
359         data.crect.setRect(tr.iTl.iX, tr.iTl.iY, tr.Width(), tr.Height());
360
361     } else if (topLevel) {
362         if (!q->testAttribute(Qt::WA_Moved) && !q->testAttribute(Qt::WA_DontShowOnScreen))
363             data.crect.moveTopLeft(QPoint(clientRect.iTl.iX, clientRect.iTl.iY));
364
365         QScopedPointer<QSymbianControl> control( q_check_ptr(new QSymbianControl(q)) );
366         QT_TRAP_THROWING(control->ConstructL(true, desktop));
367         control->SetMopParent(static_cast<CEikAppUi*>(S60->appUi()));
368
369         // Symbian windows are always created in an inactive state
370         // We perform this assignment for the case where the window is being re-created
371         // as a result of a call to setParent_sys, on either this widget or one of its
372         // ancestors.
373         extra->activated = 0;
374
375         if (!desktop) {
376             TInt stackingFlags;
377             if ((q->windowType() & Qt::Popup) == Qt::Popup) {
378                 stackingFlags = ECoeStackFlagRefusesAllKeys | ECoeStackFlagRefusesFocus;
379             } else {
380                 stackingFlags = ECoeStackFlagStandard;
381             }
382             control->MakeVisible(false);
383             QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control.data(), ECoeStackPriorityDefault, stackingFlags));
384             // Avoid keyboard focus to a hidden window.
385             control->setFocusSafely(false);
386
387             RDrawableWindow *const drawableWindow = control->DrawableWindow();
388             // Request mouse move events.
389             drawableWindow->PointerFilter(EPointerFilterEnterExit
390                 | EPointerFilterMove | EPointerFilterDrag, 0);
391             drawableWindow->EnableVisibilityChangeEvents();
392
393         }
394
395         q->setAttribute(Qt::WA_WState_Created);
396
397         int x, y, w, h;
398         data.crect.getRect(&x, &y, &w, &h);
399         control->SetRect(TRect(TPoint(x, y), TSize(w, h)));
400
401         // We wait until the control is fully constructed before calling setWinId, because
402         // this generates a WinIdChanged event.
403         setWinId(control.take());
404
405         if (!desktop)
406             s60UpdateIsOpaque(); // must be called after setWinId()
407
408     } else if (q->testAttribute(Qt::WA_NativeWindow) || paintOnScreen()) { // create native child widget
409
410         QScopedPointer<QSymbianControl> control( q_check_ptr(new QSymbianControl(q)) );
411         QT_TRAP_THROWING(control->ConstructL(!parentWidget));
412
413         // Symbian windows are always created in an inactive state
414         // We perform this assignment for the case where the window is being re-created
415         // as a result of a call to setParent_sys, on either this widget or one of its
416         // ancestors.
417         extra->activated = 0;
418
419         TInt stackingFlags;
420         if ((q->windowType() & Qt::Popup) == Qt::Popup) {
421             stackingFlags = ECoeStackFlagRefusesAllKeys | ECoeStackFlagRefusesFocus;
422         } else {
423             stackingFlags = ECoeStackFlagStandard;
424         }
425         control->MakeVisible(false);
426         QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control.data(), ECoeStackPriorityDefault, stackingFlags));
427         // Avoid keyboard focus to a hidden window.
428         control->setFocusSafely(false);
429
430         q->setAttribute(Qt::WA_WState_Created);
431         int x, y, w, h;
432         data.crect.getRect(&x, &y, &w, &h);
433         control->SetRect(TRect(TPoint(x, y), TSize(w, h)));
434
435         RDrawableWindow *const drawableWindow = control->DrawableWindow();
436         // Request mouse move events.
437         drawableWindow->PointerFilter(EPointerFilterEnterExit
438             | EPointerFilterMove | EPointerFilterDrag, 0);
439         drawableWindow->EnableVisibilityChangeEvents();
440
441         if (q->isVisible() && q->testAttribute(Qt::WA_Mapped)) {
442             activateSymbianWindow(control.data());
443             control->MakeVisible(true);
444         }
445
446         // We wait until the control is fully constructed before calling setWinId, because
447         // this generates a WinIdChanged event.
448         setWinId(control.take());
449     }
450
451     if (destroyw) {
452         destroyw->ControlEnv()->AppUi()->RemoveFromStack(destroyw);
453
454         // Delay deletion of the control in case this function is called in the
455         // context of a CONE event handler such as
456         // CCoeControl::ProcessPointerEventL
457         QMetaObject::invokeMethod(q, "_q_delayedDestroy",
458             Qt::QueuedConnection, Q_ARG(WId, destroyw));
459     }
460
461     if (q->testAttribute(Qt::WA_AcceptTouchEvents))
462         registerTouchWindow();
463 }
464
465
466 void QWidgetPrivate::show_sys()
467 {
468     Q_Q(QWidget);
469
470     if (q->testAttribute(Qt::WA_OutsideWSRange))
471         return;
472
473     Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
474
475     q->setAttribute(Qt::WA_Mapped);
476
477     if (q->testAttribute(Qt::WA_DontShowOnScreen)) {
478         invalidateBuffer(q->rect());
479         return;
480     }
481
482     if (q->internalWinId()) {
483         if (!extra->activated)
484              activateSymbianWindow();
485
486          QSymbianControl *id = static_cast<QSymbianControl *>(q->internalWinId());
487          const bool isFullscreen = q->windowState() & Qt::WindowFullScreen;
488          const TBool cbaRequested = q->windowFlags() & Qt::WindowSoftkeysVisibleHint;
489
490 #ifdef Q_WS_S60
491         // Lazily initialize the S60 screen furniture when the first window is shown.
492         if (q->isWindow() && !QApplication::testAttribute(Qt::AA_S60DontConstructApplicationPanes)
493                 && !S60->buttonGroupContainer() && !S60->statusPane()) {
494
495             if (!q->testAttribute(Qt::WA_DontShowOnScreen)) {
496
497                 // Create the status pane and CBA here
498                 CEikAppUi *ui = static_cast<CEikAppUi *>(S60->appUi());
499                 MEikAppUiFactory *factory = CEikonEnv::Static()->AppUiFactory();
500
501                 QT_TRAP_THROWING(
502                     factory->CreateResourceIndependentFurnitureL(ui);
503
504                     TRect boundingRect = static_cast<CEikAppUi*>(S60->appUi())->ClientRect();
505
506                     CEikButtonGroupContainer *cba = CEikButtonGroupContainer::NewL(CEikButtonGroupContainer::ECba,
507                         CEikButtonGroupContainer::EHorizontal,ui,R_AVKON_SOFTKEYS_EMPTY_WITH_IDS);
508                     if (isFullscreen && !cbaRequested)
509                         cba->MakeVisible(false);
510
511                     CEikButtonGroupContainer *oldCba = factory->SwapButtonGroup(cba);
512                     Q_ASSERT(!oldCba);
513                     S60->setButtonGroupContainer(cba);
514
515                     // If the creation of the first widget is delayed, for example by doing it
516                     // inside the event loop, S60 somehow "forgets" to set the visibility of the
517                     // toolbar (the three middle softkeys) when you flip the phone over, so we
518                     // need to do it ourselves to avoid a "hole" in the application, even though
519                     // Qt itself does not use the toolbar directly..
520                     CAknAppUi *appui = dynamic_cast<CAknAppUi *>(CEikonEnv::Static()->AppUi());
521                     if (appui) {
522                         CAknToolbar *toolbar = appui->PopupToolbar();
523                         if (toolbar && !toolbar->IsVisible())
524                             toolbar->SetToolbarVisibility(ETrue);
525                     }
526
527                     CEikMenuBar *menuBar = new(ELeave) CEikMenuBar;
528                     menuBar->ConstructL(ui, 0, R_AVKON_MENUPANE_EMPTY);
529                     menuBar->SetMenuType(CEikMenuBar::EMenuOptions);
530                     S60->appUi()->AddToStackL(menuBar,ECoeStackPriorityMenu,ECoeStackFlagRefusesFocus);
531
532                     CEikMenuBar *oldMenu = factory->SwapMenuBar(menuBar);
533                     Q_ASSERT(!oldMenu);
534                 )
535
536                 if (S60->statusPane()) {
537                     // Use QDesktopWidget as the status pane observer to proxy for the AppUi.
538                     // Can't use AppUi directly because it privately inherits from MEikStatusPaneObserver.
539                     QSymbianControl *desktopControl = static_cast<QSymbianControl *>(QApplication::desktop()->winId());
540                     S60->statusPane()->SetObserver(desktopControl);
541                     if (isFullscreen) {
542                         const bool cbaVisible = S60->buttonGroupContainer() && S60->buttonGroupContainer()->IsVisible();
543                         S60->setStatusPaneAndButtonGroupVisibility(false, cbaVisible);
544                     }
545                 }
546             }
547         }
548 #endif
549
550         // Fill client area if maximized OR
551         // Put window below status pane unless the window has an explicit position.
552         if (!isFullscreen) {
553             if (q->windowState() & Qt::WindowMaximized) {
554                 TRect r = static_cast<CEikAppUi*>(S60->appUi())->ClientRect();
555                 id->SetExtent(r.iTl, r.Size());
556             } else if (!q->testAttribute(Qt::WA_Moved) && q->windowType() != Qt::Dialog) {
557                 id->SetPosition(static_cast<CEikAppUi*>(S60->appUi())->ClientRect().iTl);
558             }
559         }
560
561         id->MakeVisible(true);
562
563         if(q->isWindow()&&!q->testAttribute(Qt::WA_ShowWithoutActivating))
564             id->setFocusSafely(true);
565     }
566
567     invalidateBuffer(q->rect());
568 }
569
570 void QWidgetPrivate::activateSymbianWindow(WId wid)
571 {
572     Q_Q(QWidget);
573
574     Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
575     Q_ASSERT(q->testAttribute(Qt::WA_Mapped));
576     Q_ASSERT(!extra->activated);
577
578     if(!wid)
579         wid = q->internalWinId();
580
581     Q_ASSERT(wid);
582
583     QT_TRAP_THROWING(wid->ActivateL());
584     extra->activated = 1;
585 }
586
587 void QWidgetPrivate::hide_sys()
588 {
589     Q_Q(QWidget);
590
591     Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
592     deactivateWidgetCleanup();
593     QSymbianControl *id = static_cast<QSymbianControl *>(q->internalWinId());
594
595     if (id) {
596         //Incorrect optimization - for popup windows, Qt's focus is moved before
597         //hide_sys is called, resulting in the popup window keeping its elevated
598         //position in the CONE control stack.
599         //This can result in keyboard focus being in an invisible widget in some
600         //conditions - e.g. QTBUG-4733
601         //if(id->IsFocused()) // Avoid unnecessary calls to FocusChanged()
602             id->setFocusSafely(false);
603         id->MakeVisible(false);
604         if (QWidgetBackingStore *bs = maybeBackingStore())
605             bs->releaseBuffer();
606     } else {
607         invalidateBuffer(q->rect());
608     }
609
610     q->setAttribute(Qt::WA_Mapped, false);
611 }
612
613 void QWidgetPrivate::setFocus_sys()
614 {
615     Q_Q(QWidget);
616     if (q->testAttribute(Qt::WA_WState_Created) && q->window()->windowType() != Qt::Popup)
617         if (!q->effectiveWinId()->IsFocused()) // Avoid unnecessry calls to FocusChanged()
618             static_cast<QSymbianControl *>(q->effectiveWinId())->setFocusSafely(true);
619 }
620
621 void QWidgetPrivate::raise_sys()
622 {
623     Q_Q(QWidget);
624
625     Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
626     if (q->internalWinId()) {
627         q->internalWinId()->DrawableWindow()->SetOrdinalPosition(0);
628
629         // If toplevel widget, raise app to foreground
630         if (q->isWindow())
631             S60->wsSession().SetWindowGroupOrdinalPosition(S60->windowGroup().Identifier(), 0);
632     }
633 }
634
635 void QWidgetPrivate::lower_sys()
636 {
637     Q_Q(QWidget);
638
639     Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
640     if (q->internalWinId()) {
641         // If toplevel widget, lower app to background
642         if (q->isWindow())
643             S60->wsSession().SetWindowGroupOrdinalPosition(S60->windowGroup().Identifier(), -1);
644         else
645             q->internalWinId()->DrawableWindow()->SetOrdinalPosition(-1);
646     }
647
648     if (!q->isWindow())
649         invalidateBuffer(q->rect());
650 }
651
652 void QWidgetPrivate::setModal_sys()
653 {
654
655 }
656
657 void QWidgetPrivate::stackUnder_sys(QWidget* w)
658 {
659     Q_Q(QWidget);
660     Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
661
662     if (q->internalWinId() && w->internalWinId()) {
663         RDrawableWindow *const thisWindow = q->internalWinId()->DrawableWindow();
664         RDrawableWindow *const otherWindow = w->internalWinId()->DrawableWindow();
665         thisWindow->SetOrdinalPosition(otherWindow->OrdinalPosition() + 1);
666     }
667
668     if (!q->isWindow() || !w->internalWinId())
669         invalidateBuffer(q->rect());
670 }
671
672 void QWidgetPrivate::reparentChildren()
673 {
674     Q_Q(QWidget);
675
676     QObjectList chlist = q->children();
677     for (int i = 0; i < chlist.size(); ++i) { // reparent children
678         QObject *obj = chlist.at(i);
679         if (obj->isWidgetType()) {
680             QWidget *w = (QWidget *)obj;
681             if (!w->testAttribute(Qt::WA_WState_Created))
682                 continue;
683             if (!w->isWindow()) {
684                 w->d_func()->invalidateBuffer(w->rect());
685                 WId parent = q->effectiveWinId();
686                 WId child = w->effectiveWinId();
687                 if (parent != child) {
688                     // Child widget is native.  Because Symbian windows cannot be
689                     // re-parented, we must re-create the window.
690                     const WId window = 0;
691                     const bool initializeWindow = false;
692                     const bool destroyOldWindow = true;
693                     w->d_func()->create_sys(window, initializeWindow, destroyOldWindow);
694                 }
695                 // ### TODO: We probably also need to update the component array here
696                 w->d_func()->reparentChildren();
697             } else {
698                 bool showIt = w->isVisible();
699                 QPoint old_pos = w->pos();
700                 w->setParent(q, w->windowFlags());
701                 w->move(old_pos);
702                 if (showIt)
703                     w->show();
704             }
705         }
706     }
707 }
708
709 void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
710 {
711     Q_Q(QWidget);
712
713     bool wasCreated = q->testAttribute(Qt::WA_WState_Created);
714
715     if (q->isVisible() && q->parentWidget() && parent != q->parentWidget())
716         q->parentWidget()->d_func()->invalidateBuffer(q->geometry());
717
718     if (q->testAttribute(Qt::WA_DropSiteRegistered))
719         q->setAttribute(Qt::WA_DropSiteRegistered, false);
720
721     QSymbianControl *old_winid = static_cast<QSymbianControl *>(wasCreated ? data.winid : 0);
722     if ((q->windowType() == Qt::Desktop))
723         old_winid = 0;
724
725     // old_winid may not have received a 'not visible' visibility
726     // changed event before being destroyed; make sure that it is
727     // removed from the backing store's list of visible windows.
728     if (old_winid)
729         S60->controlVisibilityChanged(old_winid, false);
730
731     setWinId(0);
732
733     // hide and reparent our own window away. Otherwise we might get
734     // destroyed when emitting the child remove event below. See QWorkspace.
735     if (wasCreated && old_winid) {
736         old_winid->MakeVisible(false);
737         if (old_winid->IsFocused()) // Avoid unnecessary calls to FocusChanged()
738             old_winid->setFocusSafely(false);
739         old_winid->SetParent(0);
740     }
741
742     QObjectPrivate::setParent_helper(parent);
743     bool explicitlyHidden = q->testAttribute(Qt::WA_WState_Hidden) && q->testAttribute(Qt::WA_WState_ExplicitShowHide);
744
745     data.window_flags = f;
746     data.fstrut_dirty = true;
747     q->setAttribute(Qt::WA_WState_Created, false);
748     q->setAttribute(Qt::WA_WState_Visible, false);
749     q->setAttribute(Qt::WA_WState_Hidden, false);
750     adjustFlags(data.window_flags, q);
751     // keep compatibility with previous versions, we need to preserve the created state
752     // (but we recreate the winId for the widget being reparented, again for compatibility)
753     if (wasCreated || (!q->isWindow() && parent->testAttribute(Qt::WA_WState_Created)))
754         createWinId();
755     if (q->isWindow() || (!parent || parent->isVisible()) || explicitlyHidden)
756         q->setAttribute(Qt::WA_WState_Hidden);
757     q->setAttribute(Qt::WA_WState_ExplicitShowHide, explicitlyHidden);
758
759     if (wasCreated)
760         reparentChildren();
761
762     if (old_winid) {
763         CBase::Delete(old_winid);
764     }
765
766     if (q->testAttribute(Qt::WA_AcceptDrops)
767         || (!q->isWindow() && q->parentWidget() && q->parentWidget()->testAttribute(Qt::WA_DropSiteRegistered)))
768         q->setAttribute(Qt::WA_DropSiteRegistered, true);
769
770     invalidateBuffer(q->rect());
771 }
772
773 void QWidgetPrivate::setConstraints_sys()
774 {
775
776 }
777
778
779 void QWidgetPrivate::s60UpdateIsOpaque()
780 {
781     Q_Q(QWidget);
782
783     if (!q->testAttribute(Qt::WA_WState_Created) || !q->testAttribute(Qt::WA_TranslucentBackground))
784         return;
785
786     createTLExtra();
787
788     RWindow *const window = static_cast<RWindow *>(q->effectiveWinId()->DrawableWindow());
789
790 #ifdef Q_SYMBIAN_SEMITRANSPARENT_BG_SURFACE
791     window->SetSurfaceTransparency(!isOpaque);
792     extra->topextra->nativeWindowTransparencyEnabled = !isOpaque;
793 #else
794     if (!isOpaque) {
795         const TDisplayMode displayMode = static_cast<TDisplayMode>(window->SetRequiredDisplayMode(EColor16MA));
796         if (window->SetTransparencyAlphaChannel() == KErrNone) {
797             window->SetBackgroundColor(TRgb(255, 255, 255, 0));
798             extra->topextra->nativeWindowTransparencyEnabled = 1;
799
800             if (extra->topextra->backingStore.data() &&
801                     QApplicationPrivate::graphics_system_name == QLatin1String("openvg")) {
802                 // Semi-transparent EGL surfaces aren't supported. We need to
803                 // recreate backing store to get translucent surface (raster surface).
804                 extra->topextra->backingStore.create(q);
805                 extra->topextra->backingStore.registerWidget(q);
806             }
807         }
808     } else if (extra->topextra->nativeWindowTransparencyEnabled) {
809         window->SetTransparentRegion(TRegionFix<1>());
810         extra->topextra->nativeWindowTransparencyEnabled = 0;
811     }
812 #endif
813 }
814
815 void QWidgetPrivate::setWindowIcon_sys(bool forceReset)
816 {
817 #ifdef Q_WS_S60
818     Q_Q(QWidget);
819
820     if (!q->testAttribute(Qt::WA_WState_Created) || !q->isWindow() )
821         return;
822
823     QTLWExtra* topData = this->topData();
824     if (topData->iconPixmap && !forceReset)
825         // already been set
826         return;
827
828     TRect cPaneRect;
829     TBool found = AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::EContextPane, cPaneRect );
830     CAknContextPane* contextPane = S60->contextPane();
831     if (found && contextPane) { // We have context pane with valid metrics
832         QIcon icon = q->windowIcon();
833         if (!icon.isNull()) {
834             // Valid icon -> set it as an context pane picture
835             QSize size = icon.actualSize(QSize(cPaneRect.Size().iWidth, cPaneRect.Size().iHeight));
836             QPixmap pm = icon.pixmap(size);
837             QBitmap mask = pm.mask();
838             if (mask.isNull()) {
839                 mask = QBitmap(pm.size());
840                 mask.fill(Qt::color1);
841             }
842
843             CFbsBitmap* nBitmap = pm.toSymbianCFbsBitmap();
844             CFbsBitmap* nMask = mask.toSymbianCFbsBitmap();
845             contextPane->SetPicture(nBitmap,nMask);
846         } else {
847             // Icon set to null -> set context pane picture to default
848             QT_TRAP_THROWING(contextPane->SetPictureToDefaultL());
849         }
850     } else {
851         // Context pane does not exist, try setting small icon to title pane
852         TRect titlePaneRect;
853         TBool found = AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::ETitlePane, titlePaneRect );
854         CAknTitlePane* titlePane = S60->titlePane();
855         if (found && titlePane) { // We have title pane with valid metrics
856             // The API to get title_pane graphics size is not public -> assume square space based
857             // on titlebar font height. CAknBitmap would be optimum, wihtout setting the size, since
858             // then title pane would automatically scale the bitmap. Unfortunately it is not public API
859             // Also this function is leaving, although it is not named as such.
860             const CFont * font;
861             QT_TRAP_THROWING(font = AknLayoutUtils::FontFromId(EAknLogicalFontTitleFont));
862             TSize iconSize(font->HeightInPixels(), font->HeightInPixels());
863
864             QIcon icon = q->windowIcon();
865             if (!icon.isNull()) {
866                 // Valid icon -> set it as an title pane small picture
867                 QSize size = icon.actualSize(QSize(iconSize.iWidth, iconSize.iHeight));
868                 QPixmap pm = icon.pixmap(size);
869                 QBitmap mask = pm.mask();
870                 if (mask.isNull()) {
871                     mask = QBitmap(pm.size());
872                     mask.fill(Qt::color1);
873                 }
874
875                 CFbsBitmap* nBitmap = pm.toSymbianCFbsBitmap();
876                 CFbsBitmap* nMask = mask.toSymbianCFbsBitmap();
877                 titlePane->SetSmallPicture( nBitmap, nMask, ETrue );
878             } else {
879                 // Icon set to null -> set context pane picture to default
880                 titlePane->SetSmallPicture( NULL, NULL, EFalse );
881             }
882         }
883     }
884
885 #else
886         Q_UNUSED(forceReset)
887 #endif
888 }
889
890 void QWidgetPrivate::setWindowTitle_sys(const QString &caption)
891 {
892 #ifdef Q_WS_S60
893     Q_Q(QWidget);
894     if (q->isWindow()) {
895         Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
896         CAknTitlePane* titlePane = S60->titlePane();
897         if (titlePane) {
898             if (caption.isEmpty()) {
899                 QT_TRAP_THROWING(titlePane->SetTextToDefaultL());
900             } else {
901                 QT_TRAP_THROWING(titlePane->SetTextL(qt_QString2TPtrC(caption)));
902             }
903         }
904     }
905 #else
906     Q_UNUSED(caption)
907 #endif
908 }
909
910 void QWidgetPrivate::setWindowIconText_sys(const QString & /*iconText */)
911 {
912
913 }
914
915 void QWidgetPrivate::scroll_sys(int dx, int dy)
916 {
917     Q_Q(QWidget);
918
919     scrollChildren(dx, dy);
920     if (!paintOnScreen() || !q->internalWinId() || !q->internalWinId()->OwnsWindow()) {
921         scrollRect(q->rect(), dx, dy);
922     } else {
923         Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
924         RDrawableWindow *const window = q->internalWinId()->DrawableWindow();
925         window->Scroll(TPoint(dx, dy));
926     }
927 }
928
929 void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r)
930 {
931     Q_Q(QWidget);
932
933     if (!paintOnScreen() || !q->internalWinId() || !q->internalWinId()->OwnsWindow()) {
934         scrollRect(r, dx, dy);
935     } else {
936         Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
937         RDrawableWindow *const window = q->internalWinId()->DrawableWindow();
938         window->Scroll(TPoint(dx, dy), qt_QRect2TRect(r));
939     }
940 }
941
942 /*!
943     For this function to work in the emulator, you must add:
944        TRANSPARENCY
945     To a line in the wsini.ini file.
946 */
947 void QWidgetPrivate::setWindowOpacity_sys(qreal)
948 {
949     // ### TODO: Implement uniform window transparency
950 }
951
952 void QWidgetPrivate::updateFrameStrut()
953 {
954
955 }
956
957 void QWidgetPrivate::updateSystemBackground()
958 {
959
960 }
961
962 void QWidgetPrivate::registerDropSite(bool /* on */)
963 {
964
965 }
966
967 void QWidgetPrivate::createTLSysExtra()
968 {
969     extra->topextra->inExpose = 0;
970     extra->topextra->nativeWindowTransparencyEnabled = 0;
971 }
972
973 void QWidgetPrivate::deleteTLSysExtra()
974 {
975     extra->topextra->backingStore.destroy();
976 }
977
978 void QWidgetPrivate::createSysExtra()
979 {
980     extra->activated = 0;
981     extra->nativePaintMode = QWExtra::Default;
982     extra->receiveNativePaintEvents = 0;
983 }
984
985 void QWidgetPrivate::deleteSysExtra()
986 {
987     // this should only be non-zero if destroy() has not run due to constructor fail
988     if (data.winid) {
989         data.winid->ControlEnv()->AppUi()->RemoveFromStack(data.winid);
990         delete data.winid;
991         data.winid = 0;
992     }
993 }
994
995 QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys()
996 {
997     return new QS60WindowSurface(q_func());
998 }
999
1000 void QWidgetPrivate::setMask_sys(const QRegion& /* region */)
1001 {
1002
1003 }
1004
1005 void QWidgetPrivate::registerTouchWindow()
1006 {
1007 #ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
1008     Q_Q(QWidget);
1009     if (q->testAttribute(Qt::WA_WState_Created) && q->windowType() != Qt::Desktop) {
1010         RWindow *rwindow = static_cast<RWindow *>(q->effectiveWinId()->DrawableWindow());
1011         QSymbianControl *window = static_cast<QSymbianControl *>(q->effectiveWinId());
1012         //Enabling advanced pointer events for controls that already have active windows causes a panic.
1013         if (!window->isControlActive())
1014             rwindow->EnableAdvancedPointers();
1015     }
1016 #endif
1017 }
1018
1019 int QWidget::metric(PaintDeviceMetric m) const
1020 {
1021     Q_D(const QWidget);
1022     int val;
1023     if (m == PdmWidth) {
1024         val = data->crect.width();
1025     } else if (m == PdmHeight) {
1026         val = data->crect.height();
1027     } else {
1028         CWsScreenDevice *scr = S60->screenDevice();
1029         switch(m) {
1030         case PdmDpiX:
1031         case PdmPhysicalDpiX:
1032             if (d->extra && d->extra->customDpiX) {
1033                 val = d->extra->customDpiX;
1034             } else {
1035                 const QWidgetPrivate *p = d;
1036                 while (p->parent) {
1037                     p = static_cast<const QWidget *>(p->parent)->d_func();
1038                     if (p->extra && p->extra->customDpiX) {
1039                         val = p->extra->customDpiX;
1040                         break;
1041                     }
1042                 }
1043                 if (p == d || !(p->extra && p->extra->customDpiX))
1044                     val = S60->defaultDpiX;
1045             }
1046             break;
1047         case PdmDpiY:
1048         case PdmPhysicalDpiY:
1049             if (d->extra && d->extra->customDpiY) {
1050                 val = d->extra->customDpiY;
1051             } else {
1052                 const QWidgetPrivate *p = d;
1053                 while (p->parent) {
1054                     p = static_cast<const QWidget *>(p->parent)->d_func();
1055                     if (p->extra && p->extra->customDpiY) {
1056                         val = p->extra->customDpiY;
1057                         break;
1058                     }
1059                 }
1060                 if (p == d || !(p->extra && p->extra->customDpiY))
1061                     val = S60->defaultDpiY;
1062             }
1063             break;
1064         case PdmWidthMM:
1065         {
1066             TInt twips = scr->HorizontalPixelsToTwips(data->crect.width());
1067             val = (int)(twips * (25.4/KTwipsPerInch));
1068             break;
1069         }
1070         case PdmHeightMM:
1071         {
1072             TInt twips = scr->VerticalPixelsToTwips(data->crect.height());
1073             val = (int)(twips * (25.4/KTwipsPerInch));
1074             break;
1075         }
1076         case PdmNumColors:
1077             val = TDisplayModeUtils::NumDisplayModeColors(scr->DisplayMode());
1078             break;
1079         case PdmDepth:
1080             val = TDisplayModeUtils::NumDisplayModeBitsPerPixel(scr->DisplayMode());
1081             break;
1082         default:
1083             val = 0;
1084             qWarning("QWidget::metric: Invalid metric command");
1085         }
1086     }
1087     return val;
1088 }
1089
1090 QPaintEngine *QWidget::paintEngine() const
1091 {
1092     return 0;
1093 }
1094
1095 QPoint QWidget::mapToGlobal(const QPoint &pos) const
1096 {
1097     Q_D(const QWidget);
1098     if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) {
1099
1100         QPoint p = pos + data->crect.topLeft();
1101         return (isWindow() || !parentWidget()) ?  p : parentWidget()->mapToGlobal(p);
1102
1103     } else if ((d->data.window_flags & Qt::Window) && internalWinId()) { //toplevel
1104         QPoint tp = geometry().topLeft();
1105         return pos + tp;
1106     }
1107
1108     // Native window case
1109     const TPoint widgetScreenOffset = internalWinId()->PositionRelativeToScreen();
1110     const QPoint globalPos = QPoint(widgetScreenOffset.iX, widgetScreenOffset.iY) + pos;
1111     return globalPos;
1112 }
1113
1114 QPoint QWidget::mapFromGlobal(const QPoint &pos) const
1115 {
1116     Q_D(const QWidget);
1117     if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) {
1118         QPoint p = (isWindow() || !parentWidget()) ?  pos : parentWidget()->mapFromGlobal(pos);
1119         return p - data->crect.topLeft();
1120     } else if ((d->data.window_flags & Qt::Window) && internalWinId()) { //toplevel
1121         QPoint tp = geometry().topLeft();
1122         return pos - tp;
1123     }
1124
1125     // Native window case
1126     const TPoint widgetScreenOffset = internalWinId()->PositionRelativeToScreen();
1127     const QPoint widgetPos = pos - QPoint(widgetScreenOffset.iX, widgetScreenOffset.iY);
1128     return widgetPos;
1129 }
1130
1131 static Qt::WindowStates effectiveState(Qt::WindowStates state)
1132 {
1133     if (state & Qt::WindowMinimized)
1134         return Qt::WindowMinimized;
1135     else if (state & Qt::WindowFullScreen)
1136         return Qt::WindowFullScreen;
1137     else if (state & Qt::WindowMaximized)
1138         return Qt::WindowMaximized;
1139     return Qt::WindowNoState;
1140 }
1141
1142 void QWidget::setWindowState(Qt::WindowStates newstate)
1143 {
1144     Q_D(QWidget);
1145
1146     Qt::WindowStates oldstate = windowState();
1147
1148     const TBool isFullscreen = newstate & Qt::WindowFullScreen;
1149 #ifdef Q_WS_S60
1150     const TBool cbaRequested = windowFlags() & Qt::WindowSoftkeysVisibleHint;
1151     const TBool cbaVisible = CEikButtonGroupContainer::Current() ? true : false;
1152     const TBool softkeyVisibilityChange = isFullscreen && (cbaRequested != cbaVisible);
1153
1154     if (oldstate == newstate && !softkeyVisibilityChange)
1155         return;
1156 #endif // Q_WS_S60
1157
1158     if (isWindow()) {
1159         createWinId();
1160         Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1161
1162         const bool wasResized = testAttribute(Qt::WA_Resized);
1163         const bool wasMoved = testAttribute(Qt::WA_Moved);
1164
1165         QSymbianControl *window = static_cast<QSymbianControl *>(effectiveWinId());
1166         if (window && newstate & Qt::WindowMinimized) {
1167             window->setFocusSafely(false);
1168             window->MakeVisible(false);
1169         } else if (window && oldstate & Qt::WindowMinimized) {
1170             window->setFocusSafely(true);
1171             window->MakeVisible(true);
1172         }
1173
1174 #ifdef Q_WS_S60
1175         bool decorationsVisible(false);
1176         if (!parentWidget()) { // Only top level native windows have control over cba/status pane
1177             // Hide window decoration when switching to fullscreen / minimized otherwise show decoration.
1178             // The window decoration visibility has to be changed before doing actual window state
1179             // change since in that order the availableGeometry will return directly the right size and
1180             // we will avoid unnecessary redraws
1181             decorationsVisible = !(newstate & (Qt::WindowFullScreen | Qt::WindowMinimized));
1182             const bool statusPaneVisibility = decorationsVisible;
1183             const bool buttonGroupVisibility = (decorationsVisible || (isFullscreen && cbaRequested));
1184             S60->setStatusPaneAndButtonGroupVisibility(statusPaneVisibility, buttonGroupVisibility);
1185         }
1186 #endif // Q_WS_S60
1187
1188         // Ensure the initial size is valid, since we store it as normalGeometry below.
1189         if (!wasResized && !isVisible())
1190             adjustSize();
1191
1192         QTLWExtra *top = d->topData();
1193         QRect normalGeometry = (top->normalGeometry.width() < 0) ? geometry() : top->normalGeometry;
1194
1195         const bool cbaVisibilityHint = windowFlags() & Qt::WindowSoftkeysVisibleHint;
1196         if (newstate & Qt::WindowFullScreen && !cbaVisibilityHint) {
1197             setAttribute(Qt::WA_OutsideWSRange, false);
1198             window->SetExtentToWholeScreen();
1199         } else if (newstate & Qt::WindowMaximized || ((newstate & Qt::WindowFullScreen) && cbaVisibilityHint)) {
1200             setAttribute(Qt::WA_OutsideWSRange, false);
1201             TRect maxExtent = qt_QRect2TRect(qApp->desktop()->availableGeometry(this));
1202             window->SetExtent(maxExtent.iTl, maxExtent.Size());
1203         } else {
1204 #ifdef Q_WS_S60
1205             // With delayed creation of S60 app panes, the normalGeometry calculated above is not
1206             // accurate because it did not consider the status pane. This means that when returning
1207             // normal mode after showing the status pane, the geometry would overlap so we should
1208             // move it if it never had an explicit position.
1209             if (!wasMoved && S60->statusPane() && decorationsVisible) {
1210                 TPoint tl = static_cast<CEikAppUi*>(S60->appUi())->ClientRect().iTl;
1211                 normalGeometry.setTopLeft(QPoint(tl.iX, tl.iY));
1212             }
1213 #endif
1214             setGeometry(normalGeometry);
1215         }
1216
1217         //restore normal geometry
1218         top->normalGeometry = normalGeometry;
1219
1220         // FixMe QTBUG-8977
1221         // In some platforms, WA_Resized and WA_Moved are also not set when application window state is
1222         // anything else than normal. In Symbian we can restore them only for normal window state since
1223         // restoring for other modes, will make fluidlauncher to be launched in wrong size (200x100)
1224         if (effectiveState(newstate) == Qt::WindowNoState) {
1225             setAttribute(Qt::WA_Resized, wasResized);
1226             setAttribute(Qt::WA_Moved, wasMoved);
1227         }
1228     }
1229
1230     data->window_state = newstate;
1231
1232     if (newstate & Qt::WindowActive)
1233         activateWindow();
1234
1235     QWindowStateChangeEvent e(oldstate);
1236     QApplication::sendEvent(this, &e);
1237 }
1238
1239
1240 void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
1241 {
1242     Q_D(QWidget);
1243     d->aboutToDestroy();
1244     if (!isWindow() && parentWidget())
1245         parentWidget()->d_func()->invalidateBuffer(geometry());
1246     d->deactivateWidgetCleanup();
1247     QSymbianControl *id = static_cast<QSymbianControl *>(internalWinId());
1248     if (testAttribute(Qt::WA_WState_Created)) {
1249
1250 #ifndef QT_NO_IM
1251         if (d->ic) {
1252             delete d->ic;
1253         } else {
1254             QInputContext *ic = QApplicationPrivate::inputContext;
1255             if (ic) {
1256                 ic->widgetDestroyed(this);
1257             }
1258         }
1259 #endif
1260
1261         if (QWidgetPrivate::mouseGrabber == this)
1262             releaseMouse();
1263         if (QWidgetPrivate::keyboardGrabber == this)
1264             releaseKeyboard();
1265         setAttribute(Qt::WA_WState_Created, false);
1266         QObjectList childList = children();
1267         for (int i = 0; i < childList.size(); ++i) { // destroy all widget children
1268             register QObject *obj = childList.at(i);
1269             if (obj->isWidgetType())
1270                 static_cast<QWidget*>(obj)->destroy(destroySubWindows,
1271                                                     destroySubWindows);
1272         }
1273         if (destroyWindow && !(windowType() == Qt::Desktop) && id) {
1274             if (id->IsFocused()) // Avoid unnecessry calls to FocusChanged()
1275                 id->setFocusSafely(false);
1276             id->ControlEnv()->AppUi()->RemoveFromStack(id);
1277         }
1278     }
1279
1280     QT_TRY {
1281         d->setWinId(0);
1282     } QT_CATCH (const std::bad_alloc &) {
1283         // swallow - destructors must not throw
1284     }
1285
1286     if (destroyWindow) {
1287         delete id;
1288         // At this point the backing store should already be destroyed
1289         // so we flush the command buffer to ensure that the freeing of
1290         // those resources and deleting the window can happen "atomically"
1291         if (qApp)
1292             S60->wsSession().Flush();
1293     }
1294 }
1295
1296 QWidget *QWidget::mouseGrabber()
1297 {
1298     return QWidgetPrivate::mouseGrabber;
1299 }
1300
1301 QWidget *QWidget::keyboardGrabber()
1302 {
1303     return QWidgetPrivate::keyboardGrabber;
1304 }
1305
1306 void QWidget::grabKeyboard()
1307 {
1308     if (!qt_nograb()) {
1309         if (QWidgetPrivate::keyboardGrabber && QWidgetPrivate::keyboardGrabber != this)
1310             QWidgetPrivate::keyboardGrabber->releaseKeyboard();
1311
1312         // ### TODO: Native keyboard grab
1313
1314         QWidgetPrivate::keyboardGrabber = this;
1315     }
1316 }
1317
1318 void QWidget::releaseKeyboard()
1319 {
1320     if (!qt_nograb() && QWidgetPrivate::keyboardGrabber == this) {
1321         // ### TODO: Native keyboard release
1322         QWidgetPrivate::keyboardGrabber = 0;
1323     }
1324 }
1325
1326 void QWidget::grabMouse()
1327 {
1328     if (isVisible() && !qt_nograb()) {
1329         if (QWidgetPrivate::mouseGrabber && QWidgetPrivate::mouseGrabber != this)
1330             QWidgetPrivate::mouseGrabber->releaseMouse();
1331         Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1332         WId id = effectiveWinId();
1333         id->SetPointerCapture(true);
1334         QWidgetPrivate::mouseGrabber = this;
1335
1336 #ifndef QT_NO_CURSOR
1337         QApplication::setOverrideCursor(cursor());
1338 #endif
1339     }
1340 }
1341
1342 #ifndef QT_NO_CURSOR
1343 void QWidget::grabMouse(const QCursor &cursor)
1344 {
1345     if (isVisible() && !qt_nograb()) {
1346         if (QWidgetPrivate::mouseGrabber && QWidgetPrivate::mouseGrabber != this)
1347             QWidgetPrivate::mouseGrabber->releaseMouse();
1348         Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1349         WId id = effectiveWinId();
1350         id->SetPointerCapture(true);
1351         QWidgetPrivate::mouseGrabber = this;
1352
1353         QApplication::setOverrideCursor(cursor);
1354     }
1355 }
1356 #endif
1357
1358 void QWidget::releaseMouse()
1359 {
1360     if (!qt_nograb() && QWidgetPrivate::mouseGrabber == this) {
1361         Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1362         if(!window()->isModal()) {
1363             WId id = effectiveWinId();
1364             id->SetPointerCapture(false);
1365         }
1366         QWidgetPrivate::mouseGrabber = 0;
1367 #ifndef QT_NO_CURSOR
1368         QApplication::restoreOverrideCursor();
1369 #endif
1370     }
1371 }
1372
1373 void QWidget::activateWindow()
1374 {
1375     Q_D(QWidget);
1376
1377     QWidget *tlw = window();
1378     if (tlw->isVisible()) {
1379         window()->createWinId();
1380         QSymbianControl *id = static_cast<QSymbianControl *>(tlw->internalWinId());
1381         id->setFocusSafely(true);
1382     }
1383 }
1384
1385 #ifndef QT_NO_CURSOR
1386
1387 void QWidgetPrivate::setCursor_sys(const QCursor &cursor)
1388 {
1389     Q_UNUSED(cursor);
1390     Q_Q(QWidget);
1391     qt_symbian_set_cursor(q, false);
1392 }
1393
1394 void QWidgetPrivate::unsetCursor_sys()
1395 {
1396     Q_Q(QWidget);
1397     qt_symbian_set_cursor(q, false);
1398 }
1399 #endif
1400
1401 QT_END_NAMESPACE