summaryrefslogtreecommitdiffstats
path: root/src/gui/kernel/qapplication_s60.cpp
diff options
context:
space:
mode:
authorShane Kearns <shane.kearns@sosco.com>2009-09-15 12:12:08 (GMT)
committerShane Kearns <shane.kearns@sosco.com>2009-09-15 14:05:53 (GMT)
commit56cec4cf9a8b04c979ced28cab89ce6232d4184a (patch)
treea9701f13161810d1e9bfbf7ef9cd8430a77580be /src/gui/kernel/qapplication_s60.cpp
parentf42f5c457b3368adb4c92e521dc56969f138bdd3 (diff)
downloadQt-56cec4cf9a8b04c979ced28cab89ce6232d4184a.zip
Qt-56cec4cf9a8b04c979ced28cab89ce6232d4184a.tar.gz
Qt-56cec4cf9a8b04c979ced28cab89ce6232d4184a.tar.bz2
QCursor support for Symbian OS
Reviewed-By: Jason Barron Reviewed-By: Alessandro Portale Summary: QT_NO_CURSOR is now not defined for symbian builds Existing QCursor APIs are all supported New public API, QApplication::setNavigationMode, to allow the navigation mode to be set. I.E. on an S60 3.2 phone, some applications will want a virtual mouse cursor (web browser), while others are designed for keypad navigation. Symbian HAL is used for detecting input capabilities. Fix DND, code cleanup & comment QCursor visibility now uses a refcount, and is called from DND and the setNavigationMode so they are both simpler and don't interfere with each other. QApplication::setNavigationMode New public API for configuring cursor/keypad navi style. This links in with ongoing work on the 4-way keypad navi branch, but 2-way and 4-way modes both act as 2-way mode until that is integrated Some of the demos/examples have cursor switched on (those that were not usable with keypad) Virtual mouse support for non touch, non mouse phones (tested on N78) add *.d and .metadata (carbide debug file / workspace dir) to .gitignore System pointers are unavailable when using sprite workaround, so the system cursor shapes are compiled into qtgui as resources. MAC port does this also for shapes that aren't standard on the MAC. Refactor Drag'n'Drop to use QCursor Add test case to check all system cursor shapes Simply a mainwindow containing a label widget for each cursor shape, with the cursor property set appropriately QCursor(QBitmap,QBitmap) supported Fixed problem with the image & mask being inverted when using the QCursor constructor that takes two mono bitmaps. add .make.cache files to .gitignore Correct implementation of QApplication::setOverrideCursor QApplication::restoreOverrideCursor and QApplication::setOverrideCursor are now working correctly on Symbian platform. Performance will be slower compared with other platforms, because the Symbian window server has a cursor associated with each native window. Add test case for custom cursors Create a pixmap cursor and associate it with a widget. No changes to production code, since test passed 1st time ;) Add manual test for QCursor Make cursor independent of construction order Updated to work around window server issue where contruction order affects what cursor is displayed in child windows. Also changed to effectiveWinId following review comments Also fixed a problem which would make qcursor not link if configured with QT_NO_CURSOR Moved some multiply declared extern functions from cpp to _p.h files Implemented Symbian versions of the cursor functions. Merged in work I'd done based on tower. Fill in bits of stub functions based on windows port Removed QT_NO_CURSOR from list of config options forced on symbian Recompiled configure.exe Added stub functions for the missing functions in s60 port
Diffstat (limited to 'src/gui/kernel/qapplication_s60.cpp')
-rw-r--r--src/gui/kernel/qapplication_s60.cpp307
1 files changed, 287 insertions, 20 deletions
diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp
index 00932a0..fd889fc 100644
--- a/src/gui/kernel/qapplication_s60.cpp
+++ b/src/gui/kernel/qapplication_s60.cpp
@@ -73,6 +73,9 @@
#include "private/qstylesheetstyle_p.h"
+#include <hal.h>
+#include <hal_data.h>
+
QT_BEGIN_NAMESPACE
#if defined(QT_DEBUG)
@@ -151,21 +154,21 @@ void QS60Beep::ConstructL(TInt aFrequency, TTimeIntervalMicroSeconds aDuration)
void QS60Beep::Play()
{
- if(iState!=EBeepNotPrepared){
- if(iState==EBeepPlaying) {
+ if (iState != EBeepNotPrepared) {
+ if (iState == EBeepPlaying) {
iToneUtil->CancelPlay();
- iState=EBeepPrepared;
+ iState = EBeepPrepared;
}
}
iToneUtil->Play();
- iState=EBeepPlaying;
+ iState = EBeepPlaying;
}
void QS60Beep::MatoPrepareComplete(TInt aError)
{
- if(aError==KErrNone) {
- iState=EBeepPrepared;
+ if (aError == KErrNone) {
+ iState = EBeepPrepared;
}
}
@@ -320,8 +323,9 @@ void QSymbianControl::ConstructL(bool topLevel, bool desktop)
{
if (!desktop)
{
- if (topLevel)
+ if (topLevel) {
CreateWindowL(S60->windowGroup());
+ }
SetFocusing(true);
m_longTapDetector = QLongTapTimer::NewL(this);
@@ -330,6 +334,8 @@ void QSymbianControl::ConstructL(bool topLevel, bool desktop)
QSymbianControl::~QSymbianControl()
{
+ if (S60->curWin == this)
+ S60->curWin = 0;
S60->appUi()->RemoveFromStack(this);
delete m_longTapDetector;
}
@@ -392,14 +398,15 @@ void QSymbianControl::HandlePointerEvent(const TPointerEvent& pEvent)
TPoint controlScreenPos = PositionRelativeToScreen();
QPoint globalPos = QPoint(controlScreenPos.iX, controlScreenPos.iY) + widgetPos;
- if (type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick)
+ if (type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick || type == QEvent::MouseMove)
{
- // get the button press target
+ // get the widget where the event happened
alienWidget = qwidget->childAt(widgetPos);
if (!alienWidget)
alienWidget = qwidget;
S60->mousePressTarget = alienWidget;
}
+
alienWidget = S60->mousePressTarget;
if (alienWidget != S60->lastPointerEventTarget)
@@ -412,12 +419,30 @@ void QSymbianControl::HandlePointerEvent(const TPointerEvent& pEvent)
button, QApplicationPrivate::mouse_buttons, mapToQtModifiers(pEvent.iModifiers));
events.append(Event(S60->lastPointerEventTarget,mEventLeave));
}
- QMouseEvent mEventEnter(QEvent::Enter, alienWidget->mapFromGlobal(globalPos), globalPos,
- button, QApplicationPrivate::mouse_buttons, mapToQtModifiers(pEvent.iModifiers));
-
- events.append(Event(alienWidget,mEventEnter));
+ if (alienWidget) {
+ QMouseEvent mEventEnter(QEvent::Enter, alienWidget->mapFromGlobal(globalPos),
+ globalPos, button, QApplicationPrivate::mouse_buttons, mapToQtModifiers(
+ pEvent.iModifiers));
+
+ events.append(Event(alienWidget, mEventEnter));
+#ifndef QT_NO_CURSOR
+ S60->curWin = alienWidget->effectiveWinId();
+ if (!QApplication::overrideCursor()) {
+#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
+ if (S60->brokenPointerCursors)
+ qt_symbian_set_pointer_sprite(alienWidget->cursor());
+ else
+#endif
+ qt_symbian_setWindowCursor(alienWidget->cursor(), S60->curWin);
+ }
+#endif
+ }
}
S60->lastCursorPos = globalPos;
+#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
+ if (S60->brokenPointerCursors)
+ qt_symbian_move_cursor_sprite();
+#endif
S60->lastPointerEventPos = widgetPos;
S60->lastPointerEventTarget = alienWidget;
if (alienWidget)
@@ -494,6 +519,82 @@ TKeyResponse QSymbianControl::OfferKeyEvent(const TKeyEvent& keyEvent, TEventCod
// Special S60 keys.
keyCode = qt_keymapper_private()->mapS60KeyToQt(s60Keysym);
}
+
+#ifndef QT_NO_CURSOR
+ if (S60->mouseInteractionEnabled && S60->virtualMouseRequired) {
+ //translate keys to pointer
+ if (keyCode >= Qt::Key_Left && keyCode <= Qt::Key_Down || keyCode == Qt::Key_Select) {
+ /*Explanation about virtualMouseAccel:
+ Tapping an arrow key allows precise pixel positioning
+ Holding an arrow key down, acceleration is applied to allow cursor
+ to be quickly moved to another part of the screen by key repeats.
+ */
+ if (S60->virtualMouseLastKey == keyCode) {
+ S60->virtualMouseAccel *= 2;
+ if (S60->virtualMouseAccel > S60->virtualMouseMaxAccel)
+ S60->virtualMouseAccel = S60->virtualMouseMaxAccel;
+ }
+ else
+ S60->virtualMouseAccel = 1;
+ S60->virtualMouseLastKey = keyCode;
+
+ QPoint pos = QCursor::pos();
+ TPointerEvent fakeEvent;
+ TInt x = pos.x();
+ TInt y = pos.y();
+ if (type == EEventKeyUp) {
+ if (keyCode == Qt::Key_Select)
+ fakeEvent.iType = TPointerEvent::EButton1Up;
+ S60->virtualMouseAccel = 1;
+ S60->virtualMouseLastKey = 0;
+ }
+ else if (type == EEventKey) {
+ switch (keyCode) {
+ case Qt::Key_Left:
+ x -= S60->virtualMouseAccel;
+ fakeEvent.iType = TPointerEvent::EMove;
+ break;
+ case Qt::Key_Right:
+ x += S60->virtualMouseAccel;
+ fakeEvent.iType = TPointerEvent::EMove;
+ break;
+ case Qt::Key_Up:
+ y -= S60->virtualMouseAccel;
+ fakeEvent.iType = TPointerEvent::EMove;
+ break;
+ case Qt::Key_Down:
+ y += S60->virtualMouseAccel;
+ fakeEvent.iType = TPointerEvent::EMove;
+ break;
+ case Qt::Key_Select:
+ fakeEvent.iType = TPointerEvent::EButton1Down;
+ break;
+ }
+ }
+ //clip to screen size (window server allows a sprite hotspot to be outside the screen)
+ if (x < 0)
+ x = 0;
+ else if (x >= S60->screenWidthInPixels)
+ x = S60->screenWidthInPixels - 1;
+ if (y < 0)
+ y = 0;
+ else if (y >= S60->screenHeightInPixels)
+ y = S60->screenHeightInPixels - 1;
+ TPoint epos(x, y);
+ TPoint cpos = epos - PositionRelativeToScreen();
+ fakeEvent.iModifiers = keyEvent.iModifiers;
+ fakeEvent.iPosition = cpos;
+ fakeEvent.iParentPosition = epos;
+ HandlePointerEvent(fakeEvent);
+ return EKeyWasConsumed;
+ }
+ else {
+ S60->virtualMouseLastKey = keyCode;
+ S60->virtualMouseAccel = 1;
+ }
+ }
+#endif
+
Qt::KeyboardModifiers mods = mapToQtModifiers(keyEvent.iModifiers);
QKeyEventEx qKeyEvent(type == EEventKeyUp ? QEvent::KeyRelease : QEvent::KeyPress, keyCode,
mods, qt_keymapper_private()->translateKeyEvent(keyCode, mods),
@@ -557,7 +658,7 @@ TKeyResponse QSymbianControl::sendKeyEvent(QWidget *widget, QKeyEvent *keyEvent)
#if !defined(QT_NO_IM) && defined(Q_WS_S60)
if (widget && widget->isEnabled() && widget->testAttribute(Qt::WA_InputMethodEnabled)) {
QInputContext *qic = widget->inputContext();
- if(qic && qic->filterEvent(keyEvent))
+ if (qic && qic->filterEvent(keyEvent))
return EKeyWasConsumed;
}
#endif // !defined(QT_NO_IM) && defined(Q_WS_S60)
@@ -574,11 +675,10 @@ TCoeInputCapabilities QSymbianControl::InputCapabilities() const
{
QWidget *w = 0;
- if(qwidget->hasFocus()) {
+ if (qwidget->hasFocus())
w = qwidget;
- } else {
+ else
w = qwidget->focusWidget();
- }
QCoeFepInputContext *ic;
if (w && w->isEnabled() && w->testAttribute(Qt::WA_InputMethodEnabled)
@@ -749,6 +849,70 @@ void qt_init(QApplicationPrivate * /* priv */, int)
TSecureId securId = me.SecureId();
S60->uid = securId.operator TUid();
+ // enable focus events - used to re-enable mouse after focus changed between mouse and non mouse app,
+ // and for dimming behind modal windows
+ S60->windowGroup().EnableFocusChangeEvents();
+
+ //Check if mouse interaction is supported (either EMouse=1 in the HAL, or EMachineUID is one of the phones known to support this)
+ const TInt KMachineUidSamsungI8510 = 0x2000C51E;
+ const TInt KMachineUidSamsungI550 = 0x2000A678;
+ TInt machineUID;
+ TInt mouse;
+ TInt touch;
+ TInt err;
+ err = HAL::Get(HALData::EMouse, mouse);
+ if (err != KErrNone)
+ mouse = 0;
+ err = HAL::Get(HALData::EMachineUid, machineUID);
+ if (err != KErrNone)
+ machineUID = 0;
+ err = HAL::Get(HALData::EPen, touch);
+ if (err != KErrNone)
+ touch = 0;
+ if (mouse || machineUID == KMachineUidSamsungI8510) {
+ S60->hasTouchscreen = false;
+ S60->virtualMouseRequired = false;
+ }
+ else if (!touch) {
+ S60->hasTouchscreen = false;
+ S60->virtualMouseRequired = true;
+ }
+ else {
+ S60->hasTouchscreen = true;
+ S60->virtualMouseRequired = false;
+ }
+
+ if (touch) {
+ QApplicationPrivate::navigationMode = Qt::NavigationModeNone;
+ } else {
+ QApplicationPrivate::navigationMode = Qt::NavigationModeKeypadDirectional;
+ }
+
+ //Check if window server pointer cursors are supported or not
+#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
+ //In generic binary, use the HAL and OS version
+ //Any other known good phones should be added here.
+ if (machineUID == KMachineUidSamsungI8510 || (QSysInfo::symbianVersion() != QSysInfo::SV_9_4
+ && QSysInfo::symbianVersion() != QSysInfo::SV_9_3 && QSysInfo::symbianVersion()
+ != QSysInfo::SV_9_2)) {
+ S60->brokenPointerCursors = false;
+ qt_symbian_setWindowGroupCursor(Qt::ArrowCursor, S60->windowGroup());
+ }
+ else
+ S60->brokenPointerCursors = true;
+#endif
+
+ if (S60->mouseInteractionEnabled) {
+#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
+ if (S60->brokenPointerCursors) {
+ qt_symbian_set_pointer_sprite(Qt::ArrowCursor);
+ qt_symbian_show_pointer_sprite();
+ }
+ else
+#endif
+ S60->wsSession().SetPointerCursorMode(EPointerCursorNormal);
+ }
+
/*
### Commented out for now as parameter handling not needed in SOS(yet). Code below will break testlib with -o flag
int argc = priv->argc;
@@ -785,6 +949,9 @@ void qt_cleanup()
// it dies.
delete QApplicationPrivate::inputContext;
QApplicationPrivate::inputContext = 0;
+
+ //Change mouse pointer back
+ S60->wsSession().SetPointerCursorMode(EPointerCursorNone);
if (S60->qtOwnsS60Environment) {
CEikonEnv* coe = CEikonEnv::Static();
@@ -1016,9 +1183,8 @@ void QApplication::beep()
TTimeIntervalMicroSeconds duration(500000);
QS60Beep* beep=NULL;
TRAPD(err, beep=QS60Beep::NewL(frequency, duration));
- if(!err) {
+ if (!err)
beep->Play();
- }
delete beep;
beep=NULL;
}
@@ -1108,7 +1274,31 @@ int QApplication::s60ProcessEvent(TWsEvent *event)
return 1;
}
break;
- default:
+ case EEventFocusGained:
+ RDebug::Printf("focus gained %x", control);
+ //re-enable mouse interaction
+ if (S60->mouseInteractionEnabled) {
+#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
+ if (S60->brokenPointerCursors)
+ qt_symbian_show_pointer_sprite();
+ else
+#endif
+ S60->wsSession().SetPointerCursorMode(EPointerCursorNormal);
+ }
+ break;
+ case EEventFocusLost:
+ RDebug::Printf("focus lost %x", control);
+ //disable mouse as may be moving to application that does not support it
+ if (S60->mouseInteractionEnabled) {
+#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
+ if (S60->brokenPointerCursors)
+ qt_symbian_hide_pointer_sprite();
+ else
+#endif
+ S60->wsSession().SetPointerCursorMode(EPointerCursorNone);
+ }
+ break;
+ default:
break;
}
@@ -1279,4 +1469,81 @@ void QSessionManager::cancel()
}
#endif //QT_NO_SESSIONMANAGER
+
+#ifdef QT_KEYPAD_NAVIGATION
+/*
+ * Show/Hide the mouse cursor depending on phone type and chosen mode
+ */
+void QApplicationPrivate::setNavigationMode(Qt::NavigationMode mode)
+{
+#ifndef QT_NO_CURSOR
+ const bool wasCursorOn = (QApplicationPrivate::navigationMode == Qt::NavigationModeCursorAuto
+ && !S60->hasTouchscreen)
+ || QApplicationPrivate::navigationMode == Qt::NavigationModeCursorForceVisible;
+ const bool isCursorOn = (mode == Qt::NavigationModeCursorAuto
+ && !S60->hasTouchscreen)
+ || mode == Qt::NavigationModeCursorForceVisible;
+
+ if (!wasCursorOn && isCursorOn) {
+ //Show the cursor, when changing from another mode to cursor mode
+ qt_symbian_set_cursor_visible(true);
+ }
+ else if (wasCursorOn && !isCursorOn) {
+ //Hide the cursor, when leaving cursor mode
+ qt_symbian_set_cursor_visible(false);
+ }
+#endif
+ QApplicationPrivate::navigationMode = mode;
+}
+#endif
+
+#ifndef QT_NO_CURSOR
+/*****************************************************************************
+ QApplication cursor stack
+ *****************************************************************************/
+
+void QApplication::setOverrideCursor(const QCursor &cursor)
+{
+ qApp->d_func()->cursor_list.prepend(cursor);
+ qt_symbian_setGlobalCursor(cursor);
+}
+
+void QApplication::restoreOverrideCursor()
+{
+ if (qApp->d_func()->cursor_list.isEmpty())
+ return;
+ qApp->d_func()->cursor_list.removeFirst();
+
+ if (!qApp->d_func()->cursor_list.isEmpty()) {
+ qt_symbian_setGlobalCursor(qApp->d_func()->cursor_list.first());
+ }
+ else {
+ //determine which widget has focus
+ QWidget *w = QApplication::widgetAt(QCursor::pos());
+#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS
+ if (S60->brokenPointerCursors) {
+ qt_symbian_set_pointer_sprite(w ? w->cursor() : Qt::ArrowCursor);
+ }
+ else
+#endif
+ {
+ //because of the internals of window server, we need to force the cursor
+ //to be set in all child windows too, otherwise when the cursor is over
+ //the child window it may show a widget cursor or arrow cursor instead,
+ //depending on construction order.
+ QListIterator<WId> iter(QWidgetPrivate::mapper->uniqueKeys());
+ while (iter.hasNext()) {
+ CCoeControl *ctrl = iter.next();
+ ctrl->DrawableWindow()->ClearPointerCursor();
+ }
+ if (w)
+ qt_symbian_setWindowCursor(w->cursor(), w->effectiveWinId());
+ else
+ qt_symbian_setWindowGroupCursor(Qt::ArrowCursor, S60->windowGroup());
+ }
+ }
+}
+
+#endif // QT_NO_CURSOR
+
QT_END_NAMESPACE