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

Last change on this file since 1023 was 865, checked in by Dmitry A. Kuminov, 14 years ago

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

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