diff options
Diffstat (limited to 'src/gui/kernel')
53 files changed, 5545 insertions, 390 deletions
diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri index a94c5a3..8489817 100644 --- a/src/gui/kernel/kernel.pri +++ b/src/gui/kernel/kernel.pri @@ -7,6 +7,7 @@ PRECOMPILED_HEADER = kernel/qt_gui_pch.h KERNEL_P= kernel HEADERS += \ kernel/qaction.h \ + kernel/qaction_p.h \ kernel/qactiongroup.h \ kernel/qapplication.h \ kernel/qapplication_p.h \ @@ -96,6 +97,27 @@ win32 { !contains(DEFINES, QT_NO_DIRECTDRAW):LIBS += ddraw.lib } +symbian { + SOURCES += \ + kernel/qapplication_s60.cpp \ + kernel/qeventdispatcher_s60.cpp \ + kernel/qwidget_s60.cpp \ + kernel/qcursor_s60.cpp \ + kernel/qdesktopwidget_s60.cpp \ + kernel/qkeymapper_s60.cpp\ + kernel/qclipboard_s60.cpp\ + kernel/qdnd_s60.cpp \ + kernel/qsound_s60.cpp + + HEADERS += \ + kernel/qt_s60_p.h \ + kernel/qeventdispatcher_s60_p.h + LIBS += -lbafl -lestor + + INCLUDEPATH += $$MW_LAYER_SYSTEMINCLUDE +} + + unix:x11 { INCLUDEPATH += ../3rdparty/xorg HEADERS += \ @@ -172,7 +194,7 @@ embedded { qcocoaview_mac_p.h \ qcocoaapplication_mac_p.h \ qcocoaapplicationdelegate_mac_p.h \ - qmultitouch_mac_p.h + qmultitouch_mac_p.h OBJECTIVE_SOURCES += \ kernel/qcursor_mac.mm \ @@ -190,7 +212,7 @@ embedded { kernel/qt_cocoa_helpers_mac.mm \ kernel/qdesktopwidget_mac.mm \ kernel/qeventdispatcher_mac.mm \ - kernel/qcocoawindowcustomthemeframe_mac.mm \ + kernel/qcocoawindowcustomthemeframe_mac.mm \ kernel/qmultitouch_mac.mm \ HEADERS += \ @@ -199,10 +221,10 @@ embedded { kernel/qcocoaapplicationdelegate_mac_p.h \ kernel/qeventdispatcher_mac_p.h - MENU_NIB.files = mac/qt_menu.nib - MENU_NIB.path = Resources + MENU_NIB.files = mac/qt_menu.nib + MENU_NIB.path = Resources MENU_NIB.version = Versions - QMAKE_BUNDLE_DATA += MENU_NIB + QMAKE_BUNDLE_DATA += MENU_NIB RESOURCES += mac/macresources.qrc LIBS_PRIVATE += -framework AppKit diff --git a/src/gui/kernel/qaction.cpp b/src/gui/kernel/qaction.cpp index 4b44452..f5e1f29 100644 --- a/src/gui/kernel/qaction.cpp +++ b/src/gui/kernel/qaction.cpp @@ -81,7 +81,8 @@ static QString qt_strippedText(QString s) QActionPrivate::QActionPrivate() : group(0), enabled(1), forceDisabled(0), visible(1), forceInvisible(0), checkable(0), checked(0), separator(0), fontSet(false), - menuRole(QAction::TextHeuristicRole), priority(QAction::NormalPriority), iconVisibleInMenu(-1) + menuRole(QAction::TextHeuristicRole), softKeyRole(QAction::OptionsSoftKey), + priority(QAction::NormalPriority), iconVisibleInMenu(-1) { #ifdef QT3_SUPPORT static int qt_static_action_id = -1; @@ -261,6 +262,11 @@ void QActionPrivate::setShortcutEnabled(bool enable, QShortcutMap &map) \c{Info.plist} file in the application's bundle (See \l{Deploying an Application on Mac OS X}). \value PreferencesRole This action should be placed where the "Preferences..." menu item is in the application menu. \value QuitRole This action should be placed where the Quit menu item is in the application menu. + + Setting this value only has effect on items that are in the immediate menus + of the menubar, not the submenus of those menus. For example, if you have + File menu in your menubar and the File menu has a submenu, setting the + MenuRole for the actions in that submenu have no effect. They will never be moved. */ /*! @@ -1407,6 +1413,32 @@ QAction::MenuRole QAction::menuRole() const } /*! + \property QAction::softKeyRole + \brief the action's softkey role + \since 4.6 + + This indicates what softkey action this action is. Usually used on mobile + platforms to map QActions to hardware keys. + + The softkey role can be changed any time. +*/ +void QAction::setSoftKeyRole(SoftKeyRole softKeyRole) +{ + Q_D(QAction); + if (d->softKeyRole == softKeyRole) + return; + + d->softKeyRole = softKeyRole; + d->sendDataChanged(); +} + +QAction::SoftKeyRole QAction::softKeyRole() const +{ + Q_D(const QAction); + return d->softKeyRole; +} + +/*! \property QAction::iconVisibleInMenu \brief Whether or not an action should show an icon in a menu \since 4.4 diff --git a/src/gui/kernel/qaction.h b/src/gui/kernel/qaction.h index 1e799cf..bee8c11 100644 --- a/src/gui/kernel/qaction.h +++ b/src/gui/kernel/qaction.h @@ -67,6 +67,7 @@ class Q_GUI_EXPORT QAction : public QObject Q_DECLARE_PRIVATE(QAction) Q_ENUMS(MenuRole) + Q_ENUMS(SoftKeyRole) Q_ENUMS(Priority) Q_PROPERTY(bool checkable READ isCheckable WRITE setCheckable NOTIFY changed) Q_PROPERTY(bool checked READ isChecked WRITE setChecked DESIGNABLE isCheckable NOTIFY toggled) @@ -85,12 +86,17 @@ class Q_GUI_EXPORT QAction : public QObject #endif Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY changed) Q_PROPERTY(MenuRole menuRole READ menuRole WRITE setMenuRole NOTIFY changed) + Q_PROPERTY(SoftKeyRole softKeyRole READ softKeyRole WRITE setSoftKeyRole NOTIFY changed) Q_PROPERTY(bool iconVisibleInMenu READ isIconVisibleInMenu WRITE setIconVisibleInMenu NOTIFY changed) Q_PROPERTY(Priority priority READ priority WRITE setPriority) public: enum MenuRole { NoRole, TextHeuristicRole, ApplicationSpecificRole, AboutQtRole, AboutRole, PreferencesRole, QuitRole }; + enum SoftKeyRole { OptionsSoftKey, SelectSoftKey, BackSoftKey, NextSoftKey, PreviousSoftKey, + OkSoftKey, CancelSoftKey, EditSoftKey, ViewSoftKey, BackSpaceSoftKey, + EndEditSoftKey, RevertEditSoftKey, DeselectSoftKey, FinishSoftKey, + MenuSoftKey, ContextMenuSoftKey, ExitSoftKey }; enum Priority { LowPriority = 0, NormalPriority = 128, HighPriority = 256}; @@ -176,6 +182,9 @@ public: void setMenuRole(MenuRole menuRole); MenuRole menuRole() const; + void setSoftKeyRole(SoftKeyRole softKeyRole); + SoftKeyRole softKeyRole() const; + void setIconVisibleInMenu(bool visible); bool isIconVisibleInMenu() const; diff --git a/src/gui/kernel/qaction_p.h b/src/gui/kernel/qaction_p.h index d158e7c..732196c 100644 --- a/src/gui/kernel/qaction_p.h +++ b/src/gui/kernel/qaction_p.h @@ -102,6 +102,7 @@ public: uint separator : 1; uint fontSet : 1; QAction::MenuRole menuRole; + QAction::SoftKeyRole softKeyRole; QAction::Priority priority; int iconVisibleInMenu : 3; // Only has values -1, 0, and 1 QList<QWidget *> widgets; diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index ccf6ac9..8e9c3a1 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -75,6 +75,9 @@ #ifdef Q_WS_X11 #include <private/qt_x11_p.h> +#endif + +#if defined(Q_WS_X11) || defined(Q_WS_S60) #include "qinputcontextfactory.h" #endif @@ -138,6 +141,8 @@ bool QApplicationPrivate::quitOnLastWindowClosed = true; #ifdef Q_WS_WINCE int QApplicationPrivate::autoMaximizeThreshold = -1; bool QApplicationPrivate::autoSipEnabled = false; +#else +bool QApplicationPrivate::autoSipEnabled = true; #endif QApplicationPrivate::QApplicationPrivate(int &argc, char **argv, QApplication::Type type) @@ -433,7 +438,12 @@ bool Q_GUI_EXPORT qt_tab_all_widgets = true; bool qt_in_tab_key_event = false; int qt_antialiasing_threshold = -1; static int drag_time = 500; +#ifdef Q_OS_SYMBIAN +// The screens are a bit too small to for your thumb when using only 4 pixels drag distance. +static int drag_distance = 8; +#else static int drag_distance = 4; +#endif static Qt::LayoutDirection layout_direction = Qt::LeftToRight; QSize QApplicationPrivate::app_strut = QSize(0,0); // no default application strut bool QApplicationPrivate::animate_ui = true; @@ -448,7 +458,11 @@ bool QApplicationPrivate::widgetCount = false; bool QApplicationPrivate::inSizeMove = false; #endif #ifdef QT_KEYPAD_NAVIGATION +# if defined(Q_OS_SYMBIAN) +bool QApplicationPrivate::keypadNavigation = true; +# else bool QApplicationPrivate::keypadNavigation = false; +# endif QWidget *QApplicationPrivate::oldEditFocus = 0; #endif @@ -836,7 +850,7 @@ extern int qUnregisterGuiStateMachine(); void QApplicationPrivate::initialize() { QWidgetPrivate::mapper = new QWidgetMapper; - QWidgetPrivate::uncreatedWidgets = new QWidgetSet; + QWidgetPrivate::allWidgets = new QWidgetSet; if (qt_appType != QApplication::Tty) (void) QApplication::style(); // trigger creation of application style // trigger registering of QVariant's GUI types @@ -980,23 +994,14 @@ QApplication::~QApplication() qt_clipboard = 0; #endif - // delete widget mapper - if (QWidgetPrivate::mapper) { - QWidgetMapper * myMapper = QWidgetPrivate::mapper; - QWidgetPrivate::mapper = 0; - for (QWidgetMapper::Iterator it = myMapper->begin(); it != myMapper->end(); ++it) { - register QWidget *w = *it; - if (!w->parent()) // window - w->destroy(true, true); - } - delete myMapper; - } + delete QWidgetPrivate::mapper; + QWidgetPrivate::mapper = 0; - // delete uncreated widgets - if (QWidgetPrivate::uncreatedWidgets) { - QWidgetSet *mySet = QWidgetPrivate::uncreatedWidgets; - QWidgetPrivate::uncreatedWidgets = 0; - for (QWidgetSet::Iterator it = mySet->begin(); it != mySet->end(); ++it) { + // delete all widgets + if (QWidgetPrivate::allWidgets) { + QWidgetSet *mySet = QWidgetPrivate::allWidgets; + QWidgetPrivate::allWidgets = 0; + for (QWidgetSet::ConstIterator it = mySet->constBegin(); it != mySet->constEnd(); ++it) { register QWidget *w = *it; if (!w->parent()) // window w->destroy(true, true); @@ -1219,11 +1224,15 @@ bool QApplication::compressEvent(QEvent *event, QObject *receiver, QPostEventLis \since 4.5 \brief toggles automatic SIP (software input panel) visibility - \bold{The auto SIP property is only available as part of Qt for Windows CE.} - Set this property to \c true to automatically display the SIP when entering widgets that accept keyboard input. This property only affects widgets with - the WA_InputMethodEnabled attribute set. + the WA_InputMethodEnabled attribute set, and is typically used to launch + a virtual keyboard on devices which have very few or no keys. + + \bold{ The property only has an effect on platforms which use software input + panels, such as Windows CE and Symbian.} + + The default is platform dependent. */ #ifdef Q_WS_WINCE @@ -1236,6 +1245,7 @@ int QApplication::autoMaximizeThreshold() const { return QApplicationPrivate::autoMaximizeThreshold; } +#endif void QApplication::setAutoSipEnabled(const bool enabled) { @@ -1246,7 +1256,6 @@ bool QApplication::autoSipEnabled() const { return QApplicationPrivate::autoSipEnabled; } -#endif #ifndef QT_NO_STYLE_STYLESHEET @@ -1928,6 +1937,10 @@ QString desktopstyle; desktopstyle = QLatin1String("Windows"); // default styles for Windows #elif defined(Q_WS_X11) && defined(Q_OS_SOLARIS) desktopstyle = QLatin1String("CDE"); // default style for X11 on Solaris +#elif defined(Q_WS_S60) + desktopstyle = QLatin1String("S60"); // default style for Symbian with S60 +#elif defined(Q_OS_SYMBIAN) + desktopstyle = QLatin1String("Windows"); // default style for Symbian without S60 #elif defined(Q_WS_X11) && defined(Q_OS_IRIX) desktopstyle = QLatin1String("SGI"); // default style for X11 on IRIX #elif defined(Q_WS_QWS) @@ -2012,12 +2025,9 @@ QWidgetList QApplication::topLevelWidgets() QWidgetList QApplication::allWidgets() { - QWidgetList list; - if (QWidgetPrivate::mapper) - list += QWidgetPrivate::mapper->values(); - if (QWidgetPrivate::uncreatedWidgets) - list += QWidgetPrivate::uncreatedWidgets->toList(); - return list; + if (QWidgetPrivate::allWidgets) + return QWidgetPrivate::allWidgets->toList(); + return QWidgetList(); } /*! @@ -2082,6 +2092,16 @@ void QApplicationPrivate::setFocusWidget(QWidget *focus, Qt::FocusReason reason) prev->setEditFocus(false); } #endif +#ifndef QT_NO_IM + if (focus) { + QInputContext *prevIc; + prevIc = prev->inputContext(); + if (prevIc && prevIc != focus->inputContext()) { + QEvent closeSIPEvent(QEvent::CloseSoftwareInputPanel); + QApplication::sendEvent(prev, &closeSIPEvent); + } + } +#endif QFocusEvent out(QEvent::FocusOut, reason); QPointer<QWidget> that = prev; QApplication::sendEvent(prev, &out); @@ -3720,6 +3740,14 @@ bool QApplication::notify(QObject *receiver, QEvent *e) QPoint relpos = mouse->pos(); if (e->spontaneous()) { +#ifndef QT_NO_IM + QInputContext *ic = w->inputContext(); + if (ic + && w->testAttribute(Qt::WA_InputMethodEnabled) + && ic->filterEvent(mouse)) + return true; +#endif + if (e->type() == QEvent::MouseButtonPress) { QApplicationPrivate::giveFocusAccordingToFocusPolicy(w, Qt::ClickFocus, @@ -4058,6 +4086,20 @@ bool QApplication::notify(QObject *receiver, QEvent *e) touchEvent->setAccepted(eventAccepted); break; } + case QEvent::RequestSoftwareInputPanel: + case QEvent::CloseSoftwareInputPanel: +#ifndef QT_NO_IM + if (receiver->isWidgetType()) { + QWidget *w = static_cast<QWidget *>(receiver); + QInputContext *ic = w->inputContext(); + if (ic && ic->filterEvent(e)) { + break; + } + } +#endif + res = d->notify_helper(receiver, e); + break; + case QEvent::NativeGesture: { // only propagate the first gesture event (after the GID_BEGIN) @@ -4729,7 +4771,7 @@ void QApplicationPrivate::emitLastWindowClosed() If \a enable is true, Qt::Key_Up and Qt::Key_Down are used to change focus. - This feature is available in Qt for Embedded Linux only. + This feature is available in Qt for Embedded Linux and Symbian only. \sa keypadNavigationEnabled() */ @@ -4740,9 +4782,9 @@ void QApplication::setKeypadNavigationEnabled(bool enable) /*! Returns true if Qt is set to use keypad navigation; otherwise returns - false. The default is false. + false. The default value is true on Symbian, but false on other platforms. - This feature is available in Qt for Embedded Linux only. + This feature is available in Qt for Embedded Linux and Symbian only. \sa setKeypadNavigationEnabled() */ @@ -4797,8 +4839,8 @@ bool QApplication::keypadNavigationEnabled() from two consecutive mouse clicks The default value on X11 is 400 milliseconds. On Windows and Mac OS, the - operating system's value is used. However, on Windows, calling this - function sets the double click interval for all applications. + operating system's value is used. However, on Windows and Symbian OS, + calling this function sets the double click interval for all applications. */ /*! @@ -4957,8 +4999,7 @@ void QApplication::setInputContext(QInputContext *inputContext) qWarning("QApplication::setInputContext: called with 0 input context"); return; } - if (d->inputContext) - delete d->inputContext; + delete d->inputContext; d->inputContext = inputContext; } @@ -4982,6 +5023,11 @@ QInputContext *QApplication::inputContext() const qic = QInputContextFactory::create(QLatin1String("xim"), that); that->d_func()->inputContext = qic; } +#elif defined(Q_WS_S60) + if (!d->inputContext) { + QApplication *that = const_cast<QApplication *>(this); + that->d_func()->inputContext = QInputContextFactory::create(QString::fromLatin1("coefep"), that); + } #endif return d->inputContext; } @@ -4999,6 +5045,8 @@ uint QApplicationPrivate::currentPlatform(){ platform |= KB_Gnome; if (X11->desktopEnvironment == DE_CDE) platform |= KB_CDE; +#elif defined(Q_OS_SYMBIAN) + platform = KB_S60; #endif return platform; } diff --git a/src/gui/kernel/qapplication.h b/src/gui/kernel/qapplication.h index 8d3acae..8122977 100644 --- a/src/gui/kernel/qapplication.h +++ b/src/gui/kernel/qapplication.h @@ -61,6 +61,10 @@ QT_BEGIN_HEADER +#if defined(Q_OS_SYMBIAN) +class TWsEvent; +#endif + QT_BEGIN_NAMESPACE QT_MODULE(Gui) @@ -84,6 +88,7 @@ class QApplicationPrivate; #endif #define qApp (static_cast<QApplication *>(QCoreApplication::instance())) + class Q_GUI_EXPORT QApplication : public QCoreApplication { Q_OBJECT @@ -104,8 +109,8 @@ class Q_GUI_EXPORT QApplication : public QCoreApplication #endif #ifdef Q_WS_WINCE Q_PROPERTY(int autoMaximizeThreshold READ autoMaximizeThreshold WRITE setAutoMaximizeThreshold) - Q_PROPERTY(bool autoSipEnabled READ autoSipEnabled WRITE setAutoSipEnabled) #endif + Q_PROPERTY(bool autoSipEnabled READ autoSipEnabled WRITE setAutoSipEnabled) public: enum Type { Tty, GuiClient, GuiServer }; @@ -223,6 +228,12 @@ public: virtual int x11ClientMessage(QWidget*, XEvent*, bool passive_only); int x11ProcessEvent(XEvent*); #endif +#if defined(Q_OS_SYMBIAN) + int s60ProcessEvent(TWsEvent *event); + virtual bool s60EventFilter(TWsEvent *aEvent); + void symbianHandleCommand(int command); + void symbianResourceChange(int type); +#endif #if defined(Q_WS_QWS) virtual bool qwsEventFilter(QWSEvent *); int qwsProcessEvent(QWSEvent*); @@ -239,7 +250,6 @@ public: void winFocus(QWidget *, bool); static void winMouseButtonUp(); #endif - #ifndef QT_NO_SESSIONMANAGER // session management bool isSessionRestored() const; @@ -284,9 +294,9 @@ public Q_SLOTS: #ifdef Q_WS_WINCE void setAutoMaximizeThreshold(const int threshold); int autoMaximizeThreshold() const; +#endif void setAutoSipEnabled(const bool enabled); bool autoSipEnabled() const; -#endif static void closeAllWindows(); static void aboutQt(); diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index 5d409f4..e839617 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -100,6 +100,7 @@ extern QSysInfo::MacVersion qt_macver; #if defined(Q_WS_QWS) class QWSManager; class QDirectPainter; +struct QWSServerCleaner { ~QWSServerCleaner(); }; #endif #ifndef QT_NO_TABLET @@ -248,6 +249,17 @@ typedef struct tagGESTURECONFIG #endif // WM_GESTURE +#if defined(Q_WS_WINCE_WM) && defined(QT_WINCE_GESTURES) +#undef GID_ZOOM +#define GID_ZOOM 0xf000 +#undef GID_ROTATE +#define GID_ROTATE 0xf001 +#undef GID_TWOFINGERTAP +#define GID_TWOFINGERTAP 0xf002 +#undef GID_ROLLOVER +#define GID_ROLLOVER 0xf003 +#endif + #endif // Q_WS_WIN class QPanGesture; @@ -299,8 +311,8 @@ public: static void emitLastWindowClosed(); #ifdef Q_WS_WINCE static int autoMaximizeThreshold; - static bool autoSipEnabled; #endif + static bool autoSipEnabled; static QString desktopStyleKey(); static QGraphicsSystem *graphicsSystem() @@ -312,7 +324,6 @@ public: void createEventDispatcher(); QString appName() const; - static void dispatchEnterLeave(QWidget *enter, QWidget *leave); //modality @@ -349,6 +360,7 @@ public: KB_KDE = 8, KB_Gnome = 16, KB_CDE = 32, + KB_S60 = 64, KB_All = 0xffff }; @@ -461,6 +473,7 @@ public: #ifdef Q_WS_QWS QPointer<QWSManager> last_manager; + QWSServerCleaner qwsServerCleaner; # ifndef QT_NO_DIRECTPAINTER QMap<WId, QDirectPainter *> *directPainters; # endif @@ -494,6 +507,9 @@ public: static bool sendMouseEvent(QWidget *receiver, QMouseEvent *event, QWidget *alienWidget, QWidget *native, QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver, bool spontaneous = true); +#ifdef Q_OS_SYMBIAN + static TUint resolveS60ScanCode(TInt scanCode, TUint keysym); +#endif #if defined(Q_WS_WIN) || defined(Q_WS_X11) void sendSyntheticEnterLeave(QWidget *widget); #endif @@ -531,6 +547,7 @@ public: PtrBeginPanningFeedback BeginPanningFeedback; PtrUpdatePanningFeedback UpdatePanningFeedback; PtrEndPanningFeedback EndPanningFeedback; + QWidget *gestureWidget; #endif #ifdef QT_RX71_MULTITOUCH @@ -556,6 +573,10 @@ private: QMap<const QScreen*, QRect> maxWindowRects; #endif +#ifdef Q_OS_SYMBIAN + static QHash<TInt, TUint> scanCodeCache; +#endif + static QApplicationPrivate *self; static void giveFocusAccordingToFocusPolicy(QWidget *w, diff --git a/src/gui/kernel/qapplication_qws.cpp b/src/gui/kernel/qapplication_qws.cpp index f7b7173..f7a7ab0 100644 --- a/src/gui/kernel/qapplication_qws.cpp +++ b/src/gui/kernel/qapplication_qws.cpp @@ -163,6 +163,8 @@ bool qws_overrideCursor = false; #ifndef QT_NO_QWS_MANAGER #include "qdecorationfactory_qws.h" +extern Q_GUI_EXPORT QWSServer *qwsServer; + QT_BEGIN_NAMESPACE QT_USE_NAMESPACE @@ -496,8 +498,13 @@ QList<QWSCommand*> *qt_get_server_queue() void qt_server_enqueue(const QWSCommand *command) { QWSCommand *copy = QWSCommand::factory(command->type); - copy->copyFrom(command); - outgoing.append(copy); + QT_TRY { + copy->copyFrom(command); + outgoing.append(copy); + } QT_CATCH(...) { + delete copy; + QT_RETHROW; + } } QWSDisplay::Data::Data(QObject* parent, bool singleProcess) @@ -673,7 +680,7 @@ void QWSDisplay::Data::sendSynchronousCommand(QWSCommand & cmd) int QWSDisplay::Data::takeId() { int unusedIdCount = unused_identifiers.count(); - if (unusedIdCount == 10) + if (unusedIdCount <= 10) create(15); if (unusedIdCount == 0) { create(1); // Make sure we have an incoming id to wait for, just in case we're recursive @@ -2311,7 +2318,7 @@ void qt_init(QApplicationPrivate *priv, int type) qws_decoration = QApplication::qwsSetDecoration(decoration); #endif // QT_NO_QWS_MANAGER #ifndef QT_NO_QWS_INPUTMETHODS - qApp->setInputContext(new QWSInputContext); + qApp->setInputContext(new QWSInputContext(qApp)); #endif } @@ -3558,10 +3565,10 @@ bool QETWidget::translateKeyEvent(const QWSKeyEvent *event, bool grab) /* grab i #if defined QT3_SUPPORT && !defined(QT_NO_SHORTCUT) if (type == QEvent::KeyPress && !grab - && static_cast<QApplicationPrivate*>(qApp->d_ptr)->use_compat()) { + && static_cast<QApplicationPrivate*>(qApp->d_ptr.data())->use_compat()) { // send accel events if the keyboard is not grabbed QKeyEvent a(type, code, state, text, autor, int(text.length())); - if (static_cast<QApplicationPrivate*>(qApp->d_ptr)->qt_tryAccelEvent(this, &a)) + if (static_cast<QApplicationPrivate*>(qApp->d_ptr.data())->qt_tryAccelEvent(this, &a)) return true; } #else @@ -3766,4 +3773,14 @@ void QApplicationPrivate::initializeMultitouch_sys() void QApplicationPrivate::cleanupMultitouch_sys() { } +/* \internal + This is used to clean up the qws server + in case the QApplication constructor threw an exception +*/ +QWSServerCleaner::~QWSServerCleaner() +{ + if (qwsServer && qws_single_process) + QWSServer::closedown(); +} + QT_END_NAMESPACE diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp new file mode 100644 index 0000000..648a5d5 --- /dev/null +++ b/src/gui/kernel/qapplication_s60.cpp @@ -0,0 +1,1198 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qapplication_p.h" +#include "qsessionmanager.h" +#include "qevent.h" +#include "qeventdispatcher_s60_p.h" +#include "qwidget.h" +#include "qdesktopwidget.h" +#include "private/qbackingstore_p.h" +#include "qt_s60_p.h" +#include "private/qevent_p.h" +#include "qstring.h" +#include "qdebug.h" +#include "qimage.h" +#include "private/qkeymapper_p.h" +#include "private/qfont_p.h" +#ifndef QT_NO_STYLE_S60 +#include "private/qs60style_p.h" +#endif +#include "private/qwindowsurface_s60_p.h" +#include "qpaintengine.h" +#include "private/qmenubar_p.h" + +#include "apgwgnam.h" // For CApaWindowGroupName +#include <MdaAudioTonePlayer.h> // For CMdaAudioToneUtility + +#if !defined(QT_NO_IM) && defined(Q_WS_S60) +#include "qinputcontext.h" +#include <private/qcoefepinputcontext_p.h> +#endif // !defined(QT_NO_IM) && defined(Q_WS_S60) + +#include "private/qstylesheetstyle_p.h" + +QT_BEGIN_NAMESPACE + +#if defined(QT_DEBUG) +static bool appNoGrab = false; // Grabbing enabled +#endif +static bool app_do_modal = false; // modal mode +Q_GLOBAL_STATIC(QS60Data, qt_s60Data); + +extern bool qt_sendSpontaneousEvent(QObject*,QEvent*); +extern QWidgetList *qt_modal_stack; // stack of modal widgets +extern QDesktopWidget *qt_desktopWidget; // qapplication.cpp + +QWidget *qt_button_down = 0; // widget got last button-down + +QS60Data* qGlobalS60Data() +{ + return qt_s60Data(); +} + +bool qt_nograb() // application no-grab option +{ +#if defined(QT_DEBUG) + return appNoGrab; +#else + return false; +#endif +} + +// Modified from http://www3.symbian.com/faq.nsf/0/0F1464EE96E737E780256D5E00503DD1?OpenDocument +class QS60Beep : public CBase, public MMdaAudioToneObserver +{ +public: + static QS60Beep* NewL(TInt aFrequency, TTimeIntervalMicroSeconds iDuration); + void Play(); + ~QS60Beep(); +private: + void ConstructL(TInt aFrequency, TTimeIntervalMicroSeconds iDuration); + void MatoPrepareComplete(TInt aError); + void MatoPlayComplete(TInt aError); +private: + typedef enum + { + EBeepNotPrepared, + EBeepPrepared, + EBeepPlaying + } TBeepState; +private: + CMdaAudioToneUtility* iToneUtil; + TBeepState iState; + TInt iFrequency; + TTimeIntervalMicroSeconds iDuration; +}; + +QS60Beep::~QS60Beep() +{ + delete iToneUtil; +} + +QS60Beep* QS60Beep::NewL(TInt aFrequency, TTimeIntervalMicroSeconds aDuration) +{ + QS60Beep* self=new (ELeave) QS60Beep(); + CleanupStack::PushL(self); + self->ConstructL(aFrequency, aDuration); + CleanupStack::Pop(); + return self; +}; + +void QS60Beep::ConstructL(TInt aFrequency, TTimeIntervalMicroSeconds aDuration) +{ + iToneUtil=CMdaAudioToneUtility::NewL(*this); + iState=EBeepNotPrepared; + iFrequency=aFrequency; + iDuration=aDuration; + iToneUtil->PrepareToPlayTone(iFrequency,iDuration); +} + +void QS60Beep::Play() +{ + if(iState!=EBeepNotPrepared){ + if(iState==EBeepPlaying) { + iToneUtil->CancelPlay(); + iState=EBeepPrepared; + } + } + + iToneUtil->Play(); + iState=EBeepPlaying; +} + +void QS60Beep::MatoPrepareComplete(TInt aError) +{ + if(aError==KErrNone) { + iState=EBeepPrepared; + } +} + +void QS60Beep::MatoPlayComplete(TInt aError) +{ + Q_UNUSED(aError); + iState=EBeepPrepared; +} + + +QHash<TInt, TUint> QApplicationPrivate::scanCodeCache; + +static Qt::KeyboardModifiers mapToQtModifiers(TUint s60Modifiers) +{ + Qt::KeyboardModifiers result = Qt::NoModifier; + + if (s60Modifiers & EModifierKeypad) + result |= Qt::KeypadModifier; + if (s60Modifiers & EModifierShift || s60Modifiers & EModifierLeftShift + || s60Modifiers & EModifierRightShift) + result |= Qt::ShiftModifier; + if (s60Modifiers & EModifierCtrl || s60Modifiers & EModifierLeftCtrl + || s60Modifiers & EModifierRightCtrl) + result |= Qt::ControlModifier; + if (s60Modifiers & EModifierAlt || s60Modifiers & EModifierLeftAlt + || s60Modifiers & EModifierRightAlt) + result |= Qt::AltModifier; + + return result; +} + +static void mapS60MouseEventTypeToQt(QEvent::Type *type, Qt::MouseButton *button, const TPointerEvent *pEvent) +{ + switch (pEvent->iType) { + case TPointerEvent::EButton1Down: + *type = QEvent::MouseButtonPress; + *button = Qt::LeftButton; + break; + case TPointerEvent::EButton1Up: + *type = QEvent::MouseButtonRelease; + *button = Qt::LeftButton; + break; + case TPointerEvent::EButton2Down: + *type = QEvent::MouseButtonPress; + *button = Qt::MidButton; + break; + case TPointerEvent::EButton2Up: + *type = QEvent::MouseButtonRelease; + *button = Qt::MidButton; + break; + case TPointerEvent::EButton3Down: + *type = QEvent::MouseButtonPress; + *button = Qt::RightButton; + break; + case TPointerEvent::EButton3Up: + *type = QEvent::MouseButtonRelease; + *button = Qt::RightButton; + break; + case TPointerEvent::EDrag: + *type = QEvent::MouseMove; + *button = Qt::NoButton; + break; + case TPointerEvent::EMove: + // Qt makes no distinction between move and drag + *type = QEvent::MouseMove; + *button = Qt::NoButton; + break; + default: + *type = QEvent::None; + *button = Qt::NoButton; + break; + } + if (pEvent->iModifiers & EModifierDoubleClick){ + *type = QEvent::MouseButtonDblClick; + } + + if (*type == QEvent::MouseButtonPress || *type == QEvent::MouseButtonDblClick) + QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons | (*button); + else if (*type == QEvent::MouseButtonRelease) + QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons &(~(*button)); + + QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons & Qt::MouseButtonMask; +} + +//### Can be replaced with CAknLongTapDetector if animation is required. +//NOTE: if CAknLongTapDetector is used make sure it gets variated out of 3.1 and 3.2,. +//also MLongTapObserver needs to be changed to MAknLongTapDetectorCallBack if CAknLongTapDetector is used. +class QLongTapTimer : public CTimer +{ +public: + static QLongTapTimer* NewL(QAbstractLongTapObserver *observer); + QLongTapTimer(QAbstractLongTapObserver *observer); + void ConstructL(); +public: + void PointerEventL(const TPointerEvent &event); + void RunL(); +protected: +private: + QAbstractLongTapObserver *m_observer; + TPointerEvent m_event; + QPoint m_pressedCoordinates; + int m_dragDistance; +}; + +QLongTapTimer* QLongTapTimer::NewL(QAbstractLongTapObserver *observer) +{ + QLongTapTimer* self = new QLongTapTimer(observer); + self->ConstructL(); + return self; +} +void QLongTapTimer::ConstructL() +{ + CTimer::ConstructL(); +} + +QLongTapTimer::QLongTapTimer(QAbstractLongTapObserver *observer):CTimer(CActive::EPriorityHigh) +{ + m_observer = observer; + m_dragDistance = qApp->startDragDistance(); + CActiveScheduler::Add(this); +} + +void QLongTapTimer::PointerEventL(const TPointerEvent& event) +{ + if ( event.iType == TPointerEvent::EDrag || event.iType == TPointerEvent::EButtonRepeat) + { + QPoint diff(QPoint(event.iPosition.iX,event.iPosition.iY) - m_pressedCoordinates); + if (diff.manhattanLength() < m_dragDistance) + return; + } + Cancel(); + m_event = event; + if (event.iType == TPointerEvent::EButton1Down) + { + m_pressedCoordinates = QPoint(event.iPosition.iX,event.iPosition.iY); + // must be same as KLongTapDelay in aknlongtapdetector.h + After(800000); + } +} +void QLongTapTimer::RunL() +{ + if (m_observer) + m_observer->HandleLongTapEventL(m_event.iPosition, m_event.iParentPosition); +} + +QSymbianControl::QSymbianControl(QWidget *w) + : CCoeControl(), qwidget(w), m_ignoreFocusChanged(false) +{ +} + +void QSymbianControl::ConstructL(bool topLevel, bool desktop) +{ + if (!desktop) + { + if (topLevel) + CreateWindowL(S60->windowGroup()); + + SetFocusing(true); + m_longTapDetector = QLongTapTimer::NewL(this); + } +} + +QSymbianControl::~QSymbianControl() +{ + S60->appUi()->RemoveFromStack(this); + delete m_longTapDetector; +} + +void QSymbianControl::setWidget(QWidget *w) +{ + qwidget = w; +} +void QSymbianControl::HandleLongTapEventL( const TPoint& aPenEventLocation, const TPoint& aPenEventScreenLocation ) +{ + QWidget *alienWidget; + QPoint widgetPos = QPoint(aPenEventLocation.iX, aPenEventLocation.iY); + QPoint globalPos = QPoint(aPenEventScreenLocation.iX,aPenEventScreenLocation.iY); + alienWidget = qwidget->childAt(widgetPos); + if (!alienWidget) + alienWidget = qwidget; + QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons &(~Qt::LeftButton); + QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons | Qt::RightButton; + QMouseEvent mEvent(QEvent::MouseButtonPress, alienWidget->mapFrom(qwidget, widgetPos), globalPos, + Qt::RightButton, QApplicationPrivate::mouse_buttons, Qt::NoModifier); + + bool res = sendMouseEvent(alienWidget, &mEvent); + +#if !defined(QT_NO_CONTEXTMENU) + QContextMenuEvent e2(QContextMenuEvent::Mouse, widgetPos, globalPos, mEvent.modifiers()); +#endif + + m_previousEventLongTap = true; +} + +void QSymbianControl::HandlePointerEventL(const TPointerEvent& pEvent) +{ + m_longTapDetector->PointerEventL(pEvent); + QT_TRYCATCH_LEAVING(HandlePointerEvent(pEvent)); +} + +void QSymbianControl::HandlePointerEvent(const TPointerEvent& pEvent) +{ + //### refactor me, getting too complex + QMouseEvent::Type type; + Qt::MouseButton button; + mapS60MouseEventTypeToQt(&type, &button, &pEvent); + + if (m_previousEventLongTap) + if (type == QEvent::MouseButtonRelease){ + button = Qt::RightButton; + QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons & ~Qt::RightButton; + m_previousEventLongTap = false; + } + if (type == QMouseEvent::None) + return; + + // store events for later sending/saving + QWidget *alienWidget; + typedef QPair<QWidget*,QMouseEvent> Event; + QList<Event > events; + + QPoint widgetPos = QPoint(pEvent.iPosition.iX, pEvent.iPosition.iY); + TPoint controlScreenPos = PositionRelativeToScreen(); + QPoint globalPos = QPoint(controlScreenPos.iX, controlScreenPos.iY) + widgetPos; + + if (type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick) + { + // get the button press target + alienWidget = qwidget->childAt(widgetPos); + if (!alienWidget) + alienWidget = qwidget; + S60->mousePressTarget = alienWidget; + //pointer grab + SetGloballyCapturing(ETrue); + SetPointerCapture(ETrue); + } + else if (type == QEvent::MouseButtonRelease) + { + //release pointer grab + SetGloballyCapturing(EFalse); + SetPointerCapture(EFalse); + } + alienWidget = S60->mousePressTarget; + + if (alienWidget != S60->lastPointerEventTarget) + if (type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick || type == QEvent::MouseMove) + { + //moved to another widget, create enter and leave events + if (S60->lastPointerEventTarget) + { + QMouseEvent mEventLeave(QEvent::Leave, S60->lastPointerEventTarget->mapFromGlobal(S60->lastCursorPos), S60->lastCursorPos, + 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)); + } + S60->lastCursorPos = globalPos; + S60->lastPointerEventPos = widgetPos; + S60->lastPointerEventTarget = alienWidget; + if (alienWidget) + { + QMouseEvent mEvent(type, alienWidget->mapFromGlobal(globalPos), globalPos, + button, QApplicationPrivate::mouse_buttons, mapToQtModifiers(pEvent.iModifiers)); + events.append(Event(alienWidget,mEvent)); + QEventDispatcherS60 *dispatcher; + // It is theoretically possible for someone to install a different event dispatcher. + if ((dispatcher = qobject_cast<QEventDispatcherS60 *>(alienWidget->d_func()->threadData->eventDispatcher)) != 0) { + if (dispatcher->excludeUserInputEvents()) { + for (int i=0;i < events.count();++i) + { + Event next = events[i]; + dispatcher->saveInputEvent(this, next.first, new QMouseEvent(next.second)); + } + return; + } + } + } + for (int i=0;i < events.count();++i) + { + Event next = events[i]; + sendMouseEvent(next.first, &(next.second)); + } +} + +bool QSymbianControl::sendMouseEvent(QWidget *widget, QMouseEvent *mEvent) +{ + return qt_sendSpontaneousEvent(widget, mEvent); +} + +TKeyResponse QSymbianControl::OfferKeyEventL(const TKeyEvent& keyEvent, TEventCode type) +{ + TKeyResponse r = EKeyWasNotConsumed; + QT_TRYCATCH_LEAVING(r = OfferKeyEvent(keyEvent, type)); + return r; +} + +TKeyResponse QSymbianControl::OfferKeyEvent(const TKeyEvent& keyEvent, TEventCode type) +{ + switch (type) { + //case EEventKeyDown: // <-- Intentionally left out. See below. + case EEventKeyUp: + case EEventKey: + { + // S60 has a confusing way of delivering key events. There are three types of + // events: EKeyEvent, EKeyEventDown and EKeyEventUp. When a key is pressed, the + // two first events are generated. When releasing the key, the last one is + // generated. + // Because S60 does not generate keysyms for EKeyEventDown and EKeyEventUp events, + // we need to do some special tricks to map it to the Qt way. First, we completely + // discard EKeyEventDown events, since they are redundant. Second, since + // EKeyEventUp does not give us a keysym, we need to cache the keysyms from + // the EKeyEvent events. This is what resolveS60ScanCode does. + + + // ### hackish way to send Qt application to background when pressing right softkey + /* + if( keyEvent.iScanCode == EStdKeyDevice1 ) { + S60->window_group->SetOrdinalPosition(-1); + qApp->setActiveWindow(0); + return EKeyWasNotConsumed; + } + */ + + TUint s60Keysym = QApplicationPrivate::resolveS60ScanCode(keyEvent.iScanCode, + keyEvent.iCode); + int keyCode; + if (s60Keysym >= 0x20 && s60Keysym < ENonCharacterKeyBase) { + // Normal characters keys. + keyCode = s60Keysym; + } else { + // Special S60 keys. + keyCode = qt_keymapper_private()->mapS60KeyToQt(s60Keysym); + } + Qt::KeyboardModifiers mods = mapToQtModifiers(keyEvent.iModifiers); + QKeyEventEx qKeyEvent(type == EEventKeyUp ? QEvent::KeyRelease : QEvent::KeyPress, keyCode, + mods, qt_keymapper_private()->translateKeyEvent(keyCode, mods), + false, 1, keyEvent.iScanCode, s60Keysym, mods); +// WId wid = reinterpret_cast<RWindowGroup *>(keyEvent.Handle())->Child(); +// if (!wid) +// Could happen if window isn't shown yet. +// return EKeyWasNotConsumed; + QWidget *widget; + widget = QWidget::keyboardGrabber(); + if (!widget) { + if (QApplicationPrivate::popupWidgets != 0) { + widget = QApplication::activePopupWidget()->focusWidget(); + if (!widget) { + widget = QApplication::activePopupWidget(); + } + } else { + widget = QApplicationPrivate::focus_widget; + if (!widget) { + widget = qwidget; + } + } + } + + QEventDispatcherS60 *dispatcher; + // It is theoretically possible for someone to install a different event dispatcher. + if ((dispatcher = qobject_cast<QEventDispatcherS60 *>(widget->d_func()->threadData->eventDispatcher)) != 0) { + if (dispatcher->excludeUserInputEvents()) { + dispatcher->saveInputEvent(this, widget, new QKeyEventEx(qKeyEvent)); + return EKeyWasConsumed; + } + } + return sendKeyEvent(widget, &qKeyEvent); + } + } + return EKeyWasNotConsumed; +} + +void QSymbianControl::sendInputEvent(QWidget *widget, QInputEvent *inputEvent) +{ + switch (inputEvent->type()) { + case QEvent::KeyPress: + case QEvent::KeyRelease: + sendKeyEvent(widget, static_cast<QKeyEvent *>(inputEvent)); + break; + case QEvent::MouseButtonDblClick: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseMove: + sendMouseEvent(widget, static_cast<QMouseEvent *>(inputEvent)); + break; + default: + // Shouldn't get here. + Q_ASSERT_X(0 == 1, "QSymbianControl::sendInputEvent()", "inputEvent->type() is unknown"); + break; + } +} + +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)) + return EKeyWasConsumed; + } +#endif // !defined(QT_NO_IM) && defined(Q_WS_S60) + + if (widget && qt_sendSpontaneousEvent(widget, keyEvent)) + if (keyEvent->isAccepted()) + return EKeyWasConsumed; + + return EKeyWasNotConsumed; +} + +#if !defined(QT_NO_IM) && defined(Q_WS_S60) +TCoeInputCapabilities QSymbianControl::InputCapabilities() const +{ + QWidget *w = 0; + + if(qwidget->hasFocus()) { + w = qwidget; + } else { + w = qwidget->focusWidget(); + } + + QCoeFepInputContext *ic; + if (w && w->isEnabled() && w->testAttribute(Qt::WA_InputMethodEnabled) + && (ic = qobject_cast<QCoeFepInputContext *>(w->inputContext()))) { + return ic->inputCapabilities(); + } else { + return TCoeInputCapabilities(TCoeInputCapabilities::ENone, 0, 0); + } +} +#endif + +void QSymbianControl::Draw(const TRect& r) const +{ + QWindowSurface *surface = qwidget->windowSurface(); + if (!surface) + return; + + QPaintEngine *engine = surface->paintDevice()->paintEngine(); + if (!engine) + return; + if (engine->type() == QPaintEngine::Raster) { + QS60WindowSurface *s60Surface = static_cast<QS60WindowSurface *>(qwidget->windowSurface()); + CFbsBitmap *bitmap = s60Surface->symbianBitmap(); + CWindowGc &gc = SystemGc(); + if (qwidget->d_func()->isOpaque) + gc.SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha); + gc.BitBlt(r.iTl, bitmap, r); + } else { + surface->flush(qwidget, QRegion(qt_TRect2QRect(r)), QPoint()); + } +} + +void QSymbianControl::SizeChanged() +{ + CCoeControl::SizeChanged(); + + QSize oldSize = qwidget->size(); + QSize newSize(Size().iWidth, Size().iHeight); + + if (oldSize != newSize) { + QRect cr = qwidget->geometry(); + cr.setSize(newSize); + qwidget->data->crect = cr; + if (qwidget->isVisible()) { + QTLWExtra *tlwExtra = qwidget->d_func()->maybeTopData(); + bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt(); + if (!slowResize && tlwExtra) + tlwExtra->inTopLevelResize = true; + QResizeEvent e(newSize, oldSize); + qt_sendSpontaneousEvent(qwidget, &e); + if (!qwidget->testAttribute(Qt::WA_StaticContents)) + qwidget->d_func()->syncBackingStore(); + if (!slowResize && tlwExtra) + tlwExtra->inTopLevelResize = false; + } + } +} + +void QSymbianControl::PositionChanged() +{ + CCoeControl::PositionChanged(); + + QPoint oldPos = qwidget->geometry().topLeft(); + QPoint newPos(Position().iX, Position().iY); + + if (oldPos != newPos) { + QRect cr = qwidget->geometry(); + cr.moveTopLeft(newPos); + qwidget->data->crect = cr; + QTLWExtra *top = qwidget->d_func()->maybeTopData(); + if (top) + top->normalGeometry = cr; + if (qwidget->isVisible()) { + QMoveEvent e(newPos, oldPos); + qt_sendSpontaneousEvent(qwidget, &e); + } else { + QMoveEvent * e = new QMoveEvent(newPos, oldPos); + QApplication::postEvent(qwidget, e); + } + } +} + +void QSymbianControl::FocusChanged(TDrawNow /* aDrawNow */) +{ + if (m_ignoreFocusChanged) + return; + + // Popups never get focused, but still receive the FocusChanged when they are hidden. + if (QApplicationPrivate::popupWidgets != 0 + || (qwidget->windowType() & Qt::Popup) == Qt::Popup) + return; + + QEvent *deferredFocusEvent = new QEvent(QEvent::SymbianDeferredFocusChanged); + QApplication::postEvent(qwidget, deferredFocusEvent); +} + +void QSymbianControl::HandleResourceChange(int resourceType) +{ + switch (resourceType) { + case KInternalStatusPaneChange: + qwidget->d_func()->setWindowIcon_sys(true); + break; + case KUidValueCoeFontChangeEvent: + // font change event + break; +#ifdef Q_WS_S60 + case KEikDynamicLayoutVariantSwitch: + { + if (qwidget->isFullScreen()) { + SetExtentToWholeScreen(); + } else if (qwidget->isMaximized()) { + TRect r = static_cast<CEikAppUi*>(S60->appUi())->ClientRect(); + SetExtent(r.iTl, r.Size()); + } + break; + } +#endif + default: + break; + } + + CCoeControl::HandleResourceChange(resourceType); + +} +void QSymbianControl::CancelLongTapTimer() +{ + m_longTapDetector->Cancel(); +} + +TTypeUid::Ptr QSymbianControl::MopSupplyObject(TTypeUid id) +{ + if (id.iUid == ETypeId) + return id.MakePtr(this); + + return CCoeControl::MopSupplyObject(id); +} + +void qt_init(QApplicationPrivate * /* priv */, int) +{ +#ifdef QT_NO_DEBUG + if (!qgetenv("QT_S60_AUTO_FLUSH_WSERV").isEmpty()) +#endif + S60->wsSession().SetAutoFlush(ETrue); + + S60->updateScreenSize(); + + + TDisplayMode mode = S60->screenDevice()->DisplayMode(); + S60->screenDepth = TDisplayModeUtils::NumDisplayModeBitsPerPixel(mode); + + RProcess me; + TSecureId securId = me.SecureId(); + S60->uid = securId.operator TUid(); + +/* + ### Commented out for now as parameter handling not needed in SOS(yet). Code below will break testlib with -o flag + int argc = priv->argc; + char **argv = priv->argv; + + // Get command line params + int j = argc ? 1 : 0; + for (int i=1; i<argc; i++) { + if (argv[i] && *argv[i] != '-') { + argv[j++] = argv[i]; + continue; + } + +#if defined(QT_DEBUG) + if (qstrcmp(argv[i], "-nograb") == 0) + appNoGrab = !appNoGrab; + else +#endif // QT_DEBUG + ; + } +*/ +} + +/***************************************************************************** + qt_cleanup() - cleans up when the application is finished + *****************************************************************************/ +void qt_cleanup() +{ + QFontCache::cleanup(); // Has to happen now, since QFontEngineS60 has FBS handles +// S60 structure and window server session are freed in eventdispatcher destructor as they are needed there + + // It's important that this happens here, before the event dispatcher gets + // deleted, because the input context needs the event loop one last time before + // it dies. + delete QApplicationPrivate::inputContext; + QApplicationPrivate::inputContext = 0; +} + +void QApplicationPrivate::initializeWidgetPaletteHash() +{ + // TODO: Implement QApplicationPrivate::initializeWidgetPaletteHash() + // Possibly a task fot the S60Style guys +} + +void QApplicationPrivate::createEventDispatcher() +{ + Q_Q(QApplication); + eventDispatcher = new QEventDispatcherS60(q); +} + +QString QApplicationPrivate::appName() const +{ + return QCoreApplicationPrivate::appName(); +} + +bool QApplicationPrivate::modalState() +{ + return app_do_modal; +} + +void QApplicationPrivate::enterModal_sys(QWidget *widget) +{ + if (!qt_modal_stack) + qt_modal_stack = new QWidgetList; + qt_modal_stack->insert(0, widget); + app_do_modal = true; +} + +void QApplicationPrivate::leaveModal_sys(QWidget *widget) +{ + if (qt_modal_stack && qt_modal_stack->removeAll(widget)) { + if (qt_modal_stack->isEmpty()) { + delete qt_modal_stack; + qt_modal_stack = 0; + } + } + app_do_modal = qt_modal_stack != 0; +} + +void QApplicationPrivate::openPopup(QWidget *popup) +{ + if (!QApplicationPrivate::popupWidgets) + QApplicationPrivate::popupWidgets = new QWidgetList; + QApplicationPrivate::popupWidgets->append(popup); + + if (QApplicationPrivate::popupWidgets->count() == 1 && !qt_nograb()) { + Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created)); + WId id = popup->effectiveWinId(); + id->SetPointerCapture(true); + id->SetGloballyCapturing(true); + } + + // popups are not focus-handled by the window system (the first + // popup grabbed the keyboard), so we have to do that manually: A + // new popup gets the focus + if (QApplication::focusWidget()) + static_cast<QSymbianControl*>(QApplication::focusWidget()->effectiveWinId())->CancelLongTapTimer(); + QWidget *fw = popup->focusWidget(); + if (fw) { + fw->setFocus(Qt::PopupFocusReason); + } else if (QApplicationPrivate::popupWidgets->count() == 1) { // this was the first popup + fw = QApplication::focusWidget(); + if (fw) { + QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason); + q_func()->sendEvent(fw, &e); + } + } +} + +void QApplicationPrivate::closePopup(QWidget *popup) +{ + if (!QApplicationPrivate::popupWidgets) + return; + QApplicationPrivate::popupWidgets->removeAll(popup); + + if (QApplicationPrivate::popupWidgets->isEmpty()) { // this was the last popup + delete QApplicationPrivate::popupWidgets; + QApplicationPrivate::popupWidgets = 0; + if (!qt_nograb()) { // grabbing not disabled + Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created)); + WId id = popup->effectiveWinId(); + id->SetPointerCapture(false); + id->SetGloballyCapturing(false); + if (QWidgetPrivate::mouseGrabber != 0) + QWidgetPrivate::mouseGrabber->grabMouse(); + + if (QWidgetPrivate::keyboardGrabber != 0) + QWidgetPrivate::keyboardGrabber->grabKeyboard(); + + QWidget *fw = QApplicationPrivate::active_window ? QApplicationPrivate::active_window->focusWidget() + : q_func()->focusWidget(); + if (fw) { + if (fw != q_func()->focusWidget()) { + fw->setFocus(Qt::PopupFocusReason); + } else { + QFocusEvent e(QEvent::FocusIn, Qt::PopupFocusReason); + q_func()->sendEvent(fw, &e); + } + } + } + } else { + // popups are not focus-handled by the window system (the + // first popup grabbed the keyboard), so we have to do that + // manually: A popup was closed, so the previous popup gets + // the focus. + QWidget* aw = QApplicationPrivate::popupWidgets->last(); + if (QWidget *fw = QApplication::focusWidget()) { + QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason); + q_func()->sendEvent(fw, &e); + } + } +} + +QWidget * QApplication::topLevelAt(QPoint const& point) +{ + QWidget *found = 0; + int lowestZ = INT_MAX; + QWidgetList list = QApplication::topLevelWidgets(); + for (int i = 0; i < list.count(); ++i) { + QWidget *widget = list.at(i); + if (widget->isVisible() && !(widget->windowType() == Qt::Desktop)) { + Q_ASSERT(widget->testAttribute(Qt::WA_WState_Created)); + if (widget->geometry().adjusted(0,0,1,1).contains(point)) { + // At this point we know there is a Qt widget under the point. + // Now we need to make sure it is the top most in the z-order. + RDrawableWindow* rw = widget->d_func()->topData()->rwindow; + int z = rw->OrdinalPosition(); + if (z < lowestZ) { + lowestZ = z; + found = widget; + } + } + } + } + return found; +} + +void QApplication::alert(QWidget * /* widget */, int /* duration */) +{ + // TODO: Implement QApplication::alert(QWidget *widget, int duration) +} + +int QApplication::doubleClickInterval() +{ + TTimeIntervalMicroSeconds32 us; + TInt distance; + S60->wsSession().GetDoubleClickSettings(us, distance); + return (us.Int() / 1000); +} + +void QApplication::setDoubleClickInterval(int ms) +{ + TTimeIntervalMicroSeconds32 newUs( ms * 1000); + TTimeIntervalMicroSeconds32 us; + TInt distance; + S60->wsSession().GetDoubleClickSettings(us, distance); + if (us != newUs) + S60->wsSession().SetDoubleClick(newUs, distance); +} + +int QApplication::keyboardInputInterval() +{ + return QApplicationPrivate::keyboard_input_time; +} + +void QApplication::setKeyboardInputInterval(int ms) +{ + QApplicationPrivate::keyboard_input_time = ms; +} + +int QApplication::cursorFlashTime() +{ + return QApplicationPrivate::cursor_flash_time; +} + +void QApplication::setCursorFlashTime(int msecs) +{ + QApplicationPrivate::cursor_flash_time = msecs; +} + +void QApplication::beep() +{ + TInt frequency=440; + TTimeIntervalMicroSeconds duration(500000); + QS60Beep* beep=NULL; + TRAPD(err, beep=QS60Beep::NewL(frequency, duration)); + if(!err) { + beep->Play(); + } + delete beep; + beep=NULL; +} + +int QApplication::s60ProcessEvent(TWsEvent *event) +{ + bool handled = s60EventFilter(event); + if (handled) + return 1; + + // Qt event handling. Handle some events regardless of if the handle is in our + // widget map or not. + CCoeControl* control = reinterpret_cast<CCoeControl*>(event->Handle()); + const bool controlInMap = QWidgetPrivate::mapper && QWidgetPrivate::mapper->contains(control); + switch (event->Type()) { +#if !defined(QT_NO_IM) && defined(Q_WS_S60) + case EEventKey: + case EEventKeyUp: + case EEventKeyDown: + { + // The control doesn't seem to be any of our widgets, so rely on the focused + // widget instead. If the user needs the control, it can be found inside the + // event structure. + QWidget *w = qApp ? qApp->focusWidget() : 0; + if (w) { + QInputContext *ic = w->inputContext(); + if (ic && ic->s60FilterEvent(w, event)) { + return 1; + } else { + return 0; + } + } + break; + } +#endif + case EEventPointerEnter: + if (controlInMap) + return 1; // Qt::Enter will be generated in HandlePointerL + break; + case EEventPointerExit: + if (controlInMap) { + if (S60) { + // mouseEvent outside our window, send leave event to last focused widget + QMouseEvent mEvent(QEvent::Leave, S60->lastPointerEventPos, S60->lastCursorPos, + Qt::NoButton, QApplicationPrivate::mouse_buttons, Qt::NoModifier); + if (S60->lastPointerEventTarget) + qt_sendSpontaneousEvent(S60->lastPointerEventTarget,&mEvent); + S60->lastPointerEventTarget = 0; + } + return 1; + } + break; + case EEventScreenDeviceChanged: + if (S60) + S60->updateScreenSize(); + if (qt_desktopWidget) { + QSize oldSize = qt_desktopWidget->size(); + qt_desktopWidget->data->crect.setWidth(S60->screenWidthInPixels); + qt_desktopWidget->data->crect.setHeight(S60->screenHeightInPixels); + QResizeEvent e(qt_desktopWidget->size(), oldSize); + QApplication::sendEvent(qt_desktopWidget, &e); + } + return 0; // Propagate to CONE + case EEventWindowVisibilityChanged: + if (controlInMap) { + const TWsVisibilityChangedEvent *visChangedEvent = event->VisibilityChanged(); + QWidget *w = QWidgetPrivate::mapper->value(control); + if (!w->d_func()->maybeTopData()) + break; + if (visChangedEvent->iFlags & TWsVisibilityChangedEvent::ENotVisible) { + delete w->d_func()->topData()->backingStore; + w->d_func()->topData()->backingStore = 0; + } else if ((visChangedEvent->iFlags & TWsVisibilityChangedEvent::EPartiallyVisible) + && !w->d_func()->maybeBackingStore()) { + w->d_func()->topData()->backingStore = new QWidgetBackingStore(w); + w->update(); + } + return 1; + } + break; + default: + break; + } + + if (!controlInMap) + return -1; + + return 0; +} + +bool QApplication::s60EventFilter(TWsEvent * /* aEvent */) +{ + return false; +} + +/*! + Handles commands which are typically handled by CAknAppUi::HandleCommandL() + Qts Ui integration into Symbian is partially achieved by deriving from CAknAppUi. + Currently, exit, menu and softkey commands are handled + + \sa s60EventFilter(), s60ProcessEvent() +*/ +void QApplication::symbianHandleCommand(int command) +{ + switch (command) { + case EEikCmdExit: +#ifdef Q_WS_S60 + case EAknSoftkeyExit: +#endif + exit(); + break; + default: + if (command >= SOFTKEYSTART && command <= SOFTKEYEND) { + int index= command-SOFTKEYSTART; + QWidget *focused = QApplication::focusWidget(); + QWidget *softKeySource = focused ? focused : QApplication::activeWindow(); + const QList<QAction*>& softKeys = softKeySource->softKeys(); + Q_ASSERT(index < softKeys.count()); + softKeys.at(index)->activate(QAction::Trigger); + } +#ifdef Q_WS_S60 + else + QMenuBarPrivate::symbianCommands(command); +#endif + break; + } +} + +void QApplication::symbianResourceChange(int type) +{ + switch (type) { +#ifdef Q_WS_S60 + case KEikDynamicLayoutVariantSwitch: + { + if (S60) + S60->updateScreenSize(); + +#ifndef QT_NO_STYLE_S60 + QS60Style *s60Style = 0; + +#ifndef QT_NO_STYLE_STYLESHEET + QStyleSheetStyle *proxy = qobject_cast<QStyleSheetStyle*>(QApplication::style()); + if (proxy) + s60Style = qobject_cast<QS60Style*>(proxy->baseStyle()); + else +#endif + s60Style = qobject_cast<QS60Style*>(QApplication::style()); + + if (s60Style) + s60Style->d_func()->handleDynamicLayoutVariantSwitch(); +#endif + } + break; + +#ifndef QT_NO_STYLE_S60 + case KAknsMessageSkinChange: + if (QS60Style *s60Style = qobject_cast<QS60Style*>(QApplication::style())) + s60Style->d_func()->handleSkinChange(); + break; +#endif +#endif // Q_WS_S60 + default: + break; + } +} + +#ifndef QT_NO_WHEELEVENT +int QApplication::wheelScrollLines() +{ + return QApplicationPrivate::wheel_scroll_lines; +} + +void QApplication::setWheelScrollLines(int n) +{ + QApplicationPrivate::wheel_scroll_lines = n; +} +#endif //QT_NO_WHEELEVENT + +bool QApplication::isEffectEnabled(Qt::UIEffect /* effect */) +{ + // TODO: Implement QApplication::isEffectEnabled(Qt::UIEffect effect) + return false; +} + +void QApplication::setEffectEnabled(Qt::UIEffect /* effect */, bool /* enable */) +{ + // TODO: Implement QApplication::setEffectEnabled(Qt::UIEffect effect, bool enable) +} + +TUint QApplicationPrivate::resolveS60ScanCode(TInt scanCode, TUint keysym) +{ + if (keysym) { + // If keysym is specified, cache it. + scanCodeCache.insert(scanCode, keysym); + return keysym; + } else { + // If not, retrieve the cached version. + return scanCodeCache[scanCode]; + } +} + + +void QApplicationPrivate::initializeMultitouch_sys() +{ } +void QApplicationPrivate::cleanupMultitouch_sys() +{ } + +#ifndef QT_NO_SESSIONMANAGER +QSessionManager::QSessionManager(QApplication * /* app */, QString & /* id */, QString& /* key */) +{ + +} + +QSessionManager::~QSessionManager() +{ + +} + +bool QSessionManager::allowsInteraction() +{ + return false; +} + +void QSessionManager::cancel() +{ + +} +#endif //QT_NO_SESSIONMANAGER +QT_END_NAMESPACE diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index 7d9e6ea..76a3b1e 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -323,6 +323,7 @@ extern HRGN qt_tryCreateRegion(QRegion::RegionType type, int left, int top, int #define APPCOMMAND_BASS_UP 21 #define APPCOMMAND_TREBLE_DOWN 22 #define APPCOMMAND_TREBLE_UP 23 +#endif // FAPPCOMMAND_MOUSE // New commands from Windows XP (some even Sp1) #ifndef APPCOMMAND_MICROPHONE_VOLUME_MUTE @@ -357,8 +358,6 @@ extern HRGN qt_tryCreateRegion(QRegion::RegionType type, int left, int top, int #define APPCOMMAND_MEDIA_CHANNEL_DOWN 52 #endif // APPCOMMAND_MICROPHONE_VOLUME_MUTE -#endif // FAPPCOMMAND_MOUSE - #if (_WIN32_WINNT < 0x0400) // This struct is defined in winuser.h if the _WIN32_WINNT >= 0x0400 -- in the // other cases we have to define it on our own. @@ -452,7 +451,7 @@ public: bool translateConfigEvent(const MSG &msg); bool translateCloseEvent(const MSG &msg); bool translateTabletEvent(const MSG &msg, PACKET *localPacketBuf, int numPackets); - bool translateGestureEvent(const MSG &msg); + bool translateGestureEvent(const MSG &msg, const GESTUREINFO &gi); void repolishStyle(QStyle &style); inline void showChildren(bool spontaneous) { d_func()->showChildren(spontaneous); } inline void hideChildren(bool spontaneous) { d_func()->hideChildren(spontaneous); } @@ -848,6 +847,7 @@ void qt_init(QApplicationPrivate *priv, int) (PtrEndPanningFeedback)QLibrary::resolve(QLatin1String("uxtheme"), "EndPanningFeedback"); #endif + priv->gestureWidget = 0; } /***************************************************************************** @@ -2513,10 +2513,38 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam } result = false; break; - case WM_GESTURE: - widget->translateGestureEvent(msg); + case WM_GESTURE: { + GESTUREINFO gi; + memset(&gi, 0, sizeof(GESTUREINFO)); + gi.cbSize = sizeof(GESTUREINFO); + + QApplicationPrivate *qAppPriv = QApplicationPrivate::instance(); + BOOL bResult = false; + if (qAppPriv->GetGestureInfo) + bResult = qAppPriv->GetGestureInfo((HANDLE)msg.lParam, &gi); + if (bResult) { + if (gi.dwID == GID_BEGIN) { + // find the alien widget for the gesture position. + // This might not be accurate as the position is the center + // point of two fingers for multi-finger gestures. + QPoint pt(gi.ptsLocation.x, gi.ptsLocation.y); + QWidget *w = widget->childAt(widget->mapFromGlobal(pt)); + qAppPriv->gestureWidget = w ? w : widget; + } + if (qAppPriv->gestureWidget) + static_cast<QETWidget*>(qAppPriv->gestureWidget)->translateGestureEvent(msg, gi); + if (qAppPriv->CloseGestureInfoHandle) + qAppPriv->CloseGestureInfoHandle((HANDLE)msg.lParam); + if (gi.dwID == GID_END) + qAppPriv->gestureWidget = 0; + } else { + DWORD dwErr = GetLastError(); + if (dwErr > 0) + qWarning() << "translateGestureEvent: error = " << dwErr; + } result = true; break; + } default: result = false; // event was not processed break; @@ -3725,69 +3753,42 @@ bool QETWidget::translateCloseEvent(const MSG &) return d_func()->close_helper(QWidgetPrivate::CloseWithSpontaneousEvent); } -bool QETWidget::translateGestureEvent(const MSG &msg) +bool QETWidget::translateGestureEvent(const MSG &, const GESTUREINFO &gi) { - GESTUREINFO gi; - memset(&gi, 0, sizeof(GESTUREINFO)); - gi.cbSize = sizeof(GESTUREINFO); + const QPoint widgetPos = QPoint(gi.ptsLocation.x, gi.ptsLocation.y); + QWidget *alienWidget = !internalWinId() ? this : childAt(widgetPos); + if (alienWidget && alienWidget->internalWinId()) + alienWidget = 0; + QWidget *widget = alienWidget ? alienWidget : this; - QApplicationPrivate *qAppPriv = QApplicationPrivate::instance(); -#if defined(Q_WS_WINCE_WM) && defined(QT_WINCE_GESTURES) -#undef GID_ZOOM -#define GID_ZOOM 0xf000 -#undef GID_ROTATE -#define GID_ROTATE 0xf001 -#undef GID_TWOFINGERTAP -#define GID_TWOFINGERTAP 0xf002 -#undef GID_ROLLOVER -#define GID_ROLLOVER 0xf003 -#endif - BOOL bResult = false; - if (qAppPriv->GetGestureInfo) - bResult = qAppPriv->GetGestureInfo((HANDLE)msg.lParam, &gi); - - if (bResult) { - const QPoint widgetPos = QPoint(gi.ptsLocation.x, gi.ptsLocation.y); - QWidget *alienWidget = !internalWinId() ? this : childAt(widgetPos); - if (alienWidget && alienWidget->internalWinId()) - alienWidget = 0; - QWidget *widget = alienWidget ? alienWidget : this; - - QNativeGestureEvent event; - event.sequenceId = gi.dwSequenceID; - event.position = QPoint(gi.ptsLocation.x, gi.ptsLocation.y); - event.argument = gi.ullArguments; - - switch (gi.dwID) { - case GID_BEGIN: - event.gestureType = QNativeGestureEvent::GestureBegin; - break; - case GID_END: - event.gestureType = QNativeGestureEvent::GestureEnd; - break; - case GID_ZOOM: - event.gestureType = QNativeGestureEvent::Zoom; - break; - case GID_PAN: - event.gestureType = QNativeGestureEvent::Pan; - break; - case GID_ROTATE: - event.gestureType = QNativeGestureEvent::Rotate; - break; - case GID_TWOFINGERTAP: - case GID_ROLLOVER: - default: - break; - } - if (qAppPriv->CloseGestureInfoHandle) - qAppPriv->CloseGestureInfoHandle((HANDLE)msg.lParam); - if (event.gestureType != QNativeGestureEvent::None) - qt_sendSpontaneousEvent(widget, &event); - } else { - DWORD dwErr = GetLastError(); - if (dwErr > 0) - qWarning() << "translateGestureEvent: error = " << dwErr; + QNativeGestureEvent event; + event.sequenceId = gi.dwSequenceID; + event.position = QPoint(gi.ptsLocation.x, gi.ptsLocation.y); + event.argument = gi.ullArguments; + + switch (gi.dwID) { + case GID_BEGIN: + event.gestureType = QNativeGestureEvent::GestureBegin; + break; + case GID_END: + event.gestureType = QNativeGestureEvent::GestureEnd; + break; + case GID_ZOOM: + event.gestureType = QNativeGestureEvent::Zoom; + break; + case GID_PAN: + event.gestureType = QNativeGestureEvent::Pan; + break; + case GID_ROTATE: + event.gestureType = QNativeGestureEvent::Rotate; + break; + case GID_TWOFINGERTAP: + case GID_ROLLOVER: + default: + break; } + if (event.gestureType != QNativeGestureEvent::None) + qt_sendSpontaneousEvent(widget, &event); return true; } diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp index 0d07a02..170224d 100644 --- a/src/gui/kernel/qapplication_x11.cpp +++ b/src/gui/kernel/qapplication_x11.cpp @@ -1915,9 +1915,12 @@ void qt_init(QApplicationPrivate *priv, int, bool local = displayName.isEmpty() || displayName.lastIndexOf(QLatin1Char(':')) == 0; if (local && (qgetenv("QT_X11_NO_MITSHM").toInt() == 0)) { Visual *defaultVisual = DefaultVisual(X11->display, DefaultScreen(X11->display)); - X11->use_mitshm = mitshm_pixmaps && (defaultVisual->red_mask == 0xff0000 - && defaultVisual->green_mask == 0xff00 - && defaultVisual->blue_mask == 0xff); + X11->use_mitshm = mitshm_pixmaps && ((defaultVisual->red_mask == 0xff0000 + || defaultVisual->red_mask == 0xf800) + && (defaultVisual->green_mask == 0xff00 + || defaultVisual->green_mask == 0x7e0) + && (defaultVisual->blue_mask == 0xff + || defaultVisual->blue_mask == 0x1f)); } } #endif // QT_NO_MITSHM @@ -5401,7 +5404,8 @@ class QSessionManagerPrivate : public QObjectPrivate { public: QSessionManagerPrivate(QSessionManager* mgr, QString& id, QString& key) - : QObjectPrivate(), sm(mgr), sessionId(id), sessionKey(key), eventLoop(0) {} + : QObjectPrivate(), sm(mgr), sessionId(id), sessionKey(key), + restartHint(QSessionManager::RestartIfRunning), eventLoop(0) {} QSessionManager* sm; QStringList restartCommand; QStringList discardCommand; diff --git a/src/gui/kernel/qboxlayout.cpp b/src/gui/kernel/qboxlayout.cpp index ce86c36..3f2a5dc 100644 --- a/src/gui/kernel/qboxlayout.cpp +++ b/src/gui/kernel/qboxlayout.cpp @@ -924,9 +924,15 @@ void QBoxLayout::insertSpacing(int index, int size) else b = QLayoutPrivate::createSpacerItem(this, 0, size, QSizePolicy::Minimum, QSizePolicy::Fixed); - QBoxLayoutItem *it = new QBoxLayoutItem(b); - it->magic = true; - d->list.insert(index, it); + QT_TRY { + QBoxLayoutItem *it = new QBoxLayoutItem(b); + it->magic = true; + d->list.insert(index, it); + + } QT_CATCH(...) { + delete b; + QT_RETHROW; + } invalidate(); } @@ -1026,8 +1032,21 @@ void QBoxLayout::insertWidget(int index, QWidget *widget, int stretch, index = d->list.count(); QWidgetItem *b = QLayoutPrivate::createWidgetItem(this, widget); b->setAlignment(alignment); - QBoxLayoutItem *it = new QBoxLayoutItem(b, stretch); - d->list.insert(index, it); + + QBoxLayoutItem *it; + QT_TRY{ + it = new QBoxLayoutItem(b, stretch); + } QT_CATCH(...) { + delete b; + QT_RETHROW; + } + + QT_TRY{ + d->list.insert(index, it); + } QT_CATCH(...) { + delete it; + QT_RETHROW; + } invalidate(); } diff --git a/src/gui/kernel/qclipboard_s60.cpp b/src/gui/kernel/qclipboard_s60.cpp new file mode 100644 index 0000000..9a2629c --- /dev/null +++ b/src/gui/kernel/qclipboard_s60.cpp @@ -0,0 +1,266 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qclipboard.h" + +#ifndef QT_NO_CLIPBOARD + +#include "qapplication.h" +#include "qbitmap.h" +#include "qdatetime.h" +#include "qbuffer.h" +#include "qwidget.h" +#include "qevent.h" +#include "private/qcore_symbian_p.h" +#include <QtDebug> + +// Symbian's clipboard +#include <baclipb.h> +QT_BEGIN_NAMESPACE + +//### Mime Type mapping to UIDs + +const TUid KQtCbDataStream = {0x2001B2DD}; + + +class QClipboardData +{ +public: + QClipboardData(); + ~QClipboardData(); + + void setSource(QMimeData* s) + { + if (s == src) + return; + delete src; + src = s; + } + QMimeData* source() + { return src; } + bool connected() + { return connection; } + void clear(); + +private: + QMimeData* src; + bool connection; +}; + +QClipboardData::QClipboardData():src(0),connection(true) +{ + clear(); +} + +QClipboardData::~QClipboardData() +{ + connection = false; + delete src; +} + +void QClipboardData::clear() +{ + QMimeData* newSrc = new QMimeData; + delete src; + src = newSrc; +} + +static QClipboardData *internalCbData = 0; + +static void cleanupClipboardData() +{ + delete internalCbData; + internalCbData = 0; +} + +static QClipboardData *clipboardData() +{ + if (internalCbData == 0) { + internalCbData = new QClipboardData; + if (internalCbData) + { + if (!internalCbData->connected()) + { + delete internalCbData; + internalCbData = 0; + } + else + { + qAddPostRoutine(cleanupClipboardData); + } + } + } + return internalCbData; +} + +void writeToStreamLX(const QMimeData* aData, RWriteStream& aStream) +{ + // This function both leaves and throws exceptions. There must be no destructor + // dependencies between cleanup styles, and no cleanup stack dependencies on stacked objects. + QStringList headers = aData->formats(); + aStream << TCardinality(headers.count()); + for (QStringList::const_iterator iter= headers.constBegin();iter != headers.constEnd();iter++) + { + HBufC* stringData = TPtrC(reinterpret_cast<const TUint16*>((*iter).utf16())).AllocLC(); + QByteArray ba = aData->data((*iter)); + qDebug() << "copy to clipboard mime: " << *iter << " data: " << ba; + // mime type + aStream << TCardinality(stringData->Size()); + aStream << *(stringData); + // mime data + aStream << TCardinality(ba.size()); + aStream.WriteL(reinterpret_cast<const uchar*>(ba.constData()),ba.size()); + CleanupStack::PopAndDestroy(stringData); + } +} + +void readFromStreamLX(QMimeData* aData,RReadStream& aStream) +{ + // This function both leaves and throws exceptions. There must be no destructor + // dependencies between cleanup styles, and no cleanup stack dependencies on stacked objects. + TCardinality mimeTypeCount; + aStream >> mimeTypeCount; + for (int i = 0; i< mimeTypeCount;i++) + { + // mime type + TCardinality mimeTypeSize; + aStream >> mimeTypeSize; + HBufC* mimeTypeBuf = HBufC::NewLC(aStream,mimeTypeSize); + QString mimeType = QString::fromUtf16(mimeTypeBuf->Des().Ptr(),mimeTypeBuf->Length()); + CleanupStack::PopAndDestroy(mimeTypeBuf); + // mime data + TCardinality dataSize; + aStream >> dataSize; + QByteArray ba; + ba.reserve(dataSize); + aStream.ReadL(reinterpret_cast<uchar*>(ba.data_ptr()->data),dataSize); + ba.data_ptr()->size = dataSize; + qDebug() << "paste from clipboard mime: " << mimeType << " data: " << ba; + aData->setData(mimeType,ba); + } +} + + +/***************************************************************************** + QClipboard member functions + *****************************************************************************/ + +void QClipboard::clear(Mode mode) +{ + setText(QString(), mode); +} +const QMimeData* QClipboard::mimeData(Mode mode) const +{ + if (mode != Clipboard) return 0; + QClipboardData *d = clipboardData(); + if (d) + { + TRAPD(err,{ + RFs fs = qt_s60GetRFs(); + CClipboard* cb = CClipboard::NewForReadingLC(fs); + Q_ASSERT(cb); + RStoreReadStream stream; + TStreamId stid = (cb->StreamDictionary()).At(KQtCbDataStream); + stream.OpenLC(cb->Store(),stid); + QT_TRYCATCH_LEAVING(readFromStreamLX(d->source(),stream)); + CleanupStack::PopAndDestroy(2,cb); + return d->source(); + }); + if (err != KErrNone){ + qDebug()<< "clipboard is empty/err: " << err; + } + + } + return 0; +} + + +void QClipboard::setMimeData(QMimeData* src, Mode mode) +{ + if (mode != Clipboard) return; + QClipboardData *d = clipboardData(); + if (d) + { + TRAPD(err,{ + RFs fs = qt_s60GetRFs(); + CClipboard* cb = CClipboard::NewForWritingLC(fs); + RStoreWriteStream stream; + TStreamId stid = stream.CreateLC(cb->Store()); + QT_TRYCATCH_LEAVING(writeToStreamLX(src,stream)); + d->setSource(src); + stream.CommitL(); + (cb->StreamDictionary()).AssignL(KQtCbDataStream,stid); + cb->CommitL(); + CleanupStack::PopAndDestroy(2,cb); + }); + if (err != KErrNone){ + qDebug()<< "clipboard write err :" << err; + } + } + emitChanged(QClipboard::Clipboard); +} + +bool QClipboard::supportsMode(Mode mode) const +{ + return (mode == Clipboard); +} + +bool QClipboard::ownsMode(Mode mode) const +{ + if (mode == Clipboard) + qWarning("QClipboard::ownsClipboard: UNIMPLEMENTED!"); + return false; +} + +bool QClipboard::event(QEvent * /* e */) +{ + return true; +} + +void QClipboard::connectNotify( const char * ) +{ +} + +void QClipboard::ownerDestroyed() +{ +} +QT_END_NAMESPACE +#endif // QT_NO_CLIPBOARD diff --git a/src/gui/kernel/qcocoaapplicationdelegate_mac.mm b/src/gui/kernel/qcocoaapplicationdelegate_mac.mm index 572df70..172d07b 100644 --- a/src/gui/kernel/qcocoaapplicationdelegate_mac.mm +++ b/src/gui/kernel/qcocoaapplicationdelegate_mac.mm @@ -197,11 +197,19 @@ static void cleanupCocoaApplicationDelegate() } } - // Prevent Cocoa from terminating the application, since this simply - // exits the program whithout allowing QApplication::exec() to return. - // The call to QApplication::quit() above will instead quit the - // application from the Qt side. - return NSTerminateCancel; + if (qtPrivate->threadData->eventLoops.size() == 0) { + // INVARIANT: No event loop is executing. This probably + // means that Qt is used as a plugin, or as a part of a native + // Cocoa application. In any case it should be fine to + // terminate now: + return NSTerminateNow; + } else { + // Prevent Cocoa from terminating the application, since this simply + // exits the program whithout allowing QApplication::exec() to return. + // The call to QApplication::quit() above will instead quit the + // application from the Qt side. + return NSTerminateCancel; + } } - (void)applicationDidFinishLaunching:(NSNotification *)aNotification diff --git a/src/gui/kernel/qcocoaview_mac.mm b/src/gui/kernel/qcocoaview_mac.mm index 5a0209d..5ab7ed2 100644 --- a/src/gui/kernel/qcocoaview_mac.mm +++ b/src/gui/kernel/qcocoaview_mac.mm @@ -976,6 +976,15 @@ extern "C" { return qwidget->focusPolicy() != Qt::NoFocus; } +- (BOOL)resignFirstResponder +{ + // Seems like the following test only triggers if this + // view is inside a QMacNativeWidget: + if (qwidget == QApplication::focusWidget()) + QApplicationPrivate::setFocusWidget(0, Qt::OtherFocusReason); + return YES; +} + - (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal { Q_UNUSED(isLocal); diff --git a/src/gui/kernel/qcursor.cpp b/src/gui/kernel/qcursor.cpp index 16749b7..dd7a07c 100644 --- a/src/gui/kernel/qcursor.cpp +++ b/src/gui/kernel/qcursor.cpp @@ -561,7 +561,6 @@ QCursor::operator QVariant() const { return QVariant(QVariant::Cursor, this); } - +QT_END_NAMESPACE #endif // QT_NO_CURSOR -QT_END_NAMESPACE diff --git a/src/gui/kernel/qcursor_qws.cpp b/src/gui/kernel/qcursor_qws.cpp index dd39132..72597f0 100644 --- a/src/gui/kernel/qcursor_qws.cpp +++ b/src/gui/kernel/qcursor_qws.cpp @@ -66,7 +66,11 @@ QCursorData::~QCursorData() { delete bm; delete bmm; - QPaintDevice::qwsDisplay()->destroyCursor(id); + QT_TRY { + QPaintDevice::qwsDisplay()->destroyCursor(id); + } QT_CATCH(const std::bad_alloc &) { + // do nothing. + } } diff --git a/src/gui/kernel/qcursor_s60.cpp b/src/gui/kernel/qcursor_s60.cpp new file mode 100644 index 0000000..1f89430 --- /dev/null +++ b/src/gui/kernel/qcursor_s60.cpp @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <private/qcursor_p.h> +#include <qcursor.h> +#include <qt_s60_p.h> + +#ifdef QT_NO_CURSOR +QT_BEGIN_NAMESPACE + +QPoint QCursor::pos() +{ + return S60->lastCursorPos; +} + +void QCursor::setPos(int x, int y) +{ + S60->lastCursorPos = QPoint(x, y); +} + +QT_END_NAMESPACE +#endif // QT_NO_CURSOR diff --git a/src/gui/kernel/qdesktopwidget_s60.cpp b/src/gui/kernel/qdesktopwidget_s60.cpp new file mode 100644 index 0000000..4127302 --- /dev/null +++ b/src/gui/kernel/qdesktopwidget_s60.cpp @@ -0,0 +1,201 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesktopwidget.h" +#include "qapplication_p.h" +#include "qwidget_p.h" +#include "qt_s60_p.h" +#include <w32std.h> + +#include "hal.h" +#include "hal_data.h" + +QT_BEGIN_NAMESPACE + +class QDesktopWidgetPrivate : public QWidgetPrivate +{ + +public: + QDesktopWidgetPrivate(); + ~QDesktopWidgetPrivate(); + + static void init(QDesktopWidget *that); + static void cleanup(); + + static int screenCount; + static int primaryScreen; + + static QVector<QRect> *rects; + static QVector<QRect> *workrects; + + static int refcount; +}; + +int QDesktopWidgetPrivate::screenCount = 1; +int QDesktopWidgetPrivate::primaryScreen = 0; +QVector<QRect> *QDesktopWidgetPrivate::rects = 0; +QVector<QRect> *QDesktopWidgetPrivate::workrects = 0; +int QDesktopWidgetPrivate::refcount = 0; + +QDesktopWidgetPrivate::QDesktopWidgetPrivate() +{ + ++refcount; +} + +QDesktopWidgetPrivate::~QDesktopWidgetPrivate() +{ + if (!--refcount) + cleanup(); +} + +void QDesktopWidgetPrivate::init(QDesktopWidget *that) +{ + int screenCount=0; + + if (HAL::Get(0, HALData::EDisplayNumberOfScreens, screenCount) == KErrNone) + QDesktopWidgetPrivate::screenCount = screenCount; + else + QDesktopWidgetPrivate::screenCount = 0; + + rects = new QVector<QRect>(); + workrects = new QVector<QRect>(); + + rects->resize(QDesktopWidgetPrivate::screenCount); + workrects->resize(QDesktopWidgetPrivate::screenCount); + + // ### TODO: Implement proper multi-display support + rects->resize(1); + rects->replace(0, that->rect()); + workrects->resize(1); + workrects->replace(0, that->rect()); +} + +void QDesktopWidgetPrivate::cleanup() +{ + delete rects; + rects = 0; + delete workrects; + workrects = 0; +} + + +QDesktopWidget::QDesktopWidget() + : QWidget(*new QDesktopWidgetPrivate, 0, Qt::Desktop) +{ + setObjectName(QLatin1String("desktop")); + QDesktopWidgetPrivate::init(this); +} + +QDesktopWidget::~QDesktopWidget() +{ +} + +bool QDesktopWidget::isVirtualDesktop() const +{ + return true; +} + +int QDesktopWidget::primaryScreen() const +{ + return QDesktopWidgetPrivate::primaryScreen; +} + +int QDesktopWidget::numScreens() const +{ + Q_D(const QDesktopWidget); + return QDesktopWidgetPrivate::screenCount; +} + +QWidget *QDesktopWidget::screen(int /* screen */) +{ + return this; +} + +const QRect QDesktopWidget::availableGeometry(int /* screen */) const +{ + TRect clientRect = static_cast<CEikAppUi*>(S60->appUi())->ClientRect(); + return qt_TRect2QRect(clientRect); +} + +const QRect QDesktopWidget::screenGeometry(int /* screen */) const +{ + Q_D(const QDesktopWidget); + return QRect(0, 0, S60->screenWidthInPixels, S60->screenHeightInPixels); + } + +int QDesktopWidget::screenNumber(const QWidget * /* widget */) const +{ + return QDesktopWidgetPrivate::primaryScreen; +} + +int QDesktopWidget::screenNumber(const QPoint & /* point */) const +{ + return QDesktopWidgetPrivate::primaryScreen; +} + +void QDesktopWidget::resizeEvent(QResizeEvent *) +{ + Q_D(QDesktopWidget); + QVector<QRect> oldrects; + oldrects = *d->rects; + QVector<QRect> oldworkrects; + oldworkrects = *d->workrects; + int oldscreencount = d->screenCount; + + QDesktopWidgetPrivate::cleanup(); + QDesktopWidgetPrivate::init(this); + + for (int i = 0; i < qMin(oldscreencount, d->screenCount); ++i) { + QRect oldrect = oldrects[i]; + QRect newrect = d->rects->at(i); + if (oldrect != newrect) + emit resized(i); + } + + for (int j = 0; j < qMin(oldscreencount, d->screenCount); ++j) { + QRect oldrect = oldworkrects[j]; + QRect newrect = d->workrects->at(j); + if (oldrect != newrect) + emit workAreaResized(j); + } +} + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qdesktopwidget_x11.cpp b/src/gui/kernel/qdesktopwidget_x11.cpp index 2a21ef9..d98df6e 100644 --- a/src/gui/kernel/qdesktopwidget_x11.cpp +++ b/src/gui/kernel/qdesktopwidget_x11.cpp @@ -197,7 +197,7 @@ void QDesktopWidgetPrivate::init() if (screens) { // leaks QWidget* pointers on purpose, can't delete them as pointer escapes - screens = (QWidget**) realloc(screens, j * sizeof(QWidget*)); + screens = q_check_ptr((QWidget**) realloc(screens, j * sizeof(QWidget*))); if (j > screenCount) memset(&screens[screenCount], 0, (j-screenCount) * sizeof(QWidget*)); } diff --git a/src/gui/kernel/qdnd_s60.cpp b/src/gui/kernel/qdnd_s60.cpp new file mode 100644 index 0000000..e014940 --- /dev/null +++ b/src/gui/kernel/qdnd_s60.cpp @@ -0,0 +1,395 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qapplication.h" + +#ifndef QT_NO_DRAGANDDROP + +#include "qwidget.h" +#include "qdatetime.h" +#include "qbitmap.h" +#include "qcursor.h" +#include "qevent.h" +#include "qpainter.h" +#include "qdnd_p.h" + +#include <COECNTRL.H> +// pointer cursor +#include <w32std.h> +#include <gdi.h> +QT_BEGIN_NAMESPACE +//### artistic impression of Symbians default DnD cursor ? + +static QPixmap *defaultPm = 0; +static const int default_pm_hotx = -50; +static const int default_pm_hoty = -50; +static const char *const default_pm[] = { +"13 9 3 1", +". c None", +" c #000000", +"X c #FFFFFF", +"X X X X X X X", +" X X X X X X ", +"X ......... X", +" X.........X ", +"X ......... X", +" X.........X ", +"X ......... X", +" X X X X X X ", +"X X X X X X X", +}; +//### actions need to be redefined for S60 +// Shift/Ctrl handling, and final drop status +static Qt::DropAction global_accepted_action = Qt::MoveAction; +static Qt::DropActions possible_actions = Qt::IgnoreAction; + + +// static variables in place of a proper cross-process solution +static QDrag *drag_object; +static bool qt_symbian_dnd_dragging = false; + + +static Qt::KeyboardModifiers oldstate; + +class QShapedPixmapWidget +{ +public: + QShapedPixmapWidget(RWsSession aWsSession,RWindowTreeNode* aNode) + { + sprite = RWsSprite(aWsSession); + cursorSprite.iBitmap = 0; + cursorSprite.iMaskBitmap = 0; + cursorSprite.iInvertMask = EFalse; + cursorSprite.iOffset = TPoint(0,0); + cursorSprite.iInterval = TTimeIntervalMicroSeconds32(0); + cursorSprite.iDrawMode = CGraphicsContext::EDrawModePEN; + sprite.Construct(*aNode,TPoint(0,0), ESpriteNoShadows | ESpriteNoChildClip); + sprite.AppendMember(cursorSprite); + sprite.Activate(); + } + ~QShapedPixmapWidget() + { + sprite.Close(); + cursorSprite.iBitmap = 0; + delete cursorBitmap; + cursorBitmap = 0; //redundant... + } + void disableCursor() + { + cursorSprite.iBitmap = 0; + sprite.UpdateMember(0,cursorSprite); + } + void enableCursor() + { + cursorSprite.iBitmap = cursorBitmap; + sprite.UpdateMember(0,cursorSprite); + } + void setPixmap(QPixmap pm) + { + //### heaplock centralized. + QImage temp = pm.toImage(); + QSize size = pm.size(); + temp.bits(); + CFbsBitmap *curbm = q_check_ptr(new CFbsBitmap()); // CBase derived object needs check on new + curbm->Create(TSize(size.width(),size.height()),EColor16MA); + curbm->LockHeap(ETrue); + memcpy((uchar*)curbm->DataAddress(),temp.bits(),temp.numBytes()); + curbm->UnlockHeap(ETrue); + delete cursorSprite.iBitmap; + cursorSprite.iBitmap = curbm; + cursorBitmap = curbm; + sprite.UpdateMember(0,cursorSprite); + } + CFbsBitmap *cursorBitmap; + RWsPointerCursor pointerCursor; + RWsSprite sprite; + TSpriteMember cursorSprite; + +}; + + +static QShapedPixmapWidget *qt_symbian_dnd_deco = 0; + +void QDragManager::updatePixmap() +{ + if (qt_symbian_dnd_deco) { + QPixmap pm; + QPoint pm_hot(default_pm_hotx,default_pm_hoty); + if (drag_object) { + pm = drag_object->pixmap(); + if (!pm.isNull()) + pm_hot = drag_object->hotSpot(); + } + if (pm.isNull()) { + if (!defaultPm) + defaultPm = new QPixmap(default_pm); + pm = *defaultPm; + } + qt_symbian_dnd_deco->setPixmap(pm); + } +} + +void QDragManager::timerEvent(QTimerEvent *) { } + +void QDragManager::move(const QPoint&) { +} + +void QDragManager::updateCursor() +{ +} + + +bool QDragManager::eventFilter(QObject *o, QEvent *e) +{ + if (beingCancelled) { + return false; + } + if (!o->isWidgetType()) + return false; + + switch(e->type()) { + case QEvent::MouseButtonPress: + { + } + case QEvent::MouseMove: + { + if (!object) { //#### this should not happen + qWarning("QDragManager::eventFilter: No object"); + return true; + } + QDragManager *manager = QDragManager::self(); + QMimeData *dropData = manager->object ? manager->dragPrivate()->data : manager->dropData; + if (manager->object) + possible_actions = manager->dragPrivate()->possible_actions; + else + possible_actions = Qt::IgnoreAction; + + QMouseEvent *me = (QMouseEvent *)e; + + if (me->buttons()) { + Qt::DropAction prevAction = global_accepted_action; + QWidget *cw = QApplication::widgetAt(me->globalPos()); + // map the Coords relative to the window. + if (!cw) + return true; + TPoint windowPos = cw->effectiveWinId()->PositionRelativeToScreen(); + qt_symbian_dnd_deco->sprite.SetPosition(TPoint(me->globalX()- windowPos.iX,me->globalY()- windowPos.iY)); + + while (cw && !cw->acceptDrops() && !cw->isWindow()) + cw = cw->parentWidget(); + + if (object->target() != cw) { + if (object->target()) { + QDragLeaveEvent dle; + QApplication::sendEvent(object->target(), &dle); + willDrop = false; + global_accepted_action = Qt::IgnoreAction; + updateCursor(); + restoreCursor = true; + object->d_func()->target = 0; + } + if (cw && cw->acceptDrops()) { + object->d_func()->target = cw; + QDragEnterEvent dee(cw->mapFromGlobal(me->globalPos()), possible_actions, dropData, + me->buttons(), me->modifiers()); + QApplication::sendEvent(object->target(), &dee); + willDrop = dee.isAccepted() && dee.dropAction() != Qt::IgnoreAction; + global_accepted_action = willDrop ? dee.dropAction() : Qt::IgnoreAction; + updateCursor(); + restoreCursor = true; + } + } else if (cw) { + QDragMoveEvent dme(cw->mapFromGlobal(me->globalPos()), possible_actions, dropData, + me->buttons(), me->modifiers()); + if (global_accepted_action != Qt::IgnoreAction) { + dme.setDropAction(global_accepted_action); + dme.accept(); + } + QApplication::sendEvent(cw, &dme); + willDrop = dme.isAccepted(); + global_accepted_action = willDrop ? dme.dropAction() : Qt::IgnoreAction; + updatePixmap(); + updateCursor(); + } + if (global_accepted_action != prevAction) + emitActionChanged(global_accepted_action); + } + return true; // Eat all mouse events + } + + case QEvent::MouseButtonRelease: + { + qApp->removeEventFilter(this); + if (restoreCursor) { + qt_symbian_dnd_deco->disableCursor(); + willDrop = false; + restoreCursor = false; + } + if (object && object->target()) { + + QMouseEvent *me = (QMouseEvent *)e; + + QDragManager *manager = QDragManager::self(); + QMimeData *dropData = manager->object ? manager->dragPrivate()->data : manager->dropData; + + QDropEvent de(object->target()->mapFromGlobal(me->globalPos()), possible_actions, dropData, + me->buttons(), me->modifiers()); + QApplication::sendEvent(object->target(), &de); + if (de.isAccepted()) + global_accepted_action = de.dropAction(); + else + global_accepted_action = Qt::IgnoreAction; + + if (object) + object->deleteLater(); + drag_object = object = 0; + } + eventLoop->exit(); + return true; // Eat all mouse events + } + + default: + break; + } + return false; +} + +Qt::DropAction QDragManager::drag(QDrag *o) +{ + Q_ASSERT(!qt_symbian_dnd_dragging); + if (object == o || !o || !o->source()) + return Qt::IgnoreAction; + + if (object) { + cancel(); + qApp->removeEventFilter(this); + beingCancelled = false; + } + + object = drag_object = o; + RWsSession winSession = o->source()->effectiveWinId()->ControlEnv()->WsSession(); + Q_ASSERT(!qt_symbian_dnd_deco); + qt_symbian_dnd_deco = new QShapedPixmapWidget(winSession, o->source()->effectiveWinId()->DrawableWindow()); + + oldstate = Qt::NoModifier; // #### Should use state that caused the drag + willDrop = false; + updatePixmap(); + updateCursor(); + restoreCursor = true; + + object->d_func()->target = 0; + TPoint windowPos = source()->effectiveWinId()->PositionRelativeToScreen(); + qt_symbian_dnd_deco->sprite.SetPosition(TPoint(QCursor::pos().x()- windowPos.iX ,QCursor::pos().y() - windowPos.iY)); + + QPoint hotspot = drag_object->hotSpot(); + qt_symbian_dnd_deco->cursorSprite.iOffset = TPoint(- hotspot.x(),- hotspot.y()); + qt_symbian_dnd_deco->sprite.UpdateMember(0,qt_symbian_dnd_deco->cursorSprite); + + qApp->installEventFilter(this); + + global_accepted_action = Qt::MoveAction; + qt_symbian_dnd_dragging = true; + + eventLoop = new QEventLoop; + // block + (void) eventLoop->exec(QEventLoop::AllEvents); + delete eventLoop; + eventLoop = 0; + + delete qt_symbian_dnd_deco; + qt_symbian_dnd_deco = 0; + qt_symbian_dnd_dragging = false; + + + return global_accepted_action; +} + + +void QDragManager::cancel(bool deleteSource) +{ + beingCancelled = true; + + if (object->target()) { + QDragLeaveEvent dle; + QApplication::sendEvent(object->target(), &dle); + } + + if (drag_object) { + if (deleteSource) + object->deleteLater(); + drag_object = object = 0; + } + + delete qt_symbian_dnd_deco; + qt_symbian_dnd_deco = 0; + + global_accepted_action = Qt::IgnoreAction; +} + + +void QDragManager::drop() +{ +} + +QVariant QDropData::retrieveData_sys(const QString &mimetype, QVariant::Type type) const +{ + if (!drag_object) + return QVariant(); + QByteArray data = drag_object->mimeData()->data(mimetype); + if (type == QVariant::String) + return QString::fromUtf8(data); + return data; +} + +bool QDropData::hasFormat_sys(const QString &format) const +{ + return formats().contains(format); +} + +QStringList QDropData::formats_sys() const +{ + if (drag_object) + return drag_object->mimeData()->formats(); + return QStringList(); +} + +QT_END_NAMESPACE +#endif // QT_NO_DRAGANDDROP diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index 3e1d12d..76d52c7 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -1691,6 +1691,17 @@ Qt::ButtonState QContextMenuEvent::state() const several are specified for any character in the string the behaviour is undefined. + \value Selection + If set, the edit cursor should be moved to the specified position + in the editor text contents. In contrast with \c Cursor, this + attribute does not work on the preedit text, but on the surrounding + text. The cursor will be moved after the commit string has been + committed, and the preedit string will be located at the new edit + position. + The start position specifies the new position and the length + variable can be used to set a selection starting from that point. + The value is unused. + \sa Attribute */ diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index 15a8fbd..19f57ac 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -245,7 +245,7 @@ public: inline QT3_SUPPORT_CONSTRUCTOR QKeyEvent(Type type, int key, int /*ascii*/, int modifiers, const QString& text = QString(), bool autorep = false, ushort count = 1) - : QInputEvent(type, (Qt::KeyboardModifiers)(modifiers & (int)Qt::KeyButtonMask)), txt(text), k(key), + : QInputEvent(type, Qt::KeyboardModifiers(modifiers & (int)Qt::KeyButtonMask)), txt(text), k(key), c(count), autor(autorep) { if (key >= Qt::Key_Back && key <= Qt::Key_MediaLast) @@ -428,7 +428,8 @@ public: TextFormat, Cursor, Language, - Ruby + Ruby, + Selection }; class Attribute { public: diff --git a/src/gui/kernel/qeventdispatcher_s60.cpp b/src/gui/kernel/qeventdispatcher_s60.cpp new file mode 100644 index 0000000..8dc063e --- /dev/null +++ b/src/gui/kernel/qeventdispatcher_s60.cpp @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qwidget.h> + +#include "qeventdispatcher_s60_p.h" + +QT_BEGIN_NAMESPACE + +QEventDispatcherS60::QEventDispatcherS60(QObject *parent) + : QEventDispatcherSymbian(parent), + m_noInputEvents(false) +{ +} + +QEventDispatcherS60::~QEventDispatcherS60() +{ + for (int c = 0; c < m_deferredInputEvents.size(); ++c) { + delete m_deferredInputEvents[c].event; + } +} + +bool QEventDispatcherS60::processEvents ( QEventLoop::ProcessEventsFlags flags ) +{ + bool ret = false; + + QT_TRY { + bool oldNoInputEventsValue = m_noInputEvents; + if (flags & QEventLoop::ExcludeUserInputEvents) { + m_noInputEvents = true; + } else { + m_noInputEvents = false; + ret = sendDeferredInputEvents() || ret; + } + + ret = QEventDispatcherSymbian::processEvents(flags) || ret; + + m_noInputEvents = oldNoInputEventsValue; + } QT_CATCH (const std::exception& ex) { +#ifndef QT_NO_EXCEPTIONS + CActiveScheduler::Current()->Error(qt_symbian_exception2Error(ex)); +#endif + } + + return ret; +} + +bool QEventDispatcherS60::hasPendingEvents() +{ + return !m_deferredInputEvents.isEmpty() || QEventDispatcherSymbian::hasPendingEvents(); +} + +void QEventDispatcherS60::saveInputEvent(QSymbianControl *control, QWidget *widget, QInputEvent *event) +{ + DeferredInputEvent inputEvent = {control, widget, event}; + m_deferredInputEvents.append(inputEvent); + connect(widget, SIGNAL(destroyed(QObject *)), SLOT(removeInputEventsForWidget(QObject *))); +} + +bool QEventDispatcherS60::sendDeferredInputEvents() +{ + bool eventsSent = false; + while (!m_deferredInputEvents.isEmpty()) { + DeferredInputEvent inputEvent = m_deferredInputEvents.takeFirst(); +#ifndef QT_NO_EXCEPTIONS + try { +#endif + inputEvent.control->sendInputEvent(inputEvent.widget, inputEvent.event); +#ifndef QT_NO_EXCEPTIONS + } catch (...) { + delete inputEvent.event; + throw; + } +#endif + delete inputEvent.event; + eventsSent = true; + } + + return eventsSent; +} + +void QEventDispatcherS60::removeInputEventsForWidget(QObject *object) +{ + for (int c = 0; c < m_deferredInputEvents.size(); ++c) { + if (m_deferredInputEvents[c].widget == object) { + delete m_deferredInputEvents[c].event; + m_deferredInputEvents.removeAt(c--); + } + } +} + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qeventdispatcher_s60_p.h b/src/gui/kernel/qeventdispatcher_s60_p.h new file mode 100644 index 0000000..ed1cb36 --- /dev/null +++ b/src/gui/kernel/qeventdispatcher_s60_p.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QEVENTDISPATCHER_S60_P_H +#define QEVENTDISPATCHER_S60_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <private/qeventdispatcher_symbian_p.h> +#include "qt_s60_p.h" + +QT_BEGIN_NAMESPACE + +class Q_GUI_EXPORT QEventDispatcherS60 : public QEventDispatcherSymbian +{ + Q_OBJECT + +public: + QEventDispatcherS60(QObject *parent = 0); + ~QEventDispatcherS60(); + + bool processEvents ( QEventLoop::ProcessEventsFlags flags ); + bool hasPendingEvents(); + + bool excludeUserInputEvents() { return m_noInputEvents; } + + void saveInputEvent(QSymbianControl *control, QWidget *widget, QInputEvent *event); + +private: + bool sendDeferredInputEvents(); + +private Q_SLOTS: + void removeInputEventsForWidget(QObject *object); + +private: + bool m_noInputEvents; + + struct DeferredInputEvent + { + QSymbianControl *control; + QWidget *widget; + QInputEvent *event; + }; + QList<DeferredInputEvent> m_deferredInputEvents; +}; + +QT_END_NAMESPACE + +#endif // QEVENTDISPATCHER_S60_P_H diff --git a/src/gui/kernel/qgesture.cpp b/src/gui/kernel/qgesture.cpp index 79dcae1..eeb6528 100644 --- a/src/gui/kernel/qgesture.cpp +++ b/src/gui/kernel/qgesture.cpp @@ -149,20 +149,18 @@ private: \sa setGraphicsItem() */ -QGesture::QGesture(QObject *parent) +QGesture::QGesture(QObject *gestureTarget, QObject *parent) : QObject(*new QGesturePrivate, parent) { - if (parent) - parent->installEventFilter(this); + setGestureTarget(gestureTarget); } /*! \internal */ -QGesture::QGesture(QGesturePrivate &dd, QObject *parent) +QGesture::QGesture(QGesturePrivate &dd, QObject *gestureTarget, QObject *parent) : QObject(dd, parent) { - if (parent) - parent->installEventFilter(this); + setGestureTarget(gestureTarget); } /*! @@ -172,6 +170,33 @@ QGesture::~QGesture() { } +/*! + \property QGesture::gestureTarget + + Gesture target is the object that the gesture will observe for events. + Typically this means that the gesture installs an event filter on the + target object. +*/ +void QGesture::setGestureTarget(QObject *object) +{ + d_func()->setupGestureTarget(object); +} + +QObject* QGesture::gestureTarget() const +{ + return d_func()->gestureTarget; +} + +void QGesturePrivate::setupGestureTarget(QObject *object) +{ + Q_Q(QGesture); + if (gestureTarget) + gestureTarget->removeEventFilter(q); + if (object) + object->installEventFilter(q); + gestureTarget = object; +} + /*! \internal */ bool QGesture::eventFilter(QObject *receiver, QEvent *event) diff --git a/src/gui/kernel/qgesture.h b/src/gui/kernel/qgesture.h index ee28ea4..1d2fa6d 100644 --- a/src/gui/kernel/qgesture.h +++ b/src/gui/kernel/qgesture.h @@ -63,20 +63,24 @@ class Q_GUI_EXPORT QGesture : public QObject Q_DECLARE_PRIVATE(QGesture) Q_PROPERTY(Qt::GestureState state READ state) + Q_PROPERTY(QObject* gestureTarget READ gestureTarget WRITE setGestureTarget) public: - explicit QGesture(QObject *parent = 0); + explicit QGesture(QObject *gestureTarget = 0, QObject *parent = 0); ~QGesture(); virtual bool filterEvent(QEvent *event) = 0; + void setGestureTarget(QObject *object); + QObject* gestureTarget() const; + void setGraphicsItem(QGraphicsItem *); QGraphicsItem *graphicsItem() const; Qt::GestureState state() const; protected: - QGesture(QGesturePrivate &dd, QObject *parent); + QGesture(QGesturePrivate &dd, QObject *gestureTarget, QObject *parent); bool eventFilter(QObject*, QEvent*); virtual void reset(); diff --git a/src/gui/kernel/qgesture_p.h b/src/gui/kernel/qgesture_p.h index 37f3146..f584713 100644 --- a/src/gui/kernel/qgesture_p.h +++ b/src/gui/kernel/qgesture_p.h @@ -69,11 +69,14 @@ class QGesturePrivate : public QObjectPrivate public: QGesturePrivate() - : graphicsItem(0), eventFilterProxyGraphicsItem(0), state(Qt::NoGesture) + : gestureTarget(0), graphicsItem(0), eventFilterProxyGraphicsItem(0), + state(Qt::NoGesture) { } + virtual void setupGestureTarget(QObject *o); + QPointer<QObject> gestureTarget; QGraphicsItem *graphicsItem; QGraphicsItem *eventFilterProxyGraphicsItem; diff --git a/src/gui/kernel/qkeymapper_mac.cpp b/src/gui/kernel/qkeymapper_mac.cpp index b10a804..24c15ed 100644 --- a/src/gui/kernel/qkeymapper_mac.cpp +++ b/src/gui/kernel/qkeymapper_mac.cpp @@ -563,7 +563,7 @@ QKeyMapperPrivate::QKeyMapperPrivate() QKeyMapperPrivate::~QKeyMapperPrivate() { - clearMappings(); + deleteLayouts(); } bool @@ -658,7 +658,7 @@ QKeyMapperPrivate::updateKeyboard() } void -QKeyMapperPrivate::clearMappings() +QKeyMapperPrivate::deleteLayouts() { keyboard_mode = NullMode; for (int i = 0; i < 255; ++i) { @@ -667,6 +667,12 @@ QKeyMapperPrivate::clearMappings() keyLayout[i] = 0; } } +} + +void +QKeyMapperPrivate::clearMappings() +{ + deleteLayouts(); updateKeyboard(); } diff --git a/src/gui/kernel/qkeymapper_p.h b/src/gui/kernel/qkeymapper_p.h index fe83e3f..21fecb2 100644 --- a/src/gui/kernel/qkeymapper_p.h +++ b/src/gui/kernel/qkeymapper_p.h @@ -58,6 +58,7 @@ #include <qlist.h> #include <qlocale.h> #include <qevent.h> +#include <qhash.h> #if defined (Q_WS_MAC64) # include <private/qt_mac_p.h> @@ -160,6 +161,7 @@ public: bool translateKeyEvent(QWidget *receiver, const MSG &msg, bool grab); void updatePossibleKeyCodes(unsigned char *kbdBuffer, quint32 scancode, quint32 vk_key); bool isADeadKey(unsigned int vk_key, unsigned int modifiers); + void deleteLayouts(); KeyboardLayoutItem *keyLayout[256]; @@ -188,6 +190,7 @@ public: bool updateKeyboard(); void updateKeyMap(EventHandlerCallRef, EventRef, void *); bool translateKeyEvent(QWidget *, EventHandlerCallRef, EventRef, void *, bool); + void deleteLayouts(); enum { NullMode, UnicodeMode, OtherMode } keyboard_mode; union { @@ -203,6 +206,13 @@ public: UInt32 keyboard_dead; KeyboardLayoutItem *keyLayout[256]; #elif defined(Q_WS_QWS) +#elif defined(Q_OS_SYMBIAN) +private: + QHash<TUint, int> s60ToQtKeyMap; + void fillKeyMap(); +public: + QString translateKeyEvent(int keySym, Qt::KeyboardModifiers modifiers); + int mapS60KeyToQt(TUint s60key); #endif }; diff --git a/src/gui/kernel/qkeymapper_s60.cpp b/src/gui/kernel/qkeymapper_s60.cpp new file mode 100644 index 0000000..6063ee4 --- /dev/null +++ b/src/gui/kernel/qkeymapper_s60.cpp @@ -0,0 +1,247 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qkeymapper_p.h" +#include <e32keys.h> + +QT_BEGIN_NAMESPACE + +QKeyMapperPrivate::QKeyMapperPrivate() +{ + fillKeyMap(); +} + +QKeyMapperPrivate::~QKeyMapperPrivate() +{ +} + +QList<int> QKeyMapperPrivate::possibleKeys(QKeyEvent * /* e */) +{ + QList<int> result; + return result; +} + +void QKeyMapperPrivate::clearMappings() +{ + // stub +} + +QString QKeyMapperPrivate::translateKeyEvent(int keySym, Qt::KeyboardModifiers /* modifiers */) +{ + if (keySym >= Qt::Key_Escape) + return QString(); + + // Symbian doesn't actually use modifiers, but gives us the character code directly. + + return QString(QChar(keySym)); +} + +void QKeyMapperPrivate::fillKeyMap() +{ + using namespace Qt; + static const struct { + TUint s60Key; + int qtKey; + } map[] = { + {EKeyBell, Key_unknown}, + {EKeyBackspace, Key_Backspace}, + {EKeyTab, Key_Tab}, + {EKeyLineFeed, Key_unknown}, + {EKeyVerticalTab, Key_unknown}, + {EKeyFormFeed, Key_unknown}, + {EKeyEnter, Key_Enter}, + {EKeyEscape, Key_Escape}, + {EKeySpace, Key_Space}, + {EKeyDelete, Key_Delete}, + {EKeyPrintScreen, Key_SysReq}, + {EKeyPause, Key_Pause}, + {EKeyHome, Key_Home}, + {EKeyEnd, Key_End}, + {EKeyPageUp, Key_PageUp}, + {EKeyPageDown, Key_PageDown}, + {EKeyInsert, Key_Insert}, + {EKeyLeftArrow, Key_Left}, + {EKeyRightArrow, Key_Right}, + {EKeyUpArrow, Key_Up}, + {EKeyDownArrow, Key_Down}, + {EKeyLeftShift, Key_Shift}, + {EKeyRightShift, Key_Shift}, + {EKeyLeftAlt, Key_Alt}, + {EKeyRightAlt, Key_AltGr}, + {EKeyLeftCtrl, Key_Control}, + {EKeyRightCtrl, Key_Control}, + {EKeyLeftFunc, Key_Super_L}, + {EKeyRightFunc, Key_Super_R}, + {EKeyCapsLock, Key_CapsLock}, + {EKeyNumLock, Key_NumLock}, + {EKeyScrollLock, Key_ScrollLock}, + {EKeyF1, Key_F1}, + {EKeyF2, Key_F2}, + {EKeyF3, Key_F3}, + {EKeyF4, Key_F4}, + {EKeyF5, Key_F5}, + {EKeyF6, Key_F6}, + {EKeyF7, Key_F7}, + {EKeyF8, Key_F8}, + {EKeyF9, Key_F9}, + {EKeyF10, Key_F10}, + {EKeyF11, Key_F11}, + {EKeyF12, Key_F12}, + {EKeyF13, Key_F13}, + {EKeyF14, Key_F14}, + {EKeyF15, Key_F15}, + {EKeyF16, Key_F16}, + {EKeyF17, Key_F17}, + {EKeyF18, Key_F18}, + {EKeyF19, Key_F19}, + {EKeyF20, Key_F20}, + {EKeyF21, Key_F21}, + {EKeyF22, Key_F22}, + {EKeyF23, Key_F23}, + {EKeyF24, Key_F24}, + {EKeyOff, Key_unknown}, + {EKeyIncContrast, Key_unknown}, + {EKeyDecContrast, Key_unknown}, + {EKeyBacklightOn, Key_unknown}, + {EKeyBacklightOff, Key_unknown}, + {EKeyBacklightToggle, Key_unknown}, + {EKeySliderDown, Key_unknown}, + {EKeySliderUp, Key_unknown}, + {EKeyMenu, Key_Menu}, + {EKeyDictaphonePlay, Key_unknown}, + {EKeyDictaphoneStop, Key_unknown}, + {EKeyDictaphoneRecord, Key_unknown}, + {EKeyHelp, Key_unknown}, + {EKeyDial, Key_Call}, + {EKeyScreenDimension0, Key_unknown}, + {EKeyScreenDimension1, Key_unknown}, + {EKeyScreenDimension2, Key_unknown}, + {EKeyScreenDimension3, Key_unknown}, + {EKeyIncVolume, Key_unknown}, + {EKeyDecVolume, Key_unknown}, + {EKeyDevice0, Key_Context1}, // Found by manual testing, left softkey. + {EKeyDevice1, Key_Context2}, // Found by manual testing. + {EKeyDevice2, Key_unknown}, + {EKeyDevice3, Key_Select}, // Found by manual testing. + {EKeyDevice4, Key_unknown}, + {EKeyDevice5, Key_unknown}, + {EKeyDevice6, Key_unknown}, + {EKeyDevice7, Key_unknown}, + {EKeyDevice8, Key_unknown}, + {EKeyDevice9, Key_unknown}, + {EKeyDeviceA, Key_unknown}, + {EKeyDeviceB, Key_unknown}, + {EKeyDeviceC, Key_unknown}, + {EKeyDeviceD, Key_unknown}, + {EKeyDeviceE, Key_unknown}, + {EKeyDeviceF, Key_unknown}, + {EKeyApplication0, Key_Launch0}, + {EKeyApplication1, Key_Launch1}, + {EKeyApplication2, Key_Launch2}, + {EKeyApplication3, Key_Launch3}, + {EKeyApplication4, Key_Launch4}, + {EKeyApplication5, Key_Launch5}, + {EKeyApplication6, Key_Launch6}, + {EKeyApplication7, Key_Launch7}, + {EKeyApplication8, Key_Launch8}, + {EKeyApplication9, Key_Launch9}, + {EKeyApplicationA, Key_LaunchA}, + {EKeyApplicationB, Key_LaunchB}, + {EKeyApplicationC, Key_LaunchC}, + {EKeyApplicationD, Key_LaunchD}, + {EKeyApplicationE, Key_LaunchE}, + {EKeyApplicationF, Key_LaunchF}, + {EKeyYes, Key_Yes}, + {EKeyNo, Key_No}, + {EKeyIncBrightness, Key_unknown}, + {EKeyDecBrightness, Key_unknown}, + {EKeyKeyboardExtend, Key_unknown}, + {EKeyDevice10, Key_unknown}, + {EKeyDevice11, Key_unknown}, + {EKeyDevice12, Key_unknown}, + {EKeyDevice13, Key_unknown}, + {EKeyDevice14, Key_unknown}, + {EKeyDevice15, Key_unknown}, + {EKeyDevice16, Key_unknown}, + {EKeyDevice17, Key_unknown}, + {EKeyDevice18, Key_unknown}, + {EKeyDevice19, Key_unknown}, + {EKeyDevice1A, Key_unknown}, + {EKeyDevice1B, Key_unknown}, + {EKeyDevice1C, Key_unknown}, + {EKeyDevice1D, Key_unknown}, + {EKeyDevice1E, Key_unknown}, + {EKeyDevice1F, Key_unknown}, + {EKeyApplication10, Key_unknown}, + {EKeyApplication11, Key_unknown}, + {EKeyApplication12, Key_unknown}, + {EKeyApplication13, Key_unknown}, + {EKeyApplication14, Key_unknown}, + {EKeyApplication15, Key_unknown}, + {EKeyApplication16, Key_unknown}, + {EKeyApplication17, Key_unknown}, + {EKeyApplication18, Key_unknown}, + {EKeyApplication19, Key_unknown}, + {EKeyApplication1A, Key_unknown}, + {EKeyApplication1B, Key_unknown}, + {EKeyApplication1C, Key_unknown}, + {EKeyApplication1D, Key_unknown}, + {EKeyApplication1E, Key_unknown}, + {EKeyApplication1F, Key_unknown} + }; + const int mapSize = int(sizeof(map)/sizeof(map[0])); + s60ToQtKeyMap.reserve(mapSize + 5); // +5? docs: Ideally, slightly more than number of items + for (int i = 0; i < mapSize; ++i) + s60ToQtKeyMap.insert(map[i].s60Key, map[i].qtKey); +} + +int QKeyMapperPrivate::mapS60KeyToQt(TUint s60key) +{ + QHash<TUint, int>::const_iterator mapping; + mapping = s60ToQtKeyMap.find(s60key); + if (mapping != s60ToQtKeyMap.end()) { + return *mapping; + } else { + return Qt::Key_unknown; + } +} + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qkeymapper_win.cpp b/src/gui/kernel/qkeymapper_win.cpp index 36abf86..0895094 100644 --- a/src/gui/kernel/qkeymapper_win.cpp +++ b/src/gui/kernel/qkeymapper_win.cpp @@ -582,10 +582,10 @@ QKeyMapperPrivate::QKeyMapperPrivate() QKeyMapperPrivate::~QKeyMapperPrivate() { - clearMappings(); + deleteLayouts(); } -void QKeyMapperPrivate::clearMappings() +void QKeyMapperPrivate::deleteLayouts() { for (int i = 0; i < 255; ++i) { if (keyLayout[i]) { @@ -593,6 +593,11 @@ void QKeyMapperPrivate::clearMappings() keyLayout[i] = 0; } } +} + +void QKeyMapperPrivate::clearMappings() +{ + deleteLayouts(); /* MAKELCID()'s first argument is a WORD, and GetKeyboardLayout() * returns a DWORD. */ diff --git a/src/gui/kernel/qkeysequence.cpp b/src/gui/kernel/qkeysequence.cpp index 50fe849..53120da 100644 --- a/src/gui/kernel/qkeysequence.cpp +++ b/src/gui/kernel/qkeysequence.cpp @@ -225,72 +225,72 @@ void Q_AUTOTEST_EXPORT qt_set_sequence_auto_mnemonic(bool b) { qt_sequence_no_mn corresponds to the \key Control keys. \table - \header \i StandardKey \i Windows \i Mac OS X \i KDE \i GNOME - \row \i HelpContents \i F1 \i Ctrl+? \i F1 \i F1 - \row \i WhatsThis \i Shift+F1 \i Shift+F1 \i Shift+F1 \i Shift+F1 - \row \i Open \i Ctrl+O \i Ctrl+O \i Ctrl+O \i Ctrl+O - \row \i Close \i Ctrl+F4, Ctrl+W \i Ctrl+W, Ctrl+F4 \i Ctrl+W \i Ctrl+W - \row \i Save \i Ctrl+S \i Ctrl+S \i Ctrl+S \i Ctrl+S - \row \i Quit \i \i Ctrl+Q \i Qtrl+Q \i Qtrl+Q - \row \i SaveAs \i \i Ctrl+Shift+S \i \i Ctrl+Shift+S - \row \i New \i Ctrl+N \i Ctrl+N \i Ctrl+N \i Ctrl+N - \row \i Delete \i Del \i Del, Meta+D \i Del, Ctrl+D \i Del, Ctrl+D - \row \i Cut \i Ctrl+X, Shift+Del \i Ctrl+X \i Ctrl+X, F20, Shift+Del \i Ctrl+X, F20, Shift+Del - \row \i Copy \i Ctrl+C, Ctrl+Ins \i Ctrl+C \i Ctrl+C, F16, Ctrl+Ins \i Ctrl+C, F16, Ctrl+Ins - \row \i Paste \i Ctrl+V, Shift+Ins \i Ctrl+V \i Ctrl+V, F18, Shift+Ins \i Ctrl+V, F18, Shift+Ins - \row \i Preferences \i \i Ctrl+, \i \i - \row \i Undo \i Ctrl+Z, Alt+Backspace \i Ctrl+Z \i Ctrl+Z, F14 \i Ctrl+Z, F14 - \row \i Redo \i Ctrl+Y, Shift+Ctrl+Z, Alt+Shift+Backspace \i Ctrl+Shift+Z, Ctrl+Y \i Ctrl+Shift+Z \i Ctrl+Shift+Z - \row \i Back \i Alt+Left, Backspace \i Ctrl+[ \i Alt+Left \i Alt+Left - \row \i Forward \i Alt+Right, Shift+Backspace \i Ctrl+] \i Alt+Right \i Alt+Right - \row \i Refresh \i F5 \i F5 \i F5 \i Ctrl+R, F5 - \row \i ZoomIn \i Ctrl+Plus \i Ctrl+Plus \i Ctrl+Plus \i Ctrl+Plus - \row \i ZoomOut \i Ctrl+Minus \i Ctrl+Minus \i Ctrl+Minus \i Ctrl+Minus - \row \i Print \i Ctrl+P \i Ctrl+P \i Ctrl+P \i Ctrl+P - \row \i AddTab \i Ctrl+T \i Ctrl+T \i Ctrl+Shift+N, Ctrl+T \i Ctrl+T - \row \i NextChild \i Ctrl+Tab, Forward, Ctrl+F6 \i Ctrl+}, Forward, Ctrl+Tab \i Ctrl+Tab, Forward, Ctrl+Comma \i Ctrl+Tab, Forward - \row \i PreviousChild \i Ctrl+Shift+Tab, Back, Ctrl+Shift+F6 \i Ctrl+{, Back, Ctrl+Shift+Tab \i Ctrl+Shift+Tab, Back, Ctrl+Period \i Ctrl+Shift+Tab, Back - \row \i Find \i Ctrl+F \i Ctrl+F \i Ctrl+F \i Ctrl+F - \row \i FindNext \i F3, Ctrl+G \i Ctrl+G \i F3 \i Ctrl+G, F3 - \row \i FindPrevious \i Shift+F3, Ctrl+Shift+G \i Ctrl+Shift+G \i Shift+F3 \i Ctrl+Shift+G, Shift+F3 - \row \i Replace \i Ctrl+H \i (none) \i Ctrl+R \i Ctrl+H - \row \i SelectAll \i Ctrl+A \i Ctrl+A \i Ctrl+A \i Ctrl+A - \row \i Bold \i Ctrl+B \i Ctrl+B \i Ctrl+B \i Ctrl+B - \row \i Italic \i Ctrl+I \i Ctrl+I \i Ctrl+I \i Ctrl+I - \row \i Underline \i Ctrl+U \i Ctrl+U \i Ctrl+U \i Ctrl+U - \row \i MoveToNextChar \i Right \i Right \i Right \i Right - \row \i MoveToPreviousChar \i Left \i Left \i Left \i Left - \row \i MoveToNextWord \i Ctrl+Right \i Alt+Right \i Ctrl+Right \i Ctrl+Right - \row \i MoveToPreviousWord \i Ctrl+Left \i Alt+Left \i Ctrl+Left \i Ctrl+Left - \row \i MoveToNextLine \i Down \i Down \i Down \i Down - \row \i MoveToPreviousLine \i Up \i Up \i Up \i Up - \row \i MoveToNextPage \i PgDown \i PgDown, Alt+PgDown, Meta+Down, Meta+PgDown\i PgDown \i PgDown - \row \i MoveToPreviousPage \i PgUp \i PgUp, Alt+PgUp, Meta+Up, Meta+PgUp \i PgUp \i PgUp - \row \i MoveToStartOfLine \i Home \i Ctrl+Left, Meta+Left \i Home \i Home - \row \i MoveToEndOfLine \i End \i Ctrl+Right, Meta+Right \i End \i End - \row \i MoveToStartOfBlock \i (none) \i Alt+Up, Meta+A \i (none) \i (none) - \row \i MoveToEndOfBlock \i (none) \i Alt+Down, Meta+E \i (none) \i (none) - \row \i MoveToStartOfDocument\i Ctrl+Home \i Ctrl+Up, Home \i Ctrl+Home \i Ctrl+Home - \row \i MoveToEndOfDocument \i Ctrl+End \i Ctrl+Down, End \i Ctrl+End \i Ctrl+End - \row \i SelectNextChar \i Shift+Right \i Shift+Right \i Shift+Right \i Shift+Right - \row \i SelectPreviousChar \i Shift+Left \i Shift+Left \i Shift+Left \i Shift?left - \row \i SelectNextWord \i Ctrl+Shift+Right \i Alt+Shift+Right \i Ctrl+Shift+Right \i Ctrl+Shift+Right - \row \i SelectPreviousWord \i Ctrl+Shift+Left \i Alt+Shift+Left \i Ctrl+Shift+Left \i Ctrl+Shift+Left - \row \i SelectNextLine \i Shift+Down \i Shift+Down \i Shift+Down \i Shift+Down - \row \i SelectPreviousLine \i Shift+Up \i Shift+Up \i Shift+Up \i Shift+Up - \row \i SelectNextPage \i Shift+PgDown \i Shift+PgDown \i Shift+PgDown \i Shift+PgDown - \row \i SelectPreviousPage \i Shift+PgUp \i Shift+PgUp \i Shift+PgUp \i Shift+PgUp - \row \i SelectStartOfLine \i Shift+Home \i Ctrl+Shift+Left \i Shift+Home \i Shift+Home - \row \i SelectEndOfLine \i Shift+End \i Ctrl+Shift+Right \i Shift+End \i Shift+End - \row \i SelectStartOfBlock \i (none) \i Alt+Shift+Up \i (none) \i (none) - \row \i SelectEndOfBlock \i (none) \i Alt+Shift+Down \i (none) \i (none) - \row \i SelectStartOfDocument\i Ctrl+Shift+Home \i Ctrl+Shift+Up, Shift+Home \i Ctrl+Shift+Home\i Ctrl+Shift+Home - \row \i SelectEndOfDocument \i Ctrl+Shift+End \i Ctrl+Shift+Down, Shift+End \i Ctrl+Shift+End \i Ctrl+Shift+End - \row \i DeleteStartOfWord \i Ctrl+Backspace \i Alt+Backspace \i Ctrl+Backspace \i Ctrl+Backspace - \row \i DeleteEndOfWord \i Ctrl+Del \i (none) \i Ctrl+Del \i Ctrl+Del - \row \i DeleteEndOfLine \i (none) \i (none) \i Ctrl+K \i Ctrl+K - \row \i InsertParagraphSeparator \i Enter \i Enter \i Enter \i Enter - \row \i InsertLineSeparator \i Shift+Enter \i Meta+Enter \i Shift+Enter \i Shift+Enter + \header \i StandardKey \i Windows \i Mac OS X \i KDE \i GNOME \i S60 + \row \i HelpContents \i F1 \i Ctrl+? \i F1 \i F1 \i F2 + \row \i WhatsThis \i Shift+F1 \i Shift+F1 \i Shift+F1 \i Shift+F1 \i Shift+F1 + \row \i Open \i Ctrl+O \i Ctrl+O \i Ctrl+O \i Ctrl+O \i (none) + \row \i Close \i Ctrl+F4, Ctrl+W \i Ctrl+W, Ctrl+F4 \i Ctrl+W \i Ctrl+W \i (none) + \row \i Save \i Ctrl+S \i Ctrl+S \i Ctrl+S \i Ctrl+S \i (none) + \row \i Quit \i \i Ctrl+Q \i Qtrl+Q \i Qtrl+Q \i (none) + \row \i SaveAs \i \i Ctrl+Shift+S \i \i Ctrl+Shift+S \i (none) + \row \i New \i Ctrl+N \i Ctrl+N \i Ctrl+N \i Ctrl+N \i (none) + \row \i Delete \i Del \i Del, Meta+D \i Del, Ctrl+D \i Del, Ctrl+D \i Del + \row \i Cut \i Ctrl+X, Shift+Del \i Ctrl+X \i Ctrl+X, F20, Shift+Del \i Ctrl+X, F20, Shift+Del \i Ctrl+X + \row \i Copy \i Ctrl+C, Ctrl+Ins \i Ctrl+C \i Ctrl+C, F16, Ctrl+Ins \i Ctrl+C, F16, Ctrl+Ins \i Ctrl+C + \row \i Paste \i Ctrl+V, Shift+Ins \i Ctrl+V \i Ctrl+V, F18, Shift+Ins \i Ctrl+V, F18, Shift+Ins \i Ctrl+V + \row \i Preferences \i \i Ctrl+, \i \i \i (none) + \row \i Undo \i Ctrl+Z, Alt+Backspace \i Ctrl+Z \i Ctrl+Z, F14 \i Ctrl+Z, F14 \i Ctrl+Z + \row \i Redo \i Ctrl+Y, Shift+Ctrl+Z, Alt+Shift+Backspace \i Ctrl+Shift+Z, Ctrl+Y \i Ctrl+Shift+Z \i Ctrl+Shift+Z \i (none) + \row \i Back \i Alt+Left, Backspace \i Ctrl+[ \i Alt+Left \i Alt+Left \i (none) + \row \i Forward \i Alt+Right, Shift+Backspace \i Ctrl+] \i Alt+Right \i Alt+Right \i (none) + \row \i Refresh \i F5 \i F5 \i F5 \i Ctrl+R, F5 \i (none) + \row \i ZoomIn \i Ctrl+Plus \i Ctrl+Plus \i Ctrl+Plus \i Ctrl+Plus \i (none) + \row \i ZoomOut \i Ctrl+Minus \i Ctrl+Minus \i Ctrl+Minus \i Ctrl+Minus \i (none) + \row \i Print \i Ctrl+P \i Ctrl+P \i Ctrl+P \i Ctrl+P \i (none) + \row \i AddTab \i Ctrl+T \i Ctrl+T \i Ctrl+Shift+N, Ctrl+T \i Ctrl+T \i (none) + \row \i NextChild \i Ctrl+Tab, Forward, Ctrl+F6 \i Ctrl+}, Forward, Ctrl+Tab \i Ctrl+Tab, Forward, Ctrl+Comma \i Ctrl+Tab, Forward \i (none) + \row \i PreviousChild \i Ctrl+Shift+Tab, Back, Ctrl+Shift+F6 \i Ctrl+{, Back, Ctrl+Shift+Tab \i Ctrl+Shift+Tab, Back, Ctrl+Period \i Ctrl+Shift+Tab, Back \i (none) + \row \i Find \i Ctrl+F \i Ctrl+F \i Ctrl+F \i Ctrl+F \i (none) + \row \i FindNext \i F3, Ctrl+G \i Ctrl+G \i F3 \i Ctrl+G, F3 \i (none) + \row \i FindPrevious \i Shift+F3, Ctrl+Shift+G \i Ctrl+Shift+G \i Shift+F3 \i Ctrl+Shift+G, Shift+F3 \i (none) + \row \i Replace \i Ctrl+H \i (none) \i Ctrl+R \i Ctrl+H \i (none) + \row \i SelectAll \i Ctrl+A \i Ctrl+A \i Ctrl+A \i Ctrl+A \i (none) + \row \i Bold \i Ctrl+B \i Ctrl+B \i Ctrl+B \i Ctrl+B \i (none) + \row \i Italic \i Ctrl+I \i Ctrl+I \i Ctrl+I \i Ctrl+I \i (none) + \row \i Underline \i Ctrl+U \i Ctrl+U \i Ctrl+U \i Ctrl+U \i (none) + \row \i MoveToNextChar \i Right \i Right \i Right \i Right \i Right + \row \i MoveToPreviousChar \i Left \i Left \i Left \i Left \i Left + \row \i MoveToNextWord \i Ctrl+Right \i Alt+Right \i Ctrl+Right \i Ctrl+Right \i Ctrl+Right + \row \i MoveToPreviousWord \i Ctrl+Left \i Alt+Left \i Ctrl+Left \i Ctrl+Left \i Ctrl+Left + \row \i MoveToNextLine \i Down \i Down \i Down \i Down \i Down + \row \i MoveToPreviousLine \i Up \i Up \i Up \i Up \i Up + \row \i MoveToNextPage \i PgDown \i PgDown, Alt+PgDown, Meta+Down, Meta+PgDown\i PgDown \i PgDown \i PgDown + \row \i MoveToPreviousPage \i PgUp \i PgUp, Alt+PgUp, Meta+Up, Meta+PgUp \i PgUp \i PgUp \i PgUp + \row \i MoveToStartOfLine \i Home \i Ctrl+Left, Meta+Left \i Home \i Home \i Home + \row \i MoveToEndOfLine \i End \i Ctrl+Right, Meta+Right \i End \i End \i End + \row \i MoveToStartOfBlock \i (none) \i Alt+Up, Meta+A \i (none) \i (none) \i (none) + \row \i MoveToEndOfBlock \i (none) \i Alt+Down, Meta+E \i (none) \i (none) \i (none) + \row \i MoveToStartOfDocument\i Ctrl+Home \i Ctrl+Up, Home \i Ctrl+Home \i Ctrl+Home \i Ctrl+Home + \row \i MoveToEndOfDocument \i Ctrl+End \i Ctrl+Down, End \i Ctrl+End \i Ctrl+End \i Ctrl+End + \row \i SelectNextChar \i Shift+Right \i Shift+Right \i Shift+Right \i Shift+Right \i Shift+Right + \row \i SelectPreviousChar \i Shift+Left \i Shift+Left \i Shift+Left \i Shift+Left \i Shift+Left + \row \i SelectNextWord \i Ctrl+Shift+Right \i Alt+Shift+Right \i Ctrl+Shift+Right \i Ctrl+Shift+Right \i Ctrl+Shift+Right + \row \i SelectPreviousWord \i Ctrl+Shift+Left \i Alt+Shift+Left \i Ctrl+Shift+Left \i Ctrl+Shift+Left \i Ctrl+Shift+Left + \row \i SelectNextLine \i Shift+Down \i Shift+Down \i Shift+Down \i Shift+Down \i Shift+Down + \row \i SelectPreviousLine \i Shift+Up \i Shift+Up \i Shift+Up \i Shift+Up \i Shift+Up + \row \i SelectNextPage \i Shift+PgDown \i Shift+PgDown \i Shift+PgDown \i Shift+PgDown \i Shift+PgDown + \row \i SelectPreviousPage \i Shift+PgUp \i Shift+PgUp \i Shift+PgUp \i Shift+PgUp \i Shift+PgUp + \row \i SelectStartOfLine \i Shift+Home \i Ctrl+Shift+Left \i Shift+Home \i Shift+Home \i Shift+Home + \row \i SelectEndOfLine \i Shift+End \i Ctrl+Shift+Right \i Shift+End \i Shift+End \i Shift+End + \row \i SelectStartOfBlock \i (none) \i Alt+Shift+Up \i (none) \i (none) \i (none) + \row \i SelectEndOfBlock \i (none) \i Alt+Shift+Down \i (none) \i (none) \i (none) + \row \i SelectStartOfDocument\i Ctrl+Shift+Home \i Ctrl+Shift+Up, Shift+Home \i Ctrl+Shift+Home\i Ctrl+Shift+Home \i Ctrl+Shift+Home + \row \i SelectEndOfDocument \i Ctrl+Shift+End \i Ctrl+Shift+Down, Shift+End \i Ctrl+Shift+End \i Ctrl+Shift+End \i Ctrl+Shift+End + \row \i DeleteStartOfWord \i Ctrl+Backspace \i Alt+Backspace \i Ctrl+Backspace \i Ctrl+Backspace \i (none) + \row \i DeleteEndOfWord \i Ctrl+Del \i (none) \i Ctrl+Del \i Ctrl+Del \i (none) + \row \i DeleteEndOfLine \i (none) \i (none) \i Ctrl+K \i Ctrl+K \i (none) + \row \i InsertParagraphSeparator \i Enter \i Enter \i Enter \i Enter \i (none) + \row \i InsertLineSeparator \i Shift+Enter \i Meta+Enter \i Shift+Enter \i Shift+Enter \i (none) \endtable Note that, since the key sequences used for the standard shortcuts differ @@ -501,9 +501,9 @@ const QKeyBinding QKeySequencePrivate::keyBindings[] = { {QKeySequence::InsertParagraphSeparator,0, Qt::Key_Return, QApplicationPrivate::KB_All}, {QKeySequence::InsertParagraphSeparator,0, Qt::Key_Enter, QApplicationPrivate::KB_All}, {QKeySequence::Delete, 1, Qt::Key_Delete, QApplicationPrivate::KB_All}, - {QKeySequence::MoveToStartOfLine, 0, Qt::Key_Home, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11}, + {QKeySequence::MoveToStartOfLine, 0, Qt::Key_Home, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11 | QApplicationPrivate::KB_S60}, {QKeySequence::MoveToStartOfDocument, 0, Qt::Key_Home, QApplicationPrivate::KB_Mac}, - {QKeySequence::MoveToEndOfLine, 0, Qt::Key_End, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11}, + {QKeySequence::MoveToEndOfLine, 0, Qt::Key_End, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11 | QApplicationPrivate::KB_S60}, {QKeySequence::MoveToEndOfDocument, 0, Qt::Key_End, QApplicationPrivate::KB_Mac}, {QKeySequence::MoveToPreviousChar, 0, Qt::Key_Left, QApplicationPrivate::KB_All}, {QKeySequence::MoveToPreviousLine, 0, Qt::Key_Up, QApplicationPrivate::KB_All}, @@ -512,6 +512,7 @@ const QKeyBinding QKeySequencePrivate::keyBindings[] = { {QKeySequence::MoveToPreviousPage, 1, Qt::Key_PageUp, QApplicationPrivate::KB_All}, {QKeySequence::MoveToNextPage, 1, Qt::Key_PageDown, QApplicationPrivate::KB_All}, {QKeySequence::HelpContents, 0, Qt::Key_F1, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11}, + {QKeySequence::HelpContents, 0, Qt::Key_F2, QApplicationPrivate::KB_S60}, {QKeySequence::FindNext, 0, Qt::Key_F3, QApplicationPrivate::KB_X11}, {QKeySequence::FindNext, 1, Qt::Key_F3, QApplicationPrivate::KB_Win}, {QKeySequence::Refresh, 0, Qt::Key_F5, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11}, @@ -522,13 +523,14 @@ const QKeyBinding QKeySequencePrivate::keyBindings[] = { {QKeySequence::PreviousChild, 0, Qt::Key_Back, QApplicationPrivate::KB_All}, {QKeySequence::NextChild, 0, Qt::Key_Forward, QApplicationPrivate::KB_All}, {QKeySequence::Forward, 0, Qt::SHIFT | Qt::Key_Backspace, QApplicationPrivate::KB_Win}, + {QKeySequence::Delete, 0, Qt::SHIFT | Qt::Key_Backspace, QApplicationPrivate::KB_S60}, {QKeySequence::InsertLineSeparator, 0, Qt::SHIFT | Qt::Key_Return, QApplicationPrivate::KB_All}, {QKeySequence::InsertLineSeparator, 0, Qt::SHIFT | Qt::Key_Enter, QApplicationPrivate::KB_All}, {QKeySequence::Paste, 0, Qt::SHIFT | Qt::Key_Insert, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11}, {QKeySequence::Cut, 0, Qt::SHIFT | Qt::Key_Delete, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11}, //## Check if this should work on mac - {QKeySequence::SelectStartOfLine, 0, Qt::SHIFT | Qt::Key_Home, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11}, + {QKeySequence::SelectStartOfLine, 0, Qt::SHIFT | Qt::Key_Home, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11 | QApplicationPrivate::KB_S60}, {QKeySequence::SelectStartOfDocument, 0, Qt::SHIFT | Qt::Key_Home, QApplicationPrivate::KB_Mac}, - {QKeySequence::SelectEndOfLine, 0, Qt::SHIFT | Qt::Key_End, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11}, + {QKeySequence::SelectEndOfLine, 0, Qt::SHIFT | Qt::Key_End, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11 | QApplicationPrivate::KB_S60}, {QKeySequence::SelectEndOfDocument, 0, Qt::SHIFT | Qt::Key_End, QApplicationPrivate::KB_Mac}, {QKeySequence::SelectPreviousChar, 0, Qt::SHIFT | Qt::Key_Left, QApplicationPrivate::KB_All}, {QKeySequence::SelectPreviousLine, 0, Qt::SHIFT | Qt::Key_Up, QApplicationPrivate::KB_All}, @@ -581,15 +583,15 @@ const QKeyBinding QKeySequencePrivate::keyBindings[] = { {QKeySequence::DeleteStartOfWord, 0, Qt::CTRL | Qt::Key_Backspace, QApplicationPrivate::KB_X11 | QApplicationPrivate::KB_Win}, {QKeySequence::Copy, 0, Qt::CTRL | Qt::Key_Insert, QApplicationPrivate::KB_X11 | QApplicationPrivate::KB_Win}, {QKeySequence::DeleteEndOfWord, 0, Qt::CTRL | Qt::Key_Delete, QApplicationPrivate::KB_X11 | QApplicationPrivate::KB_Win}, - {QKeySequence::MoveToStartOfDocument, 0, Qt::CTRL | Qt::Key_Home, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11}, - {QKeySequence::MoveToEndOfDocument, 0, Qt::CTRL | Qt::Key_End, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11}, + {QKeySequence::MoveToStartOfDocument, 0, Qt::CTRL | Qt::Key_Home, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11 | QApplicationPrivate::KB_S60}, + {QKeySequence::MoveToEndOfDocument, 0, Qt::CTRL | Qt::Key_End, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11 | QApplicationPrivate::KB_S60}, {QKeySequence::Back, 0, Qt::CTRL | Qt::Key_Left, QApplicationPrivate::KB_Mac}, - {QKeySequence::MoveToPreviousWord, 0, Qt::CTRL | Qt::Key_Left, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11}, + {QKeySequence::MoveToPreviousWord, 0, Qt::CTRL | Qt::Key_Left, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11 | QApplicationPrivate::KB_S60}, {QKeySequence::MoveToStartOfLine, 0, Qt::CTRL | Qt::Key_Left, QApplicationPrivate::KB_Mac }, {QKeySequence::MoveToStartOfDocument, 1, Qt::CTRL | Qt::Key_Up, QApplicationPrivate::KB_Mac}, {QKeySequence::Forward, 0, Qt::CTRL | Qt::Key_Right, QApplicationPrivate::KB_Mac}, {QKeySequence::MoveToEndOfLine, 0, Qt::CTRL | Qt::Key_Right, QApplicationPrivate::KB_Mac }, - {QKeySequence::MoveToNextWord, 0, Qt::CTRL | Qt::Key_Right, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11}, + {QKeySequence::MoveToNextWord, 0, Qt::CTRL | Qt::Key_Right, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11 | QApplicationPrivate::KB_S60}, {QKeySequence::MoveToEndOfDocument, 1, Qt::CTRL | Qt::Key_Down, QApplicationPrivate::KB_Mac}, {QKeySequence::Close, 1, Qt::CTRL | Qt::Key_F4, QApplicationPrivate::KB_Win}, {QKeySequence::Close, 0, Qt::CTRL | Qt::Key_F4, QApplicationPrivate::KB_Mac}, @@ -602,12 +604,12 @@ const QKeyBinding QKeySequencePrivate::keyBindings[] = { {QKeySequence::Redo, 1, Qt::CTRL | Qt::SHIFT | Qt::Key_Z, QApplicationPrivate::KB_Mac}, //different priority from above {QKeySequence::PreviousChild, 1, Qt::CTRL | Qt::SHIFT | Qt::Key_Backtab, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11}, {QKeySequence::PreviousChild, 0, Qt::CTRL | Qt::SHIFT | Qt::Key_Backtab, QApplicationPrivate::KB_Mac },//different priority from above - {QKeySequence::SelectStartOfDocument, 0, Qt::CTRL | Qt::SHIFT | Qt::Key_Home, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11}, - {QKeySequence::SelectEndOfDocument, 0, Qt::CTRL | Qt::SHIFT | Qt::Key_End, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11}, - {QKeySequence::SelectPreviousWord, 0, Qt::CTRL | Qt::SHIFT | Qt::Key_Left, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11}, + {QKeySequence::SelectStartOfDocument, 0, Qt::CTRL | Qt::SHIFT | Qt::Key_Home, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11 | QApplicationPrivate::KB_S60}, + {QKeySequence::SelectEndOfDocument, 0, Qt::CTRL | Qt::SHIFT | Qt::Key_End, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11 | QApplicationPrivate::KB_S60}, + {QKeySequence::SelectPreviousWord, 0, Qt::CTRL | Qt::SHIFT | Qt::Key_Left, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11 | QApplicationPrivate::KB_S60}, {QKeySequence::SelectStartOfLine, 1, Qt::CTRL | Qt::SHIFT | Qt::Key_Left, QApplicationPrivate::KB_Mac }, {QKeySequence::SelectStartOfDocument, 1, Qt::CTRL | Qt::SHIFT | Qt::Key_Up, QApplicationPrivate::KB_Mac}, - {QKeySequence::SelectNextWord, 0, Qt::CTRL | Qt::SHIFT | Qt::Key_Right, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11}, + {QKeySequence::SelectNextWord, 0, Qt::CTRL | Qt::SHIFT | Qt::Key_Right, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11 | QApplicationPrivate::KB_S60}, {QKeySequence::SelectEndOfLine, 1, Qt::CTRL | Qt::SHIFT | Qt::Key_Right, QApplicationPrivate::KB_Mac }, {QKeySequence::SelectEndOfDocument, 1, Qt::CTRL | Qt::SHIFT | Qt::Key_Down, QApplicationPrivate::KB_Mac}, {QKeySequence::PreviousChild, 0, Qt::CTRL | Qt::SHIFT | Qt::Key_F6, QApplicationPrivate::KB_Win}, @@ -750,7 +752,9 @@ QKeySequence::QKeySequence(StandardKey key) */ QKeySequence::QKeySequence() { - d = new QKeySequencePrivate(); + static QKeySequencePrivate shared_empty; + d = &shared_empty; + d->ref.ref(); } /*! diff --git a/src/gui/kernel/qlayout.cpp b/src/gui/kernel/qlayout.cpp index 07c017d..4f1f52f 100644 --- a/src/gui/kernel/qlayout.cpp +++ b/src/gui/kernel/qlayout.cpp @@ -147,7 +147,12 @@ QLayout::QLayout(QLayoutPrivate &dd, QLayout *lay, QWidget *w) } else { d->topLevel = true; w->d_func()->layout = this; - invalidate(); + QT_TRY { + invalidate(); + } QT_CATCH(...) { + w->d_func()->layout = 0; + QT_RETHROW; + } } } } @@ -232,7 +237,12 @@ QLayout::QLayout(QWidget *parent, int margin, int spacing, const char *name) } else { d->topLevel = true; parent->d_func()->layout = this; - invalidate(); + QT_TRY { + invalidate(); + } QT_CATCH(...) { + parent->d_func()->layout = 0; + QT_RETHROW; + } } } } diff --git a/src/gui/kernel/qshortcutmap.cpp b/src/gui/kernel/qshortcutmap.cpp index 0027deb..585a7e1 100644 --- a/src/gui/kernel/qshortcutmap.cpp +++ b/src/gui/kernel/qshortcutmap.cpp @@ -146,9 +146,8 @@ public: QShortcutMap constructor. */ QShortcutMap::QShortcutMap() + : d_ptr(new QShortcutMapPrivate(this)) { - d_ptr = new QShortcutMapPrivate(this); - Q_ASSERT(d_ptr != 0); resetState(); } @@ -157,8 +156,6 @@ QShortcutMap::QShortcutMap() */ QShortcutMap::~QShortcutMap() { - delete d_ptr; - d_ptr = 0; } /*! \internal diff --git a/src/gui/kernel/qshortcutmap_p.h b/src/gui/kernel/qshortcutmap_p.h index c04e79e..67dd55e 100644 --- a/src/gui/kernel/qshortcutmap_p.h +++ b/src/gui/kernel/qshortcutmap_p.h @@ -55,6 +55,7 @@ #include "QtGui/qkeysequence.h" #include "QtCore/qvector.h" +#include "QtCore/qscopedpointer.h" QT_BEGIN_NAMESPACE @@ -104,7 +105,7 @@ private: #ifndef QT_NO_ACTION bool correctContext(Qt::ShortcutContext context,QAction *a, QWidget *active_window) const; #endif - QShortcutMapPrivate *d_ptr; + QScopedPointer<QShortcutMapPrivate> d_ptr; QKeySequence::SequenceMatch find(QKeyEvent *e); QKeySequence::SequenceMatch matches(const QKeySequence &seq1, const QKeySequence &seq2) const; diff --git a/src/gui/kernel/qsound.cpp b/src/gui/kernel/qsound.cpp index e5c263b..7a16acf 100644 --- a/src/gui/kernel/qsound.cpp +++ b/src/gui/kernel/qsound.cpp @@ -153,6 +153,9 @@ public: \o Qt for Embedded Linux \o A built-in mixing sound server is used, accessing \c /dev/dsp directly. Only the WAVE format is supported. + \o Symbian + \o CMdaAudioPlayerUtility is used. All formats that Symbian OS or devices support + are supported also by Qt. \endtable Note that QSound does not support \l{resources.html}{resources}. diff --git a/src/gui/kernel/qsound_s60.cpp b/src/gui/kernel/qsound_s60.cpp new file mode 100644 index 0000000..b654567 --- /dev/null +++ b/src/gui/kernel/qsound_s60.cpp @@ -0,0 +1,206 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + + +#ifndef QT_NO_SOUND + +#include "qdir.h" +#include "qapplication.h" +#include "qsound.h" +#include "qsound_p.h" +#include "qfileinfo.h" +#include <private/qcore_symbian_p.h> + +#include <e32std.h> +#include <MdaAudioSamplePlayer.h> + +QT_BEGIN_NAMESPACE + +class QAuServerS60; + +class QAuBucketS60 : public QAuBucket, public MMdaAudioPlayerCallback +{ +public: + QAuBucketS60( QAuServerS60 *server, QSound *sound); + ~QAuBucketS60(); + + void play(); + void stop(); + + inline QSound* sound() const { return m_sound; } + +public: // from MMdaAudioPlayerCallback + void MapcInitComplete(TInt aError, const TTimeIntervalMicroSeconds& aDuration); + void MapcPlayComplete(TInt aError); + +private: + QSound *m_sound; + QAuServerS60 *m_server; + bool m_prepared; + bool m_playCalled; + CMdaAudioPlayerUtility* m_playUtility; +}; + + +class QAuServerS60 : public QAuServer +{ +public: + QAuServerS60( QObject* parent ); + + void init( QSound* s ) + { + QAuBucketS60 *bucket = new QAuBucketS60( this, s ); + setBucket( s, bucket ); + } + + void play( QSound* s ) + { + bucket( s )->play(); + } + + void stop( QSound* s ) + { + bucket( s )->stop(); + } + + bool okay() { return true; } + +protected: + void playCompleted(QAuBucketS60* bucket, int error) + { + QSound *sound = bucket->sound(); + if(!error) { + // We need to handle repeats by ourselves, since with Symbian API we don't + // know how many loops have been played when user asks it + if( decLoop( sound ) ) { + play( sound ); + } + } else { + // We don't have a way to inform about errors -> just decrement loops + // in order that QSound::isFinished will return true; + while(decLoop(sound)) {} + } + } + +protected: + QAuBucketS60* bucket( QSound *s ) + { + return (QAuBucketS60*)QAuServer::bucket( s ); + } + + friend class QAuBucketS60; + +}; + +QAuServerS60::QAuServerS60(QObject* parent) : + QAuServer(parent) +{ + setObjectName(QLatin1String("QAuServerS60")); +} + + +QAuServer* qt_new_audio_server() +{ + return new QAuServerS60(qApp); +} + +QAuBucketS60::QAuBucketS60( QAuServerS60 *server, QSound *sound ) + : m_sound( sound ), m_server( server ), m_prepared(false), m_playCalled(false) +{ + QString filepath = QFileInfo( m_sound->fileName() ).absoluteFilePath(); + filepath = QDir::toNativeSeparators(filepath); + TPtrC filepathPtr(qt_QString2TPtrC(filepath)); + TRAPD(err, m_playUtility = CMdaAudioPlayerUtility::NewL(*this); + m_playUtility->OpenFileL(filepathPtr)); + if(err){ + m_server->playCompleted(this, err); + } +} + +void QAuBucketS60::play() +{ + if(m_prepared) { + // OpenFileL call is completed we can start playing immediately + m_playUtility->Play(); + } else { + m_playCalled = true; + } + +} + +void QAuBucketS60::stop() +{ + m_playCalled = false; + m_playUtility->Stop(); +} + +void QAuBucketS60::MapcPlayComplete(TInt aError) +{ + m_server->playCompleted(this, aError); +} + +void QAuBucketS60::MapcInitComplete(TInt aError, const TTimeIntervalMicroSeconds& /*aDuration*/) +{ + if(aError) { + m_server->playCompleted(this, aError); + } else { + m_prepared = true; + if(m_playCalled){ + play(); + } + } +} + +QAuBucketS60::~QAuBucketS60() +{ + if(m_playUtility){ + m_playUtility->Stop(); + m_playUtility->Close(); + } + + delete m_playUtility; +} + + +#endif // QT_NO_SOUND + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qstandardgestures.cpp b/src/gui/kernel/qstandardgestures.cpp index 10689ba..d798d32 100644 --- a/src/gui/kernel/qstandardgestures.cpp +++ b/src/gui/kernel/qstandardgestures.cpp @@ -69,42 +69,35 @@ QWidgetPrivate *qt_widget_private(QWidget *widget); On some platform like Windows it's necessary to provide a non-null widget as \a parent to get native gesture support. */ -QPanGesture::QPanGesture(QWidget *parent) - : QGesture(*new QPanGesturePrivate, parent) +QPanGesture::QPanGesture(QWidget *gestureTarget, QObject *parent) + : QGesture(*new QPanGesturePrivate, gestureTarget, parent) { - if (parent) { - QApplicationPrivate *qAppPriv = QApplicationPrivate::instance(); - qAppPriv->widgetGestures[parent].pan = this; -#ifdef Q_WS_WIN - qt_widget_private(parent)->winSetupGestures(); -#endif - } } -/*! \internal */ -bool QPanGesture::event(QEvent *event) +void QPanGesturePrivate::setupGestureTarget(QObject *newGestureTarget) { - switch (event->type()) { - case QEvent::ParentAboutToChange: - if (QWidget *w = qobject_cast<QWidget*>(parent())) { - QApplicationPrivate::instance()->widgetGestures[w].pan = 0; + Q_Q(QPanGesture); + if (gestureTarget && gestureTarget->isWidgetType()) { + QWidget *w = static_cast<QWidget*>(gestureTarget.data()); + QApplicationPrivate::instance()->widgetGestures[w].pan = 0; #ifdef Q_WS_WIN - qt_widget_private(w)->winSetupGestures(); + qt_widget_private(w)->winSetupGestures(); #endif - } - break; - case QEvent::ParentChange: - if (QWidget *w = qobject_cast<QWidget*>(parent())) { - QApplicationPrivate::instance()->widgetGestures[w].pan = this; + } + + if (newGestureTarget && newGestureTarget->isWidgetType()) { + QWidget *w = static_cast<QWidget*>(newGestureTarget); + QApplicationPrivate::instance()->widgetGestures[w].pan = q; #ifdef Q_WS_WIN - qt_widget_private(w)->winSetupGestures(); + qt_widget_private(w)->winSetupGestures(); #endif - } - break; - default: - break; } + QGesturePrivate::setupGestureTarget(newGestureTarget); +} +/*! \internal */ +bool QPanGesture::event(QEvent *event) +{ #if defined(Q_OS_MAC) && !defined(QT_MAC_USE_COCOA) Q_D(QPanGesture); if (event->type() == QEvent::Timer) { @@ -179,27 +172,29 @@ bool QPanGesture::filterEvent(QEvent *event) d->lastOffset = d->totalOffset = QSize(); } else if (event->type() == QEvent::TouchEnd) { if (state() != Qt::NoGesture) { - if (!ev->touchPoints().isEmpty()) { - QTouchEvent::TouchPoint p = ev->touchPoints().at(0); - const QPoint pos = p.pos().toPoint(); - const QPoint lastPos = p.lastPos().toPoint(); - const QPoint startPos = p.startPos().toPoint(); - d->lastOffset = QSize(pos.x() - lastPos.x(), pos.y() - lastPos.y()); - d->totalOffset = QSize(pos.x() - startPos.x(), pos.y() - startPos.y()); + if (ev->touchPoints().size() == 2) { + QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0); + QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1); + d->lastOffset = + QSize(p1.pos().x() - p1.lastPos().x() + p2.pos().x() - p2.lastPos().x(), + p1.pos().y() - p1.lastPos().y() + p2.pos().y() - p2.lastPos().y()) / 2; + d->totalOffset += d->lastOffset; } updateState(Qt::GestureFinished); } reset(); } else if (event->type() == QEvent::TouchUpdate) { - QTouchEvent::TouchPoint p = ev->touchPoints().at(0); - const QPoint pos = p.pos().toPoint(); - const QPoint lastPos = p.lastPos().toPoint(); - const QPoint startPos = p.startPos().toPoint(); - d->lastOffset = QSize(pos.x() - lastPos.x(), pos.y() - lastPos.y()); - d->totalOffset = QSize(pos.x() - startPos.x(), pos.y() - startPos.y()); - if (d->totalOffset.width() > 10 || d->totalOffset.height() > 10 || - d->totalOffset.width() < -10 || d->totalOffset.height() < -10) { - updateState(Qt::GestureUpdated); + if (ev->touchPoints().size() == 2) { + QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0); + QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1); + d->lastOffset = + QSize(p1.pos().x() - p1.lastPos().x() + p2.pos().x() - p2.lastPos().x(), + p1.pos().y() - p1.lastPos().y() + p2.pos().y() - p2.lastPos().y()) / 2; + d->totalOffset += d->lastOffset; + if (d->totalOffset.width() > 10 || d->totalOffset.height() > 10 || + d->totalOffset.width() < -10 || d->totalOffset.height() < -10) { + updateState(Qt::GestureUpdated); + } } } #ifdef Q_OS_MAC @@ -287,41 +282,35 @@ QSize QPanGesture::lastOffset() const On some platform like Windows it's necessary to provide a non-null widget as \a parent to get native gesture support. */ -QPinchGesture::QPinchGesture(QWidget *parent) - : QGesture(*new QPinchGesturePrivate, parent) +QPinchGesture::QPinchGesture(QWidget *gestureTarget, QObject *parent) + : QGesture(*new QPinchGesturePrivate, gestureTarget, parent) { - if (parent) { - QApplicationPrivate *qAppPriv = QApplicationPrivate::instance(); - qAppPriv->widgetGestures[parent].pinch = this; -#ifdef Q_WS_WIN - qt_widget_private(parent)->winSetupGestures(); -#endif - } } -/*! \internal */ -bool QPinchGesture::event(QEvent *event) +void QPinchGesturePrivate::setupGestureTarget(QObject *newGestureTarget) { - switch (event->type()) { - case QEvent::ParentAboutToChange: - if (QWidget *w = qobject_cast<QWidget*>(parent())) { - QApplicationPrivate::instance()->widgetGestures[w].pinch = 0; + Q_Q(QPinchGesture); + if (gestureTarget && gestureTarget->isWidgetType()) { + QWidget *w = static_cast<QWidget*>(gestureTarget.data()); + QApplicationPrivate::instance()->widgetGestures[w].pinch = 0; #ifdef Q_WS_WIN - qt_widget_private(w)->winSetupGestures(); + qt_widget_private(w)->winSetupGestures(); #endif - } - break; - case QEvent::ParentChange: - if (QWidget *w = qobject_cast<QWidget*>(parent())) { - QApplicationPrivate::instance()->widgetGestures[w].pinch = this; + } + + if (newGestureTarget && newGestureTarget->isWidgetType()) { + QWidget *w = static_cast<QWidget*>(newGestureTarget); + QApplicationPrivate::instance()->widgetGestures[w].pinch = q; #ifdef Q_WS_WIN - qt_widget_private(w)->winSetupGestures(); + qt_widget_private(w)->winSetupGestures(); #endif - } - break; - default: - break; } + QGesturePrivate::setupGestureTarget(newGestureTarget); +} + +/*! \internal */ +bool QPinchGesture::event(QEvent *event) +{ return QObject::event(event); } @@ -399,6 +388,7 @@ bool QPinchGesture::eventFilter(QObject *receiver, QEvent *event) return QGesture::eventFilter(receiver, event); } + /*! \internal */ bool QPinchGesture::filterEvent(QEvent *event) { diff --git a/src/gui/kernel/qstandardgestures.h b/src/gui/kernel/qstandardgestures.h index 8b5421b..0eb9d92 100644 --- a/src/gui/kernel/qstandardgestures.h +++ b/src/gui/kernel/qstandardgestures.h @@ -63,7 +63,7 @@ class Q_GUI_EXPORT QPanGesture : public QGesture Q_PROPERTY(QSize lastOffset READ lastOffset) public: - QPanGesture(QWidget *parent); + QPanGesture(QWidget *gestureTarget, QObject *parent = 0); bool filterEvent(QEvent *event); @@ -97,7 +97,7 @@ class Q_GUI_EXPORT QPinchGesture : public QGesture Q_PROPERTY(QPoint centerPoint READ centerPoint) public: - QPinchGesture(QWidget *parent); + QPinchGesture(QWidget *gestureTarget, QObject *parent = 0); bool filterEvent(QEvent *event); void reset(); diff --git a/src/gui/kernel/qstandardgestures_p.h b/src/gui/kernel/qstandardgestures_p.h index c52d16b..5fbcc5d 100644 --- a/src/gui/kernel/qstandardgestures_p.h +++ b/src/gui/kernel/qstandardgestures_p.h @@ -76,6 +76,8 @@ public: #endif } + void setupGestureTarget(QObject *o); + QSize totalOffset; QSize lastOffset; QPoint lastPosition; @@ -98,6 +100,9 @@ public: #endif { } + + void setupGestureTarget(QObject *o); + qreal scaleFactor; qreal lastScaleFactor; qreal rotationAngle; diff --git a/src/gui/kernel/qt_s60_p.h b/src/gui/kernel/qt_s60_p.h new file mode 100644 index 0000000..1523bcf --- /dev/null +++ b/src/gui/kernel/qt_s60_p.h @@ -0,0 +1,291 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT_S60_P_H +#define QT_S60_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "QtGui/qwindowdefs.h" +#include "private/qcore_symbian_p.h" +#include "qhash.h" +#include "qpoint.h" +#include "QtGui/qfont.h" +#include "QtGui/qimage.h" +#include "QtGui/qevent.h" +#include "qpointer.h" +#include <w32std.h> +#include <coecntrl.h> +#include <eikenv.h> +#include <eikappui.h> + +#ifdef Q_WS_S60 +#include <aknutils.h> // AknLayoutUtils +#include <avkon.hrh> // EEikStatusPaneUidTitle +#include <akntitle.h> // CAknTitlePane +#include <akncontext.h> // CAknContextPane +#include <eikspane.h> // CEikStatusPane +#endif + +QT_BEGIN_NAMESPACE + +// Application internal HandleResourceChangeL events, +// system evens seems to start with 0x10 +const TInt KInternalStatusPaneChange = 0x50000000; + +class QS60Data +{ +public: + TUid uid; + int screenDepth; + QPoint lastCursorPos; + QPoint lastPointerEventPos; + QPointer<QWidget> lastPointerEventTarget; + QPointer<QWidget> mousePressTarget; + int screenWidthInPixels; + int screenHeightInPixels; + int screenWidthInTwips; + int screenHeightInTwips; + int defaultDpiX; + int defaultDpiY; + static inline void updateScreenSize(); + static inline RWsSession& wsSession(); + static inline RWindowGroup& windowGroup(); + static inline CWsScreenDevice* screenDevice(); + static inline CCoeAppUi* appUi(); +#ifdef Q_WS_S60 + static inline CEikStatusPane* statusPane(); + static inline CCoeControl* statusPaneSubPane(TInt aPaneId); + static inline CAknTitlePane* titlePane(); + static inline CAknContextPane* contextPane(); + static inline CEikButtonGroupContainer* buttonGroupContainer(); +#endif +}; + +QS60Data* qGlobalS60Data(); +#define S60 qGlobalS60Data() + +class QAbstractLongTapObserver +{ +public: + virtual void HandleLongTapEventL( const TPoint& aPenEventLocation, + const TPoint& aPenEventScreenLocation ) = 0; +}; +class QLongTapTimer; + +class QSymbianControl : public CCoeControl, public QAbstractLongTapObserver +{ +public: + DECLARE_TYPE_ID(0x51740000) // Fun fact: the two first values are "Qt" in ASCII. + +public: + QSymbianControl(QWidget *w); + void ConstructL(bool topLevel = false, bool desktop = false); + ~QSymbianControl(); + void HandleResourceChange(int resourceType); + void HandlePointerEventL(const TPointerEvent& aPointerEvent); + TKeyResponse OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType); +#if !defined(QT_NO_IM) && defined(Q_WS_S60) + TCoeInputCapabilities InputCapabilities() const; +#endif + TTypeUid::Ptr MopSupplyObject(TTypeUid id); + + inline QWidget* widget() const { return qwidget; }; + void setWidget(QWidget *w); + void sendInputEvent(QWidget *widget, QInputEvent *inputEvent); + void setIgnoreFocusChanged(bool enabled) { m_ignoreFocusChanged = enabled; } + void CancelLongTapTimer(); + +protected: + void Draw(const TRect& aRect) const; + void SizeChanged(); + void PositionChanged(); + void FocusChanged(TDrawNow aDrawNow); + +private: + void HandlePointerEvent(const TPointerEvent& aPointerEvent); + TKeyResponse OfferKeyEvent(const TKeyEvent& aKeyEvent,TEventCode aType); + TKeyResponse sendKeyEvent(QWidget *widget, QKeyEvent *keyEvent); + bool sendMouseEvent(QWidget *widget, QMouseEvent *mEvent); + void HandleLongTapEventL( const TPoint& aPenEventLocation, const TPoint& aPenEventScreenLocation ); + +private: + QWidget *qwidget; + bool m_ignoreFocusChanged; + QLongTapTimer* m_longTapDetector; + bool m_previousEventLongTap; +}; + +inline void QS60Data::updateScreenSize() +{ + TPixelsTwipsAndRotation params; + int mode = S60->screenDevice()->CurrentScreenMode(); + S60->screenDevice()->GetScreenModeSizeAndRotation(mode, params); + S60->screenWidthInPixels = params.iPixelSize.iWidth; + S60->screenHeightInPixels = params.iPixelSize.iHeight; + S60->screenWidthInTwips = params.iTwipsSize.iWidth; + S60->screenHeightInTwips = params.iTwipsSize.iHeight; + + TReal inches = S60->screenHeightInTwips / (TReal)KTwipsPerInch; + S60->defaultDpiY = S60->screenHeightInPixels / inches; + inches = S60->screenWidthInTwips / (TReal)KTwipsPerInch; + S60->defaultDpiX = S60->screenWidthInPixels / inches; +} + +inline RWsSession& QS60Data::wsSession() +{ + return CCoeEnv::Static()->WsSession(); +} + +inline RWindowGroup& QS60Data::windowGroup() +{ + return CCoeEnv::Static()->RootWin(); +} + +inline CWsScreenDevice* QS60Data::screenDevice() +{ + return CCoeEnv::Static()->ScreenDevice(); +} + +inline CCoeAppUi* QS60Data::appUi() +{ + return CCoeEnv::Static()-> AppUi(); +} + +#ifdef Q_WS_S60 +inline CEikStatusPane* QS60Data::statusPane() +{ + return CEikonEnv::Static()->AppUiFactory()->StatusPane(); +} + +// Returns the application's status pane control, if not present returns NULL. +inline CCoeControl* QS60Data::statusPaneSubPane( TInt aPaneId ) +{ + const TUid paneUid = { aPaneId }; + CEikStatusPane* statusPane = S60->statusPane(); + if (statusPane && statusPane->PaneCapabilities(paneUid).IsPresent()) { + CCoeControl* control = NULL; + // ControlL shouldn't leave because the pane is present + TRAPD(err, control = statusPane->ControlL(paneUid)); + return err != KErrNone ? NULL : control; + } + return NULL; +} + +// Returns the application's title pane, if not present returns NULL. +inline CAknTitlePane* QS60Data::titlePane() +{ + return static_cast<CAknTitlePane*>(S60->statusPaneSubPane(EEikStatusPaneUidTitle)); +} + +// Returns the application's title pane, if not present returns NULL. +inline CAknContextPane* QS60Data::contextPane() +{ + return static_cast<CAknContextPane*>(S60->statusPaneSubPane(EEikStatusPaneUidContext)); +} + +inline CEikButtonGroupContainer* QS60Data::buttonGroupContainer() +{ + return CEikonEnv::Static()->AppUiFactory()->Cba(); +} +#endif // Q_WS_S60 + +static inline QFont qt_TFontSpec2QFontL(const TFontSpec &fontSpec) +{ + return QFont( + qt_TDesC2QString(fontSpec.iTypeface.iName), + fontSpec.iHeight / KTwipsPerPoint, + fontSpec.iFontStyle.StrokeWeight() == EStrokeWeightNormal ? QFont::Normal : QFont::Bold, + fontSpec.iFontStyle.Posture() == EPostureItalic + ); +} + +static inline QImage::Format qt_TDisplayMode2Format(TDisplayMode mode) +{ + QImage::Format format; + switch(mode) { + case EGray2: + format = QImage::Format_MonoLSB; + break; + case EColor256: + case EGray256: + format = QImage::Format_Indexed8; + break; + case EColor4K: + format = QImage::Format_RGB444; + break; + case EColor64K: + format = QImage::Format_RGB16; + break; + case EColor16M: + format = QImage::Format_RGB666; + break; + case EColor16MU: + format = QImage::Format_RGB32; + break; + case EColor16MA: + format = QImage::Format_ARGB32; + break; +#if !defined(__SERIES60_31__) && !defined(__S60_32__) + case EColor16MAP: + format = QImage::Format_ARGB32_Premultiplied; + break; +#endif + default: + format = QImage::Format_Invalid; + break; + } + return format; +} + + +QT_END_NAMESPACE + +#endif // QT_S60_P_H diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index 515eed9..6ffac2c 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -101,6 +101,10 @@ #endif #include <private/qpaintengine_raster_p.h> +#if defined(Q_OS_SYMBIAN) +#include "private/qt_s60_p.h" +#endif + #include "qwidget_p.h" #include "qaction_p.h" #include "qlayout_p.h" @@ -182,6 +186,7 @@ QWidgetPrivate::QWidgetPrivate(int version) , widgetItem(0) , extraPaintEngine(0) , polished(0) + , graphicsEffect(0) , inheritedFontResolveMask(0) , inheritedPaletteResolveMask(0) , leftmargin(0) @@ -212,6 +217,7 @@ QWidgetPrivate::QWidgetPrivate(int version) , window_event(0) , qd_hd(0) #endif + ,imHints(Qt::ImhNone) { if (!qApp) { qFatal("QWidget: Must construct a QApplication before a QPaintDevice"); @@ -237,6 +243,8 @@ QWidgetPrivate::~QWidgetPrivate() if (extra) deleteExtra(); + + delete graphicsEffect; } QWindowSurface *QWidgetPrivate::createDefaultWindowSurface() @@ -402,6 +410,7 @@ void QWidget::setEditFocus(bool on) QApplication::sendEvent(f, &event); QApplication::sendEvent(f->style(), &event); } + f->repaint(); // Widget might want to repaint a focus indicator } #endif @@ -890,10 +899,34 @@ void QWidget::setAutoFillBackground(bool enabled) \endlist \sa QEvent, QPainter, QGridLayout, QBoxLayout + + \section1 SoftKeys + \since 4.6 + \preliminary + + Softkeys API is a platform independent way of mapping actions to (hardware)keys + and toolbars provided by the underlying platform. + + There are three major use cases supported. First one is a mobile device + with keypad navigation and no touch ui. Second use case is a mobile + device with touch ui. Third use case is desktop. For now the softkey API is + only implemented for Series60. + + QActions are set to widget(s) via softkey API. Actions in focused widget are + mapped to native toolbar or hardware keys. Even though the API allows to set + any amount of widgets there might be physical restrictions to amount of + softkeys that can be used by the device. + + \o Series60: For series60 menu button is automatically mapped to left + soft key if there is QMainWindow with QMenuBar in widgets parent hierarchy. + + \sa softKeys() + \sa setSoftKey() + */ -QWidgetMapper *QWidgetPrivate::mapper = 0; // widget with wid -QWidgetSet *QWidgetPrivate::uncreatedWidgets = 0; // widgets with no wid +QWidgetMapper *QWidgetPrivate::mapper = 0; // widget with wid +QWidgetSet *QWidgetPrivate::allWidgets = 0; // widgets with no wid /***************************************************************************** @@ -933,6 +966,23 @@ QRegion qt_dirtyRegion(QWidget *widget) \endlist */ +struct QWidgetExceptionCleaner +{ + /* this cleans up when the constructor throws an exception */ + static inline void cleanup(QWidget *that, QWidgetPrivate *d) + { +#ifndef QT_NO_EXCEPTIONS + QWidgetPrivate::allWidgets->remove(that); + if (d->focus_next != that) { + if (d->focus_next) + d->focus_next->d_func()->focus_prev = d->focus_prev; + if (d->focus_prev) + d->focus_prev->d_func()->focus_next = d->focus_next; + } +#endif + } +}; + /*! Constructs a widget which is a child of \a parent, with widget flags set to \a f. @@ -962,7 +1012,12 @@ QRegion qt_dirtyRegion(QWidget *widget) QWidget::QWidget(QWidget *parent, Qt::WindowFlags f) : QObject(*new QWidgetPrivate, 0), QPaintDevice() { - d_func()->init(parent, f); + QT_TRY { + d_func()->init(parent, f); + } QT_CATCH(...) { + QWidgetExceptionCleaner::cleanup(this, d_func()); + QT_RETHROW; + } } #ifdef QT3_SUPPORT @@ -973,8 +1028,13 @@ QWidget::QWidget(QWidget *parent, Qt::WindowFlags f) QWidget::QWidget(QWidget *parent, const char *name, Qt::WindowFlags f) : QObject(*new QWidgetPrivate, 0), QPaintDevice() { - d_func()->init(parent , f); - setObjectName(QString::fromAscii(name)); + QT_TRY { + d_func()->init(parent , f); + setObjectName(QString::fromAscii(name)); + } QT_CATCH(...) { + QWidgetExceptionCleaner::cleanup(this, d_func()); + QT_RETHROW; + } } #endif @@ -983,7 +1043,13 @@ QWidget::QWidget(QWidget *parent, const char *name, Qt::WindowFlags f) QWidget::QWidget(QWidgetPrivate &dd, QWidget* parent, Qt::WindowFlags f) : QObject(dd, 0), QPaintDevice() { - d_func()->init(parent, f); + Q_D(QWidget); + QT_TRY { + d->init(parent, f); + } QT_CATCH(...) { + QWidgetExceptionCleaner::cleanup(this, d_func()); + QT_RETHROW; + } } /*! @@ -1058,8 +1124,8 @@ void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f) if (QApplication::type() == QApplication::Tty) qFatal("QWidget: Cannot create a QWidget when no GUI is being used"); - Q_ASSERT(uncreatedWidgets); - uncreatedWidgets->insert(q); + Q_ASSERT(allWidgets); + allWidgets->insert(q); QWidget *desktopWidget = 0; if (parentWidget && parentWidget->windowType() == Qt::Desktop) { @@ -1265,7 +1331,7 @@ void QWidget::create(WId window, bool initializeWindow, bool destroyOldWindow) d->create_sys(window, initializeWindow, destroyOldWindow); // a real toplevel window needs a backing store - if (isWindow()) { + if (isWindow() && windowType() != Qt::Desktop) { delete d->topData()->backingStore; // QWidgetBackingStore will check this variable, hence it must be 0 d->topData()->backingStore = 0; @@ -1352,15 +1418,31 @@ QWidget::~QWidget() } #endif - clearFocus(); + QT_TRY { + clearFocus(); + } QT_CATCH(...) { + // swallow this problem because we are in a destructor + } d->setDirtyOpaqueRegion(); - if (isWindow() && isVisible() && internalWinId()) - d->close_helper(QWidgetPrivate::CloseNoEvent); + if (isWindow() && isVisible() && internalWinId()) { + QT_TRY { + d->close_helper(QWidgetPrivate::CloseNoEvent); + } QT_CATCH(...) { + // if we're out of memory, at least hide the window. + QT_TRY { + hide(); + } QT_CATCH(...) { + // and if that also doesn't work, then give up + } + } + } + #if defined(Q_WS_WIN) || defined(Q_WS_X11) - else if (!internalWinId() && isVisible()) + else if (!internalWinId() && isVisible()) { qApp->d_func()->sendSyntheticEnterLeave(this); + } #endif if (QWidgetBackingStore *bs = d->maybeBackingStore()) { @@ -1385,12 +1467,15 @@ QWidget::~QWidget() QApplication::removePostedEvents(this); - destroy(); // platform-dependent cleanup - + QT_TRY { + destroy(); // platform-dependent cleanup + } QT_CATCH(...) { + // if this fails we can't do anything about it but at least we are not allowed to throw. + } --QWidgetPrivate::instanceCounter; - if (QWidgetPrivate::uncreatedWidgets) // might have been deleted by ~QApplication - QWidgetPrivate::uncreatedWidgets->remove(this); + if (QWidgetPrivate::allWidgets) // might have been deleted by ~QApplication + QWidgetPrivate::allWidgets->remove(this); QEvent e(QEvent::Destroy); QCoreApplication::sendEvent(this, &e); @@ -1410,7 +1495,6 @@ void QWidgetPrivate::setWinId(WId id) // set widget identifier bool userDesktopWidget = qt_desktopWidget != 0 && qt_desktopWidget != q && q->windowType() == Qt::Desktop; if (mapper && data.winid && !userDesktopWidget) { mapper->remove(data.winid); - uncreatedWidgets->insert(q); } data.winid = id; @@ -1419,7 +1503,6 @@ void QWidgetPrivate::setWinId(WId id) // set widget identifier #endif if (mapper && id && !userDesktopWidget) { mapper->insert(data.winid, q); - uncreatedWidgets->remove(q); } } @@ -1548,9 +1631,9 @@ bool QWidgetPrivate::isOverlapped(const QRect &rect) const continue; } - if (qRectIntersects(sibling->data->crect, r)) { + if (qRectIntersects(sibling->d_func()->effectiveRectFor(sibling->data->crect), r)) { const QWExtra *siblingExtra = sibling->d_func()->extra; - if (siblingExtra && siblingExtra->hasMask + if (siblingExtra && siblingExtra->hasMask && !sibling->d_func()->graphicsEffect && !siblingExtra->mask.translated(sibling->data->crect.topLeft()).intersects(r)) { continue; } @@ -1649,7 +1732,7 @@ QRect QWidgetPrivate::clipRect() const const QWidget * w = q; if (!w->isVisible()) return QRect(); - QRect r = q->rect(); + QRect r = effectiveRectFor(q->rect()); int ox = 0; int oy = 0; while (w @@ -1791,12 +1874,14 @@ void QWidgetPrivate::subtractOpaqueSiblings(QRegion &sourceRegion, bool *hasDirt break; QWidgetPrivate *pd = w->parentWidget()->d_func(); const int myIndex = pd->children.indexOf(const_cast<QWidget *>(w)); + const QRect widgetGeometry = w->d_func()->effectiveRectFor(w->data->crect); for (int i = myIndex + 1; i < pd->children.size(); ++i) { QWidget *sibling = qobject_cast<QWidget *>(pd->children.at(i)); if (!sibling || !sibling->isVisible() || sibling->isWindow()) continue; - if (!qRectIntersects(sibling->data->crect, w->data->crect)) + const QRect siblingGeometry = sibling->d_func()->effectiveRectFor(sibling->data->crect); + if (!qRectIntersects(siblingGeometry, widgetGeometry)) continue; if (dirtyClipBoundingRect) { @@ -1804,7 +1889,7 @@ void QWidgetPrivate::subtractOpaqueSiblings(QRegion &sourceRegion, bool *hasDirt dirtyClipBoundingRect = false; } - if (!qRectIntersects(sibling->data->crect, clipBoundingRect.translated(parentOffset))) + if (!qRectIntersects(siblingGeometry, clipBoundingRect.translated(parentOffset))) continue; if (dirtyParentClip) { @@ -1816,7 +1901,8 @@ void QWidgetPrivate::subtractOpaqueSiblings(QRegion &sourceRegion, bool *hasDirt const QRect siblingClipRect(sibling->d_func()->clipRect()); QRegion siblingDirty(parentClip); siblingDirty &= (siblingClipRect.translated(siblingPos)); - const bool hasMask = sibling->d_func()->extra && sibling->d_func()->extra->hasMask; + const bool hasMask = sibling->d_func()->extra && sibling->d_func()->extra->hasMask + && !sibling->d_func()->graphicsEffect; if (hasMask) siblingDirty &= sibling->d_func()->extra->mask.translated(siblingPos); if (siblingDirty.isEmpty()) @@ -1827,7 +1913,7 @@ void QWidgetPrivate::subtractOpaqueSiblings(QRegion &sourceRegion, bool *hasDirt siblingDirty.translate(-parentOffset); sourceRegion -= siblingDirty; } else { - sourceRegion -= sibling->data->crect.translated(-parentOffset); + sourceRegion -= siblingGeometry.translated(-parentOffset); } } else { if (hasDirtySiblingsAbove) @@ -1858,6 +1944,11 @@ void QWidgetPrivate::clipToEffectiveMask(QRegion ®ion) const const QWidget *w = q; QPoint offset; + if (graphicsEffect) { + w = q->parentWidget(); + offset -= data.crect.topLeft(); + } + while (w) { const QWidgetPrivate *wd = w->d_func(); if (wd->extra && wd->extra->hasMask) @@ -1891,6 +1982,12 @@ void QWidgetPrivate::updateIsOpaque() // hw: todo: only needed if opacity actually changed setDirtyOpaqueRegion(); + if (graphicsEffect) { + // ### We should probably add QGraphicsEffect::isOpaque at some point. + setOpaque(false); + return; + } + Q_Q(QWidget); #ifdef Q_WS_X11 if (q->testAttribute(Qt::WA_X11OpenGLOverlay)) { @@ -1938,6 +2035,9 @@ void QWidgetPrivate::setOpaque(bool opaque) #ifdef Q_WS_WIN winUpdateIsOpaque(); #endif +#ifdef Q_OS_SYMBIAN + s60UpdateIsOpaque(); +#endif } void QWidgetPrivate::updateIsTranslucent() @@ -1951,6 +2051,9 @@ void QWidgetPrivate::updateIsTranslucent() #ifdef Q_WS_WIN winUpdateIsOpaque(); #endif +#ifdef Q_OS_SYMBIAN + s60UpdateIsOpaque(); +#endif } /*! @@ -1985,10 +2088,17 @@ static inline void fillRegion(QPainter *painter, const QRegion &rgn, const QBrus extern void qt_mac_fill_background(QPainter *painter, const QRegion &rgn, const QBrush &brush); qt_mac_fill_background(painter, rgn, brush); #else - const QRect rect(rgn.boundingRect()); - painter->setClipRegion(rgn); - painter->drawTiledPixmap(rect, brush.texture(), rect.topLeft()); -#endif +#if !defined(QT_NO_STYLE_S60) + // Defined in qs60style.cpp + extern bool qt_s60_fill_background(QPainter *painter, const QRegion &rgn, const QBrush &brush); + if (!qt_s60_fill_background(painter, rgn, brush)) +#endif // !defined(QT_NO_STYLE_S60) + { + const QRect rect(rgn.boundingRect()); + painter->setClipRegion(rgn); + painter->drawTiledPixmap(rect, brush.texture(), rect.topLeft()); + } +#endif // Q_WS_MAC } else { const QVector<QRect> &rects = rgn.rects(); for (int i = 0; i < rects.size(); ++i) @@ -2006,7 +2116,7 @@ void QWidgetPrivate::paintBackground(QPainter *painter, const QRegion &rgn, int //If we are painting the viewport of a scrollarea, we must apply an offset to the brush in case we are drawing a texture QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea *>(parent); if (scrollArea && scrollArea->viewport() == q) { - QObjectData *scrollPrivate = static_cast<QWidget *>(scrollArea)->d_ptr; + QObjectData *scrollPrivate = static_cast<QWidget *>(scrollArea)->d_ptr.data(); QAbstractScrollAreaPrivate *priv = static_cast<QAbstractScrollAreaPrivate *>(scrollPrivate); oldBrushOrigin = painter->brushOrigin(); resetBrushOrigin = true; @@ -2581,7 +2691,7 @@ bool QWidget::isMaximized() const */ Qt::WindowStates QWidget::windowState() const { - return (Qt::WindowStates)data->window_state; + return Qt::WindowStates(data->window_state); } /*!\internal @@ -2593,7 +2703,7 @@ Qt::WindowStates QWidget::windowState() const */ void QWidget::overrideWindowState(Qt::WindowStates newstate) { - QWindowStateChangeEvent e((Qt::WindowStates)data->window_state, true); + QWindowStateChangeEvent e(Qt::WindowStates(data->window_state), true); data->window_state = newstate; QApplication::sendEvent(this, &e); } @@ -4604,8 +4714,9 @@ void QWidget::setCursor(const QCursor &cursor) #endif { d->createExtra(); + QCursor *newCursor = new QCursor(cursor); delete d->extra->curs; - d->extra->curs = new QCursor(cursor); + d->extra->curs = newCursor; } setAttribute(Qt::WA_SetCursor); d->setCursor_sys(cursor); @@ -4847,6 +4958,61 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset, d->extra->inRenderWithPainter = false; } +#if !defined(Q_OS_SYMBIAN) +void QWidgetPrivate::setSoftKeys_sys(const QList<QAction*> &softkeys) +{ + Q_UNUSED(softkeys) +} +#endif // !defined(Q_OS_SYMBIAN) + +QGraphicsEffect *QWidget::graphicsEffect() const +{ + Q_D(const QWidget); + return d->graphicsEffect; +} + +/*! + Sets \a effect as the widget's effect. If there already is an effect installed + on this widget, QWidget will delete the existing effect before installing + the new \a effect. + + If \a effect is the installed on a different widget, setGraphicsEffect() will remove + the effect from the widget and install it on this widget. + + \note This function will apply the effect on itself and all its children. + + \since 4.6 +*/ +void QWidget::setGraphicsEffect(QGraphicsEffect *effect) +{ + Q_D(QWidget); + if (d->graphicsEffect == effect) + return; + + if (d->graphicsEffect && effect) { + delete d->graphicsEffect; + d->graphicsEffect = 0; + } + + if (!effect) { + // Unset current effect. + QGraphicsEffectPrivate *oldEffectPrivate = d->graphicsEffect->d_func(); + d->graphicsEffect = 0; + if (oldEffectPrivate) { + oldEffectPrivate->setGraphicsEffectSource(0); // deletes the current source. + } + } else { + // Set new effect. + QGraphicsEffectSourcePrivate *sourced = new QWidgetEffectSourcePrivate(this); + QGraphicsEffectSource *source = new QGraphicsEffectSource(*sourced); + d->graphicsEffect = effect; + effect->d_func()->setGraphicsEffectSource(source); + } + + d->updateIsOpaque(); + update(); +} + bool QWidgetPrivate::isAboutToShow() const { if (data.in_show) @@ -4991,6 +5157,33 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP return; Q_Q(QWidget); + if (graphicsEffect && graphicsEffect->isEnabled()) { + QGraphicsEffectSource *source = graphicsEffect->d_func()->source; + QWidgetEffectSourcePrivate *sourced = static_cast<QWidgetEffectSourcePrivate *> + (source->d_func()); + if (!sourced->context) { + QWidgetPaintContext context(pdev, rgn, offset, flags, sharedPainter, backingStore); + sourced->context = &context; + if (!sharedPainter) { + QPaintEngine *paintEngine = pdev->paintEngine(); + paintEngine->d_func()->systemClip = rgn.translated(offset); + QPainter p(pdev); + p.translate(offset); + context.painter = &p; + graphicsEffect->draw(&p, source); + paintEngine->d_func()->systemClip = QRegion(); + } else { + context.painter = sharedPainter; + sharedPainter->save(); + sharedPainter->translate(offset); + graphicsEffect->draw(sharedPainter, source); + sharedPainter->restore(); + } + sourced->context = 0; + return; + } + } + const bool asRoot = flags & DrawAsRoot; const bool alsoOnScreen = flags & DrawPaintOnScreen; const bool recursive = flags & DrawRecursive; @@ -5023,7 +5216,7 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP if (sharedPainter) paintEngine->d_func()->systemClip = toBePainted; else - paintEngine->setSystemRect(q->data->crect); + paintEngine->d_func()->systemRect = q->data->crect; //paint the background if ((asRoot || q->autoFillBackground() || onScreen || q->testAttribute(Qt::WA_StyledBackground)) @@ -5062,7 +5255,7 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP if (paintEngine) { restoreRedirected(); if (!sharedPainter) - paintEngine->setSystemRect(QRect()); + paintEngine->d_func()->systemRect = QRect(); else paintEngine->d_func()->currentClipWidget = 0; paintEngine->d_func()->systemClip = QRegion(); @@ -5125,7 +5318,7 @@ void QWidgetPrivate::paintSiblingsRecursive(QPaintDevice *pdev, const QObjectLis dirtyBoundingRect = false; } - if (qRectIntersects(boundingRect, x->data->crect)) { + if (qRectIntersects(boundingRect, x->d_func()->effectiveRectFor(x->data->crect))) { #ifdef Q_BACKINGSTORE_SUBSURFACES if (x->windowSurface() == currentSurface) #endif @@ -5143,7 +5336,7 @@ void QWidgetPrivate::paintSiblingsRecursive(QPaintDevice *pdev, const QObjectLis QWidgetPrivate *wd = w->d_func(); const QPoint widgetPos(w->data->crect.topLeft()); - const bool hasMask = wd->extra && wd->extra->hasMask; + const bool hasMask = wd->extra && wd->extra->hasMask && !wd->graphicsEffect; if (index > 0) { QRegion wr(rgn); @@ -5158,7 +5351,7 @@ void QWidgetPrivate::paintSiblingsRecursive(QPaintDevice *pdev, const QObjectLis if (w->updatesEnabled() && (!w->d_func()->extra || !w->d_func()->extra->proxyWidget)) { QRegion wRegion(rgn); - wRegion &= w->data->crect; + wRegion &= wd->effectiveRectFor(w->data->crect); wRegion.translate(-widgetPos); if (hasMask) wRegion &= wd->extra->mask; @@ -5166,6 +5359,93 @@ void QWidgetPrivate::paintSiblingsRecursive(QPaintDevice *pdev, const QObjectLis } } +QRectF QWidgetEffectSourcePrivate::boundingRect(Qt::CoordinateSystem system) const +{ + if (system != Qt::DeviceCoordinates) + return m_widget->rect(); + + if (!context) { + // Device coordinates without context not yet supported. + qWarning("QGraphicsEffectSource::boundingRect: Not yet implemented, lacking device context"); + return QRectF(); + } + + return context->painter->worldTransform().mapRect(m_widget->rect()); +} + +void QWidgetEffectSourcePrivate::draw(QPainter *painter) +{ + if (!context || context->painter != painter) { + m_widget->render(painter); + return; + } + + // The region saved in the context is neither clipped to the rect + // nor the mask, so we have to clip it here before calling drawWidget. + QRegion toBePainted = context->rgn; + toBePainted &= m_widget->rect(); + QWidgetPrivate *wd = qt_widget_private(m_widget); + if (wd->extra && wd->extra->hasMask) + toBePainted &= wd->extra->mask; + + wd->drawWidget(context->pdev, toBePainted, context->offset, context->flags, + context->sharedPainter, context->backingStore); +} + +QPixmap QWidgetEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint *offset) const +{ + const bool deviceCoordinates = (system == Qt::DeviceCoordinates); + if (!context && deviceCoordinates) { + // Device coordinates without context not yet supported. + qWarning("QGraphicsEffectSource::pixmap: Not yet implemented, lacking device context"); + return QPixmap(); + } + + QPoint pixmapOffset; + QRectF sourceRect = m_widget->rect(); + + if (deviceCoordinates) { + const QTransform &painterTransform = context->painter->worldTransform(); + sourceRect = painterTransform.mapRect(sourceRect); + pixmapOffset = painterTransform.map(pixmapOffset); + } + + QRect effectRect = m_widget->graphicsEffect()->boundingRectFor(sourceRect).toAlignedRect(); + if (offset) + *offset = effectRect.topLeft(); + + if (deviceCoordinates) { + // Clip to device rect. + int left, top, right, bottom; + effectRect.getCoords(&left, &top, &right, &bottom); + if (left < 0) { + if (offset) + offset->rx() += -left; + effectRect.setX(0); + } + if (top < 0) { + if (offset) + offset->ry() += -top; + effectRect.setY(0); + } + // NB! We use +-1 for historical reasons (see QRect documentation). + QPaintDevice *device = context->painter->device(); + const int deviceWidth = device->width(); + const int deviceHeight = device->height(); + if (right + 1 > deviceWidth) + effectRect.setRight(deviceWidth - 1); + if (bottom + 1 > deviceHeight) + effectRect.setBottom(deviceHeight -1); + } + + pixmapOffset -= effectRect.topLeft(); + + QPixmap pixmap(effectRect.size()); + pixmap.fill(Qt::transparent); + m_widget->render(&pixmap, pixmapOffset); + return pixmap; +} + /*! \internal @@ -5299,6 +5579,17 @@ QString QWidget::windowTitle() const return QString(); } +/*! + Returns a modified window title with the [*] place holder + replaced according to the rules described in QWidget::setWindowTitle + + This function assumes that "[*]" can be quoted by another + "[*]", so it will replace two place holders by one and + a single last one by either "*" or nothing depending on + the modified flag. + + \internal +*/ QString qt_setWindowTitle_helperHelper(const QString &title, const QWidget *widget) { Q_ASSERT(widget); @@ -5310,16 +5601,21 @@ QString qt_setWindowTitle_helperHelper(const QString &title, const QWidget *widg QString cap = title; #endif - QString placeHolder(QLatin1String("[*]")); + if (cap.isEmpty()) + return cap; + + QLatin1String placeHolder("[*]"); + int placeHolderLength = 3; // QLatin1String doesn't have length() int index = cap.indexOf(placeHolder); + // here the magic begins while (index != -1) { - index += placeHolder.length(); + index += placeHolderLength; int count = 1; while (cap.indexOf(placeHolder, index) == index) { ++count; - index += placeHolder.length(); + index += placeHolderLength; } if (count%2) { // odd number of [*] -> replace last one @@ -5334,7 +5630,7 @@ QString qt_setWindowTitle_helperHelper(const QString &title, const QWidget *widg index = cap.indexOf(placeHolder, index); } - cap.replace(QLatin1String("[*][*]"), QLatin1String("[*]")); + cap.replace(QLatin1String("[*][*]"), placeHolder); return cap; } @@ -5935,6 +6231,10 @@ bool QWidget::isActiveWindow() const if(qt_mac_is_macdrawer(tlw) && tlw->parentWidget() && tlw->parentWidget()->isActiveWindow()) return true; + + extern bool qt_mac_insideKeyWindow(const QWidget *); //qwidget_mac.cpp + if (QApplication::testAttribute(Qt::AA_MacPluginApplication) && qt_mac_insideKeyWindow(tlw)) + return true; #endif if(style()->styleHint(QStyle::SH_Widget_ShareActivation, 0, this)) { if(tlw->windowType() == Qt::Tool && @@ -6726,7 +7026,7 @@ void QWidgetPrivate::show_helper() // On Windows, show the popup now so that our own focus handling // stores the correct old focus widget even if it's stolen in the // showevent -#if defined(Q_WS_WIN) || defined(Q_WS_MAC) +#if defined(Q_WS_WIN) || defined(Q_WS_MAC) || defined(Q_OS_SYMBIAN) if (!isEmbedded && q->windowType() == Qt::Popup) qApp->d_func()->openPopup(q); #endif @@ -6743,7 +7043,7 @@ void QWidgetPrivate::show_helper() show_sys(); -#if !defined(Q_WS_WIN) && !defined(Q_WS_MAC) +#if !defined(Q_WS_WIN) && !defined(Q_WS_MAC) && !defined(Q_OS_SYMBIAN) if (!isEmbedded && q->windowType() == Qt::Popup) qApp->d_func()->openPopup(q); #endif @@ -7315,7 +7615,7 @@ QSize QWidgetPrivate::adjustedSize() const #else // all others QRect screen = QApplication::desktop()->screenGeometry(q->pos()); #endif -#if defined (Q_WS_WINCE) +#if defined (Q_WS_WINCE) || defined (Q_OS_SYMBIAN) s.setWidth(qMin(s.width(), screen.width())); s.setHeight(qMin(s.height(), screen.height())); #else @@ -7626,6 +7926,7 @@ bool QWidget::event(QEvent *event) } break; case QEvent::FocusIn: + d->setSoftKeys_sys(softKeys()); focusInEvent((QFocusEvent*)event); break; @@ -7775,6 +8076,10 @@ bool QWidget::event(QEvent *event) if (w && w->isVisible() && !w->isWindow()) QApplication::sendEvent(w, event); } + + if (isWindow() && isActiveWindow()) + d->setSoftKeys_sys(softKeys()); + break; } case QEvent::LanguageChange: @@ -7941,6 +8246,12 @@ bool QWidget::event(QEvent *event) (void) QApplication::sendEvent(this, &mouseEvent); break; } + case QEvent::SymbianDeferredFocusChanged: { +#ifdef Q_OS_SYMBIAN + d->handleSymbianDeferredFocusChanged(); +#endif + break; + } #ifndef QT_NO_PROPERTIES case QEvent::DynamicPropertyChange: { const QByteArray &propName = static_cast<QDynamicPropertyChangeEvent *>(event)->propertyName(); @@ -8489,7 +8800,7 @@ void QWidget::inputMethodEvent(QInputMethodEvent *event) \a query specifies which property is queried. - \sa inputMethodEvent(), QInputMethodEvent, QInputContext + \sa inputMethodEvent(), QInputMethodEvent, QInputContext, inputMethodHints */ QVariant QWidget::inputMethodQuery(Qt::InputMethodQuery query) const { @@ -8498,11 +8809,54 @@ QVariant QWidget::inputMethodQuery(Qt::InputMethodQuery query) const return QRect(width()/2, 0, 1, height()); case Qt::ImFont: return font(); + case Qt::ImAnchorPosition: + // Fallback. + return inputMethodQuery(Qt::ImCursorPosition); default: return QVariant(); } } +/*! + \property QWidget::inputMethodHints + \brief What input method specific hints the widget has. + + This is only relevant for input widgets. It is used by + the input method to retrieve hints as to how the input method + should operate. For example, if the Qt::ImhFormattedNumbersOnly flag + is set, the input method may change its visual components to reflect + that only numbers can be entered. + + \note The flags are only hints, so the particular input method + implementation is free to ignore them. If you want to be + sure that a certain type of characters are entered, + you should also set a QValidator on the widget. + + The default value is Qt::ImhNone. + + \since 4.6 + + \sa inputMethodQuery(), QInputContext +*/ +Qt::InputMethodHints QWidget::inputMethodHints() const +{ + Q_D(const QWidget); + return d->imHints; +} + +void QWidget::setInputMethodHints(Qt::InputMethodHints hints) +{ + Q_D(QWidget); + d->imHints = hints; + // Optimisation to update input context only it has already been created. + if (d->ic || qApp->d_func()->inputContext) { + QInputContext *ic = inputContext(); + if (ic) + ic->update(); + } +} + + #ifndef QT_NO_DRAGANDDROP /*! @@ -10313,7 +10667,7 @@ void QWidget::setShortcutAutoRepeat(int id, bool enable) */ void QWidget::updateMicroFocus() { -#if !defined(QT_NO_IM) && (defined(Q_WS_X11) || defined(Q_WS_QWS)) +#if !defined(QT_NO_IM) && (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)) Q_D(QWidget); // and optimisation to update input context only it has already been created. if (d->ic || qApp->d_func()->inputContext) { @@ -11445,6 +11799,68 @@ void QWidget::clearMask() setMask(QRegion()); } +/*! + \preliminary + \since 4.6 + + Returns the (possibly empty) list of this widget's softkeys. + Returned list cannot be changed. Softkeys should be added + and removed via method called setSoftKeys + + \sa setSoftKey(), setSoftKeys() +*/ +const QList<QAction*>& QWidget::softKeys() const +{ + Q_D(const QWidget); + if( d->softKeys.count() > 0) + return d->softKeys; + if (isWindow() || !parentWidget()) + return d->softKeys; + + return parentWidget()->softKeys(); +} + +/*! + \preliminary + \since 4.6 + + Sets the softkey \a softkey to this widget's list of softkeys, + Setting 0 as softkey will clear all the existing softkeys set + to the widget + A QWidget can have 0 or more softkeys + + \sa softKeys(), setSoftKeys() +*/ +void QWidget::setSoftKey(QAction *softKey) +{ + Q_D(QWidget); + qDeleteAll(d->softKeys); + d->softKeys.clear(); + if (softKey) + d->softKeys.append(softKey); + if ((!QApplication::focusWidget() && this == QApplication::activeWindow()) + || QApplication::focusWidget() == this) + d->setSoftKeys_sys(this->softKeys()); +} + +/*! + Sets the list of softkeys \a softkeys to this widget's list of softkeys, + A QWidget can have 0 or more softkeys + + \sa softKeys(), setSoftKey() +*/ +void QWidget::setSoftKeys(const QList<QAction*> &softKeys) +{ + Q_D(QWidget); + qDeleteAll(d->softKeys); + d->softKeys.clear(); + d->softKeys = softKeys; + + if ((!QApplication::focusWidget() && this == QApplication::activeWindow()) + || QApplication::focusWidget() == this) + d->setSoftKeys_sys(this->softKeys()); +} + /*! \fn const QX11Info &QWidget::x11Info() const Returns information about the configuration of the X display used to display the widget. diff --git a/src/gui/kernel/qwidget.h b/src/gui/kernel/qwidget.h index 6f30883..2484ba6 100644 --- a/src/gui/kernel/qwidget.h +++ b/src/gui/kernel/qwidget.h @@ -96,6 +96,7 @@ class QWindowSurface; class QLocale; class QGraphicsProxyWidget; class QGestureManager; +class QGraphicsEffect; #if defined(Q_WS_X11) class QX11Info; #endif @@ -213,6 +214,7 @@ class Q_GUI_EXPORT QWidget : public QObject, public QPaintDevice #endif Q_PROPERTY(QLocale locale READ locale WRITE setLocale RESET unsetLocale) Q_PROPERTY(QString windowFilePath READ windowFilePath WRITE setWindowFilePath DESIGNABLE isWindow) + Q_PROPERTY(Qt::InputMethodHints inputMethodHints READ inputMethodHints WRITE setInputMethodHints) public: enum RenderFlag { @@ -352,6 +354,9 @@ public: const QRegion &sourceRegion = QRegion(), RenderFlags renderFlags = RenderFlags(DrawWindowBackground | DrawChildren)); + QGraphicsEffect *graphicsEffect() const; + void setGraphicsEffect(QGraphicsEffect *effect); + public Q_SLOTS: void setWindowTitle(const QString &); #ifndef QT_NO_STYLE_STYLESHEET @@ -555,6 +560,9 @@ public: void removeAction(QAction *action); QList<QAction*> actions() const; #endif + const QList<QAction*>& softKeys() const; + void setSoftKey(QAction *softKey); + void setSoftKeys(const QList<QAction*> &softKeys); QWidget *parentWidget() const; @@ -675,6 +683,10 @@ protected: virtual void inputMethodEvent(QInputMethodEvent *); public: virtual QVariant inputMethodQuery(Qt::InputMethodQuery) const; + + Qt::InputMethodHints inputMethodHints() const; + void setInputMethodHints(Qt::InputMethodHints hints); + protected: void resetInputContext(); protected Q_SLOTS: @@ -725,6 +737,7 @@ private: friend class QGraphicsProxyWidget; friend class QGraphicsProxyWidgetPrivate; friend class QStyleSheetStyle; + friend struct QWidgetExceptionCleaner; #ifdef Q_WS_MAC friend class QCoreGraphicsPaintEnginePrivate; @@ -746,6 +759,10 @@ private: friend bool isWidgetOpaque(const QWidget *); friend class QGLWidgetPrivate; #endif +#ifdef Q_OS_SYMBIAN + friend class QSymbianControl; + friend class QS60WindowSurface; +#endif #ifdef Q_WS_X11 friend void qt_net_update_user_time(QWidget *tlw, unsigned long timestamp); friend void qt_net_remove_user_time(QWidget *tlw); diff --git a/src/gui/kernel/qwidget_mac.mm b/src/gui/kernel/qwidget_mac.mm index 71571e4..53d1b6e 100644 --- a/src/gui/kernel/qwidget_mac.mm +++ b/src/gui/kernel/qwidget_mac.mm @@ -301,6 +301,14 @@ bool qt_mac_is_macdrawer(const QWidget *w) return (w && w->parentWidget() && w->windowType() == Qt::Drawer); } +bool qt_mac_insideKeyWindow(const QWidget *w) +{ +#ifdef QT_MAC_USE_COCOA + return [[reinterpret_cast<NSView *>(w->winId()) window] isKeyWindow]; +#endif + return false; +} + bool qt_mac_set_drawer_preferred_edge(QWidget *w, Qt::DockWidgetArea where) //users of Qt for Mac OS X can use this.. { if(!qt_mac_is_macdrawer(w)) @@ -2567,7 +2575,7 @@ void QWidget::destroy(bool destroyWindow, bool destroySubWindows) { Q_D(QWidget); if (!isWindow() && parentWidget()) - parentWidget()->d_func()->invalidateBuffer(geometry()); + parentWidget()->d_func()->invalidateBuffer(d->effectiveRectFor(geometry())); d->deactivateWidgetCleanup(); qt_mac_event_release(this); if(testAttribute(Qt::WA_WState_Created)) { @@ -2618,7 +2626,11 @@ void QWidget::destroy(bool destroyWindow, bool destroySubWindows) qt_mac_destructWindow(window); } } - d->setWinId(0); + QT_TRY { + d->setWinId(0); + } QT_CATCH (const std::bad_alloc &) { + // swallow - destructors must not throw + } } } @@ -2669,7 +2681,7 @@ void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f) OSViewRef old_id = 0; if (q->isVisible() && q->parentWidget() && parent != q->parentWidget()) - q->parentWidget()->d_func()->invalidateBuffer(q->geometry()); + q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(q->geometry())); // Maintain the glWidgets list on parent change: remove "our" gl widgets // from the list on the old parent and grandparents. @@ -4165,12 +4177,12 @@ void QWidgetPrivate::setGeometry_sys_helper(int x, int y, int w, int h, bool isM setWSGeometry(false, oldRect); if (isResize && QApplicationPrivate::graphicsSystem()) { invalidateBuffer(q->rect()); - if (extra && !extra->mask.isEmpty()) { + if (extra && !graphicsEffect && !extra->mask.isEmpty()) { QRegion oldRegion(extra->mask.translated(oldp)); oldRegion &= oldRect; q->parentWidget()->d_func()->invalidateBuffer(oldRegion); } else { - q->parentWidget()->d_func()->invalidateBuffer(oldRect); + q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(oldRect)); } } } diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index a3f4f6f..ed0abce 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -61,6 +61,8 @@ #include "QtGui/qregion.h" #include "QtGui/qsizepolicy.h" #include "QtGui/qstyle.h" +#include "QtGui/qapplication.h" +#include <private/qgraphicseffect_p.h> #ifdef Q_WS_WIN #include "QtCore/qt_windows.h" @@ -80,6 +82,14 @@ #include "QtGui/qscreen_qws.h" #endif +#if defined(Q_OS_SYMBIAN) +class RDrawableWindow; +class CCoeControl; +// The following 2 defines may only be needed for s60. To be seen. +const int SOFTKEYSTART=5000; +const int SOFTKEYEND=5004; +#endif + QT_BEGIN_NAMESPACE // Extra QWidget data @@ -162,6 +172,9 @@ struct QTLWExtra { #ifndef QT_NO_QWS_MANAGER QWSManager *qwsManager; #endif +#elif defined(Q_OS_SYMBIAN) // <--------------------------------------------------------- SYMBIAN + uint activated : 1; // RWindowBase::Activated has been called + RDrawableWindow *rwindow; #endif }; @@ -243,6 +256,7 @@ public: explicit QWidgetPrivate(int version = QObjectPrivateVersion); ~QWidgetPrivate(); + void setSoftKeys_sys(const QList<QAction*> &softkeys); QWExtra *extraData() const; QTLWExtra *topData() const; QTLWExtra *maybeTopData() const; @@ -269,6 +283,10 @@ public: QPalette naturalWidgetPalette(uint inheritedMask) const; void setMask_sys(const QRegion &); +#ifdef Q_OS_SYMBIAN + void handleSymbianDeferredFocusChanged(); +#endif + void raise_sys(); void lower_sys(); void stackUnder_sys(QWidget *); @@ -443,8 +461,28 @@ public: return extra ? extra->nativeChildrenForced : false; } + inline QRect effectiveRectFor(const QRect &rect) const + { + if (graphicsEffect && graphicsEffect->isEnabled()) + return graphicsEffect->boundingRectFor(rect).toAlignedRect(); + return rect; + } + QSize adjustedSize() const; + inline void handleSoftwareInputPanel(Qt::MouseButton button, bool clickCausedFocus) + { + Q_Q(QWidget); + if (button == Qt::LeftButton && qApp->autoSipEnabled()) { + QStyle::RequestSoftwareInputPanel behavior = QStyle::RequestSoftwareInputPanel( + q->style()->styleHint(QStyle::SH_RequestSoftwareInputPanel)); + if (!clickCausedFocus || behavior == QStyle::RSIP_OnMouseClick) { + QEvent event(QEvent::RequestSoftwareInputPanel); + QApplication::sendEvent(q, &event); + } + } + } + #ifndef Q_WS_QWS // Almost cross-platform :-) void setWSGeometry(bool dontShow=false, const QRect &oldRect = QRect()); @@ -467,18 +505,22 @@ public: QWidget *focus_next; QWidget *focus_prev; QWidget *focus_child; + QList<QAction*> softKeys; QLayout *layout; QRegion *needsFlush; QPaintDevice *redirectDev; QWidgetItemV2 *widgetItem; QPaintEngine *extraPaintEngine; mutable const QMetaObject *polished; - // All widgets are initially added into the uncreatedWidgets set. Once - // they receive a window id they are removed and added to the mapper + QGraphicsEffect *graphicsEffect; + // All widgets are added into the allWidgets set. Once + // they receive a window id they are also added to the mapper. + // This should just ensure that all widgets are deleted by QApplication static QWidgetMapper *mapper; - static QWidgetSet *uncreatedWidgets; + static QWidgetSet *allWidgets; #if !defined(QT_NO_IM) QPointer<QInputContext> ic; + Qt::InputMethodHints imHints; #endif #ifdef QT_KEYPAD_NAVIGATION static QPointer<QWidget> editingWidget; @@ -639,7 +681,64 @@ public: void updateCursor() const; #endif QScreen* getScreen() const; +#elif defined(Q_OS_SYMBIAN) // <--------------------------------------------------------- SYMBIAN + static QWidget *mouseGrabber; + static QWidget *keyboardGrabber; + void s60UpdateIsOpaque(); + void reparentChildren(); #endif + +}; + +struct QWidgetPaintContext +{ + inline QWidgetPaintContext(QPaintDevice *d, const QRegion &r, const QPoint &o, int f, + QPainter *p, QWidgetBackingStore *b) + : pdev(d), rgn(r), offset(o), flags(f), sharedPainter(p), backingStore(b), painter(0) {} + + QPaintDevice *pdev; + QRegion rgn; + QPoint offset; + int flags; + QPainter *sharedPainter; + QWidgetBackingStore *backingStore; + QPainter *painter; +}; + +class QWidgetEffectSourcePrivate : public QGraphicsEffectSourcePrivate +{ +public: + QWidgetEffectSourcePrivate(QWidget *widget) + : QGraphicsEffectSourcePrivate(), m_widget(widget), context(0) + {} + + inline void detach() + { m_widget->setGraphicsEffect(0); } + + inline const QGraphicsItem *graphicsItem() const + { return 0; } + + inline const QWidget *widget() const + { return m_widget; } + + inline void update() + { m_widget->update(); } + + inline bool isPixmap() const + { return false; } + + inline const QStyleOption *styleOption() const + { return 0; } + + inline QRect deviceRect() const + { return m_widget->window()->rect(); } + + QRectF boundingRect(Qt::CoordinateSystem system) const; + void draw(QPainter *p); + QPixmap pixmap(Qt::CoordinateSystem system, QPoint *offset) const; + + QWidget *m_widget; + QWidgetPaintContext *context; }; inline QWExtra *QWidgetPrivate::extraData() const diff --git a/src/gui/kernel/qwidget_qws.cpp b/src/gui/kernel/qwidget_qws.cpp index ea3cef2..f8ac252 100644 --- a/src/gui/kernel/qwidget_qws.cpp +++ b/src/gui/kernel/qwidget_qws.cpp @@ -258,7 +258,7 @@ void QWidget::destroy(bool destroyWindow, bool destroySubWindows) Q_D(QWidget); if (!isWindow() && parentWidget()) - parentWidget()->d_func()->invalidateBuffer(geometry()); + parentWidget()->d_func()->invalidateBuffer(d->effectiveRectFor(geometry())); d->deactivateWidgetCleanup(); if (testAttribute(Qt::WA_WState_Created)) { @@ -298,11 +298,16 @@ void QWidget::destroy(bool destroyWindow, bool destroySubWindows) d->hide_sys(); } if (destroyWindow && isWindow()) { - d->extra->topextra->backingStore->windowSurface->setGeometry(QRect()); + if (d->extra && d->extra->topextra && d->extra->topextra->backingStore) + d->extra->topextra->backingStore->windowSurface->setGeometry(QRect()); qwsDisplay()->destroyRegion(internalWinId()); } } - d->setWinId(0); + QT_TRY { + d->setWinId(0); + } QT_CATCH (const std::bad_alloc &) { + // swallow - destructors must not throw + } } } @@ -312,7 +317,7 @@ void QWidgetPrivate::setParent_sys(QWidget *newparent, Qt::WindowFlags f) Q_Q(QWidget); bool wasCreated = q->testAttribute(Qt::WA_WState_Created); if (q->isVisible() && q->parentWidget() && parent != q->parentWidget()) - q->parentWidget()->d_func()->invalidateBuffer(q->geometry()); + q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(q->geometry())); #ifndef QT_NO_CURSOR QCursor oldcurs; bool setcurs=q->testAttribute(Qt::WA_SetCursor); @@ -576,6 +581,15 @@ void QWidgetPrivate::show_sys() if (q->isWindow()) { + + if (!q->testAttribute(Qt::WA_ShowWithoutActivating) + && q->windowType() != Qt::Popup + && q->windowType() != Qt::Tool + && q->windowType() != Qt::ToolTip) { + QWidget::qwsDisplay()->requestFocus(data.winid,true); + } + + if (QWindowSurface *surface = q->windowSurface()) { const QRect frameRect = q->frameGeometry(); if (surface->geometry() != frameRect) @@ -592,12 +606,6 @@ void QWidgetPrivate::show_sys() #endif data.fstrut_dirty = true; invalidateBuffer(r); - if (!q->testAttribute(Qt::WA_ShowWithoutActivating) - && q->windowType() != Qt::Popup - && q->windowType() != Qt::Tool - && q->windowType() != Qt::ToolTip) { - QWidget::qwsDisplay()->requestFocus(data.winid,true); - } bool staysontop = (q->windowFlags() & Qt::WindowStaysOnTopHint) || q->windowType() == Qt::Popup; @@ -638,7 +646,8 @@ void QWidgetPrivate::hide_sys() q->releaseMouse(); // requestWindowRegion(QRegion()); - extra->topextra->backingStore->releaseBuffer(); + if (extra->topextra->backingStore) + extra->topextra->backingStore->releaseBuffer(); QWidget::qwsDisplay()->requestFocus(data.winid,false); @@ -805,7 +814,7 @@ void QWidgetPrivate::lower_sys() QWSChangeAltitudeCommand::Lower); } else if (QWidget *p = q->parentWidget()) { setDirtyOpaqueRegion(); - p->d_func()->invalidateBuffer(q->geometry()); + p->d_func()->invalidateBuffer(effectiveRectFor(q->geometry())); } } @@ -814,7 +823,7 @@ void QWidgetPrivate::stackUnder_sys(QWidget*) Q_Q(QWidget); if (QWidget *p = q->parentWidget()) { setDirtyOpaqueRegion(); - p->d_func()->invalidateBuffer(q->geometry()); + p->d_func()->invalidateBuffer(effectiveRectFor(q->geometry())); } } diff --git a/src/gui/kernel/qwidget_s60.cpp b/src/gui/kernel/qwidget_s60.cpp new file mode 100644 index 0000000..d28e2c0 --- /dev/null +++ b/src/gui/kernel/qwidget_s60.cpp @@ -0,0 +1,1206 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwidget_p.h" +#include "qdesktopwidget.h" +#include "qapplication.h" +#include "qapplication_p.h" +#include "private/qbackingstore_p.h" +#include "qevent.h" +#include "qt_s60_p.h" + +#include "qbitmap.h" +#include "private/qwindowsurface_s60_p.h" + +#include <qinputcontext.h> + +#ifdef Q_WS_S60 +#include <aknappui.h> +#endif + +QT_BEGIN_NAMESPACE + +extern bool qt_nograb(); + +QWidget *QWidgetPrivate::mouseGrabber = 0; +QWidget *QWidgetPrivate::keyboardGrabber = 0; + +static bool isEqual(const QList<QAction*>& a, const QList<QAction*>& b) +{ + if ( a.count() != b.count()) + return false; + int index=0; + while (index<a.count()) { + if (a.at(index)->softKeyRole() != b.at(index)->softKeyRole()) + return false; + if (a.at(index)->text().compare(b.at(index)->text())!=0) + return false; + index++; + } + return true; +} + + +void QWidgetPrivate::setSoftKeys_sys(const QList<QAction*> &softkeys) +{ +#ifdef Q_WS_S60 + Q_Q(QWidget); + if (QApplication::focusWidget() && q!=QApplication::focusWidget()) { + QList<QAction *> old = QApplication::focusWidget()->softKeys(); + if (isEqual(old, softkeys )) + return; + } + CEikButtonGroupContainer* nativeContainer = S60->buttonGroupContainer(); + QT_TRAP_THROWING(nativeContainer->SetCommandSetL(R_AVKON_SOFTKEYS_EMPTY_WITH_IDS)); + + int position = -1; + int command; + bool needsExitButton = true; + + for (int index = 0; index < softkeys.count(); index++) { + const QAction* softKeyAction = softkeys.at(index); + switch (softKeyAction->softKeyRole()) { + // Positive Actions go on LSK + case QAction::OptionsSoftKey: + case QAction::MenuSoftKey: + case QAction::ContextMenuSoftKey: + command = EAknSoftkeyOptions; //Calls DynInitMenuPane in AppUI + position = 0; + break; + case QAction::SelectSoftKey: + case QAction::PreviousSoftKey: + case QAction::OkSoftKey: + case QAction::EditSoftKey: + case QAction::ViewSoftKey: + case QAction::EndEditSoftKey: + case QAction::FinishSoftKey: + command = SOFTKEYSTART + index; + position = 0; + break; + // Negative Actions on the RSK + case QAction::BackSoftKey: + case QAction::NextSoftKey: + case QAction::CancelSoftKey: + case QAction::BackSpaceSoftKey: + case QAction::RevertEditSoftKey: + case QAction::DeselectSoftKey: + needsExitButton = false; + command = SOFTKEYSTART + index; + position = 2; + break; + case QAction::ExitSoftKey: + needsExitButton = false; + command = EAknSoftkeyExit; //Calls HandleCommand in AppUI + position = 2; + break; + default: + break; + } + + if (position != -1) { + TPtrC text = qt_QString2TPtrC(softKeyAction->text()); + QT_TRAP_THROWING(nativeContainer->SetCommandL(position, command, text)); + } + } + + if (needsExitButton) + QT_TRAP_THROWING(nativeContainer->SetCommandL(2, EAknSoftkeyExit, qt_QString2TPtrC(QObject::tr("Exit")))); + + nativeContainer->DrawDeferred(); // 3.1 needs an extra invitation +#else + Q_UNUSED(softkeys) +#endif +} + +void QWidgetPrivate::setWSGeometry(bool /* dontShow */, const QRect & /* rect */) +{ + +} + +void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove) +{ + Q_Q(QWidget); + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + + if ((q->windowType() == Qt::Desktop)) + return; + if (extra) { // any size restrictions? + w = qMin(w,extra->maxw); + h = qMin(h,extra->maxh); + w = qMax(w,extra->minw); + h = qMax(h,extra->minh); + } + + if (q->isWindow()) + topData()->normalGeometry = QRect(0, 0, -1, -1); + else { + uint s = data.window_state; + s &= ~(Qt::WindowMaximized | Qt::WindowFullScreen); + data.window_state = s; + } + + QPoint oldPos(q->pos()); + QSize oldSize(q->size()); + QRect oldGeom(data.crect); + + bool isResize = w != oldSize.width() || h != oldSize.height(); + if (!isMove && !isResize) + return; + + if (isResize) + data.window_state &= ~Qt::WindowMaximized; + + if(q->isWindow()) { + if (w == 0 || h == 0) { + q->setAttribute(Qt::WA_OutsideWSRange, true); + if (q->isVisible() && q->testAttribute(Qt::WA_Mapped)) + hide_sys(); + data.crect = QRect(x, y, w, h); + data.window_state &= ~Qt::WindowFullScreen; + } else if (q->isVisible() && q->testAttribute(Qt::WA_OutsideWSRange)) { + q->setAttribute(Qt::WA_OutsideWSRange, false); + + // put the window in its place and show it + q->internalWinId()->SetRect(TRect(TPoint(x, y), TSize(w, h))); + data.crect.setRect(x, y, w, h); + + show_sys(); + } else { + QRect r = QRect(x, y, w, h); + data.crect = r; + q->internalWinId()->SetRect(TRect(TPoint(x, y), TSize(w, h))); + topData()->normalGeometry = data.crect; + } + } else { + data.crect.setRect(x, y, w, h); + + QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData(); + const bool inTopLevelResize = tlwExtra ? tlwExtra->inTopLevelResize : false; + + if (q->isVisible() && (!inTopLevelResize || q->internalWinId())) { + // Top-level resize optimization does not work for native child widgets; + // disable it for this particular widget. + if (inTopLevelResize) + tlwExtra->inTopLevelResize = false; + if (!isResize && maybeBackingStore()) + moveRect(QRect(oldPos, oldSize), x - oldPos.x(), y - oldPos.y()); + else + invalidateBuffer_resizeHelper(oldPos, oldSize); + + if (inTopLevelResize) + tlwExtra->inTopLevelResize = true; + } + if (q->testAttribute(Qt::WA_WState_Created)) + setWSGeometry(); + } + + if (q->isVisible()) { + if (isMove && q->pos() != oldPos) { + QMoveEvent e(q->pos(), oldPos); + QApplication::sendEvent(q, &e); + } + if (isResize) { + bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt(); + const bool setTopLevelResize = !slowResize && q->isWindow() && extra && extra->topextra + && !extra->topextra->inTopLevelResize; + if (setTopLevelResize) + extra->topextra->inTopLevelResize = true; + QResizeEvent e(q->size(), oldSize); + QApplication::sendEvent(q, &e); + if (!q->testAttribute(Qt::WA_StaticContents) && q->internalWinId()) + q->internalWinId()->DrawDeferred(); + if (setTopLevelResize) + extra->topextra->inTopLevelResize = false; + } + } else { + if (isMove && q->pos() != oldPos) + q->setAttribute(Qt::WA_PendingMoveEvent, true); + if (isResize) + q->setAttribute(Qt::WA_PendingResizeEvent, true); + } +} + +void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool destroyOldWindow) +{ + Q_Q(QWidget); + + Qt::WindowType type = q->windowType(); + Qt::WindowFlags &flags = data.window_flags; + QWidget *parentWidget = q->parentWidget(); + + bool topLevel = (flags & Qt::Window); + bool popup = (type == Qt::Popup); + bool dialog = (type == Qt::Dialog + || type == Qt::Sheet + || (flags & Qt::MSWindowsFixedSizeDialogHint)); + bool desktop = (type == Qt::Desktop); + //bool tool = (type == Qt::Tool || type == Qt::Drawer); + + WId id = 0; + + if (popup) + flags |= Qt::WindowStaysOnTopHint; // a popup stays on top + + TRect clientRect = static_cast<CEikAppUi*>(S60->appUi())->ClientRect(); + int sw = clientRect.Width(); + int sh = clientRect.Height(); + + if (desktop) { + TSize screenSize = S60->screenDevice()->SizeInPixels(); + data.crect.setRect(0, 0, screenSize.iWidth, screenSize.iHeight); + q->setAttribute(Qt::WA_DontShowOnScreen); + } else if(topLevel && !q->testAttribute(Qt::WA_Resized)){ + int width = sw; + int height = sh; + if (extra) { + width = qMax(qMin(width, extra->maxw), extra->minw); + height = qMax(qMin(height, extra->maxh), extra->minh); + } + data.crect.setSize(QSize(width, height)); + } + + CCoeControl *destroyw = 0; + + createExtra(); + if(window) { + if (destroyOldWindow) + destroyw = data.winid; + id = window; + setWinId(window); + TRect tr = window->Rect(); + data.crect.setRect(tr.iTl.iX, tr.iTl.iY, tr.Width(), tr.Height()); + + } else if (topLevel) { + if (!q->testAttribute(Qt::WA_Moved) && !q->testAttribute(Qt::WA_DontShowOnScreen)) + data.crect.moveTopLeft(QPoint(clientRect.iTl.iX, clientRect.iTl.iY)); + QSymbianControl *control= q_check_ptr(new QSymbianControl(q)); + id = (WId)control; + setWinId(id); + QT_TRAP_THROWING(control->ConstructL(true,desktop)); + + if (!desktop) { + TInt stackingFlags; + if ((q->windowType() & Qt::Popup) == Qt::Popup) { + stackingFlags = ECoeStackFlagRefusesAllKeys | ECoeStackFlagRefusesFocus; + } else { + stackingFlags = ECoeStackFlagStandard; + } + QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control, ECoeStackPriorityDefault, stackingFlags)); + + QTLWExtra *topExtra = topData(); + topExtra->rwindow = control->DrawableWindow(); + // Request mouse move events. + topExtra->rwindow->PointerFilter(EPointerFilterEnterExit + | EPointerFilterMove | EPointerFilterDrag, 0); + topExtra->rwindow->EnableVisibilityChangeEvents(); + + if (!isOpaque) { + RWindow *rwindow = static_cast<RWindow*>(topExtra->rwindow); + TDisplayMode gotDM = (TDisplayMode)rwindow->SetRequiredDisplayMode(EColor16MA); + if (rwindow->SetTransparencyAlphaChannel() == KErrNone) + rwindow->SetBackgroundColor(TRgb(255, 255, 255, 0)); + } + } + + q->setAttribute(Qt::WA_WState_Created); + + int x, y, w, h; + data.crect.getRect(&x, &y, &w, &h); + control->SetRect(TRect(TPoint(x, y), TSize(w, h))); + } else if (q->testAttribute(Qt::WA_NativeWindow) || paintOnScreen()) { // create native child widget + QSymbianControl *control = new QSymbianControl(q); + setWinId(control); + QT_TRAP_THROWING(control->ConstructL(!parentWidget)); + + TInt stackingFlags; + if ((q->windowType() & Qt::Popup) == Qt::Popup) { + stackingFlags = ECoeStackFlagRefusesAllKeys | ECoeStackFlagRefusesFocus; + } else { + stackingFlags = ECoeStackFlagStandard; + } + QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control, ECoeStackPriorityDefault, stackingFlags)); + + WId parentw = parentWidget->effectiveWinId(); + QT_TRAP_THROWING(control->SetContainerWindowL(*parentw)); + + q->setAttribute(Qt::WA_WState_Created); + int x, y, w, h; + data.crect.getRect(&x, &y, &w, &h); + control->SetRect(TRect(TPoint(x, y), TSize(w, h))); + } + + if (destroyw) { + destroyw->ControlEnv()->AppUi()->RemoveFromStack(destroyw); + CBase::Delete(destroyw); + } +} + + +void QWidgetPrivate::show_sys() +{ + Q_Q(QWidget); + + if (q->testAttribute(Qt::WA_OutsideWSRange)) + return; + + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + + q->setAttribute(Qt::WA_Mapped); + + if (q->testAttribute(Qt::WA_DontShowOnScreen)) { + invalidateBuffer(q->rect()); + return; + } + + if (q->isWindow() && q->internalWinId()) { + + WId id = q->internalWinId(); + if (!extra->topextra->activated) { + QT_TRAP_THROWING(id->ActivateL()); + extra->topextra->activated = 1; + } + id->MakeVisible(true); + id->SetFocus(true); + + // Force setting of the icon after window is made visible, + // this is needed even WA_SetWindowIcon is not set, as in that case we need + // to reset to the application level window icon + setWindowIcon_sys(true); + } + + invalidateBuffer(q->rect()); +} + +void QWidgetPrivate::hide_sys() +{ + Q_Q(QWidget); + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + deactivateWidgetCleanup(); + WId id = q->internalWinId(); + if (q->isWindow() && id) { + if(id->IsFocused()) // Avoid unnecessary calls to FocusChanged() + id->SetFocus(false); + id->MakeVisible(false); + if (QWidgetBackingStore *bs = maybeBackingStore()) + bs->releaseBuffer(); + } else { + invalidateBuffer(q->rect()); + } + + q->setAttribute(Qt::WA_Mapped, false); +} + +void QWidgetPrivate::setFocus_sys() +{ + Q_Q(QWidget); + if (q->testAttribute(Qt::WA_WState_Created) && q->window()->windowType() != Qt::Popup) + if(!q->effectiveWinId()->IsFocused()) // Avoid unnecessry calls to FocusChanged() + q->effectiveWinId()->SetFocus(true); +} + +void QWidgetPrivate::handleSymbianDeferredFocusChanged() +{ + Q_Q(QWidget); + WId control = q->internalWinId(); + if (!control) { + // This could happen if the widget was reparented, while the focuschange + // was in the event queue. + return; + } + + if (control->IsFocused()) { + QApplication::setActiveWindow(q); +#ifdef Q_WS_S60 + // If widget is fullscreen, hide status pane and button container + // otherwise show them. + CEikStatusPane* statusPane = S60->statusPane(); + CEikButtonGroupContainer* buttonGroup = S60->buttonGroupContainer(); + bool isFullscreen = q->windowState() & Qt::WindowFullScreen; + if (statusPane && (statusPane->IsVisible() == isFullscreen)) + statusPane->MakeVisible(!isFullscreen); + if (buttonGroup && (buttonGroup->IsVisible() == isFullscreen)) + buttonGroup->MakeVisible(!isFullscreen); +#endif + } else { + QApplication::setActiveWindow(0); + } +} + +void QWidgetPrivate::raise_sys() +{ + Q_Q(QWidget); + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + QTLWExtra *tlwExtra = maybeTopData(); + if (q->internalWinId() && tlwExtra) { + tlwExtra->rwindow->SetOrdinalPosition(0); + } +} + +void QWidgetPrivate::lower_sys() +{ + Q_Q(QWidget); + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + QTLWExtra *tlwExtra = maybeTopData(); + if (q->internalWinId() && tlwExtra) { + tlwExtra->rwindow->SetOrdinalPosition(-1); + } + if(!q->isWindow()) + invalidateBuffer(q->rect()); +} + +void QWidgetPrivate::setModal_sys() +{ + +} + +void QWidgetPrivate::stackUnder_sys(QWidget* w) +{ + Q_Q(QWidget); + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + QTLWExtra *tlwExtra = maybeTopData(); + QTLWExtra *tlwExtraSibling = w->d_func()->maybeTopData(); + if (q->internalWinId() && tlwExtra && w->internalWinId() && tlwExtraSibling) + tlwExtra->rwindow->SetOrdinalPosition(tlwExtraSibling->rwindow->OrdinalPosition() + 1); + if(!q->isWindow() || !w->internalWinId()) + invalidateBuffer(q->rect()); +} + +void QWidgetPrivate::reparentChildren() +{ + Q_Q(QWidget); + QObjectList chlist = q->children(); + for (int i = 0; i < chlist.size(); ++i) { // reparent children + QObject *obj = chlist.at(i); + if (obj->isWidgetType()) { + QWidget *w = (QWidget *)obj; + if (!w->testAttribute(Qt::WA_WState_Created)) + continue; + if (!w->isWindow()) { + w->d_func()->invalidateBuffer(w->rect()); + WId parent = q->effectiveWinId(); + WId child = w->effectiveWinId(); + if (parent != child) + child->SetParent(parent); + // ### TODO: We probably also need to update the component array here + w->d_func()->reparentChildren(); + } else { + bool showIt = w->isVisible(); + QPoint old_pos = w->pos(); + w->setParent(q, w->windowFlags()); + w->move(old_pos); + if (showIt) + w->show(); + } + } + } +} + +void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f) +{ + Q_Q(QWidget); + bool wasCreated = q->testAttribute(Qt::WA_WState_Created); + + if (q->isVisible() && q->parentWidget() && parent != q->parentWidget()) + q->parentWidget()->d_func()->invalidateBuffer(q->geometry()); + + if (q->testAttribute(Qt::WA_DropSiteRegistered)) + q->setAttribute(Qt::WA_DropSiteRegistered, false); + + WId old_winid = wasCreated ? data.winid : 0; + if ((q->windowType() == Qt::Desktop)) + old_winid = 0; + setWinId(0); + + // hide and reparent our own window away. Otherwise we might get + // destroyed when emitting the child remove event below. See QWorkspace. + if (wasCreated && old_winid) { + old_winid->MakeVisible(false); + if(old_winid->IsFocused()) // Avoid unnecessary calls to FocusChanged() + old_winid->SetFocus(false); + old_winid->SetParent(0); + } + + QObjectPrivate::setParent_helper(parent); + bool explicitlyHidden = q->testAttribute(Qt::WA_WState_Hidden) && q->testAttribute(Qt::WA_WState_ExplicitShowHide); + + data.window_flags = f; + data.fstrut_dirty = true; + q->setAttribute(Qt::WA_WState_Created, false); + q->setAttribute(Qt::WA_WState_Visible, false); + q->setAttribute(Qt::WA_WState_Hidden, false); + adjustFlags(data.window_flags, q); + // keep compatibility with previous versions, we need to preserve the created state + // (but we recreate the winId for the widget being reparented, again for compatibility) + if (wasCreated || (!q->isWindow() && parent->testAttribute(Qt::WA_WState_Created))) + createWinId(); + if (q->isWindow() || (!parent || parent->isVisible()) || explicitlyHidden) + q->setAttribute(Qt::WA_WState_Hidden); + q->setAttribute(Qt::WA_WState_ExplicitShowHide, explicitlyHidden); + + if (wasCreated) + reparentChildren(); + + if (old_winid) { + CBase::Delete(old_winid); + } + + if (q->testAttribute(Qt::WA_AcceptDrops) + || (!q->isWindow() && q->parentWidget() && q->parentWidget()->testAttribute(Qt::WA_DropSiteRegistered))) + q->setAttribute(Qt::WA_DropSiteRegistered, true); + + invalidateBuffer(q->rect()); +} + +void QWidgetPrivate::setConstraints_sys() +{ + +} + + +void QWidgetPrivate::s60UpdateIsOpaque() +{ + Q_Q(QWidget); + + if (!q->testAttribute(Qt::WA_WState_Created) || !q->testAttribute(Qt::WA_TranslucentBackground)) + return; + + if ((data.window_flags & Qt::FramelessWindowHint) == 0) + return; + + if (!isOpaque) { + QTLWExtra *topExtra = topData(); + RWindow *rwindow = static_cast<RWindow*>(topExtra->rwindow); + TDisplayMode gotDM = (TDisplayMode)rwindow->SetRequiredDisplayMode(EColor16MA); + if (rwindow->SetTransparencyAlphaChannel() == KErrNone) + rwindow->SetBackgroundColor(TRgb(255, 255, 255, 0)); + } else { + QTLWExtra *topExtra = topData(); + RWindow *rwindow = static_cast<RWindow*>(topExtra->rwindow); + rwindow->SetTransparentRegion(TRegionFix<1>()); + } +} + +CFbsBitmap* qt_pixmapToNativeBitmap(QPixmap pixmap, bool invert) +{ + CFbsBitmap* fbsBitmap = q_check_ptr(new CFbsBitmap); // CBase derived object needs check on new + TSize size(pixmap.size().width(), pixmap.size().height()); + TDisplayMode mode(EColor16MU); + + bool isNull = pixmap.isNull(); + int depth = pixmap.depth(); + + // TODO: dummy assumptions from bit amounts for each color + // Will fix later on when native pixmap is implemented + switch(pixmap.depth()) { + case 1: + mode = EGray2; + break; + case 4: + mode = EColor16; + break; + case 8: + mode = EColor256; + break; + case 12: + mode = EColor4K; + break; + case 16: + mode = EColor64K; + break; + case 24: + mode = EColor16M; + break; + case 32: + case EColor16MU: + break; + default: + qFatal("Unsupported pixmap depth"); + break; + } + + qt_symbian_throwIfError(fbsBitmap->Create(size, mode)); + fbsBitmap->LockHeap(); + QImage image = pixmap.toImage(); + + if(invert) + image.invertPixels(); + + int height = pixmap.size().height(); + for(int i=0;i<height;i++ ) + { + TPtr8 scanline(image.scanLine(i), image.bytesPerLine(), image.bytesPerLine()); + fbsBitmap->SetScanLine( scanline, i ); + } + + fbsBitmap->UnlockHeap(); + return fbsBitmap; +} + +void QWidgetPrivate::setWindowIcon_sys(bool forceReset) +{ +#ifdef Q_WS_S60 + Q_Q(QWidget); + + if (!q->testAttribute(Qt::WA_WState_Created) || !q->isWindow() ) + return; + + QTLWExtra* topData = this->topData(); + if (topData->iconPixmap && !forceReset) + // already been set + return; + + TRect cPaneRect; + TBool found = AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::EContextPane, cPaneRect ); + CAknContextPane* contextPane = S60->contextPane(); + if (found && contextPane) { // We have context pane with valid metrics + QIcon icon = q->windowIcon(); + if (!icon.isNull()) { + // Valid icon -> set it as an context pane picture + QSize size = icon.actualSize(QSize(cPaneRect.Size().iWidth, cPaneRect.Size().iHeight)); + QPixmap pm = icon.pixmap(size); + QBitmap mask = pm.mask(); + if (mask.isNull()) { + mask = QBitmap(pm.size()); + mask.fill(Qt::color1); + } + + // Convert to CFbsBitmp + // TODO: When QPixmap is adapted to use native CFbsBitmap, + // it could be set directly to context pane + CFbsBitmap* nBitmap = qt_pixmapToNativeBitmap(pm, false); + CFbsBitmap* nMask = qt_pixmapToNativeBitmap(mask, true); + + contextPane->SetPicture(nBitmap,nMask); + } else { + // Icon set to null -> set context pane picture to default + QT_TRAP_THROWING(contextPane->SetPictureToDefaultL()); + } + } else { + // Context pane does not exist, try setting small icon to title pane + TRect titlePaneRect; + TBool found = AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::ETitlePane, titlePaneRect ); + CAknTitlePane* titlePane = S60->titlePane(); + if (found && titlePane) { // We have title pane with valid metrics + // The API to get title_pane graphics size is not public -> assume square space based + // on titlebar font height. CAknBitmap would be optimum, wihtout setting the size, since + // then title pane would automatically scale the bitmap. Unfortunately it is not public API + const CFont * font = AknLayoutUtils::FontFromId(EAknLogicalFontTitleFont); + TSize iconSize(font->HeightInPixels(), font->HeightInPixels()); + + QIcon icon = q->windowIcon(); + if (!icon.isNull()) { + // Valid icon -> set it as an title pane small picture + QSize size = icon.actualSize(QSize(iconSize.iWidth, iconSize.iHeight)); + QPixmap pm = icon.pixmap(size); + QBitmap mask = pm.mask(); + if (mask.isNull()) { + mask = QBitmap(pm.size()); + mask.fill(Qt::color1); + } + + // Convert to CFbsBitmp + // TODO: When QPixmap is adapted to use native CFbsBitmap, + // it could be set directly to context pane + CFbsBitmap* nBitmap = qt_pixmapToNativeBitmap(pm, false); + CFbsBitmap* nMask = qt_pixmapToNativeBitmap(mask, true); + + titlePane->SetSmallPicture( nBitmap, nMask, ETrue ); + } else { + // Icon set to null -> set context pane picture to default + titlePane->SetSmallPicture( NULL, NULL, EFalse ); + } + } + } + +#else + Q_UNUSED(forceReset) +#endif +} + +void QWidgetPrivate::setWindowTitle_sys(const QString &caption) +{ +#ifdef Q_WS_S60 + Q_Q(QWidget); + if (q->isWindow()) { + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + CAknTitlePane* titlePane = S60->titlePane(); + if(titlePane) { + if(caption.isEmpty()) { + QT_TRAP_THROWING(titlePane->SetTextToDefaultL()); + } else { + QT_TRAP_THROWING(titlePane->SetTextL(qt_QString2TPtrC(caption))); + } + } + } +#else + Q_UNUSED(caption) +#endif +} + +void QWidgetPrivate::setWindowIconText_sys(const QString & /*iconText */) +{ + +} + +void QWidgetPrivate::scroll_sys(int dx, int dy) +{ + Q_Q(QWidget); + + scrollChildren(dx, dy); + if (!paintOnScreen() || !q->internalWinId() || !q->internalWinId()->OwnsWindow()) { + scrollRect(q->rect(), dx, dy); + } else { + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + RDrawableWindow* rw = topData()->rwindow; + rw->Scroll(TPoint(dx, dy)); + } +} + +void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r) +{ + Q_Q(QWidget); + + if (!paintOnScreen() || !q->internalWinId() || !q->internalWinId()->OwnsWindow()) { + scrollRect(r, dx, dy); + } else { + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + RDrawableWindow* rw = topData()->rwindow; + rw->Scroll(TPoint(dx, dy), qt_QRect2TRect(r)); + } +} + +/*! + For this function to work in the emulator, you must add: + TRANSPARENCY + To a line in the wsini.ini file. +*/ +void QWidgetPrivate::setWindowOpacity_sys(qreal) +{ + // ### TODO: Implement uniform window transparency +} + +void QWidgetPrivate::updateFrameStrut() +{ + +} + +void QWidgetPrivate::updateSystemBackground() +{ + +} + +void QWidgetPrivate::registerDropSite(bool /* on */) +{ + +} + +void QWidgetPrivate::createTLSysExtra() +{ + extra->topextra->backingStore = 0; + extra->topextra->activated = 0; + extra->topextra->rwindow = 0; +} + +void QWidgetPrivate::deleteTLSysExtra() +{ + delete extra->topextra->backingStore; + extra->topextra->backingStore = 0; +} + +void QWidgetPrivate::createSysExtra() +{ + +} + +void QWidgetPrivate::deleteSysExtra() +{ + // this should only be non-zero if destroy() has not run due to constructor fail + if (data.winid) { + data.winid->ControlEnv()->AppUi()->RemoveFromStack(data.winid); + delete data.winid; + data.winid = 0; + } +} + +QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys() +{ + return new QS60WindowSurface(q_func()); +} + +void QWidgetPrivate::setMask_sys(const QRegion& /* region */) +{ + +} + +int QWidget::metric(PaintDeviceMetric m) const +{ + Q_D(const QWidget); + int val; + if (m == PdmWidth) { + val = data->crect.width(); + } else if (m == PdmHeight) { + val = data->crect.height(); + } else { + CWsScreenDevice *scr = S60->screenDevice(); + switch(m) { + case PdmDpiX: + case PdmPhysicalDpiX: + if (d->extra && d->extra->customDpiX) { + val = d->extra->customDpiX; + } else { + const QWidgetPrivate *p = d; + while (p->parent) { + p = static_cast<const QWidget *>(p->parent)->d_func(); + if (p->extra && p->extra->customDpiX) { + val = p->extra->customDpiX; + break; + } + } + if (p == d || !(p->extra && p->extra->customDpiX)) + val = S60->defaultDpiX; + } + break; + case PdmDpiY: + case PdmPhysicalDpiY: + if (d->extra && d->extra->customDpiY) { + val = d->extra->customDpiY; + } else { + const QWidgetPrivate *p = d; + while (p->parent) { + p = static_cast<const QWidget *>(p->parent)->d_func(); + if (p->extra && p->extra->customDpiY) { + val = p->extra->customDpiY; + break; + } + } + if (p == d || !(p->extra && p->extra->customDpiY)) + val = S60->defaultDpiY; + } + break; + case PdmWidthMM: + { + TInt twips = scr->HorizontalPixelsToTwips(data->crect.width()); + val = (int)(twips * (25.4/KTwipsPerInch)); + break; + } + case PdmHeightMM: + { + TInt twips = scr->VerticalPixelsToTwips(data->crect.height()); + val = (int)(twips * (25.4/KTwipsPerInch)); + break; + } + case PdmNumColors: + val = TDisplayModeUtils::NumDisplayModeColors(scr->DisplayMode()); + break; + case PdmDepth: + val = TDisplayModeUtils::NumDisplayModeBitsPerPixel(scr->DisplayMode()); + break; + default: + val = 0; + qWarning("QWidget::metric: Invalid metric command"); + } + } + return val; +} + +QPaintEngine *QWidget::paintEngine() const +{ + return 0; +} + +QPoint QWidget::mapToGlobal(const QPoint &pos) const +{ + Q_D(const QWidget); + if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) { + + QPoint p = pos + data->crect.topLeft(); + return (isWindow() || !parentWidget()) ? p : parentWidget()->mapToGlobal(p); + + } else if ((d->data.window_flags & Qt::Window) && internalWinId()) { //toplevel + QPoint tp = geometry().topLeft(); + return pos + tp; + } + + // This is the native window case. Consider using CCoeControl::PositionRelativeToScreen() + // if we decide to go with CCoeControl + return QPoint(); +} + +QPoint QWidget::mapFromGlobal(const QPoint &pos) const +{ + Q_D(const QWidget); + if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) { + QPoint p = (isWindow() || !parentWidget()) ? pos : parentWidget()->mapFromGlobal(pos); + return p - data->crect.topLeft(); + } else if ((d->data.window_flags & Qt::Window) && internalWinId()) { //toplevel + QPoint tp = geometry().topLeft(); + return pos - tp; + } + + // ### TODO native window + return QPoint(); +} + +void QWidget::setWindowState(Qt::WindowStates newstate) +{ + Q_D(QWidget); + Qt::WindowStates oldstate = windowState(); + if (oldstate == newstate) + return; + + if (isWindow()) { + createWinId(); + Q_ASSERT(testAttribute(Qt::WA_WState_Created)); + QTLWExtra *top = d->topData(); + + // Ensure the initial size is valid, since we store it as normalGeometry below. + if (!testAttribute(Qt::WA_Resized) && !isVisible()) + adjustSize(); + + if ((oldstate & Qt::WindowMaximized) != (newstate & Qt::WindowMaximized)) { + if ((newstate & Qt::WindowMaximized)) { + const QRect normalGeometry = geometry(); + + const QRect r = top->normalGeometry; + setGeometry(qApp->desktop()->availableGeometry(this)); + top->normalGeometry = r; + + if (top->normalGeometry.width() < 0) + top->normalGeometry = normalGeometry; + } else { + // restore original geometry + setGeometry(top->normalGeometry); + } + } + if ((oldstate & Qt::WindowFullScreen) != (newstate & Qt::WindowFullScreen)) { +#ifdef Q_WS_S60 + CEikStatusPane* statusPane = S60->statusPane(); + CEikButtonGroupContainer* buttonGroup = S60->buttonGroupContainer(); +#endif + if (newstate & Qt::WindowFullScreen) { + const QRect normalGeometry = geometry(); + const QRect r = top->normalGeometry; + setGeometry(qApp->desktop()->screenGeometry(this)); +#ifdef Q_WS_S60 + if (statusPane) + statusPane->MakeVisible(false); + if (buttonGroup) + buttonGroup->MakeVisible(false); +#endif + top->normalGeometry = r; + if (top->normalGeometry.width() < 0) + top->normalGeometry = normalGeometry; + } else { +#ifdef Q_WS_S60 + if (statusPane) + statusPane->MakeVisible(true); + if (buttonGroup) + buttonGroup->MakeVisible(true); +#endif + if (newstate & Qt::WindowMaximized) { + const QRect r = top->normalGeometry; + setGeometry(qApp->desktop()->availableGeometry(this)); + top->normalGeometry = r; + } else { + setGeometry(top->normalGeometry); + } + } + } + if ((oldstate & Qt::WindowMinimized) != (newstate & Qt::WindowMinimized)) { + if (newstate & Qt::WindowMinimized) { + if (isVisible()) { + WId id = effectiveWinId(); + if(id->IsFocused()) // Avoid unnecessary calls to FocusChanged() + id->SetFocus(false); + id->MakeVisible(false); + } + } else { + if (isVisible()) { + WId id = effectiveWinId(); + id->MakeVisible(true); + if(!id->IsFocused()) // Avoid unnecessary calls to FocusChanged() + id->SetFocus(true); + } + const QRect normalGeometry = geometry(); + const QRect r = top->normalGeometry; + top->normalGeometry = r; + if (top->normalGeometry.width() < 0) + top->normalGeometry = normalGeometry; + } + } + } + + data->window_state = newstate; + + if (newstate & Qt::WindowActive) + activateWindow(); + + QWindowStateChangeEvent e(oldstate); + QApplication::sendEvent(this, &e); +} + + +void QWidget::destroy(bool destroyWindow, bool destroySubWindows) +{ + Q_D(QWidget); + if (!isWindow() && parentWidget()) + parentWidget()->d_func()->invalidateBuffer(geometry()); + d->deactivateWidgetCleanup(); + WId id = internalWinId(); + if (testAttribute(Qt::WA_WState_Created)) { + +#ifndef QT_NO_IM + if (d->ic) { + delete d->ic; + } else { + QInputContext *ic = inputContext(); + if (ic) { + ic->widgetDestroyed(this); + } + } +#endif + + setAttribute(Qt::WA_WState_Created, false); + QObjectList childList = children(); + for (int i = 0; i < childList.size(); ++i) { // destroy all widget children + register QObject *obj = childList.at(i); + if (obj->isWidgetType()) + static_cast<QWidget*>(obj)->destroy(destroySubWindows, + destroySubWindows); + } + if (QWidgetPrivate::mouseGrabber == this) + releaseMouse(); + if (QWidgetPrivate::keyboardGrabber == this) + releaseKeyboard(); + if (destroyWindow && !(windowType() == Qt::Desktop) && id) { + if(id->IsFocused()) // Avoid unnecessry calls to FocusChanged() + id->SetFocus(false); + id->ControlEnv()->AppUi()->RemoveFromStack(id); + + // Hack to activate window under destroyed one. With this activation + // the next visible window will get keyboard focus + WId wid = CEikonEnv::Static()->AppUi()->TopFocusedControl(); + if (wid) { + QWidget *widget = QWidget::find(wid); + QApplication::setActiveWindow(widget); + if (widget) { + // Reset global window title for focusing window + widget->d_func()->setWindowTitle_sys(widget->windowTitle()); + } + } + } + } + + QT_TRY { + d->setWinId(0); + } QT_CATCH (const std::bad_alloc &) { + // swallow - destructors must not throw + } + + if (destroyWindow) { + delete id; + } +} + +QWidget *QWidget::mouseGrabber() +{ + return QWidgetPrivate::mouseGrabber; +} + +QWidget *QWidget::keyboardGrabber() +{ + return QWidgetPrivate::keyboardGrabber; +} + +void QWidget::grabKeyboard() +{ + if (!qt_nograb()) { + if (QWidgetPrivate::keyboardGrabber && QWidgetPrivate::keyboardGrabber != this) + QWidgetPrivate::keyboardGrabber->releaseKeyboard(); + + // ### TODO: Native keyboard grab + + QWidgetPrivate::keyboardGrabber = this; + } +} + +void QWidget::releaseKeyboard() +{ + if (!qt_nograb() && QWidgetPrivate::keyboardGrabber == this) { + // ### TODO: Native keyboard release + QWidgetPrivate::keyboardGrabber = 0; + } +} + +void QWidget::grabMouse() +{ + if (!qt_nograb()) { + if (QWidgetPrivate::mouseGrabber && QWidgetPrivate::mouseGrabber != this) + QWidgetPrivate::mouseGrabber->releaseMouse(); + Q_ASSERT(testAttribute(Qt::WA_WState_Created)); + WId id = effectiveWinId(); + id->SetPointerCapture(true); + QWidgetPrivate::mouseGrabber = this; + } +} + +void QWidget::releaseMouse() +{ + if (!qt_nograb() && QWidgetPrivate::mouseGrabber == this) { + Q_ASSERT(testAttribute(Qt::WA_WState_Created)); + WId id = effectiveWinId(); + id->SetPointerCapture(false); + QWidgetPrivate::mouseGrabber = 0; + } +} + +void QWidget::activateWindow() +{ + Q_D(QWidget); + QWidget *tlw = window(); + if (tlw->isVisible()) { + S60->windowGroup().SetOrdinalPosition(0); + window()->createWinId(); + RDrawableWindow* rw = tlw->d_func()->topData()->rwindow; + rw->SetOrdinalPosition(0); + } +} +QT_END_NAMESPACE diff --git a/src/gui/kernel/qwidget_win.cpp b/src/gui/kernel/qwidget_win.cpp index 77ab590..40e3fa2 100644 --- a/src/gui/kernel/qwidget_win.cpp +++ b/src/gui/kernel/qwidget_win.cpp @@ -535,7 +535,7 @@ void QWidget::destroy(bool destroyWindow, bool destroySubWindows) { Q_D(QWidget); if (!isWindow() && parentWidget()) - parentWidget()->d_func()->invalidateBuffer(geometry()); + parentWidget()->d_func()->invalidateBuffer(d->effectiveRectFor(geometry())); d->deactivateWidgetCleanup(); if (testAttribute(Qt::WA_WState_Created)) { setAttribute(Qt::WA_WState_Created, false); @@ -562,7 +562,11 @@ void QWidget::destroy(bool destroyWindow, bool destroySubWindows) } #endif - d->setWinId(0); + QT_TRY { + d->setWinId(0); + } QT_CATCH (const std::bad_alloc &) { + // swallow - destructors must not throw + } } } @@ -597,7 +601,7 @@ void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f) Q_Q(QWidget); bool wasCreated = q->testAttribute(Qt::WA_WState_Created); if (q->isVisible() && q->parentWidget() && parent != q->parentWidget()) - q->parentWidget()->d_func()->invalidateBuffer(q->geometry()); + q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(q->geometry())); WId old_winid = data.winid; // hide and reparent our own window away. Otherwise we might get @@ -2060,19 +2064,27 @@ void QWidgetPrivate::winSetupGestures() Q_Q(QWidget); if (!q) return; - q->setAttribute(Qt::WA_DontCreateNativeAncestors); - q->setAttribute(Qt::WA_NativeWindow); if (!q->isVisible()) return; QApplicationPrivate *qAppPriv = QApplicationPrivate::instance(); bool needh = false; bool needv = false; bool singleFingerPanEnabled = false; - QStandardGestures gestures = qAppPriv->widgetGestures[q]; + QApplicationPrivate::WidgetStandardGesturesMap::const_iterator it = + qAppPriv->widgetGestures.find(q); + if (it == qAppPriv->widgetGestures.end()) + return; + const QStandardGestures &gestures = it.value(); WId winid = 0; if (QAbstractScrollArea *asa = qobject_cast<QAbstractScrollArea*>(q)) { - winid = asa->viewport()->winId(); + winid = asa->viewport()->internalWinId(); + if (!winid) { + QWidget *nativeParent = asa->viewport()->nativeParentWidget(); + if (!nativeParent) + return; + winid = nativeParent->internalWinId(); + } QScrollBar *hbar = asa->horizontalScrollBar(); QScrollBar *vbar = asa->verticalScrollBar(); Qt::ScrollBarPolicy hbarpolicy = asa->horizontalScrollBarPolicy(); @@ -2083,9 +2095,13 @@ void QWidgetPrivate::winSetupGestures() (vbarpolicy == Qt::ScrollBarAsNeeded && vbar->minimum() < vbar->maximum())); singleFingerPanEnabled = asa->d_func()->singleFingerPanEnabled; } else { - winid = q->winId(); + winid = q->internalWinId(); + if (!winid) { + if (QWidget *nativeParent = q->nativeParentWidget()) + winid = nativeParent->internalWinId(); + } } - if (qAppPriv->SetGestureConfig) { + if (winid && qAppPriv->SetGestureConfig) { GESTURECONFIG gc[3]; memset(gc, 0, sizeof(gc)); gc[0].dwID = GID_PAN; @@ -2114,7 +2130,6 @@ void QWidgetPrivate::winSetupGestures() else gc[2].dwBlock = GC_ROTATE; - Q_ASSERT(winid); qAppPriv->SetGestureConfig(winid, 0, sizeof(gc)/sizeof(gc[0]), gc, sizeof(gc[0])); } } diff --git a/src/gui/kernel/qwidget_wince.cpp b/src/gui/kernel/qwidget_wince.cpp index bcc9cfd..fa71925 100644 --- a/src/gui/kernel/qwidget_wince.cpp +++ b/src/gui/kernel/qwidget_wince.cpp @@ -316,7 +316,7 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO if (desktop) { q->setAttribute(Qt::WA_WState_Visible); - } else if (topLevel) { + } else if (topLevel && !q->testAttribute(Qt::WA_DontShowOnScreen)) { RECT cr; GetClientRect(id, &cr); // one cannot trust cr.left and cr.top, use a correction POINT instead diff --git a/src/gui/kernel/qwidget_x11.cpp b/src/gui/kernel/qwidget_x11.cpp index de38b4c..62aba45 100644 --- a/src/gui/kernel/qwidget_x11.cpp +++ b/src/gui/kernel/qwidget_x11.cpp @@ -971,7 +971,7 @@ void QWidget::destroy(bool destroyWindow, bool destroySubWindows) { Q_D(QWidget); if (!isWindow() && parentWidget()) - parentWidget()->d_func()->invalidateBuffer(geometry()); + parentWidget()->d_func()->invalidateBuffer(d->effectiveRectFor(geometry())); d->deactivateWidgetCleanup(); if (testAttribute(Qt::WA_WState_Created)) { setAttribute(Qt::WA_WState_Created, false); @@ -1015,7 +1015,11 @@ void QWidget::destroy(bool destroyWindow, bool destroySubWindows) if (destroyWindow) qt_XDestroyWindow(this, X11->display, data->winid); } - d->setWinId(0); + QT_TRY { + d->setWinId(0); + } QT_CATCH (const std::bad_alloc &) { + // swallow - destructors must not throw + } extern void qPRCleanup(QWidget *widget); // from qapplication_x11.cpp if (testAttribute(Qt::WA_WState_Reparented)) @@ -1050,7 +1054,7 @@ void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f) QTLWExtra *topData = maybeTopData(); bool wasCreated = q->testAttribute(Qt::WA_WState_Created); if (q->isVisible() && q->parentWidget() && parent != q->parentWidget()) - q->parentWidget()->d_func()->invalidateBuffer(q->geometry()); + q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(q->geometry())); extern void qPRCreate(const QWidget *, Window); #ifndef QT_NO_CURSOR QCursor oldcurs; @@ -1276,7 +1280,7 @@ void QWidgetPrivate::updateSystemBackground() else if (brush.style() == Qt::TexturePattern) { extern QPixmap qt_toX11Pixmap(const QPixmap &pixmap); // qpixmap_x11.cpp XSetWindowBackgroundPixmap(X11->display, q->internalWinId(), - static_cast<QX11PixmapData*>(qt_toX11Pixmap(brush.texture()).data)->x11ConvertToDefaultDepth()); + static_cast<QX11PixmapData*>(qt_toX11Pixmap(brush.texture()).data.data())->x11ConvertToDefaultDepth()); } else XSetWindowBackground(X11->display, q->internalWinId(), QColormap::instance(xinfo.screen()).pixel(brush.color())); @@ -1422,7 +1426,7 @@ void QWidgetPrivate::setWindowIcon_sys(bool forceReset) // violates the ICCCM), since this works on all DEs known to Qt if (!forceReset || !topData->iconPixmap) topData->iconPixmap = new QPixmap(qt_toX11Pixmap(icon.pixmap(QSize(64,64)))); - pixmap_handle = static_cast<QX11PixmapData*>(topData->iconPixmap->data)->x11ConvertToDefaultDepth(); + pixmap_handle = static_cast<QX11PixmapData*>(topData->iconPixmap->data.data())->x11ConvertToDefaultDepth(); } } } diff --git a/src/gui/kernel/qwindowdefs.h b/src/gui/kernel/qwindowdefs.h index 8b44d38..0b5ca6c 100644 --- a/src/gui/kernel/qwindowdefs.h +++ b/src/gui/kernel/qwindowdefs.h @@ -131,6 +131,11 @@ QT_END_HEADER #endif // Q_WS_QWS +#if defined(Q_OS_SYMBIAN) +class CCoeControl; +typedef CCoeControl * WId; +#endif // Q_OS_SYMBIAN + QT_BEGIN_HEADER QT_BEGIN_NAMESPACE diff --git a/src/gui/kernel/symbian.pri b/src/gui/kernel/symbian.pri new file mode 100644 index 0000000..d267a53 --- /dev/null +++ b/src/gui/kernel/symbian.pri @@ -0,0 +1,3 @@ +symbian { + contains(QT_CONFIG, s60): LIBS+= $$QMAKE_LIBS_S60 +} |