Merge branch 4.7 into qt-4.8-from-4.7
[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 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
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 <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.
62 Q_DECLARE_METATYPE(WId)
63
64 // Workaround for the fact that S60 SDKs 3.x do not contain the akntoolbar.h
65 // header, even though the documentation says that it should be there, and indeed
66 // it is present in the library.
67 class CAknToolbar : public CAknControl,
68                     public MCoeControlObserver,
69                     public MCoeControlBackground,
70                     public MEikCommandObserver,
71                     public MAknFadedComponent
72 {
73 public:
74     IMPORT_C void SetToolbarVisibility(const TBool visible);
75 };
76
77 QT_BEGIN_NAMESPACE
78
79 extern bool qt_nograb();
80
81 QWidget *QWidgetPrivate::mouseGrabber = 0;
82 QWidget *QWidgetPrivate::keyboardGrabber = 0;
83 CEikButtonGroupContainer *QS60Data::cba = 0;
84
85 int qt_symbian_create_desktop_on_screen = -1;
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     bool checkExtra = true;
237     if (q->isWindow() && (data.window_state & (Qt::WindowFullScreen | Qt::WindowMaximized))) {
238         // Do not allow fullscreen/maximized windows to expand beyond client rect
239         TRect r = S60->clientRect();
240         w = qMin(w, r.Width());
241         h = qMin(h, r.Height());
242
243         if (w == r.Width() && h == r.Height())
244             checkExtra = false;
245     }
246
247     // Lose maximized status if deliberate resize
248     if (w != oldSize.width() || h != oldSize.height())
249         data.window_state &= ~Qt::WindowMaximized;
250
251     if (checkExtra && extra) {  // any size restrictions?
252         w = qMin(w,extra->maxw);
253         h = qMin(h,extra->maxh);
254         w = qMax(w,extra->minw);
255         h = qMax(h,extra->minh);
256     }
257
258     if (q->isWindow())
259         topData()->normalGeometry = QRect(0, 0, -1, -1);
260     else {
261         uint s = data.window_state;
262         s &= ~(Qt::WindowMaximized | Qt::WindowFullScreen);
263         data.window_state = s;
264     }
265
266     bool isResize = w != oldSize.width() || h != oldSize.height();
267     if (!isMove && !isResize)
268         return;
269
270     if (q->isWindow()) {
271         if (w == 0 || h == 0) {
272             q->setAttribute(Qt::WA_OutsideWSRange, true);
273             if (q->isVisible() && q->testAttribute(Qt::WA_Mapped))
274                 hide_sys();
275             data.crect = QRect(x, y, w, h);
276             data.window_state &= ~Qt::WindowFullScreen;
277         } else if (q->isVisible() && q->testAttribute(Qt::WA_OutsideWSRange)) {
278             q->setAttribute(Qt::WA_OutsideWSRange, false);
279
280             // put the window in its place and show it
281             q->internalWinId()->SetRect(TRect(TPoint(x, y), TSize(w, h)));
282             data.crect.setRect(x, y, w, h);
283             show_sys();
284         } else {
285             QRect r = QRect(x, y, w, h);
286             data.crect = r;
287             q->internalWinId()->SetRect(TRect(TPoint(x, y), TSize(w, h)));
288             topData()->normalGeometry = data.crect;
289         }
290         QSymbianControl *window = static_cast<QSymbianControl *>(q->internalWinId());
291         window->ensureFixNativeOrientation();
292     } else {
293         data.crect.setRect(x, y, w, h);
294
295         QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData();
296         const bool inTopLevelResize = tlwExtra ? tlwExtra->inTopLevelResize : false;
297
298         if (q->isVisible() && (!inTopLevelResize || q->internalWinId())) {
299             // Top-level resize optimization does not work for native child widgets;
300             // disable it for this particular widget.
301             if (inTopLevelResize)
302                 tlwExtra->inTopLevelResize = false;
303             if (!isResize && maybeBackingStore())
304                 moveRect(QRect(oldPos, oldSize), x - oldPos.x(), y - oldPos.y());
305             else
306                 invalidateBuffer_resizeHelper(oldPos, oldSize);
307
308             if (inTopLevelResize)
309                 tlwExtra->inTopLevelResize = true;
310         }
311         if (q->testAttribute(Qt::WA_WState_Created))
312             setWSGeometry();
313     }
314
315     if (q->isVisible()) {
316         if (isMove && q->pos() != oldPos) {
317             QMoveEvent e(q->pos(), oldPos);
318             QApplication::sendEvent(q, &e);
319         }
320         if (isResize) {
321             bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt();
322             const bool setTopLevelResize = !slowResize && q->isWindow() && extra && extra->topextra
323                                            && !extra->topextra->inTopLevelResize;
324             if (setTopLevelResize)
325                 extra->topextra->inTopLevelResize = true;
326             QResizeEvent e(q->size(), oldSize);
327             QApplication::sendEvent(q, &e);
328             if (!q->testAttribute(Qt::WA_StaticContents) && q->internalWinId())
329                 q->internalWinId()->DrawDeferred();
330             if (setTopLevelResize)
331                 extra->topextra->inTopLevelResize = false;
332         }
333     } else {
334         if (isMove && q->pos() != oldPos)
335             q->setAttribute(Qt::WA_PendingMoveEvent, true);
336         if (isResize)
337             q->setAttribute(Qt::WA_PendingResizeEvent, true);
338     }
339 }
340
341 void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool destroyOldWindow)
342 {
343     Q_Q(QWidget);
344
345     Qt::WindowType type = q->windowType();
346     Qt::WindowFlags &flags = data.window_flags;
347     QWidget *parentWidget = q->parentWidget();
348
349     bool topLevel = (flags & Qt::Window);
350     bool popup = (type == Qt::Popup);
351     bool dialog = (type == Qt::Dialog
352                    || type == Qt::Sheet
353                    || (flags & Qt::MSWindowsFixedSizeDialogHint));
354     bool desktop = (type == Qt::Desktop);
355     //bool tool = (type == Qt::Tool || type == Qt::Drawer);
356
357     if (popup)
358         flags |= Qt::WindowStaysOnTopHint; // a popup stays on top
359
360     TRect clientRect = S60->clientRect();
361     int sw = clientRect.Width();
362     int sh = clientRect.Height();
363
364     if (desktop) {
365         symbianScreenNumber = qMax(qt_symbian_create_desktop_on_screen, 0);
366         TSize screenSize = S60->screenDevice(symbianScreenNumber)->SizeInPixels();
367         data.crect.setRect(0, 0, screenSize.iWidth, screenSize.iHeight);
368         q->setAttribute(Qt::WA_DontShowOnScreen);
369     } else if (topLevel && !q->testAttribute(Qt::WA_Resized)){
370         int width = sw;
371         int height = sh;
372         if (symbianScreenNumber > 0) {
373             TSize screenSize = S60->screenDevice(symbianScreenNumber)->SizeInPixels();
374             width = screenSize.iWidth;
375             height = screenSize.iHeight;
376         }
377         if (extra) {
378             width = qMax(qMin(width, extra->maxw), extra->minw);
379             height = qMax(qMin(height, extra->maxh), extra->minh);
380         }
381         data.crect.setSize(QSize(width, height));
382     }
383
384     CCoeControl *const destroyw = destroyOldWindow ? data.winid : 0;
385
386     createExtra();
387     if (window) {
388         setWinId(window);
389         TRect tr = window->Rect();
390         data.crect.setRect(tr.iTl.iX, tr.iTl.iY, tr.Width(), tr.Height());
391
392     } else if (topLevel) {
393         if (!q->testAttribute(Qt::WA_Moved) && !q->testAttribute(Qt::WA_DontShowOnScreen))
394             data.crect.moveTopLeft(QPoint(clientRect.iTl.iX, clientRect.iTl.iY));
395
396         QScopedPointer<QSymbianControl> control( new QSymbianControl(q) );
397         Q_CHECK_PTR(control);
398
399         QT_TRAP_THROWING(control->ConstructL(true, desktop));
400         control->SetMopParent(static_cast<CEikAppUi*>(S60->appUi()));
401
402         // Symbian windows are always created in an inactive state
403         // We perform this assignment for the case where the window is being re-created
404         // as a result of a call to setParent_sys, on either this widget or one of its
405         // ancestors.
406         extra->activated = 0;
407
408         if (!desktop) {
409             TInt stackingFlags;
410             if ((q->windowType() & Qt::Popup) == Qt::Popup) {
411                 stackingFlags = ECoeStackFlagRefusesAllKeys | ECoeStackFlagRefusesFocus;
412             } else {
413                 stackingFlags = ECoeStackFlagStandard;
414             }
415             control->MakeVisible(false);
416             QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control.data(), ECoeStackPriorityDefault, stackingFlags));
417             // Avoid keyboard focus to a hidden window.
418             control->setFocusSafely(false);
419
420             RDrawableWindow *const drawableWindow = control->DrawableWindow();
421             // Request mouse move events.
422             drawableWindow->PointerFilter(EPointerFilterEnterExit
423                 | EPointerFilterMove | EPointerFilterDrag, 0);
424             drawableWindow->EnableVisibilityChangeEvents();
425
426         }
427
428         q->setAttribute(Qt::WA_WState_Created);
429
430         int x, y, w, h;
431         data.crect.getRect(&x, &y, &w, &h);
432         control->SetRect(TRect(TPoint(x, y), TSize(w, h)));
433
434         // We wait until the control is fully constructed before calling setWinId, because
435         // this generates a WinIdChanged event.
436         setWinId(control.take());
437
438         if (!desktop)
439             s60UpdateIsOpaque(); // must be called after setWinId()
440
441     } else if (q->testAttribute(Qt::WA_NativeWindow) || paintOnScreen()) { // create native child widget
442
443         QScopedPointer<QSymbianControl> control( new QSymbianControl(q) );
444         Q_CHECK_PTR(control);
445
446         QT_TRAP_THROWING(control->ConstructL(!parentWidget));
447
448         // Symbian windows are always created in an inactive state
449         // We perform this assignment for the case where the window is being re-created
450         // as a result of a call to setParent_sys, on either this widget or one of its
451         // ancestors.
452         extra->activated = 0;
453
454         TInt stackingFlags;
455         if ((q->windowType() & Qt::Popup) == Qt::Popup) {
456             stackingFlags = ECoeStackFlagRefusesAllKeys | ECoeStackFlagRefusesFocus;
457         } else {
458             stackingFlags = ECoeStackFlagStandard;
459         }
460         control->MakeVisible(false);
461         QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control.data(), ECoeStackPriorityDefault, stackingFlags));
462         // Avoid keyboard focus to a hidden window.
463         control->setFocusSafely(false);
464
465         q->setAttribute(Qt::WA_WState_Created);
466         int x, y, w, h;
467         data.crect.getRect(&x, &y, &w, &h);
468         control->SetRect(TRect(TPoint(x, y), TSize(w, h)));
469
470         RDrawableWindow *const drawableWindow = control->DrawableWindow();
471         // Request mouse move events.
472         drawableWindow->PointerFilter(EPointerFilterEnterExit
473             | EPointerFilterMove | EPointerFilterDrag, 0);
474         drawableWindow->EnableVisibilityChangeEvents();
475
476         if (q->isVisible() && q->testAttribute(Qt::WA_Mapped)) {
477             activateSymbianWindow(control.data());
478             control->MakeVisible(true);
479         }
480
481         // We wait until the control is fully constructed before calling setWinId, because
482         // this generates a WinIdChanged event.
483         setWinId(control.take());
484     }
485
486     if (destroyw) {
487         destroyw->ControlEnv()->AppUi()->RemoveFromStack(destroyw);
488
489         // Delay deletion of the control in case this function is called in the
490         // context of a CONE event handler such as
491         // CCoeControl::ProcessPointerEventL
492         widCleanupList << destroyw;
493         QMetaObject::invokeMethod(q, "_q_cleanupWinIds", Qt::QueuedConnection);
494     }
495
496     if (q->testAttribute(Qt::WA_AcceptTouchEvents))
497         registerTouchWindow();
498 }
499
500
501 void QWidgetPrivate::show_sys()
502 {
503     Q_Q(QWidget);
504
505     if (q->testAttribute(Qt::WA_OutsideWSRange))
506         return;
507
508     Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
509
510     q->setAttribute(Qt::WA_Mapped);
511
512     if (q->testAttribute(Qt::WA_DontShowOnScreen)) {
513         invalidateBuffer(q->rect());
514         return;
515     }
516
517     if (q->internalWinId()) {
518         if (!extra->activated)
519              activateSymbianWindow();
520
521          QSymbianControl *id = static_cast<QSymbianControl *>(q->internalWinId());
522          const bool isFullscreen = q->windowState() & Qt::WindowFullScreen;
523          const TBool cbaRequested = q->windowFlags() & Qt::WindowSoftkeysVisibleHint;
524
525 #ifdef Q_WS_S60
526         // Lazily initialize the S60 screen furniture when the first window is shown.
527         if (q->isWindow() && !QApplication::testAttribute(Qt::AA_S60DontConstructApplicationPanes)
528                 && !S60->buttonGroupContainer() && !S60->statusPane()) {
529
530             if (!q->testAttribute(Qt::WA_DontShowOnScreen)) {
531
532                 // Create the status pane and CBA here
533                 CEikAppUi *ui = static_cast<CEikAppUi *>(S60->appUi());
534                 MEikAppUiFactory *factory = CEikonEnv::Static()->AppUiFactory();
535
536                 QT_TRAP_THROWING(
537                     factory->CreateResourceIndependentFurnitureL(ui);
538
539                     CEikButtonGroupContainer *cba = CEikButtonGroupContainer::NewL(CEikButtonGroupContainer::ECba,
540                         CEikButtonGroupContainer::EHorizontal,ui,R_AVKON_SOFTKEYS_EMPTY_WITH_IDS);
541                     if (isFullscreen && !cbaRequested)
542                         cba->MakeVisible(false);
543
544                     CEikButtonGroupContainer *oldCba = factory->SwapButtonGroup(cba);
545                     Q_ASSERT(!oldCba);
546                     S60->setButtonGroupContainer(cba);
547
548                     // If the creation of the first widget is delayed, for example by doing it
549                     // inside the event loop, S60 somehow "forgets" to set the visibility of the
550                     // toolbar (the three middle softkeys) when you flip the phone over, so we
551                     // need to do it ourselves to avoid a "hole" in the application, even though
552                     // Qt itself does not use the toolbar directly..
553                     CAknAppUi *appui = dynamic_cast<CAknAppUi *>(CEikonEnv::Static()->AppUi());
554                     if (appui) {
555                         CAknToolbar *toolbar = appui->PopupToolbar();
556                         if (toolbar && !toolbar->IsVisible())
557                             toolbar->SetToolbarVisibility(ETrue);
558                     }
559
560                     CEikMenuBar *menuBar = new(ELeave) CEikMenuBar;
561                     menuBar->ConstructL(ui, 0, R_AVKON_MENUPANE_EMPTY);
562                     menuBar->SetMenuType(CEikMenuBar::EMenuOptions);
563                     S60->appUi()->AddToStackL(menuBar,ECoeStackPriorityMenu,ECoeStackFlagRefusesFocus);
564
565                     CEikMenuBar *oldMenu = factory->SwapMenuBar(menuBar);
566                     Q_ASSERT(!oldMenu);
567                 )
568
569                 if (S60->statusPane()) {
570                     // Use QDesktopWidget as the status pane observer to proxy for the AppUi.
571                     // Can't use AppUi directly because it privately inherits from MEikStatusPaneObserver.
572                     QSymbianControl *desktopControl = static_cast<QSymbianControl *>(QApplication::desktop()->winId());
573                     S60->statusPane()->SetObserver(desktopControl);
574                     if (isFullscreen) {
575                         const bool cbaVisible = S60->buttonGroupContainer() && S60->buttonGroupContainer()->IsVisible();
576                         S60->setStatusPaneAndButtonGroupVisibility(false, cbaVisible);
577                         if (cbaVisible) {
578                             // Fix window dimensions as without screen furniture they will have
579                             // defaulted to full screen dimensions initially.
580                             id->handleClientAreaChange();
581                         }
582                     }
583                 }
584             }
585         }
586 #endif
587
588         // Fill client area if maximized OR
589         // Put window below status pane unless the window has an explicit position.
590         if (!isFullscreen) {
591             // Use QS60Data::clientRect to take into account that native keyboard
592             // might affect ClientRect() return value.
593             if (q->windowState() & Qt::WindowMaximized) {
594                 TRect r = S60->clientRect();
595                 id->SetExtent(r.iTl, r.Size());
596             } else if (!q->testAttribute(Qt::WA_Moved) && q->windowType() != Qt::Dialog) {
597                 id->SetPosition(S60->clientRect().iTl);
598             }
599         }
600
601         id->MakeVisible(true);
602
603         if(q->isWindow()&&!q->testAttribute(Qt::WA_ShowWithoutActivating))
604             id->setFocusSafely(true);
605     }
606
607     invalidateBuffer(q->rect());
608 }
609
610 void QWidgetPrivate::activateSymbianWindow(WId wid)
611 {
612     Q_Q(QWidget);
613
614     Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
615     Q_ASSERT(q->testAttribute(Qt::WA_Mapped));
616     Q_ASSERT(!extra->activated);
617
618     if(!wid)
619         wid = q->internalWinId();
620
621     Q_ASSERT(wid);
622
623     QT_TRAP_THROWING(wid->ActivateL());
624     extra->activated = 1;
625 }
626
627 void QWidgetPrivate::hide_sys()
628 {
629     Q_Q(QWidget);
630
631     Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
632     deactivateWidgetCleanup();
633     QSymbianControl *id = static_cast<QSymbianControl *>(q->internalWinId());
634
635     if (id) {
636         //Incorrect optimization - for popup windows, Qt's focus is moved before
637         //hide_sys is called, resulting in the popup window keeping its elevated
638         //position in the CONE control stack.
639         //This can result in keyboard focus being in an invisible widget in some
640         //conditions - e.g. QTBUG-4733
641         //if(id->IsFocused()) // Avoid unnecessary calls to FocusChanged()
642             id->setFocusSafely(false);
643         id->MakeVisible(false);
644         if (QWidgetBackingStore *bs = maybeBackingStore())
645             bs->releaseBuffer();
646     } else {
647         invalidateBuffer(q->rect());
648     }
649
650     q->setAttribute(Qt::WA_Mapped, false);
651 }
652
653 void QWidgetPrivate::setFocus_sys()
654 {
655     Q_Q(QWidget);
656     if (q->testAttribute(Qt::WA_WState_Created) && q->window()->windowType() != Qt::Popup)
657         if (!q->effectiveWinId()->IsFocused()) // Avoid unnecessry calls to FocusChanged()
658             static_cast<QSymbianControl *>(q->effectiveWinId())->setFocusSafely(true);
659 }
660
661 void QWidgetPrivate::raise_sys()
662 {
663     Q_Q(QWidget);
664
665     Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
666     if (q->internalWinId()) {
667         q->internalWinId()->DrawableWindow()->SetOrdinalPosition(0);
668
669         // If toplevel widget, raise app to foreground
670         if (q->isWindow())
671             S60->wsSession().SetWindowGroupOrdinalPosition(S60->windowGroup(q).Identifier(), 0);
672     }
673 }
674
675 void QWidgetPrivate::lower_sys()
676 {
677     Q_Q(QWidget);
678
679     Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
680     if (q->internalWinId()) {
681         // If toplevel widget, lower app to background
682         if (q->isWindow())
683             S60->wsSession().SetWindowGroupOrdinalPosition(S60->windowGroup(q).Identifier(), -1);
684         else
685             q->internalWinId()->DrawableWindow()->SetOrdinalPosition(-1);
686     }
687
688     if (!q->isWindow())
689         invalidateBuffer(q->rect());
690 }
691
692 void QWidgetPrivate::setModal_sys()
693 {
694
695 }
696
697 void QWidgetPrivate::stackUnder_sys(QWidget* w)
698 {
699     Q_Q(QWidget);
700     Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
701
702     if (q->internalWinId() && w->internalWinId()) {
703         RDrawableWindow *const thisWindow = q->internalWinId()->DrawableWindow();
704         RDrawableWindow *const otherWindow = w->internalWinId()->DrawableWindow();
705         thisWindow->SetOrdinalPosition(otherWindow->OrdinalPosition() + 1);
706     }
707
708     if (!q->isWindow() || !w->internalWinId())
709         invalidateBuffer(q->rect());
710 }
711
712 void QWidgetPrivate::reparentChildren()
713 {
714     Q_Q(QWidget);
715
716     QObjectList chlist = q->children();
717     for (int i = 0; i < chlist.size(); ++i) { // reparent children
718         QObject *obj = chlist.at(i);
719         if (obj->isWidgetType()) {
720             QWidget *w = (QWidget *)obj;
721             if (!w->testAttribute(Qt::WA_WState_Created))
722                 continue;
723             if (!w->isWindow()) {
724                 w->d_func()->invalidateBuffer(w->rect());
725                 WId parent = q->effectiveWinId();
726                 WId child = w->effectiveWinId();
727                 if (parent != child) {
728                     // Child widget is native.  Because Symbian windows cannot be
729                     // re-parented, we must re-create the window.
730                     const WId window = 0;
731                     const bool initializeWindow = false;
732                     const bool destroyOldWindow = true;
733                     w->d_func()->create_sys(window, initializeWindow, destroyOldWindow);
734                 }
735                 // ### TODO: We probably also need to update the component array here
736                 w->d_func()->reparentChildren();
737             } else {
738                 bool showIt = w->isVisible();
739                 QPoint old_pos = w->pos();
740                 w->setParent(q, w->windowFlags());
741                 w->move(old_pos);
742                 if (showIt)
743                     w->show();
744             }
745         }
746     }
747 }
748
749 void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
750 {
751     Q_Q(QWidget);
752
753     if (parent && parent->windowType() == Qt::Desktop) {
754         symbianScreenNumber = qt_widget_private(parent)->symbianScreenNumber;
755         parent = 0;
756     }
757
758     bool wasCreated = q->testAttribute(Qt::WA_WState_Created);
759
760     if (q->isVisible() && q->parentWidget() && parent != q->parentWidget())
761         q->parentWidget()->d_func()->invalidateBuffer(q->geometry());
762
763     if (q->testAttribute(Qt::WA_DropSiteRegistered))
764         q->setAttribute(Qt::WA_DropSiteRegistered, false);
765
766     QSymbianControl *old_winid = static_cast<QSymbianControl *>(wasCreated ? data.winid : 0);
767     if ((q->windowType() == Qt::Desktop))
768         old_winid = 0;
769
770     // old_winid may not have received a 'not visible' visibility
771     // changed event before being destroyed; make sure that it is
772     // removed from the backing store's list of visible windows.
773     if (old_winid)
774         S60->controlVisibilityChanged(old_winid, false);
775
776     setWinId(0);
777
778     // hide and reparent our own window away. Otherwise we might get
779     // destroyed when emitting the child remove event below. See QWorkspace.
780     if (wasCreated && old_winid) {
781         old_winid->MakeVisible(false);
782         if (old_winid->IsFocused()) // Avoid unnecessary calls to FocusChanged()
783             old_winid->setFocusSafely(false);
784         old_winid->SetParent(0);
785     }
786
787     QObjectPrivate::setParent_helper(parent);
788     bool explicitlyHidden = q->testAttribute(Qt::WA_WState_Hidden) && q->testAttribute(Qt::WA_WState_ExplicitShowHide);
789
790     data.window_flags = f;
791     data.fstrut_dirty = true;
792     q->setAttribute(Qt::WA_WState_Created, false);
793     q->setAttribute(Qt::WA_WState_Visible, false);
794     q->setAttribute(Qt::WA_WState_Hidden, false);
795     adjustFlags(data.window_flags, q);
796     // keep compatibility with previous versions, we need to preserve the created state
797     // (but we recreate the winId for the widget being reparented, again for compatibility)
798     if (wasCreated || (!q->isWindow() && parent && parent->testAttribute(Qt::WA_WState_Created)))
799         createWinId();
800     if (q->isWindow() || (!parent || parent->isVisible()) || explicitlyHidden)
801         q->setAttribute(Qt::WA_WState_Hidden);
802     q->setAttribute(Qt::WA_WState_ExplicitShowHide, explicitlyHidden);
803
804     if (wasCreated)
805         reparentChildren();
806
807     if (old_winid) {
808         CBase::Delete(old_winid);
809     }
810
811     if (q->testAttribute(Qt::WA_AcceptDrops)
812         || (!q->isWindow() && q->parentWidget() && q->parentWidget()->testAttribute(Qt::WA_DropSiteRegistered)))
813         q->setAttribute(Qt::WA_DropSiteRegistered, true);
814
815     invalidateBuffer(q->rect());
816 }
817
818 void QWidgetPrivate::setConstraints_sys()
819 {
820
821 }
822
823
824 void QWidgetPrivate::s60UpdateIsOpaque()
825 {
826     Q_Q(QWidget);
827
828     if (!q->testAttribute(Qt::WA_WState_Created))
829         return;
830
831     const bool writeAlpha = extraData()->nativePaintMode == QWExtra::BlitWriteAlpha;
832     if (!q->testAttribute(Qt::WA_TranslucentBackground) && !writeAlpha)
833         return;
834     const bool requireAlphaChannel = !isOpaque || writeAlpha;
835
836     createTLExtra();
837
838     RWindow *const window = static_cast<RWindow *>(q->effectiveWinId()->DrawableWindow());
839
840 #ifdef Q_SYMBIAN_SEMITRANSPARENT_BG_SURFACE
841     if (QApplicationPrivate::instance()->useTranslucentEGLSurfaces
842             && !extra->topextra->forcedToRaster) {
843         window->SetSurfaceTransparency(!isOpaque);
844         extra->topextra->nativeWindowTransparencyEnabled = !isOpaque;
845         return;
846     }
847 #endif
848     if (requireAlphaChannel) {
849         const TDisplayMode displayMode = static_cast<TDisplayMode>(window->SetRequiredDisplayMode(EColor16MA));
850         if (window->SetTransparencyAlphaChannel() == KErrNone) {
851             window->SetBackgroundColor(TRgb(255, 255, 255, 0));
852             extra->topextra->nativeWindowTransparencyEnabled = 1;
853             if (extra->topextra->backingStore.data() && (
854                     QApplicationPrivate::graphics_system_name == QLatin1String("openvg")
855                     || QApplicationPrivate::graphics_system_name == QLatin1String("opengl"))) {
856                 // Semi-transparent EGL surfaces aren't supported. We need to
857                 // recreate backing store to get translucent surface (raster surface).
858                 extra->topextra->backingStore.create(q);
859                 extra->topextra->backingStore.registerWidget(q);
860                 // FixNativeOrientation() will not work without an EGL surface.
861                 q->setAttribute(Qt::WA_SymbianNoSystemRotation, false);
862             }
863         }
864     } else if (extra->topextra->nativeWindowTransparencyEnabled) {
865         window->SetTransparentRegion(TRegionFix<1>());
866         extra->topextra->nativeWindowTransparencyEnabled = 0;
867     }
868 }
869
870 void QWidgetPrivate::setWindowIcon_sys(bool forceReset)
871 {
872 #ifdef Q_WS_S60
873     Q_Q(QWidget);
874
875     if (!q->testAttribute(Qt::WA_WState_Created) || !q->isWindow() )
876         return;
877
878     QTLWExtra* topData = this->topData();
879     if (topData->iconPixmap && !forceReset)
880         // already been set
881         return;
882
883     TRect cPaneRect;
884     TBool found = AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::EContextPane, cPaneRect );
885     CAknContextPane* contextPane = S60->contextPane();
886     if (found && contextPane) { // We have context pane with valid metrics
887         QIcon icon = q->windowIcon();
888         if (!icon.isNull()) {
889             // Valid icon -> set it as an context pane picture
890             QSize size = icon.actualSize(QSize(cPaneRect.Size().iWidth, cPaneRect.Size().iHeight));
891             QPixmap pm = icon.pixmap(size);
892             QBitmap mask = pm.mask();
893             if (mask.isNull()) {
894                 mask = QBitmap(pm.size());
895                 mask.fill(Qt::color1);
896             }
897
898             CFbsBitmap* nBitmap = pm.toSymbianCFbsBitmap();
899             CFbsBitmap* nMask = mask.toSymbianCFbsBitmap();
900             contextPane->SetPicture(nBitmap,nMask);
901         } else {
902             // Icon set to null -> set context pane picture to default
903             QT_TRAP_THROWING(contextPane->SetPictureToDefaultL());
904         }
905     } else {
906         // Context pane does not exist, try setting small icon to title pane
907         TRect titlePaneRect;
908         TBool found = AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::ETitlePane, titlePaneRect );
909         CAknTitlePane* titlePane = S60->titlePane();
910         if (found && titlePane) { // We have title pane with valid metrics
911             // The API to get title_pane graphics size is not public -> assume square space based
912             // on titlebar font height. CAknBitmap would be optimum, wihtout setting the size, since
913             // then title pane would automatically scale the bitmap. Unfortunately it is not public API
914             // Also this function is leaving, although it is not named as such.
915             const CFont * font;
916             QT_TRAP_THROWING(font = AknLayoutUtils::FontFromId(EAknLogicalFontTitleFont));
917             TSize iconSize(font->HeightInPixels(), font->HeightInPixels());
918
919             QIcon icon = q->windowIcon();
920             if (!icon.isNull()) {
921                 // Valid icon -> set it as an title pane small picture
922                 QSize size = icon.actualSize(QSize(iconSize.iWidth, iconSize.iHeight));
923                 QPixmap pm = icon.pixmap(size);
924                 QBitmap mask = pm.mask();
925                 if (mask.isNull()) {
926                     mask = QBitmap(pm.size());
927                     mask.fill(Qt::color1);
928                 }
929
930                 CFbsBitmap* nBitmap = pm.toSymbianCFbsBitmap();
931                 CFbsBitmap* nMask = mask.toSymbianCFbsBitmap();
932                 titlePane->SetSmallPicture( nBitmap, nMask, ETrue );
933             } else {
934                 // Icon set to null -> set context pane picture to default
935                 titlePane->SetSmallPicture( NULL, NULL, EFalse );
936             }
937         }
938     }
939
940 #else
941         Q_UNUSED(forceReset)
942 #endif
943 }
944
945 void QWidgetPrivate::setWindowTitle_sys(const QString &caption)
946 {
947 #ifdef Q_WS_S60
948     Q_Q(QWidget);
949     if (q->isWindow()) {
950         Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
951         CAknTitlePane* titlePane = S60->titlePane();
952         if (titlePane) {
953             if (caption.isEmpty()) {
954                 QT_TRAP_THROWING(titlePane->SetTextToDefaultL());
955             } else {
956                 QT_TRAP_THROWING(titlePane->SetTextL(qt_QString2TPtrC(caption)));
957             }
958         }
959     }
960 #else
961     Q_UNUSED(caption)
962 #endif
963 }
964
965 void QWidgetPrivate::setWindowIconText_sys(const QString & /*iconText */)
966 {
967
968 }
969
970 void QWidgetPrivate::scroll_sys(int dx, int dy)
971 {
972     Q_Q(QWidget);
973
974     scrollChildren(dx, dy);
975     if (!paintOnScreen() || !q->internalWinId() || !q->internalWinId()->OwnsWindow()) {
976         scrollRect(q->rect(), dx, dy);
977     } else {
978         Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
979         RDrawableWindow *const window = q->internalWinId()->DrawableWindow();
980         window->Scroll(TPoint(dx, dy));
981     }
982 }
983
984 void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r)
985 {
986     Q_Q(QWidget);
987
988     if (!paintOnScreen() || !q->internalWinId() || !q->internalWinId()->OwnsWindow()) {
989         scrollRect(r, dx, dy);
990     } else {
991         Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
992         RDrawableWindow *const window = q->internalWinId()->DrawableWindow();
993         window->Scroll(TPoint(dx, dy), qt_QRect2TRect(r));
994     }
995 }
996
997 /*!
998     For this function to work in the emulator, you must add:
999        TRANSPARENCY
1000     To a line in the wsini.ini file.
1001 */
1002 void QWidgetPrivate::setWindowOpacity_sys(qreal)
1003 {
1004     // ### TODO: Implement uniform window transparency
1005 }
1006
1007 void QWidgetPrivate::updateFrameStrut()
1008 {
1009
1010 }
1011
1012 void QWidgetPrivate::updateSystemBackground()
1013 {
1014
1015 }
1016
1017 void QWidgetPrivate::registerDropSite(bool /* on */)
1018 {
1019
1020 }
1021
1022 void QWidgetPrivate::createTLSysExtra()
1023 {
1024     extra->topextra->inExpose = 0;
1025     extra->topextra->nativeWindowTransparencyEnabled = 0;
1026     extra->topextra->forcedToRaster = 0;
1027 }
1028
1029 void QWidgetPrivate::deleteTLSysExtra()
1030 {
1031     extra->topextra->backingStore.destroy();
1032 }
1033
1034 void QWidgetPrivate::createSysExtra()
1035 {
1036     extra->activated = 0;
1037     extra->nativePaintMode = QWExtra::Default;
1038     extra->receiveNativePaintEvents = 0;
1039 }
1040
1041 void QWidgetPrivate::deleteSysExtra()
1042 {
1043     // this should only be non-zero if destroy() has not run due to constructor fail
1044     if (data.winid) {
1045         data.winid->ControlEnv()->AppUi()->RemoveFromStack(data.winid);
1046         delete data.winid;
1047         data.winid = 0;
1048     }
1049 }
1050
1051 QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys()
1052 {
1053     return new QS60WindowSurface(q_func());
1054 }
1055
1056 void QWidgetPrivate::setMask_sys(const QRegion& /* region */)
1057 {
1058
1059 }
1060
1061 void QWidgetPrivate::registerTouchWindow()
1062 {
1063 #ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
1064     Q_Q(QWidget);
1065     if (q->testAttribute(Qt::WA_WState_Created) && q->windowType() != Qt::Desktop) {
1066         RWindow *rwindow = static_cast<RWindow *>(q->effectiveWinId()->DrawableWindow());
1067         QSymbianControl *window = static_cast<QSymbianControl *>(q->effectiveWinId());
1068         //Enabling advanced pointer events for controls that already have active windows causes a panic.
1069         if (!window->isControlActive())
1070             rwindow->EnableAdvancedPointers();
1071     }
1072 #endif
1073 }
1074
1075 int QWidget::metric(PaintDeviceMetric m) const
1076 {
1077     Q_D(const QWidget);
1078     int val;
1079     if (m == PdmWidth) {
1080         val = data->crect.width();
1081     } else if (m == PdmHeight) {
1082         val = data->crect.height();
1083     } else {
1084         CWsScreenDevice *scr = S60->screenDevice(this);
1085         switch(m) {
1086         case PdmDpiX:
1087         case PdmPhysicalDpiX:
1088             if (d->extra && d->extra->customDpiX) {
1089                 val = d->extra->customDpiX;
1090             } else {
1091                 const QWidgetPrivate *p = d;
1092                 while (p->parent) {
1093                     p = static_cast<const QWidget *>(p->parent)->d_func();
1094                     if (p->extra && p->extra->customDpiX) {
1095                         val = p->extra->customDpiX;
1096                         break;
1097                     }
1098                 }
1099                 if (p == d || !(p->extra && p->extra->customDpiX))
1100                     val = S60->defaultDpiX;
1101             }
1102             break;
1103         case PdmDpiY:
1104         case PdmPhysicalDpiY:
1105             if (d->extra && d->extra->customDpiY) {
1106                 val = d->extra->customDpiY;
1107             } else {
1108                 const QWidgetPrivate *p = d;
1109                 while (p->parent) {
1110                     p = static_cast<const QWidget *>(p->parent)->d_func();
1111                     if (p->extra && p->extra->customDpiY) {
1112                         val = p->extra->customDpiY;
1113                         break;
1114                     }
1115                 }
1116                 if (p == d || !(p->extra && p->extra->customDpiY))
1117                     val = S60->defaultDpiY;
1118             }
1119             break;
1120         case PdmWidthMM:
1121         {
1122             TInt twips = scr->HorizontalPixelsToTwips(data->crect.width());
1123             val = (int)(twips * (25.4/KTwipsPerInch));
1124             break;
1125         }
1126         case PdmHeightMM:
1127         {
1128             TInt twips = scr->VerticalPixelsToTwips(data->crect.height());
1129             val = (int)(twips * (25.4/KTwipsPerInch));
1130             break;
1131         }
1132         case PdmNumColors:
1133             val = TDisplayModeUtils::NumDisplayModeColors(scr->DisplayMode());
1134             break;
1135         case PdmDepth:
1136             val = TDisplayModeUtils::NumDisplayModeBitsPerPixel(scr->DisplayMode());
1137             break;
1138         default:
1139             val = 0;
1140             qWarning("QWidget::metric: Invalid metric command");
1141         }
1142     }
1143     return val;
1144 }
1145
1146 QPaintEngine *QWidget::paintEngine() const
1147 {
1148     return 0;
1149 }
1150
1151 QPoint QWidget::mapToGlobal(const QPoint &pos) const
1152 {
1153     Q_D(const QWidget);
1154     if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) {
1155
1156         QPoint p = pos + data->crect.topLeft();
1157         return (isWindow() || !parentWidget()) ?  p : parentWidget()->mapToGlobal(p);
1158
1159     } else if ((d->data.window_flags & Qt::Window) && internalWinId()) { //toplevel
1160         QPoint tp = geometry().topLeft();
1161         return pos + tp;
1162     }
1163
1164     // Native window case
1165     const TPoint widgetScreenOffset = internalWinId()->PositionRelativeToScreen();
1166     const QPoint globalPos = QPoint(widgetScreenOffset.iX, widgetScreenOffset.iY) + pos;
1167     return globalPos;
1168 }
1169
1170 QPoint QWidget::mapFromGlobal(const QPoint &pos) const
1171 {
1172     Q_D(const QWidget);
1173     if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) {
1174         QPoint p = (isWindow() || !parentWidget()) ?  pos : parentWidget()->mapFromGlobal(pos);
1175         return p - data->crect.topLeft();
1176     } else if ((d->data.window_flags & Qt::Window) && internalWinId()) { //toplevel
1177         QPoint tp = geometry().topLeft();
1178         return pos - tp;
1179     }
1180
1181     // Native window case
1182     const TPoint widgetScreenOffset = internalWinId()->PositionRelativeToScreen();
1183     const QPoint widgetPos = pos - QPoint(widgetScreenOffset.iX, widgetScreenOffset.iY);
1184     return widgetPos;
1185 }
1186
1187 static Qt::WindowStates effectiveState(Qt::WindowStates state)
1188 {
1189     if (state & Qt::WindowMinimized)
1190         return Qt::WindowMinimized;
1191     else if (state & Qt::WindowFullScreen)
1192         return Qt::WindowFullScreen;
1193     else if (state & Qt::WindowMaximized)
1194         return Qt::WindowMaximized;
1195     return Qt::WindowNoState;
1196 }
1197
1198 void QWidget::setWindowState(Qt::WindowStates newstate)
1199 {
1200     Q_D(QWidget);
1201
1202     Qt::WindowStates oldstate = windowState();
1203
1204     const TBool isFullscreen = newstate & Qt::WindowFullScreen;
1205 #ifdef Q_WS_S60
1206     const TBool cbaRequested = windowFlags() & Qt::WindowSoftkeysVisibleHint;
1207     const TBool cbaVisible = CEikButtonGroupContainer::Current() ? true : false;
1208     const TBool softkeyVisibilityChange = isFullscreen && (cbaRequested != cbaVisible);
1209
1210     if (oldstate == newstate && !softkeyVisibilityChange)
1211         return;
1212 #endif // Q_WS_S60
1213
1214     if (isWindow()) {
1215         createWinId();
1216         Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1217
1218         const bool wasResized = testAttribute(Qt::WA_Resized);
1219         const bool wasMoved = testAttribute(Qt::WA_Moved);
1220
1221         QSymbianControl *window = static_cast<QSymbianControl *>(effectiveWinId());
1222         if (window && newstate & Qt::WindowMinimized) {
1223             window->setFocusSafely(false);
1224             window->MakeVisible(false);
1225         } else if (window && oldstate & Qt::WindowMinimized) {
1226             window->setFocusSafely(true);
1227             window->MakeVisible(true);
1228         }
1229
1230 #ifdef Q_WS_S60
1231         // The window decoration visibility has to be changed before doing actual window state
1232         // change since in that order the availableGeometry will return directly the right size and
1233         // we will avoid unnecessary redraws
1234         bool decorationsVisible = S60->setRecursiveDecorationsVisibility(this, newstate);
1235 #endif // Q_WS_S60
1236
1237         // Ensure the initial size is valid, since we store it as normalGeometry below.
1238         if (!wasResized && !isVisible())
1239             adjustSize();
1240
1241         QTLWExtra *top = d->topData();
1242         QRect normalGeometry = (top->normalGeometry.width() < 0) ? geometry() : top->normalGeometry;
1243
1244         const bool cbaVisibilityHint = windowFlags() & Qt::WindowSoftkeysVisibleHint;
1245         if (newstate & Qt::WindowFullScreen && !cbaVisibilityHint) {
1246             setAttribute(Qt::WA_OutsideWSRange, false);
1247             if (d->symbianScreenNumber > 0) {
1248                 int w = S60->screenWidthInPixelsForScreen[d->symbianScreenNumber];
1249                 int h = S60->screenHeightInPixelsForScreen[d->symbianScreenNumber];
1250                 if (w <= 0 || h <= 0)
1251                     window->SetExtentToWholeScreen();
1252                 else
1253                     window->SetExtent(TPoint(0, 0), TSize(w, h));
1254             } else {
1255                 window->SetExtentToWholeScreen();
1256             }
1257         } else if (newstate & Qt::WindowMaximized || ((newstate & Qt::WindowFullScreen) && cbaVisibilityHint)) {
1258             setAttribute(Qt::WA_OutsideWSRange, false);
1259             TRect maxExtent = qt_QRect2TRect(qApp->desktop()->availableGeometry(this));
1260             window->SetExtent(maxExtent.iTl, maxExtent.Size());
1261         } else {
1262 #ifdef Q_WS_S60
1263             // With delayed creation of S60 app panes, the normalGeometry calculated above is not
1264             // accurate because it did not consider the status pane. This means that when returning
1265             // normal mode after showing the status pane, the geometry would overlap so we should
1266             // move it if it never had an explicit position.
1267             if (!wasMoved && S60->statusPane() && decorationsVisible) {
1268                 TPoint tl = S60->clientRect().iTl;
1269                 normalGeometry.setTopLeft(QPoint(tl.iX, tl.iY));
1270             }
1271 #endif
1272             setGeometry(normalGeometry);
1273         }
1274
1275         //restore normal geometry
1276         top->normalGeometry = normalGeometry;
1277
1278         // FixMe QTBUG-8977
1279         // In some platforms, WA_Resized and WA_Moved are also not set when application window state is
1280         // anything else than normal. In Symbian we can restore them only for normal window state since
1281         // restoring for other modes, will make fluidlauncher to be launched in wrong size (200x100)
1282         if (effectiveState(newstate) == Qt::WindowNoState) {
1283             setAttribute(Qt::WA_Resized, wasResized);
1284             setAttribute(Qt::WA_Moved, wasMoved);
1285         }
1286     }
1287
1288     data->window_state = newstate;
1289
1290     if (newstate & Qt::WindowActive)
1291         activateWindow();
1292
1293     if (isWindow()) {
1294         // Now that the new state is set, fix the display memory layout, if needed.
1295         QSymbianControl *window = static_cast<QSymbianControl *>(effectiveWinId());
1296         window->ensureFixNativeOrientation();
1297     }
1298
1299     QWindowStateChangeEvent e(oldstate);
1300     QApplication::sendEvent(this, &e);
1301 }
1302
1303
1304 void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
1305 {
1306     Q_D(QWidget);
1307     d->aboutToDestroy();
1308     if (!isWindow() && parentWidget())
1309         parentWidget()->d_func()->invalidateBuffer(geometry());
1310     d->deactivateWidgetCleanup();
1311     QSymbianControl *id = static_cast<QSymbianControl *>(internalWinId());
1312     if (testAttribute(Qt::WA_WState_Created)) {
1313
1314 #ifndef QT_NO_IM
1315         if (d->ic) {
1316             delete d->ic;
1317         } else {
1318             QInputContext *ic = QApplicationPrivate::inputContext;
1319             if (ic) {
1320                 ic->widgetDestroyed(this);
1321             }
1322         }
1323 #endif
1324
1325         if (QWidgetPrivate::mouseGrabber == this)
1326             releaseMouse();
1327         if (QWidgetPrivate::keyboardGrabber == this)
1328             releaseKeyboard();
1329         setAttribute(Qt::WA_WState_Created, false);
1330         QObjectList childList = children();
1331         for (int i = 0; i < childList.size(); ++i) { // destroy all widget children
1332             register QObject *obj = childList.at(i);
1333             if (obj->isWidgetType())
1334                 static_cast<QWidget*>(obj)->destroy(destroySubWindows,
1335                                                     destroySubWindows);
1336         }
1337         if (destroyWindow && !(windowType() == Qt::Desktop) && id) {
1338             if (id->IsFocused()) // Avoid unnecessry calls to FocusChanged()
1339                 id->setFocusSafely(false);
1340             id->ControlEnv()->AppUi()->RemoveFromStack(id);
1341         }
1342     }
1343
1344     QT_TRY {
1345         d->setWinId(0);
1346     } QT_CATCH (const std::bad_alloc &) {
1347         // swallow - destructors must not throw
1348     }
1349
1350     if (destroyWindow) {
1351         delete id;
1352         // At this point the backing store should already be destroyed
1353         // so we flush the command buffer to ensure that the freeing of
1354         // those resources and deleting the window can happen "atomically"
1355         if (qApp)
1356             S60->wsSession().Flush();
1357     }
1358 }
1359
1360 QWidget *QWidget::mouseGrabber()
1361 {
1362     return QWidgetPrivate::mouseGrabber;
1363 }
1364
1365 QWidget *QWidget::keyboardGrabber()
1366 {
1367     return QWidgetPrivate::keyboardGrabber;
1368 }
1369
1370 void QWidget::grabKeyboard()
1371 {
1372     if (!qt_nograb()) {
1373         if (QWidgetPrivate::keyboardGrabber && QWidgetPrivate::keyboardGrabber != this)
1374             QWidgetPrivate::keyboardGrabber->releaseKeyboard();
1375
1376         // ### TODO: Native keyboard grab
1377
1378         QWidgetPrivate::keyboardGrabber = this;
1379     }
1380 }
1381
1382 void QWidget::releaseKeyboard()
1383 {
1384     if (!qt_nograb() && QWidgetPrivate::keyboardGrabber == this) {
1385         // ### TODO: Native keyboard release
1386         QWidgetPrivate::keyboardGrabber = 0;
1387     }
1388 }
1389
1390 void QWidget::grabMouse()
1391 {
1392     if (isVisible() && !qt_nograb()) {
1393         if (QWidgetPrivate::mouseGrabber && QWidgetPrivate::mouseGrabber != this)
1394             QWidgetPrivate::mouseGrabber->releaseMouse();
1395         Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1396         WId id = effectiveWinId();
1397         id->SetPointerCapture(true);
1398         QWidgetPrivate::mouseGrabber = this;
1399
1400 #ifndef QT_NO_CURSOR
1401         QApplication::setOverrideCursor(cursor());
1402 #endif
1403     }
1404 }
1405
1406 #ifndef QT_NO_CURSOR
1407 void QWidget::grabMouse(const QCursor &cursor)
1408 {
1409     if (isVisible() && !qt_nograb()) {
1410         if (QWidgetPrivate::mouseGrabber && QWidgetPrivate::mouseGrabber != this)
1411             QWidgetPrivate::mouseGrabber->releaseMouse();
1412         Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1413         WId id = effectiveWinId();
1414         id->SetPointerCapture(true);
1415         QWidgetPrivate::mouseGrabber = this;
1416
1417         QApplication::setOverrideCursor(cursor);
1418     }
1419 }
1420 #endif
1421
1422 void QWidget::releaseMouse()
1423 {
1424     if (!qt_nograb() && QWidgetPrivate::mouseGrabber == this) {
1425         Q_ASSERT(testAttribute(Qt::WA_WState_Created));
1426         if(!window()->isModal()) {
1427             WId id = effectiveWinId();
1428             id->SetPointerCapture(false);
1429         }
1430         QWidgetPrivate::mouseGrabber = 0;
1431 #ifndef QT_NO_CURSOR
1432         QApplication::restoreOverrideCursor();
1433 #endif
1434     }
1435 }
1436
1437 void QWidget::activateWindow()
1438 {
1439     Q_D(QWidget);
1440
1441     QWidget *tlw = window();
1442     if (tlw->isVisible()) {
1443         window()->createWinId();
1444         QSymbianControl *id = static_cast<QSymbianControl *>(tlw->internalWinId());
1445         if (!id->IsFocused())
1446             id->setFocusSafely(true);
1447     }
1448 }
1449
1450 #ifndef QT_NO_CURSOR
1451
1452 void QWidgetPrivate::setCursor_sys(const QCursor &cursor)
1453 {
1454     Q_UNUSED(cursor);
1455     Q_Q(QWidget);
1456     qt_symbian_set_cursor(q, false);
1457 }
1458
1459 void QWidgetPrivate::unsetCursor_sys()
1460 {
1461     Q_Q(QWidget);
1462     qt_symbian_set_cursor(q, false);
1463 }
1464 #endif
1465
1466 QT_END_NAMESPACE