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