Show softkeys when opening a dialog that has a fullscreen parent.
[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 ** Commercial Usage
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.
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 ** 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.
35 **
36 ** If you have questions regarding the use of this file, please contact
37 ** Nokia at qt-info@nokia.com.
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 <eikbtgpc.h>
58 #endif
59
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)
65
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
74 {
75 public:
76     IMPORT_C void SetToolbarVisibility(const TBool visible);
77 };
78
79 QT_BEGIN_NAMESPACE
80
81 extern bool qt_nograb();
82
83 QWidget *QWidgetPrivate::mouseGrabber = 0;
84 QWidget *QWidgetPrivate::keyboardGrabber = 0;
85 CEikButtonGroupContainer *QS60Data::cba = 0;
86
87 static bool isEqual(const QList<QAction*>& a, const QList<QAction*>& b)
88 {
89     if ( a.count() != b.count())
90         return false;
91     int index=0;
92     while (index<a.count()) {
93         if (a.at(index)->softKeyRole() != b.at(index)->softKeyRole())
94             return false;
95         if (a.at(index)->text().compare(b.at(index)->text())!=0)
96             return false;
97         index++;
98     }
99     return true;
100 }
101
102 void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &)
103 {
104     // Note: based on x11 implementation
105
106     static const int XCOORD_MAX = 16383;
107     static const int WRECT_MAX = 16383;
108
109     Q_Q(QWidget);
110
111     Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
112
113     /*
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).
119      */
120
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);
123     QRect wrect;
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;
126
127     const QWidget *const parent = q->parentWidget();
128     QRect parentWRect = parent->data->wrect;
129
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;
134             wrect = xrect;
135             //translate from parent's to my Qt coord sys
136             wrect.translate(-data.crect.topLeft());
137         }
138         //translate from parent's Qt coords to parent's X coords
139         xrect.translate(-parentWRect.topLeft());
140
141     } else {
142         // parent is not clipped, we may or may not have to clip
143
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
148             // children
149
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)) {
153                 xrect = data.wrect;
154                 xrect.translate(data.crect.topLeft());
155                 if (data.winid)
156                     data.winid->SetExtent(TPoint(xrect.x(), xrect.y()), TSize(xrect.width(), xrect.height()));
157                 return;
158             }
159         }
160
161         if (!validRange.contains(xrect)) {
162             // we are too big, and must clip
163             xrect &=wrectRange;
164             wrect = xrect;
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.
168         }
169     }
170
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);
176         if (outsideRange) {
177             if (data.winid)
178                 data.winid->DrawableWindow()->SetVisible(EFalse);
179             q->setAttribute(Qt::WA_Mapped, false);
180         } else if (!q->isHidden()) {
181             mapWindow = true;
182         }
183     }
184
185     if (outsideRange)
186         return;
187
188     bool jump = (data.wrect != wrect);
189     data.wrect = wrect;
190
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);
198         }
199     }
200
201     if (data.winid) {
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)));
207
208         data.winid->SetExtent(TPoint(xrect.x(), xrect.y()), TSize(xrect.width(), xrect.height()));
209     }
210
211     if (mapWindow and !dontShow) {
212         q->setAttribute(Qt::WA_Mapped);
213         if (q->internalWinId())
214             q->internalWinId()->DrawableWindow()->SetVisible(ETrue);
215     }
216
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()));
220     }
221 }
222
223 void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove)
224 {
225     Q_Q(QWidget);
226
227     Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
228
229     if ((q->windowType() == Qt::Desktop))
230         return;
231
232     QPoint oldPos(q->pos());
233     QSize oldSize(q->size());
234     QRect oldGeom(data.crect);
235
236     // Lose maximized status if deliberate resize
237     if (w != oldSize.width() || h != oldSize.height())
238         data.window_state &= ~Qt::WindowMaximized;
239
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);
245     }
246
247     if (q->isWindow())
248         topData()->normalGeometry = QRect(0, 0, -1, -1);
249     else {
250         uint s = data.window_state;
251         s &= ~(Qt::WindowMaximized | Qt::WindowFullScreen);
252         data.window_state = s;
253     }
254
255     bool isResize = w != oldSize.width() || h != oldSize.height();
256     if (!isMove && !isResize)
257         return;
258
259     if (q->isWindow()) {
260         if (w == 0 || h == 0) {
261             q->setAttribute(Qt::WA_OutsideWSRange, true);
262             if (q->isVisible() && q->testAttribute(Qt::WA_Mapped))
263                 hide_sys();
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);
268
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);
272             show_sys();
273         } else {
274             QRect r = QRect(x, y, w, h);
275             data.crect = r;
276             q->internalWinId()->SetRect(TRect(TPoint(x, y), TSize(w, h)));
277             topData()->normalGeometry = data.crect;
278         }
279     } else {
280         data.crect.setRect(x, y, w, h);
281
282         QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData();
283         const bool inTopLevelResize = tlwExtra ? tlwExtra->inTopLevelResize : false;
284
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());
292             else
293                 invalidateBuffer_resizeHelper(oldPos, oldSize);
294
295             if (inTopLevelResize)
296                 tlwExtra->inTopLevelResize = true;
297         }
298         if (q->testAttribute(Qt::WA_WState_Created))
299             setWSGeometry();
300     }
301
302     if (q->isVisible()) {
303         if (isMove && q->pos() != oldPos) {
304             QMoveEvent e(q->pos(), oldPos);
305             QApplication::sendEvent(q, &e);
306         }
307         if (isResize) {
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;
319         }
320     } else {
321         if (isMove && q->pos() != oldPos)
322             q->setAttribute(Qt::WA_PendingMoveEvent, true);
323         if (isResize)
324             q->setAttribute(Qt::WA_PendingResizeEvent, true);
325     }
326 }
327
328 void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool destroyOldWindow)
329 {
330     Q_Q(QWidget);
331
332     Qt::WindowType type = q->windowType();
333     Qt::WindowFlags &flags = data.window_flags;
334     QWidget *parentWidget = q->parentWidget();
335
336     bool topLevel = (flags & Qt::Window);
337     bool popup = (type == Qt::Popup);
338     bool dialog = (type == Qt::Dialog
339                    || type == Qt::Sheet
340                    || (flags & Qt::MSWindowsFixedSizeDialogHint));
341     bool desktop = (type == Qt::Desktop);
342     //bool tool = (type == Qt::Tool || type == Qt::Drawer);
343
344     if (popup)
345         flags |= Qt::WindowStaysOnTopHint; // a popup stays on top
346
347     TRect clientRect = static_cast<CEikAppUi*>(S60->appUi())->ClientRect();
348     int sw = clientRect.Width();
349     int sh = clientRect.Height();
350
351     if (desktop) {
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)){
356         int width = sw;
357         int height = sh;
358         if (extra) {
359             width = qMax(qMin(width, extra->maxw), extra->minw);
360             height = qMax(qMin(height, extra->maxh), extra->minh);
361         }
362         data.crect.setSize(QSize(width, height));
363     }
364
365     CCoeControl *const destroyw = destroyOldWindow ? data.winid : 0;
366
367     createExtra();
368     if (window) {
369         setWinId(window);
370         TRect tr = window->Rect();
371         data.crect.setRect(tr.iTl.iX, tr.iTl.iY, tr.Width(), tr.Height());
372
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));
376
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()));
380
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
384         // ancestors.
385         extra->activated = 0;
386
387         if (!desktop) {
388             TInt stackingFlags;
389             if ((q->windowType() & Qt::Popup) == Qt::Popup) {
390                 stackingFlags = ECoeStackFlagRefusesAllKeys | ECoeStackFlagRefusesFocus;
391             } else {
392                 stackingFlags = ECoeStackFlagStandard;
393             }
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);
398
399             RDrawableWindow *const drawableWindow = control->DrawableWindow();
400             // Request mouse move events.
401             drawableWindow->PointerFilter(EPointerFilterEnterExit
402                 | EPointerFilterMove | EPointerFilterDrag, 0);
403             drawableWindow->EnableVisibilityChangeEvents();
404
405         }
406
407         q->setAttribute(Qt::WA_WState_Created);
408
409         int x, y, w, h;
410         data.crect.getRect(&x, &y, &w, &h);
411         control->SetRect(TRect(TPoint(x, y), TSize(w, h)));
412
413         // We wait until the control is fully constructed before calling setWinId, because
414         // this generates a WinIdChanged event.
415         setWinId(control.take());
416
417         if (!desktop)
418             s60UpdateIsOpaque(); // must be called after setWinId()
419
420     } else if (q->testAttribute(Qt::WA_NativeWindow) || paintOnScreen()) { // create native child widget
421
422         QScopedPointer<QSymbianControl> control( q_check_ptr(new QSymbianControl(q)) );
423         QT_TRAP_THROWING(control->ConstructL(!parentWidget));
424
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
428         // ancestors.
429         extra->activated = 0;
430
431         TInt stackingFlags;
432         if ((q->windowType() & Qt::Popup) == Qt::Popup) {
433             stackingFlags = ECoeStackFlagRefusesAllKeys | ECoeStackFlagRefusesFocus;
434         } else {
435             stackingFlags = ECoeStackFlagStandard;
436         }
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);
441
442         q->setAttribute(Qt::WA_WState_Created);
443         int x, y, w, h;
444         data.crect.getRect(&x, &y, &w, &h);
445         control->SetRect(TRect(TPoint(x, y), TSize(w, h)));
446
447         RDrawableWindow *const drawableWindow = control->DrawableWindow();
448         // Request mouse move events.
449         drawableWindow->PointerFilter(EPointerFilterEnterExit
450             | EPointerFilterMove | EPointerFilterDrag, 0);
451         drawableWindow->EnableVisibilityChangeEvents();
452
453         if (q->isVisible() && q->testAttribute(Qt::WA_Mapped)) {
454             activateSymbianWindow(control.data());
455             control->MakeVisible(true);
456         }
457
458         // We wait until the control is fully constructed before calling setWinId, because
459         // this generates a WinIdChanged event.
460         setWinId(control.take());
461     }
462
463     if (destroyw) {
464         destroyw->ControlEnv()->AppUi()->RemoveFromStack(destroyw);
465
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));
471     }
472
473     if (q->testAttribute(Qt::WA_AcceptTouchEvents))
474         registerTouchWindow();
475 }
476
477
478 void QWidgetPrivate::show_sys()
479 {
480     Q_Q(QWidget);
481
482     if (q->testAttribute(Qt::WA_OutsideWSRange))
483         return;
484
485     Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
486
487     q->setAttribute(Qt::WA_Mapped);
488
489     if (q->testAttribute(Qt::WA_DontShowOnScreen)) {
490         invalidateBuffer(q->rect());
491         return;
492     }
493
494     if (q->internalWinId()) {
495         if (!extra->activated)
496              activateSymbianWindow();
497
498          QSymbianControl *id = static_cast<QSymbianControl *>(q->internalWinId());
499          const bool isFullscreen = q->windowState() & Qt::WindowFullScreen;
500          const TBool cbaRequested = q->windowFlags() & Qt::WindowSoftkeysVisibleHint;
501
502 #ifdef Q_WS_S60
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()) {
506
507             if (!q->testAttribute(Qt::WA_DontShowOnScreen)) {
508
509                 // Create the status pane and CBA here
510                 CEikAppUi *ui = static_cast<CEikAppUi *>(S60->appUi());
511                 MEikAppUiFactory *factory = CEikonEnv::Static()->AppUiFactory();
512
513                 QT_TRAP_THROWING(
514                     factory->CreateResourceIndependentFurnitureL(ui);
515
516                     TRect boundingRect = static_cast<CEikAppUi*>(S60->appUi())->ClientRect();
517
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);
522
523                     CEikButtonGroupContainer *oldCba = factory->SwapButtonGroup(cba);
524                     Q_ASSERT(!oldCba);
525                     S60->setButtonGroupContainer(cba);
526
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());
533                     if (appui) {
534                         CAknToolbar *toolbar = appui->PopupToolbar();
535                         if (toolbar && !toolbar->IsVisible())
536                             toolbar->SetToolbarVisibility(ETrue);
537                     }
538
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);
543
544                     CEikMenuBar *oldMenu = factory->SwapMenuBar(menuBar);
545                     Q_ASSERT(!oldMenu);
546                 )
547
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);
553                     if (isFullscreen) {
554                         const bool cbaVisible = S60->buttonGroupContainer() && S60->buttonGroupContainer()->IsVisible();
555                         S60->setStatusPaneAndButtonGroupVisibility(false, cbaVisible);
556                     }
557                 }
558             }
559         }
560 #endif
561
562         // Fill client area if maximized OR
563         // Put window below status pane unless the window has an explicit position.
564         if (!isFullscreen) {
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);
570             }
571         }
572
573         id->MakeVisible(true);
574
575         if(q->isWindow()&&!q->testAttribute(Qt::WA_ShowWithoutActivating))
576             id->setFocusSafely(true);
577     }
578
579     invalidateBuffer(q->rect());
580 }
581
582 void QWidgetPrivate::activateSymbianWindow(WId wid)
583 {
584     Q_Q(QWidget);
585
586     Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
587     Q_ASSERT(q->testAttribute(Qt::WA_Mapped));
588     Q_ASSERT(!extra->activated);
589
590     if(!wid)
591         wid = q->internalWinId();
592
593     Q_ASSERT(wid);
594
595     QT_TRAP_THROWING(wid->ActivateL());
596     extra->activated = 1;
597 }
598
599 void QWidgetPrivate::hide_sys()
600 {
601     Q_Q(QWidget);
602
603     Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
604     deactivateWidgetCleanup();
605     QSymbianControl *id = static_cast<QSymbianControl *>(q->internalWinId());
606
607     if (id) {
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())
617             bs->releaseBuffer();
618     } else {
619         invalidateBuffer(q->rect());
620     }
621
622     q->setAttribute(Qt::WA_Mapped, false);
623 }
624
625 void QWidgetPrivate::setFocus_sys()
626 {
627     Q_Q(QWidget);
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);
631 }
632
633 void QWidgetPrivate::raise_sys()
634 {
635     Q_Q(QWidget);
636
637     Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
638     if (q->internalWinId()) {
639         q->internalWinId()->DrawableWindow()->SetOrdinalPosition(0);
640
641         // If toplevel widget, raise app to foreground
642         if (q->isWindow())
643             S60->wsSession().SetWindowGroupOrdinalPosition(S60->windowGroup().Identifier(), 0);
644     }
645 }
646
647 void QWidgetPrivate::lower_sys()
648 {
649     Q_Q(QWidget);
650
651     Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
652     if (q->internalWinId()) {
653         // If toplevel widget, lower app to background
654         if (q->isWindow())
655             S60->wsSession().SetWindowGroupOrdinalPosition(S60->windowGroup().Identifier(), -1);
656         else
657             q->internalWinId()->DrawableWindow()->SetOrdinalPosition(-1);
658     }
659
660     if (!q->isWindow())
661         invalidateBuffer(q->rect());
662 }
663
664 void QWidgetPrivate::setModal_sys()
665 {
666
667 }
668
669 void QWidgetPrivate::stackUnder_sys(QWidget* w)
670 {
671     Q_Q(QWidget);
672     Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
673
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);
678     }
679
680     if (!q->isWindow() || !w->internalWinId())
681         invalidateBuffer(q->rect());
682 }
683
684 void QWidgetPrivate::reparentChildren()
685 {
686     Q_Q(QWidget);
687
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))
694                 continue;
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);
706                 }
707                 // ### TODO: We probably also need to update the component array here
708                 w->d_func()->reparentChildren();
709             } else {
710                 bool showIt = w->isVisible();
711                 QPoint old_pos = w->pos();
712                 w->setParent(q, w->windowFlags());
713                 w->move(old_pos);
714                 if (showIt)
715                     w->show();
716             }
717         }
718     }
719 }
720
721 void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
722 {
723     Q_Q(QWidget);
724
725     bool wasCreated = q->testAttribute(Qt::WA_WState_Created);
726
727     if (q->isVisible() && q->parentWidget() && parent != q->parentWidget())
728         q->parentWidget()->d_func()->invalidateBuffer(q->geometry());
729
730     if (q->testAttribute(Qt::WA_DropSiteRegistered))
731         q->setAttribute(Qt::WA_DropSiteRegistered, false);
732
733     QSymbianControl *old_winid = static_cast<QSymbianControl *>(wasCreated ? data.winid : 0);
734     if ((q->windowType() == Qt::Desktop))
735         old_winid = 0;
736
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.
740     if (old_winid)
741         S60->controlVisibilityChanged(old_winid, false);
742
743     setWinId(0);
744
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);
752     }
753
754     QObjectPrivate::setParent_helper(parent);
755     bool explicitlyHidden = q->testAttribute(Qt::WA_WState_Hidden) && q->testAttribute(Qt::WA_WState_ExplicitShowHide);
756
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)))
766         createWinId();
767     if (q->isWindow() || (!parent || parent->isVisible()) || explicitlyHidden)
768         q->setAttribute(Qt::WA_WState_Hidden);
769     q->setAttribute(Qt::WA_WState_ExplicitShowHide, explicitlyHidden);
770
771     if (wasCreated)
772         reparentChildren();
773
774     if (old_winid) {
775         CBase::Delete(old_winid);
776     }
777
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);
781
782     invalidateBuffer(q->rect());
783 }
784
785 void QWidgetPrivate::setConstraints_sys()
786 {
787
788 }
789
790
791 void QWidgetPrivate::s60UpdateIsOpaque()
792 {
793     Q_Q(QWidget);
794
795     if (!q->testAttribute(Qt::WA_WState_Created) || !q->testAttribute(Qt::WA_TranslucentBackground))
796         return;
797
798     createTLExtra();
799
800     RWindow *const window = static_cast<RWindow *>(q->effectiveWinId()->DrawableWindow());
801
802 #ifdef Q_SYMBIAN_SEMITRANSPARENT_BG_SURFACE
803     window->SetSurfaceTransparency(!isOpaque);
804     extra->topextra->nativeWindowTransparencyEnabled = !isOpaque;
805 #else
806     if (!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;
811
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);
818             }
819         }
820     } else if (extra->topextra->nativeWindowTransparencyEnabled) {
821         window->SetTransparentRegion(TRegionFix<1>());
822         extra->topextra->nativeWindowTransparencyEnabled = 0;
823     }
824 #endif
825 }
826
827 void QWidgetPrivate::setWindowIcon_sys(bool forceReset)
828 {
829 #ifdef Q_WS_S60
830     Q_Q(QWidget);
831
832     if (!q->testAttribute(Qt::WA_WState_Created) || !q->isWindow() )
833         return;
834
835     QTLWExtra* topData = this->topData();
836     if (topData->iconPixmap && !forceReset)
837         // already been set
838         return;
839
840     TRect cPaneRect;
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();
850             if (mask.isNull()) {
851                 mask = QBitmap(pm.size());
852                 mask.fill(Qt::color1);
853             }
854
855             CFbsBitmap* nBitmap = pm.toSymbianCFbsBitmap();
856             CFbsBitmap* nMask = mask.toSymbianCFbsBitmap();
857             contextPane->SetPicture(nBitmap,nMask);
858         } else {
859             // Icon set to null -> set context pane picture to default
860             QT_TRAP_THROWING(contextPane->SetPictureToDefaultL());
861         }
862     } else {
863         // Context pane does not exist, try setting small icon to title pane
864         TRect titlePaneRect;
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.
872             const CFont * font;
873             QT_TRAP_THROWING(font = AknLayoutUtils::FontFromId(EAknLogicalFontTitleFont));
874             TSize iconSize(font->HeightInPixels(), font->HeightInPixels());
875
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();
882                 if (mask.isNull()) {
883                     mask = QBitmap(pm.size());
884                     mask.fill(Qt::color1);
885                 }
886
887                 CFbsBitmap* nBitmap = pm.toSymbianCFbsBitmap();
888                 CFbsBitmap* nMask = mask.toSymbianCFbsBitmap();
889                 titlePane->SetSmallPicture( nBitmap, nMask, ETrue );
890             } else {
891                 // Icon set to null -> set context pane picture to default
892                 titlePane->SetSmallPicture( NULL, NULL, EFalse );
893             }
894         }
895     }
896
897 #else
898         Q_UNUSED(forceReset)
899 #endif
900 }
901
902 void QWidgetPrivate::setWindowTitle_sys(const QString &caption)
903 {
904 #ifdef Q_WS_S60
905     Q_Q(QWidget);
906     if (q->isWindow()) {
907         Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
908         CAknTitlePane* titlePane = S60->titlePane();
909         if (titlePane) {
910             if (caption.isEmpty()) {
911                 QT_TRAP_THROWING(titlePane->SetTextToDefaultL());
912             } else {
913                 QT_TRAP_THROWING(titlePane->SetTextL(qt_QString2TPtrC(caption)));
914             }
915         }
916     }
917 #else
918     Q_UNUSED(caption)
919 #endif
920 }
921
922 void QWidgetPrivate::setWindowIconText_sys(const QString & /*iconText */)
923 {
924
925 }
926
927 void QWidgetPrivate::scroll_sys(int dx, int dy)
928 {
929     Q_Q(QWidget);
930
931     scrollChildren(dx, dy);
932     if (!paintOnScreen() || !q->internalWinId() || !q->internalWinId()->OwnsWindow()) {
933         scrollRect(q->rect(), dx, dy);
934     } else {
935         Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
936         RDrawableWindow *const window = q->internalWinId()->DrawableWindow();
937         window->Scroll(TPoint(dx, dy));
938     }
939 }
940
941 void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r)
942 {
943     Q_Q(QWidget);
944
945     if (!paintOnScreen() || !q->internalWinId() || !q->internalWinId()->OwnsWindow()) {
946         scrollRect(r, dx, dy);
947     } else {
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));
951     }
952 }
953
954 /*!
955     For this function to work in the emulator, you must add:
956        TRANSPARENCY
957     To a line in the wsini.ini file.
958 */
959 void QWidgetPrivate::setWindowOpacity_sys(qreal)
960 {
961     // ### TODO: Implement uniform window transparency
962 }
963
964 void QWidgetPrivate::updateFrameStrut()
965 {
966
967 }
968
969 void QWidgetPrivate::updateSystemBackground()
970 {
971
972 }
973
974 void QWidgetPrivate::registerDropSite(bool /* on */)
975 {
976
977 }
978
979 void QWidgetPrivate::createTLSysExtra()
980 {
981     extra->topextra->inExpose = 0;
982     extra->topextra->nativeWindowTransparencyEnabled = 0;
983 }
984
985 void QWidgetPrivate::deleteTLSysExtra()
986 {
987     extra->topextra->backingStore.destroy();
988 }
989
990 void QWidgetPrivate::createSysExtra()
991 {
992     extra->activated = 0;
993     extra->nativePaintMode = QWExtra::Default;
994     extra->receiveNativePaintEvents = 0;
995 }
996
997 void QWidgetPrivate::deleteSysExtra()
998 {
999     // this should only be non-zero if destroy() has not run due to constructor fail
1000     if (data.winid) {
1001         data.winid->ControlEnv()->AppUi()->RemoveFromStack(data.winid);
1002         delete data.winid;
1003         data.winid = 0;
1004     }
1005 }
1006
1007 QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys()
1008 {
1009     return new QS60WindowSurface(q_func());
1010 }
1011
1012 void QWidgetPrivate::setMask_sys(const QRegion& /* region */)
1013 {
1014
1015 }
1016
1017 void QWidgetPrivate::registerTouchWindow()
1018 {
1019 #ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
1020     Q_Q(QWidget);
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();
1027     }
1028 #endif
1029 }
1030
1031 int QWidget::metric(PaintDeviceMetric m) const
1032 {
1033     Q_D(const QWidget);
1034     int val;
1035     if (m == PdmWidth) {
1036         val = data->crect.width();
1037     } else if (m == PdmHeight) {
1038         val = data->crect.height();
1039     } else {
1040         CWsScreenDevice *scr = S60->screenDevice();
1041         switch(m) {
1042         case PdmDpiX:
1043         case PdmPhysicalDpiX:
1044             if (d->extra && d->extra->customDpiX) {
1045                 val = d->extra->customDpiX;
1046             } else {
1047                 const QWidgetPrivate *p = d;
1048                 while (p->parent) {
1049                     p = static_cast<const QWidget *>(p->parent)->d_func();
1050                     if (p->extra && p->extra->customDpiX) {
1051                         val = p->extra->customDpiX;
1052                         break;
1053                     }
1054                 }
1055                 if (p == d || !(p->extra && p->extra->customDpiX))
1056                     val = S60->defaultDpiX;
1057             }
1058             break;
1059         case PdmDpiY:
1060         case PdmPhysicalDpiY:
1061             if (d->extra && d->extra->customDpiY) {
1062                 val = d->extra->customDpiY;
1063             } else {
1064                 const QWidgetPrivate *p = d;
1065                 while (p->parent) {
1066                     p = static_cast<const QWidget *>(p->parent)->d_func();
1067                     if (p->extra && p->extra->customDpiY) {
1068                         val = p->extra->customDpiY;
1069                         break;
1070                     }
1071                 }
1072                 if (p == d || !(p->extra && p->extra->customDpiY))
1073                     val = S60->defaultDpiY;
1074             }
1075             break;
1076         case PdmWidthMM:
1077         {
1078             TInt twips = scr->HorizontalPixelsToTwips(data->crect.width());
1079             val = (int)(twips * (25.4/KTwipsPerInch));
1080             break;
1081         }
1082         case PdmHeightMM:
1083         {
1084             TInt twips = scr->VerticalPixelsToTwips(data->crect.height());
1085             val = (int)(twips * (25.4/KTwipsPerInch));
1086             break;
1087         }
1088         case PdmNumColors:
1089             val = TDisplayModeUtils::NumDisplayModeColors(scr->DisplayMode());
1090             break;
1091         case PdmDepth:
1092             val = TDisplayModeUtils::NumDisplayModeBitsPerPixel(scr->DisplayMode());
1093             break;
1094         default:
1095             val = 0;
1096             qWarning("QWidget::metric: Invalid metric command");
1097         }
1098     }
1099     return val;
1100 }
1101
1102 QPaintEngine *QWidget::paintEngine() const
1103 {
1104     return 0;
1105 }
1106
1107 QPoint QWidget::mapToGlobal(const QPoint &pos) const
1108 {
1109     Q_D(const QWidget);
1110     if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) {
1111
1112         QPoint p = pos + data->crect.topLeft();
1113         return (isWindow() || !parentWidget()) ?  p : parentWidget()->mapToGlobal(p);
1114
1115     } else if ((d->data.window_flags & Qt::Window) && internalWinId()) { //toplevel
1116         QPoint tp = geometry().topLeft();
1117         return pos + tp;
1118     }
1119
1120     // Native window case
1121     const TPoint widgetScreenOffset = internalWinId()->PositionRelativeToScreen();
1122     const QPoint globalPos = QPoint(widgetScreenOffset.iX, widgetScreenOffset.iY) + pos;
1123     return globalPos;
1124 }
1125
1126 QPoint QWidget::mapFromGlobal(const QPoint &pos) const
1127 {
1128     Q_D(const QWidget);
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();
1134         return pos - tp;
1135     }
1136
1137     // Native window case
1138     const TPoint widgetScreenOffset = internalWinId()->PositionRelativeToScreen();
1139     const QPoint widgetPos = pos - QPoint(widgetScreenOffset.iX, widgetScreenOffset.iY);
1140     return widgetPos;
1141 }
1142
1143 static Qt::WindowStates effectiveState(Qt::WindowStates state)
1144 {
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;
1152 }
1153
1154 void QWidget::setWindowState(Qt::WindowStates newstate)
1155 {
1156     Q_D(QWidget);
1157
1158     Qt::WindowStates oldstate = windowState();
1159
1160     const TBool isFullscreen = newstate & Qt::WindowFullScreen;
1161 #ifdef Q_WS_S60
1162     const TBool cbaRequested = windowFlags() & Qt::WindowSoftkeysVisibleHint;
1163     const TBool cbaVisible = CEikButtonGroupContainer::Current() ? true : false;
1164     const TBool softkeyVisibilityChange = isFullscreen && (cbaRequested != cbaVisible);
1165
1166     if (oldstate == newstate && !softkeyVisibilityChange)
1167         return;
1168 #endif // Q_WS_S60
1169
1170     if (isWindow()) {
1171         createWinId();
1172         Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1173
1174         const bool wasResized = testAttribute(Qt::WA_Resized);
1175         const bool wasMoved = testAttribute(Qt::WA_Moved);
1176
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);
1184         }
1185
1186 #ifdef Q_WS_S60
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();
1193         if (parentWindow) {
1194             while (parentWindow->parentWidget())
1195                 parentWindow = parentWindow->parentWidget();
1196             comparisonState = parentWindow->windowState();
1197         } else {
1198             parentWindow = this;
1199         }
1200
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));
1205
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
1210             && parentWidget()
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;
1216                     break;
1217                 }
1218             }
1219         }
1220         S60->setStatusPaneAndButtonGroupVisibility(decorationsVisible, buttonGroupVisibility);
1221
1222 #endif // Q_WS_S60
1223
1224         // Ensure the initial size is valid, since we store it as normalGeometry below.
1225         if (!wasResized && !isVisible())
1226             adjustSize();
1227
1228         QTLWExtra *top = d->topData();
1229         QRect normalGeometry = (top->normalGeometry.width() < 0) ? geometry() : top->normalGeometry;
1230
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());
1239         } else {
1240 #ifdef Q_WS_S60
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));
1248             }
1249 #endif
1250             setGeometry(normalGeometry);
1251         }
1252
1253         //restore normal geometry
1254         top->normalGeometry = normalGeometry;
1255
1256         // FixMe QTBUG-8977
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);
1263         }
1264     }
1265
1266     data->window_state = newstate;
1267
1268     if (newstate & Qt::WindowActive)
1269         activateWindow();
1270
1271     QWindowStateChangeEvent e(oldstate);
1272     QApplication::sendEvent(this, &e);
1273 }
1274
1275
1276 void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
1277 {
1278     Q_D(QWidget);
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)) {
1285
1286 #ifndef QT_NO_IM
1287         if (d->ic) {
1288             delete d->ic;
1289         } else {
1290             QInputContext *ic = QApplicationPrivate::inputContext;
1291             if (ic) {
1292                 ic->widgetDestroyed(this);
1293             }
1294         }
1295 #endif
1296
1297         if (QWidgetPrivate::mouseGrabber == this)
1298             releaseMouse();
1299         if (QWidgetPrivate::keyboardGrabber == this)
1300             releaseKeyboard();
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,
1307                                                     destroySubWindows);
1308         }
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);
1313         }
1314     }
1315
1316     QT_TRY {
1317         d->setWinId(0);
1318     } QT_CATCH (const std::bad_alloc &) {
1319         // swallow - destructors must not throw
1320     }
1321
1322     if (destroyWindow) {
1323         delete id;
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"
1327         if (qApp)
1328             S60->wsSession().Flush();
1329     }
1330 }
1331
1332 QWidget *QWidget::mouseGrabber()
1333 {
1334     return QWidgetPrivate::mouseGrabber;
1335 }
1336
1337 QWidget *QWidget::keyboardGrabber()
1338 {
1339     return QWidgetPrivate::keyboardGrabber;
1340 }
1341
1342 void QWidget::grabKeyboard()
1343 {
1344     if (!qt_nograb()) {
1345         if (QWidgetPrivate::keyboardGrabber && QWidgetPrivate::keyboardGrabber != this)
1346             QWidgetPrivate::keyboardGrabber->releaseKeyboard();
1347
1348         // ### TODO: Native keyboard grab
1349
1350         QWidgetPrivate::keyboardGrabber = this;
1351     }
1352 }
1353
1354 void QWidget::releaseKeyboard()
1355 {
1356     if (!qt_nograb() && QWidgetPrivate::keyboardGrabber == this) {
1357         // ### TODO: Native keyboard release
1358         QWidgetPrivate::keyboardGrabber = 0;
1359     }
1360 }
1361
1362 void QWidget::grabMouse()
1363 {
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;
1371
1372 #ifndef QT_NO_CURSOR
1373         QApplication::setOverrideCursor(cursor());
1374 #endif
1375     }
1376 }
1377
1378 #ifndef QT_NO_CURSOR
1379 void QWidget::grabMouse(const QCursor &cursor)
1380 {
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;
1388
1389         QApplication::setOverrideCursor(cursor);
1390     }
1391 }
1392 #endif
1393
1394 void QWidget::releaseMouse()
1395 {
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);
1401         }
1402         QWidgetPrivate::mouseGrabber = 0;
1403 #ifndef QT_NO_CURSOR
1404         QApplication::restoreOverrideCursor();
1405 #endif
1406     }
1407 }
1408
1409 void QWidget::activateWindow()
1410 {
1411     Q_D(QWidget);
1412
1413     QWidget *tlw = window();
1414     if (tlw->isVisible()) {
1415         window()->createWinId();
1416         QSymbianControl *id = static_cast<QSymbianControl *>(tlw->internalWinId());
1417         id->setFocusSafely(true);
1418     }
1419 }
1420
1421 #ifndef QT_NO_CURSOR
1422
1423 void QWidgetPrivate::setCursor_sys(const QCursor &cursor)
1424 {
1425     Q_UNUSED(cursor);
1426     Q_Q(QWidget);
1427     qt_symbian_set_cursor(q, false);
1428 }
1429
1430 void QWidgetPrivate::unsetCursor_sys()
1431 {
1432     Q_Q(QWidget);
1433     qt_symbian_set_cursor(q, false);
1434 }
1435 #endif
1436
1437 QT_END_NAMESPACE