Show softkeys when opening a dialog that has a fullscreen parent.
[qt:qt.git] / src / gui / kernel / qapplication_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 "qapplication_p.h"
43 #include "qsessionmanager.h"
44 #include "qevent.h"
45 #include "qsymbianevent.h"
46 #include "qeventdispatcher_s60_p.h"
47 #include "qwidget.h"
48 #include "qdesktopwidget.h"
49 #include "private/qbackingstore_p.h"
50 #include "qt_s60_p.h"
51 #include "private/qevent_p.h"
52 #include "qstring.h"
53 #include "qdebug.h"
54 #include "qimage.h"
55 #include "qcombobox.h"
56 #include "private/qkeymapper_p.h"
57 #include "private/qfont_p.h"
58 #ifndef QT_NO_STYLE_S60
59 #include "private/qs60style_p.h"
60 #endif
61 #include "private/qwindowsurface_s60_p.h"
62 #include "qpaintengine.h"
63 #include "private/qmenubar_p.h"
64 #include "private/qsoftkeymanager_p.h"
65 #ifdef QT_GRAPHICSSYSTEM_RUNTIME
66 #include "private/qgraphicssystem_runtime_p.h"
67 #endif
68
69 #include "apgwgnam.h" // For CApaWindowGroupName
70 #include <mdaaudiotoneplayer.h>     // For CMdaAudioToneUtility
71
72 #if defined(Q_OS_SYMBIAN)
73 # include <private/qs60mainapplication_p.h>
74 # include <centralrepository.h>
75 # include "qs60mainappui.h"
76 # include "qinputcontext.h"
77 #endif
78
79 #if defined(Q_WS_S60)
80 # if !defined(QT_NO_IM)
81 #  include <private/qcoefepinputcontext_p.h>
82 # endif
83 #endif
84
85 #include "private/qstylesheetstyle_p.h"
86
87 #include <hal.h>
88 #include <hal_data.h>
89
90 #ifdef SYMBIAN_GRAPHICS_WSERV_QT_EFFECTS
91 #include <graphics/wstfxconst.h>
92 #endif
93
94 QT_BEGIN_NAMESPACE
95
96 // Goom Events through Window Server
97 static const int KGoomMemoryLowEvent = 0x10282DBF;
98 static const int KGoomMemoryGoodEvent = 0x20026790;
99
100 #if defined(QT_DEBUG)
101 static bool        appNoGrab        = false;        // Grabbing enabled
102 #endif
103 static bool        app_do_modal        = false;        // modal mode
104 Q_GLOBAL_STATIC(QS60Data, qt_s60Data);
105
106 extern bool qt_sendSpontaneousEvent(QObject*,QEvent*);
107 extern QWidgetList *qt_modal_stack;              // stack of modal widgets
108 extern QDesktopWidget *qt_desktopWidget; // qapplication.cpp
109
110 QWidget *qt_button_down = 0;                     // widget got last button-down
111
112 QSymbianControl *QSymbianControl::lastFocusedControl = 0;
113
114 QS60Data* qGlobalS60Data()
115 {
116     return qt_s60Data();
117 }
118
119 #ifdef Q_WS_S60
120 void QS60Data::setStatusPaneAndButtonGroupVisibility(bool statusPaneVisible, bool buttonGroupVisible)
121 {
122     bool buttonGroupVisibilityChanged = false;
123     if (CEikButtonGroupContainer *const b = buttonGroupContainer()) {
124         buttonGroupVisibilityChanged = (b->IsVisible() != buttonGroupVisible);
125         b->MakeVisible(buttonGroupVisible);
126     }
127     bool statusPaneVisibilityChanged = false;
128     if (CEikStatusPane *const s = statusPane()) {
129         statusPaneVisibilityChanged = (s->IsVisible() != statusPaneVisible);
130         s->MakeVisible(statusPaneVisible);
131     }
132     if (buttonGroupVisibilityChanged  || statusPaneVisibilityChanged) {
133         const QSize size = qt_TRect2QRect(static_cast<CEikAppUi*>(S60->appUi())->ClientRect()).size();
134         const QSize oldSize; // note that QDesktopWidget::resizeEvent ignores the QResizeEvent contents
135         QResizeEvent event(size, oldSize);
136         QApplication::instance()->sendEvent(QApplication::desktop(), &event);
137     }
138     if (buttonGroupVisibilityChanged  && !statusPaneVisibilityChanged && QApplication::activeWindow())
139         // Ensure that control rectangle is updated
140         static_cast<QSymbianControl *>(QApplication::activeWindow()->winId())->handleClientAreaChange();
141 }
142 #endif
143
144 void QS60Data::controlVisibilityChanged(CCoeControl *control, bool visible)
145 {
146     if (QWidgetPrivate::mapper && QWidgetPrivate::mapper->contains(control)) {
147         QWidget *const widget = QWidgetPrivate::mapper->value(control);
148         QWidget *const window = widget->window();
149         if (QTLWExtra *topData = qt_widget_private(window)->maybeTopData()) {
150             QWidgetBackingStoreTracker &backingStore = topData->backingStore;
151             if (visible) {
152                 if (backingStore.data()) {
153                     backingStore.registerWidget(widget);
154                 } else {
155                     backingStore.create(window);
156                     backingStore.registerWidget(widget);
157                     qt_widget_private(widget)->invalidateBuffer(widget->rect());
158                     widget->repaint();
159                 }
160             } else {
161                 backingStore.unregisterWidget(widget);
162                 // In order to ensure that any resources used by the window surface
163                 // are immediately freed, we flush the WSERV command buffer.
164                 S60->wsSession().Flush();
165             }
166         }
167     }
168 }
169
170 bool qt_nograb()                                // application no-grab option
171 {
172 #if defined(QT_DEBUG)
173     return appNoGrab;
174 #else
175     return false;
176 #endif
177 }
178
179 // Modified from http://www3.symbian.com/faq.nsf/0/0F1464EE96E737E780256D5E00503DD1?OpenDocument
180 class QS60Beep : public CBase, public MMdaAudioToneObserver
181 {
182 public:
183     static QS60Beep* NewL(TInt aFrequency,  TTimeIntervalMicroSeconds iDuration);
184     void Play();
185     ~QS60Beep();
186 private:
187     void ConstructL(TInt aFrequency,  TTimeIntervalMicroSeconds iDuration);
188     void MatoPrepareComplete(TInt aError);
189     void MatoPlayComplete(TInt aError);
190 private:
191     typedef enum
192         {
193         EBeepNotPrepared,
194         EBeepPrepared,
195         EBeepPlaying
196         } TBeepState;
197 private:
198     CMdaAudioToneUtility* iToneUtil;
199     TBeepState iState;
200     TInt iFrequency;
201     TTimeIntervalMicroSeconds iDuration;
202 };
203
204 static QS60Beep* qt_S60Beep = 0;
205
206 QS60Beep::~QS60Beep()
207 {
208     if (iToneUtil) {
209         switch (iState) {
210         case EBeepPlaying:
211             iToneUtil->CancelPlay();
212             break;
213         case EBeepNotPrepared:
214             iToneUtil->CancelPrepare();
215             break;
216         }
217     }
218     delete iToneUtil;
219 }
220
221 QS60Beep* QS60Beep::NewL(TInt aFrequency, TTimeIntervalMicroSeconds aDuration)
222 {
223     QS60Beep* self = new (ELeave) QS60Beep();
224     CleanupStack::PushL(self);
225     self->ConstructL(aFrequency, aDuration);
226     CleanupStack::Pop();
227     return self;
228 }
229
230 void QS60Beep::ConstructL(TInt aFrequency, TTimeIntervalMicroSeconds aDuration)
231 {
232     iToneUtil = CMdaAudioToneUtility::NewL(*this);
233     iState = EBeepNotPrepared;
234     iFrequency = aFrequency;
235     iDuration = aDuration;
236     iToneUtil->PrepareToPlayTone(iFrequency, iDuration);
237 }
238
239 void QS60Beep::Play()
240 {
241     if (iState == EBeepPlaying) {
242         iToneUtil->CancelPlay();
243         iState = EBeepPrepared;
244     }
245
246     iToneUtil->Play();
247     iState = EBeepPlaying;
248 }
249
250 void QS60Beep::MatoPrepareComplete(TInt aError)
251 {
252     if (aError == KErrNone) {
253         iState = EBeepPrepared;
254         Play();
255     }
256 }
257
258 void QS60Beep::MatoPlayComplete(TInt aError)
259 {
260     Q_UNUSED(aError);
261     iState = EBeepPrepared;
262 }
263
264
265 static Qt::KeyboardModifiers mapToQtModifiers(TUint s60Modifiers)
266 {
267     Qt::KeyboardModifiers result = Qt::NoModifier;
268
269     if (s60Modifiers & EModifierKeypad)
270         result |= Qt::KeypadModifier;
271     if (s60Modifiers & EModifierShift || s60Modifiers & EModifierLeftShift
272             || s60Modifiers & EModifierRightShift)
273         result |= Qt::ShiftModifier;
274     if (s60Modifiers & EModifierCtrl || s60Modifiers & EModifierLeftCtrl
275             || s60Modifiers & EModifierRightCtrl)
276         result |= Qt::ControlModifier;
277     if (s60Modifiers & EModifierAlt || s60Modifiers & EModifierLeftAlt
278             || s60Modifiers & EModifierRightAlt)
279         result |= Qt::AltModifier;
280
281     return result;
282 }
283
284 static void mapS60MouseEventTypeToQt(QEvent::Type *type, Qt::MouseButton *button, const TPointerEvent *pEvent)
285 {
286     switch (pEvent->iType) {
287     case TPointerEvent::EButton1Down:
288         *type = QEvent::MouseButtonPress;
289         *button = Qt::LeftButton;
290         break;
291     case TPointerEvent::EButton1Up:
292         *type = QEvent::MouseButtonRelease;
293         *button = Qt::LeftButton;
294         break;
295     case TPointerEvent::EButton2Down:
296         *type = QEvent::MouseButtonPress;
297         *button = Qt::MidButton;
298         break;
299     case TPointerEvent::EButton2Up:
300         *type = QEvent::MouseButtonRelease;
301         *button = Qt::MidButton;
302         break;
303     case TPointerEvent::EButton3Down:
304         *type = QEvent::MouseButtonPress;
305         *button = Qt::RightButton;
306         break;
307     case TPointerEvent::EButton3Up:
308         *type = QEvent::MouseButtonRelease;
309         *button = Qt::RightButton;
310         break;
311     case TPointerEvent::EDrag:
312         *type = QEvent::MouseMove;
313         *button = Qt::NoButton;
314         break;
315     case TPointerEvent::EMove:
316         // Qt makes no distinction between move and drag
317         *type = QEvent::MouseMove;
318         *button = Qt::NoButton;
319         break;
320     default:
321         *type = QEvent::None;
322         *button = Qt::NoButton;
323         break;
324     }
325     if (pEvent->iModifiers & EModifierDoubleClick){
326         *type = QEvent::MouseButtonDblClick;
327     }
328
329     if (*type == QEvent::MouseButtonPress || *type == QEvent::MouseButtonDblClick)
330         QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons | (*button);
331     else if (*type == QEvent::MouseButtonRelease)
332         QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons &(~(*button));
333
334     QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons & Qt::MouseButtonMask;
335 }
336
337 //### Can be replaced with CAknLongTapDetector if animation is required.
338 //NOTE: if CAknLongTapDetector is used make sure it gets variated out of 3.1 and 3.2,.
339 //also MLongTapObserver needs to be changed to MAknLongTapDetectorCallBack if CAknLongTapDetector is used.
340 class QLongTapTimer : public CTimer
341 {
342 public:
343     static QLongTapTimer* NewL(QAbstractLongTapObserver *observer);
344     QLongTapTimer(QAbstractLongTapObserver *observer);
345     void ConstructL();
346 public:
347     void PointerEventL(const TPointerEvent &event);
348     void RunL();
349 protected:
350 private:
351     QAbstractLongTapObserver *m_observer;
352     TPointerEvent m_event;
353     QPoint m_pressedCoordinates;
354     int m_dragDistance;
355 };
356
357 QLongTapTimer* QLongTapTimer::NewL(QAbstractLongTapObserver *observer)
358 {
359     QLongTapTimer* self = new QLongTapTimer(observer);
360     self->ConstructL();
361     return self;
362 }
363 void QLongTapTimer::ConstructL()
364 {
365     CTimer::ConstructL();
366 }
367
368 QLongTapTimer::QLongTapTimer(QAbstractLongTapObserver *observer):CTimer(CActive::EPriorityHigh)
369 {
370     m_observer = observer;
371     m_dragDistance = qApp->startDragDistance();
372     CActiveScheduler::Add(this);
373 }
374
375 void QLongTapTimer::PointerEventL(const TPointerEvent& event)
376 {
377     if ( event.iType == TPointerEvent::EDrag || event.iType == TPointerEvent::EButtonRepeat)
378     {
379         QPoint diff(QPoint(event.iPosition.iX,event.iPosition.iY) - m_pressedCoordinates);
380         if (diff.manhattanLength() < m_dragDistance)
381             return;
382     }
383     Cancel();
384     m_event = event;
385     if (event.iType == TPointerEvent::EButton1Down)
386     {
387         m_pressedCoordinates = QPoint(event.iPosition.iX,event.iPosition.iY);
388         // must be same as KLongTapDelay in aknlongtapdetector.h
389         After(800000);
390     }
391 }
392 void QLongTapTimer::RunL()
393 {
394     if (m_observer)
395         m_observer->HandleLongTapEventL(m_event.iPosition, m_event.iParentPosition);
396 }
397
398 QSymbianControl::QSymbianControl(QWidget *w)
399     : CCoeControl()
400     , qwidget(w)
401     , m_longTapDetector(0)
402     , m_ignoreFocusChanged(0)
403     , m_symbianPopupIsOpen(0)
404 {
405 }
406
407 void QSymbianControl::ConstructL(bool isWindowOwning, bool desktop)
408 {
409     if (!desktop)
410     {
411         if (isWindowOwning || !qwidget->parentWidget())
412             CreateWindowL(S60->windowGroup());
413         else
414             /**
415              * TODO: in order to avoid creating windows for all ancestors of
416              * this widget up to the root window, the parameter passed to
417              * CreateWindowL should be
418              * qwidget->parentWidget()->effectiveWinId().  However, if we do
419              * this, then we need to take care of re-parenting when a window
420              * is created for a widget between this one and the root window.
421              */
422             CreateWindowL(qwidget->parentWidget()->winId());
423
424         // Necessary in order to be able to track the activation status of
425         // the control's window
426         qwidget->d_func()->createExtra();
427
428         SetFocusing(true);
429         m_longTapDetector = QLongTapTimer::NewL(this);
430         m_doubleClickTimer.invalidate();
431
432         DrawableWindow()->SetPointerGrab(ETrue);
433     }
434
435 #ifdef SYMBIAN_GRAPHICS_WSERV_QT_EFFECTS
436     if (OwnsWindow()) {
437         TTfxWindowPurpose windowPurpose(ETfxPurposeNone);
438         switch (qwidget->windowType()) {
439         case Qt::Dialog:
440             windowPurpose = ETfxPurposeDialogWindow;
441             break;
442         case Qt::Popup:
443             windowPurpose = ETfxPurposePopupWindow;
444             break;
445         case Qt::Tool:
446             windowPurpose = ETfxPurposeToolWindow;
447             break;
448         case Qt::ToolTip:
449             windowPurpose = ETfxPurposeToolTipWindow;
450             break;
451         case Qt::SplashScreen:
452             windowPurpose = ETfxPurposeSplashScreenWindow;
453             break;
454         default:
455             windowPurpose = (isWindowOwning || !qwidget->parentWidget())
456                             ? ETfxPurposeWindow : ETfxPurposeChildWindow;
457             break;
458         }
459         Window().SetPurpose(windowPurpose);
460     }
461 #endif
462 }
463
464 QSymbianControl::~QSymbianControl()
465 {
466     // Ensure backing store is deleted before the top-level
467     // window is destroyed
468     qt_widget_private(qwidget)->topData()->backingStore.destroy();
469
470     if (S60->curWin == this)
471         S60->curWin = 0;
472     if (!QApplicationPrivate::is_app_closing) {
473         QT_TRY {
474             setFocusSafely(false);
475         } QT_CATCH(const std::exception&) {
476             // ignore exceptions, nothing can be done
477         }
478     }
479     S60->appUi()->RemoveFromStack(this);
480     delete m_longTapDetector;
481 }
482
483 void QSymbianControl::setWidget(QWidget *w)
484 {
485     qwidget = w;
486 }
487 void QSymbianControl::HandleLongTapEventL( const TPoint& aPenEventLocation, const TPoint& aPenEventScreenLocation )
488 {
489     QWidget *alienWidget;
490     QPoint widgetPos = QPoint(aPenEventLocation.iX, aPenEventLocation.iY);
491     QPoint globalPos = QPoint(aPenEventScreenLocation.iX,aPenEventScreenLocation.iY);
492     alienWidget = qwidget->childAt(widgetPos);
493     if (!alienWidget)
494         alienWidget = qwidget;
495
496 #if !defined(QT_NO_CONTEXTMENU)
497     QContextMenuEvent contextMenuEvent(QContextMenuEvent::Mouse, widgetPos, globalPos, Qt::NoModifier);
498     qt_sendSpontaneousEvent(alienWidget, &contextMenuEvent);
499 #endif
500 }
501
502 #ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
503 void QSymbianControl::translateAdvancedPointerEvent(const TAdvancedPointerEvent *event)
504 {
505     QApplicationPrivate *d = QApplicationPrivate::instance();
506     QPointF screenPos = qwidget->mapToGlobal(QPoint(event->iPosition.iX, event->iPosition.iY));
507     qreal pressure;
508     if(d->pressureSupported
509         && event->Pressure() > 0) //workaround for misconfigured HAL
510         pressure = event->Pressure() / qreal(d->maxTouchPressure);
511     else
512         pressure = qreal(1.0);
513     processTouchEvent(event->PointerNumber(), event->iType, screenPos, pressure);
514 }
515 #endif
516
517 void QSymbianControl::processTouchEvent(int pointerNumber, TPointerEvent::TType type, QPointF screenPos, qreal pressure)
518 {
519     QRect screenGeometry = qApp->desktop()->screenGeometry(qwidget);
520
521     QApplicationPrivate *d = QApplicationPrivate::instance();
522
523     QList<QTouchEvent::TouchPoint> points = d->appAllTouchPoints;
524     while (points.count() <= pointerNumber)
525         points.append(QTouchEvent::TouchPoint(points.count()));
526
527     Qt::TouchPointStates allStates = 0;
528     for (int i = 0; i < points.count(); ++i) {
529         QTouchEvent::TouchPoint &touchPoint = points[i];
530
531         if (touchPoint.id() == pointerNumber) {
532             Qt::TouchPointStates state;
533             switch (type) {
534             case TPointerEvent::EButton1Down:
535 #ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
536             case TPointerEvent::EEnterHighPressure:
537 #endif
538                 state = Qt::TouchPointPressed;
539                 break;
540             case TPointerEvent::EButton1Up:
541 #ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
542             case TPointerEvent::EExitCloseProximity:
543 #endif
544                 state = Qt::TouchPointReleased;
545                 break;
546             case TPointerEvent::EDrag:
547                 state = Qt::TouchPointMoved;
548                 break;
549             default:
550                 // how likely is this to happen?
551                 state = Qt::TouchPointStationary;
552                 break;
553             }
554             if (pointerNumber == 0)
555                 state |= Qt::TouchPointPrimary;
556             touchPoint.setState(state);
557
558             touchPoint.setScreenPos(screenPos);
559             touchPoint.setNormalizedPos(QPointF(screenPos.x() / screenGeometry.width(),
560                                                 screenPos.y() / screenGeometry.height()));
561
562             touchPoint.setPressure(pressure);
563         } else if (touchPoint.state() != Qt::TouchPointReleased) {
564             // all other active touch points should be marked as stationary
565             touchPoint.setState(Qt::TouchPointStationary);
566         }
567
568         allStates |= touchPoint.state();
569     }
570
571     if ((allStates & Qt::TouchPointStateMask) == Qt::TouchPointReleased) {
572         // all touch points released
573         d->appAllTouchPoints.clear();
574     } else {
575         d->appAllTouchPoints = points;
576     }
577
578     QApplicationPrivate::translateRawTouchEvent(qwidget,
579                                                 QTouchEvent::TouchScreen,
580                                                 points);
581 }
582
583 void QSymbianControl::HandlePointerEventL(const TPointerEvent& pEvent)
584 {
585 #ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
586     if (pEvent.IsAdvancedPointerEvent()) {
587         const TAdvancedPointerEvent *advancedPointerEvent = pEvent.AdvancedPointerEvent();
588         translateAdvancedPointerEvent(advancedPointerEvent);
589         if (advancedPointerEvent->PointerNumber() != 0) {
590             // only send mouse events for the first touch point
591             return;
592         }
593     }
594 #endif
595
596     m_longTapDetector->PointerEventL(pEvent);
597     QT_TRYCATCH_LEAVING(HandlePointerEvent(pEvent));
598 }
599
600 void QSymbianControl::HandlePointerEvent(const TPointerEvent& pEvent)
601 {
602     QMouseEvent::Type type;
603     Qt::MouseButton button;
604     mapS60MouseEventTypeToQt(&type, &button, &pEvent);
605     Qt::KeyboardModifiers modifiers = mapToQtModifiers(pEvent.iModifiers);
606
607     QPoint widgetPos = QPoint(pEvent.iPosition.iX, pEvent.iPosition.iY);
608     TPoint controlScreenPos = PositionRelativeToScreen();
609     QPoint globalPos = QPoint(controlScreenPos.iX, controlScreenPos.iY) + widgetPos;
610     S60->lastCursorPos = globalPos;
611     S60->lastPointerEventPos = widgetPos;
612
613     QWidget *mouseGrabber = QWidget::mouseGrabber();
614
615     QWidget *popupWidget = qApp->activePopupWidget();
616     QWidget *popupReceiver = 0;
617     if (popupWidget) {
618         QWidget *popupChild = popupWidget->childAt(popupWidget->mapFromGlobal(globalPos));
619         popupReceiver = popupChild ? popupChild : popupWidget;
620     }
621
622     if (mouseGrabber) {
623         if (popupReceiver) {
624             sendMouseEvent(popupReceiver, type, globalPos, button, modifiers);
625         } else {
626             sendMouseEvent(mouseGrabber, type, globalPos, button, modifiers);
627         }
628         // No Enter/Leave events in grabbing mode.
629         return;
630     }
631
632     QWidget *widgetUnderPointer = qwidget->childAt(widgetPos);
633     if (!widgetUnderPointer)
634         widgetUnderPointer = qwidget;
635
636     QApplicationPrivate::dispatchEnterLeave(widgetUnderPointer, S60->lastPointerEventTarget);
637     S60->lastPointerEventTarget = widgetUnderPointer;
638
639     QWidget *receiver;
640     if (!popupReceiver && S60->mousePressTarget && type != QEvent::MouseButtonPress) {
641         receiver = S60->mousePressTarget;
642         if (type == QEvent::MouseButtonRelease)
643             S60->mousePressTarget = 0;
644     } else {
645         receiver = popupReceiver ? popupReceiver : widgetUnderPointer;
646         if (type == QEvent::MouseButtonPress)
647             S60->mousePressTarget = receiver;
648     }
649
650 #if !defined(QT_NO_CURSOR) && !defined(Q_SYMBIAN_FIXED_POINTER_CURSORS)
651     if (S60->brokenPointerCursors)
652         qt_symbian_move_cursor_sprite();
653 #endif
654
655 //Generate single touch event for S60 5.0 (has touchscreen, does not have advanced pointers)
656 #ifndef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
657     if (S60->hasTouchscreen) {
658         processTouchEvent(0, pEvent.iType, QPointF(globalPos), 1.0);
659     }
660 #endif
661
662     sendMouseEvent(receiver, type, globalPos, button, modifiers);
663 }
664
665 #ifdef Q_WS_S60
666 void QSymbianControl::HandleStatusPaneSizeChange()
667 {
668     QS60MainAppUi *s60AppUi = static_cast<QS60MainAppUi *>(S60->appUi());
669     s60AppUi->HandleStatusPaneSizeChange();
670 }
671 #endif
672
673 void QSymbianControl::sendMouseEvent(
674         QWidget *receiver,
675         QEvent::Type type,
676         const QPoint &globalPos,
677         Qt::MouseButton button,
678         Qt::KeyboardModifiers modifiers)
679 {
680     Q_ASSERT(receiver);
681     QMouseEvent mEvent(type, receiver->mapFromGlobal(globalPos), globalPos,
682         button, QApplicationPrivate::mouse_buttons, modifiers);
683     QEventDispatcherS60 *dispatcher;
684     // It is theoretically possible for someone to install a different event dispatcher.
685     if ((dispatcher = qobject_cast<QEventDispatcherS60 *>(receiver->d_func()->threadData->eventDispatcher)) != 0) {
686         if (dispatcher->excludeUserInputEvents()) {
687             dispatcher->saveInputEvent(this, receiver, new QMouseEvent(mEvent));
688             return;
689         }
690     }
691
692     sendMouseEvent(receiver, &mEvent);
693 }
694
695 bool QSymbianControl::sendMouseEvent(QWidget *widget, QMouseEvent *mEvent)
696 {
697     return qt_sendSpontaneousEvent(widget, mEvent);
698 }
699
700 TKeyResponse QSymbianControl::OfferKeyEventL(const TKeyEvent& keyEvent, TEventCode type)
701 {
702     TKeyResponse r = EKeyWasNotConsumed;
703     QT_TRYCATCH_LEAVING(r = OfferKeyEvent(keyEvent, type));
704     return r;
705 }
706
707 TKeyResponse QSymbianControl::OfferKeyEvent(const TKeyEvent& keyEvent, TEventCode type)
708 {
709     /*
710       S60 has a confusing way of delivering key events. There are three types of
711       events: EEventKey, EEventKeyDown and EEventKeyUp. When a key is pressed,
712       EEventKeyDown is first generated, followed by EEventKey. Then, when the key is
713       released, EEventKeyUp is generated.
714       However, it is possible that only the EEventKey is generated alone, typically
715       in relation to virtual keyboards. In that case we need to take care to
716       generate both press and release events in Qt, since applications expect that.
717       We do this by having three states for each used scan code, depending on the
718       events received. See the switch below for what happens in each state
719       transition.
720     */
721
722     if (type != EEventKeyDown)
723         if (handleVirtualMouse(keyEvent, type) == EKeyWasConsumed)
724             return EKeyWasConsumed;
725
726     TKeyResponse ret = EKeyWasNotConsumed;
727 #define GET_RETURN(x) (ret = ((x) == EKeyWasConsumed) ? EKeyWasConsumed : ret)
728
729     // This top level switch corresponds to the states, and the inner switches
730     // correspond to the transitions.
731     QS60Data::ScanCodeState &scanCodeState = S60->scanCodeStates[keyEvent.iScanCode];
732     switch (scanCodeState) {
733     case QS60Data::Unpressed:
734         switch (type) {
735         case EEventKeyDown:
736             scanCodeState = QS60Data::KeyDown;
737             break;
738         case EEventKey:
739             GET_RETURN(sendSymbianKeyEvent(keyEvent, QEvent::KeyPress));
740             GET_RETURN(sendSymbianKeyEvent(keyEvent, QEvent::KeyRelease));
741             break;
742         case EEventKeyUp:
743             // No action.
744             break;
745         }
746         break;
747     case QS60Data::KeyDown:
748         switch (type) {
749         case EEventKeyDown:
750             // This should never happen, just stay in this state to be safe.
751             break;
752         case EEventKey:
753             GET_RETURN(sendSymbianKeyEvent(keyEvent, QEvent::KeyPress));
754             scanCodeState = QS60Data::KeyDownAndKey;
755             break;
756         case EEventKeyUp:
757             scanCodeState = QS60Data::Unpressed;
758             break;
759         }
760         break;
761     case QS60Data::KeyDownAndKey:
762         switch (type) {
763         case EEventKeyDown:
764             // This should never happen, just stay in this state to be safe.
765             break;
766         case EEventKey:
767             GET_RETURN(sendSymbianKeyEvent(keyEvent, QEvent::KeyRelease));
768             GET_RETURN(sendSymbianKeyEvent(keyEvent, QEvent::KeyPress));
769             break;
770         case EEventKeyUp:
771             GET_RETURN(sendSymbianKeyEvent(keyEvent, QEvent::KeyRelease));
772             scanCodeState = QS60Data::Unpressed;
773             break;
774         }
775         break;
776     }
777     return ret;
778
779 #undef GET_RETURN
780 }
781
782 TKeyResponse QSymbianControl::sendSymbianKeyEvent(const TKeyEvent &keyEvent, QEvent::Type type)
783 {
784     // Because S60 does not generate keysyms for EKeyEventDown and EKeyEventUp
785     // events, we need to cache the keysyms from the EKeyEvent events. This is what
786     // resolveS60ScanCode does.
787     TUint s60Keysym = QApplicationPrivate::resolveS60ScanCode(keyEvent.iScanCode,
788             keyEvent.iCode);
789     int keyCode;
790     if (s60Keysym == EKeyNull){ //some key events have 0 in iCode, for them iScanCode should be used
791         keyCode = qt_keymapper_private()->mapS60ScanCodesToQt(keyEvent.iScanCode);
792     } else if (s60Keysym >= 0x20 && s60Keysym < ENonCharacterKeyBase) {
793         // Normal characters keys.
794         keyCode = s60Keysym;
795     } else {
796         // Special S60 keys.
797         keyCode = qt_keymapper_private()->mapS60KeyToQt(s60Keysym);
798     }
799
800     Qt::KeyboardModifiers mods = mapToQtModifiers(keyEvent.iModifiers);
801     QKeyEventEx qKeyEvent(type, keyCode, mods, qt_keymapper_private()->translateKeyEvent(keyCode, mods),
802             (keyEvent.iRepeats != 0), 1, keyEvent.iScanCode, s60Keysym, keyEvent.iModifiers);
803     QWidget *widget;
804     widget = QWidget::keyboardGrabber();
805     if (!widget) {
806         if (QApplicationPrivate::popupWidgets != 0) {
807             widget = QApplication::activePopupWidget()->focusWidget();
808             if (!widget) {
809                 widget = QApplication::activePopupWidget();
810             }
811         } else {
812             widget = QApplicationPrivate::focus_widget;
813             if (!widget) {
814                 widget = qwidget;
815             }
816         }
817     }
818
819     QEventDispatcherS60 *dispatcher;
820     // It is theoretically possible for someone to install a different event dispatcher.
821     if ((dispatcher = qobject_cast<QEventDispatcherS60 *>(widget->d_func()->threadData->eventDispatcher)) != 0) {
822         if (dispatcher->excludeUserInputEvents()) {
823             dispatcher->saveInputEvent(this, widget, new QKeyEventEx(qKeyEvent));
824             return EKeyWasConsumed;
825         }
826     }
827     return sendKeyEvent(widget, &qKeyEvent);
828 }
829
830 TKeyResponse QSymbianControl::handleVirtualMouse(const TKeyEvent& keyEvent,TEventCode type)
831 {
832 #ifndef QT_NO_CURSOR
833     if (S60->mouseInteractionEnabled && S60->virtualMouseRequired) {
834         //translate keys to pointer
835         if ((keyEvent.iScanCode >= EStdKeyLeftArrow && keyEvent.iScanCode <= EStdKeyDownArrow) ||
836                 (keyEvent.iScanCode >= EStdKeyDevice10 && keyEvent.iScanCode <= EStdKeyDevice13) ||
837                 keyEvent.iScanCode == EStdKeyDevice3) {
838             QPoint pos = QCursor::pos();
839             TPointerEvent fakeEvent;
840             fakeEvent.iType = (TPointerEvent::TType)(-1);
841             fakeEvent.iModifiers = keyEvent.iModifiers;
842             TInt x = pos.x();
843             TInt y = pos.y();
844             if (type == EEventKeyUp) {
845                 S60->virtualMouseAccelTimeout.start();
846                 switch (keyEvent.iScanCode) {
847                 case EStdKeyLeftArrow:
848                     S60->virtualMousePressedKeys &= ~QS60Data::Left;
849                     break;
850                 case EStdKeyRightArrow:
851                     S60->virtualMousePressedKeys &= ~QS60Data::Right;
852                     break;
853                 case EStdKeyUpArrow:
854                     S60->virtualMousePressedKeys &= ~QS60Data::Up;
855                     break;
856                 case EStdKeyDownArrow:
857                     S60->virtualMousePressedKeys &= ~QS60Data::Down;
858                     break;
859                 // diagonal keys (named aliases don't exist in 3.1 SDK)
860                 case EStdKeyDevice10:
861                     S60->virtualMousePressedKeys &= ~QS60Data::LeftUp;
862                     break;
863                 case EStdKeyDevice11:
864                     S60->virtualMousePressedKeys &= ~QS60Data::RightUp;
865                     break;
866                 case EStdKeyDevice12:
867                     S60->virtualMousePressedKeys &= ~QS60Data::RightDown;
868                     break;
869                 case EStdKeyDevice13:
870                     S60->virtualMousePressedKeys &= ~QS60Data::LeftDown;
871                     break;
872                 case EStdKeyDevice3: //select
873                     if (S60->virtualMousePressedKeys & QS60Data::Select)
874                         fakeEvent.iType = TPointerEvent::EButton1Up;
875                     S60->virtualMousePressedKeys &= ~QS60Data::Select;
876                     break;
877                 }
878             }
879             else if (type == EEventKey) {
880                 int dx = 0;
881                 int dy = 0;
882                 if (keyEvent.iScanCode != EStdKeyDevice3) {
883                     m_doubleClickTimer.invalidate();
884                     //reset mouse accelleration after a short time with no moves
885                     const int maxTimeBetweenKeyEventsMs = 500;
886                     if (S60->virtualMouseAccelTimeout.isValid() &&
887                             S60->virtualMouseAccelTimeout.hasExpired(maxTimeBetweenKeyEventsMs)) {
888                         S60->virtualMouseAccelDX = 0;
889                         S60->virtualMouseAccelDY = 0;
890                     }
891                     S60->virtualMouseAccelTimeout.invalidate();
892                 }
893                 switch (keyEvent.iScanCode) {
894                 case EStdKeyLeftArrow:
895                     S60->virtualMousePressedKeys |= QS60Data::Left;
896                     dx = -1;
897                     fakeEvent.iType = TPointerEvent::EMove;
898                     break;
899                 case EStdKeyRightArrow:
900                     S60->virtualMousePressedKeys |= QS60Data::Right;
901                     dx = 1;
902                     fakeEvent.iType = TPointerEvent::EMove;
903                     break;
904                 case EStdKeyUpArrow:
905                     S60->virtualMousePressedKeys |= QS60Data::Up;
906                     dy = -1;
907                     fakeEvent.iType = TPointerEvent::EMove;
908                     break;
909                 case EStdKeyDownArrow:
910                     S60->virtualMousePressedKeys |= QS60Data::Down;
911                     dy = 1;
912                     fakeEvent.iType = TPointerEvent::EMove;
913                     break;
914                 case EStdKeyDevice10:
915                     S60->virtualMousePressedKeys |= QS60Data::LeftUp;
916                     dx = -1;
917                     dy = -1;
918                     fakeEvent.iType = TPointerEvent::EMove;
919                     break;
920                 case EStdKeyDevice11:
921                     S60->virtualMousePressedKeys |= QS60Data::RightUp;
922                     dx = 1;
923                     dy = -1;
924                     fakeEvent.iType = TPointerEvent::EMove;
925                     break;
926                 case EStdKeyDevice12:
927                     S60->virtualMousePressedKeys |= QS60Data::RightDown;
928                     dx = 1;
929                     dy = 1;
930                     fakeEvent.iType = TPointerEvent::EMove;
931                     break;
932                 case EStdKeyDevice13:
933                     S60->virtualMousePressedKeys |= QS60Data::LeftDown;
934                     dx = -1;
935                     dy = 1;
936                     fakeEvent.iType = TPointerEvent::EMove;
937                     break;
938                 case EStdKeyDevice3:
939                     // Platform bug. If you start pressing several keys simultaneously (for
940                     // example for drag'n'drop), Symbian starts producing spurious up and
941                     // down messages for some keys. Therefore, make sure we have a clean slate
942                     // of pressed keys before starting a new button press.
943                     if (S60->virtualMousePressedKeys & QS60Data::Select) {
944                         return EKeyWasConsumed;
945                     } else {
946                         S60->virtualMousePressedKeys |= QS60Data::Select;
947                         fakeEvent.iType = TPointerEvent::EButton1Down;
948                         if (m_doubleClickTimer.isValid()
949                                 && !m_doubleClickTimer.hasExpired(QApplication::doubleClickInterval())) {
950                             fakeEvent.iModifiers |= EModifierDoubleClick;
951                             m_doubleClickTimer.invalidate();
952                         } else {
953                             m_doubleClickTimer.start();
954                         }
955                     }
956                     break;
957                 }
958                 if (dx) {
959                     int cdx = S60->virtualMouseAccelDX;
960                     //reset accel on change of sign, else double accel
961                     if (dx * cdx <= 0)
962                         cdx = dx;
963                     else
964                         cdx *= 4;
965                     //cap accelleration
966                     if (dx * cdx > S60->virtualMouseMaxAccel)
967                         cdx = dx * S60->virtualMouseMaxAccel;
968                     //move mouse position
969                     x += cdx;
970                     S60->virtualMouseAccelDX = cdx;
971                 }
972
973                 if (dy) {
974                     int cdy = S60->virtualMouseAccelDY;
975                     if (dy * cdy <= 0)
976                         cdy = dy;
977                     else
978                         cdy *= 4;
979                     if (dy * cdy > S60->virtualMouseMaxAccel)
980                         cdy = dy * S60->virtualMouseMaxAccel;
981                     y += cdy;
982                     S60->virtualMouseAccelDY = cdy;
983                 }
984             }
985             //clip to screen size (window server allows a sprite hotspot to be outside the screen)
986             if (x < 0)
987                 x = 0;
988             else if (x >= S60->screenWidthInPixels)
989                 x = S60->screenWidthInPixels - 1;
990             if (y < 0)
991                 y = 0;
992             else if (y >= S60->screenHeightInPixels)
993                 y = S60->screenHeightInPixels - 1;
994             TPoint epos(x, y);
995             TPoint cpos = epos - PositionRelativeToScreen();
996             fakeEvent.iPosition = cpos;
997             fakeEvent.iParentPosition = epos;
998             if(fakeEvent.iType != -1)
999                 HandlePointerEvent(fakeEvent);
1000             return EKeyWasConsumed;
1001         }
1002     }
1003 #endif
1004
1005     return EKeyWasNotConsumed;
1006 }
1007
1008 void QSymbianControl::sendInputEvent(QWidget *widget, QInputEvent *inputEvent)
1009 {
1010     switch (inputEvent->type()) {
1011     case QEvent::KeyPress:
1012     case QEvent::KeyRelease:
1013         sendKeyEvent(widget, static_cast<QKeyEvent *>(inputEvent));
1014         break;
1015     case QEvent::MouseButtonDblClick:
1016     case QEvent::MouseButtonPress:
1017     case QEvent::MouseButtonRelease:
1018     case QEvent::MouseMove:
1019         sendMouseEvent(widget, static_cast<QMouseEvent *>(inputEvent));
1020         break;
1021     default:
1022         // Shouldn't get here.
1023         Q_ASSERT_X(0 == 1, "QSymbianControl::sendInputEvent()", "inputEvent->type() is unknown");
1024         break;
1025     }
1026 }
1027
1028 TKeyResponse QSymbianControl::sendKeyEvent(QWidget *widget, QKeyEvent *keyEvent)
1029 {
1030 #if !defined(QT_NO_IM) && defined(Q_WS_S60)
1031     if (widget && widget->isEnabled() && widget->testAttribute(Qt::WA_InputMethodEnabled)) {
1032         QInputContext *qic = widget->inputContext();
1033         if (qic && qic->filterEvent(keyEvent))
1034             return EKeyWasConsumed;
1035     }
1036 #endif // !defined(QT_NO_IM) && defined(Q_OS_SYMBIAN)
1037
1038     if (widget && qt_sendSpontaneousEvent(widget, keyEvent))
1039         if (keyEvent->isAccepted())
1040             return EKeyWasConsumed;
1041
1042     return EKeyWasNotConsumed;
1043 }
1044
1045 #if !defined(QT_NO_IM) && defined(Q_WS_S60)
1046 TCoeInputCapabilities QSymbianControl::InputCapabilities() const
1047 {
1048     QWidget *w = 0;
1049
1050     if (qwidget->hasFocus())
1051         w = qwidget;
1052     else
1053         w = qwidget->focusWidget();
1054
1055     QCoeFepInputContext *ic;
1056     if (w && w->isEnabled() && w->testAttribute(Qt::WA_InputMethodEnabled)
1057             && (ic = qobject_cast<QCoeFepInputContext *>(w->inputContext()))) {
1058         return ic->inputCapabilities();
1059     } else {
1060         return TCoeInputCapabilities(TCoeInputCapabilities::ENone, 0, 0);
1061     }
1062 }
1063 #endif
1064
1065 void QSymbianControl::Draw(const TRect& controlRect) const
1066 {
1067     // Set flag to avoid calling DrawNow in window surface
1068     QWidget *window = qwidget->window();
1069     Q_ASSERT(window);
1070     QTLWExtra *topExtra = window->d_func()->maybeTopData();
1071     Q_ASSERT(topExtra);
1072     if (!topExtra->inExpose) {
1073         topExtra->inExpose = true;
1074         if (!qwidget->isWindow()) {
1075             // If we get here, then it means we have a native child window
1076             // Since no content should ever be painted to these windows, we
1077             // erase them with a transparent brush when they get an expose.
1078             CWindowGc &gc = SystemGc();
1079             gc.SetBrushColor(TRgb(0, 0, 0, 0));
1080             gc.Clear(controlRect);
1081         }
1082         QRect exposeRect = qt_TRect2QRect(controlRect);
1083         qwidget->d_func()->syncBackingStore(exposeRect);
1084         topExtra->inExpose = false;
1085     }
1086
1087     QWindowSurface *surface = qwidget->windowSurface();
1088     QPaintEngine *engine = surface ? surface->paintDevice()->paintEngine() : NULL;
1089
1090     if (!engine)
1091         return;
1092
1093     const bool sendNativePaintEvents = qwidget->d_func()->extraData()->receiveNativePaintEvents;
1094     if (sendNativePaintEvents) {
1095         const QRect r = qt_TRect2QRect(controlRect);
1096         QMetaObject::invokeMethod(qwidget, "beginNativePaintEvent", Qt::DirectConnection, Q_ARG(QRect, r));
1097     }
1098
1099     // Map source rectangle into coordinates of the backing store.
1100     const QPoint controlBase(controlRect.iTl.iX, controlRect.iTl.iY);
1101     const QPoint backingStoreBase = qwidget->mapTo(qwidget->window(), controlBase);
1102     const TRect backingStoreRect(TPoint(backingStoreBase.x(), backingStoreBase.y()), controlRect.Size());
1103
1104     if (engine->type() == QPaintEngine::Raster) {
1105         QS60WindowSurface *s60Surface;
1106 #ifdef QT_GRAPHICSSYSTEM_RUNTIME
1107         if (QApplicationPrivate::runtime_graphics_system) {
1108             QRuntimeWindowSurface *rtSurface =
1109                     static_cast<QRuntimeWindowSurface*>(qwidget->windowSurface());
1110             s60Surface = static_cast<QS60WindowSurface *>(rtSurface->m_windowSurface.data());
1111         } else
1112 #endif
1113             s60Surface = static_cast<QS60WindowSurface *>(qwidget->windowSurface());
1114
1115         CFbsBitmap *bitmap = s60Surface->symbianBitmap();
1116         CWindowGc &gc = SystemGc();
1117
1118         QWExtra::NativePaintMode nativePaintMode = qwidget->d_func()->extraData()->nativePaintMode;
1119         if(qwidget->d_func()->paintOnScreen())
1120             nativePaintMode = QWExtra::Disable;
1121
1122         switch(nativePaintMode) {
1123         case QWExtra::Disable:
1124             // Do nothing
1125             break;
1126         case QWExtra::Blit:
1127             if (qwidget->d_func()->isOpaque)
1128                 gc.SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha);
1129             gc.BitBlt(controlRect.iTl, bitmap, backingStoreRect);
1130             break;
1131         case QWExtra::ZeroFill:
1132             if (Window().DisplayMode() == EColor16MA
1133                 || Window().DisplayMode() == Q_SYMBIAN_ECOLOR16MAP) {
1134                 gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
1135                 gc.SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha);
1136                 gc.SetBrushColor(TRgb::Color16MA(0));
1137                 gc.Clear(controlRect);
1138             } else {
1139                 gc.SetBrushColor(TRgb(0x000000));
1140                 gc.Clear(controlRect);
1141             };
1142             break;
1143         default:
1144             Q_ASSERT(false);
1145         }
1146     }
1147
1148     if (sendNativePaintEvents) {
1149         const QRect r = qt_TRect2QRect(controlRect);
1150         // The draw ops aren't actually sent to WSERV until the graphics
1151         // context is deactivated, which happens in the function calling
1152         // this one.  We therefore delay the delivery of endNativePaintEvent,
1153         // to ensure that drawing has completed by the time the widget
1154         // receives the event.  Note that, if the widget needs to ensure
1155         // that the draw ops have actually been executed into the output
1156         // framebuffer, a call to RWsSession::Flush is required in the
1157         // endNativePaintEvent implementation.
1158         QMetaObject::invokeMethod(qwidget, "endNativePaintEvent", Qt::QueuedConnection, Q_ARG(QRect, r));
1159     }
1160 }
1161
1162 void QSymbianControl::SizeChanged()
1163 {
1164     CCoeControl::SizeChanged();
1165
1166     QSize oldSize = qwidget->size();
1167     QSize newSize(Size().iWidth, Size().iHeight);
1168
1169     if (oldSize != newSize) {
1170         QRect cr = qwidget->geometry();
1171         cr.setSize(newSize);
1172         qwidget->data->crect = cr;
1173         if (qwidget->isVisible()) {
1174             QTLWExtra *tlwExtra = qwidget->d_func()->maybeTopData();
1175             bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt();
1176             if (!slowResize && tlwExtra)
1177                 tlwExtra->inTopLevelResize = true;
1178             QResizeEvent e(newSize, oldSize);
1179             qt_sendSpontaneousEvent(qwidget, &e);
1180             if (!qwidget->testAttribute(Qt::WA_StaticContents))
1181                 qwidget->d_func()->syncBackingStore();
1182             if (!slowResize && tlwExtra)
1183                 tlwExtra->inTopLevelResize = false;
1184         } else {
1185             if (!qwidget->testAttribute(Qt::WA_PendingResizeEvent)) {
1186                 QResizeEvent *e = new QResizeEvent(newSize, oldSize);
1187                 QApplication::postEvent(qwidget, e);
1188             }
1189         }
1190     }
1191
1192     // CCoeControl::SetExtent calls SizeChanged, but does not call
1193     // PositionChanged, so we call it here to ensure that the widget's
1194     // position is updated.
1195     PositionChanged();
1196 }
1197
1198 void QSymbianControl::PositionChanged()
1199 {
1200     CCoeControl::PositionChanged();
1201
1202     QPoint oldPos = qwidget->geometry().topLeft();
1203     QPoint newPos(Position().iX, Position().iY);
1204
1205     if (oldPos != newPos) {
1206         QRect cr = qwidget->geometry();
1207         cr.moveTopLeft(newPos);
1208         qwidget->data->crect = cr;
1209         QTLWExtra *top = qwidget->d_func()->maybeTopData();
1210         if (top && (qwidget->windowState() & (~Qt::WindowActive)) == Qt::WindowNoState)
1211             top->normalGeometry.moveTopLeft(newPos);
1212         if (qwidget->isVisible()) {
1213             QMoveEvent e(newPos, oldPos);
1214             qt_sendSpontaneousEvent(qwidget, &e);
1215         } else {
1216             QMoveEvent * e = new QMoveEvent(newPos, oldPos);
1217             QApplication::postEvent(qwidget, e);
1218         }
1219     }
1220 }
1221
1222 void QSymbianControl::FocusChanged(TDrawNow /* aDrawNow */)
1223 {
1224     if (m_ignoreFocusChanged || (qwidget->windowType() & Qt::WindowType_Mask) == Qt::Desktop)
1225         return;
1226
1227     // Popups never get focused, but still receive the FocusChanged when they are hidden.
1228     if (QApplicationPrivate::popupWidgets != 0
1229             || (qwidget->windowType() & Qt::Popup) == Qt::Popup)
1230         return;
1231
1232     if (IsFocused() && IsVisible()) {
1233         if (m_symbianPopupIsOpen) {
1234             QWidget *fw = QApplication::focusWidget();
1235             if (fw) {
1236                 QFocusEvent event(QEvent::FocusIn, Qt::PopupFocusReason);
1237                 QCoreApplication::sendEvent(fw, &event);
1238             }
1239             m_symbianPopupIsOpen = false;
1240         }
1241
1242         QApplication::setActiveWindow(qwidget->window());
1243         qwidget->d_func()->setWindowIcon_sys(true);
1244         qwidget->d_func()->setWindowTitle_sys(qwidget->windowTitle());
1245 #ifdef Q_WS_S60
1246         if (qwidget->isWindow()) {
1247             QWidget *const window = qwidget->window();
1248             QWidget *parentWindow = window->parentWidget();
1249             if (parentWindow) {
1250                 while (parentWindow->parentWidget())
1251                     parentWindow = parentWindow->parentWidget();
1252             } else {
1253                 parentWindow = window;
1254             }
1255
1256             const bool parentDecorationsVisible = !(parentWindow->windowState() & (Qt::WindowFullScreen | Qt::WindowMinimized));
1257             const bool parentIsFullscreen = parentWindow->windowState() & Qt::WindowFullScreen;
1258             const bool parentCbaVisibilityHint = parentWindow->windowFlags() & Qt::WindowSoftkeysVisibleHint;
1259             bool buttonGroupVisibility = (parentDecorationsVisible || (parentIsFullscreen && parentCbaVisibilityHint));
1260
1261             // For non-toplevel normal and maximized windows, show cba if window has softkey
1262             // actions even if topmost parent is not showing cba. Do the same for fullscreen
1263             // windows that request it.
1264             if (!buttonGroupVisibility
1265                 && window->parentWidget()
1266                 && !(window->windowState() & Qt::WindowMinimized)
1267                 && ((window->windowFlags() & Qt::WindowSoftkeysVisibleHint) || !(window->windowState() & Qt::WindowFullScreen))) {
1268                 for (int i = 0; i < window->actions().size(); ++i) {
1269                     if (window->actions().at(i)->softKeyRole() != QAction::NoSoftKey) {
1270                         buttonGroupVisibility = true;
1271                         break;
1272                     }
1273                 }
1274             }
1275             S60->setStatusPaneAndButtonGroupVisibility(parentDecorationsVisible, buttonGroupVisibility);
1276         }
1277 #endif
1278     } else if (QApplication::activeWindow() == qwidget->window()) {
1279         bool focusedControlFound = false;
1280         WId winId = 0;
1281         for (QWidget *w = qwidget->parentWidget(); w && (winId = w->internalWinId()); w = w->parentWidget()) {
1282             if (winId->IsFocused() && winId->IsVisible()) {
1283                 focusedControlFound = true;
1284                 break;
1285             } else if (w->isWindow())
1286                 break;
1287         }
1288         if (!focusedControlFound) {
1289             if (CCoeEnv::Static()->AppUi()->IsDisplayingMenuOrDialog() || S60->menuBeingConstructed) {
1290                 QWidget *fw = QApplication::focusWidget();
1291                 if (fw) {
1292                     QFocusEvent event(QEvent::FocusOut, Qt::PopupFocusReason);
1293                     QCoreApplication::sendEvent(fw, &event);
1294                 }
1295                 m_symbianPopupIsOpen = true;
1296                 return;
1297             }
1298
1299             QApplication::setActiveWindow(0);
1300         }
1301     }
1302     // else { We don't touch the active window unless we were explicitly activated or deactivated }
1303 }
1304
1305 void QSymbianControl::handleClientAreaChange()
1306 {
1307     const bool cbaVisibilityHint = qwidget->windowFlags() & Qt::WindowSoftkeysVisibleHint;
1308     if (qwidget->isFullScreen() && !cbaVisibilityHint) {
1309         SetExtentToWholeScreen();
1310     } else if (qwidget->isMaximized() || (qwidget->isFullScreen() && cbaVisibilityHint)) {
1311         TRect r = static_cast<CEikAppUi*>(S60->appUi())->ClientRect();
1312         SetExtent(r.iTl, r.Size());
1313     } else if (!qwidget->isMinimized()) { // Normal geometry
1314         if (!qwidget->testAttribute(Qt::WA_Resized)) {
1315             qwidget->adjustSize();
1316             qwidget->setAttribute(Qt::WA_Resized, false); //not a user resize
1317         }
1318         if (!qwidget->testAttribute(Qt::WA_Moved) && qwidget->windowType() != Qt::Dialog) {
1319             TRect r = static_cast<CEikAppUi*>(S60->appUi())->ClientRect();
1320             SetPosition(r.iTl);
1321             qwidget->setAttribute(Qt::WA_Moved, false); // not really an explicit position
1322         }
1323     }
1324 }
1325
1326 void QSymbianControl::HandleResourceChange(int resourceType)
1327 {
1328     switch (resourceType) {
1329     case KInternalStatusPaneChange:
1330         handleClientAreaChange();
1331         if (IsFocused() && IsVisible()) {
1332             qwidget->d_func()->setWindowIcon_sys(true);
1333             qwidget->d_func()->setWindowTitle_sys(qwidget->windowTitle());
1334         }
1335         break;
1336     case KUidValueCoeFontChangeEvent:
1337         // font change event
1338         break;
1339 #ifdef Q_WS_S60
1340     case KEikDynamicLayoutVariantSwitch:
1341     {
1342         handleClientAreaChange();
1343         // Send resize event to trigger desktopwidget workAreaResized signal
1344         QResizeEvent e(qt_desktopWidget->size(), qt_desktopWidget->size());
1345         QApplication::sendEvent(qt_desktopWidget, &e);
1346         break;
1347     }
1348 #endif
1349     default:
1350         break;
1351     }
1352
1353     CCoeControl::HandleResourceChange(resourceType);
1354
1355 }
1356 void QSymbianControl::CancelLongTapTimer()
1357 {
1358     m_longTapDetector->Cancel();
1359 }
1360
1361 TTypeUid::Ptr QSymbianControl::MopSupplyObject(TTypeUid id)
1362 {
1363     if (id.iUid == ETypeId)
1364         return id.MakePtr(this);
1365
1366     return CCoeControl::MopSupplyObject(id);
1367 }
1368
1369 void QSymbianControl::setFocusSafely(bool focus)
1370 {
1371     // The stack hack in here is very unfortunate, but it is the only way to ensure proper
1372     // focus in Symbian. If this is not executed, the control which happens to be on
1373     // the top of the stack may randomly be assigned focus by Symbian, for example
1374     // when creating new windows (specifically in CCoeAppUi::HandleStackChanged()).
1375
1376     // Close any popups.
1377     CEikonEnv::Static()->EikAppUi()->StopDisplayingMenuBar();
1378
1379     if (focus) {
1380         S60->appUi()->RemoveFromStack(this);
1381         // Symbian doesn't automatically remove focus from the last focused control, so we need to
1382         // remember it and clear focus ourselves.
1383         if (lastFocusedControl && lastFocusedControl != this)
1384             lastFocusedControl->SetFocus(false);
1385         QT_TRAP_THROWING(S60->appUi()->AddToStackL(this,
1386                 ECoeStackPriorityDefault + 1, ECoeStackFlagStandard)); // Note the + 1
1387         lastFocusedControl = this;
1388         this->SetFocus(true);
1389     } else {
1390         S60->appUi()->RemoveFromStack(this);
1391         QT_TRAP_THROWING(S60->appUi()->AddToStackL(this,
1392                 ECoeStackPriorityDefault, ECoeStackFlagStandard));
1393         if(this == lastFocusedControl)
1394             lastFocusedControl = 0;
1395         this->SetFocus(false);
1396     }
1397 }
1398
1399 bool QSymbianControl::isControlActive()
1400 {
1401     return IsActivated() ? true : false;
1402 }
1403
1404 /*!
1405     \typedef QApplication::QS60MainApplicationFactory
1406     \since 4.6
1407
1408     This is a typedef for a pointer to a function with the following
1409     signature:
1410
1411     \snippet doc/src/snippets/code/src_corelib_global_qglobal.cpp 47
1412
1413     \sa QApplication::QApplication()
1414 */
1415
1416 /*!
1417     \since 4.6
1418
1419     Creates an application using the application factory given in
1420     \a factory, and using \a argc command line arguments in \a argv.
1421     \a factory can be leaving, but the error will be converted to a
1422     standard exception.
1423
1424     This function is only available on S60.
1425 */
1426 QApplication::QApplication(QApplication::QS60MainApplicationFactory factory, int &argc, char **argv)
1427     : QCoreApplication(*new QApplicationPrivate(argc, argv, GuiClient))
1428 {
1429     Q_D(QApplication);
1430     S60->s60ApplicationFactory = factory;
1431     d->construct();
1432 }
1433
1434 QApplication::QApplication(QApplication::QS60MainApplicationFactory factory, int &argc, char **argv, int _internal)
1435     : QCoreApplication(*new QApplicationPrivate(argc, argv, GuiClient))
1436 {
1437     Q_D(QApplication);
1438     S60->s60ApplicationFactory = factory;
1439     d->construct();
1440     QApplicationPrivate::app_compile_version = _internal;
1441 }
1442
1443 void qt_init(QApplicationPrivate * /* priv */, int)
1444 {
1445     if (!CCoeEnv::Static()) {
1446         // The S60 framework creates a new trap handler which will render any existing traps
1447         // invalid as long as it is active. This means that all code in main() that occurs after
1448         // the QApplication construction needs to be surrounded by a new trap, despite having
1449         // an outer one already. To avoid this, we save the original trap handler here, and set
1450         // it back after the S60 framework is constructed. Then we restore it right before the S60
1451         // framework destruction.
1452         TTrapHandler *origTrapHandler = User::TrapHandler();
1453
1454         // The S60 framework has not been initialized. We need to do it.
1455         TApaApplicationFactory factory(S60->s60ApplicationFactory ?
1456                 S60->s60ApplicationFactory : newS60Application);
1457         CApaCommandLine* commandLine = 0;
1458         TInt err = CApaCommandLine::GetCommandLineFromProcessEnvironment(commandLine);
1459         // After this construction, CEikonEnv will be available from CEikonEnv::Static().
1460         // (much like our qApp).
1461         QtEikonEnv* coe = new QtEikonEnv;
1462         //not using QT_TRAP_THROWING, because coe owns the cleanupstack so it can't be pushed there.
1463         if(err == KErrNone)
1464             TRAP(err, coe->ConstructAppFromCommandLineL(factory,*commandLine));
1465         delete commandLine;
1466         if(err != KErrNone) {
1467             qWarning() << "qt_init: Eikon application construct failed ("
1468                        << err
1469                        << "), maybe missing resource file on S60 3.1?";
1470             delete coe;
1471             qt_symbian_throwIfError(err);
1472         }
1473
1474         S60->s60InstalledTrapHandler = User::SetTrapHandler(origTrapHandler);
1475
1476         S60->qtOwnsS60Environment = true;
1477     } else {
1478         S60->qtOwnsS60Environment = false;
1479     }
1480
1481 #ifdef QT_NO_DEBUG
1482     if (!qgetenv("QT_S60_AUTO_FLUSH_WSERV").isEmpty())
1483 #endif
1484         S60->wsSession().SetAutoFlush(ETrue);
1485
1486 #ifdef Q_SYMBIAN_WINDOW_SIZE_CACHE
1487     TRAP_IGNORE(S60->wsSession().EnableWindowSizeCacheL());
1488 #endif
1489
1490     S60->updateScreenSize();
1491
1492
1493     TDisplayMode mode = S60->screenDevice()->DisplayMode();
1494     S60->screenDepth = TDisplayModeUtils::NumDisplayModeBitsPerPixel(mode);
1495
1496     //NB: RWsSession::GetColorModeList tells you what window modes are supported,
1497     //not what bitmap formats.
1498     if(QSysInfo::symbianVersion() == QSysInfo::SV_9_2)
1499         S60->supportsPremultipliedAlpha = 0;
1500     else
1501         S60->supportsPremultipliedAlpha = 1;
1502
1503     RProcess me;
1504     TSecureId securId = me.SecureId();
1505     S60->uid = securId.operator TUid();
1506
1507     // enable focus events - used to re-enable mouse after focus changed between mouse and non mouse app,
1508     // and for dimming behind modal windows
1509     S60->windowGroup().EnableFocusChangeEvents();
1510
1511     //Check if mouse interaction is supported (either EMouse=1 in the HAL, or EMachineUID is one of the phones known to support this)
1512     const TInt KMachineUidSamsungI8510 = 0x2000C51E;
1513     // HAL::Get(HALData::EPen, TInt& result) may set 'result' to 1 on some 3.1 systems (e.g. N95).
1514     // But we know that S60 systems below 5.0 did not support touch.
1515     static const bool touchIsUnsupportedOnSystem =
1516         QSysInfo::s60Version() == QSysInfo::SV_S60_3_1
1517         || QSysInfo::s60Version() == QSysInfo::SV_S60_3_2;
1518     TInt machineUID;
1519     TInt mouse;
1520     TInt touch;
1521     TInt err;
1522     err = HAL::Get(HALData::EMouse, mouse);
1523     if (err != KErrNone)
1524         mouse = 0;
1525     err = HAL::Get(HALData::EMachineUid, machineUID);
1526     if (err != KErrNone)
1527         machineUID = 0;
1528     err = HAL::Get(HALData::EPen, touch);
1529     if (err != KErrNone || touchIsUnsupportedOnSystem)
1530         touch = 0;
1531 #ifdef __WINS__
1532     if(QSysInfo::symbianVersion() <= QSysInfo::SV_9_4) {
1533         //for symbian SDK emulator, force values to match typical devices.
1534         mouse = 0;
1535         touch = touchIsUnsupportedOnSystem ? 0 : 1;
1536     }
1537 #endif
1538     if (mouse || machineUID == KMachineUidSamsungI8510) {
1539         S60->hasTouchscreen = false;
1540         S60->virtualMouseRequired = false;
1541     }
1542     else if (!touch) {
1543         S60->hasTouchscreen = false;
1544         S60->virtualMouseRequired = true;
1545     }
1546     else {
1547         S60->hasTouchscreen = true;
1548         S60->virtualMouseRequired = false;
1549     }
1550
1551     S60->avkonComponentsSupportTransparency = false;
1552     S60->menuBeingConstructed = false;
1553
1554 #ifdef Q_WS_S60
1555     TUid KCRUidAvkon = { 0x101F876E };
1556     TUint32 KAknAvkonTransparencyEnabled = 0x0000000D;
1557
1558     CRepository* repository = 0;
1559     TRAP(err, repository = CRepository::NewL(KCRUidAvkon));
1560
1561     if(err == KErrNone) {
1562         TInt value = 0;
1563         err = repository->Get(KAknAvkonTransparencyEnabled, value);
1564         if(err == KErrNone) {
1565             S60->avkonComponentsSupportTransparency = (value==1) ? true : false;
1566         }
1567     }
1568     delete repository;
1569     repository = 0;
1570 #endif
1571
1572 #ifdef QT_KEYPAD_NAVIGATION
1573     if (touch) {
1574         QApplicationPrivate::navigationMode = Qt::NavigationModeNone;
1575     } else {
1576         QApplicationPrivate::navigationMode = Qt::NavigationModeKeypadDirectional;
1577     }
1578 #endif
1579
1580 #ifndef QT_NO_CURSOR
1581     //Check if window server pointer cursors are supported or not
1582 #ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
1583     //In generic binary, use the HAL and OS version
1584     //Any other known good phones should be added here.
1585     if (machineUID == KMachineUidSamsungI8510 || (QSysInfo::symbianVersion() != QSysInfo::SV_9_4
1586         && QSysInfo::symbianVersion() != QSysInfo::SV_9_3 && QSysInfo::symbianVersion()
1587         != QSysInfo::SV_9_2)) {
1588         S60->brokenPointerCursors = false;
1589         qt_symbian_setWindowGroupCursor(Qt::ArrowCursor, S60->windowGroup());
1590     }
1591     else
1592         S60->brokenPointerCursors = true;
1593 #endif
1594
1595     if (S60->mouseInteractionEnabled) {
1596 #ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
1597         if (S60->brokenPointerCursors) {
1598             qt_symbian_set_pointer_sprite(Qt::ArrowCursor);
1599             qt_symbian_show_pointer_sprite();
1600         }
1601         else
1602 #endif
1603             S60->wsSession().SetPointerCursorMode(EPointerCursorNormal);
1604     }
1605 #endif
1606
1607     QFont systemFont;
1608     systemFont.setFamily(systemFont.defaultFamily());
1609     QApplicationPrivate::setSystemFont(systemFont);
1610
1611 #ifdef SYMBIAN_GRAPHICS_WSERV_QT_EFFECTS
1612     QObject::connect(qApp, SIGNAL(aboutToQuit()), qApp, SLOT(_q_aboutToQuit()));
1613 #endif
1614
1615 /*
1616  ### Commented out for now as parameter handling not needed in SOS(yet). Code below will break testlib with -o flag
1617     int argc = priv->argc;
1618     char **argv = priv->argv;
1619
1620     // Get command line params
1621     int j = argc ? 1 : 0;
1622     for (int i=1; i<argc; i++) {
1623         if (argv[i] && *argv[i] != '-') {
1624             argv[j++] = argv[i];
1625             continue;
1626         }
1627
1628 #if defined(QT_DEBUG)
1629         if (qstrcmp(argv[i], "-nograb") == 0)
1630             appNoGrab = !appNoGrab;
1631         else
1632 #endif // QT_DEBUG
1633             ;
1634     }
1635 */
1636
1637     // Register WId with the metatype system.  This is to enable
1638     // QWidgetPrivate::create_sys to used delayed slot invocation in order
1639     // to destroy WId objects during reparenting.
1640     qRegisterMetaType<WId>("WId");
1641 }
1642
1643 extern void qt_cleanup_symbianFontDatabase(); // qfontdatabase_s60.cpp
1644
1645 /*****************************************************************************
1646   qt_cleanup() - cleans up when the application is finished
1647  *****************************************************************************/
1648 void qt_cleanup()
1649 {
1650     if(qt_S60Beep) {
1651         delete qt_S60Beep;
1652         qt_S60Beep = 0;
1653     }
1654     QFontCache::cleanup(); // Has to happen now, since QFontEngineS60 has FBS handles
1655     QPixmapCache::clear(); // Has to happen now, since QS60PixmapData has FBS handles
1656
1657     qt_cleanup_symbianFontDatabase();
1658 // S60 structure and window server session are freed in eventdispatcher destructor as they are needed there
1659
1660     // It's important that this happens here, before the event dispatcher gets
1661     // deleted, because the input context needs the event loop one last time before
1662     // it dies.
1663     delete QApplicationPrivate::inputContext;
1664     QApplicationPrivate::inputContext = 0;
1665
1666     //Change mouse pointer back
1667     S60->wsSession().SetPointerCursorMode(EPointerCursorNone);
1668
1669 #ifdef Q_WS_S60
1670     // Clear CBA
1671     CEikonEnv::Static()->AppUiFactory()->SwapButtonGroup(0);
1672     delete S60->buttonGroupContainer();
1673     S60->setButtonGroupContainer(0);
1674 #endif
1675
1676     if (S60->qtOwnsS60Environment) {
1677         // Restore the S60 framework trap handler. See qt_init().
1678         User::SetTrapHandler(S60->s60InstalledTrapHandler);
1679
1680         CEikonEnv* coe = CEikonEnv::Static();
1681         coe->PrepareToExit();
1682         // The CEikonEnv itself is destroyed in here.
1683         coe->DestroyEnvironment();
1684     }
1685 }
1686
1687 void QApplicationPrivate::initializeWidgetPaletteHash()
1688 {
1689     // TODO: Implement QApplicationPrivate::initializeWidgetPaletteHash()
1690     // Possibly a task fot the S60Style guys
1691 }
1692
1693 void QApplicationPrivate::createEventDispatcher()
1694 {
1695     Q_Q(QApplication);
1696     eventDispatcher = new QEventDispatcherS60(q);
1697 }
1698
1699 QString QApplicationPrivate::appName() const
1700 {
1701     return QCoreApplicationPrivate::appName();
1702 }
1703
1704 bool QApplicationPrivate::modalState()
1705 {
1706     return app_do_modal;
1707 }
1708
1709 void QApplicationPrivate::enterModal_sys(QWidget *widget)
1710 {
1711 #ifdef SYMBIAN_GRAPHICS_WSERV_QT_EFFECTS
1712     S60->wsSession().SendEffectCommand(ETfxCmdAppModalModeEnter);
1713 #endif
1714     if (widget) {
1715         static_cast<QSymbianControl *>(widget->effectiveWinId())->FadeBehindPopup(ETrue);
1716         // Modal partial screen dialogs (like queries) capture pointer events.
1717         // ### FixMe: Add specialized behaviour for fullscreen modal dialogs
1718         widget->effectiveWinId()->SetGloballyCapturing(ETrue);
1719         widget->effectiveWinId()->SetPointerCapture(ETrue);
1720     }
1721     if (!qt_modal_stack)
1722         qt_modal_stack = new QWidgetList;
1723     qt_modal_stack->insert(0, widget);
1724     app_do_modal = true;
1725 }
1726
1727 void QApplicationPrivate::leaveModal_sys(QWidget *widget)
1728 {
1729 #ifdef SYMBIAN_GRAPHICS_WSERV_QT_EFFECTS
1730     S60->wsSession().SendEffectCommand(ETfxCmdAppModalModeExit);
1731 #endif
1732     if (widget) {
1733         static_cast<QSymbianControl *>(widget->effectiveWinId())->FadeBehindPopup(EFalse);
1734         // ### FixMe: Add specialized behaviour for fullscreen modal dialogs
1735         widget->effectiveWinId()->SetGloballyCapturing(EFalse);
1736         widget->effectiveWinId()->SetPointerCapture(EFalse);
1737     }
1738     if (qt_modal_stack && qt_modal_stack->removeAll(widget)) {
1739         if (qt_modal_stack->isEmpty()) {
1740             delete qt_modal_stack;
1741             qt_modal_stack = 0;
1742         }
1743     }
1744     app_do_modal = qt_modal_stack != 0;
1745 }
1746
1747 void QApplicationPrivate::openPopup(QWidget *popup)
1748 {
1749     if (popup && qobject_cast<QComboBox *>(popup->parentWidget()))
1750         static_cast<QSymbianControl *>(popup->effectiveWinId())->FadeBehindPopup(ETrue);
1751
1752     if (!QApplicationPrivate::popupWidgets)
1753         QApplicationPrivate::popupWidgets = new QWidgetList;
1754     QApplicationPrivate::popupWidgets->append(popup);
1755
1756     // Cancel focus widget pointer capture and long tap timer
1757     if (QApplication::focusWidget()) {
1758         static_cast<QSymbianControl*>(QApplication::focusWidget()->effectiveWinId())->CancelLongTapTimer();
1759         QApplication::focusWidget()->effectiveWinId()->SetPointerCapture(false);
1760         }
1761
1762     if (!qt_nograb()) {
1763         // Cancel pointer capture and long tap timer for earlier popup
1764         int popupCount = QApplicationPrivate::popupWidgets->count();
1765         if (popupCount > 1) {
1766             QWidget* prevPopup = QApplicationPrivate::popupWidgets->at(popupCount-2);
1767             static_cast<QSymbianControl*>(prevPopup->effectiveWinId())->CancelLongTapTimer();
1768             prevPopup->effectiveWinId()->SetPointerCapture(false);
1769         }
1770
1771         // Enable pointer capture for this (topmost) popup
1772         Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created));
1773         WId id = popup->effectiveWinId();
1774         id->SetPointerCapture(true);
1775     }
1776
1777     // popups are not focus-handled by the window system (the first
1778     // popup grabbed the keyboard), so we have to do that manually: A
1779     // new popup gets the focus
1780     QWidget *fw = popup->focusWidget();
1781     if (fw) {
1782         fw->setFocus(Qt::PopupFocusReason);
1783     } else if (QApplicationPrivate::popupWidgets->count() == 1) { // this was the first popup
1784         fw = QApplication::focusWidget();
1785         if (fw) {
1786             QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason);
1787             q_func()->sendEvent(fw, &e);
1788         }
1789     }
1790 }
1791
1792 void QApplicationPrivate::closePopup(QWidget *popup)
1793 {
1794     if (popup && qobject_cast<QComboBox *>(popup->parentWidget()))
1795         static_cast<QSymbianControl *>(popup->effectiveWinId())->FadeBehindPopup(EFalse);
1796
1797     if (!QApplicationPrivate::popupWidgets)
1798         return;
1799     QApplicationPrivate::popupWidgets->removeAll(popup);
1800
1801     // Cancel pointer capture and long tap for this popup
1802     WId id = popup->effectiveWinId();
1803     id->SetPointerCapture(false);
1804     static_cast<QSymbianControl*>(id)->CancelLongTapTimer();
1805
1806     if (QApplicationPrivate::popupWidgets->isEmpty()) { // this was the last popup
1807         delete QApplicationPrivate::popupWidgets;
1808         QApplicationPrivate::popupWidgets = 0;
1809         if (!qt_nograb()) {                        // grabbing not disabled
1810             Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created));
1811             if (QWidgetPrivate::mouseGrabber != 0)
1812                 QWidgetPrivate::mouseGrabber->grabMouse();
1813
1814             if (QWidgetPrivate::keyboardGrabber != 0)
1815                 QWidgetPrivate::keyboardGrabber->grabKeyboard();
1816
1817         QWidget *fw = QApplicationPrivate::active_window ? QApplicationPrivate::active_window->focusWidget()
1818               : q_func()->focusWidget();
1819           if (fw) {
1820               if(fw->window()->isModal()) // restore pointer capture for modal window
1821                   fw->effectiveWinId()->SetPointerCapture(true);
1822
1823               if (fw != q_func()->focusWidget()) {
1824                   fw->setFocus(Qt::PopupFocusReason);
1825               } else {
1826                   QFocusEvent e(QEvent::FocusIn, Qt::PopupFocusReason);
1827                   q_func()->sendEvent(fw, &e);
1828               }
1829           }
1830         }
1831     } else {
1832
1833         // popups are not focus-handled by the window system (the
1834         // first popup grabbed the keyboard), so we have to do that
1835         // manually: A popup was closed, so the previous popup gets
1836         // the focus.
1837         QWidget* aw = QApplicationPrivate::popupWidgets->last();
1838         if (QWidget *fw = QApplication::focusWidget()) {
1839             QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason);
1840             q_func()->sendEvent(fw, &e);
1841         }
1842
1843         // Enable pointer capture for previous popup
1844         if (aw) {
1845             aw->effectiveWinId()->SetPointerCapture(true);
1846         }
1847     }
1848 }
1849
1850 QWidget * QApplication::topLevelAt(QPoint const& point)
1851 {
1852     QWidget *found = 0;
1853     int lowestZ = INT_MAX;
1854     QWidgetList list = QApplication::topLevelWidgets();
1855     for (int i = 0; i < list.count(); ++i) {
1856         QWidget *widget = list.at(i);
1857         if (widget->isVisible() && !(widget->windowType() == Qt::Desktop)) {
1858             Q_ASSERT(widget->testAttribute(Qt::WA_WState_Created));
1859             if (widget->geometry().adjusted(0,0,1,1).contains(point)) {
1860                 // At this point we know there is a Qt widget under the point.
1861                 // Now we need to make sure it is the top most in the z-order.
1862                 RDrawableWindow *const window = widget->effectiveWinId()->DrawableWindow();
1863                 int z = window->OrdinalPosition();
1864                 if (z < lowestZ) {
1865                     lowestZ = z;
1866                     found = widget;
1867                 }
1868             }
1869         }
1870     }
1871     return found;
1872 }
1873
1874 void QApplication::alert(QWidget * /* widget */, int /* duration */)
1875 {
1876     // TODO: Implement QApplication::alert(QWidget *widget, int duration)
1877 }
1878
1879 int QApplication::doubleClickInterval()
1880 {
1881     TTimeIntervalMicroSeconds32 us;
1882     TInt distance;
1883     S60->wsSession().GetDoubleClickSettings(us, distance);
1884     return (us.Int() / 1000);
1885 }
1886
1887 void QApplication::setDoubleClickInterval(int ms)
1888 {
1889     TTimeIntervalMicroSeconds32 newUs( ms * 1000);
1890     TTimeIntervalMicroSeconds32 us;
1891     TInt distance;
1892     S60->wsSession().GetDoubleClickSettings(us, distance);
1893     if (us != newUs)
1894         S60->wsSession().SetDoubleClick(newUs, distance);
1895 }
1896
1897 int QApplication::keyboardInputInterval()
1898 {
1899     return QApplicationPrivate::keyboard_input_time;
1900 }
1901
1902 void QApplication::setKeyboardInputInterval(int ms)
1903 {
1904     QApplicationPrivate::keyboard_input_time = ms;
1905 }
1906
1907 int QApplication::cursorFlashTime()
1908 {
1909     return QApplicationPrivate::cursor_flash_time;
1910 }
1911
1912 void QApplication::setCursorFlashTime(int msecs)
1913 {
1914     QApplicationPrivate::cursor_flash_time = msecs;
1915 }
1916
1917 void QApplication::beep()
1918 {
1919     if (!qt_S60Beep) {
1920         TInt frequency = 880;
1921         TTimeIntervalMicroSeconds duration(500000);
1922         TRAP_IGNORE(qt_S60Beep=QS60Beep::NewL(frequency, duration));
1923     }
1924     if (qt_S60Beep)
1925         qt_S60Beep->Play();
1926 }
1927
1928 static inline bool callSymbianEventFilters(const QSymbianEvent *event)
1929 {
1930     long unused;
1931     return qApp->filterEvent(const_cast<QSymbianEvent *>(event), &unused);
1932 }
1933
1934 /*!
1935     \warning This function is only available on Symbian.
1936     \since 4.6
1937
1938     This function processes an individual Symbian event
1939     \a event. It returns 1 if the event was handled, 0 if
1940     the \a event was not handled, and -1 if the event was
1941     not handled because the event is not known to Qt.
1942  */
1943
1944 int QApplication::symbianProcessEvent(const QSymbianEvent *event)
1945 {
1946     Q_D(QApplication);
1947
1948     QScopedLoopLevelCounter counter(d->threadData);
1949
1950     if (d->eventDispatcher->filterEvent(const_cast<QSymbianEvent *>(event)))
1951         return 1;
1952
1953     QWidget *w = qApp ? qApp->focusWidget() : 0;
1954     if (w) {
1955         QInputContext *ic = w->inputContext();
1956         if (ic && ic->symbianFilterEvent(w, event))
1957             return 1;
1958     }
1959
1960     if (symbianEventFilter(event))
1961         return 1;
1962
1963     switch (event->type()) {
1964     case QSymbianEvent::WindowServerEvent:
1965         return d->symbianProcessWsEvent(event);
1966     case QSymbianEvent::CommandEvent:
1967         return d->symbianHandleCommand(event);
1968     case QSymbianEvent::ResourceChangeEvent:
1969         return d->symbianResourceChange(event);
1970     default:
1971         return -1;
1972     }
1973 }
1974
1975 int QApplicationPrivate::symbianProcessWsEvent(const QSymbianEvent *symbianEvent)
1976 {
1977     // Qt event handling. Handle some events regardless of if the handle is in our
1978     // widget map or not.
1979     const TWsEvent *event = symbianEvent->windowServerEvent();
1980     CCoeControl* control = reinterpret_cast<CCoeControl*>(event->Handle());
1981     const bool controlInMap = QWidgetPrivate::mapper && QWidgetPrivate::mapper->contains(control);
1982     switch (event->Type()) {
1983     case EEventPointerEnter:
1984         if (controlInMap) {
1985             callSymbianEventFilters(symbianEvent);
1986             return 1; // Qt::Enter will be generated in HandlePointerL
1987         }
1988         break;
1989     case EEventPointerExit:
1990         if (controlInMap) {
1991             if (callSymbianEventFilters(symbianEvent))
1992                 return 1;
1993             if (S60) {
1994                 // mouseEvent outside our window, send leave event to last focused widget
1995                 QMouseEvent mEvent(QEvent::Leave, S60->lastPointerEventPos, S60->lastCursorPos,
1996                     Qt::NoButton, QApplicationPrivate::mouse_buttons, Qt::NoModifier);
1997                 if (S60->lastPointerEventTarget)
1998                     qt_sendSpontaneousEvent(S60->lastPointerEventTarget,&mEvent);
1999                 S60->lastPointerEventTarget = 0;
2000             }
2001             return 1;
2002         }
2003         break;
2004     case EEventScreenDeviceChanged:
2005         if (callSymbianEventFilters(symbianEvent))
2006             return 1;
2007         if (S60)
2008             S60->updateScreenSize();
2009         if (qt_desktopWidget) {
2010             QSize oldSize = qt_desktopWidget->size();
2011             qt_desktopWidget->data->crect.setWidth(S60->screenWidthInPixels);
2012             qt_desktopWidget->data->crect.setHeight(S60->screenHeightInPixels);
2013             QResizeEvent e(qt_desktopWidget->size(), oldSize);
2014             QApplication::sendEvent(qt_desktopWidget, &e);
2015         }
2016         return 0; // Propagate to CONE
2017     case EEventWindowVisibilityChanged:
2018         if (controlInMap) {
2019             if (callSymbianEventFilters(symbianEvent))
2020                 return 1;
2021             const TWsVisibilityChangedEvent *visChangedEvent = event->VisibilityChanged();
2022             if (visChangedEvent->iFlags & TWsVisibilityChangedEvent::ENotVisible)
2023                 S60->controlVisibilityChanged(control, false);
2024             else if (visChangedEvent->iFlags & TWsVisibilityChangedEvent::EPartiallyVisible)
2025                 S60->controlVisibilityChanged(control, true);
2026             return 1;
2027         }
2028         break;
2029     case EEventFocusGained:
2030         if (callSymbianEventFilters(symbianEvent))
2031             return 1;
2032 #ifndef QT_NO_CURSOR
2033         //re-enable mouse interaction
2034         if (S60->mouseInteractionEnabled) {
2035 #ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
2036             if (S60->brokenPointerCursors)
2037                 qt_symbian_show_pointer_sprite();
2038             else
2039 #endif
2040                 S60->wsSession().SetPointerCursorMode(EPointerCursorNormal);
2041         }
2042 #endif
2043 #ifdef QT_SOFTKEYS_ENABLED
2044         QSoftKeyManager::updateSoftKeys();
2045 #endif
2046         break;
2047     case EEventFocusLost:
2048         if (callSymbianEventFilters(symbianEvent))
2049             return 1;
2050 #ifndef QT_NO_CURSOR
2051         //disable mouse as may be moving to application that does not support it
2052         if (S60->mouseInteractionEnabled) {
2053 #ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
2054             if (S60->brokenPointerCursors)
2055                 qt_symbian_hide_pointer_sprite();
2056             else
2057 #endif
2058                 S60->wsSession().SetPointerCursorMode(EPointerCursorNone);
2059         }
2060 #endif
2061         break;
2062     case KGoomMemoryLowEvent:
2063 #ifdef QT_DEBUG
2064         qDebug() << "QApplicationPrivate::symbianProcessWsEvent - KGoomMemoryLowEvent";
2065 #endif
2066         if (callSymbianEventFilters(symbianEvent))
2067             return 1;
2068 #ifdef QT_GRAPHICSSYSTEM_RUNTIME
2069         if(QApplicationPrivate::runtime_graphics_system) {
2070             bool switchToSwRendering(false);
2071
2072             foreach (QWidget *w, QApplication::topLevelWidgets()) {
2073                 if(w->d_func()->topData()->backingStore) {
2074                     switchToSwRendering = true;
2075                     break;
2076                 }
2077             }
2078
2079             if (switchToSwRendering) {
2080                 QRuntimeGraphicsSystem *gs =
2081                    static_cast<QRuntimeGraphicsSystem*>(QApplicationPrivate::graphics_system);
2082                 gs->setGraphicsSystem(QLatin1String("raster"));
2083             }
2084         }
2085 #endif
2086         break;
2087     case KGoomMemoryGoodEvent:
2088 #ifdef QT_DEBUG
2089         qDebug() << "QApplicationPrivate::symbianProcessWsEvent - KGoomMemoryGoodEvent";
2090 #endif
2091         if (callSymbianEventFilters(symbianEvent))
2092             return 1;
2093 #ifdef QT_GRAPHICSSYSTEM_RUNTIME
2094         if(QApplicationPrivate::runtime_graphics_system) {
2095             QRuntimeGraphicsSystem *gs =
2096                    static_cast<QRuntimeGraphicsSystem*>(QApplicationPrivate::graphics_system);
2097             gs->setGraphicsSystem(QLatin1String("openvg"));
2098         }
2099 #endif
2100         break;
2101 #ifdef Q_SYMBIAN_SUPPORTS_SURFACES
2102     case EEventUser:
2103         {
2104             // GOOM is looking for candidates to kill so indicate that we are
2105             // capable of cleaning up by handling this event
2106             TInt32 *data = reinterpret_cast<TInt32 *>(event->EventData());
2107             if (data[0] == EApaSystemEventShutdown && data[1] == KGoomMemoryLowEvent)
2108                 return 1;
2109         }
2110         break;
2111 #endif
2112     default:
2113         break;
2114     }
2115
2116     if (!controlInMap)
2117         return -1;
2118
2119     return 0;
2120 }
2121
2122 /*!
2123   \warning This virtual function is only available on Symbian.
2124   \since 4.6
2125
2126   If you create an application that inherits QApplication and reimplement
2127   this function, you get direct access to events that the are received
2128   from Symbian. The events are passed in the \a event parameter.
2129
2130   Return true if you want to stop the event from being processed. Return
2131   false for normal event dispatching. The default implementation returns
2132   false, and does nothing with \a event.
2133  */
2134 bool QApplication::symbianEventFilter(const QSymbianEvent *event)
2135 {
2136     Q_UNUSED(event);
2137     return false;
2138 }
2139
2140 /*!
2141   \warning This function is only available on Symbian.
2142   \since 4.6
2143
2144   Handles \a{command}s which are typically handled by
2145   CAknAppUi::HandleCommandL(). Qts Ui integration into Symbian is
2146   partially achieved by deriving from CAknAppUi. Currently, exit,
2147   menu and softkey commands are handled.
2148
2149   \sa s60EventFilter(), s60ProcessEvent()
2150 */
2151 int QApplicationPrivate::symbianHandleCommand(const QSymbianEvent *symbianEvent)
2152 {
2153     Q_Q(QApplication);
2154     int ret = 0;
2155
2156     if (callSymbianEventFilters(symbianEvent))
2157         return 1;
2158
2159     int command = symbianEvent->command();
2160
2161     switch (command) {
2162 #ifdef Q_WS_S60
2163     case EAknSoftkeyExit: {
2164         QCloseEvent ev;
2165         QApplication::sendSpontaneousEvent(q, &ev);
2166         if (ev.isAccepted()) {
2167             q->quit();
2168             ret = 1;
2169         }
2170         break;
2171     }
2172 #endif
2173     case EEikCmdExit:
2174         q->quit();
2175         ret = 1;
2176         break;
2177     default:
2178 #ifdef Q_WS_S60
2179         bool handled = QSoftKeyManager::handleCommand(command);
2180         if (handled)
2181             ret = 1;
2182         else
2183             ret = QMenuBarPrivate::symbianCommands(command);
2184 #endif
2185         break;
2186     }
2187
2188     return ret;
2189 }
2190
2191 /*!
2192   \warning This function is only available on Symbian.
2193   \since 4.6
2194
2195   Handles the resource change specified by \a type.
2196
2197   Currently, KEikDynamicLayoutVariantSwitch and
2198   KAknsMessageSkinChange are handled.
2199  */
2200 int QApplicationPrivate::symbianResourceChange(const QSymbianEvent *symbianEvent)
2201 {
2202     int ret = 0;
2203
2204     int type = symbianEvent->resourceChangeType();
2205
2206     switch (type) {
2207 #ifdef Q_WS_S60
2208     case KEikDynamicLayoutVariantSwitch:
2209         {
2210         if (callSymbianEventFilters(symbianEvent))
2211             return 1;
2212         if (S60)
2213             S60->updateScreenSize();
2214
2215 #ifndef QT_NO_STYLE_S60
2216         QS60Style *s60Style = 0;
2217
2218 #ifndef QT_NO_STYLE_STYLESHEET
2219         QStyleSheetStyle *proxy = qobject_cast<QStyleSheetStyle*>(QApplication::style());
2220         if (proxy)
2221             s60Style = qobject_cast<QS60Style*>(proxy->baseStyle());
2222         else
2223 #endif
2224             s60Style = qobject_cast<QS60Style*>(QApplication::style());
2225
2226         if (s60Style) {
2227             s60Style->d_func()->handleDynamicLayoutVariantSwitch();
2228             ret = 1;
2229         }
2230 #endif
2231         }
2232         break;
2233
2234 #ifndef QT_NO_STYLE_S60
2235     case KAknsMessageSkinChange:
2236         if (callSymbianEventFilters(symbianEvent))
2237             return 1;
2238         if (QS60Style *s60Style = qobject_cast<QS60Style*>(QApplication::style())) {
2239             s60Style->d_func()->handleSkinChange();
2240             ret = 1;
2241         }
2242         break;
2243 #endif
2244 #endif // Q_WS_S60
2245     default:
2246         break;
2247     }
2248
2249     return ret;
2250 }
2251
2252 #ifndef QT_NO_WHEELEVENT
2253 int QApplication::wheelScrollLines()
2254 {
2255     return QApplicationPrivate::wheel_scroll_lines;
2256 }
2257
2258 void QApplication::setWheelScrollLines(int n)
2259 {
2260     QApplicationPrivate::wheel_scroll_lines = n;
2261 }
2262 #endif //QT_NO_WHEELEVENT
2263
2264 bool QApplication::isEffectEnabled(Qt::UIEffect /* effect */)
2265 {
2266     // TODO: Implement QApplication::isEffectEnabled(Qt::UIEffect effect)
2267     return false;
2268 }
2269
2270 void QApplication::setEffectEnabled(Qt::UIEffect /* effect */, bool /* enable */)
2271 {
2272     // TODO: Implement QApplication::setEffectEnabled(Qt::UIEffect effect, bool enable)
2273 }
2274
2275 TUint QApplicationPrivate::resolveS60ScanCode(TInt scanCode, TUint keysym)
2276 {
2277     if (!scanCode)
2278         return keysym;
2279
2280     QApplicationPrivate *d = QApplicationPrivate::instance();
2281
2282     if (keysym) {
2283         // If keysym is specified, cache it.
2284         d->scanCodeCache.insert(scanCode, keysym);
2285         return keysym;
2286     } else {
2287         // If not, retrieve the cached version.
2288         return d->scanCodeCache[scanCode];
2289     }
2290 }
2291
2292 void QApplicationPrivate::initializeMultitouch_sys()
2293 {
2294 #ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
2295     if (HAL::Get(HALData::EPointer3DPressureSupported, pressureSupported) != KErrNone)
2296         pressureSupported = 0;
2297     if (HAL::Get(HALData::EPointer3DMaxPressure, maxTouchPressure) != KErrNone)
2298         maxTouchPressure = KMaxTInt;
2299 #else
2300     pressureSupported = 0;
2301     maxTouchPressure = KMaxTInt;
2302 #endif
2303 }
2304
2305 void QApplicationPrivate::cleanupMultitouch_sys()
2306 { }
2307
2308 #ifndef QT_NO_SESSIONMANAGER
2309 QSessionManager::QSessionManager(QApplication * /* app */, QString & /* id */, QString& /* key */)
2310 {
2311
2312 }
2313
2314 QSessionManager::~QSessionManager()
2315 {
2316
2317 }
2318
2319 bool QSessionManager::allowsInteraction()
2320 {
2321     return false;
2322 }
2323
2324 void QSessionManager::cancel()
2325 {
2326
2327 }
2328 #endif //QT_NO_SESSIONMANAGER
2329
2330 #ifdef QT_KEYPAD_NAVIGATION
2331 /*
2332  * Show/Hide the mouse cursor depending on phone type and chosen mode
2333  */
2334 void QApplicationPrivate::setNavigationMode(Qt::NavigationMode mode)
2335 {
2336 #ifndef QT_NO_CURSOR
2337     const bool wasCursorOn = (QApplicationPrivate::navigationMode == Qt::NavigationModeCursorAuto
2338         && !S60->hasTouchscreen)
2339         || QApplicationPrivate::navigationMode == Qt::NavigationModeCursorForceVisible;
2340     const bool isCursorOn = (mode == Qt::NavigationModeCursorAuto
2341         && !S60->hasTouchscreen)
2342         || mode == Qt::NavigationModeCursorForceVisible;
2343
2344     if (!wasCursorOn && isCursorOn) {
2345         //Show the cursor, when changing from another mode to cursor mode
2346         qt_symbian_set_cursor_visible(true);
2347     }
2348     else if (wasCursorOn && !isCursorOn) {
2349         //Hide the cursor, when leaving cursor mode
2350         qt_symbian_set_cursor_visible(false);
2351     }
2352 #endif
2353     QApplicationPrivate::navigationMode = mode;
2354 }
2355 #endif
2356
2357 #ifndef QT_NO_CURSOR
2358 /*****************************************************************************
2359  QApplication cursor stack
2360  *****************************************************************************/
2361
2362 void QApplication::setOverrideCursor(const QCursor &cursor)
2363 {
2364     qApp->d_func()->cursor_list.prepend(cursor);
2365     qt_symbian_setGlobalCursor(cursor);
2366 }
2367
2368 void QApplication::restoreOverrideCursor()
2369 {
2370     if (qApp->d_func()->cursor_list.isEmpty())
2371         return;
2372     qApp->d_func()->cursor_list.removeFirst();
2373
2374     if (!qApp->d_func()->cursor_list.isEmpty()) {
2375         qt_symbian_setGlobalCursor(qApp->d_func()->cursor_list.first());
2376     }
2377     else {
2378         //determine which widget has focus
2379         QWidget *w = QApplication::widgetAt(QCursor::pos());
2380 #ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
2381         if (S60->brokenPointerCursors) {
2382             qt_symbian_set_pointer_sprite(w ? w->cursor() : Qt::ArrowCursor);
2383         }
2384         else
2385 #endif
2386         {
2387             //because of the internals of window server, we need to force the cursor
2388             //to be set in all child windows too, otherwise when the cursor is over
2389             //the child window it may show a widget cursor or arrow cursor instead,
2390             //depending on construction order.
2391             QListIterator<WId> iter(QWidgetPrivate::mapper->uniqueKeys());
2392             while (iter.hasNext()) {
2393                 CCoeControl *ctrl = iter.next();
2394                 if(ctrl->OwnsWindow()) {
2395                     ctrl->DrawableWindow()->ClearPointerCursor();
2396                 }
2397             }
2398             if (w)
2399                 qt_symbian_setWindowCursor(w->cursor(), w->effectiveWinId());
2400             else
2401                 qt_symbian_setWindowGroupCursor(Qt::ArrowCursor, S60->windowGroup());
2402         }
2403     }
2404 }
2405
2406 #endif // QT_NO_CURSOR
2407
2408 void QApplicationPrivate::_q_aboutToQuit()
2409 {
2410 #ifdef SYMBIAN_GRAPHICS_WSERV_QT_EFFECTS
2411     // Send the shutdown tfx command
2412     S60->wsSession().SendEffectCommand(ETfxCmdAppShutDown);
2413 #endif
2414 }
2415
2416 QS60ThreadLocalData::QS60ThreadLocalData()
2417 {
2418     CCoeEnv *env = CCoeEnv::Static();
2419     if (env) {
2420         //if this is the UI thread, share objects owned by CONE
2421         usingCONEinstances = true;
2422         wsSession = env->WsSession();
2423         screenDevice = env->ScreenDevice();
2424     }
2425     else {
2426         usingCONEinstances = false;
2427         qt_symbian_throwIfError(wsSession.Connect(qt_s60GetRFs()));
2428         screenDevice = new CWsScreenDevice(wsSession);
2429         screenDevice->Construct();
2430     }
2431 }
2432
2433 QS60ThreadLocalData::~QS60ThreadLocalData()
2434 {
2435     if (!usingCONEinstances) {
2436         delete screenDevice;
2437         wsSession.Close();
2438     }
2439 }
2440
2441 QT_END_NAMESPACE