Supporting Qt application fonts on Symbian
[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 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "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 widget is fullscreen/minimized, hide status pane and button container otherwise show them.
1247         QWidget *const window = qwidget->window();
1248         const bool visible = !(window->windowState() & (Qt::WindowFullScreen | Qt::WindowMinimized));
1249         const bool statusPaneVisibility = visible;
1250         const bool isFullscreen = window->windowState() & Qt::WindowFullScreen;
1251         const bool cbaVisibilityHint = window->windowFlags() & Qt::WindowSoftkeysVisibleHint;
1252         const bool buttonGroupVisibility = (visible || (isFullscreen && cbaVisibilityHint));
1253         S60->setStatusPaneAndButtonGroupVisibility(statusPaneVisibility, buttonGroupVisibility);
1254 #endif
1255     } else if (QApplication::activeWindow() == qwidget->window()) {
1256         bool focusedControlFound = false;
1257         WId winId = 0;
1258         for (QWidget *w = qwidget->parentWidget(); w && (winId = w->internalWinId()); w = w->parentWidget()) {
1259             if (winId->IsFocused() && winId->IsVisible()) {
1260                 focusedControlFound = true;
1261                 break;
1262             } else if (w->isWindow())
1263                 break;
1264         }
1265         if (!focusedControlFound) {
1266             if (CCoeEnv::Static()->AppUi()->IsDisplayingMenuOrDialog() || S60->menuBeingConstructed) {
1267                 QWidget *fw = QApplication::focusWidget();
1268                 if (fw) {
1269                     QFocusEvent event(QEvent::FocusOut, Qt::PopupFocusReason);
1270                     QCoreApplication::sendEvent(fw, &event);
1271                 }
1272                 m_symbianPopupIsOpen = true;
1273                 return;
1274             }
1275
1276             QApplication::setActiveWindow(0);
1277         }
1278     }
1279     // else { We don't touch the active window unless we were explicitly activated or deactivated }
1280 }
1281
1282 void QSymbianControl::handleClientAreaChange()
1283 {
1284     const bool cbaVisibilityHint = qwidget->windowFlags() & Qt::WindowSoftkeysVisibleHint;
1285     if (qwidget->isFullScreen() && !cbaVisibilityHint) {
1286         SetExtentToWholeScreen();
1287     } else if (qwidget->isMaximized() || (qwidget->isFullScreen() && cbaVisibilityHint)) {
1288         TRect r = static_cast<CEikAppUi*>(S60->appUi())->ClientRect();
1289         SetExtent(r.iTl, r.Size());
1290     } else if (!qwidget->isMinimized()) { // Normal geometry
1291         if (!qwidget->testAttribute(Qt::WA_Resized)) {
1292             qwidget->adjustSize();
1293             qwidget->setAttribute(Qt::WA_Resized, false); //not a user resize
1294         }
1295         if (!qwidget->testAttribute(Qt::WA_Moved) && qwidget->windowType() != Qt::Dialog) {
1296             TRect r = static_cast<CEikAppUi*>(S60->appUi())->ClientRect();
1297             SetPosition(r.iTl);
1298             qwidget->setAttribute(Qt::WA_Moved, false); // not really an explicit position
1299         }
1300     }
1301 }
1302
1303 void QSymbianControl::HandleResourceChange(int resourceType)
1304 {
1305     switch (resourceType) {
1306     case KInternalStatusPaneChange:
1307         handleClientAreaChange();
1308         if (IsFocused() && IsVisible()) {
1309             qwidget->d_func()->setWindowIcon_sys(true);
1310             qwidget->d_func()->setWindowTitle_sys(qwidget->windowTitle());
1311         }
1312         break;
1313     case KUidValueCoeFontChangeEvent:
1314         // font change event
1315         break;
1316 #ifdef Q_WS_S60
1317     case KEikDynamicLayoutVariantSwitch:
1318     {
1319         handleClientAreaChange();
1320         // Send resize event to trigger desktopwidget workAreaResized signal
1321         QResizeEvent e(qt_desktopWidget->size(), qt_desktopWidget->size());
1322         QApplication::sendEvent(qt_desktopWidget, &e);
1323         break;
1324     }
1325 #endif
1326     default:
1327         break;
1328     }
1329
1330     CCoeControl::HandleResourceChange(resourceType);
1331
1332 }
1333 void QSymbianControl::CancelLongTapTimer()
1334 {
1335     m_longTapDetector->Cancel();
1336 }
1337
1338 TTypeUid::Ptr QSymbianControl::MopSupplyObject(TTypeUid id)
1339 {
1340     if (id.iUid == ETypeId)
1341         return id.MakePtr(this);
1342
1343     return CCoeControl::MopSupplyObject(id);
1344 }
1345
1346 void QSymbianControl::setFocusSafely(bool focus)
1347 {
1348     // The stack hack in here is very unfortunate, but it is the only way to ensure proper
1349     // focus in Symbian. If this is not executed, the control which happens to be on
1350     // the top of the stack may randomly be assigned focus by Symbian, for example
1351     // when creating new windows (specifically in CCoeAppUi::HandleStackChanged()).
1352
1353     // Close any popups.
1354     CEikonEnv::Static()->EikAppUi()->StopDisplayingMenuBar();
1355
1356     if (focus) {
1357         S60->appUi()->RemoveFromStack(this);
1358         // Symbian doesn't automatically remove focus from the last focused control, so we need to
1359         // remember it and clear focus ourselves.
1360         if (lastFocusedControl && lastFocusedControl != this)
1361             lastFocusedControl->SetFocus(false);
1362         QT_TRAP_THROWING(S60->appUi()->AddToStackL(this,
1363                 ECoeStackPriorityDefault + 1, ECoeStackFlagStandard)); // Note the + 1
1364         lastFocusedControl = this;
1365         this->SetFocus(true);
1366     } else {
1367         S60->appUi()->RemoveFromStack(this);
1368         QT_TRAP_THROWING(S60->appUi()->AddToStackL(this,
1369                 ECoeStackPriorityDefault, ECoeStackFlagStandard));
1370         if(this == lastFocusedControl)
1371             lastFocusedControl = 0;
1372         this->SetFocus(false);
1373     }
1374 }
1375
1376 bool QSymbianControl::isControlActive()
1377 {
1378     return IsActivated() ? true : false;
1379 }
1380
1381 /*!
1382     \typedef QApplication::QS60MainApplicationFactory
1383     \since 4.6
1384
1385     This is a typedef for a pointer to a function with the following
1386     signature:
1387
1388     \snippet doc/src/snippets/code/src_corelib_global_qglobal.cpp 47
1389
1390     \sa QApplication::QApplication()
1391 */
1392
1393 /*!
1394     \since 4.6
1395
1396     Creates an application using the application factory given in
1397     \a factory, and using \a argc command line arguments in \a argv.
1398     \a factory can be leaving, but the error will be converted to a
1399     standard exception.
1400
1401     This function is only available on S60.
1402 */
1403 QApplication::QApplication(QApplication::QS60MainApplicationFactory factory, int &argc, char **argv)
1404     : QCoreApplication(*new QApplicationPrivate(argc, argv, GuiClient))
1405 {
1406     Q_D(QApplication);
1407     S60->s60ApplicationFactory = factory;
1408     d->construct();
1409 }
1410
1411 QApplication::QApplication(QApplication::QS60MainApplicationFactory factory, int &argc, char **argv, int _internal)
1412     : QCoreApplication(*new QApplicationPrivate(argc, argv, GuiClient))
1413 {
1414     Q_D(QApplication);
1415     S60->s60ApplicationFactory = factory;
1416     d->construct();
1417     QApplicationPrivate::app_compile_version = _internal;
1418 }
1419
1420 void qt_init(QApplicationPrivate * /* priv */, int)
1421 {
1422     if (!CCoeEnv::Static()) {
1423         // The S60 framework creates a new trap handler which will render any existing traps
1424         // invalid as long as it is active. This means that all code in main() that occurs after
1425         // the QApplication construction needs to be surrounded by a new trap, despite having
1426         // an outer one already. To avoid this, we save the original trap handler here, and set
1427         // it back after the S60 framework is constructed. Then we restore it right before the S60
1428         // framework destruction.
1429         TTrapHandler *origTrapHandler = User::TrapHandler();
1430
1431         // The S60 framework has not been initialized. We need to do it.
1432         TApaApplicationFactory factory(S60->s60ApplicationFactory ?
1433                 S60->s60ApplicationFactory : newS60Application);
1434         CApaCommandLine* commandLine = 0;
1435         TInt err = CApaCommandLine::GetCommandLineFromProcessEnvironment(commandLine);
1436         // After this construction, CEikonEnv will be available from CEikonEnv::Static().
1437         // (much like our qApp).
1438         QtEikonEnv* coe = new QtEikonEnv;
1439         //not using QT_TRAP_THROWING, because coe owns the cleanupstack so it can't be pushed there.
1440         if(err == KErrNone)
1441             TRAP(err, coe->ConstructAppFromCommandLineL(factory,*commandLine));
1442         delete commandLine;
1443         if(err != KErrNone) {
1444             qWarning() << "qt_init: Eikon application construct failed ("
1445                        << err
1446                        << "), maybe missing resource file on S60 3.1?";
1447             delete coe;
1448             qt_symbian_throwIfError(err);
1449         }
1450
1451         S60->s60InstalledTrapHandler = User::SetTrapHandler(origTrapHandler);
1452
1453         S60->qtOwnsS60Environment = true;
1454     } else {
1455         S60->qtOwnsS60Environment = false;
1456     }
1457
1458 #ifdef QT_NO_DEBUG
1459     if (!qgetenv("QT_S60_AUTO_FLUSH_WSERV").isEmpty())
1460 #endif
1461         S60->wsSession().SetAutoFlush(ETrue);
1462
1463 #ifdef Q_SYMBIAN_WINDOW_SIZE_CACHE
1464     TRAP_IGNORE(S60->wsSession().EnableWindowSizeCacheL());
1465 #endif
1466
1467     S60->updateScreenSize();
1468
1469
1470     TDisplayMode mode = S60->screenDevice()->DisplayMode();
1471     S60->screenDepth = TDisplayModeUtils::NumDisplayModeBitsPerPixel(mode);
1472
1473     //NB: RWsSession::GetColorModeList tells you what window modes are supported,
1474     //not what bitmap formats.
1475     if(QSysInfo::symbianVersion() == QSysInfo::SV_9_2)
1476         S60->supportsPremultipliedAlpha = 0;
1477     else
1478         S60->supportsPremultipliedAlpha = 1;
1479
1480     RProcess me;
1481     TSecureId securId = me.SecureId();
1482     S60->uid = securId.operator TUid();
1483
1484     // enable focus events - used to re-enable mouse after focus changed between mouse and non mouse app,
1485     // and for dimming behind modal windows
1486     S60->windowGroup().EnableFocusChangeEvents();
1487
1488     //Check if mouse interaction is supported (either EMouse=1 in the HAL, or EMachineUID is one of the phones known to support this)
1489     const TInt KMachineUidSamsungI8510 = 0x2000C51E;
1490     // HAL::Get(HALData::EPen, TInt& result) may set 'result' to 1 on some 3.1 systems (e.g. N95).
1491     // But we know that S60 systems below 5.0 did not support touch.
1492     static const bool touchIsUnsupportedOnSystem =
1493         QSysInfo::s60Version() == QSysInfo::SV_S60_3_1
1494         || QSysInfo::s60Version() == QSysInfo::SV_S60_3_2;
1495     TInt machineUID;
1496     TInt mouse;
1497     TInt touch;
1498     TInt err;
1499     err = HAL::Get(HALData::EMouse, mouse);
1500     if (err != KErrNone)
1501         mouse = 0;
1502     err = HAL::Get(HALData::EMachineUid, machineUID);
1503     if (err != KErrNone)
1504         machineUID = 0;
1505     err = HAL::Get(HALData::EPen, touch);
1506     if (err != KErrNone || touchIsUnsupportedOnSystem)
1507         touch = 0;
1508 #ifdef __WINS__
1509     if(QSysInfo::symbianVersion() <= QSysInfo::SV_9_4) {
1510         //for symbian SDK emulator, force values to match typical devices.
1511         mouse = 0;
1512         touch = touchIsUnsupportedOnSystem ? 0 : 1;
1513     }
1514 #endif
1515     if (mouse || machineUID == KMachineUidSamsungI8510) {
1516         S60->hasTouchscreen = false;
1517         S60->virtualMouseRequired = false;
1518     }
1519     else if (!touch) {
1520         S60->hasTouchscreen = false;
1521         S60->virtualMouseRequired = true;
1522     }
1523     else {
1524         S60->hasTouchscreen = true;
1525         S60->virtualMouseRequired = false;
1526     }
1527
1528     S60->avkonComponentsSupportTransparency = false;
1529     S60->menuBeingConstructed = false;
1530
1531 #ifdef Q_WS_S60
1532     TUid KCRUidAvkon = { 0x101F876E };
1533     TUint32 KAknAvkonTransparencyEnabled = 0x0000000D;
1534
1535     CRepository* repository = 0;
1536     TRAP(err, repository = CRepository::NewL(KCRUidAvkon));
1537
1538     if(err == KErrNone) {
1539         TInt value = 0;
1540         err = repository->Get(KAknAvkonTransparencyEnabled, value);
1541         if(err == KErrNone) {
1542             S60->avkonComponentsSupportTransparency = (value==1) ? true : false;
1543         }
1544     }
1545     delete repository;
1546     repository = 0;
1547 #endif
1548
1549 #ifdef QT_KEYPAD_NAVIGATION
1550     if (touch) {
1551         QApplicationPrivate::navigationMode = Qt::NavigationModeNone;
1552     } else {
1553         QApplicationPrivate::navigationMode = Qt::NavigationModeKeypadDirectional;
1554     }
1555 #endif
1556
1557 #ifndef QT_NO_CURSOR
1558     //Check if window server pointer cursors are supported or not
1559 #ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
1560     //In generic binary, use the HAL and OS version
1561     //Any other known good phones should be added here.
1562     if (machineUID == KMachineUidSamsungI8510 || (QSysInfo::symbianVersion() != QSysInfo::SV_9_4
1563         && QSysInfo::symbianVersion() != QSysInfo::SV_9_3 && QSysInfo::symbianVersion()
1564         != QSysInfo::SV_9_2)) {
1565         S60->brokenPointerCursors = false;
1566         qt_symbian_setWindowGroupCursor(Qt::ArrowCursor, S60->windowGroup());
1567     }
1568     else
1569         S60->brokenPointerCursors = true;
1570 #endif
1571
1572     if (S60->mouseInteractionEnabled) {
1573 #ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
1574         if (S60->brokenPointerCursors) {
1575             qt_symbian_set_pointer_sprite(Qt::ArrowCursor);
1576             qt_symbian_show_pointer_sprite();
1577         }
1578         else
1579 #endif
1580             S60->wsSession().SetPointerCursorMode(EPointerCursorNormal);
1581     }
1582 #endif
1583
1584     QFont systemFont;
1585     systemFont.setFamily(systemFont.defaultFamily());
1586     QApplicationPrivate::setSystemFont(systemFont);
1587
1588 #ifdef SYMBIAN_GRAPHICS_WSERV_QT_EFFECTS
1589     QObject::connect(qApp, SIGNAL(aboutToQuit()), qApp, SLOT(_q_aboutToQuit()));
1590 #endif
1591
1592 /*
1593  ### Commented out for now as parameter handling not needed in SOS(yet). Code below will break testlib with -o flag
1594     int argc = priv->argc;
1595     char **argv = priv->argv;
1596
1597     // Get command line params
1598     int j = argc ? 1 : 0;
1599     for (int i=1; i<argc; i++) {
1600         if (argv[i] && *argv[i] != '-') {
1601             argv[j++] = argv[i];
1602             continue;
1603         }
1604
1605 #if defined(QT_DEBUG)
1606         if (qstrcmp(argv[i], "-nograb") == 0)
1607             appNoGrab = !appNoGrab;
1608         else
1609 #endif // QT_DEBUG
1610             ;
1611     }
1612 */
1613
1614     // Register WId with the metatype system.  This is to enable
1615     // QWidgetPrivate::create_sys to used delayed slot invocation in order
1616     // to destroy WId objects during reparenting.
1617     qRegisterMetaType<WId>("WId");
1618 }
1619
1620 extern void qt_cleanup_symbianFontDatabase(); // qfontdatabase_s60.cpp
1621
1622 /*****************************************************************************
1623   qt_cleanup() - cleans up when the application is finished
1624  *****************************************************************************/
1625 void qt_cleanup()
1626 {
1627     if(qt_S60Beep) {
1628         delete qt_S60Beep;
1629         qt_S60Beep = 0;
1630     }
1631     QFontCache::cleanup(); // Has to happen now, since QFontEngineS60 has FBS handles
1632     QPixmapCache::clear(); // Has to happen now, since QS60PixmapData has FBS handles
1633
1634     qt_cleanup_symbianFontDatabase();
1635 // S60 structure and window server session are freed in eventdispatcher destructor as they are needed there
1636
1637     // It's important that this happens here, before the event dispatcher gets
1638     // deleted, because the input context needs the event loop one last time before
1639     // it dies.
1640     delete QApplicationPrivate::inputContext;
1641     QApplicationPrivate::inputContext = 0;
1642
1643     //Change mouse pointer back
1644     S60->wsSession().SetPointerCursorMode(EPointerCursorNone);
1645
1646 #ifdef Q_WS_S60
1647     // Clear CBA
1648     CEikonEnv::Static()->AppUiFactory()->SwapButtonGroup(0);
1649     delete S60->buttonGroupContainer();
1650     S60->setButtonGroupContainer(0);
1651 #endif
1652
1653     if (S60->qtOwnsS60Environment) {
1654         // Restore the S60 framework trap handler. See qt_init().
1655         User::SetTrapHandler(S60->s60InstalledTrapHandler);
1656
1657         CEikonEnv* coe = CEikonEnv::Static();
1658         coe->PrepareToExit();
1659         // The CEikonEnv itself is destroyed in here.
1660         coe->DestroyEnvironment();
1661     }
1662 }
1663
1664 void QApplicationPrivate::initializeWidgetPaletteHash()
1665 {
1666     // TODO: Implement QApplicationPrivate::initializeWidgetPaletteHash()
1667     // Possibly a task fot the S60Style guys
1668 }
1669
1670 void QApplicationPrivate::createEventDispatcher()
1671 {
1672     Q_Q(QApplication);
1673     eventDispatcher = new QEventDispatcherS60(q);
1674 }
1675
1676 QString QApplicationPrivate::appName() const
1677 {
1678     return QCoreApplicationPrivate::appName();
1679 }
1680
1681 bool QApplicationPrivate::modalState()
1682 {
1683     return app_do_modal;
1684 }
1685
1686 void QApplicationPrivate::enterModal_sys(QWidget *widget)
1687 {
1688 #ifdef SYMBIAN_GRAPHICS_WSERV_QT_EFFECTS
1689     S60->wsSession().SendEffectCommand(ETfxCmdAppModalModeEnter);
1690 #endif
1691     if (widget) {
1692         static_cast<QSymbianControl *>(widget->effectiveWinId())->FadeBehindPopup(ETrue);
1693         // Modal partial screen dialogs (like queries) capture pointer events.
1694         // ### FixMe: Add specialized behaviour for fullscreen modal dialogs
1695         widget->effectiveWinId()->SetGloballyCapturing(ETrue);
1696         widget->effectiveWinId()->SetPointerCapture(ETrue);
1697     }
1698     if (!qt_modal_stack)
1699         qt_modal_stack = new QWidgetList;
1700     qt_modal_stack->insert(0, widget);
1701     app_do_modal = true;
1702 }
1703
1704 void QApplicationPrivate::leaveModal_sys(QWidget *widget)
1705 {
1706 #ifdef SYMBIAN_GRAPHICS_WSERV_QT_EFFECTS
1707     S60->wsSession().SendEffectCommand(ETfxCmdAppModalModeExit);
1708 #endif
1709     if (widget) {
1710         static_cast<QSymbianControl *>(widget->effectiveWinId())->FadeBehindPopup(EFalse);
1711         // ### FixMe: Add specialized behaviour for fullscreen modal dialogs
1712         widget->effectiveWinId()->SetGloballyCapturing(EFalse);
1713         widget->effectiveWinId()->SetPointerCapture(EFalse);
1714     }
1715     if (qt_modal_stack && qt_modal_stack->removeAll(widget)) {
1716         if (qt_modal_stack->isEmpty()) {
1717             delete qt_modal_stack;
1718             qt_modal_stack = 0;
1719         }
1720     }
1721     app_do_modal = qt_modal_stack != 0;
1722 }
1723
1724 void QApplicationPrivate::openPopup(QWidget *popup)
1725 {
1726     if (popup && qobject_cast<QComboBox *>(popup->parentWidget()))
1727         static_cast<QSymbianControl *>(popup->effectiveWinId())->FadeBehindPopup(ETrue);
1728
1729     if (!QApplicationPrivate::popupWidgets)
1730         QApplicationPrivate::popupWidgets = new QWidgetList;
1731     QApplicationPrivate::popupWidgets->append(popup);
1732
1733     // Cancel focus widget pointer capture and long tap timer
1734     if (QApplication::focusWidget()) {
1735         static_cast<QSymbianControl*>(QApplication::focusWidget()->effectiveWinId())->CancelLongTapTimer();
1736         QApplication::focusWidget()->effectiveWinId()->SetPointerCapture(false);
1737         }
1738
1739     if (!qt_nograb()) {
1740         // Cancel pointer capture and long tap timer for earlier popup
1741         int popupCount = QApplicationPrivate::popupWidgets->count();
1742         if (popupCount > 1) {
1743             QWidget* prevPopup = QApplicationPrivate::popupWidgets->at(popupCount-2);
1744             static_cast<QSymbianControl*>(prevPopup->effectiveWinId())->CancelLongTapTimer();
1745             prevPopup->effectiveWinId()->SetPointerCapture(false);
1746         }
1747
1748         // Enable pointer capture for this (topmost) popup
1749         Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created));
1750         WId id = popup->effectiveWinId();
1751         id->SetPointerCapture(true);
1752     }
1753
1754     // popups are not focus-handled by the window system (the first
1755     // popup grabbed the keyboard), so we have to do that manually: A
1756     // new popup gets the focus
1757     QWidget *fw = popup->focusWidget();
1758     if (fw) {
1759         fw->setFocus(Qt::PopupFocusReason);
1760     } else if (QApplicationPrivate::popupWidgets->count() == 1) { // this was the first popup
1761         fw = QApplication::focusWidget();
1762         if (fw) {
1763             QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason);
1764             q_func()->sendEvent(fw, &e);
1765         }
1766     }
1767 }
1768
1769 void QApplicationPrivate::closePopup(QWidget *popup)
1770 {
1771     if (popup && qobject_cast<QComboBox *>(popup->parentWidget()))
1772         static_cast<QSymbianControl *>(popup->effectiveWinId())->FadeBehindPopup(EFalse);
1773
1774     if (!QApplicationPrivate::popupWidgets)
1775         return;
1776     QApplicationPrivate::popupWidgets->removeAll(popup);
1777
1778     // Cancel pointer capture and long tap for this popup
1779     WId id = popup->effectiveWinId();
1780     id->SetPointerCapture(false);
1781     static_cast<QSymbianControl*>(id)->CancelLongTapTimer();
1782
1783     if (QApplicationPrivate::popupWidgets->isEmpty()) { // this was the last popup
1784         delete QApplicationPrivate::popupWidgets;
1785         QApplicationPrivate::popupWidgets = 0;
1786         if (!qt_nograb()) {                        // grabbing not disabled
1787             Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created));
1788             if (QWidgetPrivate::mouseGrabber != 0)
1789                 QWidgetPrivate::mouseGrabber->grabMouse();
1790
1791             if (QWidgetPrivate::keyboardGrabber != 0)
1792                 QWidgetPrivate::keyboardGrabber->grabKeyboard();
1793
1794         QWidget *fw = QApplicationPrivate::active_window ? QApplicationPrivate::active_window->focusWidget()
1795               : q_func()->focusWidget();
1796           if (fw) {
1797               if(fw->window()->isModal()) // restore pointer capture for modal window
1798                   fw->effectiveWinId()->SetPointerCapture(true);
1799
1800               if (fw != q_func()->focusWidget()) {
1801                   fw->setFocus(Qt::PopupFocusReason);
1802               } else {
1803                   QFocusEvent e(QEvent::FocusIn, Qt::PopupFocusReason);
1804                   q_func()->sendEvent(fw, &e);
1805               }
1806           }
1807         }
1808     } else {
1809
1810         // popups are not focus-handled by the window system (the
1811         // first popup grabbed the keyboard), so we have to do that
1812         // manually: A popup was closed, so the previous popup gets
1813         // the focus.
1814         QWidget* aw = QApplicationPrivate::popupWidgets->last();
1815         if (QWidget *fw = QApplication::focusWidget()) {
1816             QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason);
1817             q_func()->sendEvent(fw, &e);
1818         }
1819
1820         // Enable pointer capture for previous popup
1821         if (aw) {
1822             aw->effectiveWinId()->SetPointerCapture(true);
1823         }
1824     }
1825 }
1826
1827 QWidget * QApplication::topLevelAt(QPoint const& point)
1828 {
1829     QWidget *found = 0;
1830     int lowestZ = INT_MAX;
1831     QWidgetList list = QApplication::topLevelWidgets();
1832     for (int i = 0; i < list.count(); ++i) {
1833         QWidget *widget = list.at(i);
1834         if (widget->isVisible() && !(widget->windowType() == Qt::Desktop)) {
1835             Q_ASSERT(widget->testAttribute(Qt::WA_WState_Created));
1836             if (widget->geometry().adjusted(0,0,1,1).contains(point)) {
1837                 // At this point we know there is a Qt widget under the point.
1838                 // Now we need to make sure it is the top most in the z-order.
1839                 RDrawableWindow *const window = widget->effectiveWinId()->DrawableWindow();
1840                 int z = window->OrdinalPosition();
1841                 if (z < lowestZ) {
1842                     lowestZ = z;
1843                     found = widget;
1844                 }
1845             }
1846         }
1847     }
1848     return found;
1849 }
1850
1851 void QApplication::alert(QWidget * /* widget */, int /* duration */)
1852 {
1853     // TODO: Implement QApplication::alert(QWidget *widget, int duration)
1854 }
1855
1856 int QApplication::doubleClickInterval()
1857 {
1858     TTimeIntervalMicroSeconds32 us;
1859     TInt distance;
1860     S60->wsSession().GetDoubleClickSettings(us, distance);
1861     return (us.Int() / 1000);
1862 }
1863
1864 void QApplication::setDoubleClickInterval(int ms)
1865 {
1866     TTimeIntervalMicroSeconds32 newUs( ms * 1000);
1867     TTimeIntervalMicroSeconds32 us;
1868     TInt distance;
1869     S60->wsSession().GetDoubleClickSettings(us, distance);
1870     if (us != newUs)
1871         S60->wsSession().SetDoubleClick(newUs, distance);
1872 }
1873
1874 int QApplication::keyboardInputInterval()
1875 {
1876     return QApplicationPrivate::keyboard_input_time;
1877 }
1878
1879 void QApplication::setKeyboardInputInterval(int ms)
1880 {
1881     QApplicationPrivate::keyboard_input_time = ms;
1882 }
1883
1884 int QApplication::cursorFlashTime()
1885 {
1886     return QApplicationPrivate::cursor_flash_time;
1887 }
1888
1889 void QApplication::setCursorFlashTime(int msecs)
1890 {
1891     QApplicationPrivate::cursor_flash_time = msecs;
1892 }
1893
1894 void QApplication::beep()
1895 {
1896     if (!qt_S60Beep) {
1897         TInt frequency = 880;
1898         TTimeIntervalMicroSeconds duration(500000);
1899         TRAP_IGNORE(qt_S60Beep=QS60Beep::NewL(frequency, duration));
1900     }
1901     if (qt_S60Beep)
1902         qt_S60Beep->Play();
1903 }
1904
1905 static inline bool callSymbianEventFilters(const QSymbianEvent *event)
1906 {
1907     long unused;
1908     return qApp->filterEvent(const_cast<QSymbianEvent *>(event), &unused);
1909 }
1910
1911 /*!
1912     \warning This function is only available on Symbian.
1913     \since 4.6
1914
1915     This function processes an individual Symbian event
1916     \a event. It returns 1 if the event was handled, 0 if
1917     the \a event was not handled, and -1 if the event was
1918     not handled because the event is not known to Qt.
1919  */
1920
1921 int QApplication::symbianProcessEvent(const QSymbianEvent *event)
1922 {
1923     Q_D(QApplication);
1924
1925     QScopedLoopLevelCounter counter(d->threadData);
1926
1927     if (d->eventDispatcher->filterEvent(const_cast<QSymbianEvent *>(event)))
1928         return 1;
1929
1930     QWidget *w = qApp ? qApp->focusWidget() : 0;
1931     if (w) {
1932         QInputContext *ic = w->inputContext();
1933         if (ic && ic->symbianFilterEvent(w, event))
1934             return 1;
1935     }
1936
1937     if (symbianEventFilter(event))
1938         return 1;
1939
1940     switch (event->type()) {
1941     case QSymbianEvent::WindowServerEvent:
1942         return d->symbianProcessWsEvent(event);
1943     case QSymbianEvent::CommandEvent:
1944         return d->symbianHandleCommand(event);
1945     case QSymbianEvent::ResourceChangeEvent:
1946         return d->symbianResourceChange(event);
1947     default:
1948         return -1;
1949     }
1950 }
1951
1952 int QApplicationPrivate::symbianProcessWsEvent(const QSymbianEvent *symbianEvent)
1953 {
1954     // Qt event handling. Handle some events regardless of if the handle is in our
1955     // widget map or not.
1956     const TWsEvent *event = symbianEvent->windowServerEvent();
1957     CCoeControl* control = reinterpret_cast<CCoeControl*>(event->Handle());
1958     const bool controlInMap = QWidgetPrivate::mapper && QWidgetPrivate::mapper->contains(control);
1959     switch (event->Type()) {
1960     case EEventPointerEnter:
1961         if (controlInMap) {
1962             callSymbianEventFilters(symbianEvent);
1963             return 1; // Qt::Enter will be generated in HandlePointerL
1964         }
1965         break;
1966     case EEventPointerExit:
1967         if (controlInMap) {
1968             if (callSymbianEventFilters(symbianEvent))
1969                 return 1;
1970             if (S60) {
1971                 // mouseEvent outside our window, send leave event to last focused widget
1972                 QMouseEvent mEvent(QEvent::Leave, S60->lastPointerEventPos, S60->lastCursorPos,
1973                     Qt::NoButton, QApplicationPrivate::mouse_buttons, Qt::NoModifier);
1974                 if (S60->lastPointerEventTarget)
1975                     qt_sendSpontaneousEvent(S60->lastPointerEventTarget,&mEvent);
1976                 S60->lastPointerEventTarget = 0;
1977             }
1978             return 1;
1979         }
1980         break;
1981     case EEventScreenDeviceChanged:
1982         if (callSymbianEventFilters(symbianEvent))
1983             return 1;
1984         if (S60)
1985             S60->updateScreenSize();
1986         if (qt_desktopWidget) {
1987             QSize oldSize = qt_desktopWidget->size();
1988             qt_desktopWidget->data->crect.setWidth(S60->screenWidthInPixels);
1989             qt_desktopWidget->data->crect.setHeight(S60->screenHeightInPixels);
1990             QResizeEvent e(qt_desktopWidget->size(), oldSize);
1991             QApplication::sendEvent(qt_desktopWidget, &e);
1992         }
1993         return 0; // Propagate to CONE
1994     case EEventWindowVisibilityChanged:
1995         if (controlInMap) {
1996             if (callSymbianEventFilters(symbianEvent))
1997                 return 1;
1998             const TWsVisibilityChangedEvent *visChangedEvent = event->VisibilityChanged();
1999             if (visChangedEvent->iFlags & TWsVisibilityChangedEvent::ENotVisible)
2000                 S60->controlVisibilityChanged(control, false);
2001             else if (visChangedEvent->iFlags & TWsVisibilityChangedEvent::EPartiallyVisible)
2002                 S60->controlVisibilityChanged(control, true);
2003             return 1;
2004         }
2005         break;
2006     case EEventFocusGained:
2007         if (callSymbianEventFilters(symbianEvent))
2008             return 1;
2009 #ifndef QT_NO_CURSOR
2010         //re-enable mouse interaction
2011         if (S60->mouseInteractionEnabled) {
2012 #ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
2013             if (S60->brokenPointerCursors)
2014                 qt_symbian_show_pointer_sprite();
2015             else
2016 #endif
2017                 S60->wsSession().SetPointerCursorMode(EPointerCursorNormal);
2018         }
2019 #endif
2020 #ifdef QT_SOFTKEYS_ENABLED
2021         QSoftKeyManager::updateSoftKeys();
2022 #endif
2023         break;
2024     case EEventFocusLost:
2025         if (callSymbianEventFilters(symbianEvent))
2026             return 1;
2027 #ifndef QT_NO_CURSOR
2028         //disable mouse as may be moving to application that does not support it
2029         if (S60->mouseInteractionEnabled) {
2030 #ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
2031             if (S60->brokenPointerCursors)
2032                 qt_symbian_hide_pointer_sprite();
2033             else
2034 #endif
2035                 S60->wsSession().SetPointerCursorMode(EPointerCursorNone);
2036         }
2037 #endif
2038         break;
2039     case KGoomMemoryLowEvent:
2040 #ifdef QT_DEBUG
2041         qDebug() << "QApplicationPrivate::symbianProcessWsEvent - KGoomMemoryLowEvent";
2042 #endif
2043         if (callSymbianEventFilters(symbianEvent))
2044             return 1;
2045 #ifdef QT_GRAPHICSSYSTEM_RUNTIME
2046         if(QApplicationPrivate::runtime_graphics_system) {
2047             bool switchToSwRendering(false);
2048
2049             foreach (QWidget *w, QApplication::topLevelWidgets()) {
2050                 if(w->d_func()->topData()->backingStore) {
2051                     switchToSwRendering = true;
2052                     break;
2053                 }
2054             }
2055
2056             if (switchToSwRendering) {
2057                 QRuntimeGraphicsSystem *gs =
2058                    static_cast<QRuntimeGraphicsSystem*>(QApplicationPrivate::graphics_system);
2059                 gs->setGraphicsSystem(QLatin1String("raster"));
2060             }
2061         }
2062 #endif
2063         break;
2064     case KGoomMemoryGoodEvent:
2065 #ifdef QT_DEBUG
2066         qDebug() << "QApplicationPrivate::symbianProcessWsEvent - KGoomMemoryGoodEvent";
2067 #endif
2068         if (callSymbianEventFilters(symbianEvent))
2069             return 1;
2070 #ifdef QT_GRAPHICSSYSTEM_RUNTIME
2071         if(QApplicationPrivate::runtime_graphics_system) {
2072             QRuntimeGraphicsSystem *gs =
2073                    static_cast<QRuntimeGraphicsSystem*>(QApplicationPrivate::graphics_system);
2074             gs->setGraphicsSystem(QLatin1String("openvg"));
2075         }
2076 #endif
2077         break;
2078 #ifdef Q_SYMBIAN_SUPPORTS_SURFACES
2079     case EEventUser:
2080         {
2081             // GOOM is looking for candidates to kill so indicate that we are
2082             // capable of cleaning up by handling this event
2083             TInt32 *data = reinterpret_cast<TInt32 *>(event->EventData());
2084             if (data[0] == EApaSystemEventShutdown && data[1] == KGoomMemoryLowEvent)
2085                 return 1;
2086         }
2087         break;
2088 #endif
2089     default:
2090         break;
2091     }
2092
2093     if (!controlInMap)
2094         return -1;
2095
2096     return 0;
2097 }
2098
2099 /*!
2100   \warning This virtual function is only available on Symbian.
2101   \since 4.6
2102
2103   If you create an application that inherits QApplication and reimplement
2104   this function, you get direct access to events that the are received
2105   from Symbian. The events are passed in the \a event parameter.
2106
2107   Return true if you want to stop the event from being processed. Return
2108   false for normal event dispatching. The default implementation returns
2109   false, and does nothing with \a event.
2110  */
2111 bool QApplication::symbianEventFilter(const QSymbianEvent *event)
2112 {
2113     Q_UNUSED(event);
2114     return false;
2115 }
2116
2117 /*!
2118   \warning This function is only available on Symbian.
2119   \since 4.6
2120
2121   Handles \a{command}s which are typically handled by
2122   CAknAppUi::HandleCommandL(). Qts Ui integration into Symbian is
2123   partially achieved by deriving from CAknAppUi. Currently, exit,
2124   menu and softkey commands are handled.
2125
2126   \sa s60EventFilter(), s60ProcessEvent()
2127 */
2128 int QApplicationPrivate::symbianHandleCommand(const QSymbianEvent *symbianEvent)
2129 {
2130     Q_Q(QApplication);
2131     int ret = 0;
2132
2133     if (callSymbianEventFilters(symbianEvent))
2134         return 1;
2135
2136     int command = symbianEvent->command();
2137
2138     switch (command) {
2139 #ifdef Q_WS_S60
2140     case EAknSoftkeyExit: {
2141         QCloseEvent ev;
2142         QApplication::sendSpontaneousEvent(q, &ev);
2143         if (ev.isAccepted()) {
2144             q->quit();
2145             ret = 1;
2146         }
2147         break;
2148     }
2149 #endif
2150     case EEikCmdExit:
2151         q->quit();
2152         ret = 1;
2153         break;
2154     default:
2155 #ifdef Q_WS_S60
2156         bool handled = QSoftKeyManager::handleCommand(command);
2157         if (handled)
2158             ret = 1;
2159         else
2160             ret = QMenuBarPrivate::symbianCommands(command);
2161 #endif
2162         break;
2163     }
2164
2165     return ret;
2166 }
2167
2168 /*!
2169   \warning This function is only available on Symbian.
2170   \since 4.6
2171
2172   Handles the resource change specified by \a type.
2173
2174   Currently, KEikDynamicLayoutVariantSwitch and
2175   KAknsMessageSkinChange are handled.
2176  */
2177 int QApplicationPrivate::symbianResourceChange(const QSymbianEvent *symbianEvent)
2178 {
2179     int ret = 0;
2180
2181     int type = symbianEvent->resourceChangeType();
2182
2183     switch (type) {
2184 #ifdef Q_WS_S60
2185     case KEikDynamicLayoutVariantSwitch:
2186         {
2187         if (callSymbianEventFilters(symbianEvent))
2188             return 1;
2189         if (S60)
2190             S60->updateScreenSize();
2191
2192 #ifndef QT_NO_STYLE_S60
2193         QS60Style *s60Style = 0;
2194
2195 #ifndef QT_NO_STYLE_STYLESHEET
2196         QStyleSheetStyle *proxy = qobject_cast<QStyleSheetStyle*>(QApplication::style());
2197         if (proxy)
2198             s60Style = qobject_cast<QS60Style*>(proxy->baseStyle());
2199         else
2200 #endif
2201             s60Style = qobject_cast<QS60Style*>(QApplication::style());
2202
2203         if (s60Style) {
2204             s60Style->d_func()->handleDynamicLayoutVariantSwitch();
2205             ret = 1;
2206         }
2207 #endif
2208         }
2209         break;
2210
2211 #ifndef QT_NO_STYLE_S60
2212     case KAknsMessageSkinChange:
2213         if (callSymbianEventFilters(symbianEvent))
2214             return 1;
2215         if (QS60Style *s60Style = qobject_cast<QS60Style*>(QApplication::style())) {
2216             s60Style->d_func()->handleSkinChange();
2217             ret = 1;
2218         }
2219         break;
2220 #endif
2221 #endif // Q_WS_S60
2222     default:
2223         break;
2224     }
2225
2226     return ret;
2227 }
2228
2229 #ifndef QT_NO_WHEELEVENT
2230 int QApplication::wheelScrollLines()
2231 {
2232     return QApplicationPrivate::wheel_scroll_lines;
2233 }
2234
2235 void QApplication::setWheelScrollLines(int n)
2236 {
2237     QApplicationPrivate::wheel_scroll_lines = n;
2238 }
2239 #endif //QT_NO_WHEELEVENT
2240
2241 bool QApplication::isEffectEnabled(Qt::UIEffect /* effect */)
2242 {
2243     // TODO: Implement QApplication::isEffectEnabled(Qt::UIEffect effect)
2244     return false;
2245 }
2246
2247 void QApplication::setEffectEnabled(Qt::UIEffect /* effect */, bool /* enable */)
2248 {
2249     // TODO: Implement QApplication::setEffectEnabled(Qt::UIEffect effect, bool enable)
2250 }
2251
2252 TUint QApplicationPrivate::resolveS60ScanCode(TInt scanCode, TUint keysym)
2253 {
2254     if (!scanCode)
2255         return keysym;
2256
2257     QApplicationPrivate *d = QApplicationPrivate::instance();
2258
2259     if (keysym) {
2260         // If keysym is specified, cache it.
2261         d->scanCodeCache.insert(scanCode, keysym);
2262         return keysym;
2263     } else {
2264         // If not, retrieve the cached version.
2265         return d->scanCodeCache[scanCode];
2266     }
2267 }
2268
2269 void QApplicationPrivate::initializeMultitouch_sys()
2270 {
2271 #ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
2272     if (HAL::Get(HALData::EPointer3DPressureSupported, pressureSupported) != KErrNone)
2273         pressureSupported = 0;
2274     if (HAL::Get(HALData::EPointer3DMaxPressure, maxTouchPressure) != KErrNone)
2275         maxTouchPressure = KMaxTInt;
2276 #else
2277     pressureSupported = 0;
2278     maxTouchPressure = KMaxTInt;
2279 #endif
2280 }
2281
2282 void QApplicationPrivate::cleanupMultitouch_sys()
2283 { }
2284
2285 #ifndef QT_NO_SESSIONMANAGER
2286 QSessionManager::QSessionManager(QApplication * /* app */, QString & /* id */, QString& /* key */)
2287 {
2288
2289 }
2290
2291 QSessionManager::~QSessionManager()
2292 {
2293
2294 }
2295
2296 bool QSessionManager::allowsInteraction()
2297 {
2298     return false;
2299 }
2300
2301 void QSessionManager::cancel()
2302 {
2303
2304 }
2305 #endif //QT_NO_SESSIONMANAGER
2306
2307 #ifdef QT_KEYPAD_NAVIGATION
2308 /*
2309  * Show/Hide the mouse cursor depending on phone type and chosen mode
2310  */
2311 void QApplicationPrivate::setNavigationMode(Qt::NavigationMode mode)
2312 {
2313 #ifndef QT_NO_CURSOR
2314     const bool wasCursorOn = (QApplicationPrivate::navigationMode == Qt::NavigationModeCursorAuto
2315         && !S60->hasTouchscreen)
2316         || QApplicationPrivate::navigationMode == Qt::NavigationModeCursorForceVisible;
2317     const bool isCursorOn = (mode == Qt::NavigationModeCursorAuto
2318         && !S60->hasTouchscreen)
2319         || mode == Qt::NavigationModeCursorForceVisible;
2320
2321     if (!wasCursorOn && isCursorOn) {
2322         //Show the cursor, when changing from another mode to cursor mode
2323         qt_symbian_set_cursor_visible(true);
2324     }
2325     else if (wasCursorOn && !isCursorOn) {
2326         //Hide the cursor, when leaving cursor mode
2327         qt_symbian_set_cursor_visible(false);
2328     }
2329 #endif
2330     QApplicationPrivate::navigationMode = mode;
2331 }
2332 #endif
2333
2334 #ifndef QT_NO_CURSOR
2335 /*****************************************************************************
2336  QApplication cursor stack
2337  *****************************************************************************/
2338
2339 void QApplication::setOverrideCursor(const QCursor &cursor)
2340 {
2341     qApp->d_func()->cursor_list.prepend(cursor);
2342     qt_symbian_setGlobalCursor(cursor);
2343 }
2344
2345 void QApplication::restoreOverrideCursor()
2346 {
2347     if (qApp->d_func()->cursor_list.isEmpty())
2348         return;
2349     qApp->d_func()->cursor_list.removeFirst();
2350
2351     if (!qApp->d_func()->cursor_list.isEmpty()) {
2352         qt_symbian_setGlobalCursor(qApp->d_func()->cursor_list.first());
2353     }
2354     else {
2355         //determine which widget has focus
2356         QWidget *w = QApplication::widgetAt(QCursor::pos());
2357 #ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
2358         if (S60->brokenPointerCursors) {
2359             qt_symbian_set_pointer_sprite(w ? w->cursor() : Qt::ArrowCursor);
2360         }
2361         else
2362 #endif
2363         {
2364             //because of the internals of window server, we need to force the cursor
2365             //to be set in all child windows too, otherwise when the cursor is over
2366             //the child window it may show a widget cursor or arrow cursor instead,
2367             //depending on construction order.
2368             QListIterator<WId> iter(QWidgetPrivate::mapper->uniqueKeys());
2369             while (iter.hasNext()) {
2370                 CCoeControl *ctrl = iter.next();
2371                 if(ctrl->OwnsWindow()) {
2372                     ctrl->DrawableWindow()->ClearPointerCursor();
2373                 }
2374             }
2375             if (w)
2376                 qt_symbian_setWindowCursor(w->cursor(), w->effectiveWinId());
2377             else
2378                 qt_symbian_setWindowGroupCursor(Qt::ArrowCursor, S60->windowGroup());
2379         }
2380     }
2381 }
2382
2383 #endif // QT_NO_CURSOR
2384
2385 void QApplicationPrivate::_q_aboutToQuit()
2386 {
2387 #ifdef SYMBIAN_GRAPHICS_WSERV_QT_EFFECTS
2388     // Send the shutdown tfx command
2389     S60->wsSession().SendEffectCommand(ETfxCmdAppShutDown);
2390 #endif
2391 }
2392
2393 QS60ThreadLocalData::QS60ThreadLocalData()
2394 {
2395     CCoeEnv *env = CCoeEnv::Static();
2396     if (env) {
2397         //if this is the UI thread, share objects owned by CONE
2398         usingCONEinstances = true;
2399         wsSession = env->WsSession();
2400         screenDevice = env->ScreenDevice();
2401     }
2402     else {
2403         usingCONEinstances = false;
2404         qt_symbian_throwIfError(wsSession.Connect(qt_s60GetRFs()));
2405         screenDevice = new CWsScreenDevice(wsSession);
2406         screenDevice->Construct();
2407     }
2408 }
2409
2410 QS60ThreadLocalData::~QS60ThreadLocalData()
2411 {
2412     if (!usingCONEinstances) {
2413         delete screenDevice;
2414         wsSession.Close();
2415     }
2416 }
2417
2418 QT_END_NAMESPACE