1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
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 #include "private/qcursor_p.h"
69 
70 #include "apgwgnam.h" // For CApaWindowGroupName
71 #include <mdaaudiotoneplayer.h>     // For CMdaAudioToneUtility
72 
73 #if defined(Q_OS_SYMBIAN)
74 # include <private/qs60mainapplication_p.h>
75 # include <centralrepository.h>
76 # include "qs60mainappui.h"
77 # include "qinputcontext.h"
78 # include <private/qgraphicssystemex_symbian_p.h>
79 #endif
80 
81 #if defined(Q_WS_S60)
82 # if !defined(QT_NO_IM)
83 #  include <private/qcoefepinputcontext_p.h>
84 # endif
85 #endif
86 
87 #include "private/qstylesheetstyle_p.h"
88 
89 #include <hal.h>
90 #include <hal_data.h>
91 
92 #ifdef Q_SYMBIAN_TRANSITION_EFFECTS
93 #include <graphics/wstfxconst.h>
94 #endif
95 
96 #ifdef COE_GROUPED_POINTER_EVENT_VERSION
97 #include <coeeventdata.h>
98 #endif
99 
100 QT_BEGIN_NAMESPACE
101 
102 // Goom Events through Window Server
103 static const int KGoomMemoryLowEvent = 0x10282DBF;
104 static const int KGoomMemoryGoodEvent = 0x20026790;
105 // Split view open/close events from AVKON
106 static const int KSplitViewOpenEvent = 0x2001E2C0;
107 static const int KSplitViewCloseEvent = 0x2001E2C1;
108 
109 #if defined(QT_DEBUG)
110 static bool        appNoGrab        = false;        // Grabbing enabled
111 #endif
112 static bool        app_do_modal        = false;        // modal mode
113 Q_GLOBAL_STATIC(QS60Data, qt_s60Data);
114 
115 extern bool qt_sendSpontaneousEvent(QObject*,QEvent*);
116 extern QWidgetList *qt_modal_stack;              // stack of modal widgets
117 extern QDesktopWidget *qt_desktopWidget; // qapplication.cpp
118 
119 QWidget *qt_button_down = 0;                     // widget got last button-down
120 
121 QSymbianControl *QSymbianControl::lastFocusedControl = 0;
122 
123 static Qt::KeyboardModifiers app_keyboardModifiers = Qt::NoModifier;
124 
qGlobalS60Data()125 QS60Data* qGlobalS60Data()
126 {
127     return qt_s60Data();
128 }
129 
130 #ifdef Q_WS_S60
setStatusPaneAndButtonGroupVisibility(bool statusPaneVisible,bool buttonGroupVisible)131 void QS60Data::setStatusPaneAndButtonGroupVisibility(bool statusPaneVisible, bool buttonGroupVisible)
132 {
133     bool buttonGroupVisibilityChanged = false;
134     if (CEikButtonGroupContainer *const b = buttonGroupContainer()) {
135         buttonGroupVisibilityChanged = (b->IsVisible() != buttonGroupVisible);
136         b->MakeVisible(buttonGroupVisible);
137     }
138     bool statusPaneVisibilityChanged = false;
139     if (CEikStatusPane *const s = statusPane()) {
140         statusPaneVisibilityChanged = (s->IsVisible() != statusPaneVisible);
141         s->MakeVisible(statusPaneVisible);
142     }
143     if (buttonGroupVisibilityChanged  || statusPaneVisibilityChanged) {
144         const QSize size = qt_TRect2QRect(S60->clientRect()).size();
145         const QSize oldSize; // note that QDesktopWidget::resizeEvent ignores the QResizeEvent contents
146         QResizeEvent event(size, oldSize);
147         QApplication::instance()->sendEvent(QApplication::desktop(), &event);
148     }
149     if (buttonGroupVisibilityChanged  && !statusPaneVisibilityChanged && QApplication::activeWindow())
150         // Ensure that control rectangle is updated
151         static_cast<QSymbianControl *>(QApplication::activeWindow()->winId())->handleClientAreaChange();
152 }
153 
setRecursiveDecorationsVisibility(QWidget * window,Qt::WindowStates newState)154 bool QS60Data::setRecursiveDecorationsVisibility(QWidget *window, Qt::WindowStates newState)
155 {
156     // Show statusbar:
157     //   Topmost parent: Show unless fullscreen/minimized.
158     //   Child windows: Follow topmost parent, unless fullscreen, in which case do not show statusbar
159     // Show CBA:
160     //   Topmost parent: Show unless fullscreen/minimized.
161     //     Exception: Show if fullscreen with Qt::WindowSoftkeysVisibleHint.
162     //   Child windows:
163     //     Minimized: Unclear if there is an use case for having focused minimized window at all.
164     //       Always follow topmost parent just to be safe.
165     //     Maximized and normal: follow topmost parent.
166     //       Exception: If topmost parent is not showing CBA, show CBA if any softkey actions are
167     //                  defined.
168     //     Fullscreen: Show only if Qt::WindowSoftkeysVisibleHint set.
169 
170     Qt::WindowStates comparisonState = newState;
171     QWidget *parentWindow = window->parentWidget();
172     if (parentWindow) {
173         while (parentWindow->parentWidget())
174             parentWindow = parentWindow->parentWidget();
175         comparisonState = parentWindow->windowState();
176     } else {
177         parentWindow = window;
178     }
179 
180     bool decorationsVisible = !(comparisonState & (Qt::WindowFullScreen | Qt::WindowMinimized));
181     const bool parentIsFullscreen = comparisonState & Qt::WindowFullScreen;
182     const bool parentCbaVisibilityHint = parentWindow->windowFlags() & Qt::WindowSoftkeysVisibleHint;
183     bool buttonGroupVisibility = (decorationsVisible || (parentIsFullscreen && parentCbaVisibilityHint));
184 
185     // Do extra checking for child windows
186     if (window->parentWidget()) {
187         if (newState & Qt::WindowFullScreen) {
188             decorationsVisible = false;
189             if (window->windowFlags() & Qt::WindowSoftkeysVisibleHint)
190                 buttonGroupVisibility = true;
191             else
192                 buttonGroupVisibility = false;
193         } else if (!(newState & Qt::WindowMinimized) && !buttonGroupVisibility) {
194             for (int i = 0; i < window->actions().size(); ++i) {
195                 if (window->actions().at(i)->softKeyRole() != QAction::NoSoftKey) {
196                     buttonGroupVisibility = true;
197                     break;
198                 }
199             }
200         }
201     }
202 
203     S60->setStatusPaneAndButtonGroupVisibility(decorationsVisible, buttonGroupVisibility);
204 
205     return decorationsVisible;
206 }
207 #endif
208 
createStatusPaneAndCBA()209 void QS60Data::createStatusPaneAndCBA()
210 {
211     CEikAppUi *ui = static_cast<CEikAppUi *>(S60->appUi());
212     MEikAppUiFactory *factory = CEikonEnv::Static()->AppUiFactory();
213     QT_TRAP_THROWING(
214         factory->CreateResourceIndependentFurnitureL(ui);
215         CEikButtonGroupContainer *cba = CEikButtonGroupContainer::NewL(CEikButtonGroupContainer::ECba,
216             CEikButtonGroupContainer::EHorizontal, ui, R_AVKON_SOFTKEYS_EMPTY_WITH_IDS);
217         CEikButtonGroupContainer *oldCba = factory->SwapButtonGroup(cba);
218         Q_ASSERT(!oldCba);
219         S60->setButtonGroupContainer(cba);
220         CEikMenuBar *menuBar = new(ELeave) CEikMenuBar;
221         menuBar->ConstructL(ui, 0, R_AVKON_MENUPANE_EMPTY);
222         menuBar->SetMenuType(CEikMenuBar::EMenuOptions);
223         S60->appUi()->AddToStackL(menuBar, ECoeStackPriorityMenu, ECoeStackFlagRefusesFocus);
224         CEikMenuBar *oldMenu = factory->SwapMenuBar(menuBar);
225         Q_ASSERT(!oldMenu);
226     )
227     if (S60->statusPane()) {
228         // Use QDesktopWidget as the status pane observer to proxy for the AppUi.
229         // Can't use AppUi directly because it privately inherits from MEikStatusPaneObserver.
230         QSymbianControl *desktopControl = static_cast<QSymbianControl *>(QApplication::desktop()->winId());
231         S60->statusPane()->SetObserver(desktopControl);
232     }
233 }
234 
controlVisibilityChanged(CCoeControl * control,bool visible)235 void QS60Data::controlVisibilityChanged(CCoeControl *control, bool visible)
236 {
237     if (QWidgetPrivate::mapper && QWidgetPrivate::mapper->contains(control)) {
238         QWidget *const widget = QWidgetPrivate::mapper->value(control);
239         QWidget *const window = widget->window();
240         if (QTLWExtra *topData = qt_widget_private(window)->maybeTopData()) {
241             QWidgetBackingStoreTracker &backingStore = topData->backingStore;
242             if (visible) {
243                 QApplicationPrivate *d = QApplicationPrivate::instance();
244                 d->emitAboutToUseGpuResources();
245 
246                 // (Re)create the backing store and force repaint if we have no
247                 // backing store already, or EGL surface cration failed on last attempt.
248                 if (backingStore.data() && !S60->eglSurfaceCreationError) {
249                     backingStore.registerWidget(widget);
250                 } else {
251                     S60->eglSurfaceCreationError = false;
252                     backingStore.create(window);
253                     backingStore.registerWidget(widget);
254                     qt_widget_private(widget)->invalidateBuffer(widget->rect());
255                     widget->repaint();
256                     if (S60->eglSurfaceCreationError)
257                         backingStore.unregisterWidget(widget);
258                 }
259             } else {
260                 QApplicationPrivate *d = QApplicationPrivate::instance();
261                 d->emitAboutToReleaseGpuResources();
262 
263                 // In certain special scenarios we may get an ENotVisible event
264                 // without a previous EPartiallyVisible. The backingstore must
265                 // still be destroyed, hence the registerWidget() call below.
266                 if (backingStore.data() && widget->internalWinId()
267                     && qt_widget_private(widget)->maybeBackingStore() == backingStore.data())
268                     backingStore.registerWidget(widget);
269                 backingStore.unregisterWidget(widget);
270                 // In order to ensure that any resources used by the window surface
271                 // are immediately freed, we flush the WSERV command buffer.
272                 S60->wsSession().Flush();
273             }
274         }
275     }
276 }
277 
clientRect()278 TRect QS60Data::clientRect()
279 {
280     TRect r = static_cast<CEikAppUi*>(S60->appUi())->ClientRect();
281     if (S60->partialKeyboardOpen && !QApplication::testAttribute(Qt::AA_S60DontConstructApplicationPanes)) {
282         // Adjust client rect when splitview is open
283         // We want it to take the client rect space as if the splitview keyboard was not there
284         TRect statusPaneRect;
285         TRect mainRect;
286         AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EStatusPane, statusPaneRect);
287         AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EMainPane, mainRect);
288         int clientAreaHeight = mainRect.Height();
289         CEikStatusPane *const s = S60->statusPane();
290         if (!(s && s->IsVisible()))
291             clientAreaHeight += statusPaneRect.Height();
292         r.SetHeight(clientAreaHeight);
293     }
294     return r;
295 }
296 
qt_nograb()297 bool qt_nograb()                                // application no-grab option
298 {
299 #if defined(QT_DEBUG)
300     return appNoGrab;
301 #else
302     return false;
303 #endif
304 }
305 
306 // Modified from http://www3.symbian.com/faq.nsf/0/0F1464EE96E737E780256D5E00503DD1?OpenDocument
307 class QS60Beep : public CBase, public MMdaAudioToneObserver
308 {
309 public:
310     static QS60Beep* NewL(TInt aFrequency,  TTimeIntervalMicroSeconds iDuration);
311     void Play();
312     ~QS60Beep();
313 private:
314     void ConstructL(TInt aFrequency,  TTimeIntervalMicroSeconds iDuration);
315     void MatoPrepareComplete(TInt aError);
316     void MatoPlayComplete(TInt aError);
317 private:
318     typedef enum
319         {
320         EBeepNotPrepared,
321         EBeepPrepared,
322         EBeepPlaying
323         } TBeepState;
324 private:
325     CMdaAudioToneUtility* iToneUtil;
326     TBeepState iState;
327     TInt iFrequency;
328     TTimeIntervalMicroSeconds iDuration;
329 };
330 
331 static QS60Beep* qt_S60Beep = 0;
332 
~QS60Beep()333 QS60Beep::~QS60Beep()
334 {
335     if (iToneUtil) {
336         switch (iState) {
337         case EBeepPlaying:
338             iToneUtil->CancelPlay();
339             break;
340         case EBeepNotPrepared:
341             iToneUtil->CancelPrepare();
342             break;
343         }
344     }
345     delete iToneUtil;
346 }
347 
NewL(TInt aFrequency,TTimeIntervalMicroSeconds aDuration)348 QS60Beep* QS60Beep::NewL(TInt aFrequency, TTimeIntervalMicroSeconds aDuration)
349 {
350     QS60Beep* self = new (ELeave) QS60Beep();
351     CleanupStack::PushL(self);
352     self->ConstructL(aFrequency, aDuration);
353     CleanupStack::Pop();
354     return self;
355 }
356 
ConstructL(TInt aFrequency,TTimeIntervalMicroSeconds aDuration)357 void QS60Beep::ConstructL(TInt aFrequency, TTimeIntervalMicroSeconds aDuration)
358 {
359     iToneUtil = CMdaAudioToneUtility::NewL(*this);
360     iState = EBeepNotPrepared;
361     iFrequency = aFrequency;
362     iDuration = aDuration;
363     iToneUtil->PrepareToPlayTone(iFrequency, iDuration);
364 }
365 
Play()366 void QS60Beep::Play()
367 {
368     if (iState == EBeepPlaying) {
369         iToneUtil->CancelPlay();
370         iState = EBeepPrepared;
371     }
372 
373     iToneUtil->Play();
374     iState = EBeepPlaying;
375 }
376 
MatoPrepareComplete(TInt aError)377 void QS60Beep::MatoPrepareComplete(TInt aError)
378 {
379     if (aError == KErrNone) {
380         iState = EBeepPrepared;
381         Play();
382     }
383 }
384 
MatoPlayComplete(TInt aError)385 void QS60Beep::MatoPlayComplete(TInt aError)
386 {
387     Q_UNUSED(aError);
388     iState = EBeepPrepared;
389 }
390 
391 
mapToQtModifiers(TUint s60Modifiers)392 static Qt::KeyboardModifiers mapToQtModifiers(TUint s60Modifiers)
393 {
394     Qt::KeyboardModifiers result = Qt::NoModifier;
395 
396     if (s60Modifiers & EModifierKeypad)
397         result |= Qt::KeypadModifier;
398     if (s60Modifiers & EModifierShift || s60Modifiers & EModifierLeftShift
399             || s60Modifiers & EModifierRightShift)
400         result |= Qt::ShiftModifier;
401     if (s60Modifiers & EModifierCtrl || s60Modifiers & EModifierLeftCtrl
402             || s60Modifiers & EModifierRightCtrl)
403         result |= Qt::ControlModifier;
404     if (s60Modifiers & EModifierAlt || s60Modifiers & EModifierLeftAlt
405             || s60Modifiers & EModifierRightAlt)
406         result |= Qt::AltModifier;
407 
408     return result;
409 }
410 
mapS60MouseEventTypeToQt(QEvent::Type * type,Qt::MouseButton * button,const TPointerEvent * pEvent)411 static void mapS60MouseEventTypeToQt(QEvent::Type *type, Qt::MouseButton *button, const TPointerEvent *pEvent)
412 {
413     switch (pEvent->iType) {
414     case TPointerEvent::EButton1Down:
415         *type = QEvent::MouseButtonPress;
416         *button = Qt::LeftButton;
417         break;
418     case TPointerEvent::EButton1Up:
419         *type = QEvent::MouseButtonRelease;
420         *button = Qt::LeftButton;
421         break;
422     case TPointerEvent::EButton2Down:
423         *type = QEvent::MouseButtonPress;
424         *button = Qt::MidButton;
425         break;
426     case TPointerEvent::EButton2Up:
427         *type = QEvent::MouseButtonRelease;
428         *button = Qt::MidButton;
429         break;
430     case TPointerEvent::EButton3Down:
431         *type = QEvent::MouseButtonPress;
432         *button = Qt::RightButton;
433         break;
434     case TPointerEvent::EButton3Up:
435         *type = QEvent::MouseButtonRelease;
436         *button = Qt::RightButton;
437         break;
438     case TPointerEvent::EDrag:
439         *type = QEvent::MouseMove;
440         *button = Qt::NoButton;
441         break;
442     case TPointerEvent::EMove:
443         // Qt makes no distinction between move and drag
444         *type = QEvent::MouseMove;
445         *button = Qt::NoButton;
446         break;
447     default:
448         *type = QEvent::None;
449         *button = Qt::NoButton;
450         break;
451     }
452     if (pEvent->iModifiers & EModifierDoubleClick){
453         *type = QEvent::MouseButtonDblClick;
454     }
455 
456     if (*type == QEvent::MouseButtonPress || *type == QEvent::MouseButtonDblClick)
457         QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons | (*button);
458     else if (*type == QEvent::MouseButtonRelease)
459         QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons &(~(*button));
460 
461     QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons & Qt::MouseButtonMask;
462 }
463 
464 //### Can be replaced with CAknLongTapDetector if animation is required.
465 //NOTE: if CAknLongTapDetector is used make sure it gets variated out of 3.1 and 3.2,.
466 //also MLongTapObserver needs to be changed to MAknLongTapDetectorCallBack if CAknLongTapDetector is used.
467 class QLongTapTimer : public CTimer
468 {
469 public:
470     static QLongTapTimer* NewL(QAbstractLongTapObserver *observer);
471     QLongTapTimer(QAbstractLongTapObserver *observer);
472     void ConstructL();
473 public:
474     void PointerEventL(const TPointerEvent &event);
475     void RunL();
476 protected:
477 private:
478     QAbstractLongTapObserver *m_observer;
479     TPointerEvent m_event;
480     QPoint m_pressedCoordinates;
481     int m_dragDistance;
482 };
483 
NewL(QAbstractLongTapObserver * observer)484 QLongTapTimer* QLongTapTimer::NewL(QAbstractLongTapObserver *observer)
485 {
486     QLongTapTimer* self = new QLongTapTimer(observer);
487     self->ConstructL();
488     return self;
489 }
ConstructL()490 void QLongTapTimer::ConstructL()
491 {
492     CTimer::ConstructL();
493 }
494 
QLongTapTimer(QAbstractLongTapObserver * observer)495 QLongTapTimer::QLongTapTimer(QAbstractLongTapObserver *observer):CTimer(CActive::EPriorityHigh)
496 {
497     m_observer = observer;
498     m_dragDistance = qApp->startDragDistance();
499     CActiveScheduler::Add(this);
500 }
501 
PointerEventL(const TPointerEvent & event)502 void QLongTapTimer::PointerEventL(const TPointerEvent& event)
503 {
504     if ( event.iType == TPointerEvent::EDrag || event.iType == TPointerEvent::EButtonRepeat)
505     {
506         QPoint diff(QPoint(event.iPosition.iX,event.iPosition.iY) - m_pressedCoordinates);
507         if (diff.manhattanLength() < m_dragDistance)
508             return;
509     }
510     Cancel();
511     m_event = event;
512     if (event.iType == TPointerEvent::EButton1Down)
513     {
514         m_pressedCoordinates = QPoint(event.iPosition.iX,event.iPosition.iY);
515         // must be same as KLongTapDelay in aknlongtapdetector.h
516         After(800000);
517     }
518 }
RunL()519 void QLongTapTimer::RunL()
520 {
521     if (m_observer)
522         m_observer->HandleLongTapEventL(m_event.iPosition, m_event.iParentPosition);
523 }
524 
QSymbianControl(QWidget * w)525 QSymbianControl::QSymbianControl(QWidget *w)
526     : CCoeControl()
527     , qwidget(w)
528     , m_longTapDetector(0)
529     , m_ignoreFocusChanged(0)
530     , m_symbianPopupIsOpen(0)
531     , m_inExternalScreenOverride(false)
532     , m_lastStatusPaneVisibility(0)
533 {
534 }
535 
ConstructL(bool isWindowOwning,bool desktop)536 void QSymbianControl::ConstructL(bool isWindowOwning, bool desktop)
537 {
538     if (!desktop)
539     {
540         if (isWindowOwning || !qwidget->parentWidget()
541             || qwidget->parentWidget()->windowType() == Qt::Desktop) {
542             RWindowGroup &wg(S60->windowGroup(qwidget));
543             CreateWindowL(wg);
544         } else {
545             /**
546              * TODO: in order to avoid creating windows for all ancestors of
547              * this widget up to the root window, the parameter passed to
548              * CreateWindowL should be
549              * qwidget->parentWidget()->effectiveWinId().  However, if we do
550              * this, then we need to take care of re-parenting when a window
551              * is created for a widget between this one and the root window.
552              */
553             CreateWindowL(qwidget->parentWidget()->winId());
554         }
555 
556         // Necessary in order to be able to track the activation status of
557         // the control's window
558         qwidget->d_func()->createExtra();
559 
560         if (!qwidget->d_func()->isGLGlobalShareWidget) {
561             SetFocusing(true);
562             m_longTapDetector = QLongTapTimer::NewL(this);
563             m_doubleClickTimer.invalidate();
564 
565             DrawableWindow()->SetPointerGrab(ETrue);
566         }
567     }
568 
569 #ifdef Q_SYMBIAN_TRANSITION_EFFECTS
570     if (OwnsWindow()) {
571         TTfxWindowPurpose windowPurpose(ETfxPurposeNone);
572         switch (qwidget->windowType()) {
573         case Qt::Dialog:
574             windowPurpose = ETfxPurposeDialogWindow;
575             break;
576         case Qt::Popup:
577             windowPurpose = ETfxPurposePopupWindow;
578             break;
579         case Qt::Tool:
580             windowPurpose = ETfxPurposeToolWindow;
581             break;
582         case Qt::ToolTip:
583             windowPurpose = ETfxPurposeToolTipWindow;
584             break;
585         case Qt::SplashScreen:
586             windowPurpose = ETfxPurposeSplashScreenWindow;
587             break;
588         default:
589             windowPurpose = (isWindowOwning || !qwidget->parentWidget() || qwidget->parentWidget()->windowType() == Qt::Desktop)
590                             ? ETfxPurposeWindow : ETfxPurposeChildWindow;
591             break;
592         }
593         Window().SetPurpose(windowPurpose);
594     }
595 #endif
596 }
597 
~QSymbianControl()598 QSymbianControl::~QSymbianControl()
599 {
600     if (!qwidget->d_func()->isGLGlobalShareWidget) { // GLGlobalShareWidget doesn't interact with scene
601         // Ensure backing store is deleted before the top-level
602         // window is destroyed
603         QT_TRY {
604             qt_widget_private(qwidget)->topData()->backingStore.destroy();
605         } QT_CATCH(const std::exception&) {
606             // ignore exceptions, nothing can be done
607         }
608 
609         if (S60->curWin == this)
610             S60->curWin = 0;
611         if (!QApplicationPrivate::is_app_closing) {
612             QT_TRY {
613                 setFocusSafely(false);
614             } QT_CATCH(const std::exception&) {
615                 // ignore exceptions, nothing can be done
616             }
617         }
618         S60->appUi()->RemoveFromStack(this);
619         delete m_longTapDetector;
620     }
621 }
622 
setWidget(QWidget * w)623 void QSymbianControl::setWidget(QWidget *w)
624 {
625     qwidget = w;
626 }
627 
translatePointForFixedNativeOrientation(const TPoint & pointerEventPos,TTranslationType translationType) const628 QPoint QSymbianControl::translatePointForFixedNativeOrientation(const TPoint &pointerEventPos, TTranslationType translationType) const
629 {
630     QPoint pos(pointerEventPos.iX, pointerEventPos.iY);
631     if (qwidget->d_func()->fixNativeOrientationCalled) {
632         QSize wsize = qwidget->size(); // always same as the size in the native orientation
633         TSize size = Size(); // depends on the current orientation
634         // pixel center translations, eg touch points, should be reflected against the last pixel center, which is at size-1
635         int offset = (translationType == ETranslatePixelCenter) ? 1 : 0;
636         if (size.iWidth == wsize.height() && size.iHeight == wsize.width()) {
637             qreal x = pos.x();
638             qreal y = pos.y();
639             if (S60->screenRotation == QS60Data::ScreenRotation90) {
640                 // DisplayRightUp
641                 pos.setX(size.iHeight - offset - y);
642                 pos.setY(x);
643             } else if (S60->screenRotation == QS60Data::ScreenRotation270) {
644                 // DisplayLeftUp
645                 pos.setX(y);
646                 pos.setY(size.iWidth - offset - x);
647             }
648         }
649     }
650     return pos;
651 }
652 
translateRectForFixedNativeOrientation(const TRect & controlRect) const653 TRect QSymbianControl::translateRectForFixedNativeOrientation(const TRect &controlRect) const
654 {
655     TRect rect = controlRect;
656     if (qwidget->d_func()->fixNativeOrientationCalled) {
657         QPoint a = translatePointForFixedNativeOrientation(rect.iTl, ETranslatePixelEdge);
658         QPoint b = translatePointForFixedNativeOrientation(rect.iBr, ETranslatePixelEdge);
659         if (a.x() < b.x()) {
660             rect.iTl.iX = a.x();
661             rect.iBr.iX = b.x();
662         } else {
663             rect.iTl.iX = b.x();
664             rect.iBr.iX = a.x();
665         }
666         if (a.y() < b.y()) {
667             rect.iTl.iY = a.y();
668             rect.iBr.iY = b.y();
669         } else {
670             rect.iTl.iY = b.y();
671             rect.iBr.iY = a.y();
672         }
673     }
674     return rect;
675 }
676 
HandleLongTapEventL(const TPoint & aPenEventLocation,const TPoint & aPenEventScreenLocation)677 void QSymbianControl::HandleLongTapEventL( const TPoint& aPenEventLocation, const TPoint& aPenEventScreenLocation )
678 {
679     QWidget *alienWidget;
680     QPoint widgetPos = translatePointForFixedNativeOrientation(aPenEventLocation, ETranslatePixelCenter);
681     QPoint globalPos = translatePointForFixedNativeOrientation(aPenEventScreenLocation, ETranslatePixelCenter);
682     alienWidget = qwidget->childAt(widgetPos);
683     if (!alienWidget)
684         alienWidget = qwidget;
685 
686 #if !defined(QT_NO_CONTEXTMENU)
687     QContextMenuEvent contextMenuEvent(QContextMenuEvent::Mouse, widgetPos, globalPos, Qt::NoModifier);
688     qt_sendSpontaneousEvent(alienWidget, &contextMenuEvent);
689 #endif
690 }
691 
692 #ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
693 #ifdef COE_GROUPED_POINTER_EVENT_VERSION
translateMultiEventPointerEvent(const CCoeEventData & eventData)694 void QSymbianControl::translateMultiEventPointerEvent(const CCoeEventData &eventData )
695 {
696     TUint count = eventData.Count();
697     QVector<TouchEventParams> touches;
698     touches.reserve(count);
699     for (int i = 0; i < count; i++) {
700         const TPointerEvent *pointerEvent = eventData.Pointer(i);
701         const TAdvancedPointerEvent *advEvent = pointerEvent->AdvancedPointerEvent();
702         if (advEvent)
703             touches.push_back(TouchEventFromAdvancedPointerEvent(advEvent));
704     }
705     if (touches.size())
706         processTouchEvents(touches);
707 }
708 #endif
709 
translateAdvancedPointerEvent(const TAdvancedPointerEvent * event)710 void QSymbianControl::translateAdvancedPointerEvent(const TAdvancedPointerEvent *event)
711 {
712     processTouchEvents(QVector<TouchEventParams>(1, TouchEventFromAdvancedPointerEvent(event)));
713 }
714 
TouchEventFromAdvancedPointerEvent(const TAdvancedPointerEvent * event)715 QSymbianControl::TouchEventParams QSymbianControl::TouchEventFromAdvancedPointerEvent(const TAdvancedPointerEvent *event)
716 {
717     QApplicationPrivate *d = QApplicationPrivate::instance();
718     QPointF screenPos = qwidget->mapToGlobal(translatePointForFixedNativeOrientation(event->iPosition, ETranslatePixelCenter));
719     qreal pressure;
720     if (d->pressureSupported
721         && event->Pressure() > 0) //workaround for misconfigured HAL
722         pressure = event->Pressure() / qreal(d->maxTouchPressure);
723     else
724         pressure = qreal(1.0);
725     return TouchEventParams(event->PointerNumber(), event->iType, screenPos, pressure);
726 }
727 #endif
728 
TouchEventParams()729 QSymbianControl::TouchEventParams::TouchEventParams()
730 {}
731 
TouchEventParams(int pointerNumber,TPointerEvent::TType type,QPointF screenPos,qreal pressure)732 QSymbianControl::TouchEventParams::TouchEventParams(int pointerNumber, TPointerEvent::TType type, QPointF screenPos, qreal pressure)
733     : pointerNumber(pointerNumber),
734       type(type),
735       screenPos(screenPos),
736       pressure(pressure)
737 {}
738 
processTouchEvents(const QVector<TouchEventParams> & touches)739 void QSymbianControl::processTouchEvents(const QVector<TouchEventParams> &touches)
740 {
741     QRect screenGeometry = qApp->desktop()->screenGeometry(qwidget);
742 
743     QApplicationPrivate *d = QApplicationPrivate::instance();
744 
745     // get the maximum pointer number
746     int numUpdates = touches.size();
747     int maxPointerNumber = 0;
748     for (int i = 0; i < numUpdates; ++i) {
749         const TouchEventParams &touch = touches[i];
750         maxPointerNumber = qMax(maxPointerNumber, touch.pointerNumber);
751     }
752 
753     // ensure there are sufficient touch events in the list,
754     // touch events will be indexed by pointerNumber
755     QList<QTouchEvent::TouchPoint> points = d->appAllTouchPoints;
756     while (points.count() <= maxPointerNumber)
757         points.append(QTouchEvent::TouchPoint(points.count()));
758 
759     // first set all active touch points to stationary
760     for (int i = 0; i < points.count(); ++i) {
761         QTouchEvent::TouchPoint &touchPoint = points[i];
762         if (touchPoint.state() != Qt::TouchPointReleased) {
763             touchPoint.setState(Qt::TouchPointStationary);
764          }
765     }
766 
767     // Add all info about moving or state changed touch points
768     for (int i = 0; i < numUpdates; ++i) {
769         const TouchEventParams &touch = touches[i];
770         QTouchEvent::TouchPoint &touchPoint = points[touch.pointerNumber];
771         Qt::TouchPointStates state;
772         switch (touch.type) {
773         case TPointerEvent::EButton1Down:
774 #ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
775         case TPointerEvent::EEnterHighPressure:
776 #endif
777             state = Qt::TouchPointPressed;
778             break;
779         case TPointerEvent::EButton1Up:
780 #ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
781         case TPointerEvent::EExitCloseProximity:
782 #endif
783             state = Qt::TouchPointReleased;
784             break;
785         case TPointerEvent::EDrag:
786             state = Qt::TouchPointMoved;
787             break;
788         default:
789             // how likely is this to happen?
790             state = Qt::TouchPointStationary;
791             break;
792         }
793         if (touch.pointerNumber == 0)
794             state |= Qt::TouchPointPrimary;
795         touchPoint.setState(state);
796 
797         touchPoint.setScreenPos(touch.screenPos);
798         touchPoint.setNormalizedPos(QPointF(touch.screenPos.x() / screenGeometry.width(),
799                                             touch.screenPos.y() / screenGeometry.height()));
800 
801         touchPoint.setPressure(touch.pressure);
802     }
803 
804     // check the resulting state of all touch points
805     Qt::TouchPointStates allStates = 0;
806     for (int i = 0; i < points.count(); ++i) {
807         QTouchEvent::TouchPoint &touchPoint = points[i];
808         allStates |= touchPoint.state();
809     }
810 
811     if ((allStates & Qt::TouchPointStateMask) == Qt::TouchPointReleased) {
812         // all touch points released
813         d->appAllTouchPoints.clear();
814     } else {
815         d->appAllTouchPoints = points;
816     }
817 
818     QApplicationPrivate::translateRawTouchEvent(qwidget,
819                                                 QTouchEvent::TouchScreen,
820                                                 points);
821 }
822 
HandlePointerEventL(const TPointerEvent & pEvent)823 void QSymbianControl::HandlePointerEventL(const TPointerEvent& pEvent)
824 {
825 #ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
826 #ifdef COE_GROUPED_POINTER_EVENT_VERSION
827     if (pEvent.iType == TPointerEvent::EDataCCoeEventData) {
828         // only advanced pointers can be data type pointer events
829         const TAdvancedPointerEvent *advEvent = pEvent.AdvancedPointerEvent();
830         if (!advEvent)
831             return;
832         const CCoeEventData& eventData = CCoeEventData::EventData(*advEvent);
833         if (eventData.Type() == CWsEventWithData::EPointerEvent) {
834             QT_TRYCATCH_LEAVING(translateMultiEventPointerEvent(eventData));
835             // pointer 0 events and unnumbered events should also be handled as mouse events
836             for (int i=0; i<eventData.Count(); i++) {
837                 const TPointerEvent *pointerEvent = eventData.Pointer(i);
838                 const TAdvancedPointerEvent *advEvent = pointerEvent->AdvancedPointerEvent();
839                 if (!advEvent || advEvent->PointerNumber() == 0) {
840                     if (m_longTapDetector)
841                         m_longTapDetector->PointerEventL(*pointerEvent);
842                     QT_TRYCATCH_LEAVING(HandlePointerEvent(*pointerEvent));
843                 }
844             }
845             return;
846         }
847     }
848 #endif
849     if (pEvent.IsAdvancedPointerEvent()) {
850         const TAdvancedPointerEvent *advancedPointerEvent = pEvent.AdvancedPointerEvent();
851         translateAdvancedPointerEvent(advancedPointerEvent);
852         if (advancedPointerEvent->PointerNumber() != 0) {
853             // only send mouse events for the first touch point
854             return;
855         }
856     }
857 #endif
858     if (m_longTapDetector)
859         m_longTapDetector->PointerEventL(pEvent);
860     QT_TRYCATCH_LEAVING(HandlePointerEvent(pEvent));
861 }
862 
HandlePointerEvent(const TPointerEvent & pEvent)863 void QSymbianControl::HandlePointerEvent(const TPointerEvent& pEvent)
864 {
865     QMouseEvent::Type type;
866     Qt::MouseButton button;
867     mapS60MouseEventTypeToQt(&type, &button, &pEvent);
868     Qt::KeyboardModifiers modifiers = mapToQtModifiers(pEvent.iModifiers);
869     app_keyboardModifiers = modifiers;
870 
871     QPoint widgetPos = translatePointForFixedNativeOrientation(pEvent.iPosition, ETranslatePixelCenter);
872     TPoint controlScreenPos = PositionRelativeToScreen();
873     QPoint globalPos = QPoint(controlScreenPos.iX, controlScreenPos.iY) + widgetPos;
874     S60->lastCursorPos = globalPos;
875     S60->lastPointerEventPos = widgetPos;
876 
877     QWidget *mouseGrabber = QWidget::mouseGrabber();
878 
879     QWidget *popupWidget = qApp->activePopupWidget();
880     QWidget *popupReceiver = 0;
881     if (popupWidget) {
882         QWidget *popupChild = popupWidget->childAt(popupWidget->mapFromGlobal(globalPos));
883         popupReceiver = popupChild ? popupChild : popupWidget;
884     }
885 
886     if (mouseGrabber) {
887         if (popupReceiver) {
888             sendMouseEvent(popupReceiver, type, globalPos, button, modifiers);
889         } else {
890             sendMouseEvent(mouseGrabber, type, globalPos, button, modifiers);
891         }
892         // No Enter/Leave events in grabbing mode.
893         return;
894     }
895 
896     QWidget *widgetUnderPointer = qwidget->childAt(widgetPos);
897     if (!widgetUnderPointer)
898         widgetUnderPointer = qwidget;
899 
900     QApplicationPrivate::dispatchEnterLeave(widgetUnderPointer, S60->lastPointerEventTarget);
901     S60->lastPointerEventTarget = widgetUnderPointer;
902 
903     QWidget *receiver;
904     if (!popupReceiver && S60->mousePressTarget && type != QEvent::MouseButtonPress) {
905         receiver = S60->mousePressTarget;
906         if (type == QEvent::MouseButtonRelease)
907             S60->mousePressTarget = 0;
908     } else {
909         receiver = popupReceiver ? popupReceiver : widgetUnderPointer;
910         if (type == QEvent::MouseButtonPress)
911             S60->mousePressTarget = receiver;
912     }
913 
914 #if !defined(QT_NO_CURSOR) && !defined(Q_SYMBIAN_FIXED_POINTER_CURSORS)
915     if (S60->brokenPointerCursors)
916         qt_symbian_move_cursor_sprite();
917 #endif
918 
919 //Generate single touch event for S60 5.0 (has touchscreen, does not have advanced pointers)
920 #ifndef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
921     if (S60->hasTouchscreen) {
922         processTouchEvents(QVector<TouchEventParams>(1, TouchEventParams(0, pEvent.iType, QPointF(globalPos), 1.0)));
923     }
924 #endif
925 
926     sendMouseEvent(receiver, type, globalPos, button, modifiers);
927 }
928 
929 #ifdef Q_WS_S60
HandleStatusPaneSizeChange()930 void QSymbianControl::HandleStatusPaneSizeChange()
931 {
932     QS60MainAppUi *s60AppUi = static_cast<QS60MainAppUi *>(S60->appUi());
933     s60AppUi->HandleStatusPaneSizeChange();
934 }
935 #endif
936 
sendMouseEvent(QWidget * receiver,QEvent::Type type,const QPoint & globalPos,Qt::MouseButton button,Qt::KeyboardModifiers modifiers)937 void QSymbianControl::sendMouseEvent(
938         QWidget *receiver,
939         QEvent::Type type,
940         const QPoint &globalPos,
941         Qt::MouseButton button,
942         Qt::KeyboardModifiers modifiers)
943 {
944     Q_ASSERT(receiver);
945     QMouseEvent mEvent(type, receiver->mapFromGlobal(globalPos), globalPos,
946         button, QApplicationPrivate::mouse_buttons, modifiers);
947     QEventDispatcherS60 *dispatcher;
948     // It is theoretically possible for someone to install a different event dispatcher.
949     if ((dispatcher = qobject_cast<QEventDispatcherS60 *>(receiver->d_func()->threadData->eventDispatcher)) != 0) {
950         if (dispatcher->excludeUserInputEvents()) {
951             dispatcher->saveInputEvent(this, receiver, new QMouseEvent(mEvent));
952             return;
953         }
954     }
955 
956     sendMouseEvent(receiver, &mEvent);
957 }
958 
sendMouseEvent(QWidget * widget,QMouseEvent * mEvent)959 bool QSymbianControl::sendMouseEvent(QWidget *widget, QMouseEvent *mEvent)
960 {
961     return qt_sendSpontaneousEvent(widget, mEvent);
962 }
963 
OfferKeyEventL(const TKeyEvent & keyEvent,TEventCode type)964 TKeyResponse QSymbianControl::OfferKeyEventL(const TKeyEvent& keyEvent, TEventCode type)
965 {
966     TKeyResponse r = EKeyWasNotConsumed;
967     QT_TRYCATCH_LEAVING(r = OfferKeyEvent(keyEvent, type));
968     return r;
969 }
970 
OfferKeyEvent(const TKeyEvent & keyEvent,TEventCode type)971 TKeyResponse QSymbianControl::OfferKeyEvent(const TKeyEvent& keyEvent, TEventCode type)
972 {
973     /*
974       S60 has a confusing way of delivering key events. There are three types of
975       events: EEventKey, EEventKeyDown and EEventKeyUp. When a key is pressed,
976       EEventKeyDown is first generated, followed by EEventKey. Then, when the key is
977       released, EEventKeyUp is generated.
978       However, it is possible that only the EEventKey is generated alone, typically
979       in relation to virtual keyboards. In that case we need to take care to
980       generate both press and release events in Qt, since applications expect that.
981       We do this by having three states for each used scan code, depending on the
982       events received. See the switch below for what happens in each state
983       transition.
984     */
985 
986     if (type != EEventKeyDown)
987         if (handleVirtualMouse(keyEvent, type) == EKeyWasConsumed)
988             return EKeyWasConsumed;
989 
990     TKeyResponse ret = EKeyWasNotConsumed;
991 #define GET_RETURN(x) (ret = ((x) == EKeyWasConsumed) ? EKeyWasConsumed : ret)
992 
993     // This top level switch corresponds to the states, and the inner switches
994     // correspond to the transitions.
995     QS60Data::ScanCodeState &scanCodeState = S60->scanCodeStates[keyEvent.iScanCode];
996     switch (scanCodeState) {
997     case QS60Data::Unpressed:
998         switch (type) {
999         case EEventKeyDown:
1000             scanCodeState = QS60Data::KeyDown;
1001             break;
1002         case EEventKey:
1003             GET_RETURN(sendSymbianKeyEvent(keyEvent, QEvent::KeyPress));
1004             GET_RETURN(sendSymbianKeyEvent(keyEvent, QEvent::KeyRelease));
1005             break;
1006         case EEventKeyUp:
1007             // No action.
1008             break;
1009         }
1010         break;
1011     case QS60Data::KeyDown:
1012         switch (type) {
1013         case EEventKeyDown:
1014             // This should never happen, just stay in this state to be safe.
1015             break;
1016         case EEventKey:
1017             GET_RETURN(sendSymbianKeyEvent(keyEvent, QEvent::KeyPress));
1018             scanCodeState = QS60Data::KeyDownAndKey;
1019             break;
1020         case EEventKeyUp:
1021             scanCodeState = QS60Data::Unpressed;
1022             break;
1023         }
1024         break;
1025     case QS60Data::KeyDownAndKey:
1026         switch (type) {
1027         case EEventKeyDown:
1028             // This should never happen, just stay in this state to be safe.
1029             break;
1030         case EEventKey:
1031             GET_RETURN(sendSymbianKeyEvent(keyEvent, QEvent::KeyRelease));
1032             GET_RETURN(sendSymbianKeyEvent(keyEvent, QEvent::KeyPress));
1033             break;
1034         case EEventKeyUp:
1035             GET_RETURN(sendSymbianKeyEvent(keyEvent, QEvent::KeyRelease));
1036             scanCodeState = QS60Data::Unpressed;
1037             break;
1038         }
1039         break;
1040     }
1041     return ret;
1042 
1043 #undef GET_RETURN
1044 }
1045 
sendSymbianKeyEvent(const TKeyEvent & keyEvent,QEvent::Type type)1046 TKeyResponse QSymbianControl::sendSymbianKeyEvent(const TKeyEvent &keyEvent, QEvent::Type type)
1047 {
1048     // Because S60 does not generate keysyms for EKeyEventDown and EKeyEventUp
1049     // events, we need to cache the keysyms from the EKeyEvent events. This is what
1050     // resolveS60ScanCode does.
1051     TUint s60Keysym = QApplicationPrivate::resolveS60ScanCode(keyEvent.iScanCode,
1052             keyEvent.iCode);
1053     int keyCode;
1054     if (s60Keysym == EKeyNull){ //some key events have 0 in iCode, for them iScanCode should be used
1055         keyCode = qt_keymapper_private()->mapS60ScanCodesToQt(keyEvent.iScanCode);
1056     } else if ((s60Keysym >= 0x20 && s60Keysym < ENonCharacterKeyBase) || s60Keysym >= (ENonCharacterKeyBase + ENonCharacterKeyCount)) {
1057         // Normal characters keys.
1058         keyCode = s60Keysym;
1059     } else {
1060         // Special S60 keys.
1061         keyCode = qt_keymapper_private()->mapS60KeyToQt(s60Keysym);
1062     }
1063 
1064     Qt::KeyboardModifiers mods = mapToQtModifiers(keyEvent.iModifiers);
1065 
1066     TInt code = keyEvent.iCode;
1067 
1068     if (mods == Qt::ControlModifier) {
1069         //only support ctrl+a .. ctrl+z, 0x40 is the key value before Qt::Key_A
1070         if (code > 0 && code < 27)
1071             keyCode = 0x40 + code;
1072     }
1073 
1074     QKeyEventEx qKeyEvent(type, keyCode, mods, qt_keymapper_private()->translateKeyEvent(keyCode, mods),
1075             (keyEvent.iRepeats != 0), 1, keyEvent.iScanCode, s60Keysym, keyEvent.iModifiers);
1076     QWidget *widget;
1077     widget = QWidget::keyboardGrabber();
1078     if (!widget) {
1079         if (QApplicationPrivate::popupWidgets != 0) {
1080             widget = QApplication::activePopupWidget()->focusWidget();
1081             if (!widget) {
1082                 widget = QApplication::activePopupWidget();
1083             }
1084         } else {
1085             widget = QApplicationPrivate::focus_widget;
1086             if (!widget) {
1087                 widget = qwidget;
1088             }
1089         }
1090     }
1091 
1092     QEventDispatcherS60 *dispatcher;
1093     // It is theoretically possible for someone to install a different event dispatcher.
1094     if ((dispatcher = qobject_cast<QEventDispatcherS60 *>(widget->d_func()->threadData->eventDispatcher)) != 0) {
1095         if (dispatcher->excludeUserInputEvents()) {
1096             dispatcher->saveInputEvent(this, widget, new QKeyEventEx(qKeyEvent));
1097             return EKeyWasConsumed;
1098         }
1099     }
1100     return sendKeyEvent(widget, &qKeyEvent);
1101 }
1102 
handleVirtualMouse(const TKeyEvent & keyEvent,TEventCode type)1103 TKeyResponse QSymbianControl::handleVirtualMouse(const TKeyEvent& keyEvent,TEventCode type)
1104 {
1105 #ifndef QT_NO_CURSOR
1106     if (S60->mouseInteractionEnabled && S60->virtualMouseRequired) {
1107         //translate keys to pointer
1108         if ((keyEvent.iScanCode >= EStdKeyLeftArrow && keyEvent.iScanCode <= EStdKeyDownArrow) ||
1109                 (keyEvent.iScanCode >= EStdKeyDevice10 && keyEvent.iScanCode <= EStdKeyDevice13) ||
1110                 keyEvent.iScanCode == EStdKeyDevice3) {
1111             QPoint pos = QCursor::pos();
1112             TPointerEvent fakeEvent;
1113             fakeEvent.iType = (TPointerEvent::TType)(-1);
1114             fakeEvent.iModifiers = keyEvent.iModifiers;
1115             TInt x = pos.x();
1116             TInt y = pos.y();
1117             if (type == EEventKeyUp) {
1118                 S60->virtualMouseAccelTimeout.start();
1119                 switch (keyEvent.iScanCode) {
1120                 case EStdKeyLeftArrow:
1121                     S60->virtualMousePressedKeys &= ~QS60Data::Left;
1122                     break;
1123                 case EStdKeyRightArrow:
1124                     S60->virtualMousePressedKeys &= ~QS60Data::Right;
1125                     break;
1126                 case EStdKeyUpArrow:
1127                     S60->virtualMousePressedKeys &= ~QS60Data::Up;
1128                     break;
1129                 case EStdKeyDownArrow:
1130                     S60->virtualMousePressedKeys &= ~QS60Data::Down;
1131                     break;
1132                 // diagonal keys (named aliases don't exist in 3.1 SDK)
1133                 case EStdKeyDevice10:
1134                     S60->virtualMousePressedKeys &= ~QS60Data::LeftUp;
1135                     break;
1136                 case EStdKeyDevice11:
1137                     S60->virtualMousePressedKeys &= ~QS60Data::RightUp;
1138                     break;
1139                 case EStdKeyDevice12:
1140                     S60->virtualMousePressedKeys &= ~QS60Data::RightDown;
1141                     break;
1142                 case EStdKeyDevice13:
1143                     S60->virtualMousePressedKeys &= ~QS60Data::LeftDown;
1144                     break;
1145                 case EStdKeyDevice3: //select
1146                     if (S60->virtualMousePressedKeys & QS60Data::Select)
1147                         fakeEvent.iType = TPointerEvent::EButton1Up;
1148                     S60->virtualMousePressedKeys &= ~QS60Data::Select;
1149                     break;
1150                 }
1151             }
1152             else if (type == EEventKey) {
1153                 int dx = 0;
1154                 int dy = 0;
1155                 if (keyEvent.iScanCode != EStdKeyDevice3) {
1156                     m_doubleClickTimer.invalidate();
1157                     //reset mouse accelleration after a short time with no moves
1158                     const int maxTimeBetweenKeyEventsMs = 500;
1159                     if (S60->virtualMouseAccelTimeout.isValid() &&
1160                             S60->virtualMouseAccelTimeout.hasExpired(maxTimeBetweenKeyEventsMs)) {
1161                         S60->virtualMouseAccelDX = 0;
1162                         S60->virtualMouseAccelDY = 0;
1163                     }
1164                     S60->virtualMouseAccelTimeout.invalidate();
1165                 }
1166                 switch (keyEvent.iScanCode) {
1167                 case EStdKeyLeftArrow:
1168                     S60->virtualMousePressedKeys |= QS60Data::Left;
1169                     dx = -1;
1170                     fakeEvent.iType = TPointerEvent::EMove;
1171                     break;
1172                 case EStdKeyRightArrow:
1173                     S60->virtualMousePressedKeys |= QS60Data::Right;
1174                     dx = 1;
1175                     fakeEvent.iType = TPointerEvent::EMove;
1176                     break;
1177                 case EStdKeyUpArrow:
1178                     S60->virtualMousePressedKeys |= QS60Data::Up;
1179                     dy = -1;
1180                     fakeEvent.iType = TPointerEvent::EMove;
1181                     break;
1182                 case EStdKeyDownArrow:
1183                     S60->virtualMousePressedKeys |= QS60Data::Down;
1184                     dy = 1;
1185                     fakeEvent.iType = TPointerEvent::EMove;
1186                     break;
1187                 case EStdKeyDevice10:
1188                     S60->virtualMousePressedKeys |= QS60Data::LeftUp;
1189                     dx = -1;
1190                     dy = -1;
1191                     fakeEvent.iType = TPointerEvent::EMove;
1192                     break;
1193                 case EStdKeyDevice11:
1194                     S60->virtualMousePressedKeys |= QS60Data::RightUp;
1195                     dx = 1;
1196                     dy = -1;
1197                     fakeEvent.iType = TPointerEvent::EMove;
1198                     break;
1199                 case EStdKeyDevice12:
1200                     S60->virtualMousePressedKeys |= QS60Data::RightDown;
1201                     dx = 1;
1202                     dy = 1;
1203                     fakeEvent.iType = TPointerEvent::EMove;
1204                     break;
1205                 case EStdKeyDevice13:
1206                     S60->virtualMousePressedKeys |= QS60Data::LeftDown;
1207                     dx = -1;
1208                     dy = 1;
1209                     fakeEvent.iType = TPointerEvent::EMove;
1210                     break;
1211                 case EStdKeyDevice3:
1212                     // Platform bug. If you start pressing several keys simultaneously (for
1213                     // example for drag'n'drop), Symbian starts producing spurious up and
1214                     // down messages for some keys. Therefore, make sure we have a clean slate
1215                     // of pressed keys before starting a new button press.
1216                     if (S60->virtualMousePressedKeys & QS60Data::Select) {
1217                         return EKeyWasConsumed;
1218                     } else {
1219                         S60->virtualMousePressedKeys |= QS60Data::Select;
1220                         fakeEvent.iType = TPointerEvent::EButton1Down;
1221                         if (m_doubleClickTimer.isValid()
1222                                 && !m_doubleClickTimer.hasExpired(QApplication::doubleClickInterval())) {
1223                             fakeEvent.iModifiers |= EModifierDoubleClick;
1224                             m_doubleClickTimer.invalidate();
1225                         } else {
1226                             m_doubleClickTimer.start();
1227                         }
1228                     }
1229                     break;
1230                 }
1231                 if (dx) {
1232                     int cdx = S60->virtualMouseAccelDX;
1233                     //reset accel on change of sign, else double accel
1234                     if (dx * cdx <= 0)
1235                         cdx = dx;
1236                     else
1237                         cdx *= 4;
1238                     //cap accelleration
1239                     if (dx * cdx > S60->virtualMouseMaxAccel)
1240                         cdx = dx * S60->virtualMouseMaxAccel;
1241                     //move mouse position
1242                     x += cdx;
1243                     S60->virtualMouseAccelDX = cdx;
1244                 }
1245 
1246                 if (dy) {
1247                     int cdy = S60->virtualMouseAccelDY;
1248                     if (dy * cdy <= 0)
1249                         cdy = dy;
1250                     else
1251                         cdy *= 4;
1252                     if (dy * cdy > S60->virtualMouseMaxAccel)
1253                         cdy = dy * S60->virtualMouseMaxAccel;
1254                     y += cdy;
1255                     S60->virtualMouseAccelDY = cdy;
1256                 }
1257             }
1258             //clip to screen size (window server allows a sprite hotspot to be outside the screen)
1259             int screenNumber = S60->screenNumberForWidget(qwidget);
1260             if (x < 0)
1261                 x = 0;
1262             else if (x >= S60->screenWidthInPixelsForScreen[screenNumber])
1263                 x = S60->screenWidthInPixelsForScreen[screenNumber] - 1;
1264             if (y < 0)
1265                 y = 0;
1266             else if (y >= S60->screenHeightInPixelsForScreen[screenNumber])
1267                 y = S60->screenHeightInPixelsForScreen[screenNumber] - 1;
1268             TPoint epos(x, y);
1269             TPoint cpos = epos - PositionRelativeToScreen();
1270             fakeEvent.iPosition = cpos;
1271             fakeEvent.iParentPosition = epos;
1272             if(fakeEvent.iType != -1)
1273                 HandlePointerEvent(fakeEvent);
1274             return EKeyWasConsumed;
1275         }
1276     }
1277 #endif
1278 
1279     return EKeyWasNotConsumed;
1280 }
1281 
sendInputEvent(QWidget * widget,QInputEvent * inputEvent)1282 void QSymbianControl::sendInputEvent(QWidget *widget, QInputEvent *inputEvent)
1283 {
1284     switch (inputEvent->type()) {
1285     case QEvent::KeyPress:
1286     case QEvent::KeyRelease:
1287         sendKeyEvent(widget, static_cast<QKeyEvent *>(inputEvent));
1288         break;
1289     case QEvent::MouseButtonDblClick:
1290     case QEvent::MouseButtonPress:
1291     case QEvent::MouseButtonRelease:
1292     case QEvent::MouseMove:
1293         sendMouseEvent(widget, static_cast<QMouseEvent *>(inputEvent));
1294         break;
1295     default:
1296         // Shouldn't get here.
1297         Q_ASSERT_X(0 == 1, "QSymbianControl::sendInputEvent()", "inputEvent->type() is unknown");
1298         break;
1299     }
1300 }
1301 
sendKeyEvent(QWidget * widget,QKeyEvent * keyEvent)1302 TKeyResponse QSymbianControl::sendKeyEvent(QWidget *widget, QKeyEvent *keyEvent)
1303 {
1304 #if !defined(QT_NO_IM) && defined(Q_WS_S60)
1305     if (widget && widget->isEnabled() && widget->testAttribute(Qt::WA_InputMethodEnabled)) {
1306         QInputContext *qic = widget->inputContext();
1307         if (qic && qic->filterEvent(keyEvent))
1308             return EKeyWasConsumed;
1309     }
1310 #endif // !defined(QT_NO_IM) && defined(Q_OS_SYMBIAN)
1311 
1312     if (widget && qt_sendSpontaneousEvent(widget, keyEvent))
1313         if (keyEvent->isAccepted())
1314             return EKeyWasConsumed;
1315 
1316     return EKeyWasNotConsumed;
1317 }
1318 
1319 #if !defined(QT_NO_IM) && defined(Q_WS_S60)
InputCapabilities() const1320 TCoeInputCapabilities QSymbianControl::InputCapabilities() const
1321 {
1322     QWidget *w = 0;
1323 
1324     if (qwidget->hasFocus())
1325         w = qwidget;
1326     else
1327         w = qwidget->focusWidget();
1328 
1329     QCoeFepInputContext *ic;
1330     if (w && w->isEnabled() && w->testAttribute(Qt::WA_InputMethodEnabled)
1331             && (ic = qobject_cast<QCoeFepInputContext *>(w->inputContext()))) {
1332         return ic->inputCapabilities();
1333     } else {
1334         return TCoeInputCapabilities(TCoeInputCapabilities::ENone, 0, 0);
1335     }
1336 }
1337 #endif
1338 
Draw(const TRect & aRect) const1339 void QSymbianControl::Draw(const TRect& aRect) const
1340 {
1341     int leaveCode = 0;
1342     int exceptionCode = 0;
1343     // Implementation of CCoeControl::Draw() must never leave or throw exception.
1344     // In native Symbian code this is considered a fatal error, and it causes
1345     // process termination.
1346     TRAP(leaveCode, QT_TRYCATCH_ERROR(exceptionCode, doDraw(aRect)));
1347     if (leaveCode)
1348         qWarning() << "QSymbianControl::doDraw leaved with code " << leaveCode;
1349     else if (exceptionCode)
1350         qWarning() << "QSymbianControl::doDraw threw exception with code " << exceptionCode;
1351 }
1352 
doDraw(const TRect & controlRect) const1353 void QSymbianControl::doDraw(const TRect& controlRect) const
1354 {
1355     // Bail out immediately, if we don't have a drawing surface. Surface is attempted to be recreated
1356     // when this application becomes visible for the next time.
1357     if (S60->eglSurfaceCreationError) {
1358         qWarning() << "QSymbianControl::doDraw: EGL surface creation has failed, abort";
1359         return;
1360     }
1361 
1362     // Set flag to avoid calling DrawNow in window surface
1363     QWidget *window = qwidget->window();
1364     Q_ASSERT(window);
1365     QTLWExtra *topExtra = window->d_func()->maybeTopData();
1366     Q_ASSERT(topExtra);
1367 
1368     TRect wcontrolRect = translateRectForFixedNativeOrientation(controlRect);
1369 
1370     if (!topExtra->inExpose) {
1371         topExtra->inExpose = true;
1372         if (!qwidget->isWindow()) {
1373             // If we get here, then it means we have a native child window
1374             // Since no content should ever be painted to these windows, we
1375             // erase them with a transparent brush when they get an expose.
1376             CWindowGc &gc = SystemGc();
1377             gc.SetBrushColor(TRgb(0, 0, 0, 0));
1378             gc.Clear(controlRect);
1379         }
1380         QRect exposeRect = qt_TRect2QRect(wcontrolRect);
1381         qwidget->d_func()->syncBackingStore(exposeRect);
1382         topExtra->inExpose = false;
1383     }
1384 
1385     QWindowSurface *surface = qwidget->windowSurface();
1386     QPaintEngine *engine = surface ? surface->paintDevice()->paintEngine() : NULL;
1387 
1388     if (!engine)
1389         return;
1390 
1391     const bool sendNativePaintEvents = qwidget->d_func()->extraData()->receiveNativePaintEvents;
1392     if (sendNativePaintEvents) {
1393         const QRect r = qt_TRect2QRect(wcontrolRect);
1394         QMetaObject::invokeMethod(qwidget, "beginNativePaintEvent", Qt::DirectConnection, Q_ARG(QRect, r));
1395     }
1396 
1397     // Map source rectangle into coordinates of the backing store.
1398     const QPoint controlBase(controlRect.iTl.iX, controlRect.iTl.iY);
1399     const QPoint backingStoreBase = qwidget->mapTo(qwidget->window(), controlBase);
1400     const TRect backingStoreRect(TPoint(backingStoreBase.x(), backingStoreBase.y()), controlRect.Size());
1401 
1402     if (engine->type() == QPaintEngine::Raster) {
1403         QS60WindowSurface *s60Surface;
1404 #ifdef QT_GRAPHICSSYSTEM_RUNTIME
1405         if (QApplicationPrivate::runtime_graphics_system) {
1406             QRuntimeWindowSurface *rtSurface =
1407                     static_cast<QRuntimeWindowSurface*>(qwidget->windowSurface());
1408             s60Surface = static_cast<QS60WindowSurface *>(rtSurface->m_windowSurface.data());
1409         } else
1410 #endif
1411             s60Surface = static_cast<QS60WindowSurface *>(qwidget->windowSurface());
1412 
1413         CFbsBitmap *bitmap = s60Surface->symbianBitmap();
1414         CWindowGc &gc = SystemGc();
1415 
1416         QWExtra::NativePaintMode nativePaintMode = qwidget->d_func()->extraData()->nativePaintMode;
1417         if(qwidget->d_func()->paintOnScreen())
1418             nativePaintMode = QWExtra::Disable;
1419 
1420         switch(nativePaintMode) {
1421         case QWExtra::Disable:
1422             // Do nothing
1423             break;
1424         case QWExtra::Blit:
1425         case QWExtra::BlitWriteAlpha:
1426             if (qwidget->d_func()->isOpaque || nativePaintMode == QWExtra::BlitWriteAlpha)
1427                 gc.SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha);
1428             gc.BitBlt(controlRect.iTl, bitmap, backingStoreRect);
1429             break;
1430         case QWExtra::ZeroFill:
1431             if (Window().DisplayMode() == EColor16MA
1432                 || Window().DisplayMode() == Q_SYMBIAN_ECOLOR16MAP) {
1433                 gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
1434                 gc.SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha);
1435                 gc.SetBrushColor(TRgb::Color16MA(0));
1436                 gc.Clear(controlRect);
1437             } else {
1438                 gc.SetBrushColor(TRgb(0x000000));
1439                 gc.Clear(controlRect);
1440             };
1441             break;
1442         default:
1443             Q_ASSERT(false);
1444         }
1445     }
1446 
1447     if (sendNativePaintEvents) {
1448         const QRect r = qt_TRect2QRect(wcontrolRect);
1449         // The draw ops aren't actually sent to WSERV until the graphics
1450         // context is deactivated, which happens in the function calling
1451         // this one.  We therefore delay the delivery of endNativePaintEvent,
1452         // to ensure that drawing has completed by the time the widget
1453         // receives the event.  Note that, if the widget needs to ensure
1454         // that the draw ops have actually been executed into the output
1455         // framebuffer, a call to RWsSession::Flush is required in the
1456         // endNativePaintEvent implementation.
1457         QMetaObject::invokeMethod(qwidget, "endNativePaintEvent", Qt::QueuedConnection, Q_ARG(QRect, r));
1458     }
1459 }
1460 
qwidgetResize_helper(const QSize & newSize)1461 void QSymbianControl::qwidgetResize_helper(const QSize &newSize)
1462 {
1463     QRect cr = qwidget->geometry();
1464     QSize oldSize(cr.size());
1465     cr.setSize(newSize);
1466     qwidget->data->crect = cr;
1467     if (qwidget->isVisible()) {
1468         QTLWExtra *tlwExtra = qwidget->d_func()->maybeTopData();
1469         bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt();
1470         if (!slowResize && tlwExtra)
1471             tlwExtra->inTopLevelResize = true;
1472         QResizeEvent e(newSize, oldSize);
1473         qt_sendSpontaneousEvent(qwidget, &e);
1474         if (!qwidget->testAttribute(Qt::WA_StaticContents))
1475             qwidget->d_func()->syncBackingStore();
1476         if (!slowResize && tlwExtra)
1477             tlwExtra->inTopLevelResize = false;
1478     } else {
1479         if (!qwidget->testAttribute(Qt::WA_PendingResizeEvent)) {
1480             QResizeEvent *e = new QResizeEvent(newSize, oldSize);
1481             QApplication::postEvent(qwidget, e);
1482         }
1483     }
1484 }
1485 
SizeChanged()1486 void QSymbianControl::SizeChanged()
1487 {
1488     CCoeControl::SizeChanged();
1489 
1490     // When FixNativeOrientation had been called, the RWindow/CCoeControl size
1491     // and the surface/QWidget size have nothing to do with each other.
1492     if (qwidget->d_func()->fixNativeOrientationCalled)
1493         return;
1494 
1495     QSize oldSize = qwidget->size();
1496     QSize newSize(Size().iWidth, Size().iHeight);
1497 
1498     if (oldSize != newSize) {
1499         // Enforce the proper size for fullscreen widgets on the secondary screen.
1500         const bool isFullscreen = qwidget->windowState() & Qt::WindowFullScreen;
1501         const int screenNumber = S60->screenNumberForWidget(qwidget);
1502         if (!m_inExternalScreenOverride && isFullscreen && screenNumber > 0) {
1503             int screenWidth = S60->screenWidthInPixelsForScreen[screenNumber];
1504             int screenHeight = S60->screenHeightInPixelsForScreen[screenNumber];
1505             TSize screenSize(screenWidth, screenHeight);
1506             if (screenWidth > 0 && screenHeight > 0 && screenSize != Size()) {
1507                 m_inExternalScreenOverride = true;
1508                 SetExtent(TPoint(0, 0), screenSize);
1509                 return;
1510             }
1511         }
1512 
1513         qwidgetResize_helper(newSize);
1514     }
1515 
1516     m_inExternalScreenOverride = false;
1517 
1518     // CCoeControl::SetExtent calls SizeChanged, but does not call
1519     // PositionChanged, so we call it here to ensure that the widget's
1520     // position is updated.
1521     PositionChanged();
1522 }
1523 
PositionChanged()1524 void QSymbianControl::PositionChanged()
1525 {
1526     CCoeControl::PositionChanged();
1527 
1528     QPoint oldPos = qwidget->geometry().topLeft();
1529     QPoint newPos(Position().iX, Position().iY);
1530 
1531     if (oldPos != newPos) {
1532         QRect cr = qwidget->geometry();
1533         cr.moveTopLeft(newPos);
1534         qwidget->data->crect = cr;
1535         QTLWExtra *top = qwidget->d_func()->maybeTopData();
1536         if (top && (qwidget->windowState() & (~Qt::WindowActive)) == Qt::WindowNoState)
1537             top->normalGeometry.moveTopLeft(newPos);
1538         if (qwidget->isVisible()) {
1539             QMoveEvent e(newPos, oldPos);
1540             qt_sendSpontaneousEvent(qwidget, &e);
1541         } else {
1542             QMoveEvent * e = new QMoveEvent(newPos, oldPos);
1543             QApplication::postEvent(qwidget, e);
1544         }
1545     }
1546 }
1547 
1548 // Search recursively if there is a child widget that is both visible and focused.
hasFocusedAndVisibleChild(QWidget * parentWidget)1549 bool QSymbianControl::hasFocusedAndVisibleChild(QWidget *parentWidget)
1550 {
1551     for (int i = 0; i < parentWidget->children().size(); ++i) {
1552         QObject *object = parentWidget->children().at(i);
1553         if (object && object->isWidgetType()) {
1554             QWidget *w = static_cast<QWidget *>(object);
1555             WId winId = w->internalWinId();
1556             if (winId && winId->IsFocused() && winId->IsVisible())
1557                 return true;
1558             if (hasFocusedAndVisibleChild(w))
1559                 return true;
1560         }
1561     }
1562     return false;
1563 }
1564 
FocusChanged(TDrawNow)1565 void QSymbianControl::FocusChanged(TDrawNow /* aDrawNow */)
1566 {
1567     QT_TRY {
1568         if (m_ignoreFocusChanged || (qwidget->windowType() & Qt::WindowType_Mask) == Qt::Desktop)
1569             return;
1570 
1571         // just in case
1572         if (qwidget->d_func()->isGLGlobalShareWidget)
1573             return;
1574 
1575 #ifdef Q_WS_S60
1576         if (S60->splitViewLastWidget)
1577             return;
1578 #endif
1579 
1580         // Popups never get focused, but still receive the FocusChanged when they are hidden.
1581         if (QApplicationPrivate::popupWidgets != 0
1582                 || (qwidget->windowType() & Qt::Popup) == Qt::Popup)
1583             return;
1584 
1585         QWidget *parentWindow = qwidget->window();
1586         if (IsFocused() && IsVisible()) {
1587             if (m_symbianPopupIsOpen) {
1588                 QWidget *fw = QApplication::focusWidget();
1589                 if (fw) {
1590                     QFocusEvent event(QEvent::FocusIn, Qt::PopupFocusReason);
1591                     QCoreApplication::sendEvent(fw, &event);
1592                 }
1593                 m_symbianPopupIsOpen = false;
1594             }
1595 
1596             QApplication::setActiveWindow(qwidget->window());
1597             qwidget->d_func()->setWindowIcon_sys(true);
1598             qwidget->d_func()->setWindowTitle_sys(qwidget->windowTitle());
1599 #ifdef Q_WS_S60
1600             if (parentWindow->isWindow())
1601                 S60->setRecursiveDecorationsVisibility(parentWindow, parentWindow->windowState());
1602 #endif
1603         } else {
1604             if (QApplication::activeWindow() == parentWindow && !hasFocusedAndVisibleChild(parentWindow)) {
1605                 if (CCoeEnv::Static()->AppUi()->IsDisplayingMenuOrDialog() || S60->menuBeingConstructed) {
1606                     QWidget *fw = QApplication::focusWidget();
1607                     if (fw) {
1608                         QFocusEvent event(QEvent::FocusOut, Qt::PopupFocusReason);
1609                         QCoreApplication::sendEvent(fw, &event);
1610                     }
1611                     m_symbianPopupIsOpen = true;
1612                     return;
1613                 }
1614 
1615                 QApplication::setActiveWindow(0);
1616             }
1617         }
1618         // else { We don't touch the active window unless we were explicitly activated or deactivated }
1619     } QT_CATCH(const std::exception&) {
1620         // ignore errors
1621     }
1622 }
1623 
handleClientAreaChange()1624 void QSymbianControl::handleClientAreaChange()
1625 {
1626     const bool cbaVisibilityHint = qwidget->windowFlags() & Qt::WindowSoftkeysVisibleHint;
1627     if (qwidget->isFullScreen() && !cbaVisibilityHint) {
1628         SetExtentToWholeScreen();
1629     } else if (qwidget->isMaximized() || (qwidget->isFullScreen() && cbaVisibilityHint)) {
1630         // Note that if there is S60->splitViewLastWidget, it means the resizing is done
1631         // by input context handling and we can use just default ClientRect.
1632         TRect r = (!S60->splitViewLastWidget) ? S60->clientRect() : static_cast<CEikAppUi*>(S60->appUi())->ClientRect();
1633         SetExtent(r.iTl, r.Size());
1634     } else if (!qwidget->isMinimized()) { // Normal geometry
1635         if (!qwidget->testAttribute(Qt::WA_Resized)) {
1636             qwidget->adjustSize();
1637             qwidget->setAttribute(Qt::WA_Resized, false); //not a user resize
1638         }
1639         if (!qwidget->testAttribute(Qt::WA_Moved) && qwidget->windowType() != Qt::Dialog) {
1640             TRect r = S60->clientRect();
1641             SetPosition(r.iTl);
1642             qwidget->setAttribute(Qt::WA_Moved, false); // not really an explicit position
1643         }
1644     }
1645 }
1646 
isSplitViewWidget(QWidget * widget)1647 bool QSymbianControl::isSplitViewWidget(QWidget *widget)
1648 {
1649     bool returnValue = true;
1650     // Ignore events sent to non-active windows, not visible widgets and not parents of input widget
1651     // and non-Qt dialogs.
1652     if (!qwidget->isActiveWindow()
1653         || !qwidget->isVisible()
1654         || !qwidget->isAncestorOf(widget)
1655         || CCoeEnv::Static()->AppUi()->IsDisplayingMenuOrDialog()) {
1656 
1657         returnValue = false;
1658     }
1659     return returnValue;
1660 }
1661 
HandleResourceChange(int resourceType)1662 void QSymbianControl::HandleResourceChange(int resourceType)
1663 {
1664     switch (resourceType) {
1665     case KSplitViewCloseEvent: //intentional fall-through
1666     case KSplitViewOpenEvent: {
1667 #if !defined(QT_NO_IM) && defined(Q_WS_S60)
1668 
1669         //Fetch widget getting the text input
1670         QWidget *widget = QWidget::keyboardGrabber();
1671         if (!widget) {
1672             if (QApplicationPrivate::popupWidgets) {
1673                 widget = QApplication::activePopupWidget()->focusWidget();
1674                 if (!widget) {
1675                     widget = QApplication::activePopupWidget();
1676                 }
1677             } else {
1678                 widget = QApplicationPrivate::focus_widget;
1679                 if (!widget) {
1680                     widget = qwidget;
1681                 }
1682             }
1683         }
1684         if (widget) {
1685             QCoeFepInputContext *ic = qobject_cast<QCoeFepInputContext *>(widget->inputContext());
1686             if (!ic) {
1687                 ic = qobject_cast<QCoeFepInputContext *>(qApp->inputContext());
1688             }
1689             if (ic) {
1690                 if (resourceType == KSplitViewCloseEvent) {
1691                     S60->partialKeyboardOpen = false;
1692                     ic->resetSplitViewWidget();
1693                 } else {
1694                     S60->partialKeyboardOpen = true;
1695                     if (isSplitViewWidget(widget))
1696                         ic->ensureFocusWidgetVisible(widget);
1697                 }
1698             }
1699         }
1700 #endif // !defined(QT_NO_IM) && defined(Q_WS_S60)
1701     }
1702     break;
1703     case KInternalStatusPaneChange:
1704         // When status pane is not visible, only handle client area change if status pane was
1705         // previously visible, as size changes to hidden status pane should not affect
1706         // client area.
1707         if (S60->statusPane() && (S60->statusPane()->IsVisible() || m_lastStatusPaneVisibility)) {
1708             m_lastStatusPaneVisibility = S60->statusPane()->IsVisible();
1709             if (S60->handleStatusPaneResizeNotifications)
1710                 handleClientAreaChange();
1711         }
1712         if (IsFocused() && IsVisible()) {
1713             qwidget->d_func()->setWindowIcon_sys(true);
1714             qwidget->d_func()->setWindowTitle_sys(qwidget->windowTitle());
1715         }
1716         break;
1717     case KUidValueCoeFontChangeEvent:
1718         // font change event
1719         break;
1720 #ifdef Q_WS_S60
1721     case KEikDynamicLayoutVariantSwitch:
1722     {
1723 #ifdef QT_SOFTKEYS_ENABLED
1724         // Update needed just in case softkeys contain icons
1725         QSoftKeyManager::updateSoftKeys();
1726 #endif
1727         handleClientAreaChange();
1728         // Send resize event to trigger desktopwidget workAreaResized signal
1729         if (qt_desktopWidget) {
1730             QResizeEvent e(qt_desktopWidget->size(), qt_desktopWidget->size());
1731             QApplication::sendEvent(qt_desktopWidget, &e);
1732         }
1733         // Send resize event to dialogs so they can adjust their position if necessary.
1734         if (qwidget->windowType() & Qt::Dialog) {
1735             QResizeEvent e(qwidget->size(), qwidget->size());
1736             QApplication::sendEvent(qwidget, &e);
1737         }
1738         break;
1739     }
1740 #endif
1741     default:
1742         break;
1743     }
1744 
1745     CCoeControl::HandleResourceChange(resourceType);
1746 
1747 }
CancelLongTapTimer()1748 void QSymbianControl::CancelLongTapTimer()
1749 {
1750     if (m_longTapDetector)
1751         m_longTapDetector->Cancel();
1752 }
1753 
MopSupplyObject(TTypeUid id)1754 TTypeUid::Ptr QSymbianControl::MopSupplyObject(TTypeUid id)
1755 {
1756     if (id.iUid == ETypeId)
1757         return id.MakePtr(this);
1758 
1759     return CCoeControl::MopSupplyObject(id);
1760 }
1761 
setFocusSafely(bool focus)1762 void QSymbianControl::setFocusSafely(bool focus)
1763 {
1764     if (qwidget->d_func()->isGLGlobalShareWidget)
1765         return;
1766 
1767     // The stack hack in here is very unfortunate, but it is the only way to ensure proper
1768     // focus in Symbian. If this is not executed, the control which happens to be on
1769     // the top of the stack may randomly be assigned focus by Symbian, for example
1770     // when creating new windows (specifically in CCoeAppUi::HandleStackChanged()).
1771 
1772     // Close any popups.
1773     CEikonEnv::Static()->EikAppUi()->StopDisplayingMenuBar();
1774 
1775     if (focus) {
1776         S60->appUi()->RemoveFromStack(this);
1777         // Symbian doesn't automatically remove focus from the last focused control, so we need to
1778         // remember it and clear focus ourselves.
1779         if (lastFocusedControl && lastFocusedControl != this)
1780             lastFocusedControl->SetFocus(false);
1781         QT_TRAP_THROWING(S60->appUi()->AddToStackL(this,
1782                 ECoeStackPriorityDefault + 1, ECoeStackFlagStandard)); // Note the + 1
1783         lastFocusedControl = this;
1784         this->SetFocus(true);
1785     } else {
1786         S60->appUi()->RemoveFromStack(this);
1787         QT_TRAP_THROWING(S60->appUi()->AddToStackL(this,
1788                 ECoeStackPriorityDefault, ECoeStackFlagStandard));
1789         if(this == lastFocusedControl)
1790             lastFocusedControl = 0;
1791         this->SetFocus(false);
1792     }
1793 }
1794 
isControlActive()1795 bool QSymbianControl::isControlActive()
1796 {
1797     return IsActivated() ? true : false;
1798 }
1799 
ensureFixNativeOrientation()1800 void QSymbianControl::ensureFixNativeOrientation()
1801 {
1802 #if defined(Q_SYMBIAN_SUPPORTS_FIXNATIVEORIENTATION)
1803     if (!qwidget->isWindow() || qwidget->windowType() == Qt::Desktop)
1804         return;
1805     if (S60->screenNumberForWidget(qwidget) > 0)
1806         return;
1807     const bool isFixed = qwidget->d_func()->fixNativeOrientationCalled;
1808     const bool isFixEnabled = qwidget->testAttribute(Qt::WA_SymbianNoSystemRotation);
1809     const bool isFullScreen = qwidget->windowState().testFlag(Qt::WindowFullScreen);
1810     if (isFullScreen && isFixEnabled) {
1811         const bool surfaceBasedGs =
1812             QApplicationPrivate::graphics_system_name == QLatin1String("openvg")
1813             || QApplicationPrivate::graphics_system_name == QLatin1String("opengl");
1814         if (!surfaceBasedGs)
1815             qwidget->setAttribute(Qt::WA_SymbianNoSystemRotation, false);
1816         if (!isFixed && surfaceBasedGs) {
1817             if (Window().FixNativeOrientation() == KErrNone) {
1818                 qwidget->d_func()->fixNativeOrientationCalled = true;
1819                 // The EGL window surface is now fixed to the native orientation
1820                 // of the device, no matter what size we pass when creating it.
1821                 // Enforce the same size for the QWidget too. For the underlying
1822                 // CCoeControl and RWindow it is up to the system to resize them
1823                 // when the standard auto-rotation mechanism is in use, we must not
1824                 // change that behavior by forcing any size for those. In practice
1825                 // this means that the QWidget and the underlying native control
1826                 // dimensions will be out of sync when FixNativeOrientation was
1827                 // called and the device is turned to the non-native (typically
1828                 // landscape) orientation. The pointer event handling and certain
1829                 // functions like Draw() will need to compensate for this.
1830                 QSize newSize(S60->nativeScreenWidthInPixels, S60->nativeScreenHeightInPixels);
1831                 if (qwidget->size() != newSize)
1832                     qwidgetResize_helper(newSize);
1833             } else {
1834                 qwidget->setAttribute(Qt::WA_SymbianNoSystemRotation, false);
1835             }
1836         }
1837     } else if (isFixed) {
1838         qwidget->setAttribute(Qt::WA_SymbianNoSystemRotation, false);
1839         qwidget->d_func()->fixNativeOrientationCalled = false;
1840         qwidget->hide();
1841         qwidget->d_func()->create_sys(0, false, true);
1842         qwidget->show();
1843     }
1844 #else
1845     qwidget->setAttribute(Qt::WA_SymbianNoSystemRotation, false);
1846 #endif
1847 }
1848 
1849 /*!
1850     \typedef QApplication::QS60MainApplicationFactory
1851     \since 4.6
1852 
1853     This is a typedef for a pointer to a function with the following
1854     signature:
1855 
1856     \snippet doc/src/snippets/code/src_corelib_global_qglobal.cpp 47
1857 
1858     \sa QApplication::QApplication()
1859 */
1860 
1861 /*!
1862     \since 4.6
1863 
1864     Creates an application using the application factory given in
1865     \a factory, and using \a argc command line arguments in \a argv.
1866     \a factory can be leaving, but the error will be converted to a
1867     standard exception.
1868 
1869     This function is only available on S60.
1870 */
QApplication(QApplication::QS60MainApplicationFactory factory,int & argc,char ** argv)1871 QApplication::QApplication(QApplication::QS60MainApplicationFactory factory, int &argc, char **argv)
1872     : QCoreApplication(*new QApplicationPrivate(argc, argv, GuiClient, 0x040000))
1873 {
1874     Q_D(QApplication);
1875     S60->s60ApplicationFactory = factory;
1876     d->construct();
1877 }
1878 
QApplication(QApplication::QS60MainApplicationFactory factory,int & argc,char ** argv,int _internal)1879 QApplication::QApplication(QApplication::QS60MainApplicationFactory factory, int &argc, char **argv, int _internal)
1880     : QCoreApplication(*new QApplicationPrivate(argc, argv, GuiClient, _internal))
1881 {
1882     Q_D(QApplication);
1883     S60->s60ApplicationFactory = factory;
1884     d->construct();
1885     QApplicationPrivate::app_compile_version = _internal;
1886 }
1887 
qt_init(QApplicationPrivate *,int)1888 void qt_init(QApplicationPrivate * /* priv */, int)
1889 {
1890     if (!CCoeEnv::Static()) {
1891         // The S60 framework creates a new trap handler which will render any existing traps
1892         // invalid as long as it is active. This means that all code in main() that occurs after
1893         // the QApplication construction needs to be surrounded by a new trap, despite having
1894         // an outer one already. To avoid this, we save the original trap handler here, and set
1895         // it back after the S60 framework is constructed. Then we restore it right before the S60
1896         // framework destruction.
1897         TTrapHandler *origTrapHandler = User::TrapHandler();
1898 
1899         // The S60 framework has not been initialized. We need to do it.
1900         TApaApplicationFactory factory(S60->s60ApplicationFactory ?
1901                 S60->s60ApplicationFactory : newS60Application);
1902         CApaCommandLine* commandLine = q_check_ptr(QCoreApplicationPrivate::symbianCommandLine());
1903         if (commandLine) {
1904             // After this construction, CEikonEnv will be available from CEikonEnv::Static().
1905             // (much like our qApp).
1906             CEikonEnv* coe = new CEikonEnv;
1907             //not using QT_TRAP_THROWING, because coe owns the cleanupstack so it can't be pushed there.
1908             TRAPD(err, coe->ConstructAppFromCommandLineL(factory, *commandLine));
1909             if(err != KErrNone) {
1910                 qWarning() << "qt_init: Eikon application construct failed ("
1911                            << err
1912                            << "), maybe missing resource file on S60 3.1?";
1913                 delete coe;
1914                 qt_symbian_throwIfError(err);
1915             }
1916         }
1917 
1918         S60->s60InstalledTrapHandler = User::SetTrapHandler(origTrapHandler);
1919 
1920         S60->qtOwnsS60Environment = true;
1921     } else {
1922         S60->qtOwnsS60Environment = false;
1923     }
1924 
1925 #ifdef QT_NO_DEBUG
1926     if (!qgetenv("QT_S60_AUTO_FLUSH_WSERV").isEmpty())
1927 #endif
1928         S60->wsSession().SetAutoFlush(ETrue);
1929 
1930 #ifdef Q_SYMBIAN_WINDOW_SIZE_CACHE
1931     TRAP_IGNORE(S60->wsSession().EnableWindowSizeCacheL());
1932 #endif
1933 
1934     S60->updateScreenSize();
1935 
1936 
1937     TDisplayMode mode = S60->screenDevice()->DisplayMode();
1938     S60->screenDepth = TDisplayModeUtils::NumDisplayModeBitsPerPixel(mode);
1939 
1940     //NB: RWsSession::GetColorModeList tells you what window modes are supported,
1941     //not what bitmap formats.
1942     if(QSysInfo::symbianVersion() == QSysInfo::SV_9_2)
1943         S60->supportsPremultipliedAlpha = 0;
1944     else
1945         S60->supportsPremultipliedAlpha = 1;
1946 
1947     RProcess me;
1948     TSecureId securId = me.SecureId();
1949     S60->uid = securId.operator TUid();
1950 
1951 #ifdef QT_SYMBIAN_HAVE_AKNTRANSEFFECT_H
1952     // Notify uiaccelerator, that we are qt application. This info is used for
1953     // decision making how startup effects are shown.
1954     GfxTransEffect::BeginFullScreen(AknTransEffect::ENone,
1955         TRect(0, 0, 0, 0),
1956         AknTransEffect::EParameterAvkonInternal,
1957         AknTransEffect::GfxTransParam(S60->uid, KQtAppExitFlag));
1958 #endif
1959     // enable focus events - used to re-enable mouse after focus changed between mouse and non mouse app,
1960     // and for dimming behind modal windows
1961     S60->windowGroup().EnableFocusChangeEvents();
1962 
1963     //Check if mouse interaction is supported (either EMouse=1 in the HAL, or EMachineUID is one of the phones known to support this)
1964     const TInt KMachineUidSamsungI8510 = 0x2000C51E;
1965     // HAL::Get(HALData::EPen, TInt& result) may set 'result' to 1 on some 3.1 systems (e.g. N95).
1966     // But we know that S60 systems below 5.0 did not support touch.
1967     static const bool touchIsUnsupportedOnSystem =
1968         QSysInfo::s60Version() == QSysInfo::SV_S60_3_1
1969         || QSysInfo::s60Version() == QSysInfo::SV_S60_3_2;
1970     TInt machineUID;
1971     TInt mouse;
1972     TInt touch;
1973     TInt err;
1974     err = HAL::Get(HALData::EMouse, mouse);
1975     if (err != KErrNone)
1976         mouse = 0;
1977     err = HAL::Get(HALData::EMachineUid, machineUID);
1978     if (err != KErrNone)
1979         machineUID = 0;
1980     err = HAL::Get(HALData::EPen, touch);
1981     if (err != KErrNone || touchIsUnsupportedOnSystem)
1982         touch = 0;
1983 #ifdef __WINS__
1984     if(QSysInfo::symbianVersion() <= QSysInfo::SV_9_4) {
1985         //for symbian SDK emulator, force values to match typical devices.
1986         mouse = 0;
1987         touch = touchIsUnsupportedOnSystem ? 0 : 1;
1988     }
1989 #endif
1990     if (mouse || machineUID == KMachineUidSamsungI8510) {
1991         S60->hasTouchscreen = false;
1992         S60->virtualMouseRequired = false;
1993     }
1994     else if (!touch) {
1995         S60->hasTouchscreen = false;
1996         S60->virtualMouseRequired = true;
1997     }
1998     else {
1999         S60->hasTouchscreen = true;
2000         S60->virtualMouseRequired = false;
2001     }
2002 
2003     S60->avkonComponentsSupportTransparency = false;
2004     S60->menuBeingConstructed = false;
2005 
2006 #ifdef Q_WS_S60
2007     TUid KCRUidAvkon = { 0x101F876E };
2008     TUint32 KAknAvkonTransparencyEnabled = 0x0000000D;
2009 
2010     CRepository* repository = 0;
2011     TRAP(err, repository = CRepository::NewL(KCRUidAvkon));
2012 
2013     if(err == KErrNone) {
2014         TInt value = 0;
2015         err = repository->Get(KAknAvkonTransparencyEnabled, value);
2016         if(err == KErrNone) {
2017             S60->avkonComponentsSupportTransparency = (value==1) ? true : false;
2018         }
2019     }
2020     delete repository;
2021     repository = 0;
2022 #endif
2023 
2024     qt_keymapper_private()->updateInputLanguage();
2025 
2026 #ifdef QT_KEYPAD_NAVIGATION
2027     if (touch) {
2028         QApplicationPrivate::navigationMode = Qt::NavigationModeNone;
2029     } else {
2030         QApplicationPrivate::navigationMode = Qt::NavigationModeKeypadDirectional;
2031     }
2032 #endif
2033 
2034 #ifndef QT_NO_CURSOR
2035     //Check if window server pointer cursors are supported or not
2036 #ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
2037     //In generic binary, use the HAL and OS version
2038     //Any other known good phones should be added here.
2039     if (machineUID == KMachineUidSamsungI8510 || (QSysInfo::symbianVersion() != QSysInfo::SV_9_4
2040         && QSysInfo::symbianVersion() != QSysInfo::SV_9_3 && QSysInfo::symbianVersion()
2041         != QSysInfo::SV_9_2)) {
2042         S60->brokenPointerCursors = false;
2043         qt_symbian_setWindowGroupCursor(Qt::ArrowCursor, S60->windowGroup());
2044     }
2045     else
2046         S60->brokenPointerCursors = true;
2047 #endif
2048 
2049     if (S60->mouseInteractionEnabled) {
2050 #ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
2051         if (S60->brokenPointerCursors) {
2052             qt_symbian_set_pointer_sprite(Qt::ArrowCursor);
2053             qt_symbian_show_pointer_sprite();
2054         }
2055         else
2056 #endif
2057             S60->wsSession().SetPointerCursorMode(EPointerCursorNormal);
2058     }
2059 #endif
2060 
2061     QFont systemFont;
2062     systemFont.setFamily(systemFont.defaultFamily());
2063     QApplicationPrivate::setSystemFont(systemFont);
2064 
2065     QObject::connect(qApp, SIGNAL(aboutToQuit()), qApp, SLOT(_q_aboutToQuit()));
2066 
2067 #ifdef Q_SYMBIAN_SEMITRANSPARENT_BG_SURFACE
2068     QApplicationPrivate::instance()->useTranslucentEGLSurfaces = true;
2069 
2070     if (QSymbianGraphicsSystemEx::hasBCM2727()) {
2071         // We have only 32MB GPU memory. Use raster surfaces
2072         // for transparent TLWs.
2073         QApplicationPrivate::instance()->useTranslucentEGLSurfaces = false;
2074     }
2075 
2076     if (QApplicationPrivate::graphics_system_name == QLatin1String("raster"))
2077         QApplicationPrivate::instance()->useTranslucentEGLSurfaces = false;
2078 #else
2079     QApplicationPrivate::instance()->useTranslucentEGLSurfaces = false;
2080 #endif
2081 /*
2082  ### Commented out for now as parameter handling not needed in SOS(yet). Code below will break testlib with -o flag
2083     int argc = priv->argc;
2084     char **argv = priv->argv;
2085 
2086     // Get command line params
2087     int j = argc ? 1 : 0;
2088     for (int i=1; i<argc; i++) {
2089         if (argv[i] && *argv[i] != '-') {
2090             argv[j++] = argv[i];
2091             continue;
2092         }
2093 
2094 #if defined(QT_DEBUG)
2095         if (qstrcmp(argv[i], "-nograb") == 0)
2096             appNoGrab = !appNoGrab;
2097         else
2098 #endif // QT_DEBUG
2099             ;
2100     }
2101 */
2102 
2103     // Register WId with the metatype system.  This is to enable
2104     // QWidgetPrivate::create_sys to used delayed slot invocation in order
2105     // to destroy WId objects during reparenting.
2106     qRegisterMetaType<WId>("WId");
2107 }
2108 
2109 #ifdef QT_NO_FREETYPE
2110 extern void qt_cleanup_symbianFontDatabase(); // qfontdatabase_s60.cpp
2111 #endif
2112 
2113 /*****************************************************************************
2114   qt_cleanup() - cleans up when the application is finished
2115  *****************************************************************************/
qt_cleanup()2116 void qt_cleanup()
2117 {
2118     if(qt_S60Beep) {
2119         delete qt_S60Beep;
2120         qt_S60Beep = 0;
2121     }
2122     QFontCache::cleanup(); // Has to happen now, since QFontEngineS60 has FBS handles
2123     QPixmapCache::clear(); // Has to happen now, since QSymbianRasterPixmapData has FBS handles
2124 
2125 #ifdef QT_NO_FREETYPE
2126     qt_cleanup_symbianFontDatabase();
2127 #endif
2128 // S60 structure and window server session are freed in eventdispatcher destructor as they are needed there
2129 
2130     // It's important that this happens here, before the event dispatcher gets
2131     // deleted, because the input context needs the event loop one last time before
2132     // it dies.
2133     delete QApplicationPrivate::inputContext;
2134     QApplicationPrivate::inputContext = 0;
2135 
2136     //Change mouse pointer back
2137     S60->wsSession().SetPointerCursorMode(EPointerCursorNone);
2138 
2139 #ifdef Q_WS_S60
2140     // Clear CBA
2141     CEikonEnv::Static()->AppUiFactory()->SwapButtonGroup(0);
2142     delete S60->buttonGroupContainer();
2143     S60->setButtonGroupContainer(0);
2144 #endif
2145 
2146     // Call EndFullScreen() to prevent confusing the system effect state machine.
2147     qt_endFullScreenEffect();
2148 
2149 #ifndef QT_NO_CURSOR
2150     QCursorData::cleanup();
2151 #endif
2152 
2153     if (S60->qtOwnsS60Environment) {
2154         // Restore the S60 framework trap handler. See qt_init().
2155         User::SetTrapHandler(S60->s60InstalledTrapHandler);
2156 
2157         CEikonEnv* coe = CEikonEnv::Static();
2158         coe->PrepareToExit();
2159         // The CEikonEnv itself is destroyed in here.
2160         coe->DestroyEnvironment();
2161     }
2162 }
2163 
initializeWidgetPaletteHash()2164 void QApplicationPrivate::initializeWidgetPaletteHash()
2165 {
2166     // TODO: Implement QApplicationPrivate::initializeWidgetPaletteHash()
2167     // Possibly a task fot the S60Style guys
2168 }
2169 
createEventDispatcher()2170 void QApplicationPrivate::createEventDispatcher()
2171 {
2172     Q_Q(QApplication);
2173     eventDispatcher = new QEventDispatcherS60(q);
2174 }
2175 
appName() const2176 QString QApplicationPrivate::appName() const
2177 {
2178     return QCoreApplicationPrivate::appName();
2179 }
2180 
modalState()2181 bool QApplicationPrivate::modalState()
2182 {
2183     return app_do_modal;
2184 }
2185 
enterModal_sys(QWidget * widget)2186 void QApplicationPrivate::enterModal_sys(QWidget *widget)
2187 {
2188 #ifdef Q_SYMBIAN_TRANSITION_EFFECTS
2189     S60->wsSession().SendEffectCommand(ETfxCmdAppModalModeEnter);
2190 #endif
2191     if (widget) {
2192         static_cast<QSymbianControl *>(widget->effectiveWinId())->FadeBehindPopup(ETrue);
2193         // Modal partial screen dialogs (like queries) capture pointer events.
2194         // ### FixMe: Add specialized behaviour for fullscreen modal dialogs
2195         widget->effectiveWinId()->SetGloballyCapturing(ETrue);
2196         widget->effectiveWinId()->SetPointerCapture(ETrue);
2197     }
2198     if (!qt_modal_stack)
2199         qt_modal_stack = new QWidgetList;
2200     qt_modal_stack->insert(0, widget);
2201     app_do_modal = true;
2202 }
2203 
leaveModal_sys(QWidget * widget)2204 void QApplicationPrivate::leaveModal_sys(QWidget *widget)
2205 {
2206 #ifdef Q_SYMBIAN_TRANSITION_EFFECTS
2207     S60->wsSession().SendEffectCommand(ETfxCmdAppModalModeExit);
2208 #endif
2209     if (widget) {
2210         static_cast<QSymbianControl *>(widget->effectiveWinId())->FadeBehindPopup(EFalse);
2211         // ### FixMe: Add specialized behaviour for fullscreen modal dialogs
2212         widget->effectiveWinId()->SetGloballyCapturing(EFalse);
2213         widget->effectiveWinId()->SetPointerCapture(EFalse);
2214     }
2215     if (qt_modal_stack && qt_modal_stack->removeAll(widget)) {
2216         if (qt_modal_stack->isEmpty()) {
2217             delete qt_modal_stack;
2218             qt_modal_stack = 0;
2219         }
2220     }
2221     app_do_modal = qt_modal_stack != 0;
2222 }
2223 
openPopup(QWidget * popup)2224 void QApplicationPrivate::openPopup(QWidget *popup)
2225 {
2226     if (popup && qobject_cast<QComboBox *>(popup->parentWidget()))
2227         static_cast<QSymbianControl *>(popup->effectiveWinId())->FadeBehindPopup(ETrue);
2228 
2229     if (!QApplicationPrivate::popupWidgets)
2230         QApplicationPrivate::popupWidgets = new QWidgetList;
2231     QApplicationPrivate::popupWidgets->append(popup);
2232 
2233     // Cancel focus widget pointer capture and long tap timer
2234     if (QApplication::focusWidget() && QApplication::focusWidget()->effectiveWinId()) {
2235         static_cast<QSymbianControl*>(QApplication::focusWidget()->effectiveWinId())->CancelLongTapTimer();
2236         QApplication::focusWidget()->effectiveWinId()->SetPointerCapture(false);
2237         }
2238 
2239     if (!qt_nograb()) {
2240         // Cancel pointer capture and long tap timer for earlier popup
2241         int popupCount = QApplicationPrivate::popupWidgets->count();
2242         if (popupCount > 1) {
2243             QWidget* prevPopup = QApplicationPrivate::popupWidgets->at(popupCount-2);
2244             static_cast<QSymbianControl*>(prevPopup->effectiveWinId())->CancelLongTapTimer();
2245             prevPopup->effectiveWinId()->SetPointerCapture(false);
2246         }
2247 
2248         // Enable pointer capture for this (topmost) popup
2249         Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created));
2250         WId id = popup->effectiveWinId();
2251         id->SetPointerCapture(true);
2252     }
2253 
2254     // popups are not focus-handled by the window system (the first
2255     // popup grabbed the keyboard), so we have to do that manually: A
2256     // new popup gets the focus
2257     QWidget *fw = popup->focusWidget();
2258     if (fw) {
2259         fw->setFocus(Qt::PopupFocusReason);
2260     } else if (QApplicationPrivate::popupWidgets->count() == 1) { // this was the first popup
2261         fw = QApplication::focusWidget();
2262         if (fw) {
2263             QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason);
2264             q_func()->sendEvent(fw, &e);
2265         }
2266     }
2267 }
2268 
closePopup(QWidget * popup)2269 void QApplicationPrivate::closePopup(QWidget *popup)
2270 {
2271     if (popup && qobject_cast<QComboBox *>(popup->parentWidget()))
2272         static_cast<QSymbianControl *>(popup->effectiveWinId())->FadeBehindPopup(EFalse);
2273 
2274     if (!QApplicationPrivate::popupWidgets)
2275         return;
2276     QApplicationPrivate::popupWidgets->removeAll(popup);
2277 
2278     // Cancel pointer capture and long tap for this popup
2279     WId id = popup->effectiveWinId();
2280     id->SetPointerCapture(false);
2281     static_cast<QSymbianControl*>(id)->CancelLongTapTimer();
2282 
2283     if (QApplicationPrivate::popupWidgets->isEmpty()) { // this was the last popup
2284         delete QApplicationPrivate::popupWidgets;
2285         QApplicationPrivate::popupWidgets = 0;
2286         if (!qt_nograb()) {                        // grabbing not disabled
2287             Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created));
2288             if (QWidgetPrivate::mouseGrabber != 0)
2289                 QWidgetPrivate::mouseGrabber->grabMouse();
2290 
2291             if (QWidgetPrivate::keyboardGrabber != 0)
2292                 QWidgetPrivate::keyboardGrabber->grabKeyboard();
2293 
2294         QWidget *fw = QApplicationPrivate::active_window ? QApplicationPrivate::active_window->focusWidget()
2295               : q_func()->focusWidget();
2296           if (fw) {
2297               if(fw->window()->isModal()) // restore pointer capture for modal window
2298                   fw->effectiveWinId()->SetPointerCapture(true);
2299 
2300               if (fw != q_func()->focusWidget()) {
2301                   fw->setFocus(Qt::PopupFocusReason);
2302               } else {
2303                   QFocusEvent e(QEvent::FocusIn, Qt::PopupFocusReason);
2304                   q_func()->sendEvent(fw, &e);
2305               }
2306           }
2307         }
2308     } else {
2309 
2310         // popups are not focus-handled by the window system (the
2311         // first popup grabbed the keyboard), so we have to do that
2312         // manually: A popup was closed, so the previous popup gets
2313         // the focus.
2314         QWidget* aw = QApplicationPrivate::popupWidgets->last();
2315         if (QWidget *fw = QApplication::focusWidget()) {
2316             QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason);
2317             q_func()->sendEvent(fw, &e);
2318         }
2319 
2320         // Enable pointer capture for previous popup
2321         if (aw) {
2322             aw->effectiveWinId()->SetPointerCapture(true);
2323         }
2324     }
2325 }
2326 
topLevelAt(QPoint const & point)2327 QWidget * QApplication::topLevelAt(QPoint const& point)
2328 {
2329     QWidget *found = 0;
2330     int lowestZ = INT_MAX;
2331     QWidgetList list = QApplication::topLevelWidgets();
2332     for (int i = 0; i < list.count(); ++i) {
2333         QWidget *widget = list.at(i);
2334         if (widget->isVisible() && !(widget->windowType() == Qt::Desktop)) {
2335             Q_ASSERT(widget->testAttribute(Qt::WA_WState_Created));
2336             if (widget->geometry().adjusted(0,0,1,1).contains(point)) {
2337                 // At this point we know there is a Qt widget under the point.
2338                 // Now we need to make sure it is the top most in the z-order.
2339                 RDrawableWindow *const window = widget->effectiveWinId()->DrawableWindow();
2340                 int z = window->OrdinalPosition();
2341                 if (z < lowestZ) {
2342                     lowestZ = z;
2343                     found = widget;
2344                 }
2345             }
2346         }
2347     }
2348     return found;
2349 }
2350 
alert(QWidget *,int)2351 void QApplication::alert(QWidget * /* widget */, int /* duration */)
2352 {
2353     // TODO: Implement QApplication::alert(QWidget *widget, int duration)
2354 }
2355 
doubleClickInterval()2356 int QApplication::doubleClickInterval()
2357 {
2358     TTimeIntervalMicroSeconds32 us;
2359     TInt distance;
2360     S60->wsSession().GetDoubleClickSettings(us, distance);
2361     return (us.Int() / 1000);
2362 }
2363 
setDoubleClickInterval(int ms)2364 void QApplication::setDoubleClickInterval(int ms)
2365 {
2366     TTimeIntervalMicroSeconds32 newUs( ms * 1000);
2367     TTimeIntervalMicroSeconds32 us;
2368     TInt distance;
2369     S60->wsSession().GetDoubleClickSettings(us, distance);
2370     if (us != newUs)
2371         S60->wsSession().SetDoubleClick(newUs, distance);
2372 }
2373 
keyboardInputInterval()2374 int QApplication::keyboardInputInterval()
2375 {
2376     return QApplicationPrivate::keyboard_input_time;
2377 }
2378 
setKeyboardInputInterval(int ms)2379 void QApplication::setKeyboardInputInterval(int ms)
2380 {
2381     QApplicationPrivate::keyboard_input_time = ms;
2382 }
2383 
cursorFlashTime()2384 int QApplication::cursorFlashTime()
2385 {
2386     return QApplicationPrivate::cursor_flash_time;
2387 }
2388 
setCursorFlashTime(int msecs)2389 void QApplication::setCursorFlashTime(int msecs)
2390 {
2391     QApplicationPrivate::cursor_flash_time = msecs;
2392 }
2393 
beep()2394 void QApplication::beep()
2395 {
2396     if (!qt_S60Beep) {
2397         TInt frequency = 880;
2398         TTimeIntervalMicroSeconds duration(500000);
2399         TRAP_IGNORE(qt_S60Beep=QS60Beep::NewL(frequency, duration));
2400     }
2401     if (qt_S60Beep)
2402         qt_S60Beep->Play();
2403 }
2404 
callSymbianEventFilters(const QSymbianEvent * event)2405 static inline bool callSymbianEventFilters(const QSymbianEvent *event)
2406 {
2407     long unused;
2408     return qApp->filterEvent(const_cast<QSymbianEvent *>(event), &unused);
2409 }
2410 
2411 /*!
2412     \warning This function is only available on Symbian.
2413     \since 4.6
2414 
2415     This function processes an individual Symbian event
2416     \a event. It returns 1 if the event was handled, 0 if
2417     the \a event was not handled, and -1 if the event was
2418     not handled because the event is not known to Qt.
2419  */
2420 
symbianProcessEvent(const QSymbianEvent * event)2421 int QApplication::symbianProcessEvent(const QSymbianEvent *event)
2422 {
2423     Q_D(QApplication);
2424 
2425     QScopedLoopLevelCounter counter(d->threadData);
2426 
2427     QT_TRY {
2428         if (d->eventDispatcher->filterEvent(const_cast<QSymbianEvent *>(event)))
2429             return 1;
2430 
2431         QWidget *w = qApp ? qApp->focusWidget() : 0;
2432         if (w) {
2433             QInputContext *ic = w->inputContext();
2434             if (ic && ic->symbianFilterEvent(w, event))
2435                 return 1;
2436         }
2437 
2438         if (symbianEventFilter(event))
2439             return 1;
2440     } QT_CATCH(const std::exception& ex) {
2441         // don't allow an exception to stop exit command handling
2442         if (event->type() != QSymbianEvent::CommandEvent || event->command() != EEikCmdExit)
2443             QT_RETHROW;
2444     }
2445 
2446     switch (event->type()) {
2447     case QSymbianEvent::WindowServerEvent:
2448         return d->symbianProcessWsEvent(event);
2449     case QSymbianEvent::CommandEvent:
2450         return d->symbianHandleCommand(event);
2451     case QSymbianEvent::ResourceChangeEvent:
2452         return d->symbianResourceChange(event);
2453     default:
2454         return -1;
2455     }
2456 }
2457 
symbianProcessWsEvent(const QSymbianEvent * symbianEvent)2458 int QApplicationPrivate::symbianProcessWsEvent(const QSymbianEvent *symbianEvent)
2459 {
2460     // Qt event handling. Handle some events regardless of if the handle is in our
2461     // widget map or not.
2462     const TWsEvent *event = symbianEvent->windowServerEvent();
2463     CCoeControl* control = reinterpret_cast<CCoeControl*>(event->Handle());
2464     const bool controlInMap = QWidgetPrivate::mapper && QWidgetPrivate::mapper->contains(control);
2465     switch (event->Type()) {
2466     case EEventPointerEnter:
2467         if (controlInMap) {
2468             callSymbianEventFilters(symbianEvent);
2469             return 1; // Qt::Enter will be generated in HandlePointerL
2470         }
2471         break;
2472     case EEventPointerExit:
2473         if (controlInMap) {
2474             if (callSymbianEventFilters(symbianEvent))
2475                 return 1;
2476             if (S60) {
2477                 // mouseEvent outside our window, send leave event to last focused widget
2478                 QMouseEvent mEvent(QEvent::Leave, S60->lastPointerEventPos, S60->lastCursorPos,
2479                     Qt::NoButton, QApplicationPrivate::mouse_buttons, Qt::NoModifier);
2480                 if (S60->lastPointerEventTarget)
2481                     qt_sendSpontaneousEvent(S60->lastPointerEventTarget,&mEvent);
2482                 S60->lastPointerEventTarget = 0;
2483             }
2484             return 1;
2485         }
2486         break;
2487     case EEventScreenDeviceChanged: // fallthrough
2488 #if defined(Q_SYMBIAN_SUPPORTS_MULTIPLE_SCREENS)
2489     case EEventDisplayChanged:
2490 #endif
2491         {
2492         if (callSymbianEventFilters(symbianEvent))
2493             return 1;
2494         if (S60)
2495             S60->updateScreenSize();
2496         if (qt_desktopWidget) {
2497             QSize oldSize = qt_desktopWidget->size();
2498             qt_desktopWidget->data->crect.setWidth(S60->screenWidthInPixels);
2499             qt_desktopWidget->data->crect.setHeight(S60->screenHeightInPixels);
2500             QResizeEvent e(qt_desktopWidget->size(), oldSize);
2501             QApplication::sendEvent(qt_desktopWidget, &e);
2502         }
2503         // Close non-native QMenus (that should act like context menus, i.e. close
2504         // automatically when the orientation changes).
2505         QMenu *activeMenu = qobject_cast<QMenu *>(QApplication::activePopupWidget());
2506         if (activeMenu)
2507             activeMenu->close();
2508         }
2509         return 0; // Propagate to CONE
2510     case EEventWindowVisibilityChanged:
2511         if (controlInMap) {
2512             if (callSymbianEventFilters(symbianEvent))
2513                 return 1;
2514             const TWsVisibilityChangedEvent *visChangedEvent = event->VisibilityChanged();
2515             if (visChangedEvent->iFlags & TWsVisibilityChangedEvent::ENotVisible)
2516                 S60->controlVisibilityChanged(control, false);
2517             else if (visChangedEvent->iFlags & TWsVisibilityChangedEvent::EPartiallyVisible)
2518                 S60->controlVisibilityChanged(control, true);
2519             return 1;
2520         }
2521         break;
2522     case EEventFocusGained:
2523         if (callSymbianEventFilters(symbianEvent))
2524             return 1;
2525 #ifndef QT_NO_CURSOR
2526         //re-enable mouse interaction
2527         if (S60->mouseInteractionEnabled) {
2528 #ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
2529             if (S60->brokenPointerCursors)
2530                 qt_symbian_show_pointer_sprite();
2531             else
2532 #endif
2533                 S60->wsSession().SetPointerCursorMode(EPointerCursorNormal);
2534         }
2535 #endif
2536 #ifdef QT_SOFTKEYS_ENABLED
2537         if (!CEikonEnv::Static()->EikAppUi()->IsDisplayingMenuOrDialog())
2538             QSoftKeyManager::updateSoftKeys();
2539 #endif
2540         break;
2541     case EEventFocusLost:
2542         if (callSymbianEventFilters(symbianEvent))
2543             return 1;
2544 #ifndef QT_NO_CURSOR
2545         //disable mouse as may be moving to application that does not support it
2546         if (S60->mouseInteractionEnabled) {
2547 #ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
2548             if (S60->brokenPointerCursors)
2549                 qt_symbian_hide_pointer_sprite();
2550             else
2551 #endif
2552                 S60->wsSession().SetPointerCursorMode(EPointerCursorNone);
2553         }
2554 #endif
2555         break;
2556     case KGoomMemoryLowEvent:
2557 #ifdef QT_DEBUG
2558         qDebug() << "QApplicationPrivate::symbianProcessWsEvent - KGoomMemoryLowEvent";
2559 #endif
2560         if (callSymbianEventFilters(symbianEvent))
2561             return 1;
2562 #ifdef QT_GRAPHICSSYSTEM_RUNTIME
2563         if(QApplicationPrivate::runtime_graphics_system) {
2564             bool switchToSwRendering(false);
2565 
2566             foreach (QWidget *w, QApplication::topLevelWidgets()) {
2567                 if(w->d_func()->topData()->backingStore) {
2568                     switchToSwRendering = true;
2569                     break;
2570                 }
2571             }
2572 
2573             if (switchToSwRendering) {
2574                 QRuntimeGraphicsSystem *gs =
2575                    static_cast<QRuntimeGraphicsSystem*>(QApplicationPrivate::graphics_system);
2576                 gs->setGraphicsSystem(QLatin1String("raster"));
2577             }
2578         }
2579 #endif
2580         break;
2581     case KGoomMemoryGoodEvent:
2582 #ifdef QT_DEBUG
2583         qDebug() << "QApplicationPrivate::symbianProcessWsEvent - KGoomMemoryGoodEvent";
2584 #endif
2585         if (callSymbianEventFilters(symbianEvent))
2586             return 1;
2587 #ifdef QT_GRAPHICSSYSTEM_RUNTIME
2588         if(QApplicationPrivate::runtime_graphics_system) {
2589             QRuntimeGraphicsSystem *gs =
2590                    static_cast<QRuntimeGraphicsSystem*>(QApplicationPrivate::graphics_system);
2591             gs->setGraphicsSystem(QLatin1String("openvg"));
2592         }
2593 #endif
2594         break;
2595 #ifdef Q_SYMBIAN_SUPPORTS_SURFACES
2596     case EEventUser:
2597         {
2598             // GOOM is looking for candidates to kill so indicate that we are
2599             // capable of cleaning up by handling this event
2600             TInt32 *data = reinterpret_cast<TInt32 *>(event->EventData());
2601             if (data[0] == EApaSystemEventShutdown && data[1] == KGoomMemoryLowEvent)
2602                 return 1;
2603         }
2604         break;
2605 #endif
2606 
2607 #ifdef Q_WS_S60
2608     case KEikInputLanguageChange:
2609         qt_keymapper_private()->updateInputLanguage();
2610         break;
2611 #endif
2612 
2613     default:
2614         break;
2615     }
2616 
2617     if (!controlInMap)
2618         return -1;
2619 
2620     return 0;
2621 }
2622 
2623 /*!
2624   \warning This virtual function is only available on Symbian.
2625   \since 4.6
2626 
2627   If you create an application that inherits QApplication and reimplement
2628   this function, you get direct access to events that the are received
2629   from Symbian. The events are passed in the \a event parameter.
2630 
2631   Return true if you want to stop the event from being processed. Return
2632   false for normal event dispatching. The default implementation returns
2633   false, and does nothing with \a event.
2634  */
symbianEventFilter(const QSymbianEvent * event)2635 bool QApplication::symbianEventFilter(const QSymbianEvent *event)
2636 {
2637     Q_UNUSED(event);
2638     return false;
2639 }
2640 
2641 /*!
2642   \warning This function is only available on Symbian.
2643   \since 4.6
2644 
2645   Handles \a{command}s which are typically handled by
2646   CAknAppUi::HandleCommandL(). Qts Ui integration into Symbian is
2647   partially achieved by deriving from CAknAppUi. Currently, exit,
2648   menu and softkey commands are handled.
2649 
2650   \sa s60EventFilter(), s60ProcessEvent()
2651 */
symbianHandleCommand(const QSymbianEvent * symbianEvent)2652 int QApplicationPrivate::symbianHandleCommand(const QSymbianEvent *symbianEvent)
2653 {
2654     Q_Q(QApplication);
2655     int ret = 0;
2656 
2657     if (callSymbianEventFilters(symbianEvent))
2658         return 1;
2659 
2660     int command = symbianEvent->command();
2661 
2662     switch (command) {
2663 #ifdef Q_WS_S60
2664     case EAknSoftkeyExit: {
2665         QCloseEvent ev;
2666         QApplication::sendSpontaneousEvent(q, &ev);
2667         if (ev.isAccepted()) {
2668             q->quit();
2669             ret = 1;
2670         }
2671         break;
2672     }
2673 #endif
2674     case EEikCmdExit:
2675         q->quit();
2676         ret = 1;
2677         break;
2678     default:
2679 #ifdef Q_WS_S60
2680         bool handled = QSoftKeyManager::handleCommand(command);
2681         if (handled)
2682             ret = 1;
2683         else
2684             ret = QMenuBarPrivate::symbianCommands(command);
2685 #endif
2686         break;
2687     }
2688 
2689     return ret;
2690 }
2691 
2692 /*!
2693   \warning This function is only available on Symbian.
2694   \since 4.6
2695 
2696   Handles the resource change specified by \a type.
2697 
2698   Currently, KEikDynamicLayoutVariantSwitch and
2699   KAknsMessageSkinChange are handled.
2700  */
symbianResourceChange(const QSymbianEvent * symbianEvent)2701 int QApplicationPrivate::symbianResourceChange(const QSymbianEvent *symbianEvent)
2702 {
2703     int ret = 0;
2704 
2705     int type = symbianEvent->resourceChangeType();
2706 
2707     switch (type) {
2708 #ifdef Q_WS_S60
2709     case KEikDynamicLayoutVariantSwitch:
2710         {
2711         if (callSymbianEventFilters(symbianEvent))
2712             return 1;
2713         if (S60)
2714             S60->updateScreenSize();
2715 
2716 #ifndef QT_NO_STYLE_S60
2717         QS60Style *s60Style = 0;
2718 
2719 #ifndef QT_NO_STYLE_STYLESHEET
2720         QStyleSheetStyle *proxy = qobject_cast<QStyleSheetStyle*>(QApplication::style());
2721         if (proxy)
2722             s60Style = qobject_cast<QS60Style*>(proxy->baseStyle());
2723         else
2724 #endif
2725             s60Style = qobject_cast<QS60Style*>(QApplication::style());
2726 
2727         if (s60Style) {
2728             s60Style->d_func()->handleDynamicLayoutVariantSwitch();
2729             ret = 1;
2730         }
2731 #endif
2732         }
2733         break;
2734 
2735 #ifndef QT_NO_STYLE_S60
2736     case KAknsMessageSkinChange:
2737         if (callSymbianEventFilters(symbianEvent))
2738             return 1;
2739         if (QS60Style *s60Style = qobject_cast<QS60Style*>(QApplication::style())) {
2740             s60Style->d_func()->handleSkinChange();
2741             ret = 1;
2742         }
2743         break;
2744 #endif
2745 #endif // Q_WS_S60
2746     default:
2747         break;
2748     }
2749 
2750     return ret;
2751 }
2752 
symbianHandleLiteModeStartup()2753 void QApplicationPrivate::symbianHandleLiteModeStartup()
2754 {
2755     if (QCoreApplication::arguments().contains(QLatin1String("--startup-lite"))) {
2756         if (!QApplication::testAttribute(Qt::AA_S60DontConstructApplicationPanes)
2757                 && !S60->buttonGroupContainer() && !S60->statusPane()) {
2758             // hide and force this app to the background before creating screen furniture to avoid flickers
2759             CAknAppUi *appui = static_cast<CAknAppUi*>(CCoeEnv::Static()->AppUi());
2760             if (appui)
2761                 appui->HideApplicationFromFSW(ETrue);
2762             CCoeEnv::Static()->RootWin().SetOrdinalPosition(-1);
2763             S60->createStatusPaneAndCBA();
2764             if (S60->statusPane()) {
2765                 S60->setStatusPaneAndButtonGroupVisibility(false, false);
2766             }
2767         }
2768     }
2769 }
2770 
2771 #ifndef QT_NO_WHEELEVENT
wheelScrollLines()2772 int QApplication::wheelScrollLines()
2773 {
2774     return QApplicationPrivate::wheel_scroll_lines;
2775 }
2776 
setWheelScrollLines(int n)2777 void QApplication::setWheelScrollLines(int n)
2778 {
2779     QApplicationPrivate::wheel_scroll_lines = n;
2780 }
2781 #endif //QT_NO_WHEELEVENT
2782 
isEffectEnabled(Qt::UIEffect)2783 bool QApplication::isEffectEnabled(Qt::UIEffect /* effect */)
2784 {
2785     // TODO: Implement QApplication::isEffectEnabled(Qt::UIEffect effect)
2786     return false;
2787 }
2788 
setEffectEnabled(Qt::UIEffect,bool)2789 void QApplication::setEffectEnabled(Qt::UIEffect /* effect */, bool /* enable */)
2790 {
2791     // TODO: Implement QApplication::setEffectEnabled(Qt::UIEffect effect, bool enable)
2792 }
2793 
queryKeyboardModifiers()2794 Qt::KeyboardModifiers QApplication::queryKeyboardModifiers()
2795 {
2796     return app_keyboardModifiers;
2797 }
2798 
resolveS60ScanCode(TInt scanCode,TUint keysym)2799 TUint QApplicationPrivate::resolveS60ScanCode(TInt scanCode, TUint keysym)
2800 {
2801     if (!scanCode)
2802         return keysym;
2803 
2804     QApplicationPrivate *d = QApplicationPrivate::instance();
2805 
2806     if (keysym) {
2807         // If keysym is specified, cache it.
2808         d->scanCodeCache.insert(scanCode, keysym);
2809         return keysym;
2810     } else {
2811         // If not, retrieve the cached version.
2812         return d->scanCodeCache[scanCode];
2813     }
2814 }
2815 
initializeMultitouch_sys()2816 void QApplicationPrivate::initializeMultitouch_sys()
2817 {
2818 #ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
2819     if (HAL::Get(HALData::EPointer3DPressureSupported, pressureSupported) != KErrNone)
2820         pressureSupported = 0;
2821     if (HAL::Get(HALData::EPointer3DMaxPressure, maxTouchPressure) != KErrNone)
2822         maxTouchPressure = KMaxTInt;
2823 #else
2824     pressureSupported = 0;
2825     maxTouchPressure = KMaxTInt;
2826 #endif
2827 }
2828 
cleanupMultitouch_sys()2829 void QApplicationPrivate::cleanupMultitouch_sys()
2830 { }
2831 
2832 #ifndef QT_NO_SESSIONMANAGER
QSessionManager(QApplication *,QString &,QString &)2833 QSessionManager::QSessionManager(QApplication * /* app */, QString & /* id */, QString& /* key */)
2834 {
2835 
2836 }
2837 
~QSessionManager()2838 QSessionManager::~QSessionManager()
2839 {
2840 
2841 }
2842 
allowsInteraction()2843 bool QSessionManager::allowsInteraction()
2844 {
2845     return false;
2846 }
2847 
cancel()2848 void QSessionManager::cancel()
2849 {
2850 
2851 }
2852 #endif //QT_NO_SESSIONMANAGER
2853 
2854 #ifdef QT_KEYPAD_NAVIGATION
2855 /*
2856  * Show/Hide the mouse cursor depending on phone type and chosen mode
2857  */
setNavigationMode(Qt::NavigationMode mode)2858 void QApplicationPrivate::setNavigationMode(Qt::NavigationMode mode)
2859 {
2860 #ifndef QT_NO_CURSOR
2861     const bool wasCursorOn = (QApplicationPrivate::navigationMode == Qt::NavigationModeCursorAuto
2862         && !S60->hasTouchscreen)
2863         || QApplicationPrivate::navigationMode == Qt::NavigationModeCursorForceVisible;
2864     const bool isCursorOn = (mode == Qt::NavigationModeCursorAuto
2865         && !S60->hasTouchscreen)
2866         || mode == Qt::NavigationModeCursorForceVisible;
2867 
2868     if (!wasCursorOn && isCursorOn) {
2869         //Show the cursor, when changing from another mode to cursor mode
2870         qt_symbian_set_cursor_visible(true);
2871     }
2872     else if (wasCursorOn && !isCursorOn) {
2873         //Hide the cursor, when leaving cursor mode
2874         qt_symbian_set_cursor_visible(false);
2875     }
2876 #endif
2877     QApplicationPrivate::navigationMode = mode;
2878 }
2879 #endif
2880 
2881 #ifndef QT_NO_CURSOR
2882 /*****************************************************************************
2883  QApplication cursor stack
2884  *****************************************************************************/
2885 
setOverrideCursor(const QCursor & cursor)2886 void QApplication::setOverrideCursor(const QCursor &cursor)
2887 {
2888     qApp->d_func()->cursor_list.prepend(cursor);
2889     qt_symbian_setGlobalCursor(cursor);
2890 }
2891 
restoreOverrideCursor()2892 void QApplication::restoreOverrideCursor()
2893 {
2894     if (qApp->d_func()->cursor_list.isEmpty())
2895         return;
2896     qApp->d_func()->cursor_list.removeFirst();
2897 
2898     if (!qApp->d_func()->cursor_list.isEmpty()) {
2899         qt_symbian_setGlobalCursor(qApp->d_func()->cursor_list.first());
2900     }
2901     else {
2902         //determine which widget has focus
2903         QWidget *w = QApplication::widgetAt(QCursor::pos());
2904 #ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
2905         if (S60->brokenPointerCursors) {
2906             qt_symbian_set_pointer_sprite(w ? w->cursor() : Qt::ArrowCursor);
2907         }
2908         else
2909 #endif
2910         {
2911             //because of the internals of window server, we need to force the cursor
2912             //to be set in all child windows too, otherwise when the cursor is over
2913             //the child window it may show a widget cursor or arrow cursor instead,
2914             //depending on construction order.
2915             QListIterator<WId> iter(QWidgetPrivate::mapper->uniqueKeys());
2916             while (iter.hasNext()) {
2917                 CCoeControl *ctrl = iter.next();
2918                 if(ctrl->OwnsWindow()) {
2919                     ctrl->DrawableWindow()->ClearPointerCursor();
2920                 }
2921             }
2922             if (w)
2923                 qt_symbian_setWindowCursor(w->cursor(), w->effectiveWinId());
2924             else
2925                 qt_symbian_setWindowGroupCursor(Qt::ArrowCursor, S60->windowGroup());
2926         }
2927     }
2928 }
2929 
2930 #endif // QT_NO_CURSOR
2931 
_q_aboutToQuit()2932 void QApplicationPrivate::_q_aboutToQuit()
2933 {
2934     qt_beginFullScreenEffect();
2935 
2936 #ifdef Q_SYMBIAN_TRANSITION_EFFECTS
2937     // Send the shutdown tfx command
2938     S60->wsSession().SendEffectCommand(ETfxCmdAppShutDown);
2939 #endif
2940 }
2941 
emitAboutToReleaseGpuResources()2942 void QApplicationPrivate::emitAboutToReleaseGpuResources()
2943 {
2944 #ifdef Q_SYMBIAN_SUPPORTS_SURFACES
2945     Q_Q(QApplication);
2946     QPointer<QApplication> guard(q);
2947     emit q->aboutToReleaseGpuResources();
2948 #endif
2949 }
2950 
emitAboutToUseGpuResources()2951 void QApplicationPrivate::emitAboutToUseGpuResources()
2952 {
2953 #ifdef Q_SYMBIAN_SUPPORTS_SURFACES
2954     Q_Q(QApplication);
2955     QPointer<QApplication> guard(q);
2956     emit q->aboutToUseGpuResources();
2957 #endif
2958 }
2959 
QS60ThreadLocalData()2960 QS60ThreadLocalData::QS60ThreadLocalData()
2961 {
2962     CCoeEnv *env = CCoeEnv::Static();
2963     if (env) {
2964         //if this is the UI thread, share objects owned by CONE
2965         usingCONEinstances = true;
2966         wsSession = env->WsSession();
2967         screenDevice = env->ScreenDevice();
2968     }
2969     else {
2970         usingCONEinstances = false;
2971         qt_symbian_throwIfError(wsSession.Connect(qt_s60GetRFs()));
2972         screenDevice = new CWsScreenDevice(wsSession);
2973         screenDevice->Construct();
2974     }
2975 }
2976 
~QS60ThreadLocalData()2977 QS60ThreadLocalData::~QS60ThreadLocalData()
2978 {
2979     for (int i = 0; i < releaseFuncs.count(); ++i)
2980         releaseFuncs[i]();
2981     releaseFuncs.clear();
2982     if (!usingCONEinstances) {
2983         // wserv has a thread specific handle, do not close it, or delete the screenDevice, if it is not open in this thread
2984         THandleInfo handleInfo;
2985         wsSession.HandleInfo(&handleInfo);
2986         if (handleInfo.iNumOpenInThread) {
2987             delete screenDevice;
2988             wsSession.Close();
2989         }
2990     }
2991 }
2992 
2993 QT_END_NAMESPACE
2994