source: trunk/src/gui/kernel/qapplication_s60.cpp@ 769

Last change on this file since 769 was 769, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.3 sources from branches/vendor/nokia/qt.

  • Property svn:eol-style set to native
File size: 69.2 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
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
66#include "apgwgnam.h" // For CApaWindowGroupName
67#include <mdaaudiotoneplayer.h> // For CMdaAudioToneUtility
68
69#if defined(Q_WS_S60)
70# if !defined(QT_NO_IM)
71# include "qinputcontext.h"
72# include <private/qcoefepinputcontext_p.h>
73# endif
74# include <private/qs60mainapplication_p.h>
75# include <centralrepository.h>
76# include "qs60mainappui.h"
77#endif
78
79#include "private/qstylesheetstyle_p.h"
80
81#include <hal.h>
82#include <hal_data.h>
83
84QT_BEGIN_NAMESPACE
85
86#if defined(QT_DEBUG)
87static bool appNoGrab = false; // Grabbing enabled
88#endif
89static bool app_do_modal = false; // modal mode
90Q_GLOBAL_STATIC(QS60Data, qt_s60Data);
91
92extern bool qt_sendSpontaneousEvent(QObject*,QEvent*);
93extern QWidgetList *qt_modal_stack; // stack of modal widgets
94extern QDesktopWidget *qt_desktopWidget; // qapplication.cpp
95
96QWidget *qt_button_down = 0; // widget got last button-down
97
98QSymbianControl *QSymbianControl::lastFocusedControl = 0;
99
100QS60Data* qGlobalS60Data()
101{
102 return qt_s60Data();
103}
104
105bool qt_nograb() // application no-grab option
106{
107#if defined(QT_DEBUG)
108 return appNoGrab;
109#else
110 return false;
111#endif
112}
113
114// Modified from http://www3.symbian.com/faq.nsf/0/0F1464EE96E737E780256D5E00503DD1?OpenDocument
115class QS60Beep : public CBase, public MMdaAudioToneObserver
116{
117public:
118 static QS60Beep* NewL(TInt aFrequency, TTimeIntervalMicroSeconds iDuration);
119 void Play();
120 ~QS60Beep();
121private:
122 void ConstructL(TInt aFrequency, TTimeIntervalMicroSeconds iDuration);
123 void MatoPrepareComplete(TInt aError);
124 void MatoPlayComplete(TInt aError);
125private:
126 typedef enum
127 {
128 EBeepNotPrepared,
129 EBeepPrepared,
130 EBeepPlaying
131 } TBeepState;
132private:
133 CMdaAudioToneUtility* iToneUtil;
134 TBeepState iState;
135 TInt iFrequency;
136 TTimeIntervalMicroSeconds iDuration;
137};
138
139static QS60Beep* qt_S60Beep = 0;
140
141QS60Beep::~QS60Beep()
142{
143 if (iToneUtil) {
144 switch (iState) {
145 case EBeepPlaying:
146 iToneUtil->CancelPlay();
147 break;
148 case EBeepNotPrepared:
149 iToneUtil->CancelPrepare();
150 break;
151 }
152 }
153 delete iToneUtil;
154}
155
156QS60Beep* QS60Beep::NewL(TInt aFrequency, TTimeIntervalMicroSeconds aDuration)
157{
158 QS60Beep* self = new (ELeave) QS60Beep();
159 CleanupStack::PushL(self);
160 self->ConstructL(aFrequency, aDuration);
161 CleanupStack::Pop();
162 return self;
163}
164
165void QS60Beep::ConstructL(TInt aFrequency, TTimeIntervalMicroSeconds aDuration)
166{
167 iToneUtil = CMdaAudioToneUtility::NewL(*this);
168 iState = EBeepNotPrepared;
169 iFrequency = aFrequency;
170 iDuration = aDuration;
171 iToneUtil->PrepareToPlayTone(iFrequency, iDuration);
172}
173
174void QS60Beep::Play()
175{
176 if (iState == EBeepPlaying) {
177 iToneUtil->CancelPlay();
178 iState = EBeepPrepared;
179 }
180
181 iToneUtil->Play();
182 iState = EBeepPlaying;
183}
184
185void QS60Beep::MatoPrepareComplete(TInt aError)
186{
187 if (aError == KErrNone) {
188 iState = EBeepPrepared;
189 Play();
190 }
191}
192
193void QS60Beep::MatoPlayComplete(TInt aError)
194{
195 Q_UNUSED(aError);
196 iState = EBeepPrepared;
197}
198
199
200QHash<TInt, TUint> QApplicationPrivate::scanCodeCache;
201
202static Qt::KeyboardModifiers mapToQtModifiers(TUint s60Modifiers)
203{
204 Qt::KeyboardModifiers result = Qt::NoModifier;
205
206 if (s60Modifiers & EModifierKeypad)
207 result |= Qt::KeypadModifier;
208 if (s60Modifiers & EModifierShift || s60Modifiers & EModifierLeftShift
209 || s60Modifiers & EModifierRightShift)
210 result |= Qt::ShiftModifier;
211 if (s60Modifiers & EModifierCtrl || s60Modifiers & EModifierLeftCtrl
212 || s60Modifiers & EModifierRightCtrl)
213 result |= Qt::ControlModifier;
214 if (s60Modifiers & EModifierAlt || s60Modifiers & EModifierLeftAlt
215 || s60Modifiers & EModifierRightAlt)
216 result |= Qt::AltModifier;
217
218 return result;
219}
220
221static void mapS60MouseEventTypeToQt(QEvent::Type *type, Qt::MouseButton *button, const TPointerEvent *pEvent)
222{
223 switch (pEvent->iType) {
224 case TPointerEvent::EButton1Down:
225 *type = QEvent::MouseButtonPress;
226 *button = Qt::LeftButton;
227 break;
228 case TPointerEvent::EButton1Up:
229 *type = QEvent::MouseButtonRelease;
230 *button = Qt::LeftButton;
231 break;
232 case TPointerEvent::EButton2Down:
233 *type = QEvent::MouseButtonPress;
234 *button = Qt::MidButton;
235 break;
236 case TPointerEvent::EButton2Up:
237 *type = QEvent::MouseButtonRelease;
238 *button = Qt::MidButton;
239 break;
240 case TPointerEvent::EButton3Down:
241 *type = QEvent::MouseButtonPress;
242 *button = Qt::RightButton;
243 break;
244 case TPointerEvent::EButton3Up:
245 *type = QEvent::MouseButtonRelease;
246 *button = Qt::RightButton;
247 break;
248 case TPointerEvent::EDrag:
249 *type = QEvent::MouseMove;
250 *button = Qt::NoButton;
251 break;
252 case TPointerEvent::EMove:
253 // Qt makes no distinction between move and drag
254 *type = QEvent::MouseMove;
255 *button = Qt::NoButton;
256 break;
257 default:
258 *type = QEvent::None;
259 *button = Qt::NoButton;
260 break;
261 }
262 if (pEvent->iModifiers & EModifierDoubleClick){
263 *type = QEvent::MouseButtonDblClick;
264 }
265
266 if (*type == QEvent::MouseButtonPress || *type == QEvent::MouseButtonDblClick)
267 QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons | (*button);
268 else if (*type == QEvent::MouseButtonRelease)
269 QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons &(~(*button));
270
271 QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons & Qt::MouseButtonMask;
272}
273
274//### Can be replaced with CAknLongTapDetector if animation is required.
275//NOTE: if CAknLongTapDetector is used make sure it gets variated out of 3.1 and 3.2,.
276//also MLongTapObserver needs to be changed to MAknLongTapDetectorCallBack if CAknLongTapDetector is used.
277class QLongTapTimer : public CTimer
278{
279public:
280 static QLongTapTimer* NewL(QAbstractLongTapObserver *observer);
281 QLongTapTimer(QAbstractLongTapObserver *observer);
282 void ConstructL();
283public:
284 void PointerEventL(const TPointerEvent &event);
285 void RunL();
286protected:
287private:
288 QAbstractLongTapObserver *m_observer;
289 TPointerEvent m_event;
290 QPoint m_pressedCoordinates;
291 int m_dragDistance;
292};
293
294QLongTapTimer* QLongTapTimer::NewL(QAbstractLongTapObserver *observer)
295{
296 QLongTapTimer* self = new QLongTapTimer(observer);
297 self->ConstructL();
298 return self;
299}
300void QLongTapTimer::ConstructL()
301{
302 CTimer::ConstructL();
303}
304
305QLongTapTimer::QLongTapTimer(QAbstractLongTapObserver *observer):CTimer(CActive::EPriorityHigh)
306{
307 m_observer = observer;
308 m_dragDistance = qApp->startDragDistance();
309 CActiveScheduler::Add(this);
310}
311
312void QLongTapTimer::PointerEventL(const TPointerEvent& event)
313{
314 if ( event.iType == TPointerEvent::EDrag || event.iType == TPointerEvent::EButtonRepeat)
315 {
316 QPoint diff(QPoint(event.iPosition.iX,event.iPosition.iY) - m_pressedCoordinates);
317 if (diff.manhattanLength() < m_dragDistance)
318 return;
319 }
320 Cancel();
321 m_event = event;
322 if (event.iType == TPointerEvent::EButton1Down)
323 {
324 m_pressedCoordinates = QPoint(event.iPosition.iX,event.iPosition.iY);
325 // must be same as KLongTapDelay in aknlongtapdetector.h
326 After(800000);
327 }
328}
329void QLongTapTimer::RunL()
330{
331 if (m_observer)
332 m_observer->HandleLongTapEventL(m_event.iPosition, m_event.iParentPosition);
333}
334
335QSymbianControl::QSymbianControl(QWidget *w)
336 : CCoeControl()
337 , qwidget(w)
338 , m_longTapDetector(0)
339 , m_ignoreFocusChanged(0)
340 , m_symbianPopupIsOpen(0)
341{
342}
343
344void QSymbianControl::ConstructL(bool isWindowOwning, bool desktop)
345{
346 if (!desktop)
347 {
348 if (isWindowOwning or !qwidget->parentWidget())
349 CreateWindowL(S60->windowGroup());
350 else
351 /**
352 * TODO: in order to avoid creating windows for all ancestors of
353 * this widget up to the root window, the parameter passed to
354 * CreateWindowL should be
355 * qwidget->parentWidget()->effectiveWinId(). However, if we do
356 * this, then we need to take care of re-parenting when a window
357 * is created for a widget between this one and the root window.
358 */
359 CreateWindowL(qwidget->parentWidget()->winId());
360
361 // Necessary in order to be able to track the activation status of
362 // the control's window
363 qwidget->d_func()->createExtra();
364
365 SetFocusing(true);
366 m_longTapDetector = QLongTapTimer::NewL(this);
367
368 DrawableWindow()->SetPointerGrab(ETrue);
369 }
370}
371
372QSymbianControl::~QSymbianControl()
373{
374 if (S60->curWin == this)
375 S60->curWin = 0;
376 if (!QApplicationPrivate::is_app_closing) {
377 QT_TRY {
378 setFocusSafely(false);
379 } QT_CATCH(const std::exception&) {
380 // ignore exceptions, nothing can be done
381 }
382 }
383 S60->appUi()->RemoveFromStack(this);
384 delete m_longTapDetector;
385}
386
387void QSymbianControl::setWidget(QWidget *w)
388{
389 qwidget = w;
390}
391void QSymbianControl::HandleLongTapEventL( const TPoint& aPenEventLocation, const TPoint& aPenEventScreenLocation )
392{
393 QWidget *alienWidget;
394 QPoint widgetPos = QPoint(aPenEventLocation.iX, aPenEventLocation.iY);
395 QPoint globalPos = QPoint(aPenEventScreenLocation.iX,aPenEventScreenLocation.iY);
396 alienWidget = qwidget->childAt(widgetPos);
397 if (!alienWidget)
398 alienWidget = qwidget;
399
400#if !defined(QT_NO_CONTEXTMENU)
401 QContextMenuEvent contextMenuEvent(QContextMenuEvent::Mouse, widgetPos, globalPos, Qt::NoModifier);
402 qt_sendSpontaneousEvent(alienWidget, &contextMenuEvent);
403#endif
404}
405
406#ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
407void QSymbianControl::translateAdvancedPointerEvent(const TAdvancedPointerEvent *event)
408{
409 QApplicationPrivate *d = QApplicationPrivate::instance();
410 qreal pressure;
411 if(d->pressureSupported
412 && event->Pressure() > 0) //workaround for misconfigured HAL
413 pressure = event->Pressure() / qreal(d->maxTouchPressure);
414 else
415 pressure = qreal(1.0);
416
417 QRect screenGeometry = qApp->desktop()->screenGeometry(qwidget);
418
419 QList<QTouchEvent::TouchPoint> points = d->appAllTouchPoints;
420 while (points.count() <= event->PointerNumber())
421 points.append(QTouchEvent::TouchPoint(points.count()));
422
423 Qt::TouchPointStates allStates = 0;
424 for (int i = 0; i < points.count(); ++i) {
425 QTouchEvent::TouchPoint &touchPoint = points[i];
426
427 if (touchPoint.id() == event->PointerNumber()) {
428 Qt::TouchPointStates state;
429 switch (event->iType) {
430 case TPointerEvent::EButton1Down:
431 case TPointerEvent::EEnterHighPressure:
432 state = Qt::TouchPointPressed;
433 break;
434 case TPointerEvent::EButton1Up:
435 case TPointerEvent::EExitCloseProximity:
436 state = Qt::TouchPointReleased;
437 break;
438 case TPointerEvent::EDrag:
439 state = Qt::TouchPointMoved;
440 break;
441 default:
442 // how likely is this to happen?
443 state = Qt::TouchPointStationary;
444 break;
445 }
446 if (event->PointerNumber() == 0)
447 state |= Qt::TouchPointPrimary;
448 touchPoint.setState(state);
449
450 QPointF screenPos = qwidget->mapToGlobal(QPoint(event->iPosition.iX, event->iPosition.iY));
451 touchPoint.setScreenPos(screenPos);
452 touchPoint.setNormalizedPos(QPointF(screenPos.x() / screenGeometry.width(),
453 screenPos.y() / screenGeometry.height()));
454
455 touchPoint.setPressure(pressure);
456 } else if (touchPoint.state() != Qt::TouchPointReleased) {
457 // all other active touch points should be marked as stationary
458 touchPoint.setState(Qt::TouchPointStationary);
459 }
460
461 allStates |= touchPoint.state();
462 }
463
464 if ((allStates & Qt::TouchPointStateMask) == Qt::TouchPointReleased) {
465 // all touch points released
466 d->appAllTouchPoints.clear();
467 } else {
468 d->appAllTouchPoints = points;
469 }
470
471 QApplicationPrivate::translateRawTouchEvent(qwidget,
472 QTouchEvent::TouchScreen,
473 points);
474}
475#endif
476
477void QSymbianControl::HandlePointerEventL(const TPointerEvent& pEvent)
478{
479#ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
480 if (pEvent.IsAdvancedPointerEvent()) {
481 const TAdvancedPointerEvent *advancedPointerEvent = pEvent.AdvancedPointerEvent();
482 translateAdvancedPointerEvent(advancedPointerEvent);
483 if (advancedPointerEvent->PointerNumber() != 0) {
484 // only send mouse events for the first touch point
485 return;
486 }
487 }
488#endif
489
490 m_longTapDetector->PointerEventL(pEvent);
491 QT_TRYCATCH_LEAVING(HandlePointerEvent(pEvent));
492}
493
494void QSymbianControl::HandlePointerEvent(const TPointerEvent& pEvent)
495{
496 QMouseEvent::Type type;
497 Qt::MouseButton button;
498 mapS60MouseEventTypeToQt(&type, &button, &pEvent);
499 Qt::KeyboardModifiers modifiers = mapToQtModifiers(pEvent.iModifiers);
500
501 QPoint widgetPos = QPoint(pEvent.iPosition.iX, pEvent.iPosition.iY);
502 TPoint controlScreenPos = PositionRelativeToScreen();
503 QPoint globalPos = QPoint(controlScreenPos.iX, controlScreenPos.iY) + widgetPos;
504 S60->lastCursorPos = globalPos;
505 S60->lastPointerEventPos = widgetPos;
506
507 QWidget *mouseGrabber = QWidget::mouseGrabber();
508
509 QWidget *popupWidget = qApp->activePopupWidget();
510 QWidget *popupReceiver = 0;
511 if (popupWidget) {
512 QWidget *popupChild = popupWidget->childAt(popupWidget->mapFromGlobal(globalPos));
513 popupReceiver = popupChild ? popupChild : popupWidget;
514 }
515
516 if (mouseGrabber) {
517 if (popupReceiver) {
518 sendMouseEvent(popupReceiver, type, globalPos, button, modifiers);
519 } else {
520 sendMouseEvent(mouseGrabber, type, globalPos, button, modifiers);
521 }
522 // No Enter/Leave events in grabbing mode.
523 return;
524 }
525
526 QWidget *widgetUnderPointer = qwidget->childAt(widgetPos);
527 if (!widgetUnderPointer)
528 widgetUnderPointer = qwidget;
529
530 QApplicationPrivate::dispatchEnterLeave(widgetUnderPointer, S60->lastPointerEventTarget);
531 S60->lastPointerEventTarget = widgetUnderPointer;
532
533 QWidget *receiver;
534 if (!popupReceiver && S60->mousePressTarget && type != QEvent::MouseButtonPress) {
535 receiver = S60->mousePressTarget;
536 if (type == QEvent::MouseButtonRelease)
537 S60->mousePressTarget = 0;
538 } else {
539 receiver = popupReceiver ? popupReceiver : widgetUnderPointer;
540 if (type == QEvent::MouseButtonPress)
541 S60->mousePressTarget = receiver;
542 }
543
544#if !defined(QT_NO_CURSOR) && !defined(Q_SYMBIAN_FIXED_POINTER_CURSORS)
545 if (S60->brokenPointerCursors)
546 qt_symbian_move_cursor_sprite();
547#endif
548
549 sendMouseEvent(receiver, type, globalPos, button, modifiers);
550}
551
552#ifdef Q_WS_S60
553void QSymbianControl::HandleStatusPaneSizeChange()
554{
555 QS60MainAppUi *s60AppUi = static_cast<QS60MainAppUi *>(S60->appUi());
556 s60AppUi->HandleStatusPaneSizeChange();
557}
558#endif
559
560void QSymbianControl::sendMouseEvent(
561 QWidget *receiver,
562 QEvent::Type type,
563 const QPoint &globalPos,
564 Qt::MouseButton button,
565 Qt::KeyboardModifiers modifiers)
566{
567 Q_ASSERT(receiver);
568 QMouseEvent mEvent(type, receiver->mapFromGlobal(globalPos), globalPos,
569 button, QApplicationPrivate::mouse_buttons, modifiers);
570 QEventDispatcherS60 *dispatcher;
571 // It is theoretically possible for someone to install a different event dispatcher.
572 if ((dispatcher = qobject_cast<QEventDispatcherS60 *>(receiver->d_func()->threadData->eventDispatcher)) != 0) {
573 if (dispatcher->excludeUserInputEvents()) {
574 dispatcher->saveInputEvent(this, receiver, new QMouseEvent(mEvent));
575 return;
576 }
577 }
578
579 sendMouseEvent(receiver, &mEvent);
580}
581
582bool QSymbianControl::sendMouseEvent(QWidget *widget, QMouseEvent *mEvent)
583{
584 return qt_sendSpontaneousEvent(widget, mEvent);
585}
586
587TKeyResponse QSymbianControl::OfferKeyEventL(const TKeyEvent& keyEvent, TEventCode type)
588{
589 TKeyResponse r = EKeyWasNotConsumed;
590 QT_TRYCATCH_LEAVING(r = OfferKeyEvent(keyEvent, type));
591 return r;
592}
593
594TKeyResponse QSymbianControl::OfferKeyEvent(const TKeyEvent& keyEvent, TEventCode type)
595{
596 switch (type) {
597 //case EEventKeyDown: // <-- Intentionally left out. See below.
598 case EEventKeyUp:
599 case EEventKey:
600 {
601 // S60 has a confusing way of delivering key events. There are three types of
602 // events: EKeyEvent, EKeyEventDown and EKeyEventUp. When a key is pressed, the
603 // two first events are generated. When releasing the key, the last one is
604 // generated.
605 // Because S60 does not generate keysyms for EKeyEventDown and EKeyEventUp events,
606 // we need to do some special tricks to map it to the Qt way. First, we completely
607 // discard EKeyEventDown events, since they are redundant. Second, since
608 // EKeyEventUp does not give us a keysym, we need to cache the keysyms from
609 // the EKeyEvent events. This is what resolveS60ScanCode does.
610
611
612 // ### hackish way to send Qt application to background when pressing right softkey
613 /*
614 if( keyEvent.iScanCode == EStdKeyDevice1 ) {
615 S60->window_group->SetOrdinalPosition(-1);
616 qApp->setActiveWindow(0);
617 return EKeyWasNotConsumed;
618 }
619 */
620
621 TUint s60Keysym = QApplicationPrivate::resolveS60ScanCode(keyEvent.iScanCode,
622 keyEvent.iCode);
623 int keyCode;
624 if (s60Keysym == EKeyNull){ //some key events have 0 in iCode, for them iScanCode should be used
625 keyCode = qt_keymapper_private()->mapS60ScanCodesToQt(keyEvent.iScanCode);
626 } else if (s60Keysym >= 0x20 && s60Keysym < ENonCharacterKeyBase) {
627 // Normal characters keys.
628 keyCode = s60Keysym;
629 } else {
630 // Special S60 keys.
631 keyCode = qt_keymapper_private()->mapS60KeyToQt(s60Keysym);
632 }
633
634#ifndef QT_NO_CURSOR
635 if (S60->mouseInteractionEnabled && S60->virtualMouseRequired) {
636 //translate keys to pointer
637 if (keyCode >= Qt::Key_Left && keyCode <= Qt::Key_Down || keyCode == Qt::Key_Select) {
638 /*Explanation about virtualMouseAccel:
639 Tapping an arrow key allows precise pixel positioning
640 Holding an arrow key down, acceleration is applied to allow cursor
641 to be quickly moved to another part of the screen by key repeats.
642 */
643 if (S60->virtualMouseLastKey == keyCode) {
644 S60->virtualMouseAccel *= 2;
645 if (S60->virtualMouseAccel > S60->virtualMouseMaxAccel)
646 S60->virtualMouseAccel = S60->virtualMouseMaxAccel;
647 }
648 else
649 S60->virtualMouseAccel = 1;
650 S60->virtualMouseLastKey = keyCode;
651
652 QPoint pos = QCursor::pos();
653 TPointerEvent fakeEvent;
654 fakeEvent.iType = (TPointerEvent::TType)(-1);
655 TInt x = pos.x();
656 TInt y = pos.y();
657 if (type == EEventKeyUp) {
658 if (keyCode == Qt::Key_Select &&
659 (S60->virtualMousePressedKeys & QS60Data::Select))
660 fakeEvent.iType = TPointerEvent::EButton1Up;
661 S60->virtualMouseAccel = 1;
662 S60->virtualMouseLastKey = 0;
663 switch (keyCode) {
664 case Qt::Key_Left:
665 S60->virtualMousePressedKeys &= ~QS60Data::Left;
666 break;
667 case Qt::Key_Right:
668 S60->virtualMousePressedKeys &= ~QS60Data::Right;
669 break;
670 case Qt::Key_Up:
671 S60->virtualMousePressedKeys &= ~QS60Data::Up;
672 break;
673 case Qt::Key_Down:
674 S60->virtualMousePressedKeys &= ~QS60Data::Down;
675 break;
676 case Qt::Key_Select:
677 S60->virtualMousePressedKeys &= ~QS60Data::Select;
678 break;
679 }
680 }
681 else if (type == EEventKey) {
682 switch (keyCode) {
683 case Qt::Key_Left:
684 S60->virtualMousePressedKeys |= QS60Data::Left;
685 x -= S60->virtualMouseAccel;
686 fakeEvent.iType = TPointerEvent::EMove;
687 break;
688 case Qt::Key_Right:
689 S60->virtualMousePressedKeys |= QS60Data::Right;
690 x += S60->virtualMouseAccel;
691 fakeEvent.iType = TPointerEvent::EMove;
692 break;
693 case Qt::Key_Up:
694 S60->virtualMousePressedKeys |= QS60Data::Up;
695 y -= S60->virtualMouseAccel;
696 fakeEvent.iType = TPointerEvent::EMove;
697 break;
698 case Qt::Key_Down:
699 S60->virtualMousePressedKeys |= QS60Data::Down;
700 y += S60->virtualMouseAccel;
701 fakeEvent.iType = TPointerEvent::EMove;
702 break;
703 case Qt::Key_Select:
704 // Platform bug. If you start pressing several keys simultaneously (for
705 // example for drag'n'drop), Symbian starts producing spurious up and
706 // down messages for some keys. Therefore, make sure we have a clean slate
707 // of pressed keys before starting a new button press.
708 if (S60->virtualMousePressedKeys & QS60Data::Select) {
709 return EKeyWasConsumed;
710 } else {
711 S60->virtualMousePressedKeys |= QS60Data::Select;
712 fakeEvent.iType = TPointerEvent::EButton1Down;
713 }
714 break;
715 }
716 }
717 //clip to screen size (window server allows a sprite hotspot to be outside the screen)
718 if (x < 0)
719 x = 0;
720 else if (x >= S60->screenWidthInPixels)
721 x = S60->screenWidthInPixels - 1;
722 if (y < 0)
723 y = 0;
724 else if (y >= S60->screenHeightInPixels)
725 y = S60->screenHeightInPixels - 1;
726 TPoint epos(x, y);
727 TPoint cpos = epos - PositionRelativeToScreen();
728 fakeEvent.iModifiers = keyEvent.iModifiers;
729 fakeEvent.iPosition = cpos;
730 fakeEvent.iParentPosition = epos;
731 if(fakeEvent.iType != -1)
732 HandlePointerEvent(fakeEvent);
733 return EKeyWasConsumed;
734 }
735 else {
736 S60->virtualMouseLastKey = keyCode;
737 S60->virtualMouseAccel = 1;
738 }
739 }
740#endif
741
742 Qt::KeyboardModifiers mods = mapToQtModifiers(keyEvent.iModifiers);
743 QKeyEventEx qKeyEvent(type == EEventKeyUp ? QEvent::KeyRelease : QEvent::KeyPress, keyCode,
744 mods, qt_keymapper_private()->translateKeyEvent(keyCode, mods),
745 (keyEvent.iRepeats != 0), 1, keyEvent.iScanCode, s60Keysym, keyEvent.iModifiers);
746// WId wid = reinterpret_cast<RWindowGroup *>(keyEvent.Handle())->Child();
747// if (!wid)
748// Could happen if window isn't shown yet.
749// return EKeyWasNotConsumed;
750 QWidget *widget;
751 widget = QWidget::keyboardGrabber();
752 if (!widget) {
753 if (QApplicationPrivate::popupWidgets != 0) {
754 widget = QApplication::activePopupWidget()->focusWidget();
755 if (!widget) {
756 widget = QApplication::activePopupWidget();
757 }
758 } else {
759 widget = QApplicationPrivate::focus_widget;
760 if (!widget) {
761 widget = qwidget;
762 }
763 }
764 }
765
766 QEventDispatcherS60 *dispatcher;
767 // It is theoretically possible for someone to install a different event dispatcher.
768 if ((dispatcher = qobject_cast<QEventDispatcherS60 *>(widget->d_func()->threadData->eventDispatcher)) != 0) {
769 if (dispatcher->excludeUserInputEvents()) {
770 dispatcher->saveInputEvent(this, widget, new QKeyEventEx(qKeyEvent));
771 return EKeyWasConsumed;
772 }
773 }
774 return sendKeyEvent(widget, &qKeyEvent);
775 }
776 }
777 return EKeyWasNotConsumed;
778}
779
780void QSymbianControl::sendInputEvent(QWidget *widget, QInputEvent *inputEvent)
781{
782 switch (inputEvent->type()) {
783 case QEvent::KeyPress:
784 case QEvent::KeyRelease:
785 sendKeyEvent(widget, static_cast<QKeyEvent *>(inputEvent));
786 break;
787 case QEvent::MouseButtonDblClick:
788 case QEvent::MouseButtonPress:
789 case QEvent::MouseButtonRelease:
790 case QEvent::MouseMove:
791 sendMouseEvent(widget, static_cast<QMouseEvent *>(inputEvent));
792 break;
793 default:
794 // Shouldn't get here.
795 Q_ASSERT_X(0 == 1, "QSymbianControl::sendInputEvent()", "inputEvent->type() is unknown");
796 break;
797 }
798}
799
800TKeyResponse QSymbianControl::sendKeyEvent(QWidget *widget, QKeyEvent *keyEvent)
801{
802#if !defined(QT_NO_IM) && defined(Q_WS_S60)
803 if (widget && widget->isEnabled() && widget->testAttribute(Qt::WA_InputMethodEnabled)) {
804 QInputContext *qic = widget->inputContext();
805 if (qic && qic->filterEvent(keyEvent))
806 return EKeyWasConsumed;
807 }
808#endif // !defined(QT_NO_IM) && defined(Q_WS_S60)
809
810 if (widget && qt_sendSpontaneousEvent(widget, keyEvent))
811 if (keyEvent->isAccepted())
812 return EKeyWasConsumed;
813
814 return EKeyWasNotConsumed;
815}
816
817#if !defined(QT_NO_IM) && defined(Q_WS_S60)
818TCoeInputCapabilities QSymbianControl::InputCapabilities() const
819{
820 QWidget *w = 0;
821
822 if (qwidget->hasFocus())
823 w = qwidget;
824 else
825 w = qwidget->focusWidget();
826
827 QCoeFepInputContext *ic;
828 if (w && w->isEnabled() && w->testAttribute(Qt::WA_InputMethodEnabled)
829 && (ic = qobject_cast<QCoeFepInputContext *>(w->inputContext()))) {
830 return ic->inputCapabilities();
831 } else {
832 return TCoeInputCapabilities(TCoeInputCapabilities::ENone, 0, 0);
833 }
834}
835#endif
836
837void QSymbianControl::Draw(const TRect& controlRect) const
838{
839 // Set flag to avoid calling DrawNow in window surface
840 QWidget *window = qwidget->window();
841 Q_ASSERT(window);
842 QTLWExtra *topExtra = window->d_func()->maybeTopData();
843 Q_ASSERT(topExtra);
844 if (!topExtra->inExpose) {
845 topExtra->inExpose = true;
846 QRect exposeRect = qt_TRect2QRect(controlRect);
847 qwidget->d_func()->syncBackingStore(exposeRect);
848 topExtra->inExpose = false;
849 }
850
851 QWindowSurface *surface = qwidget->windowSurface();
852 QPaintEngine *engine = surface ? surface->paintDevice()->paintEngine() : NULL;
853
854 if (!engine)
855 return;
856
857 const bool sendNativePaintEvents = qwidget->d_func()->extraData()->receiveNativePaintEvents;
858 if (sendNativePaintEvents) {
859 const QRect r = qt_TRect2QRect(controlRect);
860 QMetaObject::invokeMethod(qwidget, "beginNativePaintEvent", Qt::DirectConnection, Q_ARG(QRect, r));
861 }
862
863 // Map source rectangle into coordinates of the backing store.
864 const QPoint controlBase(controlRect.iTl.iX, controlRect.iTl.iY);
865 const QPoint backingStoreBase = qwidget->mapTo(qwidget->window(), controlBase);
866 const TRect backingStoreRect(TPoint(backingStoreBase.x(), backingStoreBase.y()), controlRect.Size());
867
868 if (engine->type() == QPaintEngine::Raster) {
869 QS60WindowSurface *s60Surface = static_cast<QS60WindowSurface *>(qwidget->windowSurface());
870 CFbsBitmap *bitmap = s60Surface->symbianBitmap();
871 CWindowGc &gc = SystemGc();
872
873 switch(qwidget->d_func()->extraData()->nativePaintMode) {
874 case QWExtra::Disable:
875 // Do nothing
876 break;
877
878 case QWExtra::Blit:
879 if (qwidget->d_func()->isOpaque)
880 gc.SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha);
881 gc.BitBlt(controlRect.iTl, bitmap, backingStoreRect);
882 break;
883
884 case QWExtra::ZeroFill:
885 if (Window().DisplayMode() == EColor16MA) {
886 gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
887 gc.SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha);
888 gc.SetBrushColor(TRgb::Color16MA(0));
889 gc.Clear(controlRect);
890 } else {
891 gc.SetBrushColor(TRgb(0x000000));
892 gc.Clear(controlRect);
893 };
894 break;
895
896 default:
897 Q_ASSERT(false);
898 }
899 }
900
901 if (sendNativePaintEvents) {
902 const QRect r = qt_TRect2QRect(controlRect);
903 // The draw ops aren't actually sent to WSERV until the graphics
904 // context is deactivated, which happens in the function calling
905 // this one. We therefore delay the delivery of endNativePaintEvent,
906 // to ensure that drawing has completed by the time the widget
907 // receives the event. Note that, if the widget needs to ensure
908 // that the draw ops have actually been executed into the output
909 // framebuffer, a call to RWsSession::Flush is required in the
910 // endNativePaintEvent implementation.
911 QMetaObject::invokeMethod(qwidget, "endNativePaintEvent", Qt::QueuedConnection, Q_ARG(QRect, r));
912 }
913}
914
915void QSymbianControl::SizeChanged()
916{
917 CCoeControl::SizeChanged();
918
919 QSize oldSize = qwidget->size();
920 QSize newSize(Size().iWidth, Size().iHeight);
921
922 if (oldSize != newSize) {
923 QRect cr = qwidget->geometry();
924 cr.setSize(newSize);
925 qwidget->data->crect = cr;
926 if (qwidget->isVisible()) {
927 QTLWExtra *tlwExtra = qwidget->d_func()->maybeTopData();
928 bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt();
929 if (!slowResize && tlwExtra)
930 tlwExtra->inTopLevelResize = true;
931 QResizeEvent e(newSize, oldSize);
932 qt_sendSpontaneousEvent(qwidget, &e);
933 if (!qwidget->testAttribute(Qt::WA_StaticContents))
934 qwidget->d_func()->syncBackingStore();
935 if (!slowResize && tlwExtra)
936 tlwExtra->inTopLevelResize = false;
937 } else {
938 QResizeEvent *e = new QResizeEvent(newSize, oldSize);
939 QApplication::postEvent(qwidget, e);
940 }
941 }
942
943 // CCoeControl::SetExtent calls SizeChanged, but does not call
944 // PositionChanged, so we call it here to ensure that the widget's
945 // position is updated.
946 PositionChanged();
947}
948
949void QSymbianControl::PositionChanged()
950{
951 CCoeControl::PositionChanged();
952
953 QPoint oldPos = qwidget->geometry().topLeft();
954 QPoint newPos(Position().iX, Position().iY);
955
956 if (oldPos != newPos) {
957 QRect cr = qwidget->geometry();
958 cr.moveTopLeft(newPos);
959 qwidget->data->crect = cr;
960 QTLWExtra *top = qwidget->d_func()->maybeTopData();
961 if (top && (qwidget->windowState() & (~Qt::WindowActive)) == Qt::WindowNoState)
962 top->normalGeometry.moveTopLeft(newPos);
963 if (qwidget->isVisible()) {
964 QMoveEvent e(newPos, oldPos);
965 qt_sendSpontaneousEvent(qwidget, &e);
966 } else {
967 QMoveEvent * e = new QMoveEvent(newPos, oldPos);
968 QApplication::postEvent(qwidget, e);
969 }
970 }
971}
972
973void QSymbianControl::FocusChanged(TDrawNow /* aDrawNow */)
974{
975 if (m_ignoreFocusChanged || (qwidget->windowType() & Qt::WindowType_Mask) == Qt::Desktop)
976 return;
977
978 // Popups never get focused, but still receive the FocusChanged when they are hidden.
979 if (QApplicationPrivate::popupWidgets != 0
980 || (qwidget->windowType() & Qt::Popup) == Qt::Popup)
981 return;
982
983 if (IsFocused() && IsVisible()) {
984 if (m_symbianPopupIsOpen) {
985 QWidget *fw = QApplication::focusWidget();
986 if (fw) {
987 QFocusEvent event(QEvent::FocusIn, Qt::PopupFocusReason);
988 QCoreApplication::sendEvent(fw, &event);
989 }
990 m_symbianPopupIsOpen = false;
991 }
992
993 QApplication::setActiveWindow(qwidget->window());
994 qwidget->d_func()->setWindowIcon_sys(true);
995 qwidget->d_func()->setWindowTitle_sys(qwidget->windowTitle());
996#ifdef Q_WS_S60
997 // If widget is fullscreen/minimized, hide status pane and button container otherwise show them.
998 CEikStatusPane *statusPane = S60->statusPane();
999 CEikButtonGroupContainer *buttonGroup = S60->buttonGroupContainer();
1000 TBool visible = !(qwidget->windowState() & (Qt::WindowFullScreen | Qt::WindowMinimized));
1001 if (statusPane)
1002 statusPane->MakeVisible(visible);
1003 if (buttonGroup) {
1004 // Visibility
1005 const TBool isFullscreen = qwidget->windowState() & Qt::WindowFullScreen;
1006 const TBool cbaVisibilityHint = qwidget->windowFlags() & Qt::WindowSoftkeysVisibleHint;
1007 buttonGroup->MakeVisible(visible || (isFullscreen && cbaVisibilityHint));
1008 }
1009#endif
1010 } else if (QApplication::activeWindow() == qwidget->window()) {
1011 if (CCoeEnv::Static()->AppUi()->IsDisplayingMenuOrDialog() || S60->menuBeingConstructed) {
1012 QWidget *fw = QApplication::focusWidget();
1013 if (fw) {
1014 QFocusEvent event(QEvent::FocusOut, Qt::PopupFocusReason);
1015 QCoreApplication::sendEvent(fw, &event);
1016 }
1017 m_symbianPopupIsOpen = true;
1018 return;
1019 }
1020
1021 QApplication::setActiveWindow(0);
1022 }
1023 // else { We don't touch the active window unless we were explicitly activated or deactivated }
1024}
1025
1026void QSymbianControl::handleClientAreaChange()
1027{
1028 const bool cbaVisibilityHint = qwidget->windowFlags() & Qt::WindowSoftkeysVisibleHint;
1029 if (qwidget->isFullScreen() && !cbaVisibilityHint) {
1030 SetExtentToWholeScreen();
1031 } else if (qwidget->isMaximized() || (qwidget->isFullScreen() && cbaVisibilityHint)) {
1032 TRect r = static_cast<CEikAppUi*>(S60->appUi())->ClientRect();
1033 SetExtent(r.iTl, r.Size());
1034 } else if (!qwidget->isMinimized()) { // Normal geometry
1035 if (!qwidget->testAttribute(Qt::WA_Resized)) {
1036 qwidget->adjustSize();
1037 qwidget->setAttribute(Qt::WA_Resized, false); //not a user resize
1038 }
1039 if (!qwidget->testAttribute(Qt::WA_Moved) && qwidget->windowType() != Qt::Dialog) {
1040 TRect r = static_cast<CEikAppUi*>(S60->appUi())->ClientRect();
1041 SetPosition(r.iTl);
1042 qwidget->setAttribute(Qt::WA_Moved, false); // not really an explicit position
1043 }
1044 }
1045}
1046
1047void QSymbianControl::HandleResourceChange(int resourceType)
1048{
1049 switch (resourceType) {
1050 case KInternalStatusPaneChange:
1051 handleClientAreaChange();
1052 if (IsFocused() && IsVisible()) {
1053 qwidget->d_func()->setWindowIcon_sys(true);
1054 qwidget->d_func()->setWindowTitle_sys(qwidget->windowTitle());
1055 }
1056 break;
1057 case KUidValueCoeFontChangeEvent:
1058 // font change event
1059 break;
1060#ifdef Q_WS_S60
1061 case KEikDynamicLayoutVariantSwitch:
1062 {
1063 handleClientAreaChange();
1064 break;
1065 }
1066#endif
1067 default:
1068 break;
1069 }
1070
1071 CCoeControl::HandleResourceChange(resourceType);
1072
1073}
1074void QSymbianControl::CancelLongTapTimer()
1075{
1076 m_longTapDetector->Cancel();
1077}
1078
1079TTypeUid::Ptr QSymbianControl::MopSupplyObject(TTypeUid id)
1080{
1081 if (id.iUid == ETypeId)
1082 return id.MakePtr(this);
1083
1084 return CCoeControl::MopSupplyObject(id);
1085}
1086
1087void QSymbianControl::setFocusSafely(bool focus)
1088{
1089 // The stack hack in here is very unfortunate, but it is the only way to ensure proper
1090 // focus in Symbian. If this is not executed, the control which happens to be on
1091 // the top of the stack may randomly be assigned focus by Symbian, for example
1092 // when creating new windows (specifically in CCoeAppUi::HandleStackChanged()).
1093 if (focus) {
1094 S60->appUi()->RemoveFromStack(this);
1095 // Symbian doesn't automatically remove focus from the last focused control, so we need to
1096 // remember it and clear focus ourselves.
1097 if (lastFocusedControl && lastFocusedControl != this)
1098 lastFocusedControl->SetFocus(false);
1099 QT_TRAP_THROWING(S60->appUi()->AddToStackL(this,
1100 ECoeStackPriorityDefault + 1, ECoeStackFlagStandard)); // Note the + 1
1101 lastFocusedControl = this;
1102 this->SetFocus(true);
1103 } else {
1104 S60->appUi()->RemoveFromStack(this);
1105 QT_TRAP_THROWING(S60->appUi()->AddToStackL(this,
1106 ECoeStackPriorityDefault, ECoeStackFlagStandard));
1107 if(this == lastFocusedControl)
1108 lastFocusedControl = 0;
1109 this->SetFocus(false);
1110 }
1111}
1112
1113/*!
1114 \typedef QApplication::QS60MainApplicationFactory
1115 \since 4.6
1116
1117 This is a typedef for a pointer to a function with the following
1118 signature:
1119
1120 \snippet doc/src/snippets/code/src_corelib_global_qglobal.cpp 47
1121
1122 \sa QApplication::QApplication()
1123*/
1124
1125/*!
1126 \since 4.6
1127
1128 Creates an application using the application factory given in
1129 \a factory, and using \a argc command line arguments in \a argv.
1130 \a factory can be leaving, but the error will be converted to a
1131 standard exception.
1132
1133 This function is only available on S60.
1134*/
1135QApplication::QApplication(QApplication::QS60MainApplicationFactory factory, int &argc, char **argv)
1136 : QCoreApplication(*new QApplicationPrivate(argc, argv, GuiClient))
1137{
1138 Q_D(QApplication);
1139 S60->s60ApplicationFactory = factory;
1140 d->construct();
1141}
1142
1143QApplication::QApplication(QApplication::QS60MainApplicationFactory factory, int &argc, char **argv, int _internal)
1144 : QCoreApplication(*new QApplicationPrivate(argc, argv, GuiClient))
1145{
1146 Q_D(QApplication);
1147 S60->s60ApplicationFactory = factory;
1148 d->construct();
1149 QApplicationPrivate::app_compile_version = _internal;
1150}
1151
1152void qt_init(QApplicationPrivate * /* priv */, int)
1153{
1154 if (!CCoeEnv::Static()) {
1155 // The S60 framework creates a new trap handler which will render any existing traps
1156 // invalid as long as it is active. This means that all code in main() that occurs after
1157 // the QApplication construction needs to be surrounded by a new trap, despite having
1158 // an outer one already. To avoid this, we save the original trap handler here, and set
1159 // it back after the S60 framework is constructed. Then we restore it right before the S60
1160 // framework destruction.
1161 TTrapHandler *origTrapHandler = User::TrapHandler();
1162
1163 // The S60 framework has not been initalized. We need to do it.
1164 TApaApplicationFactory factory(S60->s60ApplicationFactory ?
1165 S60->s60ApplicationFactory : newS60Application);
1166 CApaCommandLine* commandLine = 0;
1167 TInt err = CApaCommandLine::GetCommandLineFromProcessEnvironment(commandLine);
1168 // After this construction, CEikonEnv will be available from CEikonEnv::Static().
1169 // (much like our qApp).
1170 CEikonEnv* coe = new CEikonEnv;
1171 //not using QT_TRAP_THROWING, because coe owns the cleanupstack so it can't be pushed there.
1172 if(err == KErrNone)
1173 TRAP(err, coe->ConstructAppFromCommandLineL(factory,*commandLine));
1174 delete commandLine;
1175 if(err != KErrNone) {
1176 qWarning() << "qt_init: Eikon application construct failed ("
1177 << err
1178 << "), maybe missing resource file on S60 3.1?";
1179 delete coe;
1180 qt_symbian_throwIfError(err);
1181 }
1182
1183 S60->s60InstalledTrapHandler = User::SetTrapHandler(origTrapHandler);
1184
1185 S60->qtOwnsS60Environment = true;
1186 } else {
1187 S60->qtOwnsS60Environment = false;
1188 }
1189
1190#ifdef QT_NO_DEBUG
1191 if (!qgetenv("QT_S60_AUTO_FLUSH_WSERV").isEmpty())
1192#endif
1193 S60->wsSession().SetAutoFlush(ETrue);
1194
1195#ifdef Q_SYMBIAN_WINDOW_SIZE_CACHE
1196 TRAP_IGNORE(S60->wsSession().EnableWindowSizeCacheL());
1197#endif
1198
1199 S60->updateScreenSize();
1200
1201
1202 TDisplayMode mode = S60->screenDevice()->DisplayMode();
1203 S60->screenDepth = TDisplayModeUtils::NumDisplayModeBitsPerPixel(mode);
1204
1205 //NB: RWsSession::GetColorModeList tells you what window modes are supported,
1206 //not what bitmap formats.
1207 if(QSysInfo::symbianVersion() == QSysInfo::SV_9_2)
1208 S60->supportsPremultipliedAlpha = 0;
1209 else
1210 S60->supportsPremultipliedAlpha = 1;
1211
1212 RProcess me;
1213 TSecureId securId = me.SecureId();
1214 S60->uid = securId.operator TUid();
1215
1216 // enable focus events - used to re-enable mouse after focus changed between mouse and non mouse app,
1217 // and for dimming behind modal windows
1218 S60->windowGroup().EnableFocusChangeEvents();
1219
1220 //Check if mouse interaction is supported (either EMouse=1 in the HAL, or EMachineUID is one of the phones known to support this)
1221 const TInt KMachineUidSamsungI8510 = 0x2000C51E;
1222 // HAL::Get(HALData::EPen, TInt& result) may set 'result' to 1 on some 3.1 systems (e.g. N95).
1223 // But we know that S60 systems below 5.0 did not support touch.
1224 static const bool touchIsUnsupportedOnSystem =
1225 QSysInfo::s60Version() == QSysInfo::SV_S60_3_1
1226 || QSysInfo::s60Version() == QSysInfo::SV_S60_3_2;
1227 TInt machineUID;
1228 TInt mouse;
1229 TInt touch;
1230 TInt err;
1231 err = HAL::Get(HALData::EMouse, mouse);
1232 if (err != KErrNone)
1233 mouse = 0;
1234 err = HAL::Get(HALData::EMachineUid, machineUID);
1235 if (err != KErrNone)
1236 machineUID = 0;
1237 err = HAL::Get(HALData::EPen, touch);
1238 if (err != KErrNone || touchIsUnsupportedOnSystem)
1239 touch = 0;
1240#ifdef __WINS__
1241 if(QSysInfo::symbianVersion() <= QSysInfo::SV_9_4) {
1242 //for symbian SDK emulator, force values to match typical devices.
1243 mouse = 0;
1244 touch = touchIsUnsupportedOnSystem ? 0 : 1;
1245 }
1246#endif
1247 if (mouse || machineUID == KMachineUidSamsungI8510) {
1248 S60->hasTouchscreen = false;
1249 S60->virtualMouseRequired = false;
1250 }
1251 else if (!touch) {
1252 S60->hasTouchscreen = false;
1253 S60->virtualMouseRequired = true;
1254 }
1255 else {
1256 S60->hasTouchscreen = true;
1257 S60->virtualMouseRequired = false;
1258 }
1259
1260 S60->avkonComponentsSupportTransparency = false;
1261 S60->menuBeingConstructed = false;
1262
1263#ifdef Q_WS_S60
1264 TUid KCRUidAvkon = { 0x101F876E };
1265 TUint32 KAknAvkonTransparencyEnabled = 0x0000000D;
1266
1267 CRepository* repository = 0;
1268 TRAP(err, repository = CRepository::NewL(KCRUidAvkon));
1269
1270 if(err == KErrNone) {
1271 TInt value = 0;
1272 err = repository->Get(KAknAvkonTransparencyEnabled, value);
1273 if(err == KErrNone) {
1274 S60->avkonComponentsSupportTransparency = (value==1) ? true : false;
1275 }
1276 }
1277#endif
1278
1279 if (touch) {
1280 QApplicationPrivate::navigationMode = Qt::NavigationModeNone;
1281 } else {
1282 QApplicationPrivate::navigationMode = Qt::NavigationModeKeypadDirectional;
1283 }
1284
1285#ifndef QT_NO_CURSOR
1286 //Check if window server pointer cursors are supported or not
1287#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
1288 //In generic binary, use the HAL and OS version
1289 //Any other known good phones should be added here.
1290 if (machineUID == KMachineUidSamsungI8510 || (QSysInfo::symbianVersion() != QSysInfo::SV_9_4
1291 && QSysInfo::symbianVersion() != QSysInfo::SV_9_3 && QSysInfo::symbianVersion()
1292 != QSysInfo::SV_9_2)) {
1293 S60->brokenPointerCursors = false;
1294 qt_symbian_setWindowGroupCursor(Qt::ArrowCursor, S60->windowGroup());
1295 }
1296 else
1297 S60->brokenPointerCursors = true;
1298#endif
1299
1300 if (S60->mouseInteractionEnabled) {
1301#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
1302 if (S60->brokenPointerCursors) {
1303 qt_symbian_set_pointer_sprite(Qt::ArrowCursor);
1304 qt_symbian_show_pointer_sprite();
1305 }
1306 else
1307#endif
1308 S60->wsSession().SetPointerCursorMode(EPointerCursorNormal);
1309 }
1310#endif
1311
1312 QFont systemFont;
1313 systemFont.setFamily(systemFont.defaultFamily());
1314 QApplicationPrivate::setSystemFont(systemFont);
1315
1316/*
1317 ### Commented out for now as parameter handling not needed in SOS(yet). Code below will break testlib with -o flag
1318 int argc = priv->argc;
1319 char **argv = priv->argv;
1320
1321 // Get command line params
1322 int j = argc ? 1 : 0;
1323 for (int i=1; i<argc; i++) {
1324 if (argv[i] && *argv[i] != '-') {
1325 argv[j++] = argv[i];
1326 continue;
1327 }
1328
1329#if defined(QT_DEBUG)
1330 if (qstrcmp(argv[i], "-nograb") == 0)
1331 appNoGrab = !appNoGrab;
1332 else
1333#endif // QT_DEBUG
1334 ;
1335 }
1336*/
1337
1338 // Register WId with the metatype system. This is to enable
1339 // QWidgetPrivate::create_sys to used delayed slot invokation in order
1340 // to destroy WId objects during reparenting.
1341 qRegisterMetaType<WId>("WId");
1342}
1343
1344/*****************************************************************************
1345 qt_cleanup() - cleans up when the application is finished
1346 *****************************************************************************/
1347void qt_cleanup()
1348{
1349 if(qt_S60Beep) {
1350 delete qt_S60Beep;
1351 qt_S60Beep = 0;
1352 }
1353 QFontCache::cleanup(); // Has to happen now, since QFontEngineS60 has FBS handles
1354// S60 structure and window server session are freed in eventdispatcher destructor as they are needed there
1355
1356 // It's important that this happens here, before the event dispatcher gets
1357 // deleted, because the input context needs the event loop one last time before
1358 // it dies.
1359 delete QApplicationPrivate::inputContext;
1360 QApplicationPrivate::inputContext = 0;
1361
1362 //Change mouse pointer back
1363 S60->wsSession().SetPointerCursorMode(EPointerCursorNone);
1364
1365 if (S60->qtOwnsS60Environment) {
1366 // Restore the S60 framework trap handler. See qt_init().
1367 User::SetTrapHandler(S60->s60InstalledTrapHandler);
1368
1369 CEikonEnv* coe = CEikonEnv::Static();
1370 coe->PrepareToExit();
1371 // The CEikonEnv itself is destroyed in here.
1372 coe->DestroyEnvironment();
1373 }
1374}
1375
1376void QApplicationPrivate::initializeWidgetPaletteHash()
1377{
1378 // TODO: Implement QApplicationPrivate::initializeWidgetPaletteHash()
1379 // Possibly a task fot the S60Style guys
1380}
1381
1382void QApplicationPrivate::createEventDispatcher()
1383{
1384 Q_Q(QApplication);
1385 eventDispatcher = new QEventDispatcherS60(q);
1386}
1387
1388QString QApplicationPrivate::appName() const
1389{
1390 return QCoreApplicationPrivate::appName();
1391}
1392
1393bool QApplicationPrivate::modalState()
1394{
1395 return app_do_modal;
1396}
1397
1398void QApplicationPrivate::enterModal_sys(QWidget *widget)
1399{
1400 if (widget) {
1401 static_cast<QSymbianControl *>(widget->effectiveWinId())->FadeBehindPopup(ETrue);
1402 // Modal partial screen dialogs (like queries) capture pointer events.
1403 // ### FixMe: Add specialized behaviour for fullscreen modal dialogs
1404 widget->effectiveWinId()->SetGloballyCapturing(ETrue);
1405 widget->effectiveWinId()->SetPointerCapture(ETrue);
1406 }
1407 if (!qt_modal_stack)
1408 qt_modal_stack = new QWidgetList;
1409 qt_modal_stack->insert(0, widget);
1410 app_do_modal = true;
1411}
1412
1413void QApplicationPrivate::leaveModal_sys(QWidget *widget)
1414{
1415 if (widget) {
1416 static_cast<QSymbianControl *>(widget->effectiveWinId())->FadeBehindPopup(EFalse);
1417 // ### FixMe: Add specialized behaviour for fullscreen modal dialogs
1418 widget->effectiveWinId()->SetGloballyCapturing(EFalse);
1419 widget->effectiveWinId()->SetPointerCapture(EFalse);
1420 }
1421 if (qt_modal_stack && qt_modal_stack->removeAll(widget)) {
1422 if (qt_modal_stack->isEmpty()) {
1423 delete qt_modal_stack;
1424 qt_modal_stack = 0;
1425 }
1426 }
1427 app_do_modal = qt_modal_stack != 0;
1428}
1429
1430void QApplicationPrivate::openPopup(QWidget *popup)
1431{
1432 if (popup && qobject_cast<QComboBox *>(popup->parentWidget()))
1433 static_cast<QSymbianControl *>(popup->effectiveWinId())->FadeBehindPopup(ETrue);
1434
1435 if (!QApplicationPrivate::popupWidgets)
1436 QApplicationPrivate::popupWidgets = new QWidgetList;
1437 QApplicationPrivate::popupWidgets->append(popup);
1438
1439 // Cancel focus widget pointer capture and long tap timer
1440 if (QApplication::focusWidget()) {
1441 static_cast<QSymbianControl*>(QApplication::focusWidget()->effectiveWinId())->CancelLongTapTimer();
1442 QApplication::focusWidget()->effectiveWinId()->SetPointerCapture(false);
1443 }
1444
1445 if (!qt_nograb()) {
1446 // Cancel pointer capture and long tap timer for earlier popup
1447 int popupCount = QApplicationPrivate::popupWidgets->count();
1448 if (popupCount > 1) {
1449 QWidget* prevPopup = QApplicationPrivate::popupWidgets->at(popupCount-2);
1450 static_cast<QSymbianControl*>(prevPopup->effectiveWinId())->CancelLongTapTimer();
1451 prevPopup->effectiveWinId()->SetPointerCapture(false);
1452 }
1453
1454 // Enable pointer capture for this (topmost) popup
1455 Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created));
1456 WId id = popup->effectiveWinId();
1457 id->SetPointerCapture(true);
1458 }
1459
1460 // popups are not focus-handled by the window system (the first
1461 // popup grabbed the keyboard), so we have to do that manually: A
1462 // new popup gets the focus
1463 QWidget *fw = popup->focusWidget();
1464 if (fw) {
1465 fw->setFocus(Qt::PopupFocusReason);
1466 } else if (QApplicationPrivate::popupWidgets->count() == 1) { // this was the first popup
1467 fw = QApplication::focusWidget();
1468 if (fw) {
1469 QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason);
1470 q_func()->sendEvent(fw, &e);
1471 }
1472 }
1473}
1474
1475void QApplicationPrivate::closePopup(QWidget *popup)
1476{
1477 if (popup && qobject_cast<QComboBox *>(popup->parentWidget()))
1478 static_cast<QSymbianControl *>(popup->effectiveWinId())->FadeBehindPopup(EFalse);
1479
1480 if (!QApplicationPrivate::popupWidgets)
1481 return;
1482 QApplicationPrivate::popupWidgets->removeAll(popup);
1483
1484 // Cancel pointer capture and long tap for this popup
1485 WId id = popup->effectiveWinId();
1486 id->SetPointerCapture(false);
1487 static_cast<QSymbianControl*>(id)->CancelLongTapTimer();
1488
1489 if (QApplicationPrivate::popupWidgets->isEmpty()) { // this was the last popup
1490 delete QApplicationPrivate::popupWidgets;
1491 QApplicationPrivate::popupWidgets = 0;
1492 if (!qt_nograb()) { // grabbing not disabled
1493 Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created));
1494 if (QWidgetPrivate::mouseGrabber != 0)
1495 QWidgetPrivate::mouseGrabber->grabMouse();
1496
1497 if (QWidgetPrivate::keyboardGrabber != 0)
1498 QWidgetPrivate::keyboardGrabber->grabKeyboard();
1499
1500 QWidget *fw = QApplicationPrivate::active_window ? QApplicationPrivate::active_window->focusWidget()
1501 : q_func()->focusWidget();
1502 if (fw) {
1503 if(fw->window()->isModal()) // restore pointer capture for modal window
1504 fw->effectiveWinId()->SetPointerCapture(true);
1505
1506 if (fw != q_func()->focusWidget()) {
1507 fw->setFocus(Qt::PopupFocusReason);
1508 } else {
1509 QFocusEvent e(QEvent::FocusIn, Qt::PopupFocusReason);
1510 q_func()->sendEvent(fw, &e);
1511 }
1512 }
1513 }
1514 } else {
1515
1516 // popups are not focus-handled by the window system (the
1517 // first popup grabbed the keyboard), so we have to do that
1518 // manually: A popup was closed, so the previous popup gets
1519 // the focus.
1520 QWidget* aw = QApplicationPrivate::popupWidgets->last();
1521 if (QWidget *fw = QApplication::focusWidget()) {
1522 QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason);
1523 q_func()->sendEvent(fw, &e);
1524 }
1525
1526 // Enable pointer capture for previous popup
1527 if (aw) {
1528 aw->effectiveWinId()->SetPointerCapture(true);
1529 }
1530 }
1531}
1532
1533QWidget * QApplication::topLevelAt(QPoint const& point)
1534{
1535 QWidget *found = 0;
1536 int lowestZ = INT_MAX;
1537 QWidgetList list = QApplication::topLevelWidgets();
1538 for (int i = 0; i < list.count(); ++i) {
1539 QWidget *widget = list.at(i);
1540 if (widget->isVisible() && !(widget->windowType() == Qt::Desktop)) {
1541 Q_ASSERT(widget->testAttribute(Qt::WA_WState_Created));
1542 if (widget->geometry().adjusted(0,0,1,1).contains(point)) {
1543 // At this point we know there is a Qt widget under the point.
1544 // Now we need to make sure it is the top most in the z-order.
1545 RDrawableWindow *const window = widget->effectiveWinId()->DrawableWindow();
1546 int z = window->OrdinalPosition();
1547 if (z < lowestZ) {
1548 lowestZ = z;
1549 found = widget;
1550 }
1551 }
1552 }
1553 }
1554 return found;
1555}
1556
1557void QApplication::alert(QWidget * /* widget */, int /* duration */)
1558{
1559 // TODO: Implement QApplication::alert(QWidget *widget, int duration)
1560}
1561
1562int QApplication::doubleClickInterval()
1563{
1564 TTimeIntervalMicroSeconds32 us;
1565 TInt distance;
1566 S60->wsSession().GetDoubleClickSettings(us, distance);
1567 return (us.Int() / 1000);
1568}
1569
1570void QApplication::setDoubleClickInterval(int ms)
1571{
1572 TTimeIntervalMicroSeconds32 newUs( ms * 1000);
1573 TTimeIntervalMicroSeconds32 us;
1574 TInt distance;
1575 S60->wsSession().GetDoubleClickSettings(us, distance);
1576 if (us != newUs)
1577 S60->wsSession().SetDoubleClick(newUs, distance);
1578}
1579
1580int QApplication::keyboardInputInterval()
1581{
1582 return QApplicationPrivate::keyboard_input_time;
1583}
1584
1585void QApplication::setKeyboardInputInterval(int ms)
1586{
1587 QApplicationPrivate::keyboard_input_time = ms;
1588}
1589
1590int QApplication::cursorFlashTime()
1591{
1592 return QApplicationPrivate::cursor_flash_time;
1593}
1594
1595void QApplication::setCursorFlashTime(int msecs)
1596{
1597 QApplicationPrivate::cursor_flash_time = msecs;
1598}
1599
1600void QApplication::beep()
1601{
1602 if (!qt_S60Beep) {
1603 TInt frequency = 880;
1604 TTimeIntervalMicroSeconds duration(500000);
1605 TRAP_IGNORE(qt_S60Beep=QS60Beep::NewL(frequency, duration));
1606 }
1607 if (qt_S60Beep)
1608 qt_S60Beep->Play();
1609}
1610
1611static inline bool callSymbianEventFilters(const QSymbianEvent *event)
1612{
1613 long unused;
1614 return qApp->filterEvent(const_cast<QSymbianEvent *>(event), &unused);
1615}
1616
1617/*!
1618 \warning This function is only available on Symbian.
1619 \since 4.6
1620
1621 This function processes an individual Symbian event
1622 \a event. It returns 1 if the event was handled, 0 if
1623 the \a event was not handled, and -1 if the event was
1624 not handled because the event is not known to Qt.
1625 */
1626
1627int QApplication::symbianProcessEvent(const QSymbianEvent *event)
1628{
1629 Q_D(QApplication);
1630
1631 QScopedLoopLevelCounter counter(d->threadData);
1632
1633 if (d->eventDispatcher->filterEvent(const_cast<QSymbianEvent *>(event)))
1634 return 1;
1635
1636 QWidget *w = qApp ? qApp->focusWidget() : 0;
1637 if (w) {
1638 QInputContext *ic = w->inputContext();
1639 if (ic && ic->symbianFilterEvent(w, event))
1640 return 1;
1641 }
1642
1643 if (symbianEventFilter(event))
1644 return 1;
1645
1646 switch (event->type()) {
1647 case QSymbianEvent::WindowServerEvent:
1648 return d->symbianProcessWsEvent(event);
1649 case QSymbianEvent::CommandEvent:
1650 return d->symbianHandleCommand(event);
1651 case QSymbianEvent::ResourceChangeEvent:
1652 return d->symbianResourceChange(event);
1653 default:
1654 return -1;
1655 }
1656}
1657
1658int QApplicationPrivate::symbianProcessWsEvent(const QSymbianEvent *symbianEvent)
1659{
1660 // Qt event handling. Handle some events regardless of if the handle is in our
1661 // widget map or not.
1662 const TWsEvent *event = symbianEvent->windowServerEvent();
1663 CCoeControl* control = reinterpret_cast<CCoeControl*>(event->Handle());
1664 const bool controlInMap = QWidgetPrivate::mapper && QWidgetPrivate::mapper->contains(control);
1665 switch (event->Type()) {
1666 case EEventPointerEnter:
1667 if (controlInMap) {
1668 callSymbianEventFilters(symbianEvent);
1669 return 1; // Qt::Enter will be generated in HandlePointerL
1670 }
1671 break;
1672 case EEventPointerExit:
1673 if (controlInMap) {
1674 if (callSymbianEventFilters(symbianEvent))
1675 return 1;
1676 if (S60) {
1677 // mouseEvent outside our window, send leave event to last focused widget
1678 QMouseEvent mEvent(QEvent::Leave, S60->lastPointerEventPos, S60->lastCursorPos,
1679 Qt::NoButton, QApplicationPrivate::mouse_buttons, Qt::NoModifier);
1680 if (S60->lastPointerEventTarget)
1681 qt_sendSpontaneousEvent(S60->lastPointerEventTarget,&mEvent);
1682 S60->lastPointerEventTarget = 0;
1683 }
1684 return 1;
1685 }
1686 break;
1687 case EEventScreenDeviceChanged:
1688 if (callSymbianEventFilters(symbianEvent))
1689 return 1;
1690 if (S60)
1691 S60->updateScreenSize();
1692 if (qt_desktopWidget) {
1693 QSize oldSize = qt_desktopWidget->size();
1694 qt_desktopWidget->data->crect.setWidth(S60->screenWidthInPixels);
1695 qt_desktopWidget->data->crect.setHeight(S60->screenHeightInPixels);
1696 QResizeEvent e(qt_desktopWidget->size(), oldSize);
1697 QApplication::sendEvent(qt_desktopWidget, &e);
1698 }
1699 return 0; // Propagate to CONE
1700 case EEventWindowVisibilityChanged:
1701 if (controlInMap) {
1702 if (callSymbianEventFilters(symbianEvent))
1703 return 1;
1704 const TWsVisibilityChangedEvent *visChangedEvent = event->VisibilityChanged();
1705 QWidget *w = QWidgetPrivate::mapper->value(control);
1706 if (!w->d_func()->maybeTopData())
1707 break;
1708 if (visChangedEvent->iFlags & TWsVisibilityChangedEvent::ENotVisible) {
1709 delete w->d_func()->topData()->backingStore;
1710 w->d_func()->topData()->backingStore = 0;
1711 // In order to ensure that any resources used by the window surface
1712 // are immediately freed, we flush the WSERV command buffer.
1713 S60->wsSession().Flush();
1714 } else if ((visChangedEvent->iFlags & TWsVisibilityChangedEvent::EPartiallyVisible)
1715 && !w->d_func()->maybeBackingStore()) {
1716 w->d_func()->topData()->backingStore = new QWidgetBackingStore(w);
1717 w->d_func()->invalidateBuffer(w->rect());
1718 w->repaint();
1719 }
1720 return 1;
1721 }
1722 break;
1723 case EEventFocusGained:
1724 if (callSymbianEventFilters(symbianEvent))
1725 return 1;
1726#ifndef QT_NO_CURSOR
1727 //re-enable mouse interaction
1728 if (S60->mouseInteractionEnabled) {
1729#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
1730 if (S60->brokenPointerCursors)
1731 qt_symbian_show_pointer_sprite();
1732 else
1733#endif
1734 S60->wsSession().SetPointerCursorMode(EPointerCursorNormal);
1735 }
1736#endif
1737 break;
1738 case EEventFocusLost:
1739 if (callSymbianEventFilters(symbianEvent))
1740 return 1;
1741#ifndef QT_NO_CURSOR
1742 //disable mouse as may be moving to application that does not support it
1743 if (S60->mouseInteractionEnabled) {
1744#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
1745 if (S60->brokenPointerCursors)
1746 qt_symbian_hide_pointer_sprite();
1747 else
1748#endif
1749 S60->wsSession().SetPointerCursorMode(EPointerCursorNone);
1750 }
1751#endif
1752 break;
1753 default:
1754 break;
1755 }
1756
1757 if (!controlInMap)
1758 return -1;
1759
1760 return 0;
1761}
1762
1763/*!
1764 \warning This virtual function is only available on Symbian.
1765 \since 4.6
1766
1767 If you create an application that inherits QApplication and reimplement
1768 this function, you get direct access to events that the are received
1769 from Symbian. The events are passed in the \a event parameter.
1770
1771 Return true if you want to stop the event from being processed. Return
1772 false for normal event dispatching. The default implementation returns
1773 false, and does nothing with \a event.
1774 */
1775bool QApplication::symbianEventFilter(const QSymbianEvent *event)
1776{
1777 Q_UNUSED(event);
1778 return false;
1779}
1780
1781/*!
1782 \warning This function is only available on Symbian.
1783 \since 4.6
1784
1785 Handles \a{command}s which are typically handled by
1786 CAknAppUi::HandleCommandL(). Qts Ui integration into Symbian is
1787 partially achieved by deriving from CAknAppUi. Currently, exit,
1788 menu and softkey commands are handled.
1789
1790 \sa s60EventFilter(), s60ProcessEvent()
1791*/
1792int QApplicationPrivate::symbianHandleCommand(const QSymbianEvent *symbianEvent)
1793{
1794 Q_Q(QApplication);
1795 int ret = 0;
1796
1797 if (callSymbianEventFilters(symbianEvent))
1798 return 1;
1799
1800 int command = symbianEvent->command();
1801
1802 switch (command) {
1803#ifdef Q_WS_S60
1804 case EAknSoftkeyExit: {
1805 QCloseEvent ev;
1806 QApplication::sendSpontaneousEvent(q, &ev);
1807 if (ev.isAccepted()) {
1808 q->quit();
1809 ret = 1;
1810 }
1811 break;
1812 }
1813#endif
1814 case EEikCmdExit:
1815 q->quit();
1816 ret = 1;
1817 break;
1818 default:
1819 bool handled = QSoftKeyManager::handleCommand(command);
1820 if (handled)
1821 ret = 1;
1822#ifdef Q_WS_S60
1823 else
1824 ret = QMenuBarPrivate::symbianCommands(command);
1825#endif
1826 break;
1827 }
1828
1829 return ret;
1830}
1831
1832/*!
1833 \warning This function is only available on Symbian.
1834 \since 4.6
1835
1836 Handles the resource change specified by \a type.
1837
1838 Currently, KEikDynamicLayoutVariantSwitch and
1839 KAknsMessageSkinChange are handled.
1840 */
1841int QApplicationPrivate::symbianResourceChange(const QSymbianEvent *symbianEvent)
1842{
1843 int ret = 0;
1844
1845 int type = symbianEvent->resourceChangeType();
1846
1847 switch (type) {
1848#ifdef Q_WS_S60
1849 case KEikDynamicLayoutVariantSwitch:
1850 {
1851 if (callSymbianEventFilters(symbianEvent))
1852 return 1;
1853 if (S60)
1854 S60->updateScreenSize();
1855
1856#ifndef QT_NO_STYLE_S60
1857 QS60Style *s60Style = 0;
1858
1859#ifndef QT_NO_STYLE_STYLESHEET
1860 QStyleSheetStyle *proxy = qobject_cast<QStyleSheetStyle*>(QApplication::style());
1861 if (proxy)
1862 s60Style = qobject_cast<QS60Style*>(proxy->baseStyle());
1863 else
1864#endif
1865 s60Style = qobject_cast<QS60Style*>(QApplication::style());
1866
1867 if (s60Style) {
1868 s60Style->d_func()->handleDynamicLayoutVariantSwitch();
1869 ret = 1;
1870 }
1871#endif
1872 }
1873 break;
1874
1875#ifndef QT_NO_STYLE_S60
1876 case KAknsMessageSkinChange:
1877 if (callSymbianEventFilters(symbianEvent))
1878 return 1;
1879 if (QS60Style *s60Style = qobject_cast<QS60Style*>(QApplication::style())) {
1880 s60Style->d_func()->handleSkinChange();
1881 ret = 1;
1882 }
1883 break;
1884#endif
1885#endif // Q_WS_S60
1886 default:
1887 break;
1888 }
1889
1890 return ret;
1891}
1892
1893#ifndef QT_NO_WHEELEVENT
1894int QApplication::wheelScrollLines()
1895{
1896 return QApplicationPrivate::wheel_scroll_lines;
1897}
1898
1899void QApplication::setWheelScrollLines(int n)
1900{
1901 QApplicationPrivate::wheel_scroll_lines = n;
1902}
1903#endif //QT_NO_WHEELEVENT
1904
1905bool QApplication::isEffectEnabled(Qt::UIEffect /* effect */)
1906{
1907 // TODO: Implement QApplication::isEffectEnabled(Qt::UIEffect effect)
1908 return false;
1909}
1910
1911void QApplication::setEffectEnabled(Qt::UIEffect /* effect */, bool /* enable */)
1912{
1913 // TODO: Implement QApplication::setEffectEnabled(Qt::UIEffect effect, bool enable)
1914}
1915
1916TUint QApplicationPrivate::resolveS60ScanCode(TInt scanCode, TUint keysym)
1917{
1918 if (keysym) {
1919 // If keysym is specified, cache it.
1920 scanCodeCache.insert(scanCode, keysym);
1921 return keysym;
1922 } else {
1923 // If not, retrieve the cached version.
1924 return scanCodeCache[scanCode];
1925 }
1926}
1927
1928void QApplicationPrivate::initializeMultitouch_sys()
1929{
1930#ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
1931 if (HAL::Get(HALData::EPointer3DPressureSupported, pressureSupported) != KErrNone)
1932 pressureSupported = 0;
1933 if (HAL::Get(HALData::EPointer3DMaxPressure, maxTouchPressure) != KErrNone)
1934 maxTouchPressure = KMaxTInt;
1935#endif
1936}
1937
1938void QApplicationPrivate::cleanupMultitouch_sys()
1939{ }
1940
1941#ifndef QT_NO_SESSIONMANAGER
1942QSessionManager::QSessionManager(QApplication * /* app */, QString & /* id */, QString& /* key */)
1943{
1944
1945}
1946
1947QSessionManager::~QSessionManager()
1948{
1949
1950}
1951
1952bool QSessionManager::allowsInteraction()
1953{
1954 return false;
1955}
1956
1957void QSessionManager::cancel()
1958{
1959
1960}
1961#endif //QT_NO_SESSIONMANAGER
1962
1963#ifdef QT_KEYPAD_NAVIGATION
1964/*
1965 * Show/Hide the mouse cursor depending on phone type and chosen mode
1966 */
1967void QApplicationPrivate::setNavigationMode(Qt::NavigationMode mode)
1968{
1969#ifndef QT_NO_CURSOR
1970 const bool wasCursorOn = (QApplicationPrivate::navigationMode == Qt::NavigationModeCursorAuto
1971 && !S60->hasTouchscreen)
1972 || QApplicationPrivate::navigationMode == Qt::NavigationModeCursorForceVisible;
1973 const bool isCursorOn = (mode == Qt::NavigationModeCursorAuto
1974 && !S60->hasTouchscreen)
1975 || mode == Qt::NavigationModeCursorForceVisible;
1976
1977 if (!wasCursorOn && isCursorOn) {
1978 //Show the cursor, when changing from another mode to cursor mode
1979 qt_symbian_set_cursor_visible(true);
1980 }
1981 else if (wasCursorOn && !isCursorOn) {
1982 //Hide the cursor, when leaving cursor mode
1983 qt_symbian_set_cursor_visible(false);
1984 }
1985#endif
1986 QApplicationPrivate::navigationMode = mode;
1987}
1988#endif
1989
1990#ifndef QT_NO_CURSOR
1991/*****************************************************************************
1992 QApplication cursor stack
1993 *****************************************************************************/
1994
1995void QApplication::setOverrideCursor(const QCursor &cursor)
1996{
1997 qApp->d_func()->cursor_list.prepend(cursor);
1998 qt_symbian_setGlobalCursor(cursor);
1999}
2000
2001void QApplication::restoreOverrideCursor()
2002{
2003 if (qApp->d_func()->cursor_list.isEmpty())
2004 return;
2005 qApp->d_func()->cursor_list.removeFirst();
2006
2007 if (!qApp->d_func()->cursor_list.isEmpty()) {
2008 qt_symbian_setGlobalCursor(qApp->d_func()->cursor_list.first());
2009 }
2010 else {
2011 //determine which widget has focus
2012 QWidget *w = QApplication::widgetAt(QCursor::pos());
2013#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
2014 if (S60->brokenPointerCursors) {
2015 qt_symbian_set_pointer_sprite(w ? w->cursor() : Qt::ArrowCursor);
2016 }
2017 else
2018#endif
2019 {
2020 //because of the internals of window server, we need to force the cursor
2021 //to be set in all child windows too, otherwise when the cursor is over
2022 //the child window it may show a widget cursor or arrow cursor instead,
2023 //depending on construction order.
2024 QListIterator<WId> iter(QWidgetPrivate::mapper->uniqueKeys());
2025 while (iter.hasNext()) {
2026 CCoeControl *ctrl = iter.next();
2027 if(ctrl->OwnsWindow()) {
2028 ctrl->DrawableWindow()->ClearPointerCursor();
2029 }
2030 }
2031 if (w)
2032 qt_symbian_setWindowCursor(w->cursor(), w->effectiveWinId());
2033 else
2034 qt_symbian_setWindowGroupCursor(Qt::ArrowCursor, S60->windowGroup());
2035 }
2036 }
2037}
2038
2039#endif // QT_NO_CURSOR
2040
2041QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.