diff options
Diffstat (limited to 'src/gui/kernel')
131 files changed, 19281 insertions, 3810 deletions
diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri index cb2b014..8859358 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 \ @@ -41,7 +42,14 @@ HEADERS += \ kernel/qwidgetaction.h \ kernel/qwidgetaction_p.h \ kernel/qwindowdefs.h \ - kernel/qkeymapper_p.h + kernel/qkeymapper_p.h \ + kernel/qgesture.h \ + kernel/qgesture_p.h \ + kernel/qstandardgestures_p.h \ + kernel/qgesturerecognizer.h \ + kernel/qgesturemanager_p.h \ + kernel/qsoftkeymanager_p.h \ + kernel/qguiplatformplugin_p.h SOURCES += \ kernel/qaction.cpp \ @@ -70,11 +78,21 @@ SOURCES += \ kernel/qwhatsthis.cpp \ kernel/qwidget.cpp \ kernel/qwidgetaction.cpp \ - kernel/qkeymapper.cpp + kernel/qkeymapper.cpp \ + kernel/qgesture.cpp \ + kernel/qstandardgestures.cpp \ + kernel/qgesturerecognizer.cpp \ + kernel/qgesturemanager.cpp \ + kernel/qsoftkeymanager.cpp \ + kernel/qdesktopwidget.cpp \ + kernel/qguiplatformplugin.cpp win32 { DEFINES += QT_NO_DIRECTDRAW + HEADERS += \ + kernel/qwinnativepangesturerecognizer_win_p.h + SOURCES += \ kernel/qapplication_win.cpp \ kernel/qclipboard_win.cpp \ @@ -85,16 +103,39 @@ win32 { kernel/qsound_win.cpp \ kernel/qwidget_win.cpp \ kernel/qole_win.cpp \ - kernel/qkeymapper_win.cpp + kernel/qkeymapper_win.cpp \ + kernel/qwinnativepangesturerecognizer_win.cpp !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 += \ kernel/qx11embed_x11.h \ - kernel/qx11info_x11.h + kernel/qx11info_x11.h \ + kernel/qkde_p.h SOURCES += \ kernel/qapplication_x11.cpp \ @@ -108,7 +149,8 @@ unix:x11 { kernel/qwidgetcreate_x11.cpp \ kernel/qx11embed_x11.cpp \ kernel/qx11info_x11.cpp \ - kernel/qkeymapper_x11.cpp + kernel/qkeymapper_x11.cpp \ + kernel/qkde.cpp contains(QT_CONFIG, glib) { SOURCES += \ @@ -116,7 +158,7 @@ unix:x11 { HEADERS += \ kernel/qguieventdispatcher_glib_p.h QMAKE_CXXFLAGS += $$QT_CFLAGS_GLIB - LIBS +=$$QT_LIBS_GLIB + LIBS_PRIVATE +=$$QT_LIBS_GLIB } SOURCES += \ kernel/qeventdispatcher_x11.cpp @@ -164,24 +206,28 @@ embedded { qcocoaview_mac_p.h \ qcocoaapplication_mac_p.h \ qcocoaapplicationdelegate_mac_p.h \ + qmacgesturerecognizer_mac_p.h \ + qmultitouch_mac_p.h OBJECTIVE_SOURCES += \ kernel/qcursor_mac.mm \ kernel/qdnd_mac.mm \ kernel/qsound_mac.mm \ kernel/qapplication_mac.mm \ - kernel/qwidget_mac.mm \ - kernel/qcocoapanel_mac.mm \ - kernel/qcocoaview_mac.mm \ - kernel/qcocoawindow_mac.mm \ - kernel/qcocoawindowdelegate_mac.mm \ + kernel/qwidget_mac.mm \ + kernel/qcocoapanel_mac.mm \ + kernel/qcocoaview_mac.mm \ + kernel/qcocoawindow_mac.mm \ + kernel/qcocoawindowdelegate_mac.mm \ kernel/qcocoamenuloader_mac.mm \ kernel/qcocoaapplication_mac.mm \ kernel/qcocoaapplicationdelegate_mac.mm \ kernel/qt_cocoa_helpers_mac.mm \ - kernel/qdesktopwidget_mac.mm \ + kernel/qdesktopwidget_mac.mm \ kernel/qeventdispatcher_mac.mm \ - kernel/qcocoawindowcustomthemeframe_mac.mm + kernel/qcocoawindowcustomthemeframe_mac.mm \ + kernel/qmacgesturerecognizer_mac.mm \ + kernel/qmultitouch_mac.mm HEADERS += \ kernel/qt_cocoa_helpers_mac_p.h \ @@ -189,13 +235,13 @@ 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 - RESOURCES += mac/maccursors.qrc + QMAKE_BUNDLE_DATA += MENU_NIB + RESOURCES += mac/macresources.qrc - LIBS += -framework AppKit + LIBS_PRIVATE += -framework AppKit } wince*: { diff --git a/src/gui/kernel/mac.pri b/src/gui/kernel/mac.pri index 415fe0a..1538510 100644 --- a/src/gui/kernel/mac.pri +++ b/src/gui/kernel/mac.pri @@ -1,4 +1,4 @@ !x11:!embedded:mac { - LIBS += -framework Carbon -lz + LIBS_PRIVATE += -framework Carbon -lz *-mwerks:INCLUDEPATH += compat } diff --git a/src/gui/kernel/qaction.cpp b/src/gui/kernel/qaction.cpp index e594990..5f5650f 100644 --- a/src/gui/kernel/qaction.cpp +++ b/src/gui/kernel/qaction.cpp @@ -76,12 +76,13 @@ static QString qt_strippedText(QString s) s.remove(i-1,1); } return s.trimmed(); -}; +} QActionPrivate::QActionPrivate() : group(0), enabled(1), forceDisabled(0), visible(1), forceInvisible(0), checkable(0), checked(0), separator(0), fontSet(false), - menuRole(QAction::TextHeuristicRole), iconVisibleInMenu(-1) + menuRole(QAction::TextHeuristicRole), softKeyRole(QAction::NoSoftKey), + priority(QAction::NormalPriority), iconVisibleInMenu(-1) { #ifdef QT3_SUPPORT static int qt_static_action_id = -1; @@ -136,25 +137,31 @@ void QActionPrivate::redoGrab(QShortcutMap &map) void QActionPrivate::redoGrabAlternate(QShortcutMap &map) { Q_Q(QAction); - foreach (int id, alternateShortcutIds) - if (id) + for(int i = 0; i < alternateShortcutIds.count(); ++i) { + if (const int id = alternateShortcutIds.at(i)) map.removeShortcut(id, q); + } alternateShortcutIds.clear(); if (alternateShortcuts.isEmpty()) return; - foreach (const QKeySequence& alternate, alternateShortcuts) { + for(int i = 0; i < alternateShortcuts.count(); ++i) { + const QKeySequence& alternate = alternateShortcuts.at(i); if (!alternate.isEmpty()) alternateShortcutIds.append(map.addShortcut(q, alternate, shortcutContext)); else alternateShortcutIds.append(0); } if (!enabled) { - foreach (int id, alternateShortcutIds) + for(int i = 0; i < alternateShortcutIds.count(); ++i) { + const int id = alternateShortcutIds.at(i); map.setShortcutEnabled(false, id, q); + } } if (!autorepeat) { - foreach (int id, alternateShortcutIds) + for(int i = 0; i < alternateShortcutIds.count(); ++i) { + const int id = alternateShortcutIds.at(i); map.setShortcutAutoRepeat(false, id, q); + } } } @@ -163,9 +170,10 @@ void QActionPrivate::setShortcutEnabled(bool enable, QShortcutMap &map) Q_Q(QAction); if (shortcutId) map.setShortcutEnabled(enable, shortcutId, q); - foreach (int id, alternateShortcutIds) - if (id) + for(int i = 0; i < alternateShortcutIds.count(); ++i) { + if (const int id = alternateShortcutIds.at(i)) map.setShortcutEnabled(enable, id, q); + } } #endif // QT_NO_SHORTCUT @@ -175,8 +183,8 @@ void QActionPrivate::setShortcutEnabled(bool enable, QShortcutMap &map) \brief The QAction class provides an abstract user interface action that can be inserted into widgets. - \ingroup application - \mainclass + \ingroup mainwindow-classes + \omit * parent and widget are different @@ -261,6 +269,26 @@ void QActionPrivate::setShortcutEnabled(bool enable, QShortcutMap &map) MenuRole for the actions in that submenu have no effect. They will never be moved. */ +/*! \since 4.6 + + \enum QAction::SoftKeyRole + + This enum describes how an action should be placed in the softkey bar. Currently this enum only + has an effect on the Symbian platform. + + \value NoSoftKey This action should not be used as a softkey + \value PositiveSoftKey This action is used to describe a softkey with a positive or non-destructive + role such as Ok, Select, or Options. + \value NegativeSoftKey This action is used to describe a soft ey with a negative or destructive role + role such as Cancel, Discard, or Close. + \value SelectSoftKey This action is used to describe a role that selects a particular item or widget + in the application. + + Actions with a softkey role defined are only visible in the softkey bar when the widget containing + the action has focus. If no widget currently has focus, the softkey framework will traverse up the + widget parent heirarchy looking for a widget containing softkey actions. + */ + /*! Constructs an action with \a parent. If \a parent is an action group the action will be automatically inserted into the group. @@ -622,8 +650,10 @@ QAction::~QAction() #ifndef QT_NO_SHORTCUT if (d->shortcutId && qApp) { qApp->d_func()->shortcutMap.removeShortcut(d->shortcutId, this); - foreach (int id, d->alternateShortcutIds) + for(int i = 0; i < d->alternateShortcutIds.count(); ++i) { + const int id = d->alternateShortcutIds.at(i); qApp->d_func()->shortcutMap.removeShortcut(id, this); + } } #endif } @@ -905,6 +935,52 @@ QString QAction::whatsThis() const return d->whatsthis; } +/*! + \enum QAction::Priority + \since 4.6 + + This enum defines priorities for actions in user interface. + + \value LowPriority The action should not be prioritized in + the user interface. + + \value NormalPriority + + \value HighPriority The action should be prioritized in + the user interface. + + \sa priority +*/ + + +/*! + \property QAction::priority + \since 4.6 + + \brief the actions's priority in the user interface. + + This property can be set to indicate how the action should be prioritized + in the user interface. + + For instance, when toolbars have the Qt::ToolButtonTextBesideIcon + mode set, then actions with LowPriority will not show the text + labels. +*/ +void QAction::setPriority(Priority priority) +{ + Q_D(QAction); + if (d->priority == priority) + return; + + d->priority = priority; + d->sendDataChanged(); +} + +QAction::Priority QAction::priority() const +{ + Q_D(const QAction); + return d->priority; +} /*! \property QAction::checkable @@ -1158,6 +1234,8 @@ void QAction::activate(ActionEvent event) // the checked action of an exclusive group cannot be unchecked if (d->checked && (d->group && d->group->isExclusive() && d->group->checkedAction() == this)) { + if (guard) + emit triggered(true); QMetaObject::removeGuard(&guard); return; } @@ -1355,6 +1433,33 @@ QAction::MenuRole QAction::menuRole() const } /*! + \property QAction::softKeyRole + \brief the action's softkey role + \since 4.6 + + This indicates what type of role this action describes in the softkey framework + on platforms where such a framework is supported. Currently this is only + supported on the Symbian platform. + + 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 @@ -1375,7 +1480,7 @@ QAction::MenuRole QAction::menuRole() const void QAction::setIconVisibleInMenu(bool visible) { Q_D(QAction); - if (visible != (bool)d->iconVisibleInMenu) { + if (d->iconVisibleInMenu == -1 || visible != bool(d->iconVisibleInMenu)) { int oldValue = d->iconVisibleInMenu; d->iconVisibleInMenu = visible; // Only send data changed if we really need to. diff --git a/src/gui/kernel/qaction.h b/src/gui/kernel/qaction.h index a4a13de..bfc7491 100644 --- a/src/gui/kernel/qaction.h +++ b/src/gui/kernel/qaction.h @@ -67,28 +67,37 @@ class Q_GUI_EXPORT QAction : public QObject Q_DECLARE_PRIVATE(QAction) Q_ENUMS(MenuRole) - Q_PROPERTY(bool checkable READ isCheckable WRITE setCheckable) + 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) - Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled) - Q_PROPERTY(QIcon icon READ icon WRITE setIcon) - Q_PROPERTY(QString text READ text WRITE setText) - Q_PROPERTY(QString iconText READ iconText WRITE setIconText) - Q_PROPERTY(QString toolTip READ toolTip WRITE setToolTip) - Q_PROPERTY(QString statusTip READ statusTip WRITE setStatusTip) - Q_PROPERTY(QString whatsThis READ whatsThis WRITE setWhatsThis) - Q_PROPERTY(QFont font READ font WRITE setFont) + Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY changed) + Q_PROPERTY(QIcon icon READ icon WRITE setIcon NOTIFY changed) + Q_PROPERTY(QString text READ text WRITE setText NOTIFY changed) + Q_PROPERTY(QString iconText READ iconText WRITE setIconText NOTIFY changed) + Q_PROPERTY(QString toolTip READ toolTip WRITE setToolTip NOTIFY changed) + Q_PROPERTY(QString statusTip READ statusTip WRITE setStatusTip NOTIFY changed) + Q_PROPERTY(QString whatsThis READ whatsThis WRITE setWhatsThis NOTIFY changed) + Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY changed) #ifndef QT_NO_SHORTCUT - Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut) - Q_PROPERTY(Qt::ShortcutContext shortcutContext READ shortcutContext WRITE setShortcutContext) - Q_PROPERTY(bool autoRepeat READ autoRepeat WRITE setAutoRepeat) + Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut NOTIFY changed) + Q_PROPERTY(Qt::ShortcutContext shortcutContext READ shortcutContext WRITE setShortcutContext NOTIFY changed) + Q_PROPERTY(bool autoRepeat READ autoRepeat WRITE setAutoRepeat NOTIFY changed) #endif - Q_PROPERTY(bool visible READ isVisible WRITE setVisible) - Q_PROPERTY(MenuRole menuRole READ menuRole WRITE setMenuRole) - Q_PROPERTY(bool iconVisibleInMenu READ isIconVisibleInMenu WRITE setIconVisibleInMenu) + 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 { + NoSoftKey, PositiveSoftKey, NegativeSoftKey, SelectSoftKey }; + enum Priority { LowPriority = 0, + NormalPriority = 128, + HighPriority = 256}; explicit QAction(QObject* parent); QAction(const QString &text, QObject* parent); QAction(const QIcon &icon, const QString &text, QObject* parent); @@ -123,6 +132,9 @@ public: void setWhatsThis(const QString &what); QString whatsThis() const; + void setPriority(Priority priority); + Priority priority() const; + #ifndef QT_NO_MENU QMenu *menu() const; void setMenu(QMenu *menu); @@ -168,6 +180,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 f08a6ae..2527a02 100644 --- a/src/gui/kernel/qaction_p.h +++ b/src/gui/kernel/qaction_p.h @@ -102,6 +102,8 @@ 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; #ifndef QT_NO_GRAPHICSVIEW diff --git a/src/gui/kernel/qactiongroup.cpp b/src/gui/kernel/qactiongroup.cpp index e2f73c7..8db76e4 100644 --- a/src/gui/kernel/qactiongroup.cpp +++ b/src/gui/kernel/qactiongroup.cpp @@ -72,10 +72,16 @@ void QActionGroupPrivate::_q_actionChanged() Q_Q(QActionGroup); QAction *action = qobject_cast<QAction*>(q->sender()); Q_ASSERT_X(action != 0, "QWidgetGroup::_q_actionChanged", "internal error"); - if(exclusive && action->isChecked() && action != current) { - if(current) - current->setChecked(false); - current = action; + if(exclusive) { + if (action->isChecked()) { + if (action != current) { + if(current) + current->setChecked(false); + current = action; + } + } else if (action == current) { + current = 0; + } } } @@ -100,7 +106,7 @@ void QActionGroupPrivate::_q_actionHovered() \class QActionGroup \brief The QActionGroup class groups actions together. - \ingroup application + \ingroup mainwindow-classes In some situations it is useful to group actions together. For example, if you have a \gui{Left Align} action, a \gui{Right diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 832d829..987aa26 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -39,6 +39,7 @@ ** ****************************************************************************/ +#include "qplatformdefs.h" #include "qabstracteventdispatcher.h" #include "qaccessible.h" #include "qapplication.h" @@ -74,9 +75,14 @@ #ifdef Q_WS_X11 #include <private/qt_x11_p.h> +#endif + +#if defined(Q_WS_X11) || defined(Q_WS_S60) #include "qinputcontextfactory.h" #endif +#include "qguiplatformplugin_p.h" + #include <qthread.h> #include <private/qthread_p.h> @@ -85,11 +91,19 @@ #include <stdlib.h> #include "qapplication_p.h" +#include "qevent_p.h" #include "qwidget_p.h" #include "qapplication.h" -#ifdef Q_OS_WINCE +#include "qgesture.h" +#include "private/qgesturemanager_p.h" + +#ifndef QT_NO_LIBRARY +#include "qlibrary.h" +#endif + +#ifdef Q_WS_WINCE #include "qdatetime.h" #include "qguifunctions_wince.h" extern bool qt_wince_is_smartphone(); //qguifunctions_wince.cpp @@ -97,19 +111,22 @@ extern bool qt_wince_is_mobile(); //qguifunctions_wince.cpp extern bool qt_wince_is_pocket_pc(); //qguifunctions_wince.cpp #endif +#include "qdatetime.h" + +#ifdef QT_MAC_USE_COCOA +#include <private/qt_cocoa_helpers_mac_p.h> +#endif + //#define ALIEN_DEBUG static void initResources() { -#ifdef Q_OS_WINCE +#ifdef Q_WS_WINCE Q_INIT_RESOURCE(qstyle_wince); #else Q_INIT_RESOURCE(qstyle); #endif -#if !defined(QT_NO_DIRECT3D) && defined(Q_WS_WIN) - Q_INIT_RESOURCE(qpaintengine_d3d); -#endif Q_INIT_RESOURCE(qmessagebox); #if !defined(QT_NO_PRINTDIALOG) Q_INIT_RESOURCE(qprintdialog); @@ -130,9 +147,11 @@ QInputContext *QApplicationPrivate::inputContext = 0; bool QApplicationPrivate::quitOnLastWindowClosed = true; -#ifdef Q_OS_WINCE +#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) @@ -158,6 +177,8 @@ QApplicationPrivate::QApplicationPrivate(int &argc, char **argv, QApplication::T directPainters = 0; #endif + gestureWidget = 0; + if (!self) self = this; } @@ -173,16 +194,13 @@ QApplicationPrivate::~QApplicationPrivate() \brief The QApplication class manages the GUI application's control flow and main settings. - \ingroup application - \mainclass - QApplication contains the main event loop, where all events from the window system and other sources are processed and dispatched. It also handles the - application's initialization and finalization, and provides session - management. In addition, it handles most system-wide and application-wide - settings. + application's initialization, finalization, and provides session + management. In addition, QApplication handles most of the system-wide and + application-wide settings. - For any GUI application using Qt, there is precisely one QApplication + For any GUI application using Qt, there is precisely \bold one QApplication object, no matter whether the application has 0, 1, 2 or more windows at any given time. For non-GUI Qt applications, use QCoreApplication instead, as it does not depend on the \l QtGui library. @@ -238,9 +256,9 @@ QApplicationPrivate::~QApplicationPrivate() saveState() for details. \endlist - The QApplication object does so much initialization. Hence, it \e{must} be + Since the QApplication object does so much initialization, it \e{must} be created before any other objects related to the user interface are created. - Since QApplication also deals with common command line arguments, it is + QApplication also deals with common command line arguments. Hence, it is usually a good idea to create it \e before any interpretation or modification of \c argv is done in the application itself. @@ -394,6 +412,7 @@ Qt::MouseButtons QApplicationPrivate::mouse_buttons = Qt::NoButton; Qt::KeyboardModifiers QApplicationPrivate::modifier_buttons = Qt::NoModifier; QStyle *QApplicationPrivate::app_style = 0; // default application style +QString QApplicationPrivate::styleOverride; // style override #ifndef QT_NO_STYLE_STYLESHEET QString QApplicationPrivate::styleSheet; // default application stylesheet @@ -408,7 +427,7 @@ QPalette *QApplicationPrivate::set_pal = 0; // default palette set by pro QGraphicsSystem *QApplicationPrivate::graphics_system = 0; // default graphics system QString QApplicationPrivate::graphics_system_name; // graphics system id - for delayed initialization -Q_GLOBAL_STATIC(QMutex, applicationFontMutex); +Q_GLOBAL_STATIC(QMutex, applicationFontMutex) QFont *QApplicationPrivate::app_font = 0; // default application font QFont *QApplicationPrivate::sys_font = 0; // default system font QFont *QApplicationPrivate::set_font = 0; // default font set by programmer @@ -430,7 +449,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; @@ -441,24 +465,31 @@ bool QApplicationPrivate::animate_tooltip = false; bool QApplicationPrivate::fade_tooltip = false; bool QApplicationPrivate::animate_toolbox = false; bool QApplicationPrivate::widgetCount = false; -QString* QApplicationPrivate::styleOverride = 0; -#if defined(Q_WS_WIN) && !defined(Q_OS_WINCE) -bool QApplicationPrivate::inSizeMove = false; -#endif +bool QApplicationPrivate::load_testability = false; #ifdef QT_KEYPAD_NAVIGATION -bool QApplicationPrivate::keypadNavigation = false; +# ifdef Q_OS_SYMBIAN +Qt::NavigationMode QApplicationPrivate::navigationMode = Qt::NavigationModeKeypadDirectional; +# else +Qt::NavigationMode QApplicationPrivate::navigationMode = Qt::NavigationModeKeypadTabOrder; +# endif QWidget *QApplicationPrivate::oldEditFocus = 0; #endif bool qt_tabletChokeMouse = false; static bool force_reverse = false; -static inline bool isAlien(QWidget *widget) +inline bool QApplicationPrivate::isAlien(QWidget *widget) { if (!widget) return false; -#ifdef Q_WS_MAC // Fake alien behavior on the Mac :) +#if defined(Q_WS_MAC) // Fake alien behavior on the Mac :) return !widget->isWindow() && widget->window()->testAttribute(Qt::WA_DontShowOnScreen); +#elif defined(Q_WS_QWS) + return !widget->isWindow() +# ifdef Q_BACKINGSTORE_SUBSURFACES + && !(widget->d_func()->maybeTopData() && widget->d_func()->maybeTopData()->windowSurface) +# endif + ; #else return !widget->internalWinId(); #endif @@ -466,15 +497,12 @@ static inline bool isAlien(QWidget *widget) // ######## move to QApplicationPrivate // Default application palettes and fonts (per widget type) - -typedef QHash<QByteArray, QPalette> PaletteHash; Q_GLOBAL_STATIC(PaletteHash, app_palettes) PaletteHash *qt_app_palettes_hash() { return app_palettes(); } -typedef QHash<QByteArray, QFont> FontHash; Q_GLOBAL_STATIC(FontHash, app_fonts) FontHash *qt_app_fonts_hash() { @@ -494,8 +522,6 @@ QWidgetList * qt_modal_stack=0; // stack of modal widgets */ void QApplicationPrivate::process_cmdline() { - Q_Q(QApplication); - Q_UNUSED(q);// only static members being used. // process platform-indep command line if (!qt_is_gui_used || !argc) return; @@ -540,9 +566,11 @@ void QApplicationPrivate::process_cmdline() #endif } else if (qstrcmp(arg, "-reverse") == 0) { force_reverse = true; - q->setLayoutDirection(Qt::RightToLeft); + QApplication::setLayoutDirection(Qt::RightToLeft); } else if (qstrcmp(arg, "-widgetcount") == 0) { widgetCount = true; + } else if (qstrcmp(arg, "-testability") == 0) { + load_testability = true; } else if (arg == "-graphicssystem" && i < argc-1) { graphics_system_name = QString::fromLocal8Bit(argv[++i]); } else { @@ -553,9 +581,7 @@ void QApplicationPrivate::process_cmdline() delete app_style; app_style = 0; } - if (!styleOverride) - styleOverride = new QString; - *styleOverride = s; + styleOverride = s; } } @@ -620,13 +646,6 @@ void QApplicationPrivate::process_cmdline() and QPixmaps. Available options are \c{raster} and \c{opengl}. \endlist - The Windows version of Qt supports an additional command line option, if - Direct3D support has been compiled into Qt: - \list - \o -direct3d will make the Direct3D paint engine the default widget - paint engine in Qt. \bold {This functionality is experimental.} - \endlist - The X11 version of Qt supports some traditional X11 command line options: \list \o -display \e display, sets the X display (default is $DISPLAY). @@ -686,9 +705,9 @@ QApplication::QApplication(int &argc, char **argv, int _internal) On X11, the window system is initialized if \a GUIenabled is true. If \a GUIenabled is false, the application does not connect to the X server. - On Windows and Macintosh, currently the window system is always - initialized, regardless of the value of GUIenabled. This may change in - future versions of Qt. + On Windows and Mac OS, currently the window system is always initialized, + regardless of the value of GUIenabled. This may change in future versions + of Qt. The following example shows how to create an application that uses a graphical interface when available. @@ -754,6 +773,26 @@ void QApplicationPrivate::construct( extern void qt_gui_eval_init(uint); qt_gui_eval_init(application_type); #endif + +#ifndef QT_NO_LIBRARY + if(load_testability) { + QLibrary testLib(QLatin1String("qttestability")); + if (testLib.load()) { + typedef void (*TasInitialize)(void); + TasInitialize initFunction = (TasInitialize)testLib.resolve("qt_testability_init"); + if (initFunction) { + initFunction(); + } else { + qCritical("Library qttestability resolve failed!"); + } + } else { + qCritical("Library qttestability load failed!"); + } + } + + //make sure the plugin is loaded + qt_guiPlatformPlugin(); +#endif } #if defined(Q_WS_X11) @@ -833,6 +872,12 @@ QApplication::QApplication(Display *dpy, int &argc, char **argv, #endif // Q_WS_X11 extern void qInitDrawhelperAsm(); +extern int qRegisterGuiVariant(); +extern int qUnregisterGuiVariant(); +#ifndef QT_NO_STATEMACHINE +extern int qRegisterGuiStateMachine(); +extern int qUnregisterGuiStateMachine(); +#endif /*! \fn void QApplicationPrivate::initialize() @@ -842,12 +887,15 @@ extern void qInitDrawhelperAsm(); 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 - extern int qRegisterGuiVariant(); qRegisterGuiVariant(); +#ifndef QT_NO_STATEMACHINE + // trigger registering of QStateMachine's GUI types + qRegisterGuiStateMachine(); +#endif is_app_running = true; // no longer starting up @@ -860,13 +908,7 @@ void QApplicationPrivate::initialize() if (qgetenv("QT_USE_NATIVE_WINDOWS").toInt() > 0) q->setAttribute(Qt::AA_NativeWindows); -#if defined(Q_WS_WIN) - // Alien is not currently working on Windows 98 - if (QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based) - q->setAttribute(Qt::AA_NativeWindows); -#endif - -#ifdef Q_OS_WINCE +#ifdef Q_WS_WINCE #ifdef QT_AUTO_MAXIMIZE_THRESHOLD autoMaximizeThreshold = QT_AUTO_MAXIMIZE_THRESHOLD; #else @@ -875,7 +917,7 @@ void QApplicationPrivate::initialize() else autoMaximizeThreshold = -1; #endif //QT_AUTO_MAXIMIZE_THRESHOLD -#endif //Q_OS_WINCE +#endif //Q_WS_WINCE // Set up which span functions should be used in raster engine... qInitDrawhelperAsm(); @@ -887,12 +929,10 @@ void QApplicationPrivate::initialize() graphics_system = QGraphicsSystemFactory::create(graphics_system_name); #endif #ifndef QT_NO_WHEELEVENT -#ifdef QT_MAC_USE_COCOA - QApplicationPrivate::wheel_scroll_lines = 1; -#else QApplicationPrivate::wheel_scroll_lines = 3; #endif -#endif + + initializeMultitouch(); } /*! @@ -976,34 +1016,25 @@ QApplication::~QApplication() d->eventDispatcher->closingDown(); d->eventDispatcher = 0; + QApplicationPrivate::is_app_closing = true; + QApplicationPrivate::is_app_running = false; delete qt_desktopWidget; qt_desktopWidget = 0; - QApplicationPrivate::is_app_closing = true; - QApplicationPrivate::is_app_running = false; #ifndef QT_NO_CLIPBOARD delete qt_clipboard; 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); @@ -1043,6 +1074,8 @@ QApplication::~QApplication() delete QDragManager::self(); #endif + d->cleanupMultitouch(); + qt_cleanup(); if (QApplicationPrivate::widgetCount) @@ -1069,8 +1102,11 @@ QApplication::~QApplication() QApplicationPrivate::fade_tooltip = false; QApplicationPrivate::widgetCount = false; +#ifndef QT_NO_STATEMACHINE + // trigger unregistering of QStateMachine's GUI types + qUnregisterGuiStateMachine(); +#endif // trigger unregistering of QVariant's GUI types - extern int qUnregisterGuiVariant(); qUnregisterGuiVariant(); } @@ -1151,6 +1187,7 @@ bool QApplication::compressEvent(QEvent *event, QObject *receiver, QPostEventLis || event->type() == QEvent::Resize || event->type() == QEvent::Move || event->type() == QEvent::LanguageChange + || event->type() == QEvent::UpdateSoftKeys || event->type() == QEvent::InputMethod)) { for (int i = 0; i < postedEvents->size(); ++i) { const QPostEvent &cur = postedEvents->at(i); @@ -1168,6 +1205,8 @@ bool QApplication::compressEvent(QEvent *event, QObject *receiver, QPostEventLis ((QMoveEvent *)(cur.event))->p = ((QMoveEvent *)event)->p; } else if (cur.event->type() == QEvent::LanguageChange) { ; + } else if (cur.event->type() == QEvent::UpdateSoftKeys) { + ; } else if ( cur.event->type() == QEvent::InputMethod ) { *(QInputMethodEvent *)(cur.event) = *(QInputMethodEvent *)event; } else { @@ -1197,21 +1236,22 @@ bool QApplication::compressEvent(QEvent *event, QObject *receiver, QPostEventLis \since 4.4 \brief defines a threshold for auto maximizing widgets - The auto maximize threshold is only available as part of Qt for Windows CE. + \bold{The auto maximize threshold is only available as part of Qt for + Windows CE.} This property defines a threshold for the size of a window as a percentage of the screen size. If the minimum size hint of a window exceeds the - threshold, calling show() will then cause the window to be maximized + threshold, calling show() will cause the window to be maximized automatically. - Setting the threshold to be 100 or greater means that it will cause it to - always be maximized. Setting it to be 50 means that the widget is maximized - if the vertical minimum size hint is at least 50% of the vertical screen - size. + Setting the threshold to 100 or greater means that the widget will always + be maximized. Alternatively, setting the threshold to 50 means that the + widget will be maximized only if the vertical minimum size hint is at least + 50% of the vertical screen size. - If -1 is specified then this will disable the feature. + Setting the threshold to -1 disables the feature. - On Windows CE the default is -1 (i.e. it is disabled). + On Windows CE the default is -1 (i.e., it is disabled). On Windows Mobile the default is 40. */ @@ -1220,14 +1260,18 @@ bool QApplication::compressEvent(QEvent *event, QObject *receiver, QPostEventLis \since 4.5 \brief toggles automatic SIP (software input panel) visibility - The auto SIP property is only available as part of Qt for Windows CE. - - Set this property to true to automatically display the SIP when entering + 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_OS_WINCE +#ifdef Q_WS_WINCE void QApplication::setAutoMaximizeThreshold(const int threshold) { QApplicationPrivate::autoMaximizeThreshold = threshold; @@ -1237,6 +1281,7 @@ int QApplication::autoMaximizeThreshold() const { return QApplicationPrivate::autoMaximizeThreshold; } +#endif void QApplication::setAutoSipEnabled(const bool enabled) { @@ -1247,7 +1292,6 @@ bool QApplication::autoSipEnabled() const { return QApplicationPrivate::autoSipEnabled; } -#endif #ifndef QT_NO_STYLE_STYLESHEET @@ -1289,44 +1333,14 @@ QStyle *QApplication::style() return 0; } -#if defined(Q_WS_X11) - if(!QApplicationPrivate::styleOverride) - QApplicationPrivate::x11_initialize_style(); // run-time search for default style -#endif if (!QApplicationPrivate::app_style) { // Compile-time search for default style // QString style; - if (QApplicationPrivate::styleOverride) { - style = *QApplicationPrivate::styleOverride; - delete QApplicationPrivate::styleOverride; - QApplicationPrivate::styleOverride = 0; - } else { -#if defined(Q_WS_WIN) && defined(Q_OS_WINCE) - if (qt_wince_is_smartphone() || qt_wince_is_pocket_pc()) - style = QLatin1String("WindowsMobile"); - else - style = QLatin1String("WindowsCE"); - -#elif defined(Q_WS_WIN) - if ((QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA - && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)) - style = QLatin1String("WindowsVista"); - else if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP - && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)) - style = QLatin1String("WindowsXP"); - else - style = QLatin1String("Windows"); // default styles for Windows -#elif defined(Q_WS_X11) && defined(Q_OS_SOLARIS) - style = QLatin1String("CDE"); // default style for X11 on Solaris -#elif defined(Q_WS_X11) && defined(Q_OS_IRIX) - style = QLatin1String("SGI"); // default style for X11 on IRIX -#elif defined(Q_WS_X11) || defined(Q_WS_QWS) - style = QLatin1String("Plastique"); // default style for X11 and small devices -#elif defined(Q_WS_MAC) - style = QLatin1String("Macintosh"); // default style for all Mac's -#endif - } + if (!QApplicationPrivate::styleOverride.isEmpty()) + style = QApplicationPrivate::styleOverride; + else + style = QApplicationPrivate::desktopStyleKey(); QStyle *&app_style = QApplicationPrivate::app_style; app_style = QStyleFactory::create(style); @@ -1414,7 +1428,6 @@ void QApplication::setStyle(QStyle *style) } else #endif // QT_NO_STYLE_STYLESHEET QApplicationPrivate::app_style = style; - QApplicationPrivate::app_style->setParent(qApp); // take ownership // take care of possible palette requirements of certain gui @@ -1551,7 +1564,7 @@ int QApplication::colorSpec() strategy. Use this option if your application uses buttons, menus, texts and pixmaps with few colors. With this option, the application uses system global colors. This works fine for most - applications under X11, but on Windows machines it may cause + applications under X11, but on the Windows platform, it may cause dithering of non-standard colors. \o QApplication::CustomColor. Use this option if your application needs a small number of custom colors. On X11, this option is the @@ -1938,6 +1951,13 @@ void QApplicationPrivate::setSystemFont(const QFont &font) QApplication::setFont(*sys_font); } +/*! \internal +*/ +QString QApplicationPrivate::desktopStyleKey() +{ + return qt_guiPlatformPlugin()->styleName(); +} + /*! \property QApplication::windowIcon \brief the default window icon @@ -2010,12 +2030,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(); } /*! @@ -2053,7 +2070,7 @@ void QApplicationPrivate::setFocusWidget(QWidget *focus, Qt::FocusReason reason) } QWidget *prev = focus_widget; focus_widget = focus; - +#ifndef QT_NO_IM if (prev && ((reason != Qt::PopupFocusReason && reason != Qt::MenuBarFocusReason && prev->testAttribute(Qt::WA_InputMethodEnabled)) // Do reset the input context, in case the new focus widget won't accept keyboard input @@ -2066,6 +2083,7 @@ void QApplicationPrivate::setFocusWidget(QWidget *focus, Qt::FocusReason reason) qic->setFocusWidget(0); } } +#endif //QT_NO_IM if(focus_widget) focus_widget->d_func()->setFocus_sys(); @@ -2080,6 +2098,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); @@ -2087,11 +2115,14 @@ void QApplicationPrivate::setFocusWidget(QWidget *focus, Qt::FocusReason reason) QApplication::sendEvent(that->style(), &out); } if(focus && QApplicationPrivate::focus_widget == focus) { +#ifndef QT_NO_IM if (focus->testAttribute(Qt::WA_InputMethodEnabled)) { QInputContext *qic = focus->inputContext(); - if (qic && focus_widget->testAttribute(Qt::WA_WState_Created)) - qic->setFocusWidget( focus_widget ); + if (qic && focus->testAttribute(Qt::WA_WState_Created) + && focus->isEnabled()) + qic->setFocusWidget(focus); } +#endif //QT_NO_IM QFocusEvent in(QEvent::FocusIn, reason); QPointer<QWidget> that = focus; QApplication::sendEvent(focus, &in); @@ -2309,10 +2340,6 @@ bool QApplication::event(QEvent *e) } else if (te->timerId() == d->toolTipFallAsleep.timerId()) { d->toolTipFallAsleep.stop(); } -#ifdef QT_MAC_USE_COCOA - } else if (e->type() == QEvent::CocoaRequestModal) { - d->_q_runAppModalWindow(); -#endif } return QCoreApplication::event(e); } @@ -2456,6 +2483,7 @@ void QApplication::setActiveWindow(QWidget* act) /*!internal * Helper function that returns the new focus widget, but does not set the focus reason. * Returns 0 if a new focus widget could not be found. + * Shared with QGraphicsProxyWidgetPrivate::findFocusChild() */ QWidget *QApplicationPrivate::focusNextPrevChild_helper(QWidget *toplevel, bool next) { @@ -2496,12 +2524,6 @@ QWidget *QApplicationPrivate::focusNextPrevChild_helper(QWidget *toplevel, bool Creates the proper Enter/Leave event when widget \a enter is entered and widget \a leave is left. */ -#if defined(Q_WS_WIN) - extern void qt_win_set_cursor(QWidget *, bool); -#elif defined(Q_WS_X11) - extern void qt_x11_enforce_cursor(QWidget *, bool); -#endif - void QApplicationPrivate::dispatchEnterLeave(QWidget* enter, QWidget* leave) { #if 0 if (leave) { @@ -2576,14 +2598,14 @@ void QApplicationPrivate::dispatchEnterLeave(QWidget* enter, QWidget* leave) { QEvent leaveEvent(QEvent::Leave); for (int i = 0; i < leaveList.size(); ++i) { w = leaveList.at(i); - if (!qApp->activeModalWidget() || QApplicationPrivate::tryModalHelper(w, 0)) { + if (!QApplication::activeModalWidget() || QApplicationPrivate::tryModalHelper(w, 0)) { #if defined(Q_WS_WIN) || defined(Q_WS_X11) if (leaveAfterRelease == w) leaveAfterRelease = 0; #endif QApplication::sendEvent(w, &leaveEvent); if (w->testAttribute(Qt::WA_Hover) && - (!qApp->activePopupWidget() || qApp->activePopupWidget() == w->window())) { + (!QApplication::activePopupWidget() || QApplication::activePopupWidget() == w->window())) { Q_ASSERT(instance()); QHoverEvent he(QEvent::HoverLeave, QPoint(-1, -1), w->mapFromGlobal(QApplicationPrivate::instance()->hoverGlobalPos)); qApp->d_func()->notify_helper(w, &he); @@ -2594,10 +2616,10 @@ void QApplicationPrivate::dispatchEnterLeave(QWidget* enter, QWidget* leave) { QEvent enterEvent(QEvent::Enter); for (int i = 0; i < enterList.size(); ++i) { w = enterList.at(i); - if (!qApp->activeModalWidget() || QApplicationPrivate::tryModalHelper(w, 0)) { + if (!QApplication::activeModalWidget() || QApplicationPrivate::tryModalHelper(w, 0)) { QApplication::sendEvent(w, &enterEvent); if (w->testAttribute(Qt::WA_Hover) && - (!qApp->activePopupWidget() || qApp->activePopupWidget() == w->window())) { + (!QApplication::activePopupWidget() || QApplication::activePopupWidget() == w->window())) { QHoverEvent he(QEvent::HoverEnter, w->mapFromGlobal(posEnter), QPoint(-1, -1)); qApp->d_func()->notify_helper(w, &he); } @@ -2617,7 +2639,10 @@ void QApplicationPrivate::dispatchEnterLeave(QWidget* enter, QWidget* leave) { if (!isAlien(w)) break; if (w->testAttribute(Qt::WA_SetCursor)) { - parentOfLeavingCursor = w->parentWidget(); + QWidget *parent = w->parentWidget(); + while (parent && parent->d_func()->data.in_destructor) + parent = parent->parentWidget(); + parentOfLeavingCursor = parent; //continue looping, we need to find the downest alien widget with a cursor. // (downest on the screen) } @@ -2651,6 +2676,8 @@ void QApplicationPrivate::dispatchEnterLeave(QWidget* enter, QWidget* leave) { qt_win_set_cursor(cursorWidget, true); #elif defined(Q_WS_X11) qt_x11_enforce_cursor(cursorWidget, true); +#elif defined(Q_WS_S60) + qt_symbian_set_cursor(cursorWidget, true); #endif } } @@ -2671,7 +2698,7 @@ bool QApplicationPrivate::isBlockedByModal(QWidget *widget) widget = widget->window(); if (!modalState()) return false; - if (qApp->activePopupWidget() == widget) + if (QApplication::activePopupWidget() == widget) return false; for (int i = 0; i < qt_modal_stack->size(); ++i) { @@ -2760,7 +2787,7 @@ bool QApplicationPrivate::isBlockedByModal(QWidget *widget) void QApplicationPrivate::enterModal(QWidget *widget) { QSet<QWidget*> blocked; - QList<QWidget*> windows = qApp->topLevelWidgets(); + QList<QWidget*> windows = QApplication::topLevelWidgets(); for (int i = 0; i < windows.count(); ++i) { QWidget *window = windows.at(i); if (window->windowType() != Qt::Tool && isBlockedByModal(window)) @@ -2769,7 +2796,7 @@ void QApplicationPrivate::enterModal(QWidget *widget) enterModal_sys(widget); - windows = qApp->topLevelWidgets(); + windows = QApplication::topLevelWidgets(); QEvent e(QEvent::WindowBlocked); for (int i = 0; i < windows.count(); ++i) { QWidget *window = windows.at(i); @@ -2783,7 +2810,7 @@ void QApplicationPrivate::enterModal(QWidget *widget) void QApplicationPrivate::leaveModal(QWidget *widget) { QSet<QWidget*> blocked; - QList<QWidget*> windows = qApp->topLevelWidgets(); + QList<QWidget*> windows = QApplication::topLevelWidgets(); for (int i = 0; i < windows.count(); ++i) { QWidget *window = windows.at(i); if (window->windowType() != Qt::Tool && isBlockedByModal(window)) @@ -2792,7 +2819,7 @@ void QApplicationPrivate::leaveModal(QWidget *widget) leaveModal_sys(widget); - windows = qApp->topLevelWidgets(); + windows = QApplication::topLevelWidgets(); QEvent e(QEvent::WindowUnblocked); for (int i = 0; i < windows.count(); ++i) { QWidget *window = windows.at(i); @@ -2815,7 +2842,7 @@ bool QApplicationPrivate::tryModalHelper(QWidget *widget, QWidget **rettop) *rettop = top; // the active popup widget always gets the input event - if (qApp->activePopupWidget()) + if (QApplication::activePopupWidget()) return true; #if defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA) @@ -2849,7 +2876,7 @@ QWidget *QApplicationPrivate::pickMouseReceiver(QWidget *candidate, const QPoint QWidget *receiver = candidate; if (!mouseGrabber) - mouseGrabber = buttonDown ? buttonDown : alienWidget; + mouseGrabber = (buttonDown && !isBlockedByModal(buttonDown)) ? buttonDown : alienWidget; if (mouseGrabber && mouseGrabber != candidate) { receiver = mouseGrabber; @@ -2868,7 +2895,8 @@ QWidget *QApplicationPrivate::pickMouseReceiver(QWidget *candidate, const QPoint */ bool QApplicationPrivate::sendMouseEvent(QWidget *receiver, QMouseEvent *event, QWidget *alienWidget, QWidget *nativeWidget, - QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver) + QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver, + bool spontaneous) { Q_ASSERT(receiver); Q_ASSERT(event); @@ -2881,7 +2909,7 @@ bool QApplicationPrivate::sendMouseEvent(QWidget *receiver, QMouseEvent *event, QPointer<QWidget> receiverGuard = receiver; QPointer<QWidget> nativeGuard = nativeWidget; QPointer<QWidget> alienGuard = alienWidget; - QPointer<QWidget> activePopupWidget = qApp->activePopupWidget(); + QPointer<QWidget> activePopupWidget = QApplication::activePopupWidget(); const bool graphicsWidget = nativeWidget->testAttribute(Qt::WA_DontShowOnScreen); @@ -2921,7 +2949,11 @@ bool QApplicationPrivate::sendMouseEvent(QWidget *receiver, QMouseEvent *event, // We need this quard in case someone opens a modal dialog / popup. If that's the case // leaveAfterRelease is set to null, but we shall not update lastMouseReceiver. const bool wasLeaveAfterRelease = leaveAfterRelease != 0; - bool result = QApplication::sendSpontaneousEvent(receiver, event); + bool result; + if (spontaneous) + result = QApplication::sendSpontaneousEvent(receiver, event); + else + result = QApplication::sendEvent(receiver, event); if (!graphicsWidget && leaveAfterRelease && event->type() == QEvent::MouseButtonRelease && !event->buttons() && QWidget::mouseGrabber() != leaveAfterRelease) { @@ -2950,7 +2982,7 @@ bool QApplicationPrivate::sendMouseEvent(QWidget *receiver, QMouseEvent *event, return result; } -#if defined(Q_WS_WIN) || defined(Q_WS_X11) +#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined(Q_WS_QWS) /* This function should only be called when the widget changes visibility, i.e. when the \a widget is shown, hidden or deleted. This function does nothing @@ -2962,9 +2994,13 @@ extern QWidget *qt_button_down; void QApplicationPrivate::sendSyntheticEnterLeave(QWidget *widget) { #ifndef QT_NO_CURSOR +#ifdef Q_WS_QWS + if (!widget || widget->isWindow()) + return; +#else if (!widget || widget->internalWinId() || widget->isWindow()) return; - +#endif const bool widgetInShow = widget->isVisible() && !widget->data->in_destructor; if (!widgetInShow && widget != qt_last_mouse_receiver) return; // Widget was not under the cursor when it was hidden/deleted. @@ -3477,6 +3513,15 @@ void QApplication::changeOverrideCursor(const QCursor &cursor) if (qApp->d_func()->cursor_list.isEmpty()) return; qApp->d_func()->cursor_list.removeFirst(); +#ifdef QT_MAC_USE_COCOA + // We use native NSCursor stacks in Cocoa. The currentCursor is the + // top of this stack. So to avoid flickering of cursor, we have to + // change the cusor instead of pop-ing the existing OverrideCursor + // and pushing the new one. + qApp->d_func()->cursor_list.prepend(cursor); + qt_cocoaChangeOverrideCursor(cursor); + return; +#endif setOverrideCursor(cursor); } #endif @@ -3496,7 +3541,7 @@ void QApplication::changeOverrideCursor(const QCursor &cursor) It is necessary to call this function to start event handling. The main event loop receives events from the window system and dispatches these to the application widgets. - + Generally, no user interaction can take place before calling exec(). As a special case, modal widgets like QMessageBox can be used before calling exec(), because modal widgets call exec() to start a local event loop. @@ -3507,12 +3552,12 @@ void QApplication::changeOverrideCursor(const QCursor &cursor) We recommend that you connect clean-up code to the \l{QCoreApplication::}{aboutToQuit()} signal, instead of putting it in your - application's \c{main()} function because on some platforms the - QApplication::exec() call may not return. For example, on Windows when the - user logs off, the system terminates the process after Qt closes all - top-level windows. Hence, there is no guarantee that the application will - have time to exit its event loop and execute code at the end of the - \c{main()} function after the QApplication::exec() call. + application's \c{main()} function. This is because, on some platforms the + QApplication::exec() call may not return. For example, on the Windows + platform, when the user logs off, the system terminates the process after Qt + closes all top-level windows. Hence, there is \e{no guarantee} that the + application will have time to exit its event loop and execute code at the + end of the \c{main()} function, after the QApplication::exec() call. \sa quitOnLastWindowClosed, quit(), exit(), processEvents(), QCoreApplication::exec() @@ -3562,26 +3607,36 @@ bool QApplication::notify(QObject *receiver, QEvent *e) QApplicationPrivate::mouse_buttons |= me->button(); else QApplicationPrivate::mouse_buttons &= ~me->button(); - } + } #if !defined(QT_NO_WHEELEVENT) || !defined(QT_NO_TABLETEVENT) - else if ( + else if (false # ifndef QT_NO_WHEELEVENT - e->type() == QEvent::Wheel -# else - false + || e->type() == QEvent::Wheel # endif # ifndef QT_NO_TABLETEVENT - || e->type() == QEvent::TabletMove - || e->type() == QEvent::TabletPress - || e->type() == QEvent::TabletRelease + || e->type() == QEvent::TabletMove + || e->type() == QEvent::TabletPress + || e->type() == QEvent::TabletRelease # endif - ) { + ) { QInputEvent *ie = static_cast<QInputEvent*>(e); QApplicationPrivate::modifier_buttons = ie->modifiers(); } #endif // !QT_NO_WHEELEVENT || !QT_NO_TABLETEVENT } + // walk through parents and check for gestures + if (qt_gestureManager) { + if (receiver->isWidgetType()) { + if (qt_gestureManager->filterEvent(static_cast<QWidget *>(receiver), e)) + return true; + } else if (QGesture *gesture = qobject_cast<QGesture *>(receiver)) { + if (qt_gestureManager->filterEvent(gesture, e)) + return true; + } + } + + // User input and window activation makes tooltips sleep switch (e->type()) { case QEvent::Wheel: @@ -3594,6 +3649,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e) case QEvent::MouseButtonRelease: case QEvent::MouseButtonDblClick: d->toolTipFallAsleep.stop(); + // fall-through case QEvent::Leave: d->toolTipWakeUp.stop(); default: @@ -3709,19 +3765,18 @@ 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) { - QWidget *fw = w; - while (fw) { - if (fw->isEnabled() - && QApplicationPrivate::shouldSetFocus(fw, Qt::ClickFocus)) { - fw->setFocus(Qt::MouseFocusReason); - break; - } - if (fw->isWindow()) - break; - fw = fw->parentWidget(); - } + QApplicationPrivate::giveFocusAccordingToFocusPolicy(w, + Qt::ClickFocus, + Qt::MouseFocusReason); } // ### Qt 5 These dynamic tool tips should be an OPT-IN feature. Some platforms @@ -3787,7 +3842,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e) QPoint diff = relpos - w->mapFromGlobal(d->hoverGlobalPos); while (w) { if (w->testAttribute(Qt::WA_Hover) && - (!qApp->activePopupWidget() || qApp->activePopupWidget() == w->window())) { + (!QApplication::activePopupWidget() || QApplication::activePopupWidget() == w->window())) { QHoverEvent he(QEvent::HoverMove, relpos, relpos - diff); d->notify_helper(w, &he); } @@ -3810,17 +3865,9 @@ bool QApplication::notify(QObject *receiver, QEvent *e) bool eventAccepted = wheel->isAccepted(); if (e->spontaneous()) { - QWidget *fw = w; - while (fw) { - if (fw->isEnabled() - && QApplicationPrivate::shouldSetFocus(fw, Qt::WheelFocus)) { - fw->setFocus(Qt::MouseFocusReason); - break; - } - if (fw->isWindow()) - break; - fw = fw->parentWidget(); - } + QApplicationPrivate::giveFocusAccordingToFocusPolicy(w, + Qt::WheelFocus, + Qt::MouseFocusReason); } while (w) { @@ -4025,7 +4072,137 @@ bool QApplication::notify(QObject *receiver, QEvent *e) } break; #endif + case QEvent::TouchBegin: + // Note: TouchUpdate and TouchEnd events are never propagated + { + QWidget *widget = static_cast<QWidget *>(receiver); + QTouchEvent *touchEvent = static_cast<QTouchEvent *>(e); + bool eventAccepted = touchEvent->isAccepted(); + if (widget->testAttribute(Qt::WA_AcceptTouchEvents) && e->spontaneous()) { + // give the widget focus if the focus policy allows it + QApplicationPrivate::giveFocusAccordingToFocusPolicy(widget, + Qt::ClickFocus, + Qt::MouseFocusReason); + } + + while (widget) { + // first, try to deliver the touch event + bool acceptTouchEvents = widget->testAttribute(Qt::WA_AcceptTouchEvents); + touchEvent->setWidget(widget); + touchEvent->setAccepted(acceptTouchEvents); + res = acceptTouchEvents && d->notify_helper(widget, touchEvent); + eventAccepted = touchEvent->isAccepted(); + widget->setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent, res && eventAccepted); + touchEvent->spont = false; + if (res && eventAccepted) { + // the first widget to accept the TouchBegin gets an implicit grab. + for (int i = 0; i < touchEvent->touchPoints().count(); ++i) { + const QTouchEvent::TouchPoint &touchPoint = touchEvent->touchPoints().at(i); + d->widgetForTouchPointId[touchPoint.id()] = widget; + } + break; + } else if (widget->isWindow() || widget->testAttribute(Qt::WA_NoMousePropagation)) { + break; + } + widget = widget->parentWidget(); + d->updateTouchPointsForWidget(widget, touchEvent); + } + + 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) + QWidget *w = static_cast<QWidget *>(receiver); + while (w) { + e->ignore(); + res = d->notify_helper(w, e); + if ((res && e->isAccepted()) || w->isWindow()) + break; + w = w->parentWidget(); + } + break; + } + case QEvent::Gesture: + case QEvent::GestureOverride: + { + if (receiver->isWidgetType()) { + QWidget *w = static_cast<QWidget *>(receiver); + QGestureEvent *gestureEvent = static_cast<QGestureEvent *>(e); + QList<QGesture *> allGestures = gestureEvent->gestures(); + + bool eventAccepted = gestureEvent->isAccepted(); + bool wasAccepted = eventAccepted; + while (w) { + // send only gestures the widget expects + QList<QGesture *> gestures; + QWidgetPrivate *wd = w->d_func(); + for (int i = 0; i < allGestures.size();) { + QGesture *g = allGestures.at(i); + Qt::GestureType type = g->gestureType(); + QMap<Qt::GestureType, Qt::GestureFlags>::iterator contextit = + wd->gestureContext.find(type); + bool deliver = contextit != wd->gestureContext.end() && + (g->state() == Qt::GestureStarted || w == receiver || + (contextit.value() & Qt::ReceivePartialGestures)); + if (deliver) { + allGestures.removeAt(i); + gestures.append(g); + } else { + ++i; + } + } + if (!gestures.isEmpty()) { // we have gestures for this w + QGestureEvent ge(gestures); + ge.t = gestureEvent->t; + ge.spont = gestureEvent->spont; + ge.m_accept = wasAccepted; + ge.d_func()->accepted = gestureEvent->d_func()->accepted; + res = d->notify_helper(w, &ge); + gestureEvent->spont = false; + eventAccepted = ge.isAccepted(); + for (int i = 0; i < gestures.size(); ++i) { + QGesture *g = gestures.at(i); + if ((res && eventAccepted) || (!eventAccepted && ge.isAccepted(g))) { + // if the gesture was accepted, mark the target widget for it + gestureEvent->d_func()->targetWidgets[g->gestureType()] = w; + gestureEvent->setAccepted(g, true); + } else if (!eventAccepted && !ge.isAccepted(g)) { + // if the gesture was explicitly ignored by the application, + // put it back so a parent can get it + allGestures.append(g); + } + } + } + if (allGestures.isEmpty()) // everything delivered + break; + if (w->isWindow()) + break; + w = w->parentWidget(); + } + foreach (QGesture *g, allGestures) + gestureEvent->setAccepted(g, false); + gestureEvent->m_accept = false; // to make sure we check individual gestures + } else { + res = d->notify_helper(receiver, e); + } + break; + } default: res = d->notify_helper(receiver, e); break; @@ -4043,10 +4220,10 @@ bool QApplicationPrivate::notify_helper(QObject *receiver, QEvent * e) if (receiver->isWidgetType()) { QWidget *widget = static_cast<QWidget *>(receiver); -#if !defined(Q_OS_WINCE) || (defined(GWES_ICONCURS) && !defined(QT_NO_CURSOR)) +#if !defined(Q_WS_WINCE) || (defined(GWES_ICONCURS) && !defined(QT_NO_CURSOR)) // toggle HasMouse widget state on enter and leave if ((e->type() == QEvent::Enter || e->type() == QEvent::DragEnter) && - (!qApp->activePopupWidget() || qApp->activePopupWidget() == widget->window())) + (!QApplication::activePopupWidget() || QApplication::activePopupWidget() == widget->window())) widget->setAttribute(Qt::WA_UnderMouse, true); else if (e->type() == QEvent::Leave || e->type() == QEvent::DragLeave) widget->setAttribute(Qt::WA_UnderMouse, false); @@ -4072,9 +4249,6 @@ bool QApplicationPrivate::notify_helper(QObject *receiver, QEvent * e) \class QSessionManager \brief The QSessionManager class provides access to the session manager. - \ingroup application - \ingroup environment - A session manager in a desktop environment (in which Qt GUI applications live) keeps track of a session, which is a group of running applications, each of which has a particular state. The state of an application contains @@ -4373,13 +4547,13 @@ HRESULT qt_CoCreateGuid(GUID* guid) { // We will use the following information to create the GUID // 1. absolute path to application - wchar_t tempFilename[512]; - if (!GetModuleFileNameW(0, tempFilename, 512)) + wchar_t tempFilename[MAX_PATH]; + if (!GetModuleFileName(0, tempFilename, MAX_PATH)) return S_FALSE; - unsigned int hash = qHash(QString::fromUtf16((const unsigned short *) tempFilename)); + unsigned int hash = qHash(QString::fromWCharArray(tempFilename)); guid->Data1 = hash; // 2. creation time of file - QFileInfo info(QString::fromUtf16((const unsigned short *) tempFilename)); + QFileInfo info(QString::fromWCharArray(tempFilename)); guid->Data2 = qHash(info.created().toTime_t()); // 3. current system time guid->Data3 = qHash(QDateTime::currentDateTime().toTime_t()); @@ -4413,10 +4587,10 @@ QSessionManager::QSessionManager(QApplication * app, QString &id, QString &key) GUID guid; CoCreateGuid(&guid); StringFromGUID2(guid, guidstr, 40); - id = QString::fromUtf16((ushort*)guidstr); + id = QString::fromWCharArray(guidstr); CoCreateGuid(&guid); StringFromGUID2(guid, guidstr, 40); - key = QString::fromUtf16((ushort*)guidstr); + key = QString::fromWCharArray(guidstr); #endif d->sessionId = id; d->sessionKey = key; @@ -4576,9 +4750,9 @@ void QSessionManager::requestPhase2() \oldcode app.setWinStyleHighlightColor(color); \newcode - QPalette palette(qApp->palette()); + QPalette palette(QApplication::palette()); palette.setColor(QPalette::Highlight, color); - qApp->setPalette(palette); + QApplication::setPalette(palette); \endcode */ @@ -4597,7 +4771,7 @@ void QSessionManager::requestPhase2() /*! \fn const QColor &QApplication::winStyleHighlightColor() - Use qApp->palette().color(QPalette::Active, QPalette::Highlight) instead. + Use QApplication::palette().color(QPalette::Active, QPalette::Highlight) instead. */ /*! @@ -4682,39 +4856,104 @@ void QApplicationPrivate::emitLastWindowClosed() #ifdef QT_KEYPAD_NAVIGATION /*! - Sets whether Qt should use focus navigation suitable for use with a - minimal keypad. + Sets the kind of focus navigation Qt should use to \a mode. + + This feature is available in Qt for Embedded Linux, Symbian and Windows CE + only. + + \note On Windows CE this feature is disabled by default for touch device + mkspecs. To enable keypad navigation, build Qt with + QT_KEYPAD_NAVIGATION defined. + + \note On Symbian, setting the mode to Qt::NavigationModeCursorAuto will enable a + virtual mouse cursor on non touchscreen devices, which is controlled + by the cursor keys if there is no analog pointer device. + On other platforms and on touchscreen devices, it has the same + meaning as Qt::NavigationModeNone. + + \since 4.6 - If \a enable is true, Qt::Key_Up and Qt::Key_Down are used to change focus. + \sa keypadNavigationEnabled() +*/ +void QApplication::setNavigationMode(Qt::NavigationMode mode) +{ +#ifdef Q_OS_SYMBIAN + QApplicationPrivate::setNavigationMode(mode); +#else + QApplicationPrivate::navigationMode = mode; +#endif +} + +/*! + Returns what kind of focus navigation Qt is using. - This feature is available in Qt for Embedded Linux and Windows CE only. + This feature is available in Qt for Embedded Linux, Symbian and Windows CE + only. \note On Windows CE this feature is disabled by default for touch device mkspecs. To enable keypad navigation, build Qt with QT_KEYPAD_NAVIGATION defined. + \note On Symbian, the default mode is Qt::NavigationModeNone for touch + devices, and Qt::NavigationModeKeypadDirectional. + + \since 4.6 + \sa keypadNavigationEnabled() */ +Qt::NavigationMode QApplication::navigationMode() +{ + return QApplicationPrivate::navigationMode; +} + +/*! + Sets whether Qt should use focus navigation suitable for use with a + minimal keypad. + + This feature is available in Qt for Embedded Linux, Symbian and Windows CE + only. + + \note On Windows CE this feature is disabled by default for touch device + mkspecs. To enable keypad navigation, build Qt with + QT_KEYPAD_NAVIGATION defined. + + \deprecated + + \sa setNavigationMode() +*/ void QApplication::setKeypadNavigationEnabled(bool enable) { - QApplicationPrivate::keypadNavigation = enable; + if (enable) { +#ifdef Q_OS_SYMBIAN + QApplication::setNavigationMode(Qt::NavigationModeKeypadDirectional); +#else + QApplication::setNavigationMode(Qt::NavigationModeKeypadTabOrder); +#endif + } + else { + QApplication::setNavigationMode(Qt::NavigationModeNone); + } } /*! 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 and Windows CE only. + This feature is available in Qt for Embedded Linux, Symbian and Windows CE + only. \note On Windows CE this feature is disabled by default for touch device mkspecs. To enable keypad navigation, build Qt with QT_KEYPAD_NAVIGATION defined. - \sa setKeypadNavigationEnabled() + \deprecated + + \sa navigationMode() */ bool QApplication::keypadNavigationEnabled() { - return QApplicationPrivate::keypadNavigation; + return QApplicationPrivate::navigationMode == Qt::NavigationModeKeypadTabOrder || + QApplicationPrivate::navigationMode == Qt::NavigationModeKeypadDirectional; } #endif @@ -4732,7 +4971,7 @@ bool QApplication::keypadNavigationEnabled() On Mac OS X, this works more at the application level and will cause the application icon to bounce in the dock. - On Windows this causes the window's taskbar entry to flash for a time. If + On Windows, this causes the window's taskbar entry to flash for a time. If \a msec is zero, the flashing will stop and the taskbar entry will turn a different color (currently orange). @@ -4749,24 +4988,22 @@ bool QApplication::keypadNavigationEnabled() caret display. Usually the text cursor is displayed for half the cursor flash time, then hidden for the same amount of time, but this may vary. - The default value on X11 is 1000 milliseconds. On Windows, the control - panel value is used. Widgets should not cache this value since it may be - changed at any time by the user changing the global desktop settings. + The default value on X11 is 1000 milliseconds. On Windows, the + \gui{Control Panel} value is used and setting this property sets the cursor + flash time for all applications. - \note On Microsoft Windows, setting this property sets the cursor flash - time for all applications. + We recommend that widgets do not cache this value as it may change at any + time if the user changes the global desktop settings. */ /*! \property QApplication::doubleClickInterval - \brief the time limit in milliseconds that distinguishes a double click from two - consecutive mouse clicks + \brief the time limit in milliseconds that distinguishes a double click + from two consecutive mouse clicks - The default value on X11 is 400 milliseconds. On Windows and Mac OS X, the - operating system's value is used. - - On Microsoft Windows, calling this function sets the double click interval - for all applications. + The default value on X11 is 400 milliseconds. On Windows and Mac OS, the + operating system's value is used. However, on Windows and Symbian OS, + calling this function sets the double click interval for all applications. */ /*! @@ -4775,7 +5012,7 @@ bool QApplication::keypadNavigationEnabled() from two consecutive key presses \since 4.2 - The default value on X11 is 400 milliseconds. On Windows and Mac OS X, the + The default value on X11 is 400 milliseconds. On Windows and Mac OS, the operating system's value is used. */ @@ -4840,7 +5077,7 @@ bool QApplication::keypadNavigationEnabled() You need not have a main widget; connecting lastWindowClosed() to quit() is an alternative. - For X11, this function also resizes and moves the main widget according + On X11, this function also resizes and moves the main widget according to the \e -geometry command-line option, so you should set the default geometry (using \l QWidget::setGeometry()) before calling setMainWidget(). @@ -4869,9 +5106,10 @@ bool QApplication::keypadNavigationEnabled() Application cursors are stored on an internal stack. setOverrideCursor() pushes the cursor onto the stack, and restoreOverrideCursor() pops the active cursor off the stack. changeOverrideCursor() changes the curently - active application override cursor. Every setOverrideCursor() must - eventually be followed by a corresponding restoreOverrideCursor(), - otherwise the stack will never be emptied. + active application override cursor. + + Every setOverrideCursor() must eventually be followed by a corresponding + restoreOverrideCursor(), otherwise the stack will never be emptied. Example: \snippet doc/src/snippets/code/src_gui_kernel_qapplication_x11.cpp 0 @@ -4924,8 +5162,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; } @@ -4949,6 +5186,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; } @@ -4966,6 +5208,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; } @@ -5000,6 +5244,23 @@ Qt::LayoutDirection QApplication::keyboardInputDirection() return qt_keymapper_private()->keyboardInputDirection; } +void QApplicationPrivate::giveFocusAccordingToFocusPolicy(QWidget *widget, + Qt::FocusPolicy focusPolicy, + Qt::FocusReason focusReason) +{ + QWidget *focusWidget = widget; + while (focusWidget) { + if (focusWidget->isEnabled() + && QApplicationPrivate::shouldSetFocus(focusWidget, focusPolicy)) { + focusWidget->setFocus(focusReason); + break; + } + if (focusWidget->isWindow()) + break; + focusWidget = focusWidget->parentWidget(); + } +} + bool QApplicationPrivate::shouldSetFocus(QWidget *w, Qt::FocusPolicy policy) { QWidget *f = w; @@ -5035,19 +5296,19 @@ bool QApplicationPrivate::shouldSetFocus(QWidget *w, Qt::FocusPolicy policy) */ /*! \fn QDecoration* QApplication::qwsSetDecoration(const QString &decoration) - \overload + \overload - Requests a QDecoration object for \a decoration from the QDecorationFactory. + Requests a QDecoration object for \a decoration from the + QDecorationFactory. - The string must be one of the QDecorationFactory::keys(). Keys are - case insensitive. + The string must be one of the QDecorationFactory::keys(). Keys are case + insensitive. - A later call to the QApplication constructor will override the - requested style when a "-style" option is passed in as a commandline - parameter. + A later call to the QApplication constructor will override the requested + style when a "-style" option is passed in as a commandline parameter. - Returns 0 if an unknown \a decoration is passed, otherwise the QStyle object - returned is set as the application's GUI style. + Returns 0 if an unknown \a decoration is passed, otherwise the QStyle object + returned is set as the application's GUI style. */ /*! @@ -5144,6 +5405,211 @@ bool QApplicationPrivate::shouldSetFocus(QWidget *w, Qt::FocusPolicy policy) This normally takes some time. Does nothing on other platforms. */ +void QApplicationPrivate::updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent) +{ + for (int i = 0; i < touchEvent->touchPoints().count(); ++i) { + QTouchEvent::TouchPoint &touchPoint = touchEvent->_touchPoints[i]; + + // preserve the sub-pixel resolution + QRectF rect = touchPoint.screenRect(); + const QPointF screenPos = rect.center(); + const QPointF delta = screenPos - screenPos.toPoint(); + + rect.moveCenter(widget->mapFromGlobal(screenPos.toPoint()) + delta); + touchPoint.setRect(rect); + touchPoint.setStartPos(widget->mapFromGlobal(touchPoint.startScreenPos().toPoint()) + delta); + touchPoint.setLastPos(widget->mapFromGlobal(touchPoint.lastScreenPos().toPoint()) + delta); + } +} + +void QApplicationPrivate::initializeMultitouch() +{ + widgetForTouchPointId.clear(); + appCurrentTouchPoints.clear(); + + initializeMultitouch_sys(); +} + +void QApplicationPrivate::cleanupMultitouch() +{ + cleanupMultitouch_sys(); + + widgetForTouchPointId.clear(); + appCurrentTouchPoints.clear(); +} + +int QApplicationPrivate::findClosestTouchPointId(const QPointF &screenPos) +{ + int closestTouchPointId = -1; + qreal closestDistance = qreal(0.); + foreach (const QTouchEvent::TouchPoint &touchPoint, appCurrentTouchPoints) { + qreal distance = QLineF(screenPos, touchPoint.screenPos()).length(); + if (closestTouchPointId == -1 || distance < closestDistance) { + closestTouchPointId = touchPoint.id(); + closestDistance = distance; + } + } + return closestTouchPointId; +} + +void QApplicationPrivate::translateRawTouchEvent(QWidget *window, + QTouchEvent::DeviceType deviceType, + const QList<QTouchEvent::TouchPoint> &touchPoints) +{ + QApplicationPrivate *d = self; + typedef QPair<Qt::TouchPointStates, QList<QTouchEvent::TouchPoint> > StatesAndTouchPoints; + QHash<QWidget *, StatesAndTouchPoints> widgetsNeedingEvents; + + for (int i = 0; i < touchPoints.count(); ++i) { + QTouchEvent::TouchPoint touchPoint = touchPoints.at(i); + + // update state + QWidget *widget = 0; + switch (touchPoint.state()) { + case Qt::TouchPointPressed: + { + if (deviceType == QTouchEvent::TouchPad) { + // on touch-pads, send all touch points to the same widget + widget = d->widgetForTouchPointId.isEmpty() + ? 0 + : d->widgetForTouchPointId.constBegin().value(); + } + + if (!widget) { + // determine which widget this event will go to + if (!window) + window = QApplication::topLevelAt(touchPoint.screenPos().toPoint()); + if (!window) + continue; + widget = window->childAt(window->mapFromGlobal(touchPoint.screenPos().toPoint())); + if (!widget) + widget = window; + } + + if (deviceType == QTouchEvent::TouchScreen) { + int closestTouchPointId = d->findClosestTouchPointId(touchPoint.screenPos()); + QWidget *closestWidget = d->widgetForTouchPointId.value(closestTouchPointId); + if (closestWidget + && (widget->isAncestorOf(closestWidget) || closestWidget->isAncestorOf(widget))) { + widget = closestWidget; + } + } + + d->widgetForTouchPointId[touchPoint.id()] = widget; + touchPoint.setStartScreenPos(touchPoint.screenPos()); + touchPoint.setLastScreenPos(touchPoint.screenPos()); + touchPoint.setStartNormalizedPos(touchPoint.normalizedPos()); + touchPoint.setLastNormalizedPos(touchPoint.normalizedPos()); + if (touchPoint.pressure() < qreal(0.)) + touchPoint.setPressure(qreal(1.)); + d->appCurrentTouchPoints.insert(touchPoint.id(), touchPoint); + break; + } + case Qt::TouchPointReleased: + { + widget = d->widgetForTouchPointId.take(touchPoint.id()); + if (!widget) + continue; + + QTouchEvent::TouchPoint previousTouchPoint = d->appCurrentTouchPoints.take(touchPoint.id()); + touchPoint.setStartScreenPos(previousTouchPoint.startScreenPos()); + touchPoint.setLastScreenPos(previousTouchPoint.screenPos()); + touchPoint.setStartNormalizedPos(previousTouchPoint.startNormalizedPos()); + touchPoint.setLastNormalizedPos(previousTouchPoint.normalizedPos()); + if (touchPoint.pressure() < qreal(0.)) + touchPoint.setPressure(qreal(0.)); + break; + } + default: + widget = d->widgetForTouchPointId.value(touchPoint.id()); + if (!widget) + continue; + + Q_ASSERT(d->appCurrentTouchPoints.contains(touchPoint.id())); + QTouchEvent::TouchPoint previousTouchPoint = d->appCurrentTouchPoints.value(touchPoint.id()); + touchPoint.setStartScreenPos(previousTouchPoint.startScreenPos()); + touchPoint.setLastScreenPos(previousTouchPoint.screenPos()); + touchPoint.setStartNormalizedPos(previousTouchPoint.startNormalizedPos()); + touchPoint.setLastNormalizedPos(previousTouchPoint.normalizedPos()); + if (touchPoint.pressure() < qreal(0.)) + touchPoint.setPressure(qreal(1.)); + d->appCurrentTouchPoints[touchPoint.id()] = touchPoint; + break; + } + Q_ASSERT(widget != 0); + + // make the *scene* functions return the same as the *screen* functions + touchPoint.setSceneRect(touchPoint.screenRect()); + touchPoint.setStartScenePos(touchPoint.startScreenPos()); + touchPoint.setLastScenePos(touchPoint.lastScreenPos()); + + StatesAndTouchPoints &maskAndPoints = widgetsNeedingEvents[widget]; + maskAndPoints.first |= touchPoint.state(); + if (touchPoint.isPrimary()) + maskAndPoints.first |= Qt::TouchPointPrimary; + maskAndPoints.second.append(touchPoint); + } + + if (widgetsNeedingEvents.isEmpty()) + return; + + QHash<QWidget *, StatesAndTouchPoints>::ConstIterator it = widgetsNeedingEvents.constBegin(); + const QHash<QWidget *, StatesAndTouchPoints>::ConstIterator end = widgetsNeedingEvents.constEnd(); + for (; it != end; ++it) { + QWidget *widget = it.key(); + if (!QApplicationPrivate::tryModalHelper(widget, 0)) + continue; + + QEvent::Type eventType; + switch (it.value().first & Qt::TouchPointStateMask) { + case Qt::TouchPointPressed: + eventType = QEvent::TouchBegin; + break; + case Qt::TouchPointReleased: + eventType = QEvent::TouchEnd; + break; + case Qt::TouchPointStationary: + // don't send the event if nothing changed + continue; + default: + eventType = QEvent::TouchUpdate; + break; + } + + QTouchEvent touchEvent(eventType, + deviceType, + QApplication::keyboardModifiers(), + it.value().first, + it.value().second); + updateTouchPointsForWidget(widget, &touchEvent); + + switch (touchEvent.type()) { + case QEvent::TouchBegin: + { + // if the TouchBegin handler recurses, we assume that means the event + // has been implicitly accepted and continue to send touch events + widget->setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent); + (void ) QApplication::sendSpontaneousEvent(widget, &touchEvent); + break; + } + default: + if (widget->testAttribute(Qt::WA_WState_AcceptedTouchBeginEvent)) { + if (touchEvent.type() == QEvent::TouchEnd) + widget->setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent, false); + (void) QApplication::sendSpontaneousEvent(widget, &touchEvent); + } + break; + } + } +} + +Q_GUI_EXPORT void qt_translateRawTouchEvent(QWidget *window, + QTouchEvent::DeviceType deviceType, + const QList<QTouchEvent::TouchPoint> &touchPoints) +{ + QApplicationPrivate::translateRawTouchEvent(window, deviceType, touchPoints); +} + QT_END_NAMESPACE #include "moc_qapplication.cpp" diff --git a/src/gui/kernel/qapplication.h b/src/gui/kernel/qapplication.h index 456be91..e8c1281 100644 --- a/src/gui/kernel/qapplication.h +++ b/src/gui/kernel/qapplication.h @@ -61,6 +61,10 @@ QT_BEGIN_HEADER +#if defined(Q_WS_S60) +class CApaApplication; +#endif + QT_BEGIN_NAMESPACE QT_MODULE(Gui) @@ -76,6 +80,9 @@ class QLocale; #if defined(Q_WS_QWS) class QDecoration; #endif +#if defined(Q_OS_SYMBIAN) +class QSymbianEvent; +#endif class QApplication; class QApplicationPrivate; @@ -84,6 +91,7 @@ class QApplicationPrivate; #endif #define qApp (static_cast<QApplication *>(QCoreApplication::instance())) + class Q_GUI_EXPORT QApplication : public QCoreApplication { Q_OBJECT @@ -102,13 +110,18 @@ class Q_GUI_EXPORT QApplication : public QCoreApplication #ifndef QT_NO_STYLE_STYLESHEET Q_PROPERTY(QString styleSheet READ styleSheet WRITE setStyleSheet) #endif -#ifdef Q_OS_WINCE +#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 }; + +#ifdef Q_WS_S60 + typedef CApaApplication * (*QS60MainApplicationFactory)(); +#endif + #ifndef qdoc QApplication(int &argc, char **argv, int = QT_VERSION); QApplication(int &argc, char **argv, bool GUIenabled, int = QT_VERSION); @@ -117,6 +130,9 @@ public: QApplication(Display* dpy, Qt::HANDLE visual = 0, Qt::HANDLE cmap = 0, int = QT_VERSION); QApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap= 0, int = QT_VERSION); #endif +#if defined(Q_WS_S60) + QApplication(QApplication::QS60MainApplicationFactory factory, int &argc, char **argv, int = QT_VERSION); +#endif #endif virtual ~QApplication(); @@ -223,6 +239,10 @@ public: virtual int x11ClientMessage(QWidget*, XEvent*, bool passive_only); int x11ProcessEvent(XEvent*); #endif +#if defined(Q_OS_SYMBIAN) + int symbianProcessEvent(const QSymbianEvent *event); + virtual bool symbianEventFilter(const QSymbianEvent *event); +#endif #if defined(Q_WS_QWS) virtual bool qwsEventFilter(QWSEvent *); int qwsProcessEvent(QWSEvent*); @@ -239,7 +259,6 @@ public: void winFocus(QWidget *, bool); static void winMouseButtonUp(); #endif - #ifndef QT_NO_SESSIONMANAGER // session management bool isSessionRestored() const; @@ -262,8 +281,10 @@ public: static bool quitOnLastWindowClosed(); #ifdef QT_KEYPAD_NAVIGATION - static void setKeypadNavigationEnabled(bool); + static Q_DECL_DEPRECATED void setKeypadNavigationEnabled(bool); static bool keypadNavigationEnabled(); + static void setNavigationMode(Qt::NavigationMode mode); + static Qt::NavigationMode navigationMode(); #endif Q_SIGNALS: @@ -281,12 +302,12 @@ public Q_SLOTS: #ifndef QT_NO_STYLE_STYLESHEET void setStyleSheet(const QString& sheet); #endif -#ifdef Q_OS_WINCE +#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(); @@ -317,7 +338,7 @@ public: { if (replace) changeOverrideCursor(cursor); else setOverrideCursor(cursor); } # endif inline static QT3_SUPPORT bool hasGlobalMouseTracking() {return true;} - inline static QT3_SUPPORT void setGlobalMouseTracking(bool) {}; + inline static QT3_SUPPORT void setGlobalMouseTracking(bool) {} inline static QT3_SUPPORT void flushX() { flush(); } static inline QT3_SUPPORT void setWinStyleHighlightColor(const QColor &c) { QPalette p(palette()); @@ -327,7 +348,7 @@ public: static inline QT3_SUPPORT const QColor &winStyleHighlightColor() { return palette().color(QPalette::Active, QPalette::Highlight); } static inline QT3_SUPPORT void setPalette(const QPalette &pal, bool, const char* className = 0) - { setPalette(pal, className); }; + { setPalette(pal, className); } static inline QT3_SUPPORT void setFont(const QFont &font, bool, const char* className = 0) { setFont(font, className); } @@ -345,6 +366,9 @@ public: QApplication(Display* dpy, Qt::HANDLE visual = 0, Qt::HANDLE cmap = 0); QApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap= 0); #endif +#if defined(Q_WS_S60) || defined(qdoc) + QApplication(QApplication::QS60MainApplicationFactory factory, int &argc, char **argv); +#endif #endif private: @@ -374,14 +398,14 @@ private: friend class QDirectPainter; friend class QDirectPainterPrivate; #endif - -#if defined(Q_WS_WIN) - friend QApplicationPrivate* getQApplicationPrivateInternal(); -#endif + friend class QGestureManager; #if defined(Q_WS_MAC) || defined(Q_WS_X11) Q_PRIVATE_SLOT(d_func(), void _q_alertTimeOut()) #endif +#if defined(QT_RX71_MULTITOUCH) + Q_PRIVATE_SLOT(d_func(), void _q_readRX71MultiTouchEvents()) +#endif }; QT_END_NAMESPACE diff --git a/src/gui/kernel/qapplication_mac.mm b/src/gui/kernel/qapplication_mac.mm index e450f3c..84e0d50 100644 --- a/src/gui/kernel/qapplication_mac.mm +++ b/src/gui/kernel/qapplication_mac.mm @@ -154,13 +154,16 @@ #define kThemeBrushAlternatePrimaryHighlightColor -5 #endif +#define kCMDeviceUnregisteredNotification CFSTR("CMDeviceUnregisteredNotification") +#define kCMDefaultDeviceNotification CFSTR("CMDefaultDeviceNotification") +#define kCMDeviceProfilesNotification CFSTR("CMDeviceProfilesNotification") +#define kCMDefaultDeviceProfileNotification CFSTR("CMDefaultDeviceProfileNotification") QT_BEGIN_NAMESPACE //for qt_mac.h QPaintDevice *qt_mac_safe_pdev = 0; QList<QMacWindowChangeEvent*> *QMacWindowChangeEvent::change_events = 0; -extern QHash<QByteArray, QFont> *qt_app_fonts_hash(); // qapplication.cpp /***************************************************************************** Internal variables and functions @@ -200,6 +203,8 @@ static EventHandlerRef tablet_proximity_handler = 0; static EventHandlerUPP tablet_proximity_UPP = 0; bool QApplicationPrivate::native_modal_dialog_active; +Q_GUI_EXPORT bool qt_applefontsmoothing_enabled; + /***************************************************************************** External functions *****************************************************************************/ @@ -219,6 +224,12 @@ extern bool qt_sendSpontaneousEvent(QObject *obj, QEvent *event); // qapplicatio void onApplicationWindowChangedActivation( QWidget*widget, bool activated ); void onApplicationChangedActivation( bool activated ); +static void qt_mac_read_fontsmoothing_settings() +{ + NSInteger appleFontSmoothing = [[NSUserDefaults standardUserDefaults] integerForKey:@"AppleFontSmoothing"]; + qt_applefontsmoothing_enabled = (appleFontSmoothing > 0); +} + Q_GUI_EXPORT bool qt_mac_execute_apple_script(const char *script, long script_len, AEDesc *ret) { OSStatus err; AEDesc scriptTextDesc; @@ -523,9 +534,9 @@ void qt_mac_update_os_settings() for(int i = 0; mac_widget_fonts[i].qt_class; i++) { QFont fnt = qfontForThemeFont(mac_widget_fonts[i].font_key); bool set_font = true; - QHash<QByteArray, QFont> *hash = qt_app_fonts_hash(); + FontHash *hash = qt_app_fonts_hash(); if (!hash->isEmpty()) { - QHash<QByteArray, QFont>::const_iterator it + FontHash::const_iterator it = hash->constFind(mac_widget_fonts[i].qt_class); if (it != hash->constEnd()) set_font = (fnt != *it); @@ -624,10 +635,9 @@ void QApplicationPrivate::initializeWidgetPaletteHash() } bool set_palette = true; - extern QHash<QByteArray, QPalette> *qt_app_palettes_hash(); //qapplication.cpp - QHash<QByteArray, QPalette> *phash = qt_app_palettes_hash(); + PaletteHash *phash = qt_app_palettes_hash(); if (!phash->isEmpty()) { - QHash<QByteArray, QPalette>::const_iterator it + PaletteHash::const_iterator it = phash->constFind(mac_widget_colors[i].qt_class); if (it != phash->constEnd()) set_palette = (pal != *it); @@ -958,7 +968,18 @@ struct QMacAppleEventTypeSpec { { kCoreEventClass, kAEQuitApplication }, { kCoreEventClass, kAEOpenDocuments } }; + #ifndef QT_MAC_USE_COCOA + +#if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5) +enum +{ + kEventMouseScroll = 11, + kEventParamMouseWheelSmoothVerticalDelta = 'saxy', + kEventParamMouseWheelSmoothHorizontalDelta = 'saxx', +}; +#endif + /* watched events */ static EventTypeSpec app_events[] = { { kEventClassQt, kEventQtRequestWindowChange }, @@ -970,6 +991,7 @@ static EventTypeSpec app_events[] = { { kEventClassWindow, kEventWindowActivated }, { kEventClassWindow, kEventWindowDeactivated }, + { kEventClassMouse, kEventMouseScroll }, { kEventClassMouse, kEventMouseWheelMoved }, { kEventClassMouse, kEventMouseDown }, { kEventClassMouse, kEventMouseUp }, @@ -1040,16 +1062,34 @@ void qt_release_app_proc_handler() #endif } +void qt_color_profile_changed(CFNotificationCenterRef, void *, CFStringRef, const void *, + CFDictionaryRef) +{ + QCoreGraphicsPaintEngine::cleanUpMacColorSpaces(); +} /* platform specific implementations */ void qt_init(QApplicationPrivate *priv, int) { if (qt_is_gui_used) { CGDisplayRegisterReconfigurationCallback(qt_mac_display_change_callbk, 0); + CFNotificationCenterRef center = CFNotificationCenterGetDistributedCenter(); + CFNotificationCenterAddObserver(center, qApp, qt_color_profile_changed, + kCMDeviceUnregisteredNotification, 0, + CFNotificationSuspensionBehaviorDeliverImmediately); + CFNotificationCenterAddObserver(center, qApp, qt_color_profile_changed, + kCMDefaultDeviceNotification, 0, + CFNotificationSuspensionBehaviorDeliverImmediately); + CFNotificationCenterAddObserver(center, qApp, qt_color_profile_changed, + kCMDeviceProfilesNotification, 0, + CFNotificationSuspensionBehaviorDeliverImmediately); + CFNotificationCenterAddObserver(center, qApp, qt_color_profile_changed, + kCMDefaultDeviceProfileNotification, 0, + CFNotificationSuspensionBehaviorDeliverImmediately); ProcessSerialNumber psn; if (GetCurrentProcess(&psn) == noErr) { // Jambi needs to transform itself since most people aren't "used" // to putting things in bundles, but other people may actually not - // want to tranform the process (running as a helper or somethng) + // want to tranform the process (running as a helper or something) // so don't do that for them. This means checking both LSUIElement // and LSBackgroundOnly. If you set them both... well, you // shouldn't do that. @@ -1171,6 +1211,9 @@ void qt_init(QApplicationPrivate *priv, int) } if (QApplication::desktopSettingsAware()) QApplicationPrivate::qt_mac_apply_settings(); + + qt_mac_read_fontsmoothing_settings(); + // Cocoa application delegate #ifdef QT_MAC_USE_COCOA NSApplication *cocoaApp = [NSApplication sharedApplication]; @@ -1196,10 +1239,6 @@ void qt_init(QApplicationPrivate *priv, int) [qtMenuLoader release]; } #endif - if (QApplication::testAttribute(Qt::AA_MacPluginApplication)) { - extern void qt_mac_set_native_menubar(bool); - qt_mac_set_native_menubar(false); - } // Register for Carbon tablet proximity events on the event monitor target. // This means that we should receive proximity events even when we aren't the active application. if (!tablet_proximity_handler) { @@ -1228,6 +1267,12 @@ void qt_release_apple_event_handler() void qt_cleanup() { CGDisplayRemoveReconfigurationCallback(qt_mac_display_change_callbk, 0); + CFNotificationCenterRef center = CFNotificationCenterGetDistributedCenter(); + CFNotificationCenterRemoveObserver(center, qApp, kCMDeviceUnregisteredNotification, 0); + CFNotificationCenterRemoveObserver(center, qApp, kCMDefaultDeviceNotification, 0); + CFNotificationCenterRemoveObserver(center, qApp, kCMDeviceProfilesNotification, 0); + CFNotificationCenterRemoveObserver(center, qApp, kCMDefaultDeviceProfileNotification, 0); + #ifndef QT_MAC_USE_COCOA qt_release_app_proc_handler(); if (app_proc_handlerUPP) { @@ -1355,29 +1400,6 @@ QWidget *QApplication::topLevelAt(const QPoint &p) #endif } -static QWidget *qt_mac_recursive_widgetAt(QWidget *widget, int x, int y) -{ - if (!widget) - return 0; - const QObjectList kids = widget->children(); - for(int i = kids.size()-1; i >= 0; --i) { - if ( QWidget *kid = qobject_cast<QWidget*>(kids.at(i)) ) { - if (kid->isVisible() && !kid->isTopLevel() && - !kid->testAttribute(Qt::WA_TransparentForMouseEvents)) { - const int wx=kid->x(), wy=kid->y(), - wx2=wx+kid->width(), wy2=wy+kid->height(); - if (x >= wx && y >= wy && x < wx2 && y < wy2) { - const QRegion mask = kid->mask(); - if (!mask.isEmpty() && !mask.contains(QPoint(x-wx, y-wy))) - continue; - return qt_mac_recursive_widgetAt(kid, x-wx, y-wy); - } - } - } - } - return widget; -} - /***************************************************************************** Main event loop *****************************************************************************/ @@ -1410,13 +1432,8 @@ void QApplicationPrivate::enterModal_sys(QWidget *widget) qt_button_down = 0; #ifdef QT_MAC_USE_COCOA - if (!qt_mac_is_macsheet(widget)) { - // Add a new, empty (null), NSModalSession to the stack. - // The next time we spin the event dispatcher, it will - // check the stack, and recurse into a modal session for it: - QCocoaModalSessionInfo info = {widget, 0}; - QEventDispatcherMacPrivate::cocoaModalSessionStack.push(info); - } + if (!qt_mac_is_macsheet(widget)) + QEventDispatcherMacPrivate::beginModalSession(widget); #endif } @@ -1442,7 +1459,7 @@ void QApplicationPrivate::leaveModal_sys(QWidget *widget) } #ifdef QT_MAC_USE_COCOA if (!qt_mac_is_macsheet(widget)) - QEventDispatcherMacPrivate::rebuildModalSessionStack(true); + QEventDispatcherMacPrivate::endModalSession(widget); #endif } #ifdef DEBUG_MODAL_EVENTS @@ -1453,21 +1470,6 @@ void QApplicationPrivate::leaveModal_sys(QWidget *widget) qt_event_request_menubarupdate(); } -#if defined(QT_MAC_USE_COCOA) -void QApplicationPrivate::_q_runAppModalWindow() -{ - if (QEventDispatcherMacPrivate::blockCocoaRequestModal) { - // Just postpone the event until the event dispatcher tells - // us (by releasing the block) that it is OK to recurse into - // a new event loop for our non-execing modal window: - qApp->postEvent(qApp, new QEvent(QEvent::CocoaRequestModal)); - } else { - // Recurse into a new event loop for the current app modal window: - threadData->eventDispatcher->processEvents(QEventLoop::DialogExec); - } -} -#endif - QWidget *QApplicationPrivate::tryModalHelper_sys(QWidget *top) { #ifndef QT_MAC_USE_COCOA @@ -1654,21 +1656,13 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event bool inNonClientArea = false; GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, 0, sizeof(where), 0, &where); - if(ekind == kEventMouseMoved && qt_mac_app_fullscreen && - QApplication::desktop()->screenNumber(QPoint(where.h, where.v)) == - QApplication::desktop()->primaryScreen()) { - if(where.v <= 0) - ShowMenuBar(); - else if(qt_mac_window_at(where.h, where.v, 0) != inMenuBar) - HideMenuBar(); - } - #if defined(DEBUG_MOUSE_MAPS) const char *edesc = 0; switch(ekind) { case kEventMouseDown: edesc = "MouseButtonPress"; break; case kEventMouseUp: edesc = "MouseButtonRelease"; break; case kEventMouseDragged: case kEventMouseMoved: edesc = "MouseMove"; break; + case kEventMouseScroll: edesc = "MouseWheelScroll"; break; case kEventMouseWheelMoved: edesc = "MouseWheelMove"; break; } if(ekind == kEventMouseDown || ekind == kEventMouseUp) @@ -1689,12 +1683,46 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event sizeof(mac_buttons), 0, &mac_buttons); buttons = qt_mac_get_buttons(mac_buttons); } - int wheel_delta=0; - if(ekind == kEventMouseWheelMoved) { - int mdelt = 0; - GetEventParameter(event, kEventParamMouseWheelDelta, typeSInt32, 0, + + int wheel_deltaX = 0; + int wheel_deltaY = 0; + static EventRef compatibilityEvent = 0; + + if (ekind == kEventMouseScroll) { + // kEventMouseScroll is the new way of dealing with mouse wheel + // events (kEventMouseWheelMoved was the old). kEventMouseScroll results + // in much smoother scrolling when using Mighty Mouse or TrackPad. For + // compatibility with older applications, carbon will also send us + // kEventMouseWheelMoved events if we dont eat this event + // (actually two events; one for horizontal and one for vertical). + // As a results of this, and to make sure we dont't receive duplicate events, + // we try to detect when this happend by checking the 'compatibilityEvent'. + SInt32 mdelt = 0; + GetEventParameter(event, kEventParamMouseWheelSmoothHorizontalDelta, typeSInt32, 0, sizeof(mdelt), 0, &mdelt); - wheel_delta = mdelt * 120; + wheel_deltaX = mdelt; + mdelt = 0; + GetEventParameter(event, kEventParamMouseWheelSmoothVerticalDelta, typeSInt32, 0, + sizeof(mdelt), 0, &mdelt); + wheel_deltaY = mdelt; + GetEventParameter(event, kEventParamEventRef, typeEventRef, 0, + sizeof(compatibilityEvent), 0, &compatibilityEvent); + } else if (ekind == kEventMouseWheelMoved) { + if (event != compatibilityEvent) { + compatibilityEvent = 0; + int mdelt = 0; + GetEventParameter(event, kEventParamMouseWheelDelta, typeSInt32, 0, + sizeof(mdelt), 0, &mdelt); + EventMouseWheelAxis axis; + GetEventParameter(event, kEventParamMouseWheelAxis, typeMouseWheelAxis, 0, + sizeof(axis), 0, &axis); + + // Remove acceleration, and use either -120 or 120 as delta: + if (axis == kEventMouseWheelAxisX) + wheel_deltaX = qBound(-120, int(mdelt * 10000), 120); + else + wheel_deltaY = qBound(-120, int(mdelt * 10000), 120); + } } Qt::MouseButton button = Qt::NoButton; @@ -1759,7 +1787,7 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event if(window) { HIViewRef hiview; if(HIViewGetViewForMouseEvent(HIViewGetRoot(window), event, &hiview) == noErr) { - widget = QWidget::find((WId)hiview);; + widget = QWidget::find((WId)hiview); if (widget) { // Make sure we didn't pass over a widget with a "fake hole" in it. QWidget *otherWidget = QApplication::widgetAt(where.h, where.v); @@ -1876,9 +1904,10 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event tablet_button_state = new_tablet_button_state; QMacTabletHash *tabletHash = qt_mac_tablet_hash(); - if (!tabletHash->contains(tabletPointRec.deviceID)) { - qWarning("QCocoaView handleTabletEvent: This tablet device is unknown" - " (received no proximity event for it). Discarding event."); + if (!tabletHash->contains(tabletPointRec.deviceID) && t != QEvent::TabletRelease) { + // Never discard TabletRelease events as they may be delivered *after* TabletLeaveProximity events + qWarning("handleTabletEvent: This tablet device is unknown" + " (received no proximity event for it). Discarding event."); return false; } QTabletDeviceData &deviceData = tabletHash->operator[](tabletPointRec.deviceID); @@ -1920,8 +1949,13 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event tp, rotation, z, modifiers, deviceData.tabletUniqueID); QApplication::sendSpontaneousEvent(widget, &e); if (e.isAccepted()) { + if (t == QEvent::TabletPress) { + qt_button_down = widget; + } else if (t == QEvent::TabletRelease) { + qt_button_down = 0; + } #if defined(DEBUG_MOUSE_MAPS) - qDebug("Bail out early due to table acceptance"); + qDebug("Bail out early due to tablet acceptance"); #endif break; } @@ -2078,20 +2112,29 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event qt_mac_dblclick.last_button = button; qt_mac_dblclick.last_time = GetEventTime(event); } - if(wheel_delta) { - EventMouseWheelAxis axis; - GetEventParameter(event, kEventParamMouseWheelAxis, typeMouseWheelAxis, 0, - sizeof(axis), 0, &axis); - QWheelEvent qwe(plocal, p, wheel_delta, buttons, modifiers, - axis == kEventMouseWheelAxisX ? Qt::Horizontal : Qt::Vertical); - QApplication::sendSpontaneousEvent(widget, &qwe); - if(!qwe.isAccepted() && QApplicationPrivate::focus_widget && QApplicationPrivate::focus_widget != widget) { - QWheelEvent qwe2(QApplicationPrivate::focus_widget->mapFromGlobal(p), p, - wheel_delta, buttons, modifiers, - axis == kEventMouseWheelAxisX ? Qt::Horizontal : Qt::Vertical); - QApplication::sendSpontaneousEvent(QApplicationPrivate::focus_widget, &qwe2); - if(!qwe2.isAccepted()) - handled_event = false; + + if (wheel_deltaX || wheel_deltaY) { + if (wheel_deltaX) { + QWheelEvent qwe(plocal, p, wheel_deltaX, buttons, modifiers, Qt::Horizontal); + QApplication::sendSpontaneousEvent(widget, &qwe); + if (!qwe.isAccepted() && QApplicationPrivate::focus_widget && QApplicationPrivate::focus_widget != widget) { + QWheelEvent qwe2(QApplicationPrivate::focus_widget->mapFromGlobal(p), p, + wheel_deltaX, buttons, modifiers, Qt::Horizontal); + QApplication::sendSpontaneousEvent(QApplicationPrivate::focus_widget, &qwe2); + if (!qwe2.isAccepted()) + handled_event = false; + } + } + if (wheel_deltaY) { + QWheelEvent qwe(plocal, p, wheel_deltaY, buttons, modifiers, Qt::Vertical); + QApplication::sendSpontaneousEvent(widget, &qwe); + if (!qwe.isAccepted() && QApplicationPrivate::focus_widget && QApplicationPrivate::focus_widget != widget) { + QWheelEvent qwe2(QApplicationPrivate::focus_widget->mapFromGlobal(p), p, + wheel_deltaY, buttons, modifiers, Qt::Vertical); + QApplication::sendSpontaneousEvent(QApplicationPrivate::focus_widget, &qwe2); + if (!qwe2.isAccepted()) + handled_event = false; + } } } else { #ifdef QMAC_SPEAK_TO_ME @@ -2154,7 +2197,7 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event plocal.x(), plocal.y(), event_desc, (QWidget*)widget, widget ? widget->objectName().toLocal8Bit().constData() : "*Unknown*", widget ? widget->metaObject()->className() : "*Unknown*", - button, (int)buttons, (int)modifiers, wheel_delta); + button, (int)buttons, (int)modifiers, wheel_deltaX); #endif } else { handled_event = false; @@ -2968,4 +3011,9 @@ void onApplicationChangedActivation( bool activated ) #endif } +void QApplicationPrivate::initializeMultitouch_sys() +{ } +void QApplicationPrivate::cleanupMultitouch_sys() +{ } + QT_END_NAMESPACE diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index 295e28a..8df4d08 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -55,6 +55,7 @@ // #include "QtGui/qapplication.h" +#include "QtGui/qevent.h" #include "QtGui/qfont.h" #include "QtGui/qcursor.h" #include "QtGui/qregion.h" @@ -70,6 +71,9 @@ #include "QtGui/qscreen_qws.h" #include <private/qgraphicssystem_qws_p.h> #endif +#ifdef Q_OS_SYMBIAN +#include <w32std.h> +#endif QT_BEGIN_NAMESPACE @@ -77,11 +81,9 @@ class QClipboard; class QGraphicsScene; class QGraphicsSystem; class QInputContext; -class QKeyEvent; -class QMouseEvent; class QObject; -class QWheelEvent; class QWidget; +class QSocketNotifier; extern bool qt_is_gui_used; #ifndef QT_NO_CLIPBOARD @@ -100,6 +102,7 @@ extern QSysInfo::MacVersion qt_macver; #if defined(Q_WS_QWS) class QWSManager; class QDirectPainter; +struct QWSServerCleaner { ~QWSServerCleaner(); }; #endif #ifndef QT_NO_TABLET @@ -158,17 +161,19 @@ inline QPointF QTabletDeviceData::scaleCoord(int coordX, int coordY, int outOriginY, int outExtentY) const { QPointF ret; + if (sign(outExtentX) == sign(maxX)) - ret.setX(((coordX - minX) * qAbs(outExtentX) / qAbs(qreal(maxX))) + outOriginX); + ret.setX(((coordX - minX) * qAbs(outExtentX) / qAbs(qreal(maxX - minX))) + outOriginX); else - ret.setX(((qAbs(maxX) - (coordX - minX)) * qAbs(outExtentX) / qAbs(qreal(maxX))) + ret.setX(((qAbs(maxX) - (coordX - minX)) * qAbs(outExtentX) / qAbs(qreal(maxX - minX))) + outOriginX); if (sign(outExtentY) == sign(maxY)) - ret.setY(((coordY - minY) * qAbs(outExtentY) / qAbs(qreal(maxY))) + outOriginY); + ret.setY(((coordY - minY) * qAbs(outExtentY) / qAbs(qreal(maxY - minY))) + outOriginY); else - ret.setY(((qAbs(maxY) - (coordY - minY)) * qAbs(outExtentY) / qAbs(qreal(maxY))) + ret.setY(((qAbs(maxY) - (coordY - minY)) * qAbs(outExtentY) / qAbs(qreal(maxY - minY))) + outOriginY); + return ret; } #endif @@ -189,6 +194,76 @@ extern "C" { } #endif +#if defined(Q_WS_WIN) +typedef BOOL (WINAPI *PtrRegisterTouchWindow)(HWND, ULONG); +typedef BOOL (WINAPI *PtrGetTouchInputInfo)(HANDLE, UINT, PVOID, int); +typedef BOOL (WINAPI *PtrCloseTouchInputHandle)(HANDLE); + +typedef BOOL (WINAPI *PtrGetGestureInfo)(HANDLE, PVOID); +typedef BOOL (WINAPI *PtrGetGestureExtraArgs)(HANDLE, UINT, PBYTE); +typedef BOOL (WINAPI *PtrCloseGestureInfoHandle)(HANDLE); +typedef BOOL (WINAPI *PtrSetGestureConfig)(HWND, DWORD, UINT, PVOID, UINT); +typedef BOOL (WINAPI *PtrGetGestureConfig)(HWND, DWORD, DWORD, PUINT, PVOID, UINT); + +typedef BOOL (WINAPI *PtrBeginPanningFeedback)(HWND); +typedef BOOL (WINAPI *PtrUpdatePanningFeedback)(HWND, LONG, LONG, BOOL); +typedef BOOL (WINAPI *PtrEndPanningFeedback)(HWND, BOOL); + +#ifndef WM_GESTURE +# define WM_GESTURE 0x0119 + +# define GID_BEGIN 1 +# define GID_END 2 +# define GID_ZOOM 3 +# define GID_PAN 4 +# define GID_ROTATE 5 +# define GID_TWOFINGERTAP 6 +# define GID_ROLLOVER 7 + +typedef struct tagGESTUREINFO +{ + UINT cbSize; + DWORD dwFlags; + DWORD dwID; + HWND hwndTarget; + POINTS ptsLocation; + DWORD dwInstanceID; + DWORD dwSequenceID; + ULONGLONG ullArguments; + UINT cbExtraArgs; +} GESTUREINFO; + +# define GC_PAN 0x00000001 +# define GC_PAN_WITH_SINGLE_FINGER_VERTICALLY 0x00000002 +# define GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY 0x00000004 + +# define GC_ZOOM 0x00000001 +# define GC_ROTATE 0x00000001 + +typedef struct tagGESTURECONFIG +{ + DWORD dwID; + DWORD dwWant; + DWORD dwBlock; +} GESTURECONFIG; + +# define GID_ROTATE_ANGLE_FROM_ARGUMENT(arg) ((((double)(arg) / 65535.0) * 4.0 * 3.14159265) - 2.0*3.14159265) + +#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 QScopedLoopLevelCounter { QThreadData *threadData; @@ -200,6 +275,12 @@ public: { --threadData->loopLevel; } }; +typedef QHash<QByteArray, QFont> FontHash; +FontHash *qt_app_fonts_hash(); + +typedef QHash<QByteArray, QPalette> PaletteHash; +PaletteHash *qt_app_palettes_hash(); + class Q_GUI_EXPORT QApplicationPrivate : public QCoreApplicationPrivate { Q_DECLARE_PUBLIC(QApplication) @@ -209,7 +290,6 @@ public: #if defined(Q_WS_X11) #ifndef QT_NO_SETTINGS - static QString kdeHome(); static bool x11_apply_settings(); #endif static void reset_instance_pointer(); @@ -219,10 +299,11 @@ public: #endif static bool quitOnLastWindowClosed; static void emitLastWindowClosed(); -#ifdef Q_OS_WINCE +#ifdef Q_WS_WINCE static int autoMaximizeThreshold; - static bool autoSipEnabled; #endif + static bool autoSipEnabled; + static QString desktopStyleKey(); static QGraphicsSystem *graphicsSystem() #if !defined(Q_WS_QWS) @@ -233,7 +314,6 @@ public: void createEventDispatcher(); QString appName() const; - static void dispatchEnterLeave(QWidget *enter, QWidget *leave); //modality @@ -270,6 +350,7 @@ public: KB_KDE = 8, KB_Gnome = 16, KB_CDE = 32, + KB_S60 = 64, KB_All = 0xffff }; @@ -355,12 +436,10 @@ public: static bool fade_tooltip; static bool animate_toolbox; static bool widgetCount; // Coupled with -widgetcount switch + static bool load_testability; // Coupled with -testability switch #ifdef Q_WS_MAC static bool native_modal_dialog_active; #endif -#if defined(Q_WS_WIN) && !defined(Q_OS_WINCE) - static bool inSizeMove; -#endif static void setSystemPalette(const QPalette &pal); static void setPalette_helper(const QPalette &palette, const char* className, bool clearWidgetPaletteHash); @@ -382,6 +461,7 @@ public: #ifdef Q_WS_QWS QPointer<QWSManager> last_manager; + QWSServerCleaner qwsServerCleaner; # ifndef QT_NO_DIRECTPAINTER QMap<WId, QDirectPainter *> *directPainters; # endif @@ -392,25 +472,19 @@ public: static QApplicationPrivate *instance() { return self; } - static QString *styleOverride; + static QString styleOverride; static int app_compile_version; #ifdef QT_KEYPAD_NAVIGATION - static bool keypadNavigation; static QWidget *oldEditFocus; + static Qt::NavigationMode navigationMode; #endif #if defined(Q_WS_MAC) || defined(Q_WS_X11) void _q_alertTimeOut(); QHash<QWidget *, QTimer *> alertTimerHash; #endif -#if defined(QT_MAC_USE_COCOA) - void _q_runAppModalWindow(); -#endif -#if defined(QT_MAC_USE_COCOA) - void _q_runModalWindow(); -#endif #ifndef QT_NO_STYLE_STYLESHEET static QString styleSheet; #endif @@ -419,20 +493,112 @@ public: QEvent::Type type, Qt::MouseButtons buttons, QWidget *buttonDown, QWidget *alienWidget); static bool sendMouseEvent(QWidget *receiver, QMouseEvent *event, QWidget *alienWidget, - QWidget *native, QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver); -#if defined(Q_WS_WIN) || defined(Q_WS_X11) + QWidget *native, QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver, + bool spontaneous = true); +#ifdef Q_OS_SYMBIAN + static void setNavigationMode(Qt::NavigationMode mode); + static TUint resolveS60ScanCode(TInt scanCode, TUint keysym); + QSet<WId> nativeWindows; + + int symbianProcessWsEvent(const TWsEvent *event); + int symbianHandleCommand(int command); + int symbianResourceChange(int type); + +#endif +#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined (Q_WS_QWS) void sendSyntheticEnterLeave(QWidget *widget); #endif + QWidget *gestureWidget; + + QMap<int, QWidget *> widgetForTouchPointId; + QMap<int, QTouchEvent::TouchPoint> appCurrentTouchPoints; + static void updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent); + void initializeMultitouch(); + void initializeMultitouch_sys(); + void cleanupMultitouch(); + void cleanupMultitouch_sys(); + int findClosestTouchPointId(const QPointF &screenPos); + void appendTouchPoint(const QTouchEvent::TouchPoint &touchPoint); + void removeTouchPoint(int touchPointId); + static void translateRawTouchEvent(QWidget *widget, + QTouchEvent::DeviceType deviceType, + const QList<QTouchEvent::TouchPoint> &touchPoints); + +#if defined(Q_WS_WIN) + static PtrRegisterTouchWindow RegisterTouchWindow; + static PtrGetTouchInputInfo GetTouchInputInfo; + static PtrCloseTouchInputHandle CloseTouchInputHandle; + + QHash<DWORD, int> touchInputIDToTouchPointID; + bool translateTouchEvent(const MSG &msg); + + PtrGetGestureInfo GetGestureInfo; + PtrGetGestureExtraArgs GetGestureExtraArgs; + PtrCloseGestureInfoHandle CloseGestureInfoHandle; + PtrSetGestureConfig SetGestureConfig; + PtrGetGestureConfig GetGestureConfig; + PtrBeginPanningFeedback BeginPanningFeedback; + PtrUpdatePanningFeedback UpdatePanningFeedback; + PtrEndPanningFeedback EndPanningFeedback; +#endif + +#ifdef QT_RX71_MULTITOUCH + bool hasRX71MultiTouch; + + struct RX71TouchPointState { + QSocketNotifier *socketNotifier; + QTouchEvent::TouchPoint touchPoint; + + int minX, maxX, scaleX; + int minY, maxY, scaleY; + int minZ, maxZ; + }; + QList<RX71TouchPointState> allRX71TouchPoints; + + bool readRX71MultiTouchEvents(int deviceNumber); + void fakeMouseEventFromRX71TouchEvent(); + void _q_readRX71MultiTouchEvents(); +#endif + +#if defined(Q_WS_S60) + int maxTouchPressure; + QList<QTouchEvent::TouchPoint> appAllTouchPoints; +#endif + private: #ifdef Q_WS_QWS QMap<const QScreen*, QRect> maxWindowRects; #endif +#ifdef Q_OS_SYMBIAN + static QHash<TInt, TUint> scanCodeCache; +#endif + static QApplicationPrivate *self; + + static void giveFocusAccordingToFocusPolicy(QWidget *w, + Qt::FocusPolicy focusPolicy, + Qt::FocusReason focusReason); static bool shouldSetFocus(QWidget *w, Qt::FocusPolicy policy); + + + static bool isAlien(QWidget *); }; +Q_GUI_EXPORT void qt_translateRawTouchEvent(QWidget *window, + QTouchEvent::DeviceType deviceType, + const QList<QTouchEvent::TouchPoint> &touchPoints); + +#if defined(Q_WS_WIN) + extern void qt_win_set_cursor(QWidget *, bool); +#elif defined(Q_WS_X11) + extern void qt_x11_enforce_cursor(QWidget *, bool); + extern void qt_x11_enforce_cursor(QWidget *); +#elif defined(Q_OS_SYMBIAN) + extern void qt_symbian_set_cursor(QWidget *, bool); +#endif + QT_END_NAMESPACE #endif // QAPPLICATION_P_H diff --git a/src/gui/kernel/qapplication_qws.cpp b/src/gui/kernel/qapplication_qws.cpp index b7ed3b8..167beb2 100644 --- a/src/gui/kernel/qapplication_qws.cpp +++ b/src/gui/kernel/qapplication_qws.cpp @@ -72,6 +72,7 @@ //#include "qwsregionmanager_qws.h" #include "qwindowsystem_qws.h" #include "private/qwindowsystem_p.h" +#include "qdecorationfactory_qws.h" #include "qwsdisplay_qws.h" #include "private/qwsdisplay_qws_p.h" @@ -101,10 +102,16 @@ #include <locale.h> #include <errno.h> #include <fcntl.h> -#include <sys/time.h> +#ifdef Q_OS_VXWORKS +# include <sys/times.h> +#else +# include <sys/time.h> +#endif #include <sys/stat.h> #include <sys/types.h> +#include <qvfbhdr.h> + #ifndef QT_NO_QWS_MULTIPROCESS #ifdef QT_NO_QSHM #include <sys/ipc.h> @@ -118,6 +125,8 @@ #endif #endif +QT_BEGIN_NAMESPACE + #ifndef QT_NO_DIRECTPAINTER class QDirectPainter; extern void qt_directpainter_region(QDirectPainter *dp, const QRegion &alloc, int type); @@ -157,11 +166,9 @@ int qt_servershmid = -1; bool qws_overrideCursor = false; #ifndef QT_NO_QWS_MANAGER -#include "qdecorationfactory_qws.h" -QT_BEGIN_NAMESPACE +extern Q_GUI_EXPORT QWSServer *qwsServer; -QT_USE_NAMESPACE static QDecoration *qws_decoration = 0; #endif @@ -194,37 +201,39 @@ QString qws_dataDir() static QString result; if (!result.isEmpty()) return result; - QByteArray dataDir = QString(QLatin1String("/tmp/qtembedded-%1")).arg(qws_display_id).toLocal8Bit(); - if (mkdir(dataDir, 0700)) { + result = QT_VFB_DATADIR(qws_display_id); + QByteArray dataDir = result.toLocal8Bit(); + + if (QT_MKDIR(dataDir, 0700)) { if (errno != EEXIST) { qFatal("Cannot create Qt for Embedded Linux data directory: %s", dataDir.constData()); } } - struct stat buf; - if (lstat(dataDir, &buf)) + QT_STATBUF buf; + if (QT_LSTAT(dataDir, &buf)) qFatal("stat failed for Qt for Embedded Linux data directory: %s", dataDir.constData()); if (!S_ISDIR(buf.st_mode)) qFatal("%s is not a directory", dataDir.constData()); -#ifndef Q_OS_INTEGRITY +#if !defined(Q_OS_INTEGRITY) && !defined(Q_OS_VXWORKS) if (buf.st_uid != getuid()) qFatal("Qt for Embedded Linux data directory is not owned by user %d", getuid()); if ((buf.st_mode & 0677) != 0600) qFatal("Qt for Embedded Linux data directory has incorrect permissions: %s", dataDir.constData()); #endif - dataDir += "/"; - result = QString::fromLocal8Bit(dataDir); + result.append("/"); return result; } // Get the filename of the pipe Qt for Embedded Linux uses for server/client comms Q_GUI_EXPORT QString qws_qtePipeFilename() { - return (qws_dataDir() + QString(QLatin1String(QTE_PIPE)).arg(qws_display_id)); + qws_dataDir(); + return QTE_PIPE(qws_display_id); } static void setMaxWindowRect(const QRect &rect) @@ -418,6 +427,7 @@ static QWidget *popupOfPopupButtonFocus = 0; static bool popupCloseDownMode = false; static bool popupGrabOk; static QPointer<QWidget> *mouseInWidget = 0; +QPointer<QWidget> qt_last_mouse_receiver = 0; static bool sm_blockUserInput = false; // session management @@ -485,8 +495,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) @@ -662,7 +677,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 @@ -2015,8 +2030,8 @@ bool QApplicationPrivate::qws_apply_settings() // read new QStyle QString stylename = settings.value(QLatin1String("style")).toString(); if (QCoreApplication::startingUp()) { - if (!stylename.isEmpty() && !QApplicationPrivate::styleOverride) - QApplicationPrivate::styleOverride = new QString(stylename); + if (!stylename.isEmpty() && QApplicationPrivate::styleOverride.isNull()) + QApplicationPrivate::styleOverride = stylename; } else { QApplication::setStyle(stylename); } @@ -2185,6 +2200,8 @@ void qt_init(QApplicationPrivate *priv, int type) mouse_double_click_distance = read_int_env_var("QWS_DBLCLICK_DISTANCE", 5); + priv->inputContext = 0; + int flags = 0; char *p; int argc = priv->argc; @@ -2284,7 +2301,8 @@ void qt_init(QApplicationPrivate *priv, int type) qt_appType = QApplication::Type(type); qws_single_process = true; QWSServer::startup(flags); - setenv("QWS_DISPLAY", qws_display_spec.constData(), 0); + if (!display) // if not already set + qputenv("QWS_DISPLAY", qws_display_spec); } if(qt_is_gui_used) { @@ -2299,7 +2317,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 } @@ -2343,6 +2361,11 @@ void qt_cleanup() delete mouseInWidget; mouseInWidget = 0; + +#if !defined(QT_NO_IM) + delete QApplicationPrivate::inputContext; + QApplicationPrivate::inputContext = 0; +#endif } @@ -2352,7 +2375,7 @@ void qt_cleanup() QString QApplicationPrivate::appName() const // get application name { - return ::appName; + return QT_PREPEND_NAMESPACE(appName); } /***************************************************************************** @@ -3498,10 +3521,12 @@ bool QETWidget::translateMouseEvent(const QWSMouseEvent *event, int prevstate) if (widget != (*mouseInWidget)) { QApplicationPrivate::dispatchEnterLeave(widget, *mouseInWidget); (*mouseInWidget) = widget; + qt_last_mouse_receiver = widget; } QApplication::sendSpontaneousEvent(widget, &e); if (leaveAfterRelease && !QWidget::mouseGrabber()) { *mouseInWidget = QApplication::widgetAt(globalPos); + qt_last_mouse_receiver = *mouseInWidget; QApplicationPrivate::dispatchEnterLeave(*mouseInWidget, leaveAfterRelease); leaveAfterRelease = 0; } @@ -3546,10 +3571,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 @@ -3749,4 +3774,19 @@ void QApplication::setArgs(int c, char **v) d->argv = v; } +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..1b0659a --- /dev/null +++ b/src/gui/kernel/qapplication_s60.cpp @@ -0,0 +1,1853 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qapplication_p.h" +#include "qsessionmanager.h" +#include "qevent.h" +#include "qsymbianevent.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 "private/qsoftkeymanager_p.h" + +#include "apgwgnam.h" // For CApaWindowGroupName +#include <MdaAudioTonePlayer.h> // For CMdaAudioToneUtility + +#if defined(Q_WS_S60) +# if !defined(QT_NO_IM) +# include "qinputcontext.h" +# include <private/qcoefepinputcontext_p.h> +# endif +# include <private/qs60mainapplication_p.h> +#endif + +#include "private/qstylesheetstyle_p.h" + +#include <hal.h> +#include <hal_data.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 + +QSymbianControl *QSymbianControl::lastFocusedControl = 0; + +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 isWindowOwning, bool desktop) +{ + if (!desktop) + { + if (isWindowOwning or !qwidget->parentWidget()) + CreateWindowL(S60->windowGroup()); + else + /** + * TODO: in order to avoid creating windows for all ancestors of + * this widget up to the root window, the parameter passed to + * CreateWindowL should be + * qwidget->parentWidget()->effectiveWinId(). However, if we do + * this, then we need to take care of re-parenting when a window + * is created for a widget between this one and the root window. + */ + CreateWindowL(qwidget->parentWidget()->winId()); + + // Necessary in order to be able to track the activation status of + // the control's window + qwidget->d_func()->createExtra(); + + SetFocusing(true); + m_longTapDetector = QLongTapTimer::NewL(this); + } +} + +QSymbianControl::~QSymbianControl() +{ + if (S60->curWin == this) + S60->curWin = 0; + if (!QApplicationPrivate::is_app_closing) + setFocusSafely(false); + 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 contextMenuEvent(QContextMenuEvent::Mouse, widgetPos, globalPos, mEvent.modifiers()); + qt_sendSpontaneousEvent(alienWidget, &contextMenuEvent); +#endif + + m_previousEventLongTap = true; +} + +#ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER +void QSymbianControl::translateAdvancedPointerEvent(const TAdvancedPointerEvent *event) +{ + QApplicationPrivate *d = QApplicationPrivate::instance(); + + QRect screenGeometry = qApp->desktop()->screenGeometry(qwidget); + + while (d->appAllTouchPoints.count() <= event->PointerNumber()) + d->appAllTouchPoints.append(QTouchEvent::TouchPoint(d->appAllTouchPoints.count())); + + Qt::TouchPointStates allStates = 0; + for (int i = 0; i < d->appAllTouchPoints.count(); ++i) { + QTouchEvent::TouchPoint &touchPoint = d->appAllTouchPoints[i]; + + if (touchPoint.id() == event->PointerNumber()) { + Qt::TouchPointStates state; + switch (event->iType) { + case TPointerEvent::EButton1Down: + case TPointerEvent::EEnterHighPressure: + state = Qt::TouchPointPressed; + break; + case TPointerEvent::EButton1Up: + case TPointerEvent::EExitCloseProximity: + state = Qt::TouchPointReleased; + break; + case TPointerEvent::EDrag: + state = Qt::TouchPointMoved; + break; + default: + // how likely is this to happen? + state = Qt::TouchPointStationary; + break; + } + if (event->PointerNumber() == 0) + state |= Qt::TouchPointPrimary; + touchPoint.setState(state); + + QPointF screenPos = QPointF(event->iPosition.iX, event->iPosition.iY); + touchPoint.setScreenPos(screenPos); + touchPoint.setNormalizedPos(QPointF(screenPos.x() / screenGeometry.width(), + screenPos.y() / screenGeometry.height())); + + touchPoint.setPressure(event->Pressure() / qreal(d->maxTouchPressure)); + } else if (touchPoint.state() != Qt::TouchPointReleased) { + // all other active touch points should be marked as stationary + touchPoint.setState(Qt::TouchPointStationary); + } + + allStates |= touchPoint.state(); + } + + if ((allStates & Qt::TouchPointStateMask) == Qt::TouchPointReleased) { + // all touch points released + d->appAllTouchPoints.clear(); + } + + QApplicationPrivate::translateRawTouchEvent(qwidget, + QTouchEvent::TouchScreen, + d->appAllTouchPoints); +} +#endif + +void QSymbianControl::HandlePointerEventL(const TPointerEvent& pEvent) +{ +#ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER + if (pEvent.IsAdvancedPointerEvent()) { + const TAdvancedPointerEvent *advancedPointerEvent = pEvent.AdvancedPointerEvent(); + translateAdvancedPointerEvent(advancedPointerEvent); + if (advancedPointerEvent->PointerNumber() != 0) { + // only send mouse events for the first touch point + return; + } + } +#endif + + m_longTapDetector->PointerEventL(pEvent); + QT_TRYCATCH_LEAVING(HandlePointerEvent(pEvent)); +} + +typedef QPair<QWidget*,QMouseEvent> Event; + +/* + * Helper function called by HandlePointerEvent - separated to keep that function readable + */ +static void generateEnterLeaveEvents(QList<Event> &events, QWidget *widgetUnderPointer, + QPoint globalPos, Qt::MouseButton button, Qt::KeyboardModifiers modifiers) +{ + //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, + modifiers); + events.append(Event(S60->lastPointerEventTarget, mEventLeave)); + } + if (widgetUnderPointer) { + QMouseEvent mEventEnter(QEvent::Enter, widgetUnderPointer->mapFromGlobal(globalPos), + globalPos, button, QApplicationPrivate::mouse_buttons, modifiers); + + events.append(Event(widgetUnderPointer, mEventEnter)); +#ifndef QT_NO_CURSOR + S60->curWin = widgetUnderPointer->effectiveWinId(); + if (!QApplication::overrideCursor()) { +#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS + if (S60->brokenPointerCursors) + qt_symbian_set_pointer_sprite(widgetUnderPointer->cursor()); + else +#endif + qt_symbian_setWindowCursor(widgetUnderPointer->cursor(), S60->curWin); + } +#endif + } +} + + +void QSymbianControl::HandlePointerEvent(const TPointerEvent& pEvent) +{ + QMouseEvent::Type type; + Qt::MouseButton button; + mapS60MouseEventTypeToQt(&type, &button, &pEvent); + Qt::KeyboardModifiers modifiers = mapToQtModifiers(pEvent.iModifiers); + + 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 + QList<Event > events; + + QPoint widgetPos = QPoint(pEvent.iPosition.iX, pEvent.iPosition.iY); + TPoint controlScreenPos = PositionRelativeToScreen(); + QPoint globalPos = QPoint(controlScreenPos.iX, controlScreenPos.iY) + widgetPos; + + // widgets interested in the event + QWidget *widgetUnderPointer = qwidget->childAt(widgetPos); + if (!widgetUnderPointer) + widgetUnderPointer = qwidget; //i.e. this container widget + + QWidget *widgetWithMouseGrab = QWidget::mouseGrabber(); + + // handle auto grab of pointer when pressing / releasing + if (!widgetWithMouseGrab && type == QEvent::MouseButtonPress) { + //if previously auto-grabbed, generate a fake mouse release (platform bug: mouse release event was lost) + if (S60->mousePressTarget) { + QMouseEvent mEvent(QEvent::MouseButtonRelease, S60->mousePressTarget->mapFromGlobal(globalPos), globalPos, + button, QApplicationPrivate::mouse_buttons, modifiers); + events.append(Event(S60->mousePressTarget,mEvent)); + } + //auto grab the mouse + widgetWithMouseGrab = S60->mousePressTarget = widgetUnderPointer; + widgetWithMouseGrab->grabMouse(); + } + if (widgetWithMouseGrab && widgetWithMouseGrab == S60->mousePressTarget && type == QEvent::MouseButtonRelease) { + //release the auto grab - note this release event still goes to the autograb widget + S60->mousePressTarget = 0; + widgetWithMouseGrab->releaseMouse(); + } + + QWidget *widgetToReceiveMouseEvent; + if (widgetWithMouseGrab) + widgetToReceiveMouseEvent = widgetWithMouseGrab; + else + widgetToReceiveMouseEvent = widgetUnderPointer; + + //queue QEvent::Enter and QEvent::Leave, if the pointer has moved + if (widgetUnderPointer != S60->lastPointerEventTarget && (type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick || type == QEvent::MouseMove)) + generateEnterLeaveEvents(events, widgetUnderPointer, globalPos, button, modifiers); + + //save global state + S60->lastCursorPos = globalPos; + S60->lastPointerEventPos = widgetPos; + S60->lastPointerEventTarget = widgetUnderPointer; + +#if !defined(QT_NO_CURSOR) && !defined(Q_SYMBIAN_FIXED_POINTER_CURSORS) + if (S60->brokenPointerCursors) + qt_symbian_move_cursor_sprite(); +#endif + + //queue this event. + Q_ASSERT(widgetToReceiveMouseEvent); + QMouseEvent mEvent(type, widgetToReceiveMouseEvent->mapFromGlobal(globalPos), globalPos, + button, QApplicationPrivate::mouse_buttons, modifiers); + events.append(Event(widgetToReceiveMouseEvent,mEvent)); + QEventDispatcherS60 *dispatcher; + // It is theoretically possible for someone to install a different event dispatcher. + if ((dispatcher = qobject_cast<QEventDispatcherS60 *>(widgetToReceiveMouseEvent->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; + } + } + + //send events in the queue + 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); + } + +#ifndef QT_NO_CURSOR + if (S60->mouseInteractionEnabled && S60->virtualMouseRequired) { + //translate keys to pointer + if (keyCode >= Qt::Key_Left && keyCode <= Qt::Key_Down || keyCode == Qt::Key_Select) { + /*Explanation about virtualMouseAccel: + Tapping an arrow key allows precise pixel positioning + Holding an arrow key down, acceleration is applied to allow cursor + to be quickly moved to another part of the screen by key repeats. + */ + if (S60->virtualMouseLastKey == keyCode) { + S60->virtualMouseAccel *= 2; + if (S60->virtualMouseAccel > S60->virtualMouseMaxAccel) + S60->virtualMouseAccel = S60->virtualMouseMaxAccel; + } + else + S60->virtualMouseAccel = 1; + S60->virtualMouseLastKey = keyCode; + + QPoint pos = QCursor::pos(); + TPointerEvent fakeEvent; + TInt x = pos.x(); + TInt y = pos.y(); + if (type == EEventKeyUp) { + if (keyCode == Qt::Key_Select) + fakeEvent.iType = TPointerEvent::EButton1Up; + S60->virtualMouseAccel = 1; + S60->virtualMouseLastKey = 0; + } + else if (type == EEventKey) { + switch (keyCode) { + case Qt::Key_Left: + x -= S60->virtualMouseAccel; + fakeEvent.iType = TPointerEvent::EMove; + break; + case Qt::Key_Right: + x += S60->virtualMouseAccel; + fakeEvent.iType = TPointerEvent::EMove; + break; + case Qt::Key_Up: + y -= S60->virtualMouseAccel; + fakeEvent.iType = TPointerEvent::EMove; + break; + case Qt::Key_Down: + y += S60->virtualMouseAccel; + fakeEvent.iType = TPointerEvent::EMove; + break; + case Qt::Key_Select: + fakeEvent.iType = TPointerEvent::EButton1Down; + break; + } + } + //clip to screen size (window server allows a sprite hotspot to be outside the screen) + if (x < 0) + x = 0; + else if (x >= S60->screenWidthInPixels) + x = S60->screenWidthInPixels - 1; + if (y < 0) + y = 0; + else if (y >= S60->screenHeightInPixels) + y = S60->screenHeightInPixels - 1; + TPoint epos(x, y); + TPoint cpos = epos - PositionRelativeToScreen(); + fakeEvent.iModifiers = keyEvent.iModifiers; + fakeEvent.iPosition = cpos; + fakeEvent.iParentPosition = epos; + HandlePointerEvent(fakeEvent); + return EKeyWasConsumed; + } + else { + S60->virtualMouseLastKey = keyCode; + S60->virtualMouseAccel = 1; + } + } +#endif + + Qt::KeyboardModifiers mods = mapToQtModifiers(keyEvent.iModifiers); + QKeyEventEx qKeyEvent(type == EEventKeyUp ? QEvent::KeyRelease : QEvent::KeyPress, keyCode, + mods, qt_keymapper_private()->translateKeyEvent(keyCode, mods), + false, 1, keyEvent.iScanCode, s60Keysym, keyEvent.iModifiers); +// 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& controlRect) const +{ + QWindowSurface *surface = qwidget->windowSurface(); + QPaintEngine *engine = surface ? surface->paintDevice()->paintEngine() : NULL; + + if (!engine) + return; + + // Map source rectangle into coordinates of the backing store. + const QPoint controlBase(controlRect.iTl.iX, controlRect.iTl.iY); + const QPoint backingStoreBase = qwidget->mapTo(qwidget->window(), controlBase); + const TRect backingStoreRect(TPoint(backingStoreBase.x(), backingStoreBase.y()), controlRect.Size()); + + if (engine->type() == QPaintEngine::Raster) { + QS60WindowSurface *s60Surface = static_cast<QS60WindowSurface *>(qwidget->windowSurface()); + CFbsBitmap *bitmap = s60Surface->symbianBitmap(); + CWindowGc &gc = SystemGc(); + + if(!qwidget->d_func()->extraData()->disableBlit) { + if (qwidget->d_func()->isOpaque) + gc.SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha); + gc.BitBlt(controlRect.iTl, bitmap, backingStoreRect); + } + } else { + surface->flush(qwidget, QRegion(qt_TRect2QRect(backingStoreRect)), 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; + + if (IsFocused() && IsVisible()) { + QApplication::setActiveWindow(qwidget->window()); +#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 = qwidget->windowState() & Qt::WindowFullScreen; + if (statusPane && (bool)statusPane->IsVisible() == isFullscreen) + statusPane->MakeVisible(!isFullscreen); + if (buttonGroup && (bool)buttonGroup->IsVisible() == isFullscreen) + buttonGroup->MakeVisible(!isFullscreen); +#endif + } else if (QApplication::activeWindow() == qwidget->window()) { + QApplication::setActiveWindow(0); + } + // else { We don't touch the active window unless we were explicitly activated or deactivated } +} + +void QSymbianControl::HandleResourceChange(int resourceType) +{ + switch (resourceType) { + case KInternalStatusPaneChange: + if (qwidget->isFullScreen()) { + SetExtentToWholeScreen(); + } else if (qwidget->isMaximized()) { + TRect r = static_cast<CEikAppUi*>(S60->appUi())->ClientRect(); + SetExtent(r.iTl, r.Size()); + } + 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 QSymbianControl::setFocusSafely(bool focus) +{ + // The stack hack in here is very unfortunate, but it is the only way to ensure proper + // focus in Symbian. If this is not executed, the control which happens to be on + // the top of the stack may randomly be assigned focus by Symbian, for example + // when creating new windows (specifically in CCoeAppUi::HandleStackChanged()). + if (focus) { + S60->appUi()->RemoveFromStack(this); + // Symbian doesn't automatically remove focus from the last focused control, so we need to + // remember it and clear focus ourselves. + if (lastFocusedControl && lastFocusedControl != this) + lastFocusedControl->SetFocus(false); + QT_TRAP_THROWING(S60->appUi()->AddToStackL(this, + ECoeStackPriorityDefault + 1, ECoeStackFlagStandard)); // Note the + 1 + lastFocusedControl = this; + this->SetFocus(true); + } else { + S60->appUi()->RemoveFromStack(this); + QT_TRAP_THROWING(S60->appUi()->AddToStackL(this, + ECoeStackPriorityDefault, ECoeStackFlagStandard)); + if(this == lastFocusedControl) + lastFocusedControl = 0; + this->SetFocus(false); + } +} + +/*! + \typedef QApplication::QS60MainApplicationFactory + \since 4.6 + + This is a typedef for a pointer to a function with the following + signature: + + \snippet doc/src/snippets/code/src_corelib_global_qglobal.cpp 47 + + \sa QApplication::QApplication() +*/ + +/*! + \since 4.6 + + Creates an application using the application factory given in + \a factory, and using \a argc command line arguments in \a argv. + \a factory can be leaving, but the error will be converted to a + standard exception. + + This function is only available on S60. +*/ +QApplication::QApplication(QApplication::QS60MainApplicationFactory factory, int &argc, char **argv) + : QCoreApplication(*new QApplicationPrivate(argc, argv, GuiClient)) +{ + Q_D(QApplication); + S60->s60ApplicationFactory = factory; + d->construct(); +} + +QApplication::QApplication(QApplication::QS60MainApplicationFactory factory, int &argc, char **argv, int _internal) + : QCoreApplication(*new QApplicationPrivate(argc, argv, GuiClient)) +{ + Q_D(QApplication); + S60->s60ApplicationFactory = factory; + d->construct(); + QApplicationPrivate::app_compile_version = _internal; +} + +void qt_init(QApplicationPrivate * /* priv */, int) +{ + if (!CCoeEnv::Static()) { + // The S60 framework creates a new trap handler which will render any existing traps + // invalid as long as it is active. This means that all code in main() that occurs after + // the QApplication construction needs to be surrounded by a new trap, despite having + // an outer one already. To avoid this, we save the original trap handler here, and set + // it back after the S60 framework is constructed. Then we restore it right before the S60 + // framework destruction. + TTrapHandler *origTrapHandler = User::TrapHandler(); + + // The S60 framework has not been initalized. We need to do it. + TApaApplicationFactory factory(S60->s60ApplicationFactory ? + S60->s60ApplicationFactory : newS60Application); + CApaCommandLine* commandLine = 0; + TInt err = CApaCommandLine::GetCommandLineFromProcessEnvironment(commandLine); + // After this construction, CEikonEnv will be available from CEikonEnv::Static(). + // (much like our qApp). + CEikonEnv* coe = new CEikonEnv; + //not using QT_TRAP_THROWING, because coe owns the cleanupstack so it can't be pushed there. + if(err == KErrNone) + TRAP(err, coe->ConstructAppFromCommandLineL(factory,*commandLine)); + delete commandLine; + if(err != KErrNone) { + qWarning() << "qt_init: Eikon application construct failed (" + << err + << "), maybe missing resource file on S60 3.1?"; + delete coe; + qt_symbian_throwIfError(err); + } + + S60->s60InstalledTrapHandler = User::SetTrapHandler(origTrapHandler); + + S60->qtOwnsS60Environment = true; + } else { + S60->qtOwnsS60Environment = false; + } + +#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); + + //NB: RWsSession::GetColorModeList tells you what window modes are supported, + //not what bitmap formats. + if(QSysInfo::symbianVersion() == QSysInfo::SV_9_2) + S60->supportsPremultipliedAlpha = 0; + else + S60->supportsPremultipliedAlpha = 1; + + RProcess me; + TSecureId securId = me.SecureId(); + S60->uid = securId.operator TUid(); + + // enable focus events - used to re-enable mouse after focus changed between mouse and non mouse app, + // and for dimming behind modal windows + S60->windowGroup().EnableFocusChangeEvents(); + + //Check if mouse interaction is supported (either EMouse=1 in the HAL, or EMachineUID is one of the phones known to support this) + const TInt KMachineUidSamsungI8510 = 0x2000C51E; + // HAL::Get(HALData::EPen, TInt& result) may set 'result' to 1 on some 3.1 systems (e.g. N95). + // But we know that S60 systems below 5.0 did not support touch. + static const bool touchIsUnsupportedOnSystem = + QSysInfo::s60Version() == QSysInfo::SV_S60_3_1 + || QSysInfo::s60Version() == QSysInfo::SV_S60_3_2; + TInt machineUID; + TInt mouse; + TInt touch; + TInt err; + err = HAL::Get(HALData::EMouse, mouse); + if (err != KErrNone) + mouse = 0; + err = HAL::Get(HALData::EMachineUid, machineUID); + if (err != KErrNone) + machineUID = 0; + err = HAL::Get(HALData::EPen, touch); + if (err != KErrNone || touchIsUnsupportedOnSystem) + touch = 0; +#ifdef __WINS__ + if(QSysInfo::symbianVersion() <= QSysInfo::SV_9_4) { + //for symbian SDK emulator, force values to match typical devices. + mouse = 0; + touch = touchIsUnsupportedOnSystem ? 0 : 1; + } +#endif + if (mouse || machineUID == KMachineUidSamsungI8510) { + S60->hasTouchscreen = false; + S60->virtualMouseRequired = false; + } + else if (!touch) { + S60->hasTouchscreen = false; + S60->virtualMouseRequired = true; + } + else { + S60->hasTouchscreen = true; + S60->virtualMouseRequired = false; + } + + if (touch) { + QApplicationPrivate::navigationMode = Qt::NavigationModeNone; + } else { + QApplicationPrivate::navigationMode = Qt::NavigationModeKeypadDirectional; + } + +#ifndef QT_NO_CURSOR + //Check if window server pointer cursors are supported or not +#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS + //In generic binary, use the HAL and OS version + //Any other known good phones should be added here. + if (machineUID == KMachineUidSamsungI8510 || (QSysInfo::symbianVersion() != QSysInfo::SV_9_4 + && QSysInfo::symbianVersion() != QSysInfo::SV_9_3 && QSysInfo::symbianVersion() + != QSysInfo::SV_9_2)) { + S60->brokenPointerCursors = false; + qt_symbian_setWindowGroupCursor(Qt::ArrowCursor, S60->windowGroup()); + } + else + S60->brokenPointerCursors = true; +#endif + + if (S60->mouseInteractionEnabled) { +#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS + if (S60->brokenPointerCursors) { + qt_symbian_set_pointer_sprite(Qt::ArrowCursor); + qt_symbian_show_pointer_sprite(); + } + else +#endif + S60->wsSession().SetPointerCursorMode(EPointerCursorNormal); + } +#endif + + QFont systemFont; + systemFont.setFamily(systemFont.defaultFamily()); + QApplicationPrivate::setSystemFont(systemFont); + +/* + ### 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 + ; + } +*/ + + // Register WId with the metatype system. This is to enable + // QWidgetPrivate::create_sys to used delayed slot invokation in order + // to destroy WId objects during reparenting. + qRegisterMetaType<WId>("WId"); +} + +/***************************************************************************** + 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; + + //Change mouse pointer back + S60->wsSession().SetPointerCursorMode(EPointerCursorNone); + + if (S60->qtOwnsS60Environment) { + // Restore the S60 framework trap handler. See qt_init(). + User::SetTrapHandler(S60->s60InstalledTrapHandler); + + CEikonEnv* coe = CEikonEnv::Static(); + coe->PrepareToExit(); + // The CEikonEnv itself is destroyed in here. + coe->DestroyEnvironment(); + } +} + +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 (widget) { + widget->effectiveWinId()->DrawableWindow()->FadeBehind(ETrue); + // Modal partial screen dialogs (like queries) capture pointer events. + // ### FixMe: Add specialized behaviour for fullscreen modal dialogs + widget->effectiveWinId()->SetGloballyCapturing(ETrue); + widget->effectiveWinId()->SetPointerCapture(ETrue); + } + 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 (widget) { + widget->effectiveWinId()->DrawableWindow()->FadeBehind(EFalse); + // ### FixMe: Add specialized behaviour for fullscreen modal dialogs + widget->effectiveWinId()->SetGloballyCapturing(EFalse); + widget->effectiveWinId()->SetPointerCapture(EFalse); + } + 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); + + + // Cancel focus widget pointer capture and long tap timer + if (QApplication::focusWidget()) { + static_cast<QSymbianControl*>(QApplication::focusWidget()->effectiveWinId())->CancelLongTapTimer(); + QApplication::focusWidget()->effectiveWinId()->SetPointerCapture(false); + } + + if (!qt_nograb()) { + // Cancel pointer capture and long tap timer for earlier popup + int popupCount = QApplicationPrivate::popupWidgets->count(); + if (popupCount > 1) { + QWidget* prevPopup = QApplicationPrivate::popupWidgets->at(popupCount-2); + static_cast<QSymbianControl*>(prevPopup->effectiveWinId())->CancelLongTapTimer(); + prevPopup->effectiveWinId()->SetPointerCapture(false); + } + + // Enable pointer capture for this (topmost) popup + Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created)); + WId id = popup->effectiveWinId(); + id->SetPointerCapture(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 + 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); + + // Cancel pointer capture and long tap for this popup + WId id = popup->effectiveWinId(); + id->SetPointerCapture(false); + static_cast<QSymbianControl*>(id)->CancelLongTapTimer(); + + 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)); + 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); + } + + // Enable pointer capture for previous popup + if (aw) { + aw->effectiveWinId()->SetPointerCapture(true); + } + } +} + +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 *const window = widget->effectiveWinId()->DrawableWindow(); + int z = window->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; +} + +/*! + \warning This function is only available on Symbian. + \since 4.6 + + This function processes an individual Symbian event + \a event. It returns 1 if the event was handled, 0 if + the \a event was not handled, and -1 if the event was + not handled because the event is not known to Qt. + */ + +int QApplication::symbianProcessEvent(const QSymbianEvent *event) +{ + Q_D(QApplication); + + QScopedLoopLevelCounter counter(d->threadData); + + QWidget *w = qApp ? qApp->focusWidget() : 0; + if (w) { + QInputContext *ic = w->inputContext(); + if (ic && ic->symbianFilterEvent(w, event)) + return 1; + } + + if (symbianEventFilter(event)) + return 1; + + switch (event->type()) { + case QSymbianEvent::WindowServerEvent: + return d->symbianProcessWsEvent(event->windowServerEvent()); + case QSymbianEvent::CommandEvent: + return d->symbianHandleCommand(event->command()); + case QSymbianEvent::ResourceChangeEvent: + return d->symbianResourceChange(event->resourceChangeType()); + default: + return -1; + } +} + +int QApplicationPrivate::symbianProcessWsEvent(const TWsEvent *event) +{ + // 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()) { + 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->d_func()->invalidateBuffer(w->rect()); + w->repaint(); + } + return 1; + } + break; + case EEventFocusGained: +#ifndef QT_NO_CURSOR + //re-enable mouse interaction + if (S60->mouseInteractionEnabled) { +#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS + if (S60->brokenPointerCursors) + qt_symbian_show_pointer_sprite(); + else +#endif + S60->wsSession().SetPointerCursorMode(EPointerCursorNormal); + } +#endif + break; + case EEventFocusLost: +#ifndef QT_NO_CURSOR + //disable mouse as may be moving to application that does not support it + if (S60->mouseInteractionEnabled) { +#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS + if (S60->brokenPointerCursors) + qt_symbian_hide_pointer_sprite(); + else +#endif + S60->wsSession().SetPointerCursorMode(EPointerCursorNone); + } +#endif + break; + default: + break; + } + + if (!controlInMap) + return -1; + + return 0; +} + +/*! + \warning This virtual function is only available on Symbian. + \since 4.6 + + If you create an application that inherits QApplication and reimplement + this function, you get direct access to events that the are received + from Symbian. The events are passed in the \a event parameter. + + Return true if you want to stop the event from being processed. Return + false for normal event dispatching. The default implementation returns + false, and does nothing with \a event. + */ +bool QApplication::symbianEventFilter(const QSymbianEvent *event) +{ + Q_UNUSED(event); + return false; +} + +/*! + \warning This function is only available on Symbian. + \since 4.6 + + Handles \a{command}s 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() +*/ +int QApplicationPrivate::symbianHandleCommand(int command) +{ + Q_Q(QApplication); + int ret = 0; + + switch (command) { +#ifdef Q_WS_S60 + case EAknSoftkeyExit: { + QCloseEvent ev; + QApplication::sendSpontaneousEvent(q, &ev); + if (ev.isAccepted()) { + q->quit(); + ret = 1; + } + break; + } +#endif + case EEikCmdExit: + q->quit(); + ret = 1; + break; + default: + bool handled = QSoftKeyManager::handleCommand(command); + if (handled) + ret = 1; +#ifdef Q_WS_S60 + else + ret = QMenuBarPrivate::symbianCommands(command); +#endif + break; + } + + return ret; +} + +/*! + \warning This function is only available on Symbian. + \since 4.6 + + Handles the resource change specified by \a type. + + Currently, KEikDynamicLayoutVariantSwitch and + KAknsMessageSkinChange are handled. + */ +int QApplicationPrivate::symbianResourceChange(int type) +{ + int ret = 0; + + 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(); + ret = 1; + } +#endif + } + break; + +#ifndef QT_NO_STYLE_S60 + case KAknsMessageSkinChange: + if (QS60Style *s60Style = qobject_cast<QS60Style*>(QApplication::style())) { + s60Style->d_func()->handleSkinChange(); + ret = 1; + } + break; +#endif +#endif // Q_WS_S60 + default: + break; + } + + return ret; +} + +#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() +{ +#ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER + if (HAL::Get(HALData::EPointer3DMaxPressure, maxTouchPressure) != KErrNone) + maxTouchPressure = KMaxTInt; +#endif +} + +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 + +#ifdef QT_KEYPAD_NAVIGATION +/* + * Show/Hide the mouse cursor depending on phone type and chosen mode + */ +void QApplicationPrivate::setNavigationMode(Qt::NavigationMode mode) +{ +#ifndef QT_NO_CURSOR + const bool wasCursorOn = (QApplicationPrivate::navigationMode == Qt::NavigationModeCursorAuto + && !S60->hasTouchscreen) + || QApplicationPrivate::navigationMode == Qt::NavigationModeCursorForceVisible; + const bool isCursorOn = (mode == Qt::NavigationModeCursorAuto + && !S60->hasTouchscreen) + || mode == Qt::NavigationModeCursorForceVisible; + + if (!wasCursorOn && isCursorOn) { + //Show the cursor, when changing from another mode to cursor mode + qt_symbian_set_cursor_visible(true); + } + else if (wasCursorOn && !isCursorOn) { + //Hide the cursor, when leaving cursor mode + qt_symbian_set_cursor_visible(false); + } +#endif + QApplicationPrivate::navigationMode = mode; +} +#endif + +#ifndef QT_NO_CURSOR +/***************************************************************************** + QApplication cursor stack + *****************************************************************************/ + +void QApplication::setOverrideCursor(const QCursor &cursor) +{ + qApp->d_func()->cursor_list.prepend(cursor); + qt_symbian_setGlobalCursor(cursor); +} + +void QApplication::restoreOverrideCursor() +{ + if (qApp->d_func()->cursor_list.isEmpty()) + return; + qApp->d_func()->cursor_list.removeFirst(); + + if (!qApp->d_func()->cursor_list.isEmpty()) { + qt_symbian_setGlobalCursor(qApp->d_func()->cursor_list.first()); + } + else { + //determine which widget has focus + QWidget *w = QApplication::widgetAt(QCursor::pos()); +#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS + if (S60->brokenPointerCursors) { + qt_symbian_set_pointer_sprite(w ? w->cursor() : Qt::ArrowCursor); + } + else +#endif + { + //because of the internals of window server, we need to force the cursor + //to be set in all child windows too, otherwise when the cursor is over + //the child window it may show a widget cursor or arrow cursor instead, + //depending on construction order. + QListIterator<WId> iter(QWidgetPrivate::mapper->uniqueKeys()); + while (iter.hasNext()) { + CCoeControl *ctrl = iter.next(); + if(ctrl->OwnsWindow()) { + ctrl->DrawableWindow()->ClearPointerCursor(); + } + } + if (w) + qt_symbian_setWindowCursor(w->cursor(), w->effectiveWinId()); + else + qt_symbian_setWindowGroupCursor(Qt::ArrowCursor, S60->windowGroup()); + } + } +} + +#endif // QT_NO_CURSOR + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index 5a4f4e6..387c29b 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -39,7 +39,7 @@ ** ****************************************************************************/ -#ifdef Q_OS_WINCE +#ifdef Q_WS_WINCE #include "qguifunctions_wince.h" #include "qmenubar.h" extern bool qt_wince_is_mobile(); //defined in qguifunctions_wince.cpp @@ -48,9 +48,12 @@ extern bool qt_wince_is_smartphone(); //defined in qguifunctions_wince.c extern bool qt_wince_is_pocket_pc(); //defined in qguifunctions_wince.cpp extern void qt_wince_hide_taskbar(HWND hwnd); //defined in qguifunctions_wince.cpp #endif -#ifdef Q_OS_WINCE_WM +#ifdef Q_WS_WINCE_WM #include <windowsm.h> #include <tpcshell.h> +#ifdef QT_WINCE_GESTURES +#include <gesture.h> +#endif #endif #include "qapplication.h" @@ -88,6 +91,7 @@ extern void qt_wince_hide_taskbar(HWND hwnd); //defined in qguifunctions_wince.c #include "qdebug.h" #include <private/qkeymapper_p.h> #include <private/qlocale_p.h> +#include "qevent_p.h" //#define ALIEN_DEBUG @@ -104,32 +108,44 @@ extern void qt_wince_hide_taskbar(HWND hwnd); //defined in qguifunctions_wince.c #endif #endif // QT_NO_ACCESSIBILITY -#include <winuser.h> #if !defined(WINABLEAPI) -# if defined(Q_OS_WINCE) +# if defined(Q_WS_WINCE) # include <bldver.h> # endif # include <winable.h> #endif +#ifndef WM_TOUCH +# define WM_TOUCH 0x0240 + +# define TOUCHEVENTF_MOVE 0x0001 +# define TOUCHEVENTF_DOWN 0x0002 +# define TOUCHEVENTF_UP 0x0004 +# define TOUCHEVENTF_INRANGE 0x0008 +# define TOUCHEVENTF_PRIMARY 0x0010 +# define TOUCHEVENTF_NOCOALESCE 0x0020 +# define TOUCHEVENTF_PEN 0x0040 +# define TOUCHEVENTF_PALM 0x0080 + +# define TOUCHINPUTMASKF_TIMEFROMSYSTEM 0x0001 +# define TOUCHINPUTMASKF_EXTRAINFO 0x0002 +# define TOUCHINPUTMASKF_CONTACTAREA 0x0004 -#ifndef FLASHW_STOP -typedef struct { - UINT cbSize; - HWND hwnd; +typedef struct tagTOUCHINPUT +{ + LONG x; + LONG y; + HANDLE hSource; + DWORD dwID; DWORD dwFlags; - UINT uCount; - DWORD dwTimeout; -} FLASHWINFO, *PFLASHWINFO; -#define FLASHW_STOP 0 -#define FLASHW_CAPTION 0x00000001 -#define FLASHW_TRAY 0x00000002 -#define FLASHW_ALL (FLASHW_CAPTION | FLASHW_TRAY) -#define FLASHW_TIMER 0x00000004 -#define FLASHW_TIMERNOFG 0x0000000C -#endif /* FLASHW_STOP */ -typedef BOOL (WINAPI *PtrFlashWindowEx)(PFLASHWINFO pfwi); -static PtrFlashWindowEx pFlashWindowEx = 0; + DWORD dwMask; + DWORD dwTime; + ULONG_PTR dwExtraInfo; + DWORD cxContact; + DWORD cyContact; +} TOUCHINPUT, *PTOUCHINPUT; + +#endif #include <windowsx.h> #include <limits.h> @@ -153,9 +169,16 @@ static PtrFlashWindowEx pFlashWindowEx = 0; #include <mywinsock.h> #endif +#ifndef IMR_RECONVERTSTRING +#define IMR_RECONVERTSTRING 4 +#endif + +#ifndef IMR_CONFIRMRECONVERTSTRING +#define IMR_CONFIRMRECONVERTSTRING 0x0005 +#endif QT_BEGIN_NAMESPACE -#ifdef Q_OS_WINCE +#ifdef Q_WS_WINCE #ifndef SHRG_RETURNCMD struct SHRGINFO { DWORD cbSize; @@ -198,7 +221,7 @@ static void resolveAygLibs() # define FE_FONTSMOOTHINGCLEARTYPE 0x0002 #endif -bool qt_cleartype_enabled; +Q_GUI_EXPORT bool qt_cleartype_enabled; Q_GUI_EXPORT bool qt_win_owndc_required; // CS_OWNDC is required if we use the GL graphicssystem as default typedef HCTX (API *PtrWTOpen)(HWND, LPLOGCONTEXT, BOOL); @@ -240,10 +263,6 @@ QTabletDeviceData currentTabletPointer; // from qregion_win.cpp extern HRGN qt_tryCreateRegion(QRegion::RegionType type, int left, int top, int right, int bottom); -Q_CORE_EXPORT bool winPeekMessage(MSG* msg, HWND hWnd, UINT wMsgFilterMin, - UINT wMsgFilterMax, UINT wRemoveMsg); -Q_CORE_EXPORT bool winPostMessage(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); - // support for on-the-fly changes of the XP theme engine #ifndef WM_THEMECHANGED #define WM_THEMECHANGED 0x031A @@ -258,22 +277,24 @@ Q_CORE_EXPORT bool winPostMessage(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPa #define WM_XBUTTONDOWN 0x020B #define WM_XBUTTONUP 0x020C #define WM_XBUTTONDBLCLK 0x020D +#endif +#ifndef GET_KEYSTATE_WPARAM #define GET_KEYSTATE_WPARAM(wParam) (LOWORD(wParam)) #define GET_XBUTTON_WPARAM(wParam) (HIWORD(wParam)) #define XBUTTON1 0x0001 #define XBUTTON2 0x0002 +#endif +#ifndef MK_XBUTTON1 #define MK_XBUTTON1 0x0020 #define MK_XBUTTON2 0x0040 #endif -#ifdef Q_OS_WINCE -#define GET_KEYSTATE_WPARAM(wParam) (LOWORD(wParam)) -#endif - -// support for multi-media-keys on ME/2000/XP +// support for multi-media-keys #ifndef WM_APPCOMMAND #define WM_APPCOMMAND 0x0319 +#endif +#ifndef FAPPCOMMAND_MOUSE #define FAPPCOMMAND_MOUSE 0x8000 #define FAPPCOMMAND_KEY 0 #define FAPPCOMMAND_OEM 0x1000 @@ -307,6 +328,7 @@ Q_CORE_EXPORT bool winPostMessage(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPa #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 @@ -341,10 +363,6 @@ Q_CORE_EXPORT bool winPostMessage(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPa #define APPCOMMAND_MEDIA_CHANNEL_DOWN 52 #endif // APPCOMMAND_MICROPHONE_VOLUME_MUTE -#endif // WM_APPCOMMAND - -static UINT WM95_MOUSEWHEEL = 0; - #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. @@ -376,11 +394,6 @@ QRgb qt_colorref2qrgb(COLORREF col) Internal variables and functions *****************************************************************************/ -extern Q_CORE_EXPORT char theAppName[]; -extern Q_CORE_EXPORT char appFileName[]; -extern Q_CORE_EXPORT HINSTANCE appInst; // handle to app instance -extern Q_CORE_EXPORT HINSTANCE appPrevInst; // handle to prev app instance -extern Q_CORE_EXPORT int appCmdShow; // main window show command static HWND curWin = 0; // current window static HDC displayDC = 0; // display device context @@ -422,11 +435,6 @@ extern QCursor *qt_grab_cursor(); #define __export #endif -QApplicationPrivate* getQApplicationPrivateInternal() -{ - return qApp->d_func(); -} - extern "C" LRESULT CALLBACK QtWndProc(HWND, UINT, WPARAM, LPARAM); class QETWidget : public QWidget // event translator widget @@ -448,6 +456,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, 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); } @@ -497,7 +506,7 @@ static void qt_set_windows_color_resources() pal.setColor(QPalette::HighlightedText, QColor(qt_colorref2qrgb(GetSysColor(COLOR_HIGHLIGHTTEXT)))); -#if defined(Q_OS_WINCE) +#if defined(Q_WS_WINCE) // ### hardcoded until I find out how to get it from the system settings. pal.setColor(QPalette::LinkVisited, pal.highlight().color().dark(150)); pal.setColor(QPalette::Link, pal.highlight().color().light(130)); @@ -516,14 +525,13 @@ static void qt_set_windows_color_resources() pal.setColor(QPalette::Inactive, QPalette::Light, pal.light().color()); pal.setColor(QPalette::Inactive, QPalette::Dark, pal.dark().color()); - if (QSysInfo::WindowsVersion != QSysInfo::WV_NT && QSysInfo::WindowsVersion != QSysInfo::WV_95) { - if (pal.midlight() == pal.button()) - pal.setColor(QPalette::Midlight, pal.button().color().lighter(110)); - if (pal.background() != pal.base()) { - pal.setColor(QPalette::Inactive, QPalette::Highlight, pal.color(QPalette::Inactive, QPalette::Window)); - pal.setColor(QPalette::Inactive, QPalette::HighlightedText, pal.color(QPalette::Inactive, QPalette::Text)); - } + if (pal.midlight() == pal.button()) + pal.setColor(QPalette::Midlight, pal.button().color().lighter(110)); + if (pal.background() != pal.base()) { + pal.setColor(QPalette::Inactive, QPalette::Highlight, pal.color(QPalette::Inactive, QPalette::Window)); + pal.setColor(QPalette::Inactive, QPalette::HighlightedText, pal.color(QPalette::Inactive, QPalette::Text)); } + const QColor bg = pal.background().color(); const QColor fg = pal.foreground().color(), btn = pal.button().color(); QColor disabled((fg.red()+btn.red())/2,(fg.green()+btn.green())/2, @@ -573,36 +581,19 @@ static void qt_set_windows_color_resources() static void qt_set_windows_font_resources() { -#ifndef Q_OS_WINCE - QFont menuFont; - QFont messageFont; - QFont statusFont; - QFont titleFont; - QFont iconTitleFont; - QT_WA({ - NONCLIENTMETRICS ncm; - ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICS, lfMessageFont) + sizeof(LOGFONTW); - SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize , &ncm, 0); - menuFont = qt_LOGFONTtoQFont(ncm.lfMenuFont,true); - messageFont = qt_LOGFONTtoQFont(ncm.lfMessageFont,true); - statusFont = qt_LOGFONTtoQFont(ncm.lfStatusFont,true); - titleFont = qt_LOGFONTtoQFont(ncm.lfCaptionFont,true); - LOGFONTW lfIconTitleFont; - SystemParametersInfoW(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0); - iconTitleFont = qt_LOGFONTtoQFont(lfIconTitleFont,true); - } , { - // A version - NONCLIENTMETRICSA ncm; - ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICSA, lfMessageFont) + sizeof(LOGFONTA); - SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0); - menuFont = qt_LOGFONTtoQFont((LOGFONT&)ncm.lfMenuFont,true); - messageFont = qt_LOGFONTtoQFont((LOGFONT&)ncm.lfMessageFont,true); - statusFont = qt_LOGFONTtoQFont((LOGFONT&)ncm.lfStatusFont,true); - titleFont = qt_LOGFONTtoQFont((LOGFONT&)ncm.lfCaptionFont,true); - LOGFONTA lfIconTitleFont; - SystemParametersInfoA(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0); - iconTitleFont = qt_LOGFONTtoQFont((LOGFONT&)lfIconTitleFont,true); - }); +#ifndef Q_WS_WINCE + NONCLIENTMETRICS ncm; + ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICS, lfMessageFont) + sizeof(LOGFONT); + SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize , &ncm, 0); + + QFont menuFont = qt_LOGFONTtoQFont(ncm.lfMenuFont, true); + QFont messageFont = qt_LOGFONTtoQFont(ncm.lfMessageFont, true); + QFont statusFont = qt_LOGFONTtoQFont(ncm.lfStatusFont, true); + QFont titleFont = qt_LOGFONTtoQFont(ncm.lfCaptionFont, true); + + LOGFONT lfIconTitleFont; + SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lfIconTitleFont), &lfIconTitleFont, 0); + QFont iconTitleFont = qt_LOGFONTtoQFont(lfIconTitleFont, true); QApplication::setFont(menuFont, "QMenu"); QApplication::setFont(menuFont, "QMenuBar"); @@ -627,24 +618,19 @@ static void qt_set_windows_font_resources() smallerFont.setBold(true); QApplication::setFont(smallerFont, "QAbstractButton"); } -#endif// Q_OS_WINCE +#endif// Q_WS_WINCE } static void qt_win_read_cleartype_settings() { - QT_WA({ - UINT result; - BOOL ok; - ok = SystemParametersInfoW(SPI_GETFONTSMOOTHINGTYPE, 0, &result, 0); - if (ok) - qt_cleartype_enabled = (result == FE_FONTSMOOTHINGCLEARTYPE); - }, { - UINT result; - BOOL ok; - ok = SystemParametersInfoA(SPI_GETFONTSMOOTHINGTYPE, 0, &result, 0); - if (ok) - qt_cleartype_enabled = (result == FE_FONTSMOOTHINGCLEARTYPE); - }); + UINT result = 0; +#ifdef Q_OS_WINCE + if (SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &result, 0)) + qt_cleartype_enabled = result; +#else + if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &result, 0)) + qt_cleartype_enabled = (result == FE_FONTSMOOTHINGCLEARTYPE); +#endif } @@ -661,10 +647,10 @@ void QApplicationPrivate::initializeWidgetPaletteHash() QPalette pal = *QApplicationPrivate::sys_pal; QColor menuCol(qt_colorref2qrgb(GetSysColor(COLOR_MENU))); QColor menuText(qt_colorref2qrgb(GetSysColor(COLOR_MENUTEXT))); - BOOL isFlat = 0; + BOOL isFlat = false; if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)) - SystemParametersInfo(0x1022 /*SPI_GETFLATMENU*/, 0, &isFlat, 0); + SystemParametersInfo(SPI_GETFLATMENU, 0, &isFlat, 0); QPalette menu(pal); // we might need a special color group for the menu. menu.setColor(QPalette::Active, QPalette::Button, menuCol); @@ -679,8 +665,7 @@ void QApplicationPrivate::initializeWidgetPaletteHash() QColor(qt_colorref2qrgb(GetSysColor( (QSysInfo::WindowsVersion >= QSysInfo::WV_XP && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based) - && isFlat ? COLOR_MENUHILIGHT - : COLOR_HIGHLIGHT)))); + && isFlat ? COLOR_MENUHILIGHT : COLOR_HIGHLIGHT)))); menu.setColor(QPalette::Disabled, QPalette::HighlightedText, disabled); menu.setColor(QPalette::Disabled, QPalette::Button, menu.color(QPalette::Active, QPalette::Button)); @@ -696,10 +681,8 @@ void QApplicationPrivate::initializeWidgetPaletteHash() menu.color(QPalette::Active, QPalette::Highlight)); menu.setColor(QPalette::Inactive, QPalette::HighlightedText, menu.color(QPalette::Active, QPalette::HighlightedText)); - - if (QSysInfo::WindowsVersion != QSysInfo::WV_NT && QSysInfo::WindowsVersion != QSysInfo::WV_95) - menu.setColor(QPalette::Inactive, QPalette::ButtonText, - pal.color(QPalette::Inactive, QPalette::Dark)); + menu.setColor(QPalette::Inactive, QPalette::ButtonText, + pal.color(QPalette::Inactive, QPalette::Dark)); QApplication::setPalette(menu, "QMenu"); if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP @@ -716,11 +699,10 @@ void QApplicationPrivate::initializeWidgetPaletteHash() qt_init() - initializes Qt for Windows *****************************************************************************/ -typedef BOOL (WINAPI *PtrUpdateLayeredWindow)(HWND hwnd, HDC hdcDst, const POINT *pptDst, - const SIZE *psize, HDC hdcSrc, const POINT *pptSrc, COLORREF crKey, - const Q_BLENDFUNCTION *pblend, DWORD dwflags); -static PtrUpdateLayeredWindow ptrUpdateLayeredWindow = 0; - +typedef BOOL (WINAPI *PtrSetProcessDPIAware) (VOID); +static PtrSetProcessDPIAware ptrSetProcessDPIAware = 0; +PtrUpdateLayeredWindow ptrUpdateLayeredWindow = 0; +PtrUpdateLayeredWindowIndirect ptrUpdateLayeredWindowIndirect = 0; static BOOL WINAPI qt_updateLayeredWindowIndirect(HWND hwnd, const Q_UPDATELAYEREDWINDOWINFO *info) { return (*ptrUpdateLayeredWindow)(hwnd, info->hdcDst, info->pptDst, info->psize, info->hdcSrc, @@ -747,9 +729,6 @@ void qt_init(QApplicationPrivate *priv, int) appNoGrab = !appNoGrab; else #endif // QT_DEBUG - if (qstrcmp(argv[i], "-direct3d") == 0) - QApplication::setAttribute(Qt::AA_MSWindowsUseDirect3DByDefault); - else argv[j++] = argv[i]; } if(j < priv->argc) { @@ -757,21 +736,12 @@ void qt_init(QApplicationPrivate *priv, int) priv->argc = j; } - // Get the application name/instance if qWinMain() was not invoked -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE // No message boxes but important ones SetErrorMode(SetErrorMode(0) | SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); #endif - if (appInst == 0) { - QT_WA({ - appInst = GetModuleHandle(0); - }, { - appInst = GetModuleHandleA(0); - }); - } - -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE // Initialize OLE/COM // S_OK means success and S_FALSE means that it has already // been initialized @@ -783,7 +753,7 @@ void qt_init(QApplicationPrivate *priv, int) #endif // Misc. initialization -#if defined(QT_DEBUG) && !defined(Q_OS_WINCE) +#if defined(QT_DEBUG) && !defined(Q_WS_WINCE) GdiSetBatchLimit(1); #endif @@ -795,48 +765,32 @@ void qt_init(QApplicationPrivate *priv, int) #ifndef QT_NO_CURSOR QCursorData::initialize(); #endif - qApp->setObjectName(QLatin1String(theAppName)); + qApp->setObjectName(priv->appName()); -#if !defined(Q_OS_WINCE) // default font - HFONT hfont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); - QFont f(QLatin1String("MS Sans Serif"),8); - int result = 0; - QT_WA({ - LOGFONT lf; - if (result = GetObject(hfont, sizeof(lf), &lf)) - f = qt_LOGFONTtoQFont((LOGFONT&)lf,true); - } , { - LOGFONTA lf; - if (result = GetObjectA(hfont, sizeof(lf), &lf)) - f = qt_LOGFONTtoQFont((LOGFONT&)lf,true); - }); - if (result - && QSysInfo::WindowsVersion >= QSysInfo::WV_2000 - && QSysInfo::WindowsVersion <= QSysInfo::WV_NT_based - && f.family() == QLatin1String("MS Shell Dlg")) - f.setFamily(QLatin1String("MS Shell Dlg 2")); - QApplicationPrivate::setSystemFont(f); -#else //Q_OS_WINCE - LOGFONT lf; - HGDIOBJ stockFont = GetStockObject(SYSTEM_FONT); - int result = 0; - result = GetObject(stockFont, sizeof(lf), &lf); - QFont font = qt_LOGFONTtoQFont(lf, true); - if (result) - QApplicationPrivate::setSystemFont(font); -#endif //Q_OS_WINCE +#ifndef Q_WS_WINCE + HGDIOBJ stockFont = GetStockObject(DEFAULT_GUI_FONT); +#else + HGDIOBJ stockFont = GetStockObject(SYSTEM_FONT); +#endif + + LOGFONT lf; + GetObject(stockFont, sizeof(lf), &lf); + QFont systemFont = qt_LOGFONTtoQFont(lf, true); + +#ifndef Q_WS_WINCE + if (systemFont.family() == QLatin1String("MS Shell Dlg")) { + systemFont.setFamily(QLatin1String("MS Shell Dlg 2")); + } +#endif + + QApplicationPrivate::setSystemFont(systemFont); // QFont::locale_init(); ### Uncomment when it does something on Windows if (QApplication::desktopSettingsAware()) qt_set_windows_resources(); - QT_WA({ - WM95_MOUSEWHEEL = RegisterWindowMessage(L"MSWHEEL_ROLLMSG"); - } , { - WM95_MOUSEWHEEL = RegisterWindowMessageA("MSWHEEL_ROLLMSG"); - }); initWinTabFunctions(); QApplicationPrivate::inputContext = new QWinInputContext(0); @@ -857,6 +811,51 @@ void qt_init(QApplicationPrivate *priv, int) if (ptrUpdateLayeredWindow && !ptrUpdateLayeredWindowIndirect) ptrUpdateLayeredWindowIndirect = qt_updateLayeredWindowIndirect; + + // Notify Vista and Windows 7 that we support highter DPI settings + ptrSetProcessDPIAware = (PtrSetProcessDPIAware) + QLibrary::resolve(QLatin1String("user32"), "SetProcessDPIAware"); + if (ptrSetProcessDPIAware) + ptrSetProcessDPIAware(); +#endif + + priv->GetGestureInfo = 0; + priv->GetGestureExtraArgs = 0; + priv->CloseGestureInfoHandle = 0; + priv->SetGestureConfig = 0; + priv->GetGestureConfig = 0; + priv->BeginPanningFeedback = 0; + priv->UpdatePanningFeedback = 0; + priv->EndPanningFeedback = 0; + +#if defined(Q_WS_WINCE_WM) && defined(QT_WINCE_GESTURES) + priv->GetGestureInfo = (PtrGetGestureInfo) &TKGetGestureInfo; + priv->GetGestureExtraArgs = (PtrGetGestureExtraArgs) &TKGetGestureExtraArguments; +#elif !defined(Q_WS_WINCE) + priv->GetGestureInfo = + (PtrGetGestureInfo)QLibrary::resolve(QLatin1String("user32"), + "GetGestureInfo"); + priv->GetGestureExtraArgs = + (PtrGetGestureExtraArgs)QLibrary::resolve(QLatin1String("user32"), + "GetGestureExtraArgs"); + priv->CloseGestureInfoHandle = + (PtrCloseGestureInfoHandle)QLibrary::resolve(QLatin1String("user32"), + "CloseGestureInfoHandle"); + priv->SetGestureConfig = + (PtrSetGestureConfig)QLibrary::resolve(QLatin1String("user32"), + "SetGestureConfig"); + priv->GetGestureConfig = + (PtrGetGestureConfig)QLibrary::resolve(QLatin1String("user32"), + "GetGestureConfig"); + priv->BeginPanningFeedback = + (PtrBeginPanningFeedback)QLibrary::resolve(QLatin1String("uxtheme"), + "BeginPanningFeedback"); + priv->UpdatePanningFeedback = + (PtrUpdatePanningFeedback)QLibrary::resolve(QLatin1String("uxtheme"), + "UpdatePanningFeedback"); + priv->EndPanningFeedback = + (PtrEndPanningFeedback)QLibrary::resolve(QLatin1String("uxtheme"), + "EndPanningFeedback"); #endif } @@ -882,7 +881,7 @@ void qt_cleanup() delete QApplicationPrivate::inputContext; QApplicationPrivate::inputContext = 0; -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE // Deinitialize OLE/COM OleUninitialize(); #endif @@ -893,12 +892,6 @@ void qt_cleanup() Platform specific global and internal functions *****************************************************************************/ -Q_GUI_EXPORT int qWinAppCmdShow() // get main window show command -{ - return appCmdShow; -} - - Q_GUI_EXPORT HDC qt_win_display_dc() // get display DC { Q_ASSERT(qApp && qApp->thread() == QThread::currentThread()); @@ -930,7 +923,7 @@ const QString qt_reg_winclass(QWidget *w) // register window class if (flags & Qt::MSWindowsOwnDC) { cname = QLatin1String("QWidgetOwnDC"); style = CS_DBLCLKS; -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE style |= CS_OWNDC; #endif icon = true; @@ -939,25 +932,25 @@ const QString qt_reg_winclass(QWidget *w) // register window class if (w->inherits("QTipLabel") || w->inherits("QAlphaWidget")) { if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)) { - style |= 0x00020000; // CS_DROPSHADOW + style |= CS_DROPSHADOW; } cname = QLatin1String("QToolTip"); } else { cname = QLatin1String("QTool"); } -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE style |= CS_SAVEBITS; #endif icon = false; } else if (type == Qt::Popup) { cname = QLatin1String("QPopup"); style = CS_DBLCLKS; -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE style |= CS_SAVEBITS; #endif if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)) - style |= 0x00020000; // CS_DROPSHADOW + style |= CS_DROPSHADOW; icon = false; } else { cname = QLatin1String("QWidget"); @@ -965,7 +958,7 @@ const QString qt_reg_winclass(QWidget *w) // register window class icon = true; } -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE // force CS_OWNDC when the GL graphics system is // used as the default renderer if (qt_win_owndc_required) @@ -977,11 +970,11 @@ const QString qt_reg_winclass(QWidget *w) // register window class // unique ID on WinCE to make sure we can // move the windows to the front when starting // a second instance. - wchar_t uniqueAppID[256]; - GetModuleFileNameW(0, uniqueAppID, 255); - cname = QString::number(RegisterWindowMessageW( - (const wchar_t *) QString::fromUtf16((const ushort *)uniqueAppID).toLower().replace(QString(QString::fromLatin1("\\")), - QString(QString::fromLatin1("_"))).utf16())); + wchar_t uniqueAppID[MAX_PATH]; + GetModuleFileName(0, uniqueAppID, MAX_PATH); + cname = QString::number(RegisterWindowMessage( + (const wchar_t *) QString::fromWCharArray(uniqueAppID).toLower().replace(QLatin1Char('\\'), + QLatin1Char('_')).utf16())); #endif // since multiple Qt versions can be used in one process @@ -992,15 +985,9 @@ const QString qt_reg_winclass(QWidget *w) // register window class static int classExists = -1; if (classExists == -1) { - QT_WA({ - WNDCLASS wcinfo; - classExists = GetClassInfo((HINSTANCE)qWinAppInst(), (TCHAR*)cname.utf16(), &wcinfo); - classExists = classExists && wcinfo.lpfnWndProc != QtWndProc; - }, { - WNDCLASSA wcinfo; - classExists = GetClassInfoA((HINSTANCE)qWinAppInst(), cname.toLatin1(), &wcinfo); - classExists = classExists && wcinfo.lpfnWndProc != QtWndProc; - }); + WNDCLASS wcinfo; + classExists = GetClassInfo((HINSTANCE)qWinAppInst(), (wchar_t*)cname.utf16(), &wcinfo); + classExists = classExists && wcinfo.lpfnWndProc != QtWndProc; } if (classExists) @@ -1009,73 +996,37 @@ const QString qt_reg_winclass(QWidget *w) // register window class if (winclassNames()->contains(cname)) // already registered in our list return cname; - ATOM atom; -#ifndef Q_OS_WINCE - HBRUSH bgBrush = (HBRUSH)GetSysColorBrush(COLOR_WINDOW); - QT_WA({ - WNDCLASS wc; - wc.style = style; - wc.lpfnWndProc = (WNDPROC)QtWndProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = (HINSTANCE)qWinAppInst(); - if (icon) { - wc.hIcon = LoadIcon(appInst, L"IDI_ICON1"); - if (!wc.hIcon) - wc.hIcon = LoadIcon(0, IDI_APPLICATION); - } else { - wc.hIcon = 0; - } - wc.hCursor = 0; - wc.hbrBackground= bgBrush; - wc.lpszMenuName = 0; - wc.lpszClassName= (TCHAR*)cname.utf16(); - atom = RegisterClass(&wc); - } , { - WNDCLASSA wc; - wc.style = style; - wc.lpfnWndProc = (WNDPROC)QtWndProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = (HINSTANCE)qWinAppInst(); - if (icon) { - wc.hIcon = LoadIconA(appInst, (char*)"IDI_ICON1"); - if (!wc.hIcon) - wc.hIcon = LoadIconA(0, (char*)IDI_APPLICATION); - } else { - wc.hIcon = 0; - } - wc.hCursor = 0; - wc.hbrBackground= bgBrush; - wc.lpszMenuName = 0; - QByteArray tempArray = cname.toLatin1(); - wc.lpszClassName= tempArray; - atom = RegisterClassA(&wc); - }); + WNDCLASS wc; + wc.style = style; + wc.lpfnWndProc = (WNDPROC)QtWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = qWinAppInst(); + if (icon) { + wc.hIcon = (HICON)LoadImage(qWinAppInst(), L"IDI_ICON1", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); +#ifndef Q_WS_WINCE + if (!wc.hIcon) + wc.hIcon = (HICON)LoadImage(0, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED); +#endif + } else { + wc.hIcon = 0; + } + wc.hCursor = 0; +#ifndef Q_WS_WINCE + wc.hbrBackground = (HBRUSH)GetSysColorBrush(COLOR_WINDOW); #else - WNDCLASS wc; - wc.style = style; - wc.lpfnWndProc = (WNDPROC)QtWndProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = (HINSTANCE)qWinAppInst(); - if (icon) { - wc.hIcon = LoadIcon(appInst, L"IDI_ICON1"); -// if (!wc.hIcon) -// wc.hIcon = LoadIcon(0, IDI_APPLICATION); - } else { - wc.hIcon = 0; - } - wc.hCursor = 0; - wc.hbrBackground= 0; - wc.lpszMenuName = 0; - wc.lpszClassName= (TCHAR*)cname.utf16(); - atom = RegisterClass(&wc); + wc.hbrBackground = 0; #endif + wc.lpszMenuName = 0; + wc.lpszClassName = (wchar_t*)cname.utf16(); + + ATOM atom = RegisterClass(&wc); #ifndef QT_NO_DEBUG if (!atom) qErrnoWarning("QApplication::regClass: Registering window class failed."); +#else + Q_UNUSED(atom); #endif winclassNames()->insert(cname, 1); @@ -1093,11 +1044,7 @@ static void unregWinClasses() WinClassNameHash *hash = winclassNames(); QHash<QString, int>::ConstIterator it = hash->constBegin(); while (it != hash->constEnd()) { - QT_WA({ - UnregisterClass((TCHAR*)it.key().utf16(), (HINSTANCE)qWinAppInst()); - } , { - UnregisterClassA(it.key().toLatin1(), (HINSTANCE)qWinAppInst()); - }); + UnregisterClass((wchar_t*)it.key().utf16(), qWinAppInst()); ++it; } hash->clear(); @@ -1131,7 +1078,7 @@ void qWinRequestConfig(WId id, int req, int x, int y, int w, int h) configRequests->append(r); // store request in queue } -Q_GUI_EXPORT void qWinProcessConfigRequests() // perform requests in queue +static void qWinProcessConfigRequests() // perform requests in queue { if (!configRequests) return; @@ -1314,16 +1261,13 @@ void QApplication::beep() static void alert_widget(QWidget *widget, int duration) { +#ifdef Q_OS_WINCE + Q_UNUSED(widget); + Q_UNUSED(duration); +#else bool stopFlash = duration < 0; - if (!pFlashWindowEx) { -#ifndef Q_OS_WINCE - QLibrary themeLib(QLatin1String("user32")); - pFlashWindowEx = (PtrFlashWindowEx)themeLib.resolve("FlashWindowEx"); -#endif - } - - if (pFlashWindowEx && widget && (!widget->isActiveWindow() || stopFlash)) { + if (widget && (!widget->isActiveWindow() || stopFlash)) { DWORD timeOut = GetCaretBlinkTime(); if (timeOut <= 0) timeOut = 250; @@ -1341,8 +1285,9 @@ static void alert_widget(QWidget *widget, int duration) info.dwTimeout = stopFlash ? 0 : timeOut; info.uCount = stopFlash ? 0 : flashCount; - pFlashWindowEx(&info); + FlashWindowEx(&info); } +#endif } void QApplication::alert(QWidget *widget, int duration) @@ -1383,7 +1328,7 @@ void QApplication::winFocus(QWidget *widget, bool gotFocus) && (QApplicationPrivate::active_window->windowType() == Qt::Dialog)) { // raise the entire application, not just the dialog QWidget* mw = QApplicationPrivate::active_window; -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE while(mw->parentWidget() && (mw->windowType() == Qt::Dialog)) mw = mw->parentWidget()->window(); if (mw->testAttribute(Qt::WA_WState_Created) && mw != QApplicationPrivate::active_window) @@ -1430,12 +1375,13 @@ static int inputcharset = CP_ACP; static bool qt_is_translatable_mouse_event(UINT message) { - return (message >= WM_MOUSEFIRST && message <= WM_MOUSELAST || - message >= WM_XBUTTONDOWN && message <= WM_XBUTTONDBLCLK) + return (((message >= WM_MOUSEFIRST && message <= WM_MOUSELAST) || + (message >= WM_XBUTTONDOWN && message <= WM_XBUTTONDBLCLK)) && message != WM_MOUSEWHEEL + && message != WM_MOUSEHWHEEL) -#ifndef Q_OS_WINCE - || message >= WM_NCMOUSEMOVE && message <= WM_NCMBUTTONDBLCLK +#ifndef Q_WS_WINCE + || (message >= WM_NCMOUSEMOVE && message <= WM_NCMBUTTONDBLCLK) #endif ; } @@ -1474,7 +1420,7 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam msg.pt.y = GET_Y_LPARAM(lParam); // If it's a non-client-area message the coords are screen coords, otherwise they are // client coords. -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE if (message < WM_NCMOUSEMOVE || message > WM_NCMBUTTONDBLCLK) #endif ClientToScreen(msg.hwnd, &msg.pt); @@ -1504,7 +1450,7 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam if (imeParentWnd && QApplication::activePopupWidget() && (message == WM_MBUTTONDOWN || message == WM_XBUTTONDOWN || message == WM_LBUTTONDOWN || message == WM_RBUTTONDOWN -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE || message == WM_NCMBUTTONDOWN || message == WM_NCLBUTTONDOWN || message == WM_NCRBUTTONDOWN)) { #else @@ -1514,7 +1460,7 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam } switch (message) { -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE case WM_QUERYENDSESSION: { if (sm_smActive) // bogus message from windows RETURN(true); @@ -1536,19 +1482,19 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam // we receive the message for each toplevel window included internal hidden ones, // but the aboutToQuit signal should be emitted only once. - QApplicationPrivate *qAppPriv = getQApplicationPrivateInternal(); + QApplicationPrivate *qAppPriv = QApplicationPrivate::instance(); if (endsession && !qAppPriv->aboutToQuitEmitted) { qAppPriv->aboutToQuitEmitted = true; int index = QApplication::staticMetaObject.indexOfSignal("aboutToQuit()"); qApp->qt_metacall(QMetaObject::InvokeMetaMethod, index,0); // since the process will be killed immediately quit() has no real effect - qApp->quit(); + QApplication::quit(); } RETURN(0); } case WM_DISPLAYCHANGE: - if (qApp->type() == QApplication::Tty) + if (QApplication::type() == QApplication::Tty) break; if (qt_desktopWidget) { qt_desktopWidget->move(GetSystemMetrics(76), GetSystemMetrics(77)); @@ -1565,7 +1511,7 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam #endif case WM_SETTINGCHANGE: -#ifdef Q_OS_WINCE +#ifdef Q_WS_WINCE // CE SIP hide/show if (wParam == SPI_SETSIPINFO) { QResizeEvent re(QSize(0, 0), QSize(0, 0)); // Calculated by QDesktopWidget @@ -1574,7 +1520,7 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam } #endif // ignore spurious XP message when user logs in again after locking - if (qApp->type() == QApplication::Tty) + if (QApplication::type() == QApplication::Tty) break; if (QApplication::desktopSettingsAware() && wParam != SPI_SETWORKAREA) { widget = (QETWidget*)QWidget::find(hwnd); @@ -1597,7 +1543,7 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam if (wParam == SPI_SETFONTSMOOTHINGTYPE) { qt_win_read_cleartype_settings(); - foreach (QWidget *w, qApp->topLevelWidgets()) { + foreach (QWidget *w, QApplication::topLevelWidgets()) { if (!w->isVisible()) continue; ((QETWidget *) w)->forceUpdate(); @@ -1606,7 +1552,7 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam break; case WM_SYSCOLORCHANGE: - if (qApp->type() == QApplication::Tty) + if (QApplication::type() == QApplication::Tty) break; if (QApplication::desktopSettingsAware()) { widget = (QETWidget*)QWidget::find(hwnd); @@ -1658,7 +1604,7 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam RETURN(res); if (qt_is_translatable_mouse_event(message)) { - if (qApp->activePopupWidget() != 0) { // in popup mode + if (QApplication::activePopupWidget() != 0) { // in popup mode POINT curPos = msg.pt; QWidget* w = QApplication::widgetAt(curPos.x, curPos.y); if (w) @@ -1667,10 +1613,10 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam if (!qt_tabletChokeMouse) { result = widget->translateMouseEvent(msg); // mouse event -#if defined(Q_OS_WINCE) && !defined(QT_NO_CONTEXTMENU) - if (message == WM_LBUTTONDOWN && widget != qApp->activePopupWidget()) { +#if defined(Q_WS_WINCE) && !defined(QT_NO_CONTEXTMENU) + if (message == WM_LBUTTONDOWN && widget != QApplication::activePopupWidget()) { QWidget* alienWidget = widget; - if ((alienWidget != qApp->activePopupWidget()) && (alienWidget->contextMenuPolicy() != Qt::PreventContextMenu)) { + if ((alienWidget != QApplication::activePopupWidget()) && (alienWidget->contextMenuPolicy() != Qt::PreventContextMenu)) { QPoint pos(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); QPoint globalPos(msg.pt.x, msg.pt.y); // In case we are using Alien, then the widget to @@ -1689,8 +1635,8 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam shrg.dwFlags = SHRG_RETURNCMD | SHRG_NOANIMATION; resolveAygLibs(); if (ptrRecognizeGesture && (ptrRecognizeGesture(&shrg) == GN_CONTEXTMENU)) { - if (qApp->activePopupWidget()) - qApp->activePopupWidget()->close(); + if (QApplication::activePopupWidget()) + QApplication::activePopupWidget()->close(); QContextMenuEvent e(QContextMenuEvent::Mouse, pos, globalPos); result = qt_sendSpontaneousEvent(alienWidget, &e); } @@ -1702,7 +1648,7 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam // Sometimes we only get a WM_MOUSEMOVE message // and sometimes we get both a WM_MOUSEMOVE and // a WM_LBUTTONDOWN/UP, this creates a spurious mouse - // press/release event, using the winPeekMessage + // press/release event, using the PeekMessage // will help us fix this. This leaves us with a // question: // This effectively kills using the mouse AND the @@ -1712,18 +1658,19 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam bool is_mouse_move = (message == WM_MOUSEMOVE); if (is_mouse_move) { MSG msg1; - if (winPeekMessage(&msg1, msg.hwnd, WM_MOUSEFIRST, - WM_MOUSELAST, PM_NOREMOVE)) + if (PeekMessage(&msg1, msg.hwnd, WM_MOUSEFIRST, + WM_MOUSELAST, PM_NOREMOVE)) next_is_button = (msg1.message == WM_LBUTTONUP || msg1.message == WM_LBUTTONDOWN); } if (!is_mouse_move || (is_mouse_move && !next_is_button)) qt_tabletChokeMouse = false; } - } else if (message == WM95_MOUSEWHEEL) { - result = widget->translateWheelEvent(msg); } else { switch (message) { + case WM_TOUCH: + result = QApplicationPrivate::instance()->translateTouchEvent(msg); + break; case WM_KEYDOWN: // keyboard event case WM_SYSKEYDOWN: qt_keymapper_private()->updateKeyMap(msg); @@ -1749,7 +1696,7 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam case WM_IME_KEYDOWN: case WM_CHAR: { MSG msg1; - bool anyMsg = winPeekMessage(&msg1, msg.hwnd, 0, 0, PM_NOREMOVE); + bool anyMsg = PeekMessage(&msg1, msg.hwnd, 0, 0, PM_NOREMOVE); if (anyMsg && msg1.message == WM_DEADCHAR) { result = true; // consume event since there is a dead char next break; @@ -1768,7 +1715,7 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam widget = (QETWidget*)QApplication::activePopupWidget()->focusWidget() ? (QETWidget*)QApplication::activePopupWidget()->focusWidget() : (QETWidget*)QApplication::activePopupWidget(); - else if (qApp->focusWidget()) + else if (QApplication::focusWidget()) widget = (QETWidget*)QApplication::focusWidget(); else if (!widget || widget->internalWinId() == GetFocus()) // We faked the message to go to exactly that widget. widget = (QETWidget*)widget->window(); @@ -1783,6 +1730,7 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam break; case WM_MOUSEWHEEL: + case WM_MOUSEHWHEEL: result = widget->translateWheelEvent(msg); break; @@ -1809,79 +1757,18 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam case APPCOMMAND_BASS_UP: key = Qt::Key_BassUp; break; - case APPCOMMAND_BROWSER_BACKWARD: - key = Qt::Key_Back; - break; - case APPCOMMAND_BROWSER_FAVORITES: - key = Qt::Key_Favorites; - break; - case APPCOMMAND_BROWSER_FORWARD: - key = Qt::Key_Forward; - break; - case APPCOMMAND_BROWSER_HOME: - key = Qt::Key_HomePage; - break; - case APPCOMMAND_BROWSER_REFRESH: - key = Qt::Key_Refresh; - break; - case APPCOMMAND_BROWSER_SEARCH: - key = Qt::Key_Search; - break; - case APPCOMMAND_BROWSER_STOP: - key = Qt::Key_Stop; - break; - case APPCOMMAND_LAUNCH_APP1: - key = Qt::Key_Launch0; - break; - case APPCOMMAND_LAUNCH_APP2: - key = Qt::Key_Launch1; - break; - case APPCOMMAND_LAUNCH_MAIL: - key = Qt::Key_LaunchMail; - break; - case APPCOMMAND_LAUNCH_MEDIA_SELECT: - key = Qt::Key_LaunchMedia; - break; - case APPCOMMAND_MEDIA_NEXTTRACK: - key = Qt::Key_MediaNext; - break; - case APPCOMMAND_MEDIA_PLAY_PAUSE: - key = Qt::Key_MediaPlay; - break; - case APPCOMMAND_MEDIA_PREVIOUSTRACK: - key = Qt::Key_MediaPrevious; - break; - case APPCOMMAND_MEDIA_STOP: - key = Qt::Key_MediaStop; - break; case APPCOMMAND_TREBLE_DOWN: key = Qt::Key_TrebleDown; break; case APPCOMMAND_TREBLE_UP: key = Qt::Key_TrebleUp; break; - case APPCOMMAND_VOLUME_DOWN: - key = Qt::Key_VolumeDown; - break; - case APPCOMMAND_VOLUME_MUTE: - key = Qt::Key_VolumeMute; - break; - case APPCOMMAND_VOLUME_UP: - key = Qt::Key_VolumeUp; - break; - // Commands new in Windows XP case APPCOMMAND_HELP: key = Qt::Key_Help; break; case APPCOMMAND_FIND: key = Qt::Key_Search; break; - case APPCOMMAND_PRINT: - key = Qt::Key_Print; - break; - case APPCOMMAND_MEDIA_PLAY: - key = Qt::Key_MediaPlay; - break; default: break; } @@ -1890,8 +1777,8 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam QWidget *g = QWidget::keyboardGrabber(); if (g) widget = (QETWidget*)g; - else if (qApp->focusWidget()) - widget = (QETWidget*)qApp->focusWidget(); + else if (QApplication::focusWidget()) + widget = (QETWidget*)QApplication::focusWidget(); else widget = (QETWidget*)widget->window(); if (widget->isEnabled()) { @@ -1913,17 +1800,21 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam } break; -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE case WM_NCHITTEST: if (widget->isWindow()) { QPoint pos = widget->mapFromGlobal(QPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); // don't show resize-cursors for fixed-size widgets QRect fs = widget->frameStrut(); if (!widget->isMinimized()) { + if (widget->minimumHeight() == widget->maximumHeight()) { + if (pos.y() < -(fs.top() - fs.left())) + return HTCAPTION; + if (pos.y() >= widget->height()) + return HTBORDER; + } if (widget->minimumWidth() == widget->maximumWidth() && (pos.x() < 0 || pos.x() >= widget->width())) - break; - if (widget->minimumHeight() == widget->maximumHeight() && (pos.y() < -(fs.top() - fs.left()) || pos.y() >= widget->height())) - break; + return HTBORDER; } } @@ -1932,7 +1823,7 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam #endif case WM_SYSCOMMAND: { -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE bool window_state_change = false; Qt::WindowStates oldstate = Qt::WindowStates(widget->dataPtr()->window_state); // MSDN:In WM_SYSCOMMAND messages, the four low-order bits of the wParam parameter are @@ -1944,11 +1835,7 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam #ifndef QT_NO_WHATSTHIS QWhatsThis::enterWhatsThisMode(); #endif - QT_WA({ - DefWindowProc(hwnd, WM_NCPAINT, 1, 0); - } , { - DefWindowProcA(hwnd, WM_NCPAINT, 1, 0); - }); + DefWindowProc(hwnd, WM_NCPAINT, 1, 0); break; #if defined(QT_NON_COMMERCIAL) QT_NC_SYSCOMMAND @@ -2002,12 +1889,11 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam } case WM_SETTINGCHANGE: - if ( qApp->type() == QApplication::Tty ) + if ( QApplication::type() == QApplication::Tty ) break; if (!msg.wParam) { - QString area = QT_WA_INLINE(QString::fromUtf16((unsigned short *)msg.lParam), - QString::fromLocal8Bit((char*)msg.lParam)); + QString area = QString::fromWCharArray((wchar_t*)msg.lParam); if (area == QLatin1String("intl")) { QLocalePrivate::updateSystemPrivate(); if (!widget->testAttribute(Qt::WA_SetLocale)) @@ -2015,7 +1901,7 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam } } else if (msg.wParam == SPI_SETICONTITLELOGFONT) { - if (qApp->desktopSettingsAware()) { + if (QApplication::desktopSettingsAware()) { widget = (QETWidget*)QWidget::find(hwnd); if (widget && !widget->parentWidget()) { qt_set_windows_font_resources(); @@ -2029,14 +1915,12 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam result = widget->translatePaintEvent(msg); break; -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE case WM_ENTERSIZEMOVE: autoCaptureWnd = hwnd; - QApplicationPrivate::inSizeMove = true; break; case WM_EXITSIZEMOVE: autoCaptureWnd = 0; - QApplicationPrivate::inSizeMove = false; break; #endif case WM_MOVE: // move window @@ -2058,7 +1942,7 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam break; case WM_ACTIVATE: - if ( qApp->type() == QApplication::Tty ) + if ( QApplication::type() == QApplication::Tty ) break; if (ptrWTOverlap && ptrWTEnable) { @@ -2084,19 +1968,28 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam // WM_ACTIVATEAPP handles the "true" false case, as this is only when the application // loses focus. Doing it here would result in the widget getting focus to not know // where it got it from; it would simply get a 0 value as the old focus widget. -#ifdef Q_OS_WINCE +#ifdef Q_WS_WINCE { - if (widget->windowState() & Qt::WindowMinimized) { - if (widget->windowState() & Qt::WindowMaximized) - widget->showMaximized(); - else - widget->show(); +#ifdef Q_WS_WINCE_WM + // On Windows mobile we do not receive WM_SYSCOMMAND / SC_MINIMIZE messages. + // Thus we have to unset the minimized state explicitly. We must do this for all + // top-level widgets, because we get the HWND of a random widget here. + foreach (QWidget* tlw, QApplication::topLevelWidgets()) { + if (tlw->isMinimized()) + tlw->setWindowState(tlw->windowState() & ~Qt::WindowMinimized); } #else + // On Windows CE we do not receive WM_SYSCOMMAND / SC_MINIMIZE messages. + // Thus we have to unset the minimized state explicitly. + if (widget->windowState() & Qt::WindowMinimized) + widget->setWindowState(widget->windowState() & ~Qt::WindowMinimized); +#endif // Q_WS_WINCE_WM + +#else if (!(widget->windowState() & Qt::WindowMinimized)) { #endif // Ignore the activate message send by WindowsXP to a minimized window -#ifdef Q_OS_WINCE_WM +#ifdef Q_WS_WINCE_WM if (widget->windowState() & Qt::WindowFullScreen) qt_wince_hide_taskbar(widget->winId()); #endif @@ -2123,7 +2016,7 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam } break; -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE case WM_MOUSEACTIVATE: if (widget->window()->windowType() == Qt::Tool) { QWidget *w = widget; @@ -2212,7 +2105,7 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam result = false; break; -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE case WM_WINDOWPOSCHANGING: { result = false; @@ -2293,12 +2186,12 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam QWidget *fw = QWidget::keyboardGrabber(); if (!fw) { - if (qApp->activePopupWidget()) - fw = (qApp->activePopupWidget()->focusWidget() - ? qApp->activePopupWidget()->focusWidget() - : qApp->activePopupWidget()); - else if (qApp->focusWidget()) - fw = qApp->focusWidget(); + if (QApplication::activePopupWidget()) + fw = (QApplication::activePopupWidget()->focusWidget() + ? QApplication::activePopupWidget()->focusWidget() + : QApplication::activePopupWidget()); + else if (QApplication::focusWidget()) + fw = QApplication::focusWidget(); else if (widget) fw = widget->window(); } @@ -2315,7 +2208,7 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam case WM_IME_STARTCOMPOSITION: case WM_IME_ENDCOMPOSITION: case WM_IME_COMPOSITION: { - QWidget *fw = qApp->focusWidget(); + QWidget *fw = QApplication::focusWidget(); QWinInputContext *im = fw ? qobject_cast<QWinInputContext *>(fw->inputContext()) : 0; if (fw && im) { if(message == WM_IME_STARTCOMPOSITION) @@ -2327,8 +2220,27 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam } break; } - -#ifndef Q_OS_WINCE + case WM_IME_REQUEST: { + QWidget *fw = QApplication::focusWidget(); + QWinInputContext *im = fw ? qobject_cast<QWinInputContext *>(fw->inputContext()) : 0; + if (fw && im) { + if(wParam == IMR_RECONVERTSTRING) { + int ret = im->reconvertString((RECONVERTSTRING *)lParam); + if (ret == -1) { + result = false; + } else { + return ret; + } + } else if (wParam == IMR_CONFIRMRECONVERTSTRING) { + RETURN(TRUE); + } else { + // in all other cases, call DefWindowProc() + result = false; + } + } + break; + } +#ifndef Q_WS_WINCE case WM_CHANGECBCHAIN: case WM_DRAWCLIPBOARD: #endif @@ -2348,7 +2260,7 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam case WM_GETOBJECT: { // Ignoring all requests while starting up - if (qApp->startingUp() || qApp->closingDown() || (DWORD)lParam != OBJID_CLIENT) { + if (QApplication::startingUp() || QApplication::closingDown() || (DWORD)lParam != OBJID_CLIENT) { result = false; break; } @@ -2391,11 +2303,7 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam text = widget->objectName(); ret = qMin<int>(wParam - 1, text.size()); text.resize(ret); - QT_WA({ - memcpy((void *)lParam, text.utf16(), (text.size() + 1) * 2); - }, { - memcpy((void *)lParam, text.toLocal8Bit().data(), text.size() + 1); - }); + memcpy((void *)lParam, text.utf16(), (text.size() + 1) * sizeof(ushort)); delete acc; } if (!ret) { @@ -2435,7 +2343,7 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam #endif // QT_NO_TABLETEVENT } break; -#ifdef Q_OS_WINCE_WM +#ifdef Q_WS_WINCE_WM case WM_SETFOCUS: { HIMC hC; hC = ImmGetContext(hwnd); @@ -2448,7 +2356,7 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam case WM_KILLFOCUS: if (!QWidget::find((HWND)wParam)) { // we don't get focus, so unset it now if (!widget->hasFocus()) // work around Windows bug after minimizing/restoring - widget = (QETWidget*)qApp->focusWidget(); + widget = (QETWidget*)QApplication::focusWidget(); HWND focus = ::GetFocus(); //if there is a current widget and the new widget belongs to the same toplevel window //or if the current widget was embedded into non-qt window (i.e. we won't get WM_ACTIVATEAPP) @@ -2467,27 +2375,27 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam } break; case WM_THEMECHANGED: - if ((widget->windowType() == Qt::Desktop) || !qApp || qApp->closingDown() - || qApp->type() == QApplication::Tty) + if ((widget->windowType() == Qt::Desktop) || !qApp || QApplication::closingDown() + || QApplication::type() == QApplication::Tty) break; if (widget->testAttribute(Qt::WA_WState_Polished)) - qApp->style()->unpolish(widget); + QApplication::style()->unpolish(widget); if (widget->testAttribute(Qt::WA_WState_Polished)) - qApp->style()->polish(widget); - widget->repolishStyle(*qApp->style()); + QApplication::style()->polish(widget); + widget->repolishStyle(*QApplication::style()); if (widget->isVisible()) widget->update(); break; -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE case WM_INPUTLANGCHANGE: { - char info[7]; - if (!GetLocaleInfoA(MAKELCID(lParam, SORT_DEFAULT), LOCALE_IDEFAULTANSICODEPAGE, info, 6)) { + wchar_t info[7]; + if (!GetLocaleInfo(MAKELCID(lParam, SORT_DEFAULT), LOCALE_IDEFAULTANSICODEPAGE, info, 6)) { inputcharset = CP_ACP; } else { - inputcharset = QString::fromLatin1(info).toInt(); + inputcharset = QString::fromWCharArray(info).toInt(); } QKeyMapper::changeKeyboard(); break; @@ -2581,6 +2489,38 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam } result = false; break; + 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; @@ -2679,19 +2619,19 @@ bool qt_try_modal(QWidget *widget, MSG *msg, int& ret) int type = msg->message; bool block_event = false; -#ifndef Q_OS_WINCE - if (type != WM_NCHITTEST) +#ifndef Q_WS_WINCE + if (type != WM_NCHITTEST) { #endif if ((type >= WM_MOUSEFIRST && type <= WM_MOUSELAST) || - type == WM_MOUSEWHEEL || type == (int)WM95_MOUSEWHEEL || + type == WM_MOUSEWHEEL || type == WM_MOUSEHWHEEL || type == WM_MOUSELEAVE || (type >= WM_KEYFIRST && type <= WM_KEYLAST) -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE || type == WM_NCMOUSEMOVE #endif ) { if (type == WM_MOUSEMOVE -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE || type == WM_NCMOUSEMOVE #endif ) { @@ -2709,18 +2649,19 @@ bool qt_try_modal(QWidget *widget, MSG *msg, int& ret) } else if (type == WM_CLOSE) { block_event = true; } -#ifndef Q_OS_WINCE - else if (type == WM_MOUSEACTIVATE || type == WM_NCLBUTTONDOWN){ - if (!top->isActiveWindow()) { - top->activateWindow(); - } else { - QApplication::beep(); - } - block_event = true; - ret = MA_NOACTIVATEANDEAT; - } else if (type == WM_SYSCOMMAND) { - if (!(msg->wParam == SC_RESTORE && widget->isMinimized())) +#ifndef Q_WS_WINCE + else if (type == WM_MOUSEACTIVATE || type == WM_NCLBUTTONDOWN){ + if (!top->isActiveWindow()) { + top->activateWindow(); + } else { + QApplication::beep(); + } block_event = true; + ret = MA_NOACTIVATEANDEAT; + } else if (type == WM_SYSCOMMAND) { + if (!(msg->wParam == SC_RESTORE && widget->isMinimized())) + block_event = true; + } } #endif @@ -2764,9 +2705,9 @@ void QApplicationPrivate::openPopup(QWidget *popup) if (popup->focusWidget()) { popup->focusWidget()->setFocus(Qt::PopupFocusReason); } else if (QApplicationPrivate::popupWidgets->count() == 1) { // this was the first popup - if (QWidget *fw = q_func()->focusWidget()) { + if (QWidget *fw = QApplication::focusWidget()) { QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason); - q_func()->sendEvent(fw, &e); + QApplication::sendEvent(fw, &e); } } } @@ -2793,13 +2734,13 @@ void QApplicationPrivate::closePopup(QWidget *popup) if (!qt_nograb()) // grabbing not disabled releaseAutoCapture(); QWidget *fw = QApplicationPrivate::active_window ? QApplicationPrivate::active_window->focusWidget() - : q_func()->focusWidget(); + : QApplication::focusWidget(); if (fw) { - if (fw != q_func()->focusWidget()) { + if (fw != QApplication::focusWidget()) { fw->setFocus(Qt::PopupFocusReason); } else { QFocusEvent e(QEvent::FocusIn, Qt::PopupFocusReason); - q_func()->sendEvent(fw, &e); + QApplication::sendEvent(fw, &e); } } } else { @@ -2867,7 +2808,7 @@ static const ushort mouseTbl[] = { WM_XBUTTONUP, QEvent::MouseButtonRelease, Qt::XButton1, WM_XBUTTONDBLCLK, QEvent::MouseButtonDblClick, Qt::XButton1, -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE WM_NCMOUSEMOVE, QEvent::NonClientAreaMouseMove, 0, WM_NCLBUTTONDOWN, QEvent::NonClientAreaMouseButtonPress, Qt::LeftButton, WM_NCLBUTTONUP, QEvent::NonClientAreaMouseButtonRelease, Qt::LeftButton, @@ -2922,20 +2863,11 @@ void qt_win_eatMouseMove() // remove all those messages (usually 1) and post the last one with a // reset button state - MSG msg = {0, 0, 0, 0, 0, 0, 0}; - QT_WA( { - while (PeekMessage(&msg, 0, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE)) - ; - if (msg.message == WM_MOUSEMOVE) - PostMessage(msg.hwnd, msg.message, 0, msg.lParam); - }, { - MSG msg; - msg.message = 0; - while (PeekMessageA(&msg, 0, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE)) - ; - if (msg.message == WM_MOUSEMOVE) - PostMessageA(msg.hwnd, msg.message, 0, msg.lParam); - } ); + MSG msg = {0, 0, 0, 0, 0, {0, 0} }; + while (PeekMessage(&msg, 0, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE)) + ; + if (msg.message == WM_MOUSEMOVE) + PostMessage(msg.hwnd, msg.message, 0, msg.lParam); } // In DnD, the mouse release event never appears, so the @@ -2970,8 +2902,8 @@ bool QETWidget::translateMouseEvent(const MSG &msg) // Compress mouse move events if (msg.message == WM_MOUSEMOVE) { MSG mouseMsg; - while (winPeekMessage(&mouseMsg, msg.hwnd, WM_MOUSEFIRST, - WM_MOUSELAST, PM_NOREMOVE)) { + while (PeekMessage(&mouseMsg, msg.hwnd, WM_MOUSEFIRST, + WM_MOUSELAST, PM_NOREMOVE)) { if (mouseMsg.message == WM_MOUSEMOVE) { #define PEEKMESSAGE_IS_BROKEN 1 #ifdef PEEKMESSAGE_IS_BROKEN @@ -2982,12 +2914,12 @@ bool QETWidget::translateMouseEvent(const MSG &msg) // key release events (kls 2003-05-13): MSG keyMsg; bool done = false; - while (winPeekMessage(&keyMsg, 0, WM_KEYFIRST, WM_KEYLAST, - PM_NOREMOVE)) { + while (PeekMessage(&keyMsg, 0, WM_KEYFIRST, WM_KEYLAST, + PM_NOREMOVE)) { if (keyMsg.time < mouseMsg.time) { if ((keyMsg.lParam & 0xC0000000) == 0x40000000) { - winPeekMessage(&keyMsg, 0, keyMsg.message, - keyMsg.message, PM_REMOVE); + PeekMessage(&keyMsg, 0, keyMsg.message, + keyMsg.message, PM_REMOVE); } else { done = true; break; @@ -3013,8 +2945,8 @@ bool QETWidget::translateMouseEvent(const MSG &msg) msgPtr->wParam = mouseMsg.wParam; msgPtr->pt = mouseMsg.pt; // Remove the mouse move message - winPeekMessage(&mouseMsg, msg.hwnd, WM_MOUSEMOVE, - WM_MOUSEMOVE, PM_REMOVE); + PeekMessage(&mouseMsg, msg.hwnd, WM_MOUSEMOVE, + WM_MOUSEMOVE, PM_REMOVE); } else { break; // there was no more WM_MOUSEMOVE event } @@ -3043,7 +2975,9 @@ bool QETWidget::translateMouseEvent(const MSG &msg) if (alienWidget && alienWidget->internalWinId()) alienWidget = 0; - if (type == QEvent::MouseMove || type == QEvent::NonClientAreaMouseMove) { + if (type == QEvent::MouseMove || type == QEvent::NonClientAreaMouseMove + || type == QEvent::TabletMove) { + if (!(state & Qt::MouseButtonMask)) qt_button_down = 0; #ifndef QT_NO_CURSOR @@ -3063,7 +2997,7 @@ bool QETWidget::translateMouseEvent(const MSG &msg) HWND id = effectiveWinId(); QWidget *mouseGrabber = QWidget::mouseGrabber(); - QWidget *activePopupWidget = qApp->activePopupWidget(); + QWidget *activePopupWidget = QApplication::activePopupWidget(); if (mouseGrabber) { if (!activePopupWidget || (activePopupWidget == this && !rect().contains(widgetPos))) id = mouseGrabber->effectiveWinId(); @@ -3156,7 +3090,7 @@ bool QETWidget::translateMouseEvent(const MSG &msg) return false; replayPopupMouseEvent = false; - QWidget* activePopupWidget = qApp->activePopupWidget(); + QWidget* activePopupWidget = QApplication::activePopupWidget(); QWidget *target = activePopupWidget; const QPoint globalPos(gpos.x, gpos.y); @@ -3174,6 +3108,8 @@ bool QETWidget::translateMouseEvent(const MSG &msg) popupButtonFocus = popupChild; break; case QEvent::MouseButtonRelease: + case QEvent::TabletRelease: + releaseAfter = true; break; default: @@ -3184,10 +3120,7 @@ bool QETWidget::translateMouseEvent(const MSG &msg) if (popupButtonFocus) { target = popupButtonFocus; } else if (popupChild) { - // forward mouse events to the popup child. mouse move events - // are only forwarded to popup children that enable mouse tracking. - if (type != QEvent::MouseMove || popupChild->hasMouseTracking()) - target = popupChild; + target = popupChild; } pos = target->mapFromGlobal(globalPos); @@ -3217,7 +3150,7 @@ bool QETWidget::translateMouseEvent(const MSG &msg) } if (type == QEvent::MouseButtonPress - && qApp->activePopupWidget() != activePopupWidget + && QApplication::activePopupWidget() != activePopupWidget && replayPopupMouseEvent) { // the popup dissappeared. Replay the event QWidget* w = QApplication::widgetAt(gpos.x, gpos.y); @@ -3231,10 +3164,10 @@ bool QETWidget::translateMouseEvent(const MSG &msg) POINT widgetpt = gpos; ScreenToClient(hwndTarget, &widgetpt); LPARAM lParam = MAKELPARAM(widgetpt.x, widgetpt.y); - winPostMessage(hwndTarget, msg.message, msg.wParam, lParam); + PostMessage(hwndTarget, msg.message, msg.wParam, lParam); } } else if (type == QEvent::MouseButtonRelease && button == Qt::RightButton - && qApp->activePopupWidget() == activePopupWidget) { + && QApplication::activePopupWidget() == activePopupWidget) { // popup still alive and received right-button-release #if !defined(QT_NO_CONTEXTMENU) QContextMenuEvent e2(QContextMenuEvent::Mouse, pos, globalPos, @@ -3298,12 +3231,12 @@ bool QETWidget::translateWheelEvent(const MSG &msg) state = translateButtonState(GET_KEYSTATE_WPARAM(msg.wParam), 0, 0); int delta; - if (msg.message == WM_MOUSEWHEEL) + if (msg.message == WM_MOUSEWHEEL || msg.message == WM_MOUSEHWHEEL) delta = (short) HIWORD (msg.wParam); else delta = (int) msg.wParam; - Qt::Orientation orient = (state&Qt::AltModifier + Qt::Orientation orient = (msg.message == WM_MOUSEHWHEEL || state&Qt::AltModifier #if 0 // disabled for now - Trenton's one-wheel mouse makes trouble... // "delta" for usual wheels is +-120. +-240 seems to indicate @@ -3317,6 +3250,13 @@ bool QETWidget::translateWheelEvent(const MSG &msg) #endif ) ? Qt::Horizontal : Qt::Vertical; + // according to the MSDN documentation on WM_MOUSEHWHEEL: + // a positive value indicates that the wheel was rotated to the right; + // a negative value indicates that the wheel was rotated to the left. + // Qt defines this value as the exact opposite, so we have to flip the value! + if (msg.message == WM_MOUSEHWHEEL) + delta = -delta; + QPoint globalPos; globalPos.rx() = (short)LOWORD (msg.lParam); @@ -3337,7 +3277,7 @@ bool QETWidget::translateWheelEvent(const MSG &msg) // send the event to the widget or its ancestors { - QWidget* popup = qApp->activePopupWidget(); + QWidget* popup = QApplication::activePopupWidget(); if (popup && w->window() != popup) popup->close(); #ifndef QT_NO_WHEELEVENT @@ -3353,8 +3293,8 @@ bool QETWidget::translateWheelEvent(const MSG &msg) } // send the event to the widget that has the focus or its ancestors, if different - if (w != qApp->focusWidget() && (w = qApp->focusWidget())) { - QWidget* popup = qApp->activePopupWidget(); + if (w != QApplication::focusWidget() && (w = QApplication::focusWidget())) { + QWidget* popup = QApplication::activePopupWidget(); if (popup && w->window() != popup) popup->close(); #ifndef QT_NO_WHEELEVENT @@ -3407,17 +3347,19 @@ static void tabletInit(UINT wActiveCsr, HCTX hTab) tdd.minTanPressure = int(np.axMin); tdd.maxTanPressure = int(np.axMax); - ptrWTInfo(WTI_DEVICES + lc.lcDevice, DVC_X, &np); - tdd.minX = int(np.axMin); - tdd.maxX = int(np.axMax); + LOGCONTEXT lcMine; - ptrWTInfo(WTI_DEVICES + lc.lcDevice, DVC_Y, &np); - tdd.minY = int(np.axMin); - tdd.maxY = int(np.axMax); + /* get default region */ + ptrWTInfo(WTI_DEFCONTEXT, 0, &lcMine); - ptrWTInfo(WTI_DEVICES + lc.lcDevice, DVC_Z, &np); - tdd.minZ = int(np.axMin); - tdd.maxZ = int(np.axMax); + tdd.minX = 0; + tdd.maxX = int(lcMine.lcInExtX) - int(lcMine.lcInOrgX); + + tdd.minY = 0; + tdd.maxY = int(lcMine.lcInExtY) - int(lcMine.lcInOrgY); + + tdd.minZ = 0; + tdd.maxZ = int(lcMine.lcInExtZ) - int(lcMine.lcInOrgZ); int csr_type, csr_physid; @@ -3527,13 +3469,34 @@ bool QETWidget::translateTabletEvent(const MSG &msg, PACKET *localPacketBuf, } QPoint globalPos(qRound(hiResGlobal.x()), qRound(hiResGlobal.y())); + if (t == QEvent::TabletPress) + { + qt_button_down = QApplication::widgetAt(globalPos); + } + // make sure the tablet event get's sent to the proper widget... - QWidget *w = QApplication::widgetAt(globalPos); + QWidget *w = 0; + if (qt_button_down) w = qt_button_down; // Pass it to the thing that's grabbed it. + else + w = QApplication::widgetAt(globalPos); if (!w) w = this; + + if (t == QEvent::TabletRelease) + { + if (qt_win_ignoreNextMouseReleaseEvent) { + qt_win_ignoreNextMouseReleaseEvent = false; + if (qt_button_down && qt_button_down->internalWinId() == autoCaptureWnd) { + releaseAutoCapture(); + qt_button_down = 0; + } + } + + } + QPoint localPos = w->mapFromGlobal(globalPos); #ifndef QT_NO_TABLETEVENT if (currentTabletPointer.currentDevice == QTabletEvent::Airbrush) { @@ -3591,14 +3554,8 @@ static void initWinTabFunctions() QLibrary library(QLatin1String("wintab32")); if (library.load()) { - QT_WA({ - ptrWTInfo = (PtrWTInfo)library.resolve("WTInfoW"); - ptrWTGet = (PtrWTGet)library.resolve("WTGetW"); - } , { - ptrWTInfo = (PtrWTInfo)library.resolve("WTInfoA"); - ptrWTGet = (PtrWTGet)library.resolve("WTGetA"); - }); - + ptrWTInfo = (PtrWTInfo)library.resolve("WTInfoW"); + ptrWTGet = (PtrWTGet)library.resolve("WTGetW"); ptrWTEnable = (PtrWTEnable)library.resolve("WTEnable"); ptrWTOverlap = (PtrWTEnable)library.resolve("WTOverlap"); ptrWTPacketsGet = (PtrWTPacketsGet)library.resolve("WTPacketsGet"); @@ -3669,7 +3626,7 @@ bool QETWidget::translateConfigEvent(const MSG &msg) WORD b = HIWORD(msg.lParam); QSize oldSize = size(); QSize newSize(a, b); -#ifdef Q_OS_WINCE_WM +#ifdef Q_WS_WINCE_WM if (isFullScreen() && (oldSize.width() == newSize.height()) && (oldSize.height() == newSize.width())) qt_wince_hide_taskbar(internalWinId()); #endif @@ -3681,7 +3638,7 @@ bool QETWidget::translateConfigEvent(const MSG &msg) // Capture SIZE_MINIMIZED without preceding WM_SYSCOMMAND // (like Windows+M) if (msg.wParam == SIZE_MINIMIZED && !isMinimized()) { -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE const QString title = windowIconText(); if (!title.isEmpty()) d_func()->setWindowTitle_helper(title); @@ -3693,7 +3650,7 @@ bool QETWidget::translateConfigEvent(const MSG &msg) hideChildren(true); } } else if (msg.wParam != SIZE_MINIMIZED && isMinimized()) { -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE const QString title = windowTitle(); if (!title.isEmpty()) d_func()->setWindowTitle_helper(title); @@ -3739,7 +3696,7 @@ bool QETWidget::translateConfigEvent(const MSG &msg) QPoint oldPos = geometry().topLeft(); QPoint newCPos(a, b); // Ignore silly Windows move event to wild pos after iconify. -#if !defined(Q_OS_WINCE) +#if !defined(Q_WS_WINCE) if (!IsIconic(internalWinId()) && newCPos != oldPos) { #endif cr.moveTopLeft(newCPos); @@ -3751,7 +3708,7 @@ bool QETWidget::translateConfigEvent(const MSG &msg) QMoveEvent * e = new QMoveEvent(newCPos, oldPos); QApplication::postEvent(this, e); } -#if !defined(Q_OS_WINCE) +#if !defined(Q_WS_WINCE) } #endif } @@ -3772,6 +3729,45 @@ bool QETWidget::translateCloseEvent(const MSG &) return d_func()->close_helper(QWidgetPrivate::CloseWithSpontaneousEvent); } +bool QETWidget::translateGestureEvent(const MSG &, const GESTUREINFO &gi) +{ + 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 (event.gestureType != QNativeGestureEvent::None) + qt_sendSpontaneousEvent(widget, &event); + return true; +} + void QApplication::setCursorFlashTime(int msecs) { @@ -3793,7 +3789,7 @@ int QApplication::cursorFlashTime() void QApplication::setDoubleClickInterval(int ms) { -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE SetDoubleClickTime(ms); #endif QApplicationPrivate::mouse_double_click_time = ms; @@ -3825,11 +3821,7 @@ void QApplication::setWheelScrollLines(int n) #ifdef SPI_SETWHEELSCROLLLINES if (n < 0) n = 0; - QT_WA({ - SystemParametersInfo(SPI_SETWHEELSCROLLLINES, (uint)n, 0, 0); - } , { - SystemParametersInfoA(SPI_SETWHEELSCROLLLINES, (uint)n, 0, 0); - }); + SystemParametersInfo(SPI_SETWHEELSCROLLLINES, (uint)n, 0, 0); #else QApplicationPrivate::wheel_scroll_lines = n; #endif @@ -3839,11 +3831,7 @@ int QApplication::wheelScrollLines() { #ifdef SPI_GETWHEELSCROLLLINES uint i = 3; - QT_WA({ - SystemParametersInfo(SPI_GETWHEELSCROLLLINES, sizeof(uint), &i, 0); - } , { - SystemParametersInfoA(SPI_GETWHEELSCROLLLINES, sizeof(uint), &i, 0); - }); + SystemParametersInfo(SPI_GETWHEELSCROLLLINES, sizeof(uint), &i, 0); if (i > INT_MAX) i = INT_MAX; return i; @@ -3888,8 +3876,7 @@ bool QApplication::isEffectEnabled(Qt::UIEffect effect) if (QColormap::instance().depth() < 16) return false; - if (!effect_override && desktopSettingsAware() - && !(QSysInfo::WindowsVersion == QSysInfo::WV_95 || QSysInfo::WindowsVersion == QSysInfo::WV_NT)) { + if (!effect_override && desktopSettingsAware()) { // we know that they can be used when we are here BOOL enabled = false; UINT api; @@ -3898,33 +3885,22 @@ bool QApplication::isEffectEnabled(Qt::UIEffect effect) api = SPI_GETMENUANIMATION; break; case Qt::UI_FadeMenu: - if (QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based) - return false; api = SPI_GETMENUFADE; break; case Qt::UI_AnimateCombo: api = SPI_GETCOMBOBOXANIMATION; break; case Qt::UI_AnimateTooltip: - if (QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based) - api = SPI_GETMENUANIMATION; - else - api = SPI_GETTOOLTIPANIMATION; + api = SPI_GETTOOLTIPANIMATION; break; case Qt::UI_FadeTooltip: - if (QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based) - return false; api = SPI_GETTOOLTIPFADE; break; default: api = SPI_GETUIEFFECTS; break; } - QT_WA({ - SystemParametersInfo(api, 0, &enabled, 0); - } , { - SystemParametersInfoA(api, 0, &enabled, 0); - }); + SystemParametersInfo(api, 0, &enabled, 0); return enabled; } @@ -3973,4 +3949,90 @@ void QSessionManager::cancel() #endif //QT_NO_SESSIONMANAGER + +PtrRegisterTouchWindow QApplicationPrivate::RegisterTouchWindow = 0; +PtrGetTouchInputInfo QApplicationPrivate::GetTouchInputInfo = 0; +PtrCloseTouchInputHandle QApplicationPrivate::CloseTouchInputHandle = 0; + +void QApplicationPrivate::initializeMultitouch_sys() +{ + QLibrary library(QLatin1String("user32")); + // MinGW (g++ 3.4.5) accepts only C casts. + RegisterTouchWindow = (PtrRegisterTouchWindow)(library.resolve("RegisterTouchWindow")); + GetTouchInputInfo = (PtrGetTouchInputInfo)(library.resolve("GetTouchInputInfo")); + CloseTouchInputHandle = (PtrCloseTouchInputHandle)(library.resolve("CloseTouchInputHandle")); + + touchInputIDToTouchPointID.clear(); +} + +void QApplicationPrivate::cleanupMultitouch_sys() +{ + touchInputIDToTouchPointID.clear(); +} + +bool QApplicationPrivate::translateTouchEvent(const MSG &msg) +{ + QWidget *widgetForHwnd = QWidget::find(msg.hwnd); + if (!widgetForHwnd) + return false; + + QRect screenGeometry = QApplication::desktop()->screenGeometry(widgetForHwnd); + + QList<QTouchEvent::TouchPoint> touchPoints; + + QVector<TOUCHINPUT> winTouchInputs(msg.wParam); + memset(winTouchInputs.data(), 0, sizeof(TOUCHINPUT) * winTouchInputs.count()); + Qt::TouchPointStates allStates = 0; + QApplicationPrivate::GetTouchInputInfo((HANDLE) msg.lParam, msg.wParam, winTouchInputs.data(), sizeof(TOUCHINPUT)); + for (int i = 0; i < winTouchInputs.count(); ++i) { + const TOUCHINPUT &touchInput = winTouchInputs.at(i); + + int touchPointID = touchInputIDToTouchPointID.value(touchInput.dwID, -1); + if (touchPointID == -1) { + touchPointID = touchInputIDToTouchPointID.count(); + touchInputIDToTouchPointID.insert(touchInput.dwID, touchPointID); + } + + QTouchEvent::TouchPoint touchPoint(touchPointID); + + // update state + QPointF screenPos(qreal(touchInput.x) / qreal(100.), qreal(touchInput.y) / qreal(100.)); + QRectF screenRect; + if (touchInput.dwMask & TOUCHINPUTMASKF_CONTACTAREA) + screenRect.setSize(QSizeF(qreal(touchInput.cxContact) / qreal(100.), + qreal(touchInput.cyContact) / qreal(100.))); + screenRect.moveCenter(screenPos); + + Qt::TouchPointStates state; + if (touchInput.dwFlags & TOUCHEVENTF_DOWN) { + state = Qt::TouchPointPressed; + } else if (touchInput.dwFlags & TOUCHEVENTF_UP) { + state = Qt::TouchPointReleased; + } else { + state = (screenPos == touchPoint.screenPos() + ? Qt::TouchPointStationary + : Qt::TouchPointMoved); + } + if (touchInput.dwFlags & TOUCHEVENTF_PRIMARY) + state |= Qt::TouchPointPrimary; + touchPoint.setState(state); + touchPoint.setScreenRect(screenRect); + touchPoint.setNormalizedPos(QPointF(screenPos.x() / screenGeometry.width(), + screenPos.y() / screenGeometry.height())); + + allStates |= state; + + touchPoints.append(touchPoint); + } + QApplicationPrivate::CloseTouchInputHandle((HANDLE) msg.lParam); + + if ((allStates & Qt::TouchPointStateMask) == Qt::TouchPointReleased) { + // all touch points released, forget the ids we've seen, they may not be reused + touchInputIDToTouchPointID.clear(); + } + + translateRawTouchEvent(widgetForHwnd, QTouchEvent::TouchScreen, touchPoints); + return true; +} + QT_END_NAMESPACE diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp index 60748bc..b71ae73 100644 --- a/src/gui/kernel/qapplication_x11.cpp +++ b/src/gui/kernel/qapplication_x11.cpp @@ -78,11 +78,15 @@ #include <private/qcrashhandler_p.h> #include <private/qcolor_p.h> #include <private/qcursor_p.h> +#include <private/qiconloader_p.h> +#include <qgtkstyle.h> #include "qstyle.h" #include "qmetaobject.h" #include "qtimer.h" #include "qlibrary.h" #include <private/qgraphicssystemfactory_p.h> +#include "qguiplatformplugin_p.h" +#include "qkde_p.h" #if !defined (QT_NO_TABLET) extern "C" { @@ -130,6 +134,16 @@ extern "C" { #include <private/qbackingstore_p.h> +#ifdef QT_RX71_MULTITOUCH +# include <qsocketnotifier.h> +# include <linux/input.h> +# include <errno.h> +#endif + +#if _POSIX_VERSION+0 < 200112L && !defined(Q_OS_BSD4) +# define QT_NO_UNSETENV +#endif + QT_BEGIN_NAMESPACE //#define X_NOT_BROKEN @@ -159,6 +173,8 @@ static const char * x11_atomnames = { "WM_TAKE_FOCUS\0" "_NET_WM_PING\0" "_NET_WM_CONTEXT_HELP\0" + "_NET_WM_SYNC_REQUEST\0" + "_NET_WM_SYNC_REQUEST_COUNTER\0" // ICCCM window state "WM_STATE\0" @@ -175,10 +191,12 @@ static const char * x11_atomnames = { "TARGETS\0" "MULTIPLE\0" "TIMESTAMP\0" + "SAVE_TARGETS\0" "CLIP_TEMPORARY\0" "_QT_SELECTION\0" "_QT_CLIPBOARD_SENTINEL\0" "_QT_SELECTION_SENTINEL\0" + "CLIPBOARD_MANAGER\0" "RESOURCE_MANAGER\0" @@ -296,6 +314,10 @@ static const char * x11_atomnames = { // XEMBED "_XEMBED\0" "_XEMBED_INFO\0" + + "Wacom Stylus\0" + "Wacom Cursor\0" + "Wacom Eraser\0" }; Q_GUI_EXPORT QX11Data *qt_x11Data = 0; @@ -506,6 +528,7 @@ static Bool qt_xfixes_scanner(Display*, XEvent *event, XPointer arg) class QETWidget : public QWidget // event translator widget { public: + QWidgetPrivate* d_func() { return QWidget::d_func(); } bool translateMouseEvent(const XEvent *); void translatePaintEvent(const XEvent *); bool translateConfigEvent(const XEvent *); @@ -718,6 +741,44 @@ static int qt_xio_errhandler(Display *) } #endif +#ifndef QT_NO_XSYNC +struct qt_sync_request_event_data +{ + WId window; +}; + +#if defined(Q_C_CALLBACKS) +extern "C" { +#endif + +static Bool qt_sync_request_scanner(Display*, XEvent *event, XPointer arg) +{ + qt_sync_request_event_data *data = + reinterpret_cast<qt_sync_request_event_data*>(arg); + if (event->type == ClientMessage && + event->xany.window == data->window && + event->xclient.message_type == ATOM(WM_PROTOCOLS) && + (Atom)event->xclient.data.l[0] == ATOM(_NET_WM_SYNC_REQUEST)) { + QWidget *w = QWidget::find(event->xany.window); + if (QTLWExtra *tlw = ((QETWidget*)w)->d_func()->maybeTopData()) { + const ulong timestamp = (const ulong) event->xclient.data.l[1]; + if (timestamp > X11->time) + X11->time = timestamp; + if (timestamp == CurrentTime || timestamp > tlw->syncRequestTimestamp) { + tlw->syncRequestTimestamp = timestamp; + tlw->newCounterValueLo = event->xclient.data.l[2]; + tlw->newCounterValueHi = event->xclient.data.l[3]; + } + } + return true; + } + return false; +} + +#if defined(Q_C_CALLBACKS) +} +#endif +#endif // QT_NO_XSYNC static void qt_x11_create_intern_atoms() { @@ -759,26 +820,6 @@ Q_GUI_EXPORT void qt_x11_apply_settings_in_all_apps() } /*! \internal - Gets the current KDE 3 or 4 home path -*/ -QString QApplicationPrivate::kdeHome() -{ - static QString kdeHomePath; - if (kdeHomePath.isEmpty()) { - kdeHomePath = QString::fromLocal8Bit(qgetenv("KDEHOME")); - if (kdeHomePath.isEmpty()) { - int kdeSessionVersion = QString::fromLocal8Bit(qgetenv("KDE_SESSION_VERSION")).toInt(); - QDir homeDir(QDir::homePath()); - QString kdeConfDir(QLatin1String("/.kde")); - if (4 == kdeSessionVersion && homeDir.exists(QLatin1String(".kde4"))) - kdeConfDir = QLatin1String("/.kde4"); - kdeHomePath = QDir::homePath() + kdeConfDir; - } - } - return kdeHomePath; -} - -/*! \internal apply the settings to the application */ bool QApplicationPrivate::x11_apply_settings() @@ -834,30 +875,32 @@ bool QApplicationPrivate::x11_apply_settings() } // ### Fix properly for 4.6 - if (!(QApplicationPrivate::app_style && QApplicationPrivate::app_style->inherits("QGtkStyle"))) { + bool usingGtkSettings = QApplicationPrivate::app_style && QApplicationPrivate::app_style->inherits("QGtkStyle"); + if (!usingGtkSettings) { if (groupCount == QPalette::NColorGroups) QApplicationPrivate::setSystemPalette(pal); } - int kdeSessionVersion = QString::fromLocal8Bit(qgetenv("KDE_SESSION_VERSION")).toInt(); - if (!appFont) { - QFont font(QApplication::font()); - QString fontDescription; - // Override Qt font if KDE4 settings can be used - if (4 == kdeSessionVersion) { - QSettings kdeSettings(kdeHome() + QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat); - fontDescription = kdeSettings.value(QLatin1String("font")).toString(); - if (fontDescription.isEmpty()) { - // KDE stores fonts without quotes - fontDescription = kdeSettings.value(QLatin1String("font")).toStringList().join(QLatin1String(",")); + // ### Fix properly for 4.6 + if (!usingGtkSettings) { + QFont font(QApplication::font()); + QString fontDescription; + // Override Qt font if KDE4 settings can be used + if (X11->desktopVersion == 4) { + QSettings kdeSettings(QKde::kdeHome() + QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat); + fontDescription = kdeSettings.value(QLatin1String("font")).toString(); + if (fontDescription.isEmpty()) { + // KDE stores fonts without quotes + fontDescription = kdeSettings.value(QLatin1String("font")).toStringList().join(QLatin1String(",")); + } + } + if (fontDescription.isEmpty()) + fontDescription = settings.value(QLatin1String("font")).toString(); + if (!fontDescription .isEmpty()) { + font.fromString(fontDescription ); + QApplicationPrivate::setSystemFont(font); } - } - if (fontDescription.isEmpty()) - fontDescription = settings.value(QLatin1String("font")).toString(); - if (!fontDescription .isEmpty()) { - font.fromString(fontDescription ); - QApplicationPrivate::setSystemFont(font); } } @@ -875,29 +918,15 @@ bool QApplicationPrivate::x11_apply_settings() // read new QStyle QString stylename = settings.value(QLatin1String("style")).toString(); - if (stylename.isEmpty() && !QApplicationPrivate::styleOverride && X11->use_xrender) { - QStringList availableStyles = QStyleFactory::keys(); - // Override Qt style if KDE4 settings can be used - if (4 == kdeSessionVersion) { - QSettings kdeSettings(kdeHome() + QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat); - QString kde4Style = kdeSettings.value(QLatin1String("widgetStyle"), - QLatin1String("Oxygen")).toString(); - foreach (const QString &style, availableStyles) { - if (style.toLower() == kde4Style.toLower()) - stylename = kde4Style; - } - // Set QGtkStyle for GNOME - } else if (X11->desktopEnvironment == DE_GNOME) { - QString gtkStyleKey = QString::fromLatin1("GTK+"); - if (availableStyles.contains(gtkStyleKey)) - stylename = gtkStyleKey; - } + + if (stylename.isEmpty() && QApplicationPrivate::styleOverride.isNull() && X11->use_xrender) { + stylename = qt_guiPlatformPlugin()->styleName(); } static QString currentStyleName = stylename; if (QCoreApplication::startingUp()) { - if (!stylename.isEmpty() && !QApplicationPrivate::styleOverride) - QApplicationPrivate::styleOverride = new QString(stylename); + if (!stylename.isEmpty() && QApplicationPrivate::styleOverride.isNull()) + QApplicationPrivate::styleOverride = stylename; } else { if (currentStyleName != stylename) { currentStyleName = stylename; @@ -1047,24 +1076,6 @@ static void qt_set_input_encoding() XFree((char *)data); } -// Reads a KDE color setting -static QColor kdeColor(const QString &key) -{ - QSettings kdeSettings(QApplicationPrivate::kdeHome() + - QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat); - QVariant variant = kdeSettings.value(key); - if (variant.isValid()) { - QStringList values = variant.toStringList(); - if (values.size() == 3) { - int r = values[0].toInt(); - int g = values[1].toInt(); - int b = values[2].toInt(); - return QColor(r, g, b); - } - } - return QColor(); -} - // set font, foreground and background from x11 resources. The // arguments may override the resource settings. static void qt_set_x11_resources(const char* font = 0, const char* fg = 0, @@ -1085,7 +1096,6 @@ static void qt_set_x11_resources(const char* font = 0, const char* fg = 0, if (QApplication::desktopSettingsAware()) { // first, read from settings QApplicationPrivate::x11_apply_settings(); - // the call to QApplication::style() below creates the system // palette, which breaks the logic after the RESOURCE_MANAGER // loop... so I have to save this value to be able to use it later @@ -1231,9 +1241,10 @@ static void qt_set_x11_resources(const char* font = 0, const char* fg = 0, QApplicationPrivate::setSystemFont(fnt); } + // QGtkStyle sets it's own system palette + bool gtkStyle = QApplicationPrivate::app_style && QApplicationPrivate::app_style->inherits("QGtkStyle"); bool kdeColors = (QApplication::desktopSettingsAware() && X11->desktopEnvironment == DE_KDE); - - if (kdeColors || (button || !resBG.isEmpty() || !resFG.isEmpty())) {// set app colors + if (!gtkStyle && (kdeColors || (button || !resBG.isEmpty() || !resFG.isEmpty()))) {// set app colors bool allowX11ColorNames = QColor::allowX11ColorNames(); QColor::setAllowX11ColorNames(true); @@ -1269,41 +1280,6 @@ static void qt_set_x11_resources(const char* font = 0, const char* fg = 0, bright_mode = true; } - if (kdeColors) { - // Setup KDE palette - QColor color; - color = kdeColor(QLatin1String("buttonBackground")); - if (!color.isValid()) - color = kdeColor(QLatin1String("Colors:Button/BackgroundNormal")); - if (color.isValid()) - btn = color; - - color = kdeColor(QLatin1String("background")); - if (!color.isValid()) - color = kdeColor(QLatin1String("Colors:Window/BackgroundNormal")); - if (color.isValid()) - bg = color; - - color = kdeColor(QLatin1String("foreground")); - if (!color.isValid()) - color = kdeColor(QLatin1String("Colors:View/ForegroundNormal")); - if (color.isValid()) { - fg = color; - } - - color = kdeColor(QLatin1String("windowForeground")); - if (!color.isValid()) - color = kdeColor(QLatin1String("Colors:Window/ForegroundNormal")); - if (color.isValid()) - wfg = color; - - color = kdeColor(QLatin1String("windowBackground")); - if (!color.isValid()) - color = kdeColor(QLatin1String("Colors:View/BackgroundNormal")); - if (color.isValid()) - base = color; - } - QPalette pal(fg, btn, btn.lighter(125), btn.darker(130), btn.darker(120), wfg.isValid() ? wfg : fg, Qt::white, base, bg); QColor disabled((fg.red() + btn.red()) / 2, (fg.green() + btn.green())/ 2, @@ -1316,34 +1292,6 @@ static void qt_set_x11_resources(const char* font = 0, const char* fg = 0, highlight = QColor(selectBackground); highlightText = QColor(selectForeground); } - // Use KDE3 or KDE4 color settings if present - if (kdeColors) { - QColor color = kdeColor(QLatin1String("selectBackground")); - if (!color.isValid()) - color = kdeColor(QLatin1String("Colors:Selection/BackgroundNormal")); - if (color.isValid()) - highlight = color; - - color = kdeColor(QLatin1String("selectForeground")); - if (!color.isValid()) - color = kdeColor(QLatin1String("Colors:Selection/ForegroundNormal")); - if (color.isValid()) - highlightText = color; - - color = kdeColor(QLatin1String("alternateBackground")); - if (!color.isValid()) - color = kdeColor(QLatin1String("Colors:View/BackgroundAlternate")); - if (color.isValid()) - pal.setColor(QPalette::AlternateBase, color); - else - pal.setBrush(QPalette::AlternateBase, pal.base().color().darker(110)); - - color = kdeColor(QLatin1String("buttonForeground")); - if (!color.isValid()) - color = kdeColor(QLatin1String("Colors:Button/ForegroundNormal")); - if (color.isValid()) - pal.setColor(QPalette::ButtonText, color); - } if (highlight.isValid() && highlightText.isValid()) { pal.setColor(QPalette::Highlight, highlight); @@ -1366,10 +1314,8 @@ static void qt_set_x11_resources(const char* font = 0, const char* fg = 0, pal.setColor(QPalette::Disabled, QPalette::Highlight, Qt::darkBlue); } - // QGtkStyle sets it's own system palette - if (!(QApplicationPrivate::app_style && QApplicationPrivate::app_style->inherits("QGtkStyle"))) { - QApplicationPrivate::setSystemPalette(pal); - } + pal = qt_guiPlatformPlugin()->palette().resolve(pal); + QApplicationPrivate::setSystemPalette(pal); QColor::setAllowX11ColorNames(allowX11ColorNames); } @@ -1389,6 +1335,8 @@ static void qt_set_x11_resources(const char* font = 0, const char* fg = 0, QApplication::setEffectEnabled(Qt::UI_AnimateToolBox, effects.contains(QLatin1String("animatetoolbox"))); } + + QIconLoader::instance()->updateSystemTheme(); } @@ -1583,6 +1531,7 @@ static PtrWacomConfigOpenDevice ptrWacomConfigOpenDevice = 0; static PtrWacomConfigGetRawParam ptrWacomConfigGetRawParam = 0; static PtrWacomConfigCloseDevice ptrWacomConfigCloseDevice = 0; static PtrWacomConfigTerm ptrWacomConfigTerm = 0; +Q_GLOBAL_STATIC(QByteArray, wacomDeviceName) #endif #endif @@ -1676,6 +1625,7 @@ void qt_init(QApplicationPrivate *priv, int, // MIT-SHM X11->use_mitshm = false; + X11->use_mitshm_pixmaps = false; X11->mitshm_major = 0; X11->sip_serial = 0; @@ -1723,7 +1673,7 @@ void qt_init(QApplicationPrivate *priv, int, X11->pattern_fills[i].screen = -1; #endif - X11->startupId = X11->originalStartupId = 0; + X11->startupId = 0; int argc = priv->argc; char **argv = priv->argv; @@ -1905,10 +1855,20 @@ void qt_init(QApplicationPrivate *priv, int, QX11InfoData *screen = X11->screens + s; screen->ref = 1; // ensures it doesn't get deleted screen->screen = s; - screen->dpiX = (DisplayWidth(X11->display, s) * 254 + DisplayWidthMM(X11->display, s)*5) - / (DisplayWidthMM(X11->display, s)*10); - screen->dpiY = (DisplayHeight(X11->display, s) * 254 + DisplayHeightMM(X11->display, s)*5) - / (DisplayHeightMM(X11->display, s)*10); + + int widthMM = DisplayWidthMM(X11->display, s); + if (widthMM != 0) { + screen->dpiX = (DisplayWidth(X11->display, s) * 254 + widthMM * 5) / (widthMM * 10); + } else { + screen->dpiX = 72; + } + + int heightMM = DisplayHeightMM(X11->display, s); + if (heightMM != 0) { + screen->dpiY = (DisplayHeight(X11->display, s) * 254 + heightMM * 5) / (heightMM * 10); + } else { + screen->dpiY = 72; + } X11->argbVisuals[s] = 0; X11->argbColormaps[s] = 0; @@ -1959,12 +1919,13 @@ 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->red_mask == 0xf800) - && (defaultVisual->green_mask == 0xff00 - || defaultVisual->green_mask == 0x7e0) - && (defaultVisual->blue_mask == 0xff - || defaultVisual->blue_mask == 0x1f)); + X11->use_mitshm = ((defaultVisual->red_mask == 0xff0000 + || defaultVisual->red_mask == 0xf800) + && (defaultVisual->green_mask == 0xff00 + || defaultVisual->green_mask == 0x7e0) + && (defaultVisual->blue_mask == 0xff + || defaultVisual->blue_mask == 0x1f)); + X11->use_mitshm_pixmaps = X11->use_mitshm && mitshm_pixmaps; } } #endif // QT_NO_MITSHM @@ -2084,6 +2045,13 @@ void qt_init(QApplicationPrivate *priv, int, #endif // QT_RUNTIME_XCURSOR #endif // QT_NO_XCURSOR +#ifndef QT_NO_XSYNC + int xsync_evbase, xsync_errbase; + int major, minor; + if (XSyncQueryExtension(X11->display, &xsync_evbase, &xsync_errbase)) + XSyncInitialize(X11->display, &major, &minor); +#endif // QT_NO_XSYNC + #ifndef QT_NO_XINERAMA #ifdef QT_RUNTIME_XINERAMA X11->ptrXineramaQueryExtension = 0; @@ -2245,6 +2213,7 @@ void qt_init(QApplicationPrivate *priv, int, X11->compositingManagerRunning = XGetSelectionOwner(X11->display, ATOM(_NET_WM_CM_S0)); X11->desktopEnvironment = DE_UNKNOWN; + X11->desktopVersion = 0; // See if the current window manager is using the freedesktop.org spec to give its name Window windowManagerWindow = XNone; @@ -2289,8 +2258,13 @@ void qt_init(QApplicationPrivate *priv, int, unsigned long length, after; uchar *data = 0; - if (XGetWindowProperty(X11->display, QX11Info::appRootWindow(), ATOM(DTWM_IS_RUNNING), - 0, 1, False, AnyPropertyType, &type, &format, &length, + QString session = QString::fromLocal8Bit(qgetenv("DESKTOP_SESSION")); + if (session == QLatin1String("kde")) { + X11->desktopEnvironment = DE_KDE; + } else if (session == QLatin1String("gnome") || session == QLatin1String("xfce")) { + X11->desktopEnvironment = DE_GNOME; + } else if (XGetWindowProperty(X11->display, QX11Info::appRootWindow(), ATOM(DTWM_IS_RUNNING), + 0, 1, False, AnyPropertyType, &type, &format, &length, &after, &data) == Success && length) { // DTWM is running, meaning most likely CDE is running... X11->desktopEnvironment = DE_CDE; @@ -2320,6 +2294,15 @@ void qt_init(QApplicationPrivate *priv, int, XFree((char *)data); } + if (X11->desktopEnvironment == DE_KDE) + X11->desktopVersion = QString::fromLocal8Bit(qgetenv("KDE_SESSION_VERSION")).toInt(); + +#if !defined(QT_NO_STYLE_GTK) + if (X11->desktopEnvironment == DE_GNOME) { + static bool menusHaveIcons = QGtkStyle::getGConfBool(QLatin1String("/desktop/gnome/interface/menus_have_icons"), true); + QApplication::setAttribute(Qt::AA_DontShowIconsInMenus, !menusHaveIcons); + } +#endif qt_set_input_encoding(); qt_set_x11_resources(appFont, appFGCol, appBGCol, appBTNCol); @@ -2355,13 +2338,6 @@ void qt_init(QApplicationPrivate *priv, int, XAxisInfoPtr a; XDevice *dev = 0; -#if !defined(Q_OS_IRIX) - // XFree86 divides a stylus and eraser into 2 devices, so we must do for both... - const QString XFREENAMESTYLUS = QLatin1String("stylus"); - const QString XFREENAMEPEN = QLatin1String("pen"); - const QString XFREENAMEERASER = QLatin1String("eraser"); -#endif - if (X11->ptrXListInputDevices) { devices = X11->ptrXListInputDevices(X11->display, &ndev); if (!devices) @@ -2376,18 +2352,19 @@ void qt_init(QApplicationPrivate *priv, int, gotStylus = false; gotEraser = false; - QString devName = QString::fromLocal8Bit(devs->name).toLower(); #if defined(Q_OS_IRIX) + QString devName = QString::fromLocal8Bit(devs->name).toLower(); if (devName == QLatin1String(WACOM_NAME)) { deviceType = QTabletEvent::Stylus; gotStylus = true; } #else - if (devName.startsWith(XFREENAMEPEN) - || devName.startsWith(XFREENAMESTYLUS)) { + if (devs->type == ATOM(XWacomStylus)) { deviceType = QTabletEvent::Stylus; + if (wacomDeviceName()->isEmpty()) + wacomDeviceName()->append(devs->name); gotStylus = true; - } else if (devName.startsWith(XFREENAMEERASER)) { + } else if (devs->type == ATOM(XWacomEraser)) { deviceType = QTabletEvent::XFreeEraser; gotEraser = true; } @@ -2523,10 +2500,15 @@ void qt_init(QApplicationPrivate *priv, int, #endif // QT_NO_TABLET X11->startupId = getenv("DESKTOP_STARTUP_ID"); - X11->originalStartupId = X11->startupId; - static char desktop_startup_id[] = "DESKTOP_STARTUP_ID="; - putenv(desktop_startup_id); - + if (X11->startupId) { +#ifndef QT_NO_UNSETENV + unsetenv("DESKTOP_STARTUP_ID"); +#else + // it's a small memory leak, however we won't crash if Qt is + // unloaded and someones tries to use the envoriment. + putenv(strdup("DESKTOP_STARTUP_ID=")); +#endif + } } else { // read some non-GUI settings when not using the X server... @@ -2580,38 +2562,6 @@ void qt_init(QApplicationPrivate *priv, int, #endif } - - // run-time search for default style -/*! - \internal -*/ -void QApplicationPrivate::x11_initialize_style() -{ - if (QApplicationPrivate::app_style) - return; - - switch(X11->desktopEnvironment) { - case DE_KDE: - if (X11->use_xrender) - QApplicationPrivate::app_style = QStyleFactory::create(QLatin1String("plastique")); - else - QApplicationPrivate::app_style = QStyleFactory::create(QLatin1String("windows")); - break; - case DE_GNOME: - if (X11->use_xrender) - QApplicationPrivate::app_style = QStyleFactory::create(QLatin1String("cleanlooks")); - else - QApplicationPrivate::app_style = QStyleFactory::create(QLatin1String("windows")); - break; - case DE_CDE: - QApplicationPrivate::app_style = QStyleFactory::create(QLatin1String("cde")); - break; - default: - // Don't do anything - break; - } -} - void QApplicationPrivate::initializeWidgetPaletteHash() { } @@ -2640,10 +2590,6 @@ void qt_cleanup() #endif } - // restore original value back. This is also done in QWidgetPrivate::show_sys. - if (X11->originalStartupId) - putenv(X11->originalStartupId); - #ifndef QT_NO_XRENDER for (int i = 0; i < X11->solid_fill_count; ++i) { if (X11->solid_fills[i].picture) @@ -2847,8 +2793,6 @@ void QApplicationPrivate::applyX11SpecificCommandLineArguments(QWidget *main_wid QApplication cursor stack *****************************************************************************/ -extern void qt_x11_enforce_cursor(QWidget * w); - void QApplication::setOverrideCursor(const QCursor &cursor) { qApp->d_func()->cursor_list.prepend(cursor); @@ -2978,7 +2922,7 @@ QWidget *QApplication::topLevelAt(const QPoint &p) void QApplication::syncX() { if (X11->display) - XSync(X11->display, False); // don't discard events + XSync(X11->display, False); // don't discard events } @@ -3116,6 +3060,19 @@ int QApplication::x11ClientMessage(QWidget* w, XEvent* event, bool passive_only) XSendEvent(event->xclient.display, event->xclient.window, False, SubstructureNotifyMask|SubstructureRedirectMask, event); } +#ifndef QT_NO_XSYNC + } else if (a == ATOM(_NET_WM_SYNC_REQUEST)) { + const ulong timestamp = (const ulong) event->xclient.data.l[1]; + if (timestamp > X11->time) + X11->time = timestamp; + if (QTLWExtra *tlw = w->d_func()->maybeTopData()) { + if (timestamp == CurrentTime || timestamp > tlw->syncRequestTimestamp) { + tlw->syncRequestTimestamp = timestamp; + tlw->newCounterValueLo = event->xclient.data.l[2]; + tlw->newCounterValueHi = event->xclient.data.l[3]; + } + } +#endif } } else if (event->xclient.message_type == ATOM(_QT_SCROLL_DONE)) { widget->translateScrollDoneEvent(event); @@ -3146,6 +3103,7 @@ int QApplication::x11ProcessEvent(XEvent* event) { Q_D(QApplication); QScopedLoopLevelCounter loopLevelCounter(d->threadData); + #ifdef ALIEN_DEBUG //qDebug() << "QApplication::x11ProcessEvent:" << event->type; #endif @@ -3351,19 +3309,10 @@ int QApplication::x11ProcessEvent(XEvent* event) QSize oldSize(w->size()); w->data->crect.setWidth(DisplayWidth(X11->display, scr)); w->data->crect.setHeight(DisplayHeight(X11->display, scr)); - QVarLengthArray<QRect> oldSizes(desktop->numScreens()); - for (int i = 0; i < desktop->numScreens(); ++i) - oldSizes[i] = desktop->screenGeometry(i); QResizeEvent e(w->size(), oldSize); QApplication::sendEvent(w, &e); - for (int i = 0; i < qMin(oldSizes.count(), desktop->numScreens()); ++i) { - if (oldSizes[i] != desktop->screenGeometry(i)) - emit desktop->resized(i); - } - for (int i = oldSizes.count(); i < desktop->numScreens(); ++i) - emit desktop->resized(i); // added - for (int i = desktop->numScreens(); i < oldSizes.count(); ++i) - emit desktop->resized(i); // removed + if (w != desktop) + QApplication::sendEvent(desktop, &e); } #endif // QT_NO_XRANDR @@ -3803,6 +3752,12 @@ int QApplication::x11ProcessEvent(XEvent* event) qt_get_net_virtual_roots(); } else if (event->xproperty.atom == ATOM(_NET_WORKAREA)) { qt_desktopwidget_update_workarea(); + + // emit the workAreaResized() signal + QDesktopWidget *desktop = QApplication::desktop(); + int numScreens = desktop->numScreens(); + for (int i = 0; i < numScreens; ++i) + emit desktop->workAreaResized(i); } } else if (widget) { widget->translatePropertyEvent(event); @@ -4139,7 +4094,9 @@ bool QETWidget::translateMouseEvent(const XEvent *event) || ((nextEvent.type == EnterNotify || nextEvent.type == LeaveNotify) && qt_button_down == this) || (nextEvent.type == ClientMessage - && nextEvent.xclient.message_type == ATOM(_QT_SCROLL_DONE))) { + && (nextEvent.xclient.message_type == ATOM(_QT_SCROLL_DONE) || + (nextEvent.xclient.message_type == ATOM(WM_PROTOCOLS) && + (Atom)nextEvent.xclient.data.l[0] == ATOM(_NET_WM_SYNC_REQUEST))))) { qApp->x11ProcessEvent(&nextEvent); continue; } else if (nextEvent.type != MotionNotify || @@ -4409,7 +4366,6 @@ bool QETWidget::translateMouseEvent(const XEvent *event) QMouseEvent e(type, pos, globalPos, button, buttons, modifiers); QApplicationPrivate::sendMouseEvent(widget, &e, alienWidget, this, &qt_button_down, qt_last_mouse_receiver); - if (type == QEvent::MouseButtonPress && button == Qt::RightButton && (openPopupCount == oldOpenPopupCount)) { @@ -4478,8 +4434,7 @@ void fetchWacomToolId(int &deviceType, qint64 &serialId) WACOMCONFIG *config = ptrWacomConfigInit(X11->display, 0); if (config == 0) return; - const char *name = "stylus"; // TODO get this from the X config instead (users may have called it differently) - WACOMDEVICE *device = ptrWacomConfigOpenDevice (config, name); + WACOMDEVICE *device = ptrWacomConfigOpenDevice (config, wacomDeviceName()->constData()); if (device == 0) return; unsigned keys[1]; @@ -4537,6 +4492,53 @@ void fetchWacomToolId(int &deviceType, qint64 &serialId) } #endif +struct qt_tablet_motion_data +{ + bool filterByWidget; + const QWidget *widget; + const QWidget *etWidget; + int tabletMotionType; + bool error; // found a reason to stop searching +}; + +static Bool qt_mouseMotion_scanner(Display *, XEvent *event, XPointer arg) +{ + qt_tablet_motion_data *data = (qt_tablet_motion_data *) arg; + if (data->error) + return false; + + if (event->type == MotionNotify) + return true; + + data->error = event->type != data->tabletMotionType; // we stop compression when another event gets in between. + return false; +} + +static Bool qt_tabletMotion_scanner(Display *, XEvent *event, XPointer arg) +{ + qt_tablet_motion_data *data = (qt_tablet_motion_data *) arg; + if (data->error) + return false; + if (event->type == data->tabletMotionType) { + const XDeviceMotionEvent *const motion = reinterpret_cast<const XDeviceMotionEvent*>(event); + if (data->filterByWidget) { + const QPoint curr(motion->x, motion->y); + const QWidget *w = data->etWidget; + const QWidget *const child = w->childAt(curr); + if (child) { + w = child; + } + if (w == data->widget) + return true; + } else { + return true; + } + } + + data->error = event->type != MotionNotify; // we stop compression when another event gets in between. + return false; +} + bool QETWidget::translateXinputEvent(const XEvent *ev, QTabletDeviceData *tablet) { #if defined (Q_OS_IRIX) @@ -4563,91 +4565,17 @@ bool QETWidget::translateXinputEvent(const XEvent *ev, QTabletDeviceData *tablet qreal rotation = 0; int deviceType = QTabletEvent::NoDevice; int pointerType = QTabletEvent::UnknownPointer; - XEvent xinputMotionEvent; - XEvent mouseMotionEvent; const XDeviceMotionEvent *motion = 0; XDeviceButtonEvent *button = 0; const XProximityNotifyEvent *proximity = 0; QEvent::Type t; Qt::KeyboardModifiers modifiers = 0; - bool reinsertMouseEvent = false; - bool neverFoundMouseEvent = true; - XEvent xinputMotionEventNext; - XEvent mouseMotionEventSave; #if !defined (Q_OS_IRIX) XID device_id; #endif if (ev->type == tablet->xinput_motion) { motion = reinterpret_cast<const XDeviceMotionEvent*>(ev); - for (;;) { - // get the corresponding mouseMotionEvent for motion - if (XCheckTypedWindowEvent(X11->display, internalWinId(), MotionNotify, &mouseMotionEvent)) { - mouseMotionEventSave = mouseMotionEvent; - reinsertMouseEvent = true; - neverFoundMouseEvent = false; - - if (mouseMotionEvent.xmotion.time > motion->time) { - XEvent xinputMotionEventLoop = *ev; - - // xinput event is older than the mouse event --> search for the corresponding xinput event for the given mouse event - while (mouseMotionEvent.xmotion.time > (reinterpret_cast<const XDeviceMotionEvent*>(&xinputMotionEventLoop))->time) { - if (XCheckTypedWindowEvent(X11->display, internalWinId(), tablet->xinput_motion, &xinputMotionEventLoop)) { - xinputMotionEvent = xinputMotionEventLoop; - } - else { - break; - } - } - motion = reinterpret_cast<const XDeviceMotionEvent*>(&xinputMotionEvent); - } - - // get the next xinputMotionEvent, for the next loop run - if (!XCheckTypedWindowEvent(X11->display, internalWinId(), tablet->xinput_motion, &xinputMotionEventNext)) { - XPutBackEvent(X11->display, &mouseMotionEvent); - reinsertMouseEvent = false; - break; - } - - if (mouseMotionEvent.xmotion.time != motion->time) { - // reinsert in order - if (mouseMotionEvent.xmotion.time >= motion->time) { - XPutBackEvent(X11->display, &mouseMotionEvent); - XPutBackEvent(X11->display, &xinputMotionEventNext); - // next entry in queue is xinputMotionEventNext - } - else { - XPutBackEvent(X11->display, &xinputMotionEventNext); - XPutBackEvent(X11->display, &mouseMotionEvent); - // next entry in queue is mouseMotionEvent - } - reinsertMouseEvent = false; - break; - } - } - else { - break; - } - - xinputMotionEvent = xinputMotionEventNext; - motion = (reinterpret_cast<const XDeviceMotionEvent*>(&xinputMotionEvent)); - } - - if (reinsertMouseEvent) { - XPutBackEvent(X11->display, &mouseMotionEventSave); - } - - if (neverFoundMouseEvent) { - XEvent xinputMotionEventLoop; - bool eventFound = false; - // xinput event without mouseMotionEvent --> search the newest xinputMotionEvent - while (XCheckTypedWindowEvent(X11->display, internalWinId(), tablet->xinput_motion, &xinputMotionEventLoop)) { - xinputMotionEvent = xinputMotionEventLoop; - eventFound = true; - } - if (eventFound) motion = reinterpret_cast<const XDeviceMotionEvent*>(&xinputMotionEvent); - } - t = QEvent::TabletMove; global = QPoint(motion->x_root, motion->y_root); curr = QPoint(motion->x, motion->y); @@ -4800,11 +4728,14 @@ bool QETWidget::translateXinputEvent(const XEvent *ev, QTabletDeviceData *tablet } #endif - QWidget *child = w->childAt(curr); - if (child) { - w = child; - curr = w->mapFromGlobal(global); + if (tablet->widgetToGetPress) { + w = tablet->widgetToGetPress; + } else { + QWidget *child = w->childAt(curr); + if (child) + w = child; } + curr = w->mapFromGlobal(global); if (t == QEvent::TabletPress) { tablet->widgetToGetPress = w; @@ -4818,10 +4749,45 @@ bool QETWidget::translateXinputEvent(const XEvent *ev, QTabletDeviceData *tablet deviceType, pointerType, qreal(pressure / qreal(tablet->maxPressure - tablet->minPressure)), xTilt, yTilt, tangentialPressure, rotation, z, modifiers, uid); - if (proximity) + if (proximity) { QApplication::sendSpontaneousEvent(qApp, &e); - else + } else { QApplication::sendSpontaneousEvent(w, &e); + const bool accepted = e.isAccepted(); + if (!accepted && ev->type == tablet->xinput_motion) { + // If the widget does not accept tablet events, we drop the next ones from the event queue + // for this widget so it is not overloaded with the numerous tablet events. + qt_tablet_motion_data tabletMotionData; + tabletMotionData.tabletMotionType = tablet->xinput_motion; + tabletMotionData.widget = w; + tabletMotionData.etWidget = this; + // if nothing is pressed, the events are filtered by position + tabletMotionData.filterByWidget = (tablet->widgetToGetPress == 0); + + bool reinsertMouseEvent = false; + XEvent mouseMotionEvent; + while (true) { + // Find first mouse event since we expect them in pairs inside Qt + tabletMotionData.error =false; + if (XCheckIfEvent(X11->display, &mouseMotionEvent, &qt_mouseMotion_scanner, (XPointer) &tabletMotionData)) { + reinsertMouseEvent = true; + } else { + break; + } + + // Now discard any duplicate tablet events. + tabletMotionData.error = false; + XEvent dummy; + while (XCheckIfEvent(X11->display, &dummy, &qt_tabletMotion_scanner, (XPointer) &tabletMotionData)) { + // just discard the event + } + } + + if (reinsertMouseEvent) { + XPutBackEvent(X11->display, &mouseMotionEvent); + } + } + } return true; } #endif @@ -5018,6 +4984,7 @@ bool QETWidget::translatePropertyEvent(const XEvent *event) return true; } + // // Paint event translation // @@ -5196,6 +5163,14 @@ bool QETWidget::translateConfigEvent(const XEvent *event) otherEvent.xconfigure.border_width; } } +#ifndef QT_NO_XSYNC + qt_sync_request_event_data sync_event; + sync_event.window = internalWinId(); + for (XEvent ev;;) { + if (!XCheckIfEvent(X11->display, &ev, &qt_sync_request_scanner, (XPointer)&sync_event)) + break; + } +#endif // QT_NO_XSYNC } QRect cr (geometry()); @@ -5281,6 +5256,20 @@ bool QETWidget::translateConfigEvent(const XEvent *event) if (d->extra && d->extra->topextra) d->extra->topextra->inTopLevelResize = false; } +#ifndef QT_NO_XSYNC + if (QTLWExtra *tlwExtra = d->maybeTopData()) { + if (tlwExtra->newCounterValueLo != 0 || tlwExtra->newCounterValueHi != 0) { + XSyncValue value; + XSyncIntsToValue(&value, + tlwExtra->newCounterValueLo, + tlwExtra->newCounterValueHi); + + XSyncSetCounter(X11->display, tlwExtra->syncUpdateCounter, value); + tlwExtra->newCounterValueHi = 0; + tlwExtra->newCounterValueLo = 0; + } + } +#endif return true; } @@ -5898,4 +5887,225 @@ void QSessionManager::requestPhase2() #endif // QT_NO_SESSIONMANAGER +#if defined(QT_RX71_MULTITOUCH) + +static inline int testBit(const char *array, int bit) +{ + return (array[bit/8] & (1<<(bit%8))); +} + +static int openRX71Device(const QByteArray &deviceName) +{ + int fd = open(deviceName, O_RDONLY | O_NONBLOCK); + if (fd == -1) { + fd = -errno; + return fd; + } + + // fetch the event type mask and check that the device reports absolute coordinates + char eventTypeMask[(EV_MAX + sizeof(char) - 1) * sizeof(char) + 1]; + memset(eventTypeMask, 0, sizeof(eventTypeMask)); + if (ioctl(fd, EVIOCGBIT(0, sizeof(eventTypeMask)), eventTypeMask) < 0) { + close(fd); + return -1; + } + if (!testBit(eventTypeMask, EV_ABS)) { + close(fd); + return -1; + } + + // make sure that we can get the absolute X and Y positions from the device + char absMask[(ABS_MAX + sizeof(char) - 1) * sizeof(char) + 1]; + memset(absMask, 0, sizeof(absMask)); + if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absMask)), absMask) < 0) { + close(fd); + return -1; + } + if (!testBit(absMask, ABS_X) || !testBit(absMask, ABS_Y)) { + close(fd); + return -1; + } + + return fd; +} + +void QApplicationPrivate::initializeMultitouch_sys() +{ + Q_Q(QApplication); + + QByteArray deviceName = QByteArray("/dev/input/event"); + int currentDeviceNumber = 0; + for (;;) { + int fd = openRX71Device(QByteArray(deviceName + QByteArray::number(currentDeviceNumber++))); + if (fd == -ENOENT) { + // no more devices + break; + } + if (fd < 0) { + // not a touch device + continue; + } + + struct input_absinfo abs_x, abs_y, abs_z; + ioctl(fd, EVIOCGABS(ABS_X), &abs_x); + ioctl(fd, EVIOCGABS(ABS_Y), &abs_y); + ioctl(fd, EVIOCGABS(ABS_Z), &abs_z); + + int deviceNumber = allRX71TouchPoints.count(); + + QSocketNotifier *socketNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, q); + QObject::connect(socketNotifier, SIGNAL(activated(int)), q, SLOT(_q_readRX71MultiTouchEvents())); + + RX71TouchPointState touchPointState = { + socketNotifier, + QTouchEvent::TouchPoint(deviceNumber), + + abs_x.minimum, abs_x.maximum, q->desktop()->screenGeometry().width(), + abs_y.minimum, abs_y.maximum, q->desktop()->screenGeometry().height(), + abs_z.minimum, abs_z.maximum + }; + allRX71TouchPoints.append(touchPointState); + } + + hasRX71MultiTouch = allRX71TouchPoints.count() > 1; + if (!hasRX71MultiTouch) { + for (int i = 0; i < allRX71TouchPoints.count(); ++i) { + QSocketNotifier *socketNotifier = allRX71TouchPoints.at(i).socketNotifier; + close(socketNotifier->socket()); + delete socketNotifier; + } + allRX71TouchPoints.clear(); + } +} + +void QApplicationPrivate::cleanupMultitouch_sys() +{ + hasRX71MultiTouch = false; + for (int i = 0; i < allRX71TouchPoints.count(); ++i) { + QSocketNotifier *socketNotifier = allRX71TouchPoints.at(i).socketNotifier; + close(socketNotifier->socket()); + delete socketNotifier; + } + allRX71TouchPoints.clear(); +} + +bool QApplicationPrivate::readRX71MultiTouchEvents(int deviceNumber) +{ + RX71TouchPointState &touchPointState = allRX71TouchPoints[deviceNumber]; + QSocketNotifier *socketNotifier = touchPointState.socketNotifier; + int fd = socketNotifier->socket(); + + QTouchEvent::TouchPoint &touchPoint = touchPointState.touchPoint; + + bool down = touchPoint.state() != Qt::TouchPointReleased; + if (down) + touchPoint.setState(Qt::TouchPointStationary); + + bool changed = false; + for (;;) { + struct input_event inputEvent; + int bytesRead = read(fd, &inputEvent, sizeof(inputEvent)); + if (bytesRead <= 0) + break; + if (bytesRead != sizeof(inputEvent)) { + qWarning("Qt: INTERNAL ERROR: short read in readRX71MultiTouchEvents()"); + return false; + } + + switch (inputEvent.type) { + case EV_SYN: + changed = true; + switch (touchPoint.state()) { + case Qt::TouchPointPressed: + case Qt::TouchPointReleased: + // make sure we don't compress pressed and releases with any other events + return changed; + default: + break; + } + continue; + case EV_KEY: + case EV_ABS: + break; + default: + qWarning("Qt: WARNING: unknown event type %d on multitouch device", inputEvent.type); + continue; + } + + QPointF screenPos = touchPoint.screenPos(); + switch (inputEvent.code) { + case BTN_TOUCH: + if (!down && inputEvent.value != 0) + touchPoint.setState(Qt::TouchPointPressed); + else if (down && inputEvent.value == 0) + touchPoint.setState(Qt::TouchPointReleased); + break; + case ABS_TOOL_WIDTH: + case ABS_VOLUME: + case ABS_PRESSURE: + // ignore for now + break; + case ABS_X: + { + qreal newValue = ((qreal(inputEvent.value - touchPointState.minX) + / qreal(touchPointState.maxX - touchPointState.minX)) + * touchPointState.scaleX); + screenPos.rx() = newValue; + touchPoint.setScreenPos(screenPos); + break; + } + case ABS_Y: + { + qreal newValue = ((qreal(inputEvent.value - touchPointState.minY) + / qreal(touchPointState.maxY - touchPointState.minY)) + * touchPointState.scaleY); + screenPos.ry() = newValue; + touchPoint.setScreenPos(screenPos); + break; + } + case ABS_Z: + { + // map Z (signal strength) to pressure for now + qreal newValue = (qreal(inputEvent.value - touchPointState.minZ) + / qreal(touchPointState.maxZ - touchPointState.minZ)); + touchPoint.setPressure(newValue); + break; + } + default: + qWarning("Qt: WARNING: unknown event code %d on multitouch device", inputEvent.code); + continue; + } + } + + if (down && touchPoint.state() != Qt::TouchPointReleased) + touchPoint.setState(changed ? Qt::TouchPointMoved : Qt::TouchPointStationary); + + return changed; +} + +void QApplicationPrivate::_q_readRX71MultiTouchEvents() +{ + // read touch events from all devices + bool changed = false; + for (int i = 0; i < allRX71TouchPoints.count(); ++i) + changed = readRX71MultiTouchEvents(i) || changed; + if (!changed) + return; + + QList<QTouchEvent::TouchPoint> touchPoints; + for (int i = 0; i < allRX71TouchPoints.count(); ++i) + touchPoints.append(allRX71TouchPoints.at(i).touchPoint); + + translateRawTouchEvent(0, QTouchEvent::TouchScreen, touchPoints); +} + +#else // !QT_RX71_MULTITOUCH + +void QApplicationPrivate::initializeMultitouch_sys() +{ } +void QApplicationPrivate::cleanupMultitouch_sys() +{ } + +#endif // QT_RX71_MULTITOUCH + QT_END_NAMESPACE diff --git a/src/gui/kernel/qboxlayout.cpp b/src/gui/kernel/qboxlayout.cpp index 2bbbece..d965933 100644 --- a/src/gui/kernel/qboxlayout.cpp +++ b/src/gui/kernel/qboxlayout.cpp @@ -452,7 +452,6 @@ void QBoxLayoutPrivate::calcHfw(int w) vertically. \ingroup geomanagement - \ingroup appearance QBoxLayout takes the space it gets (from its parent layout or from the parentWidget()), divides it up into a row of boxes, and makes @@ -527,7 +526,7 @@ void QBoxLayoutPrivate::calcHfw(int w) You will almost always want to use QVBoxLayout and QHBoxLayout rather than QBoxLayout because of their convenient constructors. - \sa QGridLayout, QStackedLayout, {Layout Classes} + \sa QGridLayout, QStackedLayout, {Layout Management} */ /*! @@ -925,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(); } @@ -1027,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(); } @@ -1271,8 +1289,6 @@ QBoxLayout::Direction QBoxLayout::direction() const \brief The QHBoxLayout class lines up widgets horizontally. \ingroup geomanagement - \ingroup appearance - \mainclass This class is used to construct horizontal box layout objects. See QBoxLayout for details. @@ -1295,7 +1311,7 @@ QBoxLayout::Direction QBoxLayout::direction() const \image qhboxlayout-with-5-children.png Horizontal box layout with five child widgets - \sa QVBoxLayout, QGridLayout, QStackedLayout, {Layout Classes}, {Basic Layouts Example} + \sa QVBoxLayout, QGridLayout, QStackedLayout, {Layout Management}, {Basic Layouts Example} */ @@ -1389,8 +1405,6 @@ QHBoxLayout::~QHBoxLayout() \brief The QVBoxLayout class lines up widgets vertically. \ingroup geomanagement - \ingroup appearance - \mainclass This class is used to construct vertical box layout objects. See QBoxLayout for details. @@ -1413,7 +1427,7 @@ QHBoxLayout::~QHBoxLayout() \image qvboxlayout-with-5-children.png Horizontal box layout with five child widgets - \sa QHBoxLayout, QGridLayout, QStackedLayout, {Layout Classes}, {Basic Layouts Example} + \sa QHBoxLayout, QGridLayout, QStackedLayout, {Layout Management}, {Basic Layouts Example} */ /*! diff --git a/src/gui/kernel/qclipboard.cpp b/src/gui/kernel/qclipboard.cpp index 6d4d99c..e43f8b5 100644 --- a/src/gui/kernel/qclipboard.cpp +++ b/src/gui/kernel/qclipboard.cpp @@ -50,6 +50,7 @@ #include "qvariant.h" #include "qbuffer.h" #include "qimage.h" +#include "qtextcodec.h" QT_BEGIN_NAMESPACE @@ -57,10 +58,6 @@ QT_BEGIN_NAMESPACE \class QClipboard \brief The QClipboard class provides access to the window system clipboard. - \ingroup io - \ingroup environment - \mainclass - The clipboard offers a simple mechanism to copy and paste data between applications. @@ -276,11 +273,12 @@ QClipboard::~QClipboard() */ QString QClipboard::text(QString &subtype, Mode mode) const { - const QMimeData *data = mimeData(mode); + const QMimeData *const data = mimeData(mode); if (!data) return QString(); + + const QStringList formats = data->formats(); if (subtype.isEmpty()) { - QStringList formats = data->formats(); if (formats.contains(QLatin1String("text/plain"))) subtype = QLatin1String("plain"); else { @@ -289,13 +287,25 @@ QString QClipboard::text(QString &subtype, Mode mode) const subtype = formats.at(i).mid(5); break; } + if (subtype.isEmpty()) + return QString(); } - } - if (subtype.isEmpty()) + } else if (!formats.contains(QLatin1String("text/") + subtype)) { return QString(); - if (subtype == QLatin1String("plain")) - return data->text(); - return QString::fromUtf8(data->data(QLatin1String("text/") + subtype)); + } + + const QByteArray rawData = data->data(QLatin1String("text/") + subtype); + +#ifndef QT_NO_TEXTCODEC + QTextCodec* codec = QTextCodec::codecForMib(106); // utf-8 is default + if (subtype == QLatin1String("html")) + codec = QTextCodec::codecForHtml(rawData, codec); + else + codec = QTextCodec::codecForUtfText(rawData, codec); + return codec->toUnicode(rawData); +#else //QT_NO_TEXTCODEC + return rawData; +#endif //QT_NO_TEXTCODEC } /*! diff --git a/src/gui/kernel/qclipboard_mac.cpp b/src/gui/kernel/qclipboard_mac.cpp index 873b226..8892269 100644 --- a/src/gui/kernel/qclipboard_mac.cpp +++ b/src/gui/kernel/qclipboard_mac.cpp @@ -50,6 +50,7 @@ #include "qurl.h" #include <stdlib.h> #include <string.h> +#include "qt_cocoa_helpers_mac_p.h" QT_BEGIN_NAMESPACE @@ -525,8 +526,17 @@ QMacPasteboard::retrieveData(const QString &format, QVariant::Type) const QString c_flavor = c->flavorFor(format); if(!c_flavor.isEmpty()) { // Handle text/plain a little differently. Try handling Unicode first. - if((c_flavor == QLatin1String("com.apple.traditional-mac-plain-text") || c_flavor == QLatin1String("public.utf8-plain-text")) && - hasFlavor(QLatin1String("public.utf16-plain-text"))) + bool checkForUtf16 = (c_flavor == QLatin1String("com.apple.traditional-mac-plain-text") + || c_flavor == QLatin1String("public.utf8-plain-text")); + if (checkForUtf16 || c_flavor == QLatin1String("public.utf16-plain-text")) { + // Try to get the NSStringPboardType from NSPasteboard, newlines are mapped + // correctly (as '\n') in this data. The 'public.utf16-plain-text' type + // usually maps newlines to '\r' instead. + QString str = qt_mac_get_pasteboardString(paste); + if (!str.isEmpty()) + return str; + } + if (checkForUtf16 && hasFlavor(QLatin1String("public.utf16-plain-text"))) c_flavor = QLatin1String("public.utf16-plain-text"); QVariant ret; diff --git a/src/gui/kernel/qclipboard_s60.cpp b/src/gui/kernel/qclipboard_s60.cpp new file mode 100644 index 0000000..de13a51 --- /dev/null +++ b/src/gui/kernel/qclipboard_s60.cpp @@ -0,0 +1,266 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $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/qclipboard_win.cpp b/src/gui/kernel/qclipboard_win.cpp index eecbdeb..0157052 100644 --- a/src/gui/kernel/qclipboard_win.cpp +++ b/src/gui/kernel/qclipboard_win.cpp @@ -51,6 +51,7 @@ #include "qmime.h" #include "qt_windows.h" #include "qdnd_p.h" +#include <private/qwidget_p.h> QT_BEGIN_NAMESPACE @@ -140,6 +141,9 @@ public: clipBoardViewer = new QWidget(); clipBoardViewer->createWinId(); clipBoardViewer->setObjectName(QLatin1String("internal clipboard owner")); + // We dont need this internal widget to appear in QApplication::topLevelWidgets() + if (QWidgetPrivate::allWidgets) + QWidgetPrivate::allWidgets->remove(clipBoardViewer); } ~QClipboardData() @@ -200,7 +204,7 @@ HRESULT QtCeGetClipboard(IDataObject** obj) if (clipData == 0) { clipData = GetClipboardData(CF_UNICODETEXT); if (clipData != 0) - clipText = QString::fromUtf16((unsigned short *)clipData); + clipText = QString::fromWCharArray((wchar_t *)clipData); } else { clipText = QString::fromLatin1((const char*)clipData); } @@ -325,13 +329,7 @@ bool QClipboard::event(QEvent *e) } if (propagate && d->nextClipboardViewer) { - QT_WA({ - SendMessage(d->nextClipboardViewer, m->message, - m->wParam, m->lParam); - } , { - SendMessageA(d->nextClipboardViewer, m->message, - m->wParam, m->lParam); - }); + SendMessage(d->nextClipboardViewer, m->message, m->wParam, m->lParam); } return true; diff --git a/src/gui/kernel/qclipboard_x11.cpp b/src/gui/kernel/qclipboard_x11.cpp index afdcf62..22d7c9e 100644 --- a/src/gui/kernel/qclipboard_x11.cpp +++ b/src/gui/kernel/qclipboard_x11.cpp @@ -78,6 +78,7 @@ #include "qimagewriter.h" #include "qvariant.h" #include "qdnd_p.h" +#include <private/qwidget_p.h> #ifndef QT_NO_XFIXES #include <X11/extensions/Xfixes.h> @@ -131,6 +132,11 @@ void setupOwner() requestor = new QWidget(0); requestor->createWinId(); requestor->setObjectName(QLatin1String("internal clipboard requestor")); + // We dont need this internal widgets to appear in QApplication::topLevelWidgets() + if (QWidgetPrivate::allWidgets) { + QWidgetPrivate::allWidgets->remove(owner); + QWidgetPrivate::allWidgets->remove(requestor); + } qAddPostRoutine(cleanup); } @@ -769,6 +775,9 @@ QByteArray QX11Data::clipboardReadIncrementalProperty(Window win, Atom property, delete requestor; requestor = new QWidget(0); requestor->setObjectName(QLatin1String("internal clipboard requestor")); + // We dont need this internal widget to appear in QApplication::topLevelWidgets() + if (QWidgetPrivate::allWidgets) + QWidgetPrivate::allWidgets->remove(requestor); return QByteArray(); } @@ -787,6 +796,7 @@ static Atom send_targets_selection(QClipboardData *d, Window window, Atom proper types.append(ATOM(TARGETS)); types.append(ATOM(MULTIPLE)); types.append(ATOM(TIMESTAMP)); + types.append(ATOM(SAVE_TARGETS)); XChangeProperty(X11->display, window, property, XA_ATOM, 32, PropModeReplace, (uchar *) types.data(), types.size()); @@ -800,7 +810,7 @@ static Atom send_selection(QClipboardData *d, Atom target, Window window, Atom p QByteArray data; QByteArray fmt = X11->xdndAtomToString(target); - if (fmt.isEmpty() || !QInternalMimeData::hasFormatHelper(QString::fromAscii(fmt), d->source())) { // Not a MIME type we have + if (fmt.isEmpty()) { // Not a MIME type we have DEBUG("QClipboard: send_selection(): converting to type '%s' is not supported", fmt.data()); return XNone; } @@ -911,8 +921,31 @@ bool QClipboard::event(QEvent *e) XEvent *xevent = (XEvent *)(((QClipboardEvent *)e)->data()); Display *dpy = X11->display; - if (!xevent) + if (!xevent) { + // That means application exits and we need to give clipboard + // content to the clipboard manager. + // First we check if there is a clipboard manager. + if (XGetSelectionOwner(X11->display, ATOM(CLIPBOARD_MANAGER)) == XNone + || !owner) + return true; + + Window ownerId = owner->internalWinId(); + Q_ASSERT(ownerId); + // we delete the property so the manager saves all TARGETS. + XDeleteProperty(X11->display, ownerId, ATOM(_QT_SELECTION)); + XConvertSelection(X11->display, ATOM(CLIPBOARD_MANAGER), ATOM(SAVE_TARGETS), + ATOM(_QT_SELECTION), ownerId, X11->time); + XSync(dpy, false); + + XEvent event; + // waiting until the clipboard manager fetches the content. + if (!X11->clipboardWaitForEvent(ownerId, SelectionNotify, &event, 10000)) { + qWarning("QClipboard: Unable to receive an event from the " + "clipboard manager in a reasonable time"); + } + return true; + } switch (xevent->type) { diff --git a/src/gui/kernel/qcocoaapplicationdelegate_mac.mm b/src/gui/kernel/qcocoaapplicationdelegate_mac.mm index 94897ac..d103cbd 100644 --- a/src/gui/kernel/qcocoaapplicationdelegate_mac.mm +++ b/src/gui/kernel/qcocoaapplicationdelegate_mac.mm @@ -194,11 +194,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/qcocoapanel_mac.mm b/src/gui/kernel/qcocoapanel_mac.mm index 05a540c..a26d775 100644 --- a/src/gui/kernel/qcocoapanel_mac.mm +++ b/src/gui/kernel/qcocoapanel_mac.mm @@ -85,6 +85,12 @@ QT_USE_NAMESPACE last resort (i.e., this is code that can potentially be removed). */ +- (void)toggleToolbarShown:(id)sender +{ + macSendToolbarChangeEvent([self QT_MANGLE_NAMESPACE(qt_qwidget)]); + [super toggleToolbarShown:sender]; +} + - (void)keyDown:(NSEvent *)theEvent { bool keyOK = qt_dispatchKeyEvent(theEvent, [self QT_MANGLE_NAMESPACE(qt_qwidget)]); diff --git a/src/gui/kernel/qcocoaview_mac.mm b/src/gui/kernel/qcocoaview_mac.mm index 286eb31..a16d1f8 100644 --- a/src/gui/kernel/qcocoaview_mac.mm +++ b/src/gui/kernel/qcocoaview_mac.mm @@ -49,6 +49,9 @@ #include <private/qt_cocoa_helpers_mac_p.h> #include <private/qdnd_p.h> #include <private/qmacinputcontext_p.h> +#include <private/qmultitouch_mac_p.h> +#include <private/qevent_p.h> +#include <private/qbackingstore_p.h> #include <qscrollarea.h> #include <qhash.h> @@ -61,6 +64,11 @@ #include <qdebug.h> +@interface NSEvent (DeviceDelta) + - (CGFloat)deviceDeltaX; + - (CGFloat)deviceDeltaY; + - (CGFloat)deviceDeltaZ; +@end QT_BEGIN_NAMESPACE @@ -100,7 +108,7 @@ static dndenum_mapper dnd_enums[] = { { NSDragOperationCopy, Qt::CopyAction, true }, { NSDragOperationGeneric, Qt::CopyAction, false }, { NSDragOperationEvery, Qt::ActionMask, false }, - { NSDragOperationNone, Qt::IgnoreAction, false } + { NSDragOperationNone, Qt::IgnoreAction, false } }; static NSDragOperation qt_mac_mapDropAction(Qt::DropAction action) @@ -196,6 +204,7 @@ extern "C" { if (self) { [self finishInitWithQWidget:widget widgetPrivate:widgetprivate]; } + composingText = new QString(); composing = false; sendKeyEvents = true; currentCustomTypes = 0; @@ -224,14 +233,14 @@ extern "C" { currentCustomTypes = new QStringList(); *currentCustomTypes = customTypes; const NSString* mimeTypeGeneric = @"com.trolltech.qt.MimeTypeName"; - NSMutableArray *supportedTypes = [NSMutableArray arrayWithObjects:NSColorPboardType, - NSFilenamesPboardType, NSStringPboardType, - NSFilenamesPboardType, NSPostScriptPboardType, NSTIFFPboardType, - NSRTFPboardType, NSTabularTextPboardType, NSFontPboardType, - NSRulerPboardType, NSFileContentsPboardType, NSColorPboardType, - NSRTFDPboardType, NSHTMLPboardType, NSPICTPboardType, + NSMutableArray *supportedTypes = [NSMutableArray arrayWithObjects:NSColorPboardType, + NSFilenamesPboardType, NSStringPboardType, + NSFilenamesPboardType, NSPostScriptPboardType, NSTIFFPboardType, + NSRTFPboardType, NSTabularTextPboardType, NSFontPboardType, + NSRulerPboardType, NSFileContentsPboardType, NSColorPboardType, + NSRTFDPboardType, NSHTMLPboardType, NSPICTPboardType, NSURLPboardType, NSPDFPboardType, NSVCardPboardType, - NSFilesPromisePboardType, NSInkTextPboardType, + NSFilesPromisePboardType, NSInkTextPboardType, NSMultipleTextSelectionPboardType, mimeTypeGeneric, nil]; // Add custom types supported by the application. for (int i = 0; i < customTypes.size(); i++) { @@ -276,16 +285,16 @@ extern "C" { dropData = 0; } } - -- (void)addDropData:(id <NSDraggingInfo>)sender + +- (void)addDropData:(id <NSDraggingInfo>)sender { [self removeDropData]; - CFStringRef dropPasteboard = (CFStringRef) [[sender draggingPasteboard] name]; + CFStringRef dropPasteboard = (CFStringRef) [[sender draggingPasteboard] name]; dropData = new QCocoaDropData(dropPasteboard); -} +} -- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender -{ +- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender +{ if (qwidget->testAttribute(Qt::WA_DropSiteRegistered) == false) return NSDragOperationNone; NSPoint windowPoint = [sender draggingLocation]; @@ -303,7 +312,7 @@ extern "C" { NSPoint globalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:windowPoint]; NSPoint localPoint = [self convertPoint:windowPoint fromView:nil]; QPoint posDrag(localPoint.x, localPoint.y); - NSDragOperation nsActions = [sender draggingSourceOperationMask]; + NSDragOperation nsActions = [sender draggingSourceOperationMask]; Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations(nsActions); QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastOperation) = nsActions; Qt::KeyboardModifiers modifiers = Qt::NoModifier; @@ -332,8 +341,8 @@ extern "C" { qDMEvent.accept(); // accept by default, since enter event was accepted. QApplication::sendEvent(qwidget, &qDMEvent); if (!qDMEvent.isAccepted() || qDMEvent.dropAction() == Qt::IgnoreAction) { - // since we accepted the drag enter event, the widget expects - // future drage move events. + // since we accepted the drag enter event, the widget expects + // future drage move events. // ### check if we need to treat this like the drag enter event. nsActions = QT_PREPEND_NAMESPACE(qt_mac_mapDropAction)(qDEEvent.dropAction()); } else { @@ -341,7 +350,7 @@ extern "C" { } QT_PREPEND_NAMESPACE(qt_mac_copy_answer_rect)(qDMEvent); return nsActions; - } + } } - (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender @@ -369,7 +378,7 @@ extern "C" { if (qt_mac_mouse_inside_answer_rect(posDrag) && QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastOperation) == nsActions) return QT_PREPEND_NAMESPACE(qt_mac_mapDropActions)(QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastAction)); - // send drag move event to the widget + // send drag move event to the widget QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastOperation) = nsActions; Qt::DropActions qtAllowed = QT_PREPEND_NAMESPACE(qt_mac_mapNSDragOperations)(nsActions); Qt::KeyboardModifiers modifiers = Qt::NoModifier; @@ -432,7 +441,7 @@ extern "C" { NSPoint localPoint = [self convertPoint:windowPoint fromView:nil]; QPoint posDrop(localPoint.x, localPoint.y); - NSDragOperation nsActions = [sender draggingSourceOperationMask]; + NSDragOperation nsActions = [sender draggingSourceOperationMask]; Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations(nsActions); QMimeData *mimeData = dropData; if (QDragManager::self()->source()) @@ -453,6 +462,7 @@ extern "C" { - (void)dealloc { + delete composingText; [[NSNotificationCenter defaultCenter] removeObserver:self]; delete currentCustomTypes; [self unregisterDraggedTypes]; @@ -494,6 +504,12 @@ extern "C" { - (void)drawRect:(NSRect)aRect { + if (QApplicationPrivate::graphicsSystem() != 0) { + if (QWidgetBackingStore *bs = qwidgetprivate->maybeBackingStore()) + bs->markDirty(qwidget->rect(), qwidget); + qwidgetprivate->syncBackingStore(qwidget->rect()); + return; + } CGContextRef cg = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; qwidgetprivate->hd = cg; CGContextSaveGState(cg); @@ -547,15 +563,7 @@ extern "C" { qwidget->objectName().local8Bit().data()); #endif QPainter p(qwidget); - QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea *>(qwidget->parent()); - QPoint scrollAreaOffset; - if (scrollArea && scrollArea->viewport() == qwidget) { - QAbstractScrollAreaPrivate *priv - = static_cast<QAbstractScrollAreaPrivate *>(qt_widget_private(scrollArea)); - scrollAreaOffset = priv->contentsOffset(); - p.translate(-scrollAreaOffset); - } - qwidgetprivate->paintBackground(&p, qrgn, scrollAreaOffset, + qwidgetprivate->paintBackground(&p, qrgn, qwidget->isWindow() ? QWidgetPrivate::DrawAsRoot : 0); p.end(); } @@ -566,11 +574,6 @@ extern "C" { qt_sendSpontaneousEvent(qwidget, &e); if (!redirectionOffset.isNull()) QPainter::restoreRedirected(qwidget); -#ifdef QT_RASTER_PAINTENGINE - if(engine && engine->type() == QPaintEngine::Raster) - static_cast<QRasterPaintEngine*>(engine)->flush(qwidget, - qrgn.boundingRect().topLeft()); -#endif if (engine) engine->setSystemClip(QRegion()); qwidget->setAttribute(Qt::WA_WState_InPaintEvent, false); @@ -641,7 +644,7 @@ extern "C" { QHoverEvent he(QEvent::HoverEnter, QPoint(viewPoint.x, viewPoint.y), QPoint(-1, -1)); QApplicationPrivate::instance()->notify_helper(qwidget, &he); } - } + } } - (void)mouseExited:(NSEvent *)event @@ -650,7 +653,7 @@ extern "C" { NSPoint globalPoint = [[event window] convertBaseToScreen:[event locationInWindow]]; if (!qAppInstance()->activeModalWidget() || QApplicationPrivate::tryModalHelper(qwidget, 0)) { QApplication::sendEvent(qwidget, &leaveEvent); - + // ### Think about if it is necessary to update the cursor, should only be for a few cases. qt_mac_update_cursor_at_global_pos(flipPoint(globalPoint).toPoint()); if (qwidget->testAttribute(Qt::WA_Hover) @@ -675,14 +678,22 @@ extern "C" { - (void)mouseMoved:(NSEvent *)theEvent { - qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseMove, Qt::NoButton); + // We always enable mouse tracking for all QCocoaView-s. In cases where we have + // child views, we will receive mouseMoved for both parent & the child (if + // mouse is over the child). We need to ignore the parent mouseMoved in such + // cases. + NSPoint windowPoint = [theEvent locationInWindow]; + NSView *candidateView = [[[self window] contentView] hitTest:windowPoint]; + if (candidateView && candidateView == self) { + qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseMove, Qt::NoButton); + } } - (void)mouseDown:(NSEvent *)theEvent { qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseButtonPress, Qt::LeftButton); // Don't call super here. This prevents us from getting the mouseUp event, - // which we need to send even if the mouseDown event was not accepted. + // which we need to send even if the mouseDown event was not accepted. // (this is standard Qt behavior.) } @@ -696,7 +707,7 @@ extern "C" { } - (void)rightMouseDown:(NSEvent *)theEvent -{ +{ bool mouseOK = qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseButtonPress, Qt::RightButton); if (!mouseOK) @@ -734,7 +745,7 @@ extern "C" { { qMacDnDParams()->view = self; qMacDnDParams()->theEvent = theEvent; - bool mouseOK = qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseMove, Qt::LeftButton); + bool mouseOK = qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseMove, Qt::NoButton); if (!mouseOK) [super mouseDragged:theEvent]; @@ -744,7 +755,7 @@ extern "C" { { qMacDnDParams()->view = self; qMacDnDParams()->theEvent = theEvent; - bool mouseOK = qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseMove, Qt::RightButton); + bool mouseOK = qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseMove, Qt::NoButton); if (!mouseOK) [super rightMouseDragged:theEvent]; @@ -754,8 +765,7 @@ extern "C" { { qMacDnDParams()->view = self; qMacDnDParams()->theEvent = theEvent; - Qt::MouseButton mouseButton = cocoaButton2QtButton([theEvent buttonNumber]); - bool mouseOK = qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseMove, mouseButton); + bool mouseOK = qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseMove, Qt::NoButton); if (!mouseOK) [super otherMouseDragged:theEvent]; @@ -777,17 +787,31 @@ extern "C" { Qt::MouseButton buttons = cocoaButton2QtButton([theEvent buttonNumber]); bool wheelOK = false; Qt::KeyboardModifiers keyMods = qt_cocoaModifiers2QtModifiers([theEvent modifierFlags]); - QWidget *widgetToGetMouse = qwidget; - - // Mouse wheel deltas seem to tick in at increments of 0.1. Qt widgets - // expect the delta to be a multiple of 120. - const int ScrollFactor = 10 * 120; - // The qMax(...) factor reduces the - // acceleration for large wheel deltas. - int deltaX = [theEvent deltaX] * ScrollFactor * qMax(0.6, 1.1 - qAbs([theEvent deltaX])); - int deltaY = [theEvent deltaY] * ScrollFactor * qMax(0.6, 1.1 - qAbs([theEvent deltaY])); - int deltaZ = [theEvent deltaZ] * ScrollFactor * qMax(0.6, 1.1 - qAbs([theEvent deltaZ])); + int deltaX = 0; + int deltaY = 0; + int deltaZ = 0; + + const EventRef carbonEvent = (EventRef)[theEvent eventRef]; + const UInt32 carbonEventKind = carbonEvent ? ::GetEventKind(carbonEvent) : 0; + const bool scrollEvent = carbonEventKind == kEventMouseScroll; + + if (scrollEvent) { + // The mouse device containts pixel scroll wheel support (Mighty Mouse, Trackpad). + // Since deviceDelta is delivered as pixels rather than degrees, we need to + // convert from pixels to degrees in a sensible manner. + // It looks like four degrees per pixel behaves most native. + // Qt expects the unit for delta to be 1/8 of a degree: + deltaX = [theEvent deviceDeltaX]; + deltaY = [theEvent deviceDeltaY]; + deltaZ = [theEvent deviceDeltaZ]; + } else { + // carbonEventKind == kEventMouseWheelMoved + // Remove acceleration, and use either -120 or 120 as delta: + deltaX = qBound(-120, int([theEvent deltaX] * 10000), 120); + deltaY = qBound(-120, int([theEvent deltaY] * 10000), 120); + deltaZ = qBound(-120, int([theEvent deltaZ] * 10000), 120); + } if (deltaX != 0) { QWheelEvent qwe(qlocal, qglobal, deltaX, buttons, keyMods, Qt::Horizontal); @@ -845,6 +869,102 @@ extern "C" { [super tabletPoint:tabletEvent]; } +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 +- (void)touchesBeganWithEvent:(NSEvent *)event; +{ + bool all = qwidget->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents); + qt_translateRawTouchEvent(qwidget, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all)); +} + +- (void)touchesMovedWithEvent:(NSEvent *)event; +{ + bool all = qwidget->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents); + qt_translateRawTouchEvent(qwidget, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all)); +} + +- (void)touchesEndedWithEvent:(NSEvent *)event; +{ + bool all = qwidget->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents); + qt_translateRawTouchEvent(qwidget, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all)); +} + +- (void)touchesCancelledWithEvent:(NSEvent *)event; +{ + bool all = qwidget->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents); + qt_translateRawTouchEvent(qwidget, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all)); +} + +- (void)magnifyWithEvent:(NSEvent *)event; +{ + if (!QApplicationPrivate::tryModalHelper(qwidget, 0)) + return; + + QNativeGestureEvent qNGEvent; + qNGEvent.gestureType = QNativeGestureEvent::Zoom; + NSPoint p = [[event window] convertBaseToScreen:[event locationInWindow]]; + qNGEvent.position = flipPoint(p).toPoint(); + qNGEvent.percentage = [event magnification]; + qt_sendSpontaneousEvent(qwidget, &qNGEvent); +} + +- (void)rotateWithEvent:(NSEvent *)event; +{ + if (!QApplicationPrivate::tryModalHelper(qwidget, 0)) + return; + + QNativeGestureEvent qNGEvent; + qNGEvent.gestureType = QNativeGestureEvent::Rotate; + NSPoint p = [[event window] convertBaseToScreen:[event locationInWindow]]; + qNGEvent.position = flipPoint(p).toPoint(); + qNGEvent.percentage = -[event rotation]; + qt_sendSpontaneousEvent(qwidget, &qNGEvent); +} + +- (void)swipeWithEvent:(NSEvent *)event; +{ + if (!QApplicationPrivate::tryModalHelper(qwidget, 0)) + return; + + QNativeGestureEvent qNGEvent; + qNGEvent.gestureType = QNativeGestureEvent::Swipe; + NSPoint p = [[event window] convertBaseToScreen:[event locationInWindow]]; + qNGEvent.position = flipPoint(p).toPoint(); + if ([event deltaX] == 1) + qNGEvent.angle = 180.0f; + else if ([event deltaX] == -1) + qNGEvent.angle = 0.0f; + else if ([event deltaY] == 1) + qNGEvent.angle = 90.0f; + else if ([event deltaY] == -1) + qNGEvent.angle = 270.0f; + qt_sendSpontaneousEvent(qwidget, &qNGEvent); +} + +- (void)beginGestureWithEvent:(NSEvent *)event; +{ + if (!QApplicationPrivate::tryModalHelper(qwidget, 0)) + return; + + QNativeGestureEvent qNGEvent; + qNGEvent.gestureType = QNativeGestureEvent::GestureBegin; + NSPoint p = [[event window] convertBaseToScreen:[event locationInWindow]]; + qNGEvent.position = flipPoint(p).toPoint(); + qt_sendSpontaneousEvent(qwidget, &qNGEvent); +} + +- (void)endGestureWithEvent:(NSEvent *)event; +{ + if (!QApplicationPrivate::tryModalHelper(qwidget, 0)) + return; + + QNativeGestureEvent qNGEvent; + qNGEvent.gestureType = QNativeGestureEvent::GestureEnd; + NSPoint p = [[event window] convertBaseToScreen:[event locationInWindow]]; + qNGEvent.position = flipPoint(p).toPoint(); + qt_sendSpontaneousEvent(qwidget, &qNGEvent); +} +#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 + - (void)frameDidChange:(NSNotification *)note { Q_UNUSED(note); @@ -887,6 +1007,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); @@ -943,7 +1072,10 @@ extern "C" { sendToPopup = true; } - if (widgetToGetKey->testAttribute(Qt::WA_InputMethodEnabled)) { + if (widgetToGetKey->testAttribute(Qt::WA_InputMethodEnabled) + && !(widgetToGetKey->inputMethodHints() & Qt::ImhDigitsOnly + || widgetToGetKey->inputMethodHints() & Qt::ImhFormattedNumbersOnly + || widgetToGetKey->inputMethodHints() & Qt::ImhHiddenText)) { [qt_mac_nativeview_for(widgetToGetKey) interpretKeyEvents:[NSArray arrayWithObject: theEvent]]; } if (sendKeyEvents && !composing) { @@ -988,20 +1120,31 @@ extern "C" { - (void) insertText:(id)aString { - if (composing) { - // Send the commit string to the widget. - QString commitText; + QString commitText; + if ([aString length]) { if ([aString isKindOfClass:[NSAttributedString class]]) { - commitText = QCFString::toQString(reinterpret_cast<CFStringRef>([aString string])); + commitText = QCFString::toQString(reinterpret_cast<CFStringRef>([aString string])); } else { commitText = QCFString::toQString(reinterpret_cast<CFStringRef>(aString)); }; + } + + if ([aString length] && composing) { + // Send the commit string to the widget. composing = false; sendKeyEvents = false; QInputMethodEvent e; e.setCommitString(commitText); qt_sendSpontaneousEvent(qwidget, &e); + } else { + // The key sequence "`q" on a French Keyboard will generate two calls to insertText before + // it returns from interpretKeyEvents. The first call will turn off 'composing' and accept + // the "`" key. The last keyDown event needs to be processed by the widget to get the + // character "q". The string parameter is ignored for the second call. + sendKeyEvents = true; } + + composingText->clear(); } - (void) setMarkedText:(id)aString selectedRange:(NSRange)selRange @@ -1023,7 +1166,7 @@ extern "C" { while (index < composingLength) { NSRange effectiveRange; NSRange range = NSMakeRange(index, composingLength-index); - NSDictionary *attributes = [aString attributesAtIndex:index + NSDictionary *attributes = [aString attributesAtIndex:index longestEffectiveRange:&effectiveRange inRange:range]; NSNumber *underlineStyle = [attributes objectForKey:NSUnderlineStyleAttributeName]; @@ -1032,7 +1175,7 @@ extern "C" { NSColor *color = [attributes objectForKey:NSUnderlineColorAttributeName]; if (color) { clr = colorFrom(color); - } + } QTextCharFormat format; format.setFontUnderline(true); format.setUnderlineColor(clr); @@ -1055,12 +1198,21 @@ extern "C" { attrs<<QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, composingLength, format); } + *composingText = qtText; QInputMethodEvent e(qtText, attrs); qt_sendSpontaneousEvent(qwidget, &e); + if (!composingLength) + composing = false; } - (void) unmarkText { + if (composing) { + QInputMethodEvent e; + e.setCommitString(*composingText); + qt_sendSpontaneousEvent(qwidget, &e); + } + composingText->clear(); composing = false; } @@ -1099,7 +1251,7 @@ extern "C" { - (NSRange) markedRange { - NSRange range; + NSRange range; if (composing) { range.location = 0; range.length = composingLength; @@ -1124,13 +1276,13 @@ extern "C" { selRange.length = 0; } return selRange; - + } - (NSRect) firstRectForCharacterRange:(NSRange)theRange { Q_UNUSED(theRange); - // The returned rect is always based on the internal cursor. + // The returned rect is always based on the internal cursor. QRect mr(qwidget->inputMethodQuery(Qt::ImMicroFocus).toRect()); QPoint mp(qwidget->mapToGlobal(QPoint(mr.bottomLeft()))); NSRect rect ; @@ -1278,7 +1430,7 @@ Qt::DropAction QDragManager::drag(QDrag *o) NSImage *image = (NSImage *)qt_mac_create_nsimage(pix); [image retain]; DnDParams dndParams = *[QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent]; - // save supported actions + // save supported actions [dndParams.view setSupportedActions: qt_mac_mapDropActions(dragPrivate()->possible_actions)]; NSPoint imageLoc = {dndParams.localPoint.x - hotspot.x(), dndParams.localPoint.y + pix.height() - hotspot.y()}; @@ -1302,7 +1454,7 @@ Qt::DropAction QDragManager::drag(QDrag *o) Qt::DropAction performedAction(qt_mac_mapNSDragOperation(dndParams.performedAction)); // do post drag processing, if required. if(performedAction != Qt::IgnoreAction) { - // check if the receiver points us to a file location. + // check if the receiver points us to a file location. // if so, we need to do the file copy/move ourselves. QCFType<CFURLRef> pasteLocation = 0; PasteboardCopyPasteLocation(dragBoard.pasteBoard(), &pasteLocation); diff --git a/src/gui/kernel/qcocoaview_mac_p.h b/src/gui/kernel/qcocoaview_mac_p.h index a25ef00..d549177 100644 --- a/src/gui/kernel/qcocoaview_mac_p.h +++ b/src/gui/kernel/qcocoaview_mac_p.h @@ -59,6 +59,7 @@ QT_FORWARD_DECLARE_CLASS(QWidgetPrivate); QT_FORWARD_DECLARE_CLASS(QWidget); QT_FORWARD_DECLARE_CLASS(QEvent); QT_FORWARD_DECLARE_CLASS(QCocoaDropData); +QT_FORWARD_DECLARE_CLASS(QString); QT_FORWARD_DECLARE_CLASS(QStringList); QT_BEGIN_NAMESPACE @@ -85,6 +86,7 @@ Q_GUI_EXPORT bool composing; int composingLength; bool sendKeyEvents; + QString *composingText; QStringList *currentCustomTypes; NSInteger dragEnterSequence; } diff --git a/src/gui/kernel/qcocoawindow_mac.mm b/src/gui/kernel/qcocoawindow_mac.mm index b15abc1..263f0ac 100644 --- a/src/gui/kernel/qcocoawindow_mac.mm +++ b/src/gui/kernel/qcocoawindow_mac.mm @@ -101,6 +101,12 @@ QT_USE_NAMESPACE last resort (i.e., this is code that can potentially be removed). */ +- (void)toggleToolbarShown:(id)sender +{ + macSendToolbarChangeEvent([self QT_MANGLE_NAMESPACE(qt_qwidget)]); + [super toggleToolbarShown:sender]; +} + - (void)keyDown:(NSEvent *)theEvent { bool keyOK = qt_dispatchKeyEvent(theEvent, [self QT_MANGLE_NAMESPACE(qt_qwidget)]); diff --git a/src/gui/kernel/qcocoawindowdelegate_mac.mm b/src/gui/kernel/qcocoawindowdelegate_mac.mm index 95c89e5..803a1b1 100644 --- a/src/gui/kernel/qcocoawindowdelegate_mac.mm +++ b/src/gui/kernel/qcocoawindowdelegate_mac.mm @@ -346,5 +346,28 @@ static void cleanupCocoaWindowDelegate() m_drawerHash->remove(drawer); } +- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu +{ + Q_UNUSED(menu); + QWidget *qwidget = m_windowHash->value(window); + if (qwidget && !qwidget->windowFilePath().isEmpty()) { + return YES; + } + return NO; +} + +- (BOOL)window:(NSWindow *)window shouldDragDocumentWithEvent:(NSEvent *)event + from:(NSPoint)dragImageLocation + withPasteboard:(NSPasteboard *)pasteboard +{ + Q_UNUSED(event); + Q_UNUSED(dragImageLocation); + Q_UNUSED(pasteboard); + QWidget *qwidget = m_windowHash->value(window); + if (qwidget && !qwidget->windowFilePath().isEmpty()) { + return YES; + } + return NO; +} @end #endif// QT_MAC_USE_COCOA diff --git a/src/gui/kernel/qcocoawindowdelegate_mac_p.h b/src/gui/kernel/qcocoawindowdelegate_mac_p.h index a06c516..3728002 100644 --- a/src/gui/kernel/qcocoawindowdelegate_mac_p.h +++ b/src/gui/kernel/qcocoawindowdelegate_mac_p.h @@ -76,6 +76,8 @@ QT_FORWARD_DECLARE_CLASS(QWidgetData) - (void)windowDidResignMain:(NSNotification*)notification; - (void)windowDidBecomeKey:(NSNotification*)notification; - (void)windowDidResignKey:(NSNotification*)notification; +- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu; +- (BOOL)window:(NSWindow *)window shouldDragDocumentWithEvent:(NSEvent *)event from:(NSPoint)dragImageLocation withPasteboard:(NSPasteboard *)pasteboard; @end @protocol NSDrawerDelegate <NSObject> diff --git a/src/gui/kernel/qcursor.cpp b/src/gui/kernel/qcursor.cpp index 8b45d64..2e54daf 100644 --- a/src/gui/kernel/qcursor.cpp +++ b/src/gui/kernel/qcursor.cpp @@ -60,7 +60,7 @@ QT_BEGIN_NAMESPACE \ingroup appearance \ingroup shared - \mainclass + This class is mainly used to create mouse cursors that are associated with particular widgets and to get and set the position @@ -403,7 +403,7 @@ void QCursorData::initialize() QCursor::QCursor() { if (!QCursorData::initialized) { - if (qApp->startingUp()) { + if (QApplication::startingUp()) { d = 0; return; } @@ -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.h b/src/gui/kernel/qcursor.h index 389a110..2b2aa4a 100644 --- a/src/gui/kernel/qcursor.h +++ b/src/gui/kernel/qcursor.h @@ -72,13 +72,19 @@ private: #ifndef QT_NO_CURSOR -struct QCursorData; +class QCursorData; class QBitmap; class QPixmap; #if defined(Q_WS_MAC) void qt_mac_set_cursor(const QCursor *c, const QPoint &p); #endif +#if defined(Q_OS_SYMBIAN) +extern void qt_symbian_show_pointer_sprite(); +extern void qt_symbian_hide_pointer_sprite(); +extern void qt_symbian_set_pointer_sprite(const QCursor& cursor); +extern void qt_symbian_move_cursor_sprite(); +#endif class Q_GUI_EXPORT QCursor { @@ -103,7 +109,7 @@ public: static QPoint pos(); static void setPos(int x, int y); inline static void setPos(const QPoint &p) { setPos(p.x(), p.y()); } - + #ifdef qdoc HCURSOR_or_HANDLE handle() const; QCursor(HCURSOR cursor); @@ -122,6 +128,8 @@ public: Qt::HANDLE handle() const; #elif defined(Q_WS_QWS) int handle() const; +#elif defined(Q_OS_SYMBIAN) + Qt::HANDLE handle() const; #endif #endif @@ -131,6 +139,12 @@ private: friend void *qt_mac_nsCursorForQCursor(const QCursor &c); friend void qt_mac_set_cursor(const QCursor *c, const QPoint &p); #endif +#if defined(Q_OS_SYMBIAN) + friend void qt_symbian_show_pointer_sprite(); + friend void qt_symbian_hide_pointer_sprite(); + friend void qt_symbian_set_pointer_sprite(const QCursor& cursor); + friend void qt_symbian_move_cursor_sprite(); +#endif }; #ifdef QT3_SUPPORT diff --git a/src/gui/kernel/qcursor_p.h b/src/gui/kernel/qcursor_p.h index aa4f4b2..12166c8 100644 --- a/src/gui/kernel/qcursor_p.h +++ b/src/gui/kernel/qcursor_p.h @@ -64,6 +64,8 @@ # include "private/qt_x11_p.h" # elif defined(Q_WS_WIN) # include "QtCore/qt_windows.h" +# elif defined(Q_OS_SYMBIAN) +# include "private/qt_s60_p.h" #endif QT_BEGIN_NAMESPACE @@ -74,7 +76,8 @@ class QMacAnimateCursor; #endif class QBitmap; -struct QCursorData { +class QCursorData { +public: QCursorData(Qt::CursorShape s = Qt::ArrowCursor); ~QCursorData(); @@ -111,12 +114,21 @@ struct QCursorData { } curs; void initCursorFromBitmap(); void initCursorFromPixmap(); +#elif defined Q_OS_SYMBIAN + void loadShapeFromResource(RWsSpriteBase& target, QString resource, int hx, int hy, int interval=0); + void constructShapeSprite(RWsSpriteBase& target); + void constructCursorSprite(RWsSpriteBase& target); + RWsPointerCursor pcurs; + RWsSprite scurs; + RPointerArray<TSpriteMember> nativeSpriteMembers; #endif static bool initialized; void update(); static QCursorData *setBitmap(const QBitmap &bitmap, const QBitmap &mask, int hotX, int hotY); }; +extern QCursorData *qt_cursorTable[Qt::LastCursor + 1]; // qcursor.cpp + QT_END_NAMESPACE #endif // QCURSOR_P_H diff --git a/src/gui/kernel/qcursor_qws.cpp b/src/gui/kernel/qcursor_qws.cpp index 31e7ebe..0eeb187 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. + } } @@ -74,8 +78,6 @@ QCursorData::~QCursorData() Global cursors *****************************************************************************/ -extern QCursorData *qt_cursorTable[Qt::LastCursor + 1]; // qcursor.cpp - int QCursor::handle() const { return d->id; diff --git a/src/gui/kernel/qcursor_s60.cpp b/src/gui/kernel/qcursor_s60.cpp new file mode 100644 index 0000000..7f5c32a --- /dev/null +++ b/src/gui/kernel/qcursor_s60.cpp @@ -0,0 +1,533 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <private/qcursor_p.h> +#include <private/qwidget_p.h> +#include <private/qapplication_p.h> +#include <coecntrl.h> +#include <qcursor.h> +#include <qt_s60_p.h> +#include <qbitmap.h> +#include <w32std.h> +#include <qapplication.h> +#include <qwidget.h> + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_CURSOR +static QCursor cursorSprite; +static int cursorSpriteVisible; +#endif + +//pos and setpos are required whether cursors are configured or not. +QPoint QCursor::pos() +{ + return S60->lastCursorPos; +} + +void QCursor::setPos(int x, int y) +{ + //clip to screen size (window server allows a sprite hotspot to be outside the screen) + if (x < 0) + x=0; + else if (x >= S60->screenWidthInPixels) + x = S60->screenWidthInPixels - 1; + if (y < 0) + y = 0; + else if (y >= S60->screenHeightInPixels) + y = S60->screenHeightInPixels - 1; + +#ifndef QT_NO_CURSOR +#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS + if (S60->brokenPointerCursors && cursorSpriteVisible) + cursorSprite.d->scurs.SetPosition(TPoint(x,y)); + else +#endif + S60->wsSession().SetPointerCursorPosition(TPoint(x, y)); +#endif + S60->lastCursorPos = QPoint(x, y); + //send a fake mouse move event, so that enter/leave events go to the widget hierarchy + QWidget *w = QApplication::topLevelAt(S60->lastCursorPos); + if (w) { + CCoeControl* ctrl = w->effectiveWinId(); + TPoint epos(x, y); + TPoint cpos = epos - ctrl->PositionRelativeToScreen(); + TPointerEvent fakeEvent; + fakeEvent.iType = TPointerEvent::EMove; + fakeEvent.iModifiers = 0U; + fakeEvent.iPosition = cpos; + fakeEvent.iParentPosition = epos; + ctrl->HandlePointerEventL(fakeEvent); + } +} + +#ifndef QT_NO_CURSOR +/* + * Request cursor to be turned on or off. + * Reference counted, so 2 on + 1 off = on, for example + */ +void qt_symbian_set_cursor_visible(bool visible) { + if (visible) + cursorSpriteVisible++; + else + cursorSpriteVisible--; + Q_ASSERT(cursorSpriteVisible >=0); + + if (cursorSpriteVisible && !S60->mouseInteractionEnabled) { +#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS + if (S60->brokenPointerCursors) + qt_symbian_show_pointer_sprite(); + else +#endif + S60->wsSession().SetPointerCursorMode(EPointerCursorNormal); + } else if (!cursorSpriteVisible && S60->mouseInteractionEnabled) { +#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS + if (S60->brokenPointerCursors) + qt_symbian_hide_pointer_sprite(); + else +#endif + S60->wsSession().SetPointerCursorMode(EPointerCursorNone); + } + S60->mouseInteractionEnabled = ((cursorSpriteVisible > 0) ? true : false); +} + +/* + * Check if the cursor is on or off + */ +bool qt_symbian_is_cursor_visible() { + return S60->mouseInteractionEnabled; +} + +QCursorData::QCursorData(Qt::CursorShape s) : + cshape(s), bm(0), bmm(0), hx(0), hy(0), pcurs() +{ + ref = 1; +} + +QCursorData::~QCursorData() +{ + for(int i=0;i<nativeSpriteMembers.Count();i++) { + delete nativeSpriteMembers[i]->iBitmap; + delete nativeSpriteMembers[i]->iMaskBitmap; + } + nativeSpriteMembers.ResetAndDestroy(); + pcurs.Close(); + delete bm; + delete bmm; +} + +/* Create a bitmap cursor, this is called by public constructors in the + * generic QCursor code. + */ +QCursorData *QCursorData::setBitmap(const QBitmap &bitmap, const QBitmap &mask, int hotX, int hotY) +{ + if (!QCursorData::initialized) + QCursorData::initialize(); + if (bitmap.depth() != 1 || mask.depth() != 1 || bitmap.size() != mask.size()) { + qWarning("QCursor: Cannot create bitmap cursor; invalid bitmap(s)"); + QCursorData *c = qt_cursorTable[0]; + c->ref.ref(); + return c; + } + QCursorData *d = new QCursorData; + d->bm = new QBitmap(bitmap); + d->bmm = new QBitmap(mask); + d->cshape = Qt::BitmapCursor; + d->hx = hotX >= 0 ? hotX : bitmap.width() / 2; + d->hy = hotY >= 0 ? hotY : bitmap.height() / 2; + return d; +} + +/* + * returns an opaque native handle to a cursor. + * It happens to be the address of the native handle, as window server handles + * are not POD types. Note there is no QCursor(HANDLE) constructor on Symbian, + * Mac or QWS. + */ +Qt::HANDLE QCursor::handle() const +{ + if (d->pcurs.WsHandle()) + return reinterpret_cast<Qt::HANDLE> (&(d->pcurs)); + +#ifdef Q_SYMBIAN_HAS_SYSTEM_CURSORS + // don't construct shape cursors, QApplication_s60 will use the system cursor instead + if (!(d->bm)) + return 0; +#endif + + d->pcurs = RWsPointerCursor(S60->wsSession()); + d->pcurs.Construct(0); + d->constructCursorSprite(d->pcurs); + d->pcurs.Activate(); + + return reinterpret_cast<Qt::HANDLE> (&(d->pcurs)); +} + +#ifndef Q_SYMBIAN_HAS_SYSTEM_CURSORS +/* + * Loads a single cursor shape from resources and appends it to a native sprite. + * Animated cursors (e.g. the busy cursor) have multiple members. + */ +void QCursorData::loadShapeFromResource(RWsSpriteBase& target, QString resource, int hx, int hy, int interval) +{ + QPixmap pix; + CFbsBitmap* native; + QScopedPointer<TSpriteMember> member(new TSpriteMember); + member->iInterval = interval; + member->iInvertMask = false; + member->iMaskBitmap = 0; // all shapes are RGBA + member->iDrawMode = CGraphicsContext::EDrawModePEN; + member->iOffset = TPoint(-hx, -hy); + QString res(QLatin1String(":/trolltech/symbian/cursors/images/%1.png")); + pix.load(res.arg(resource)); + native = pix.toSymbianCFbsBitmap(); + member->iBitmap = native; + qt_symbian_throwIfError(nativeSpriteMembers.Append(member.data())); + target.AppendMember(*(member.take())); +} + +//TODO: after 4.6, connect with style & skins? +/* + * Constructs the native cursor from resources compiled into QtGui + * This is needed only when the platform doesn't have system cursors. + * + * System cursors are higher performance, since they are constructed once + * and shared by all applications by specifying the shape number. + * Due to symbian platform security considerations, and the fact most + * existing phones have a broken RWsPointerCursor, system cursors are not + * being used. + */ +void QCursorData::constructShapeSprite(RWsSpriteBase& target) +{ + int i; + switch (cshape) { + default: + qWarning("QCursorData::constructShapeSprite unknown shape %d", cshape); + //fall through and give arrow cursor + case Qt::ArrowCursor: + loadShapeFromResource(target, QLatin1String("pointer"), 1, 1); + break; + case Qt::UpArrowCursor: + loadShapeFromResource(target, QLatin1String("uparrow"), 4, 0); + break; + case Qt::CrossCursor: + loadShapeFromResource(target, QLatin1String("cross"), 7, 7); + break; + case Qt::WaitCursor: + for (i = 1; i <= 12; i++) { + loadShapeFromResource(target, QString(QLatin1String("wait%1")).arg(i), 7, 7, 1000000); + } + break; + case Qt::IBeamCursor: + loadShapeFromResource(target, QLatin1String("ibeam"), 3, 10); + break; + case Qt::SizeVerCursor: + loadShapeFromResource(target, QLatin1String("sizever"), 4, 8); + break; + case Qt::SizeHorCursor: + loadShapeFromResource(target, QLatin1String("sizehor"), 8, 4); + break; + case Qt::SizeBDiagCursor: + loadShapeFromResource(target, QLatin1String("sizebdiag"), 8, 8); + break; + case Qt::SizeFDiagCursor: + loadShapeFromResource(target, QLatin1String("sizefdiag"), 8, 8); + break; + case Qt::SizeAllCursor: + loadShapeFromResource(target, QLatin1String("sizeall"), 7, 7); + break; + case Qt::BlankCursor: + loadShapeFromResource(target, QLatin1String("blank"), 0, 0); + break; + case Qt::SplitVCursor: + loadShapeFromResource(target, QLatin1String("splitv"), 7, 7); + break; + case Qt::SplitHCursor: + loadShapeFromResource(target, QLatin1String("splith"), 7, 7); + break; + case Qt::PointingHandCursor: + loadShapeFromResource(target, QLatin1String("handpoint"), 5, 0); + break; + case Qt::ForbiddenCursor: + loadShapeFromResource(target, QLatin1String("forbidden"), 7, 7); + break; + case Qt::WhatsThisCursor: + loadShapeFromResource(target, QLatin1String("whatsthis"), 1, 1); + break; + case Qt::BusyCursor: + loadShapeFromResource(target, QLatin1String("busy3"), 1, 1, 1000000); + loadShapeFromResource(target, QLatin1String("busy6"), 1, 1, 1000000); + loadShapeFromResource(target, QLatin1String("busy9"), 1, 1, 1000000); + loadShapeFromResource(target, QLatin1String("busy12"), 1, 1, 1000000); + break; + case Qt::OpenHandCursor: + loadShapeFromResource(target, QLatin1String("openhand"), 7, 7); + break; + case Qt::ClosedHandCursor: + loadShapeFromResource(target, QLatin1String("closehand"), 7, 7); + break; + } +} +#endif + +/* + * Common code between the sprite workaround and standard modes of operation. + * RWsSpriteBase is the base class for both RWsSprite and RWsPointerCursor. + * It is called from both handle() and qt_s60_show_pointer_sprite() + */ +void QCursorData::constructCursorSprite(RWsSpriteBase& target) +{ + int count = nativeSpriteMembers.Count(); + if (count) { + // already constructed + for (int i = 0; i < count; i++) + target.AppendMember(*(nativeSpriteMembers[i])); + + return; + } + if (pixmap.isNull() && !bm) { +#ifndef Q_SYMBIAN_HAS_SYSTEM_CURSORS + //shape cursor + constructShapeSprite(target); +#endif + return; + } + QScopedPointer<TSpriteMember> member(new TSpriteMember); + if (pixmap.isNull()) { + //construct mono cursor + member->iBitmap = bm->toSymbianCFbsBitmap(); + member->iMaskBitmap = bmm->toSymbianCFbsBitmap(); + } + else { + //construct normal cursor + member->iBitmap = pixmap.toSymbianCFbsBitmap(); + if (pixmap.hasAlphaChannel()) { + member->iMaskBitmap = 0; //use alpha blending + } + else if (pixmap.hasAlpha()) { + member->iMaskBitmap = pixmap.mask().toSymbianCFbsBitmap(); + } + else { + member->iMaskBitmap = 0; //opaque rectangle cursor (due to EDrawModePEN) + } + } + + member->iDrawMode = CGraphicsContext::EDrawModePEN; + member->iInvertMask = EFalse; + member->iInterval = 0; + member->iOffset = TPoint(-(hx), -(hy)); //Symbian hotspot coordinates are negative + qt_symbian_throwIfError(nativeSpriteMembers.Append(member.data())); + target.AppendMember(*(member.take())); +} + +/* + * shows the pointer sprite by constructing a native handle, and registering + * it with the window server. + * Only used when the sprite workaround is in use. + */ +void qt_symbian_show_pointer_sprite() +{ + if (cursorSprite.d) { + if (cursorSprite.d->scurs.WsHandle()) + cursorSprite.d->scurs.Close(); + } else { + cursorSprite = QCursor(Qt::ArrowCursor); + } + + cursorSprite.d->scurs = RWsSprite(S60->wsSession()); + QPoint pos = QCursor::pos(); + cursorSprite.d->scurs.Construct(S60->windowGroup(), TPoint(pos.x(), pos.y()), ESpriteNoChildClip | ESpriteNoShadows); + + cursorSprite.d->constructCursorSprite(cursorSprite.d->scurs); + cursorSprite.d->scurs.Activate(); +} + +/* + * hides the pointer sprite by closing the native handle. + * Only used when the sprite workaround is in use. + */ +void qt_symbian_hide_pointer_sprite() +{ + if (cursorSprite.d) { + cursorSprite.d->scurs.Close(); + } +} + +/* + * Changes the cursor sprite to the cursor specified. + * Only used when the sprite workaround is in use. + */ +void qt_symbian_set_pointer_sprite(const QCursor& cursor) +{ + if (S60->mouseInteractionEnabled) + qt_symbian_hide_pointer_sprite(); + cursorSprite = cursor; + if (S60->mouseInteractionEnabled) + qt_symbian_show_pointer_sprite(); +} + +/* + * When using sprites as a workaround on phones that have a broken + * RWsPointerCursor, this function is called in response to pointer events + * and when QCursor::setPos() is called. + * Performance is worse than a real pointer cursor, due to extra context + * switches vs. the window server moving the cursor by itself. + */ +void qt_symbian_move_cursor_sprite() +{ + if (S60->mouseInteractionEnabled) { + cursorSprite.d->scurs.SetPosition(TPoint(S60->lastCursorPos.x(), S60->lastCursorPos.y())); + } +} + +/* + * Translate from Qt::CursorShape to OS system pointer cursor list index. + * Currently we control the implementation of the system pointer cursor list, + * so this function is trivial. That may not always be the case. + */ +TInt qt_symbian_translate_cursor_shape(Qt::CursorShape shape) +{ + return (TInt) shape; +} + +/* + Internal function called from QWidget::setCursor() + force is true if this function is called from dispatchEnterLeave, it means that the + mouse is actually directly under this widget. +*/ +void qt_symbian_set_cursor(QWidget *w, bool force) +{ + static QPointer<QWidget> lastUnderMouse = 0; + if (force) { + lastUnderMouse = w; + } + else if (w->testAttribute(Qt::WA_WState_Created) && lastUnderMouse + && lastUnderMouse->effectiveWinId() == w->effectiveWinId()) { + w = lastUnderMouse; + } + + if (!S60->curWin && w && w->internalWinId()) + return; + QWidget* cW = w && !w->internalWinId() ? w : QWidget::find(S60->curWin); + if (!cW || cW->window() != w->window() || !cW->isVisible() || !cW->underMouse() + || QApplication::overrideCursor()) + return; + +#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS + if (S60->brokenPointerCursors) + qt_symbian_set_pointer_sprite(cW->cursor()); + else +#endif + qt_symbian_setWindowCursor(cW->cursor(), w->effectiveWinId()); +} + +/* + * Makes the specified cursor appear above a specific native window group + * Called from QSymbianControl and QApplication::restoreOverrideCursor + * + * Window server is needed for this, so there is no equivalent when using + * the sprite workaround. + */ +void qt_symbian_setWindowGroupCursor(const QCursor &cursor, RWindowTreeNode &node) +{ + Qt::HANDLE handle = cursor.handle(); + if (handle) { + RWsPointerCursor *pcurs = reinterpret_cast<RWsPointerCursor *> (handle); + node.SetCustomPointerCursor(*pcurs); + } +#ifdef Q_SYMBIAN_HAS_SYSTEM_CURSORS + else { + TInt shape = qt_symbian_translate_cursor_shape(cursor.shape()); + node.SetPointerCursor(shape); + } +#else + qWarning("qt_s60_setWindowGroupCursor - null handle"); +#endif +} + +/* + * Makes the specified cursor appear above a specific native window + * Called from QSymbianControl and QApplication::restoreOverrideCursor + * + * Window server is needed for this, so there is no equivalent when using + * the sprite workaround. + */ +void qt_symbian_setWindowCursor(const QCursor &cursor, const CCoeControl* wid) +{ + //find the window for this control + while (!wid->OwnsWindow()) { + wid = wid->Parent(); + if (!wid) + return; + } + RWindowTreeNode *node = wid->DrawableWindow(); + qt_symbian_setWindowGroupCursor(cursor, *node); +} + +/* + * Makes the specified cursor appear everywhere. + * Called from QApplication::setOverrideCursor + */ +void qt_symbian_setGlobalCursor(const QCursor &cursor) +{ +#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS + if (S60->brokenPointerCursors) { + qt_symbian_set_pointer_sprite(cursor); + } else +#endif + { + //because of the internals of window server, we need to force the cursor + //to be set in all child windows too, otherwise when the cursor is over + //the child window it may show a widget cursor or arrow cursor instead, + //depending on construction order. + QListIterator<WId> iter(QWidgetPrivate::mapper->uniqueKeys()); + while(iter.hasNext()) + { + CCoeControl *ctrl = iter.next(); + if(ctrl->OwnsWindow()) { + RWindowTreeNode *node = ctrl->DrawableWindow(); + qt_symbian_setWindowGroupCursor(cursor, *node); + } + } + } +} +QT_END_NAMESPACE +#endif // QT_NO_CURSOR diff --git a/src/gui/kernel/qcursor_win.cpp b/src/gui/kernel/qcursor_win.cpp index 296b8f3..26cde1a 100644 --- a/src/gui/kernel/qcursor_win.cpp +++ b/src/gui/kernel/qcursor_win.cpp @@ -50,8 +50,6 @@ QT_BEGIN_NAMESPACE -extern QCursorData *qt_cursorTable[Qt::LastCursor + 1]; // qcursor.cpp - /***************************************************************************** Internal QCursorData class *****************************************************************************/ @@ -66,7 +64,7 @@ QCursorData::~QCursorData() { delete bm; delete bmm; -#if !defined(Q_OS_WINCE) || defined(GWES_ICONCURS) +#if !defined(Q_WS_WINCE) || defined(GWES_ICONCURS) if (hcurs) DestroyCursor(hcurs); #endif @@ -129,7 +127,7 @@ extern HBITMAP qt_createIconMask(const QBitmap &bitmap); static HCURSOR create32BitCursor(const QPixmap &pixmap, int hx, int hy) { HCURSOR cur = 0; -#if !defined(Q_OS_WINCE) +#if !defined(Q_WS_WINCE) QBitmap mask = pixmap.mask(); if (mask.isNull()) { mask = QBitmap(pixmap.size()); @@ -317,54 +315,50 @@ void QCursorData::update() phand_bits, phandm_bits }; - unsigned short *sh; + wchar_t *sh = 0; switch (cshape) { // map to windows cursor case Qt::ArrowCursor: - sh = (unsigned short*)IDC_ARROW; + sh = IDC_ARROW; break; case Qt::UpArrowCursor: - sh = (unsigned short*)IDC_UPARROW; + sh = IDC_UPARROW; break; case Qt::CrossCursor: - sh = (unsigned short*)IDC_CROSS; + sh = IDC_CROSS; break; case Qt::WaitCursor: - sh = (unsigned short*)IDC_WAIT; + sh = IDC_WAIT; break; case Qt::IBeamCursor: - sh = (unsigned short*)IDC_IBEAM; + sh = IDC_IBEAM; break; case Qt::SizeVerCursor: - sh = (unsigned short*)IDC_SIZENS; + sh = IDC_SIZENS; break; case Qt::SizeHorCursor: - sh = (unsigned short*)IDC_SIZEWE; + sh = IDC_SIZEWE; break; case Qt::SizeBDiagCursor: - sh = (unsigned short*)IDC_SIZENESW; + sh = IDC_SIZENESW; break; case Qt::SizeFDiagCursor: - sh = (unsigned short*)IDC_SIZENWSE; + sh = IDC_SIZENWSE; break; case Qt::SizeAllCursor: - sh = (unsigned short*)IDC_SIZEALL; + sh = IDC_SIZEALL; break; case Qt::ForbiddenCursor: - sh = (unsigned short*)IDC_NO; + sh = IDC_NO; break; case Qt::WhatsThisCursor: - sh = (unsigned short*)IDC_HELP; + sh = IDC_HELP; break; case Qt::BusyCursor: - sh = (unsigned short*)IDC_APPSTARTING; + sh = IDC_APPSTARTING; break; case Qt::PointingHandCursor: - if ((QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based) > QSysInfo::WV_95 || - (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based) > QSysInfo::WV_NT) { - sh = (unsigned short*)IDC_HAND; - break; - } - // fall through + sh = IDC_HAND; + break; case Qt::BlankCursor: case Qt::SplitVCursor: case Qt::SplitHCursor: @@ -407,7 +401,7 @@ void QCursorData::update() } int n = qMax(1, bbits.width() / 8); int h = bbits.height(); -#if !defined(Q_OS_WINCE) +#if !defined(Q_WS_WINCE) uchar* xBits = new uchar[h * n]; uchar* xMask = new uchar[h * n]; int x = 0; @@ -430,7 +424,7 @@ void QCursorData::update() xBits, xMask); delete [] xBits; delete [] xMask; -#elif defined(GWES_ICONCURS) // Q_OS_WINCE +#elif defined(GWES_ICONCURS) // Q_WS_WINCE // Windows CE only supports fixed cursor size. int sysW = GetSystemMetrics(SM_CXCURSOR); int sysH = GetSystemMetrics(SM_CYCURSOR); @@ -480,13 +474,11 @@ void QCursorData::update() qWarning("QCursor::update: Invalid cursor shape %d", cshape); return; } - // ### From MSDN: - // ### LoadCursor has been superseded by the LoadImage function. - QT_WA({ - hcurs = LoadCursorW(0, reinterpret_cast<const TCHAR *>(sh)); - } , { - hcurs = LoadCursorA(0, reinterpret_cast<const char*>(sh)); - }); +#ifdef Q_WS_WINCE + hcurs = LoadCursor(0, sh); +#else + hcurs = (HCURSOR)LoadImage(0, sh, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED); +#endif } QT_END_NAMESPACE diff --git a/src/gui/kernel/qcursor_x11.cpp b/src/gui/kernel/qcursor_x11.cpp index d8cc2fc..3e53f04 100644 --- a/src/gui/kernel/qcursor_x11.cpp +++ b/src/gui/kernel/qcursor_x11.cpp @@ -63,8 +63,6 @@ QT_BEGIN_NAMESPACE // Define QT_USE_APPROXIMATE_CURSORS when compiling if you REALLY want to // use the ugly X11 cursors. -extern QCursorData *qt_cursorTable[Qt::LastCursor + 1]; // qcursor.cpp - /***************************************************************************** Internal QCursorData class *****************************************************************************/ @@ -100,6 +98,7 @@ QCursor::QCursor(Qt::HANDLE cursor) d = new QCursorData(Qt::CustomCursor); d->hcurs = cursor; } + #endif QCursorData *QCursorData::setBitmap(const QBitmap &bitmap, const QBitmap &mask, int hotX, int hotY) diff --git a/src/gui/kernel/qdesktopwidget.cpp b/src/gui/kernel/qdesktopwidget.cpp new file mode 100644 index 0000000..c6d5000 --- /dev/null +++ b/src/gui/kernel/qdesktopwidget.cpp @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qglobal.h" +#include "qdesktopwidget.h" +#include "qwidget_p.h" + +QT_BEGIN_NAMESPACE + +const QRect QDesktopWidget::screenGeometry(const QWidget *widget) const +{ + QRect rect = QWidgetPrivate::screenGeometry(widget); + if (rect.isNull()) + return screenGeometry(screenNumber(widget)); + else return rect; +} + +const QRect QDesktopWidget::availableGeometry(const QWidget *widget) const +{ + QRect rect = QWidgetPrivate::screenGeometry(widget); + if (rect.isNull()) + return availableGeometry(screenNumber(widget)); + else + return rect; +} + +QT_END_NAMESPACE + diff --git a/src/gui/kernel/qdesktopwidget.h b/src/gui/kernel/qdesktopwidget.h index 41afa8c..6e3447c 100644 --- a/src/gui/kernel/qdesktopwidget.h +++ b/src/gui/kernel/qdesktopwidget.h @@ -56,6 +56,9 @@ class QDesktopWidgetPrivate; class Q_GUI_EXPORT QDesktopWidget : public QWidget { Q_OBJECT + Q_PROPERTY(bool virtualDesktop READ isVirtualDesktop) + Q_PROPERTY(int screenCount READ screenCount NOTIFY screenCountChanged) + Q_PROPERTY(int primaryScreen READ primaryScreen) public: QDesktopWidget(); ~QDesktopWidget(); @@ -63,6 +66,7 @@ public: bool isVirtualDesktop() const; int numScreens() const; + int screenCount() const; int primaryScreen() const; int screenNumber(const QWidget *widget = 0) const; @@ -71,20 +75,19 @@ public: QWidget *screen(int screen = -1); const QRect screenGeometry(int screen = -1) const; - const QRect screenGeometry(const QWidget *widget) const - { return screenGeometry(screenNumber(widget)); } + const QRect screenGeometry(const QWidget *widget) const; const QRect screenGeometry(const QPoint &point) const { return screenGeometry(screenNumber(point)); } const QRect availableGeometry(int screen = -1) const; - const QRect availableGeometry(const QWidget *widget) const - { return availableGeometry(screenNumber(widget)); } + const QRect availableGeometry(const QWidget *widget) const; const QRect availableGeometry(const QPoint &point) const { return availableGeometry(screenNumber(point)); } Q_SIGNALS: void resized(int); void workAreaResized(int); + void screenCountChanged(int); protected: void resizeEvent(QResizeEvent *e); @@ -97,6 +100,9 @@ private: friend class QApplicationPrivate; }; +inline int QDesktopWidget::screenCount() const +{ return numScreens(); } + QT_END_NAMESPACE QT_END_HEADER diff --git a/src/gui/kernel/qdesktopwidget.qdoc b/src/gui/kernel/qdesktopwidget.qdoc new file mode 100644 index 0000000..bc7f5ae --- /dev/null +++ b/src/gui/kernel/qdesktopwidget.qdoc @@ -0,0 +1,283 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QDesktopWidget + \brief The QDesktopWidget class provides access to screen information on multi-head systems. + + \ingroup advanced + \ingroup desktop + + Systems with more than one graphics card and monitor can manage the + physical screen space available either as multiple desktops, or as a + large virtual desktop. + + This class provides information about the user's desktop, such as its + total size, number of screens, the geometry of each screen, and whether + they are configured as separate desktops or a single virtual desktop. + + Widgets provided by Qt use this class to place tooltips, menus and + dialog boxes on the correct screen for their parent or application + widgets. Applications can use this class to obtain information that + can be used to save window positions, or to place child widgets and + dialogs on one particular screen. + + \section1 Obtaining a Desktop Widget + + The QApplication::desktop() function is used to get an instance of + QDesktopWidget. + + The widget's screenGeometry() function provides information about the + geometry of the available screens with. The number of screens + available is returned by screenCount, and the screenCountChanged() + signal is emitted when screens are added or removed. + The screen number that a particular point or widget is located in + is returned by screenNumber(). + + \section1 Screen Geometry + + To obtain the dimensions of a particular screen, call the screenGeometry() + function. On some desktop environments, not all of the screen is + available for applications to use; for example, an application dock or + menu bar may take up some space. Use the availableGeometry() function + to obtain the available area for applications. + + QDesktopWidget also inherits the QWidget properties, width() and + height(), which specify the size of the desktop. However, for + desktops with multiple screens, the size of the desktop is the union + of all the screen sizes, so width() and height() should \e not be + used for computing the size of a widget to be placed on one of the + screens. + + On systems that are configured to use the available screens as a + single, large virtual desktop, the virtualDesktop property will be + set to true. In this case, the widget's size is usually the size of + the bounding rectangle of all the screens. + + \section1 Use of the Primary Screen + + For an application, the screen where the main widget resides is the + primary screen. This is stored in the primaryScreen property. + All windows opened in the context of the application should be + constrained to the boundaries of the primary screen; for example, + it would be inconvenient if a dialog box popped up on a different + screen, or split over two screens. + + \image qdesktopwidget.png Managing Multiple Screens + + In the illustration above, Application One's primary screen is + screen 0, and App Two's primary screen is screen 1. + + \sa QApplication, QApplication::desktop(), QX11Info::appRootWindow() +*/ + +/*! + \fn QDesktopWidget::QDesktopWidget() + + \internal + + Creates the desktop widget. + + If the system supports a virtual desktop, this widget will have + the size of the virtual desktop; otherwise this widget will have + the size of the primary screen. + + Instead of using QDesktopWidget directly, use QApplication::desktop(). +*/ + +/*! + \fn QDesktopWidget::~QDesktopWidget() + + \internal + + Destroys the desktop widget and frees any allocated resources. +*/ + +/*! + \fn int QDesktopWidget::numScreens() const + + Returns the number of available screens. + + \obsolete + + This function is deprecated. Use screenCount instead. + + \sa primaryScreen +*/ + +/*! + \fn QWidget *QDesktopWidget::screen(int screen) + + Returns a widget that represents the screen with index \a screen + (a value of -1 means the default screen). + + If the system uses a virtual desktop, the returned widget will + have the geometry of the entire virtual desktop; i.e., bounding + every \a screen. + + \sa primaryScreen, screenCount, virtualDesktop +*/ + +/*! + \fn const QRect QDesktopWidget::availableGeometry(int screen) const + + Returns the available geometry of the screen with index \a screen. What + is available will be subrect of screenGeometry() based on what the + platform decides is available (for example excludes the dock and menu bar + on Mac OS X, or the task bar on Windows). The default screen is used if + \a screen is -1. + + \sa screenNumber(), screenGeometry() +*/ + +/*! + \fn const QRect QDesktopWidget::availableGeometry(const QWidget *widget) const + \overload + + Returns the available geometry of the screen which contains \a widget. + + \sa screenGeometry() +*/ + +/*! + \fn const QRect QDesktopWidget::availableGeometry(const QPoint &p) const + \overload + + Returns the available geometry of the screen which contains \a p. + + \sa screenGeometry() +*/ + + +/*! + \fn const QRect QDesktopWidget::screenGeometry(int screen) const + + Returns the geometry of the screen with index \a screen. The default + screen is used if \a screen is -1. + + \sa screenNumber() +*/ + +/*! + \fn const QRect QDesktopWidget::screenGeometry(const QWidget *widget) const + \overload + + Returns the geometry of the screen which contains \a widget. +*/ + +/*! + \fn const QRect QDesktopWidget::screenGeometry(const QPoint &p) const + \overload + + Returns the geometry of the screen which contains \a p. +*/ + + +/*! + \fn int QDesktopWidget::screenNumber(const QWidget *widget) const + + Returns the index of the screen that contains the largest + part of \a widget, or -1 if the widget not on a screen. + + \sa primaryScreen +*/ + +/*! + \fn int QDesktopWidget::screenNumber(const QPoint &point) const + + \overload + Returns the index of the screen that contains the \a point, or the + screen which is the shortest distance from the \a point. + + \sa primaryScreen +*/ + +/*! + \fn void QDesktopWidget::resizeEvent(QResizeEvent *event) + \reimp +*/ + +/*! + \fn void QDesktopWidget::resized(int screen) + + This signal is emitted when the size of \a screen changes. +*/ + +/*! + \fn void QDesktopWidget::workAreaResized(int screen) + + This signal is emitted when the work area available on \a screen changes. +*/ + +/*! + \property QDesktopWidget::screenCount + \brief the number of screens currently available on the system. + + \since 4.6 + + \sa screenCountChanged() +*/ + +/*! + \property QDesktopWidget::primaryScreen + \brief the index of the screen that is configured to be the primary screen + on the system. +*/ + +/*! + \property QDesktopWidget::virtualDesktop + + \brief if the system manages the available screens in a virtual desktop. + + For virtual desktops, screen() will always return the same widget. + The size of the virtual desktop is the size of this desktop + widget. +*/ + +/*! + \fn void QDesktopWidget::screenCountChanged(int newCount) + + \since 4.6 + + This signal is emitted when the number of screens changes to \a newCount. + + \sa screenCount +*/ diff --git a/src/gui/kernel/qdesktopwidget_mac.mm b/src/gui/kernel/qdesktopwidget_mac.mm index 04f602f..88dc173 100644 --- a/src/gui/kernel/qdesktopwidget_mac.mm +++ b/src/gui/kernel/qdesktopwidget_mac.mm @@ -97,15 +97,13 @@ QT_USE_NAMESPACE Q_GLOBAL_STATIC(QDesktopWidgetImplementation, qdesktopWidgetImplementation) QDesktopWidgetImplementation::QDesktopWidgetImplementation() - : appScreen(0), displays(0) + : appScreen(0) { onResize(); } QDesktopWidgetImplementation::~QDesktopWidgetImplementation() { - if (displays) - [displays release]; } QDesktopWidgetImplementation *QDesktopWidgetImplementation::instance() @@ -118,13 +116,7 @@ QRect QDesktopWidgetImplementation::availableRect(int screenIndex) const if (screenIndex < 0 || screenIndex >= screenCount) screenIndex = appScreen; - NSRect r = [[displays objectAtIndex:screenIndex] visibleFrame]; - NSRect primaryRect = [[displays objectAtIndex:0] frame]; - - const int flippedY = - r.origin.y + // account for position offset and - primaryRect.size.height - r.size.height; // height difference. - return QRectF(r.origin.x, flippedY, - r.size.width, r.size.height).toRect(); + return availableRects[screenIndex].toRect(); } QRect QDesktopWidgetImplementation::screenRect(int screenIndex) const @@ -132,22 +124,28 @@ QRect QDesktopWidgetImplementation::screenRect(int screenIndex) const if (screenIndex < 0 || screenIndex >= screenCount) screenIndex = appScreen; - NSRect r = [[displays objectAtIndex:screenIndex] frame]; - NSRect primaryRect = [[displays objectAtIndex:0] frame]; - - const int flippedY = - r.origin.y + // account for position offset and - primaryRect.size.height - r.size.height; // height difference. - return QRectF(r.origin.x, flippedY, - r.size.width, r.size.height).toRect(); + return screenRects[screenIndex].toRect(); } void QDesktopWidgetImplementation::onResize() { - if (displays) - [displays release]; - - displays = [[NSScreen screens] retain]; - screenCount = [displays count]; + QMacCocoaAutoReleasePool pool; + NSArray *displays = [NSScreen screens]; + screenCount = [displays count]; + + screenRects.clear(); + availableRects.clear(); + NSRect primaryRect = [[displays objectAtIndex:0] frame]; + for (int i = 0; i<screenCount; i++) { + NSRect r = [[displays objectAtIndex:i] frame]; + const int flippedY = - r.origin.y + // account for position offset and + primaryRect.size.height - r.size.height; // height difference. + screenRects.append(QRectF(r.origin.x, flippedY, + r.size.width, r.size.height)); + r = [[displays objectAtIndex:i] visibleFrame]; + availableRects.append(QRectF(r.origin.x, flippedY, + r.size.width, r.size.height)); + } } @@ -195,7 +193,7 @@ const QRect QDesktopWidget::screenGeometry(int screen) const int QDesktopWidget::screenNumber(const QWidget *widget) const { - QDesktopWidgetImplementation *d = qdesktopWidgetImplementation(); + QDesktopWidgetImplementation *d = qdesktopWidgetImplementation(); if (!widget) return d->appScreen; QRect frame = widget->frameGeometry(); @@ -216,7 +214,7 @@ int QDesktopWidget::screenNumber(const QWidget *widget) const int QDesktopWidget::screenNumber(const QPoint &point) const { - QDesktopWidgetImplementation *d = qdesktopWidgetImplementation(); + QDesktopWidgetImplementation *d = qdesktopWidgetImplementation(); int closestScreen = -1; int shortestDistance = INT_MAX; for (int i = 0; i < d->screenCount; ++i) { @@ -232,13 +230,25 @@ int QDesktopWidget::screenNumber(const QPoint &point) const void QDesktopWidget::resizeEvent(QResizeEvent *) { - QDesktopWidgetImplementation *d = qdesktopWidgetImplementation(); + QDesktopWidgetImplementation *d = qdesktopWidgetImplementation(); + + const int oldScreenCount = d->screenCount; + const QVector<QRectF> oldRects(d->screenRects); + const QVector<QRectF> oldWorks(d->availableRects); d->onResize(); - for (int i = 0; i < d->screenCount; ++i) { - emit resized(i); + for (int i = 0; i < qMin(oldScreenCount, d->screenCount); ++i) { + if (oldRects.at(i) != d->screenRects.at(i)) + emit resized(i); + } + for (int i = 0; i < qMin(oldScreenCount, d->screenCount); ++i) { + if (oldWorks.at(i) != d->availableRects.at(i)) + emit workAreaResized(i); } + + if (oldScreenCount != d->screenCount) + emit screenCountChanged(d->screenCount); } QT_END_NAMESPACE diff --git a/src/gui/kernel/qdesktopwidget_mac_p.h b/src/gui/kernel/qdesktopwidget_mac_p.h index 19772ec..2b2edd7 100644 --- a/src/gui/kernel/qdesktopwidget_mac_p.h +++ b/src/gui/kernel/qdesktopwidget_mac_p.h @@ -64,7 +64,8 @@ public: int appScreen; int screenCount; - NSArray *displays; + QVector<QRectF> availableRects; + QVector<QRectF> screenRects; QRect availableRect(int screenIndex) const; QRect screenRect(int screenIndex) const; diff --git a/src/gui/kernel/qdesktopwidget_s60.cpp b/src/gui/kernel/qdesktopwidget_s60.cpp new file mode 100644 index 0000000..43e0b85 --- /dev/null +++ b/src/gui/kernel/qdesktopwidget_s60.cpp @@ -0,0 +1,201 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $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_win.cpp b/src/gui/kernel/qdesktopwidget_win.cpp index 5286ec1..bb498ce 100644 --- a/src/gui/kernel/qdesktopwidget_win.cpp +++ b/src/gui/kernel/qdesktopwidget_win.cpp @@ -45,7 +45,7 @@ #include "qlibrary.h" #include <qvector.h> #include <limits.h> -#ifdef Q_OS_WINCE +#ifdef Q_WS_WINCE #include <sipapi.h> #endif #include "qwidget_p.h" @@ -92,7 +92,7 @@ QVector<QRect> *QDesktopWidgetPrivate::rects = 0; QVector<QRect> *QDesktopWidgetPrivate::workrects = 0; static int screen_number = 0; int QDesktopWidgetPrivate::refcount = 0; -#ifdef Q_OS_WINCE_WM +#ifdef Q_WS_WINCE_WM // Use SIP information, if available // SipGetInfo is not supported by SSDK (no definition!). static inline void qt_get_sip_info(QRect &rect) @@ -152,41 +152,27 @@ void QDesktopWidgetPrivate::init(QDesktopWidget *that) rects = new QVector<QRect>(); workrects = new QVector<QRect>(); + screenCount = 0; #ifndef Q_OS_WINCE - if (QSysInfo::WindowsVersion != QSysInfo::WV_95 && QSysInfo::WindowsVersion != QSysInfo::WV_NT) { - screenCount = 0; - // Trying to get the function pointers to Win98/2000 only functions - QLibrary user32Lib(QLatin1String("user32")); - if (!user32Lib.load()) - return; + QLibrary user32Lib(QLatin1String("user32")); + if (user32Lib.load()) { enumDisplayMonitors = (EnumFunc)user32Lib.resolve("EnumDisplayMonitors"); - QT_WA({ - getMonitorInfo = (InfoFunc)user32Lib.resolve("GetMonitorInfoW"); - } , { - getMonitorInfo = (InfoFunc)user32Lib.resolve("GetMonitorInfoA"); - }); - - if (!enumDisplayMonitors || !getMonitorInfo) { - screenCount = GetSystemMetrics(80); // SM_CMONITORS - rects->resize(screenCount); - for (int i = 0; i < screenCount; ++i) - rects->replace(i, that->rect()); - return; - } - // Calls enumCallback - enumDisplayMonitors(0, 0, enumCallback, 0); - enumDisplayMonitors = 0; - getMonitorInfo = 0; - } else { - rects->resize(1); - rects->replace(0, that->rect()); - workrects->resize(1); - workrects->replace(0, that->rect()); + getMonitorInfo = (InfoFunc)user32Lib.resolve("GetMonitorInfoW"); } -#else - screenCount = 0; + if (!enumDisplayMonitors || !getMonitorInfo) { + screenCount = GetSystemMetrics(80); // SM_CMONITORS + rects->resize(screenCount); + for (int i = 0; i < screenCount; ++i) + rects->replace(i, that->rect()); + return; + } + // Calls enumCallback + enumDisplayMonitors(0, 0, enumCallback, 0); + enumDisplayMonitors = 0; + getMonitorInfo = 0; +#else QLibrary coreLib(QLatin1String("coredll")); if (coreLib.load()) { // CE >= 4.0 case @@ -208,7 +194,7 @@ void QDesktopWidgetPrivate::init(QDesktopWidget *that) SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); QRect qr = QRect(QPoint(r.left, r.top), QPoint(r.right - 1, r.bottom - 1)); -#if defined(Q_OS_WINCE_WM) +#if defined(Q_WS_WINCE_WM) qt_get_sip_info(qr); #endif @@ -222,7 +208,7 @@ void QDesktopWidgetPrivate::init(QDesktopWidget *that) enumDisplayMonitors(0, 0, enumCallback, 0); enumDisplayMonitors = 0; getMonitorInfo = 0; -#endif // Q_OS_WINCE +#endif // Q_WS_WINCE } QDesktopWidgetPrivate::~QDesktopWidgetPrivate() @@ -303,106 +289,99 @@ QWidget *QDesktopWidget::screen(int /* screen */) const QRect QDesktopWidget::availableGeometry(int screen) const { Q_D(const QDesktopWidget); -#ifdef Q_OS_WINCE_WM +#ifdef Q_WS_WINCE_WM for(int i=0; i < d->workrects->size(); ++i) qt_get_sip_info((*d->workrects)[i]); #endif - if (QSysInfo::WindowsVersion != QSysInfo::WV_95 && QSysInfo::WindowsVersion != QSysInfo::WV_NT) { - if (screen < 0 || screen >= d->screenCount) - screen = d->primaryScreen; + if (screen < 0 || screen >= d->screenCount) + screen = d->primaryScreen; - return d->workrects->at(screen); - } else { - return d->workrects->at(d->primaryScreen); - } + return d->workrects->at(screen); } const QRect QDesktopWidget::screenGeometry(int screen) const { const QDesktopWidgetPrivate *d = d_func(); - if (QSysInfo::WindowsVersion != QSysInfo::WV_95 && QSysInfo::WindowsVersion != QSysInfo::WV_NT) { - if (screen < 0 || screen >= d->screenCount) - screen = d->primaryScreen; + if (screen < 0 || screen >= d->screenCount) + screen = d->primaryScreen; - return d->rects->at(screen); - } else { - return d->rects->at(d->primaryScreen); - } + return d->rects->at(screen); } int QDesktopWidget::screenNumber(const QWidget *widget) const { Q_D(const QDesktopWidget); - if (QSysInfo::WindowsVersion != QSysInfo::WV_95 && QSysInfo::WindowsVersion != QSysInfo::WV_NT) { - if (!widget) - return d->primaryScreen; - QRect frame = widget->frameGeometry(); - if (!widget->isWindow()) - frame.moveTopLeft(widget->mapToGlobal(QPoint(0,0))); - - int maxSize = -1; - int maxScreen = -1; - - for (int i = 0; i < d->screenCount; ++i) { - QRect sect = d->rects->at(i).intersected(frame); - int size = sect.width() * sect.height(); - if (size > maxSize && sect.width() > 0 && sect.height() > 0) { - maxSize = size; - maxScreen = i; - } - } - return maxScreen; - } else { + if (!widget) return d->primaryScreen; + + QRect frame = widget->frameGeometry(); + if (!widget->isWindow()) + frame.moveTopLeft(widget->mapToGlobal(QPoint(0,0))); + + int maxSize = -1; + int maxScreen = -1; + + for (int i = 0; i < d->screenCount; ++i) { + QRect sect = d->rects->at(i).intersected(frame); + int size = sect.width() * sect.height(); + if (size > maxSize && sect.width() > 0 && sect.height() > 0) { + maxSize = size; + maxScreen = i; + } } + + return maxScreen; } int QDesktopWidget::screenNumber(const QPoint &point) const { Q_D(const QDesktopWidget); + int closestScreen = -1; - if (QSysInfo::WindowsVersion != QSysInfo::WV_95 && QSysInfo::WindowsVersion != QSysInfo::WV_NT) { - int shortestDistance = INT_MAX; - for (int i = 0; i < d->screenCount; ++i) { - int thisDistance = d->pointToRect(point, d->rects->at(i)); - if (thisDistance < shortestDistance) { - shortestDistance = thisDistance; - closestScreen = i; - } + int shortestDistance = INT_MAX; + + for (int i = 0; i < d->screenCount; ++i) { + int thisDistance = d->pointToRect(point, d->rects->at(i)); + if (thisDistance < shortestDistance) { + shortestDistance = thisDistance; + closestScreen = i; } } + return closestScreen; } void QDesktopWidget::resizeEvent(QResizeEvent *) { Q_D(QDesktopWidget); - QVector<QRect> oldrects; - oldrects = *d->rects; - QVector<QRect> oldworkrects; - oldworkrects = *d->workrects; + const QVector<QRect> oldrects(*d->rects); + const QVector<QRect> oldworkrects(*d->workrects); int oldscreencount = d->screenCount; QDesktopWidgetPrivate::cleanup(); QDesktopWidgetPrivate::init(this); -#ifdef Q_OS_WINCE_WM +#ifdef Q_WS_WINCE_WM for(int i=0; i < d->workrects->size(); ++i) qt_get_sip_info((*d->workrects)[i]); #endif for (int i = 0; i < qMin(oldscreencount, d->screenCount); ++i) { - QRect oldrect = oldrects[i]; - QRect newrect = d->rects->at(i); + const QRect oldrect = oldrects[i]; + const 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); + const QRect oldrect = oldworkrects[j]; + const QRect newrect = d->workrects->at(j); if (oldrect != newrect) emit workAreaResized(j); } + + if (oldscreencount != d->screenCount) { + emit screenCountChanged(d->screenCount); + } } #ifdef Q_CC_MSVC diff --git a/src/gui/kernel/qdesktopwidget_x11.cpp b/src/gui/kernel/qdesktopwidget_x11.cpp index c3c826f..14eb976 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*)); } @@ -285,26 +285,36 @@ const QRect QDesktopWidget::availableGeometry(int screen) const if (d->workareas[screen].isValid()) return d->workareas[screen]; - if ((d->screenCount == 1 || !isVirtualDesktop()) - && X11->isSupportedByWM(ATOM(_NET_WORKAREA))) { + if (X11->isSupportedByWM(ATOM(_NET_WORKAREA))) { + int x11Screen = isVirtualDesktop() ? DefaultScreen(X11->display) : screen; + Atom ret; int format, e; unsigned char *data = 0; unsigned long nitems, after; e = XGetWindowProperty(X11->display, - QX11Info::appRootWindow(screen), - ATOM(_NET_WORKAREA), 0, 4, False, XA_CARDINAL, - &ret, &format, &nitems, &after, &data); + QX11Info::appRootWindow(x11Screen), + ATOM(_NET_WORKAREA), 0, 4, False, XA_CARDINAL, + &ret, &format, &nitems, &after, &data); + QRect workArea; if (e == Success && ret == XA_CARDINAL && format == 32 && nitems == 4) { long *workarea = (long *) data; - d->workareas[screen].setRect(workarea[0], workarea[1], - workarea[2], workarea[3]); + workArea = QRect(workarea[0], workarea[1], workarea[2], workarea[3]); } else { - d->workareas[screen] = screenGeometry(screen); + workArea = screenGeometry(screen); + } + + if (isVirtualDesktop()) { + // intersect the workarea (which spawns all Xinerama screens) with the rect for the + // requested screen + workArea &= screenGeometry(screen); } + + d->workareas[screen] = workArea; + if (data) XFree(data); } else { @@ -372,7 +382,23 @@ int QDesktopWidget::screenNumber(const QPoint &point) const void QDesktopWidget::resizeEvent(QResizeEvent *event) { Q_D(QDesktopWidget); + int oldScreenCount = d->screenCount; + QVector<QRect> oldRects(oldScreenCount); + for (int i = 0; i < oldScreenCount; ++i) { + oldRects[i] = d->rects[i]; + } + d->init(); + + for (int i = 0; i < qMin(oldScreenCount, d->screenCount); ++i) { + if (oldRects.at(i) != d->rects[i]) + emit resized(i); + } + + if (oldScreenCount != d->screenCount) { + emit screenCountChanged(d->screenCount); + } + qt_desktopwidget_workarea_dirty = true; QWidget::resizeEvent(event); } diff --git a/src/gui/kernel/qdnd.cpp b/src/gui/kernel/qdnd.cpp index 37c87fd..01c376f 100644 --- a/src/gui/kernel/qdnd.cpp +++ b/src/gui/kernel/qdnd.cpp @@ -368,7 +368,7 @@ QDragManager::~QDragManager() QDragManager *QDragManager::self() { - if (!instance && qApp && !qApp->closingDown()) + if (!instance && !QApplication::closingDown()) instance = new QDragManager; return instance; } diff --git a/src/gui/kernel/qdnd_mac.mm b/src/gui/kernel/qdnd_mac.mm index 1261ace..4360c54 100644 --- a/src/gui/kernel/qdnd_mac.mm +++ b/src/gui/kernel/qdnd_mac.mm @@ -405,12 +405,12 @@ bool QWidgetPrivate::qt_mac_dnd_event(uint kind, DragRef dragRef) SetDragDropAction(dragRef, qt_mac_dnd_map_qt_actions(qDEEvent.dropAction())); if (!qDEEvent.isAccepted()) - // The widget is simply not interrested in this + // The widget is simply not interested in this // drag. So tell carbon this by returning 'false'. We will then // not receive any further move, drop or leave events for this widget. return false; else { - // Documentation states that a drag move event is sendt immidiatly after + // Documentation states that a drag move event is sent immediately after // a drag enter event. So we do that. This will honor widgets overriding // 'dragMoveEvent' only, and not 'dragEnterEvent' QDragMoveEvent qDMEvent(q->mapFromGlobal(QPoint(mouse.h, mouse.v)), qtAllowed, dropdata, diff --git a/src/gui/kernel/qdnd_p.h b/src/gui/kernel/qdnd_p.h index 663a48e..b635685 100644 --- a/src/gui/kernel/qdnd_p.h +++ b/src/gui/kernel/qdnd_p.h @@ -58,6 +58,7 @@ #include "QtGui/qmime.h" #include "QtGui/qdrag.h" #include "QtGui/qpixmap.h" +#include "QtGui/qcursor.h" #include "QtCore/qpoint.h" #include "private/qobject_p.h" #ifdef Q_WS_MAC @@ -65,7 +66,7 @@ #endif #if defined(Q_WS_WIN) -# include <windows.h> +# include <qt_windows.h> # include <objidl.h> #endif @@ -202,7 +203,7 @@ public: #endif }; -class Q_GUI_EXPORT QDragManager: public QObject { +class QDragManager: public QObject { Q_OBJECT QDragManager(); @@ -265,7 +266,11 @@ private: #ifdef Q_WS_QWS Qt::DropAction currentActionForOverrideCursor; #endif - +#ifdef Q_OS_SYMBIAN +#ifndef QT_NO_CURSOR + QCursor overrideCursor; +#endif +#endif QWidget *currentDropTarget; static QDragManager *instance; diff --git a/src/gui/kernel/qdnd_s60.cpp b/src/gui/kernel/qdnd_s60.cpp new file mode 100644 index 0000000..a8d3ac5 --- /dev/null +++ b/src/gui/kernel/qdnd_s60.cpp @@ -0,0 +1,359 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $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 "qt_s60_p.h" + +#include <COECNTRL.H> +// pointer cursor +#include <w32std.h> +#include <gdi.h> +#include <QCursor> + +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; + +void QDragManager::updatePixmap() +{ + 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; + } +#ifndef QT_NO_CURSOR + QCursor cursor(pm, pm_hot.x(), pm_hot.y()); + overrideCursor = cursor; +#endif +} + +void QDragManager::timerEvent(QTimerEvent *) { } + +void QDragManager::move(const QPoint&) { +} + +void QDragManager::updateCursor() +{ +#ifndef QT_NO_CURSOR + QCursor cursor = willDrop ? overrideCursor : Qt::ForbiddenCursor; + if (!restoreCursor) { + QApplication::setOverrideCursor(cursor); + restoreCursor = true; + } + else { + QApplication::changeOverrideCursor(cursor); + } +#endif +} + + +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; + + while (cw && !cw->acceptDrops() && !cw->isWindow()) + cw = cw->parentWidget(); + + bool oldWillDrop = willDrop; + if (object->target() != cw) { + if (object->target()) { + QDragLeaveEvent dle; + QApplication::sendEvent(object->target(), &dle); + willDrop = false; + global_accepted_action = Qt::IgnoreAction; + if (oldWillDrop != willDrop) + updateCursor(); + 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; + if (oldWillDrop != willDrop) + updateCursor(); + } + } 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; + if (oldWillDrop != willDrop) { + updatePixmap(); + updateCursor(); + } + } + if (global_accepted_action != prevAction) + emitActionChanged(global_accepted_action); + } + return true; // Eat all mouse events + } + + case QEvent::MouseButtonRelease: + { + qApp->removeEventFilter(this); +#ifndef QT_NO_CURSOR + if (restoreCursor) { + QApplication::restoreOverrideCursor(); + willDrop = false; + restoreCursor = false; + } +#endif + 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; + + oldstate = Qt::NoModifier; // #### Should use state that caused the drag + willDrop = false; + updatePixmap(); + updateCursor(); + +#ifndef QT_NO_CURSOR + qt_symbian_set_cursor_visible(true); //force cursor on even for touch phone +#endif + + object->d_func()->target = 0; + + qApp->installEventFilter(this); + + global_accepted_action = defaultAction(dragPrivate()->possible_actions, Qt::NoModifier); + qt_symbian_dnd_dragging = true; + + eventLoop = new QEventLoop; + // block + (void) eventLoop->exec(QEventLoop::AllEvents); + delete eventLoop; + eventLoop = 0; + +#ifndef QT_NO_CURSOR + qt_symbian_set_cursor_visible(false); + + overrideCursor = QCursor(); //deref the cursor data + qt_symbian_dnd_dragging = false; +#endif + + 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; + } + +#ifndef QT_NO_CURSOR + if (restoreCursor) { + QApplication::restoreOverrideCursor(); + restoreCursor = false; + } +#endif + + global_accepted_action = Qt::IgnoreAction; +} + + +void QDragManager::drop() +{ +#ifndef QT_NO_CURSOR + if (restoreCursor) { + QApplication::restoreOverrideCursor(); + restoreCursor = false; + } +#endif +} + +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/qdnd_win.cpp b/src/gui/kernel/qdnd_win.cpp index b6ff066..e7afe15 100644 --- a/src/gui/kernel/qdnd_win.cpp +++ b/src/gui/kernel/qdnd_win.cpp @@ -154,9 +154,9 @@ QOleDataObject::GetData(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium) #ifdef QDND_DEBUG qDebug("QOleDataObject::GetData(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium)"); #ifndef Q_OS_WINCE - char buf[256] = {0}; - GetClipboardFormatNameA(pformatetc->cfFormat, buf, 255); - qDebug("CF = %d : %s", pformatetc->cfFormat, buf); + wchar_t buf[256] = {0}; + GetClipboardFormatName(pformatetc->cfFormat, buf, 255); + qDebug("CF = %d : %s", pformatetc->cfFormat, QString::fromWCharArray(buf)); #endif #endif @@ -398,52 +398,47 @@ void QOleDropSource::createCursors() int h = cpm.height(); if (!pm.isNull()) { - int x1 = qMin(-hotSpot.x(),0); - int x2 = qMax(pm.width()-hotSpot.x(),cpm.width()); - int y1 = qMin(-hotSpot.y(),0); - int y2 = qMax(pm.height()-hotSpot.y(),cpm.height()); + int x1 = qMin(-hotSpot.x(), 0); + int x2 = qMax(pm.width() - hotSpot.x(), cpm.width()); + int y1 = qMin(-hotSpot.y(), 0); + int y2 = qMax(pm.height() - hotSpot.y(), cpm.height()); - w = x2-x1+1; - h = y2-y1+1; + w = x2 - x1 + 1; + h = y2 - y1 + 1; } QRect srcRect = pm.rect(); QPoint pmDest = QPoint(qMax(0, -hotSpot.x()), qMax(0, -hotSpot.y())); QPoint newHotSpot = hotSpot; -#if !defined(Q_OS_WINCE) || defined(GWES_ICONCURS) - bool limitedCursorSize = (QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based) - || (QSysInfo::WindowsVersion == QSysInfo::WV_NT) - || (QSysInfo::WindowsVersion == QSysInfo::WV_CE); - - if (limitedCursorSize) { - // Limited cursor size - int reqw = GetSystemMetrics(SM_CXCURSOR); - int reqh = GetSystemMetrics(SM_CYCURSOR); - - QPoint hotspotInPM = newHotSpot - pmDest; - if (reqw < w) { - // Not wide enough - move objectpm right - qreal r = qreal(newHotSpot.x()) / w; - newHotSpot = QPoint(int(r * reqw), newHotSpot.y()); - if (newHotSpot.x() + cpm.width() > reqw) - newHotSpot.setX(reqw - cpm.width()); - - srcRect = QRect(QPoint(hotspotInPM.x() - newHotSpot.x(), srcRect.top()), QSize(reqw, srcRect.height())); - } - if (reqh < h) { - qreal r = qreal(newHotSpot.y()) / h; - newHotSpot = QPoint(newHotSpot.x(), int(r * reqh)); - if (newHotSpot.y() + cpm.height() > reqh) - newHotSpot.setY(reqh - cpm.height()); - - srcRect = QRect(QPoint(srcRect.left(), hotspotInPM.y() - newHotSpot.y()), QSize(srcRect.width(), reqh)); - } - // Always use system cursor size - w = reqw; - h = reqh; +#if defined(Q_OS_WINCE) + // Limited cursor size + int reqw = GetSystemMetrics(SM_CXCURSOR); + int reqh = GetSystemMetrics(SM_CYCURSOR); + + QPoint hotspotInPM = newHotSpot - pmDest; + if (reqw < w) { + // Not wide enough - move objectpm right + qreal r = qreal(newHotSpot.x()) / w; + newHotSpot = QPoint(int(r * reqw), newHotSpot.y()); + if (newHotSpot.x() + cpm.width() > reqw) + newHotSpot.setX(reqw - cpm.width()); + + srcRect = QRect(QPoint(hotspotInPM.x() - newHotSpot.x(), srcRect.top()), QSize(reqw, srcRect.height())); } + if (reqh < h) { + qreal r = qreal(newHotSpot.y()) / h; + newHotSpot = QPoint(newHotSpot.x(), int(r * reqh)); + if (newHotSpot.y() + cpm.height() > reqh) + newHotSpot.setY(reqh - cpm.height()); + + srcRect = QRect(QPoint(srcRect.left(), hotspotInPM.y() - newHotSpot.y()), QSize(srcRect.width(), reqh)); + } + // Always use system cursor size + w = reqw; + h = reqh; #endif + QPixmap newCursor(w, h); if (!pm.isNull()) { newCursor.fill(QColor(0, 0, 0, 0)); @@ -549,7 +544,7 @@ QOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) return ResultFromScode(DRAGDROP_S_DROP); } #endif - qApp->processEvents(); + QApplication::processEvents(); return NOERROR; } } diff --git a/src/gui/kernel/qdnd_x11.cpp b/src/gui/kernel/qdnd_x11.cpp index d5a6095..da150fb 100644 --- a/src/gui/kernel/qdnd_x11.cpp +++ b/src/gui/kernel/qdnd_x11.cpp @@ -544,6 +544,8 @@ bool QX11Data::xdndMimeDataForAtom(Atom a, QMimeData *mimeData, QByteArray *data (dm->xdndMimeTransferedPixmapIndex + 1) % 2; ret = true; } + } else { + DEBUG("QClipboard: xdndMimeDataForAtom(): converting to type '%s' is not supported", qPrintable(atomName)); } } return ret && data != 0; @@ -624,28 +626,12 @@ QVariant QX11Data::xdndMimeConvertToFormat(Atom a, const QByteArray &data, const if (format == QLatin1String("image/ppm")) { if (a == XA_PIXMAP && data.size() == sizeof(Pixmap)) { Pixmap xpm = *((Pixmap*)data.data()); - Display *dpy = display; - Window r; - int x,y; - uint w,h,bw,d; if (!xpm) return QByteArray(); - XGetGeometry(dpy,xpm, &r,&x,&y,&w,&h,&bw,&d); + QPixmap qpm = QPixmap::fromX11Pixmap(xpm); QImageWriter imageWriter; - GC gc = XCreateGC(dpy, xpm, 0, 0); - QImage imageToWrite; - if (d == 1) { - QBitmap qbm(w,h); - XCopyArea(dpy,xpm,qbm.handle(),gc,0,0,w,h,0,0); - imageWriter.setFormat("PBMRAW"); - imageToWrite = qbm.toImage(); - } else { - QPixmap qpm(w,h); - XCopyArea(dpy,xpm,qpm.handle(),gc,0,0,w,h,0,0); - imageWriter.setFormat("PPMRAW"); - imageToWrite = qpm.toImage(); - } - XFreeGC(dpy,gc); + imageWriter.setFormat("PPMRAW"); + QImage imageToWrite = qpm.toImage(); QBuffer buf; buf.open(QIODevice::WriteOnly); imageWriter.setDevice(&buf); @@ -1089,12 +1075,14 @@ void qt_xdnd_send_leave() if (!qt_xdnd_current_target) return; + QDragManager *manager = QDragManager::self(); + XClientMessageEvent leave; leave.type = ClientMessage; leave.window = qt_xdnd_current_target; leave.format = 32; leave.message_type = ATOM(XdndLeave); - leave.data.l[0] = qt_xdnd_dragsource_xid; + leave.data.l[0] = manager->dragPrivate()->source->effectiveWinId(); leave.data.l[1] = 0; // flags leave.data.l[2] = 0; // x, y leave.data.l[3] = 0; // w, h @@ -1110,8 +1098,8 @@ void qt_xdnd_send_leave() else XSendEvent(X11->display, qt_xdnd_current_proxy_target, False, NoEventMask, (XEvent*)&leave); + // reset the drag manager state - QDragManager *manager = QDragManager::self(); manager->willDrop = false; if (global_accepted_action != Qt::IgnoreAction) manager->emitActionChanged(Qt::IgnoreAction); diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index e8d8916..ad68aea 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -45,10 +45,13 @@ #include "private/qapplication_p.h" #include "private/qkeysequence_p.h" #include "qwidget.h" +#include "qgraphicsview.h" #include "qdebug.h" #include "qmime.h" #include "qdnd_p.h" #include "qevent_p.h" +#include "qgesture.h" +#include "qgesture_p.h" QT_BEGIN_NAMESPACE @@ -83,6 +86,13 @@ QInputEvent::~QInputEvent() \sa QApplication::keyboardModifiers() */ +/*! \fn void QInputEvent::setModifiers(Qt::KeyboardModifiers modifiers) + + \internal + + Sets the keyboard modifiers flags for this event. +*/ + /*! \class QMouseEvent \ingroup events @@ -106,8 +116,12 @@ QInputEvent::~QInputEvent() propagated up the parent widget chain until a widget accepts it with accept(), or an event filter consumes it. + \note If a mouse event is propagated to a \l{QWidget}{widget} for + which Qt::WA_NoMousePropagation has been set, that mouse event + will not be propagated further up the parent widget chain. + The state of the keyboard modifier keys can be found by calling the - \l{QInputEvent::modifiers()}{modifiers()} function, inhertied from + \l{QInputEvent::modifiers()}{modifiers()} function, inherited from QInputEvent. The functions pos(), x(), and y() give the cursor position @@ -663,8 +677,9 @@ QWheelEvent::QWheelEvent(const QPoint &pos, const QPoint& globalPos, int delta, The QWidget::setEnable() function can be used to enable or disable mouse and keyboard events for a widget. - The event handlers QWidget::keyPressEvent() and - QWidget::keyReleaseEvent() receive key events. + The event handlers QWidget::keyPressEvent(), QWidget::keyReleaseEvent(), + QGraphicsItem::keyPressEvent() and QGraphicsItem::keyReleaseEvent() + receive key events. \sa QFocusEvent, QWidget::grabKeyboard() */ @@ -861,6 +876,17 @@ bool QKeyEvent::matches(QKeySequence::StandardKey matchKey) const uint searchkey = (modifiers() | key()) & ~(Qt::KeypadModifier); //The keypad modifier should not make a difference uint platform = QApplicationPrivate::currentPlatform(); +#ifdef Q_WS_MAC + if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) { + uint oldSearchKey = searchkey; + searchkey &= ~(Qt::ControlModifier | Qt::MetaModifier); + if (oldSearchKey & Qt::ControlModifier) + searchkey |= Qt::MetaModifier; + if (oldSearchKey & Qt::MetaModifier) + searchkey |= Qt::ControlModifier; + } +#endif + uint N = QKeySequencePrivate::numberOfKeyBindings; int first = 0; int last = N - 1; @@ -969,8 +995,9 @@ bool QKeyEvent::matches(QKeySequence::StandardKey matchKey) const The reason for a particular focus event is returned by reason() in the appropriate event handler. - The event handlers QWidget::focusInEvent() and - QWidget::focusOutEvent() receive focus events. + The event handlers QWidget::focusInEvent(), + QWidget::focusOutEvent(), QGraphicsItem::focusInEvent and + QGraphicsItem::focusOutEvent() receive focus events. \sa QWidget::setFocus(), QWidget::setFocusPolicy(), {Keyboard Focus} */ @@ -1056,8 +1083,17 @@ Qt::FocusReason QFocusEvent::reason() const rect() that is the bounding rectangle of that region. Both are provided because many widgets can't make much use of region(), and rect() can be much faster than region().boundingRect(). + + \section1 Automatic Clipping + Painting is clipped to region() during the processing of a paint - event. + event. This clipping is performed by Qt's paint system and is + independent of any clipping that may be applied to a QPainter used to + draw on the paint device. + + As a result, the value returned by QPainter::clipRegion() on + a newly-constructed QPainter will not reflect the clip region that is + used by the paint system. \sa QPainter, QWidget::update(), QWidget::repaint(), QWidget::paintEvent() @@ -1588,12 +1624,14 @@ Qt::ButtonState QContextMenuEvent::state() const string is controlled by the widget only). The AttributeType enum describes the different attributes that can be set. - A class implementing QWidget::inputMethodEvent() should at least - understand and honor the \l TextFormat and \l Cursor attributes. + A class implementing QWidget::inputMethodEvent() or + QGraphicsItem::inputMethodEvent() should at least understand and + honor the \l TextFormat and \l Cursor attributes. Since input methods need to be able to query certain properties - from the widget, the widget must also implement - QWidget::inputMethodQuery(). + from the widget or graphics item, subclasses must also implement + QWidget::inputMethodQuery() and QGraphicsItem::inputMethodQuery(), + respectively. When receiving an input method event, the text widget has to performs the following steps: @@ -1665,6 +1703,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 */ @@ -3070,7 +3119,7 @@ QDebug operator<<(QDebug dbg, const QEvent *e) { << ", " << me->button() << ", " << hex << (int)me->buttons() << ", " << hex << (int)me->modifiers() - << ")"; + << ')'; } return dbg.space(); @@ -3091,7 +3140,7 @@ QDebug operator<<(QDebug dbg, const QEvent *e) { #ifndef QT_NO_WHEELEVENT case QEvent::Wheel: dbg.nospace() << "QWheelEvent(" << static_cast<const QWheelEvent *>(e)->delta() - << ")"; + << ')'; return dbg.space(); #endif case QEvent::KeyPress: @@ -3117,7 +3166,7 @@ QDebug operator<<(QDebug dbg, const QEvent *e) { << ", \"" << ke->text() << "\", " << ke->isAutoRepeat() << ", " << ke->count() - << ")"; + << ')'; } return dbg.space(); case QEvent::FocusIn: @@ -3311,6 +3360,9 @@ QDebug operator<<(QDebug dbg, const QEvent *e) { case QEvent::ChildRemoved: n = n ? n : "ChildRemoved"; dbg.nospace() << "QChildEvent(" << n << ", " << (static_cast<const QChildEvent*>(e))->child(); return dbg.space(); + case QEvent::Gesture: + n = "Gesture"; + break; default: dbg.nospace() << "QEvent(" << (const void *)e << ", type = " << e->type() << ')'; return dbg.space(); @@ -3507,4 +3559,942 @@ QMenubarUpdatedEvent::QMenubarUpdatedEvent(QMenuBar * const menuBar) #endif +/*! + \class QTouchEvent + \brief The QTouchEvent class contains parameters that describe a touch event. + \since 4.6 + \ingroup events + \ingroup multitouch + + \section1 Enabling Touch Events + + Touch events occur when pressing, releasing, or moving one or more touch points on a touch + device (such as a touch-screen or track-pad). To receive touch events, widgets have to have the + Qt::WA_AcceptTouchEvents attribute set and graphics items need to have the + \l{QGraphicsItem::setAcceptTouchEvents()}{acceptTouchEvents} attribute set to true. + + When using QAbstractScrollArea based widgets, you should enable the Qt::WA_AcceptTouchEvents + attribute on the scroll area's \l{QAbstractScrollArea::viewport()}{viewport}. + + Similarly to QMouseEvent, Qt automatically grabs each touch point on the first press inside a + widget, and the widget will receive all updates for the touch point until it is released. + Note that it is possible for a widget to receive events for multiple touch points, and that + multiple widgets may be receiving touch events at the same time. + + \section1 Event Handling + + All touch events are of type QEvent::TouchBegin, QEvent::TouchUpdate, or QEvent::TouchEnd. + Reimplement QWidget::event() or QAbstractScrollArea::viewportEvent() for widgets and + QGraphicsItem::sceneEvent() for items in a graphics view to receive touch events. + + The QEvent::TouchUpdate and QEvent::TouchEnd events are sent to the widget or item that + accepted the QEvent::TouchBegin event. If the QEvent::TouchBegin event is not accepted and not + filtered by an event filter, then no further touch events are sent until the next + QEvent::TouchBegin. + + The touchPoints() function returns a list of all touch points contained in the event. + Information about each touch point can be retrieved using the QTouchEvent::TouchPoint class. + The Qt::TouchPointState enum describes the different states that a touch point may have. + + \section1 Event Delivery and Propagation + + By default, QWidget::event() translates the first non-primary touch point in a QTouchEvent into + a QMouseEvent. This makes it possible to enable touch events on existing widgets that do not + normally handle QTouchEvent. See below for information on some special considerations needed + when doing this. + + QEvent::TouchBegin is the first touch event sent to a widget. The QEvent::TouchBegin event + contains a special accept flag that indicates whether the receiver wants the event. By default, + the event is accepted. You should call ignore() if the touch event is not handled by your + widget. The QEvent::TouchBegin event is propagated up the parent widget chain until a widget + accepts it with accept(), or an event filter consumes it. For QGraphicsItems, the + QEvent::TouchBegin event is propagated to items under the mouse (similar to mouse event + propagation for QGraphicsItems). + + \section1 Touch Point Grouping + + As mentioned above, it is possible that several widgets can be receiving QTouchEvents at the + same time. However, Qt makes sure to never send duplicate QEvent::TouchBegin events to the same + widget, which could theoretically happen during propagation if, for example, the user touched 2 + separate widgets in a QGroupBox and both widgets ignored the QEvent::TouchBegin event. + + To avoid this, Qt will group new touch points together using the following rules: + + \list + + \i When the first touch point is detected, the destination widget is determined firstly by the + location on screen and secondly by the propagation rules. + + \i When additional touch points are detected, Qt first looks to see if there are any active + touch points on any ancestor or descendent of the widget under the new touch point. If there + are, the new touch point is grouped with the first, and the new touch point will be sent in a + single QTouchEvent to the widget that handled the first touch point. (The widget under the new + touch point will not receive an event). + + \endlist + + This makes it possible for sibling widgets to handle touch events independently while making + sure that the sequence of QTouchEvents is always correct. + + \section1 Mouse Events and the Primary Touch Point + + QTouchEvent delivery is independent from that of QMouseEvent. On some windowing systems, mouse + events are also sent for the \l{QTouchEvent::TouchPoint::isPrimary()}{primary touch point}. + This means it is possible for your widget to receive both QTouchEvent and QMouseEvent for the + same user interaction point. You can use the QTouchEvent::TouchPoint::isPrimary() function to + identify the primary touch point. + + Note that on some systems, it is possible to receive touch events without a primary touch + point. All this means is that there will be no mouse event generated for the touch points in + the QTouchEvent. + + \section1 Caveats + + \list + + \i As mentioned above, enabling touch events means multiple widgets can be receiving touch + events simultaneously. Combined with the default QWidget::event() handling for QTouchEvents, + this gives you great flexibility in designing multi-touch user interfaces. Be aware of the + implications. For example, it is possible that the user is moving a QSlider with one finger and + pressing a QPushButton with another. The signals emitted by these widgets will be + interleaved. + + \i Recursion into the event loop using one of the exec() methods (e.g., QDialog::exec() or + QMenu::exec()) in a QTouchEvent event handler is not supported. Since there are multiple event + recipients, recursion may cause problems, including but not limited to lost events + and unexpected infinite recursion. + + \i QTouchEvents are not affected by a \l{QWidget::grabMouse()}{mouse grab} or an + \l{QApplication::activePopupWidget()}{active pop-up widget}. The behavior of QTouchEvents is + undefined when opening a pop-up or grabbing the mouse while there are multiple active touch + points. + + \endlist + + \sa QTouchEvent::TouchPoint, Qt::TouchPointState, Qt::WA_AcceptTouchEvents, + QGraphicsItem::acceptTouchEvents() +*/ + +/*! \enum Qt::TouchPointState + \since 4.6 + + This enum represents the state of a touch point at the time the + QTouchEvent occurred. + + \value TouchPointPressed The touch point is now pressed. + \value TouchPointMoved The touch point moved. + \value TouchPointStationary The touch point did not move. + \value TouchPointReleased The touch point was released. + + \omitvalue TouchPointStateMask + \omitvalue TouchPointPrimary +*/ + +/*! \enum QTouchEvent::DeviceType + + This enum represents the type of device that generated a QTouchEvent. + + \value TouchScreen In this type of device, the touch surface and display are integrated. This + means the surface and display typically have the same size, such that there + is a direct relationship between the touch points' physical positions and the + coordinate reported by QTouchEvent::TouchPoint. As a result, Qt allows the + user to interact directly with multiple QWidgets and QGraphicsItems at the + same time. + + \value TouchPad In this type of device, the touch surface is separate from the display. There + is not a direct relationship between the physical touch location and the + on-screen coordinates. Instead, they are calculated relative to the current + mouse position, and the user must use the touch-pad to move this reference + point. Unlike touch-screens, Qt allows users to only interact with a single + QWidget or QGraphicsItem at a time. +*/ + +/*! + Constructs a QTouchEvent with the given \a eventType, \a deviceType, and \a touchPoints. + The \a touchPointStates and \a modifiers are the current touch point states and keyboard + modifiers at the time of the event. +*/ +QTouchEvent::QTouchEvent(QEvent::Type eventType, + QTouchEvent::DeviceType deviceType, + Qt::KeyboardModifiers modifiers, + Qt::TouchPointStates touchPointStates, + const QList<QTouchEvent::TouchPoint> &touchPoints) + : QInputEvent(eventType, modifiers), + _widget(0), + _deviceType(deviceType), + _touchPointStates(touchPointStates), + _touchPoints(touchPoints) +{ } + +/*! + Destroys the QTouchEvent. +*/ +QTouchEvent::~QTouchEvent() +{ } + +/*! \fn QWidget *QTouchEvent::widget() const + + Returns the widget on which the event occurred. +*/ + + +/*! \fn Qt::TouchPointStates QTouchEvent::touchPointStates() const + + Returns a bitwise OR of all the touch point states for this event. +*/ + +/*! \fn const QList<QTouchEvent::TouchPoint> &QTouchEvent::touchPoints() const + + Returns the list of touch points contained in the touch event. +*/ + +/*! \fn QTouchEvent::DeviceType QTouchEvent::deviceType() const + + Returns the touch device Type, which is of type \l {QTouchEvent::DeviceType} {DeviceType}. +*/ + +/*! \fn void QTouchEvent::setWidget(QWidget *widget) + + \internal + + Sets the widget for this event. +*/ + +/*! \fn void QTouchEvent::setTouchPointStates(Qt::TouchPointStates touchPointStates) + + \internal + + Sets a bitwise OR of all the touch point states for this event. +*/ + +/*! \fn void QTouchEvent::setTouchPoints(const QList<QTouchEvent::TouchPoint> &touchPoints) + + \internal + + Sets the list of touch points for this event. +*/ + +/*! \fn void QTouchEvent::setDeviceType(DeviceType deviceType) + + \internal + + Sets the device type to \a deviceType, which is of type \l {QTouchEvent::DeviceType} + {DeviceType}. +*/ + +/*! \class QTouchEvent::TouchPoint + \brief The TouchPoint class provides information about a touch point in a QTouchEvent. + \since 4.6 +*/ + +/*! \internal + + Constructs a QTouchEvent::TouchPoint for use in a QTouchEvent. +*/ +QTouchEvent::TouchPoint::TouchPoint(int id) + : d(new QTouchEventTouchPointPrivate(id)) +{ } + +/*! \internal + + Constructs a copy of \a other. +*/ +QTouchEvent::TouchPoint::TouchPoint(const QTouchEvent::TouchPoint &other) + : d(other.d) +{ + d->ref.ref(); +} + +/*! \internal + + Destroys the QTouchEvent::TouchPoint. +*/ +QTouchEvent::TouchPoint::~TouchPoint() +{ + if (!d->ref.deref()) + delete d; +} + +/*! + Returns the id number of this touch point. + + Id numbers are globally sequential, starting at zero, meaning the + first touch point in the application has id 0, the second has id 1, + and so on. +*/ +int QTouchEvent::TouchPoint::id() const +{ + return d->id; +} + +/*! + Returns the current state of this touch point. +*/ +Qt::TouchPointState QTouchEvent::TouchPoint::state() const +{ + return Qt::TouchPointState(int(d->state) & Qt::TouchPointStateMask); +} + +/*! + Returns true if this touch point is the primary touch point. The primary touch point is the + point for which the windowing system generates mouse events. +*/ +bool QTouchEvent::TouchPoint::isPrimary() const +{ + return (d->state & Qt::TouchPointPrimary) != 0; +} + +/*! + Returns the position of this touch point, relative to the widget + or QGraphicsItem that received the event. + + \sa startPos(), lastPos(), screenPos(), scenePos(), normalizedPos() +*/ +QPointF QTouchEvent::TouchPoint::pos() const +{ + return d->rect.center(); +} + +/*! + Returns the scene position of this touch point. + + The scene position is the position in QGraphicsScene coordinates + if the QTouchEvent is handled by a QGraphicsItem::touchEvent() + reimplementation, and identical to the screen position for + widgets. + + \sa startScenePos(), lastScenePos(), pos() +*/ +QPointF QTouchEvent::TouchPoint::scenePos() const +{ + return d->sceneRect.center(); +} + +/*! + Returns the screen position of this touch point. + + \sa startScreenPos(), lastScreenPos(), pos() +*/ +QPointF QTouchEvent::TouchPoint::screenPos() const +{ + return d->screenRect.center(); +} + +/*! + Returns the normalized position of this touch point. + + The coordinates are normalized to the size of the touch device, + i.e. (0,0) is the top-left corner and (1,1) is the bottom-right corner. + + \sa startNormalizedPos(), lastNormalizedPos(), pos() +*/ +QPointF QTouchEvent::TouchPoint::normalizedPos() const +{ + return d->normalizedPos; +} + +/*! + Returns the starting position of this touch point, relative to the + widget or QGraphicsItem that received the event. + + \sa pos(), lastPos() +*/ +QPointF QTouchEvent::TouchPoint::startPos() const +{ + return d->startPos; +} + +/*! + Returns the starting scene position of this touch point. + + The scene position is the position in QGraphicsScene coordinates + if the QTouchEvent is handled by a QGraphicsItem::touchEvent() + reimplementation, and identical to the screen position for + widgets. + + \sa scenePos(), lastScenePos() +*/ +QPointF QTouchEvent::TouchPoint::startScenePos() const +{ + return d->startScenePos; +} + +/*! + Returns the starting screen position of this touch point. + + \sa screenPos(), lastScreenPos() +*/ +QPointF QTouchEvent::TouchPoint::startScreenPos() const +{ + return d->startScreenPos; +} + +/*! + Returns the normalized starting position of this touch point. + + The coordinates are normalized to the size of the touch device, + i.e. (0,0) is the top-left corner and (1,1) is the bottom-right corner. + + \sa normalizedPos(), lastNormalizedPos() +*/ +QPointF QTouchEvent::TouchPoint::startNormalizedPos() const +{ + return d->startNormalizedPos; +} + +/*! + Returns the position of this touch point from the previous touch + event, relative to the widget or QGraphicsItem that received the event. + + \sa pos(), startPos() +*/ +QPointF QTouchEvent::TouchPoint::lastPos() const +{ + return d->lastPos; +} + +/*! + Returns the scene position of this touch point from the previous + touch event. + + The scene position is the position in QGraphicsScene coordinates + if the QTouchEvent is handled by a QGraphicsItem::touchEvent() + reimplementation, and identical to the screen position for + widgets. + + \sa scenePos(), startScenePos() +*/ +QPointF QTouchEvent::TouchPoint::lastScenePos() const +{ + return d->lastScenePos; +} + +/*! + Returns the screen position of this touch point from the previous + touch event. + + \sa screenPos(), startScreenPos() +*/ +QPointF QTouchEvent::TouchPoint::lastScreenPos() const +{ + return d->lastScreenPos; +} + +/*! + Returns the normalized position of this touch point from the + previous touch event. + + The coordinates are normalized to the size of the touch device, + i.e. (0,0) is the top-left corner and (1,1) is the bottom-right corner. + + \sa normalizedPos(), startNormalizedPos() +*/ +QPointF QTouchEvent::TouchPoint::lastNormalizedPos() const +{ + return d->lastNormalizedPos; +} + +/*! + Returns the rect for this touch point, relative to the widget + or QGraphicsItem that received the event. The rect is centered + around the point returned by pos(). + + \note This function returns an empty rect if the device does not report touch point sizes. +*/ +QRectF QTouchEvent::TouchPoint::rect() const +{ + return d->rect; +} + +/*! + Returns the rect for this touch point in scene coordinates. + + \note This function returns an empty rect if the device does not report touch point sizes. + + \sa scenePos(), rect() +*/ +QRectF QTouchEvent::TouchPoint::sceneRect() const +{ + return d->sceneRect; +} + +/*! + Returns the rect for this touch point in screen coordinates. + + \note This function returns an empty rect if the device does not report touch point sizes. + + \sa screenPos(), rect() +*/ +QRectF QTouchEvent::TouchPoint::screenRect() const +{ + return d->screenRect; +} + +/*! + Returns the pressure of this touch point. The return value is in + the range 0.0 to 1.0. +*/ +qreal QTouchEvent::TouchPoint::pressure() const +{ + return d->pressure; +} + +/*! \internal */ +void QTouchEvent::TouchPoint::setId(int id) +{ + if (d->ref != 1) + d = d->detach(); + d->id = id; +} + +/*! \internal */ +void QTouchEvent::TouchPoint::setState(Qt::TouchPointStates state) +{ + if (d->ref != 1) + d = d->detach(); + d->state = state; +} + +/*! \internal */ +void QTouchEvent::TouchPoint::setPos(const QPointF &pos) +{ + if (d->ref != 1) + d = d->detach(); + d->rect.moveCenter(pos); +} + +/*! \internal */ +void QTouchEvent::TouchPoint::setScenePos(const QPointF &scenePos) +{ + if (d->ref != 1) + d = d->detach(); + d->sceneRect.moveCenter(scenePos); +} + +/*! \internal */ +void QTouchEvent::TouchPoint::setScreenPos(const QPointF &screenPos) +{ + if (d->ref != 1) + d = d->detach(); + d->screenRect.moveCenter(screenPos); +} + +/*! \internal */ +void QTouchEvent::TouchPoint::setNormalizedPos(const QPointF &normalizedPos) +{ + if (d->ref != 1) + d = d->detach(); + d->normalizedPos = normalizedPos; +} + +/*! \internal */ +void QTouchEvent::TouchPoint::setStartPos(const QPointF &startPos) +{ + if (d->ref != 1) + d = d->detach(); + d->startPos = startPos; +} + +/*! \internal */ +void QTouchEvent::TouchPoint::setStartScenePos(const QPointF &startScenePos) +{ + if (d->ref != 1) + d = d->detach(); + d->startScenePos = startScenePos; +} + +/*! \internal */ +void QTouchEvent::TouchPoint::setStartScreenPos(const QPointF &startScreenPos) +{ + if (d->ref != 1) + d = d->detach(); + d->startScreenPos = startScreenPos; +} + +/*! \internal */ +void QTouchEvent::TouchPoint::setStartNormalizedPos(const QPointF &startNormalizedPos) +{ + if (d->ref != 1) + d = d->detach(); + d->startNormalizedPos = startNormalizedPos; +} + +/*! \internal */ +void QTouchEvent::TouchPoint::setLastPos(const QPointF &lastPos) +{ + if (d->ref != 1) + d = d->detach(); + d->lastPos = lastPos; +} + +/*! \internal */ +void QTouchEvent::TouchPoint::setLastScenePos(const QPointF &lastScenePos) +{ + if (d->ref != 1) + d = d->detach(); + d->lastScenePos = lastScenePos; +} + +/*! \internal */ +void QTouchEvent::TouchPoint::setLastScreenPos(const QPointF &lastScreenPos) +{ + if (d->ref != 1) + d = d->detach(); + d->lastScreenPos = lastScreenPos; +} + +/*! \internal */ +void QTouchEvent::TouchPoint::setLastNormalizedPos(const QPointF &lastNormalizedPos) +{ + if (d->ref != 1) + d = d->detach(); + d->lastNormalizedPos = lastNormalizedPos; +} + +/*! \internal */ +void QTouchEvent::TouchPoint::setRect(const QRectF &rect) +{ + if (d->ref != 1) + d = d->detach(); + d->rect = rect; +} + +/*! \internal */ +void QTouchEvent::TouchPoint::setSceneRect(const QRectF &sceneRect) +{ + if (d->ref != 1) + d = d->detach(); + d->sceneRect = sceneRect; +} + +/*! \internal */ +void QTouchEvent::TouchPoint::setScreenRect(const QRectF &screenRect) +{ + if (d->ref != 1) + d = d->detach(); + d->screenRect = screenRect; +} + +/*! \internal */ +void QTouchEvent::TouchPoint::setPressure(qreal pressure) +{ + if (d->ref != 1) + d = d->detach(); + d->pressure = pressure; +} + +/*! \internal */ +QTouchEvent::TouchPoint &QTouchEvent::TouchPoint::operator=(const QTouchEvent::TouchPoint &other) +{ + other.d->ref.ref(); + if (!d->ref.deref()) + delete d; + d = other.d; + return *this; +} + +/*! + \class QGestureEvent + \since 4.6 + \ingroup events + \ingroup gestures + + \brief The QGestureEvent class provides the description of triggered gestures. + + The QGestureEvent class contains a list of gestures, which can be obtained using the + gestures() function. + + The gestures are either active or canceled. A list of those that are currently being + executed can be obtained using the activeGestures() function. A list of those which + were previously active and have been canceled can be accessed using the + canceledGestures() function. A gesture might be canceled if the current window loses + focus, for example, or because of a timeout, or for other reasons. + + If the event handler does not accept the event by calling the generic + QEvent::accept() function, all individual QGesture object that were not + accepted and in the Qt::GestureStarted state will be propagated up the + parent widget chain until a widget accepts them individually, by calling + QGestureEvent::accept() for each of them, or an event filter consumes the + event. + + \sa QGesture, QGestureRecognizer, + QWidget::grabGesture(), QGraphicsObject::grabGesture() +*/ + +/*! + Creates new QGestureEvent containing a list of \a gestures. +*/ +QGestureEvent::QGestureEvent(const QList<QGesture *> &gestures) + : QEvent(QEvent::Gesture) +{ + d = reinterpret_cast<QEventPrivate *>(new QGestureEventPrivate(gestures)); +} + +/*! + Destroys QGestureEvent. +*/ +QGestureEvent::~QGestureEvent() +{ + delete reinterpret_cast<QGestureEventPrivate *>(d); +} + +/*! + Returns all gestures that are delivered in the event. +*/ +QList<QGesture *> QGestureEvent::gestures() const +{ + return d_func()->gestures; +} + +/*! + Returns a gesture object by \a type. +*/ +QGesture *QGestureEvent::gesture(Qt::GestureType type) const +{ + const QGestureEventPrivate *d = d_func(); + for(int i = 0; i < d->gestures.size(); ++i) + if (d->gestures.at(i)->gestureType() == type) + return d->gestures.at(i); + return 0; +} + +/*! + Returns a list of active (not canceled) gestures. +*/ +QList<QGesture *> QGestureEvent::activeGestures() const +{ + QList<QGesture *> gestures; + foreach (QGesture *gesture, d_func()->gestures) { + if (gesture->state() != Qt::GestureCanceled) + gestures.append(gesture); + } + return gestures; +} + +/*! + Returns a list of canceled gestures. +*/ +QList<QGesture *> QGestureEvent::canceledGestures() const +{ + QList<QGesture *> gestures; + foreach (QGesture *gesture, d_func()->gestures) { + if (gesture->state() == Qt::GestureCanceled) + gestures.append(gesture); + } + return gestures; +} + +/*! + Sets the accept flag of the given \a gesture object to the specified \a value. + + Setting the accept flag indicates that the event receiver wants the \a gesture. + Unwanted gestures may be propagated to the parent widget. + + By default, gestures in events of type QEvent::Gesture are accepted, and + gestures in QEvent::GestureOverride events are ignored. + + For convenience, the accept flag can also be set with + \l{QGestureEvent::accept()}{accept(gesture)}, and cleared with + \l{QGestureEvent::ignore()}{ignore(gesture)}. +*/ +void QGestureEvent::setAccepted(QGesture *gesture, bool value) +{ + if (gesture) + setAccepted(gesture->gestureType(), value); +} + +/*! + Sets the accept flag of the given \a gesture object, the equivalent of calling + \l{QGestureEvent::setAccepted()}{setAccepted(gesture, true)}. + + Setting the accept flag indicates that the event receiver wants the + gesture. Unwanted gestures may be propagated to the parent widget. + + \sa QGestureEvent::ignore() +*/ +void QGestureEvent::accept(QGesture *gesture) +{ + if (gesture) + setAccepted(gesture->gestureType(), true); +} + +/*! + Clears the accept flag parameter of the given \a gesture object, the equivalent + of calling \l{QGestureEvent::setAccepted()}{setAccepted(gesture, false)}. + + Clearing the accept flag indicates that the event receiver does not + want the gesture. Unwanted gestures may be propgated to the parent widget. + + \sa QGestureEvent::accept() +*/ +void QGestureEvent::ignore(QGesture *gesture) +{ + if (gesture) + setAccepted(gesture->gestureType(), false); +} + +/*! + Returns true if the \a gesture is accepted; otherwise returns false. +*/ +bool QGestureEvent::isAccepted(QGesture *gesture) const +{ + return gesture ? isAccepted(gesture->gestureType()) : false; +} + +/*! + Sets the accept flag of the given \a gestureType object to the specified + \a value. + + Setting the accept flag indicates that the event receiver wants to receive + gestures of the specified type, \a gestureType. Unwanted gestures may be + propagated to the parent widget. + + By default, gestures in events of type QEvent::Gesture are accepted, and + gestures in QEvent::GestureOverride events are ignored. + + For convenience, the accept flag can also be set with + \l{QGestureEvent::accept()}{accept(gestureType)}, and cleared with + \l{QGestureEvent::ignore()}{ignore(gestureType)}. +*/ +void QGestureEvent::setAccepted(Qt::GestureType gestureType, bool value) +{ + setAccepted(false); + d_func()->accepted[gestureType] = value; +} + +/*! + Sets the accept flag of the given \a gestureType, the equivalent of calling + \l{QGestureEvent::setAccepted()}{setAccepted(gestureType, true)}. + + Setting the accept flag indicates that the event receiver wants the + gesture. Unwanted gestures may be propagated to the parent widget. + + \sa QGestureEvent::ignore() +*/ +void QGestureEvent::accept(Qt::GestureType gestureType) +{ + setAccepted(gestureType, true); +} + +/*! + Clears the accept flag parameter of the given \a gestureType, the equivalent + of calling \l{QGestureEvent::setAccepted()}{setAccepted(gesture, false)}. + + Clearing the accept flag indicates that the event receiver does not + want the gesture. Unwanted gestures may be propgated to the parent widget. + + \sa QGestureEvent::accept() +*/ +void QGestureEvent::ignore(Qt::GestureType gestureType) +{ + setAccepted(gestureType, false); +} + +/*! + Returns true if the gesture of type \a gestureType is accepted; otherwise + returns false. +*/ +bool QGestureEvent::isAccepted(Qt::GestureType gestureType) const +{ + return d_func()->accepted.value(gestureType, true); +} + +/*! + \internal + + Sets the widget for this event to the \a widget specified. +*/ +void QGestureEvent::setWidget(QWidget *widget) +{ + d_func()->widget = widget; +} + +/*! + Returns the widget on which the event occurred. +*/ +QWidget *QGestureEvent::widget() const +{ + return d_func()->widget; +} + +#ifndef QT_NO_GRAPHICSVIEW +/*! + Returns the scene-local coordinates if the \a gesturePoint is inside a + graphics view. + + This functional might be useful when the gesture event is delivered to a + QGraphicsObject to translate a point in screen coordinates to scene-local + coordinates. + + \sa QPointF::isNull(). +*/ +QPointF QGestureEvent::mapToGraphicsScene(const QPointF &gesturePoint) const +{ + QWidget *w = widget(); + if (w) // we get the viewport as widget, not the graphics view + w = w->parentWidget(); + QGraphicsView *view = qobject_cast<QGraphicsView*>(w); + if (view) { + return view->mapToScene(view->mapFromGlobal(gesturePoint.toPoint())); + } + return QPointF(); +} +#endif //QT_NO_GRAPHICSVIEW + +/*! + \internal +*/ +QGestureEventPrivate *QGestureEvent::d_func() +{ + return reinterpret_cast<QGestureEventPrivate *>(d); +} + +/*! + \internal +*/ +const QGestureEventPrivate *QGestureEvent::d_func() const +{ + return reinterpret_cast<const QGestureEventPrivate *>(d); +} + +#ifdef Q_NO_USING_KEYWORD +/*! + \fn void QGestureEvent::setAccepted(bool accepted) + + Sets or clears the event's internal flag that determines whether it should + be delivered to other objects. + + Calling this function with a value of true for \a accepted indicates that the + caller has accepted the event and that it should not be propagated further. + Calling this function with a value of false indicates that the caller has + ignored the event and that it should be delivered to other objects. + + For convenience, the accept flag can also be set with accept(), and cleared + with ignore(). + + \sa QEvent::accepted +*/ +/*! + \fn bool QGestureEvent::isAccepted() const + + Returns true is the event has been accepted; otherwise returns false. + + \sa QEvent::accepted +*/ +/*! + \fn void QGestureEvent::accept() + + Accepts the event, the equivalent of calling setAccepted(true). + + \sa QEvent::accept() +*/ +/*! + \fn void QGestureEvent::ignore() + + Ignores the event, the equivalent of calling setAccepted(false). + + \sa QEvent::ignore() +*/ +#endif + QT_END_NAMESPACE diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index 7bcdd38..b9512fa 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -52,6 +52,8 @@ #include <QtGui/qmime.h> #include <QtGui/qdrag.h> #include <QtCore/qvariant.h> +#include <QtCore/qmap.h> +#include <QtCore/qset.h> QT_BEGIN_HEADER @@ -60,6 +62,7 @@ QT_BEGIN_NAMESPACE QT_MODULE(Gui) class QAction; +class QGesture; class Q_GUI_EXPORT QInputEvent : public QEvent { @@ -67,6 +70,7 @@ public: QInputEvent(Type type, Qt::KeyboardModifiers modifiers = Qt::NoModifier); ~QInputEvent(); inline Qt::KeyboardModifiers modifiers() const { return modState; } + inline void setModifiers(Qt::KeyboardModifiers amodifiers) { modState = amodifiers; } protected: Qt::KeyboardModifiers modState; }; @@ -241,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) @@ -424,7 +428,8 @@ public: TextFormat, Cursor, Language, - Ruby + Ruby, + Selection }; class Attribute { public: @@ -680,7 +685,7 @@ public: QClipboardEvent(QEventPrivate *data); ~QClipboardEvent(); - QEventPrivate *data() { return d; }; + QEventPrivate *data() { return d; } }; #endif @@ -719,6 +724,153 @@ inline bool operator==(QKeyEvent *e, QKeySequence::StandardKey key){return (e ? inline bool operator==(QKeySequence::StandardKey key, QKeyEvent *e){return (e ? e->matches(key) : false);} #endif // QT_NO_SHORTCUT +class QTouchEventTouchPointPrivate; +class Q_GUI_EXPORT QTouchEvent : public QInputEvent +{ +public: + class Q_GUI_EXPORT TouchPoint + { + public: + TouchPoint(int id = -1); + TouchPoint(const QTouchEvent::TouchPoint &other); + ~TouchPoint(); + + int id() const; + + Qt::TouchPointState state() const; + bool isPrimary() const; + + QPointF pos() const; + QPointF startPos() const; + QPointF lastPos() const; + + QPointF scenePos() const; + QPointF startScenePos() const; + QPointF lastScenePos() const; + + QPointF screenPos() const; + QPointF startScreenPos() const; + QPointF lastScreenPos() const; + + QPointF normalizedPos() const; + QPointF startNormalizedPos() const; + QPointF lastNormalizedPos() const; + + QRectF rect() const; + QRectF sceneRect() const; + QRectF screenRect() const; + + qreal pressure() const; + + // internal + void setId(int id); + void setState(Qt::TouchPointStates state); + void setPos(const QPointF &pos); + void setScenePos(const QPointF &scenePos); + void setScreenPos(const QPointF &screenPos); + void setNormalizedPos(const QPointF &normalizedPos); + void setStartPos(const QPointF &startPos); + void setStartScenePos(const QPointF &startScenePos); + void setStartScreenPos(const QPointF &startScreenPos); + void setStartNormalizedPos(const QPointF &startNormalizedPos); + void setLastPos(const QPointF &lastPos); + void setLastScenePos(const QPointF &lastScenePos); + void setLastScreenPos(const QPointF &lastScreenPos); + void setLastNormalizedPos(const QPointF &lastNormalizedPos); + void setRect(const QRectF &rect); + void setSceneRect(const QRectF &sceneRect); + void setScreenRect(const QRectF &screenRect); + void setPressure(qreal pressure); + QTouchEvent::TouchPoint &operator=(const QTouchEvent::TouchPoint &other); + + private: + QTouchEventTouchPointPrivate *d; + }; + + enum DeviceType { + TouchScreen, + TouchPad + }; + + QTouchEvent(QEvent::Type eventType, + QTouchEvent::DeviceType deviceType = TouchScreen, + Qt::KeyboardModifiers modifiers = Qt::NoModifier, + Qt::TouchPointStates touchPointStates = 0, + const QList<QTouchEvent::TouchPoint> &touchPoints = QList<QTouchEvent::TouchPoint>()); + ~QTouchEvent(); + + inline QWidget *widget() const { return _widget; } + inline QTouchEvent::DeviceType deviceType() const { return _deviceType; } + inline Qt::TouchPointStates touchPointStates() const { return _touchPointStates; } + inline const QList<QTouchEvent::TouchPoint> &touchPoints() const { return _touchPoints; } + + // internal + inline void setWidget(QWidget *awidget) { _widget = awidget; } + inline void setDeviceType(DeviceType adeviceType) { _deviceType = adeviceType; } + inline void setTouchPointStates(Qt::TouchPointStates aTouchPointStates) { _touchPointStates = aTouchPointStates; } + inline void setTouchPoints(const QList<QTouchEvent::TouchPoint> &atouchPoints) { _touchPoints = atouchPoints; } + +protected: + QWidget *_widget; + QTouchEvent::DeviceType _deviceType; + Qt::TouchPointStates _touchPointStates; + QList<QTouchEvent::TouchPoint> _touchPoints; + + friend class QApplicationPrivate; +}; + +class QGesture; +class QGestureEventPrivate; +class Q_GUI_EXPORT QGestureEvent : public QEvent +{ +public: + QGestureEvent(const QList<QGesture *> &gestures); + ~QGestureEvent(); + + QList<QGesture *> gestures() const; + QGesture *gesture(Qt::GestureType type) const; + + QList<QGesture *> activeGestures() const; + QList<QGesture *> canceledGestures() const; + +#ifdef Q_NO_USING_KEYWORD + inline void setAccepted(bool accepted) { QEvent::setAccepted(accepted); } + inline bool isAccepted() const { return QEvent::isAccepted(); } + + inline void accept() { QEvent::accept(); } + inline void ignore() { QEvent::ignore(); } +#else + using QEvent::setAccepted; + using QEvent::isAccepted; + using QEvent::accept; + using QEvent::ignore; +#endif + + void setAccepted(QGesture *, bool); + void accept(QGesture *); + void ignore(QGesture *); + bool isAccepted(QGesture *) const; + + void setAccepted(Qt::GestureType, bool); + void accept(Qt::GestureType); + void ignore(Qt::GestureType); + bool isAccepted(Qt::GestureType) const; + + void setWidget(QWidget *widget); + QWidget *widget() const; + +#ifndef QT_NO_GRAPHICSVIEW + QPointF mapToGraphicsScene(const QPointF &gesturePoint) const; +#endif + +private: + QGestureEventPrivate *d_func(); + const QGestureEventPrivate *d_func() const; + + friend class QApplication; + friend class QGestureManager; +}; + QT_END_NAMESPACE QT_END_HEADER diff --git a/src/gui/kernel/qevent_p.h b/src/gui/kernel/qevent_p.h index b33cc6b..6e6ab01 100644 --- a/src/gui/kernel/qevent_p.h +++ b/src/gui/kernel/qevent_p.h @@ -43,6 +43,7 @@ #define QEVENT_P_H #include <QtCore/qglobal.h> +#include <QtGui/qevent.h> QT_BEGIN_NAMESPACE @@ -58,7 +59,7 @@ QT_BEGIN_NAMESPACE // // ### Qt 5: remove -class Q_GUI_EXPORT QKeyEventEx : public QKeyEvent +class QKeyEventEx : public QKeyEvent { public: QKeyEventEx(Type type, int key, Qt::KeyboardModifiers modifiers, @@ -76,7 +77,7 @@ protected: }; // ### Qt 5: remove -class Q_GUI_EXPORT QMouseEventEx : public QMouseEvent +class QMouseEventEx : public QMouseEvent { public: QMouseEventEx(Type type, const QPointF &pos, const QPoint &globalPos, @@ -89,6 +90,80 @@ protected: friend class QMouseEvent; }; +class QTouchEventTouchPointPrivate +{ +public: + inline QTouchEventTouchPointPrivate(int id) + : ref(1), + id(id), + state(Qt::TouchPointReleased), + pressure(qreal(-1.)) + { } + + inline QTouchEventTouchPointPrivate *detach() + { + QTouchEventTouchPointPrivate *d = new QTouchEventTouchPointPrivate(*this); + d->ref = 1; + if (!this->ref.deref()) + delete this; + return d; + } + + QAtomicInt ref; + int id; + Qt::TouchPointStates state; + QRectF rect, sceneRect, screenRect; + QPointF normalizedPos, + startPos, startScenePos, startScreenPos, startNormalizedPos, + lastPos, lastScenePos, lastScreenPos, lastNormalizedPos; + qreal pressure; +}; + +class QNativeGestureEvent : public QEvent +{ +public: + enum Type { + None, + GestureBegin, + GestureEnd, + Pan, + Zoom, + Rotate, + Swipe + }; + + QNativeGestureEvent() + : QEvent(QEvent::NativeGesture), gestureType(None), percentage(0) +#ifdef Q_WS_WIN + , sequenceId(0), argument(0) +#endif + { + } + + Type gestureType; + float percentage; + QPoint position; + float angle; +#ifdef Q_WS_WIN + ulong sequenceId; + quint64 argument; +#endif +}; + +class QGestureEventPrivate +{ +public: + inline QGestureEventPrivate(const QList<QGesture *> &list) + : gestures(list), widget(0) + { + } + + QList<QGesture *> gestures; + QWidget *widget; + QMap<Qt::GestureType, bool> accepted; + QMap<Qt::GestureType, QWidget *> targetWidgets; +}; + QT_END_NAMESPACE #endif // QEVENT_P_H diff --git a/src/gui/kernel/qeventdispatcher_mac.mm b/src/gui/kernel/qeventdispatcher_mac.mm index 3fc7f2d..c9dd949 100644 --- a/src/gui/kernel/qeventdispatcher_mac.mm +++ b/src/gui/kernel/qeventdispatcher_mac.mm @@ -136,14 +136,19 @@ void QEventDispatcherMacPrivate::activateTimer(CFRunLoopTimerRef, void *info) if (tmr == 0 || tmr->pending == true) return; // Can't send another timer event if it's pending. - tmr->pending = true; - QTimerEvent e(tmr->id); - qt_sendSpontaneousEvent(tmr->obj, &e); - // Get the value again in case the timer gets unregistered during the sendEvent. - tmr = macTimerHash.value(timerID); - if (tmr != 0) - tmr->pending = false; + if (blockSendPostedEvents) { + QCoreApplication::postEvent(tmr->obj, new QTimerEvent(tmr->id)); + } else { + tmr->pending = true; + QTimerEvent e(tmr->id); + qt_sendSpontaneousEvent(tmr->obj, &e); + // Get the value again in case the timer gets unregistered during the sendEvent. + tmr = macTimerHash.value(timerID); + if (tmr != 0) + tmr->pending = false; + } + } void QEventDispatcherMac::registerTimer(int timerId, int interval, QObject *obj) @@ -497,6 +502,40 @@ static bool IsMouseOrKeyEvent( NSEvent* event ) } #endif +static inline void qt_mac_waitForMoreEvents() +{ +#ifndef QT_MAC_USE_COCOA + while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e20, true) == kCFRunLoopRunTimedOut) ; +#else + // If no event exist in the cocoa event que, wait + // (and free up cpu time) until at least one event occur. + // This implementation is a bit on the edge, but seems to + // work fine: + NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:[NSDate distantFuture] + inMode:NSDefaultRunLoopMode + dequeue:YES]; + if (event) + [NSApp postEvent:event atStart:YES]; +#endif +} + +#ifdef QT_MAC_USE_COCOA +static inline void qt_mac_waitForMoreModalSessionEvents() +{ + // If no event exist in the cocoa event que, wait + // (and free up cpu time) until at least one event occur. + // This implementation is a bit on the edge, but seems to + // work fine: + NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:[NSDate distantFuture] + inMode:NSModalPanelRunLoopMode + dequeue:YES]; + if (event) + [NSApp postEvent:event atStart:YES]; +} +#endif + bool QEventDispatcherMac::processEvents(QEventLoop::ProcessEventsFlags flags) { Q_D(QEventDispatcherMac); @@ -506,16 +545,6 @@ bool QEventDispatcherMac::processEvents(QEventLoop::ProcessEventsFlags flags) wakeUp(); emit awake(); -#ifndef QT_MAC_NO_QUICKDRAW - if(!qt_mac_safe_pdev) { //create an empty widget and this can be used for a port anytime - QWidget *tlw = new QWidget; - tlw->setAttribute(Qt::WA_DeleteOnClose); - tlw->setObjectName(QLatin1String("empty_widget")); - tlw->hide(); - qt_mac_safe_pdev = tlw; - } -#endif - bool retVal = false; forever { if (d->interrupt) @@ -525,55 +554,42 @@ bool QEventDispatcherMac::processEvents(QEventLoop::ProcessEventsFlags flags) QMacCocoaAutoReleasePool pool; NSEvent* event = 0; - if (flags & QEventLoop::DialogExec || flags & QEventLoop::EventLoopExec) { - // The point of the CocoaRequestModal event is to make sure that a - // non-execed app modal window recurses into it's own dialog exec - // once cocoa is spinning the event loop for us (e.g on top of [NSApp run]). - // We expect only one event to notify us about this, regardless of how many - // widgets that are waiting to be modal. So we remove all other pending - // events, if any. And since cocoa will now take over event processing for us, - // we allow new app modal widgets to recurse on top of us, hence the release of - // the block: - QBoolBlocker block(d->blockCocoaRequestModal, false); - QCoreApplication::removePostedEvents(qApp, QEvent::CocoaRequestModal); - - if (NSModalSession session = d->activeModalSession()) - while ([NSApp runModalSession:session] == NSRunContinuesResponse) { - // runModalSession will not wait for events, so we do it - // ourselves (otherwise we would spend 100% CPU inside this loop): - event = [NSApp nextEventMatchingMask:NSAnyEventMask - untilDate:[NSDate distantFuture] inMode:NSModalPanelRunLoopMode dequeue:YES]; - if (event) - [NSApp postEvent:event atStart:YES]; - } - else + // If Qt is used as a plugin, or just added into a native cocoa + // application, we should not run or stop NSApplication; + // This will be done from outside Qt. + // And if processEvents is called manually (rather than from QEventLoop), we + // cannot enter a tight loop and block the call, but instead return after one flush: + bool canExec_3rdParty = d->nsAppRunCalledByQt || ![NSApp isRunning]; + bool canExec_Qt = flags & QEventLoop::DialogExec || flags & QEventLoop::EventLoopExec; + + if (canExec_Qt && canExec_3rdParty) { + // We can use exec-mode, meaning that we can stay in a tight loop until + // interrupted. This is mostly an optimization, but it also allow us + // to use [NSApp run], which is the recommended way of running applications + // in cocoa. [NSApp run] should be called at least once for any cocoa app. + if (NSModalSession session = d->currentModalSession()) { + QBoolBlocker execGuard(d->currentExecIsNSAppRun, false); + while (!d->interrupt && [NSApp runModalSession:session] == NSRunContinuesResponse) + qt_mac_waitForMoreModalSessionEvents(); + } else { + d->nsAppRunCalledByQt = true; + QBoolBlocker execGuard(d->currentExecIsNSAppRun, true); [NSApp run]; - - d->rebuildModalSessionStack(false); + } retVal = true; } else do { - // Since we now are going to spin the event loop just _one_ round - // we need to block all incoming CocoaRequestModal events to ensure - // that we don't recurse into a new exec-ing event loop while doing - // so (and as such, 'hang' the thread inside the recursion): - QBoolBlocker block(d->blockCocoaRequestModal, true); + // INVARIANT: We cannot block the thread (and run in a tight loop). + // Instead we will process all current pending events and return. bool mustRelease = false; if (!(flags & QEventLoop::ExcludeUserInputEvents) && !d->queuedUserInputEvents.isEmpty()) { - // process a pending user input event + // Process a pending user input event mustRelease = true; event = static_cast<NSEvent *>(d->queuedUserInputEvents.takeFirst()); } else { - if (NSModalSession session = d->activeModalSession()) { - // There's s a modal widget showing, run it's session: - if (flags & QEventLoop::WaitForMoreEvents) { - // Wait for at least one event - // before spinning the session: - event = [NSApp nextEventMatchingMask:NSAnyEventMask - untilDate:[NSDate distantFuture] inMode:NSModalPanelRunLoopMode dequeue:YES]; - if (event) - [NSApp postEvent:event atStart:YES]; - } + if (NSModalSession session = d->currentModalSession()) { + if (flags & QEventLoop::WaitForMoreEvents) + qt_mac_waitForMoreModalSessionEvents(); [NSApp runModalSession:session]; retVal = true; break; @@ -644,41 +660,35 @@ bool QEventDispatcherMac::processEvents(QEventLoop::ProcessEventsFlags flags) && (flags & QEventLoop::WaitForMoreEvents)); if (canWait) { // INVARIANT: We haven't processed any events yet. And we're told - // to stay inside this function until at least one event is processed - // (WaitForMoreEvents). So we wait on the window server: -#ifndef QT_MAC_USE_COCOA - while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e20, true) == kCFRunLoopRunTimedOut); -#else - QMacCocoaAutoReleasePool pool; - NSEvent *manualEvent = [NSApp nextEventMatchingMask:NSAnyEventMask - untilDate:[NSDate distantFuture] inMode:NSDefaultRunLoopMode - dequeue:YES]; - if (manualEvent) - [NSApp sendEvent:manualEvent]; -#endif + // to stay inside this function until at least one event is processed. + qt_mac_waitForMoreEvents(); flags &= ~QEventLoop::WaitForMoreEvents; } else { - // Done with event processing for now. Leave the function: + // Done with event processing for now. + // Leave the function: break; } } - // Because pending deffered-delete events are only sendt after - // returning from the loop level they were posted in, we schedule - // an extra wakup to force the _current_ run loop to process them (in - // case the application stands idle waiting for the delete event): - wakeUp(); +#ifdef QT_MAC_USE_COCOA + // In case we _now_ process events using [NSApp run], we need to stop it to + // ensure that: + // 1. the QEventLoop that called us is still executing, or + // 2. we have a modal session that needs to be spun instead. + // In case this is a plain call to processEvents (perhaps from a loop) + // from the application (rather than from a QEventLoop), we delay the + // interrupting until we/ actually enter a lower loop level (hence the + // deffered delete of the object below): + QtMacInterruptDispatcherHelp::interruptLater(); +#endif - if (d->interrupt){ - // We restart NSApplication by first stopping it, and then call 'run' - // again (NSApplication is actually already stopped, hence the need - // for a restart, but calling stop again will also make the call - // return from the current recursion). When the call returns to - // QEventLoop (mind, not from this recursion, but from the one we're - // about to stop), it will just call QEventDispatcherMac::processEvents() - // again. + if (d->interrupt) { + // We should continue to leave all recursion to processEvents until + // processEvents is called again (e.g. from a QEventLoop that + // was not yet told to quit: interrupt(); } + return retVal; } @@ -710,104 +720,169 @@ bool QEventDispatcherMacPrivate::blockSendPostedEvents = false; #ifdef QT_MAC_USE_COCOA QStack<QCocoaModalSessionInfo> QEventDispatcherMacPrivate::cocoaModalSessionStack; -bool QEventDispatcherMacPrivate::blockCocoaRequestModal = false; +bool QEventDispatcherMacPrivate::currentExecIsNSAppRun = false; +bool QEventDispatcherMacPrivate::nsAppRunCalledByQt = false; +NSModalSession QEventDispatcherMacPrivate::currentModalSessionCached = 0; + +int QEventDispatcherMacPrivate::activeModalSessionCount() +{ + // Returns the number of modal sessions created + // (and not just pushed onto the stack, pending to be created) + int count = 0; + for (int i=cocoaModalSessionStack.size()-1; i>=0; --i) { + QCocoaModalSessionInfo &info = cocoaModalSessionStack[i]; + if (info.session) + ++count; + } + return count; +} + +void QEventDispatcherMacPrivate::temporarilyStopAllModalSessions() +{ + // Stop all created modal session, and as such, make then + // pending again. The next call to currentModalSession will + // recreate the session on top again: + int stackSize = cocoaModalSessionStack.size(); + for (int i=stackSize-1; i>=0; --i) { + QCocoaModalSessionInfo &info = cocoaModalSessionStack[i]; + if (info.session) { + [NSApp endModalSession:info.session]; + info.session = 0; + } + } + currentModalSessionCached = 0; +} -static void qt_mac_setChildDialogsResponsive(QWidget *widget, bool responsive) +NSModalSession QEventDispatcherMacPrivate::currentModalSession() { + // If we have one or more modal windows, this function will create + // a session for each of those, and return the one for the top. + if (currentModalSessionCached) + return currentModalSessionCached; + + if (cocoaModalSessionStack.isEmpty()) + return 0; + + // Since this code will end up calling our Qt event handler + // (also from beginModalSessionForWindow), we need to block + // that to avoid side effects of events beeing delivered: + QBoolBlocker block(blockSendPostedEvents, true); + + if (![NSApp isRunning]) { + // Sadly, we need to introduce this little event flush + // to stop dialogs from blinking/poping in front if a + // modal session restart was needed: + while (NSEvent *event = [NSApp nextEventMatchingMask:0 + untilDate:nil + inMode:NSDefaultRunLoopMode + dequeue: YES]) { + qt_mac_send_event(0, event, 0); + } + } + + int sessionCount = cocoaModalSessionStack.size(); + for (int i=0; i<sessionCount; ++i) { + QCocoaModalSessionInfo &info = cocoaModalSessionStack[i]; + if (!info.widget) + continue; + if (info.widget->testAttribute(Qt::WA_DontShowOnScreen)) + continue; + if (!info.session) { + QMacCocoaAutoReleasePool pool; + NSWindow *window = qt_mac_window_for(info.widget); + if (!window) + continue; + info.session = [NSApp beginModalSessionForWindow:window]; + } + currentModalSessionCached = info.session; + } + + return currentModalSessionCached; +} + +static void setChildrenWorksWhenModal(QWidget *widget, bool worksWhenModal) +{ + // For NSPanels (but not NSWindows, sadly), we can set the flag + // worksWhenModal, so that they are active even when they are not modal. QList<QDialog *> dialogs = widget->findChildren<QDialog *>(); for (int i=0; i<dialogs.size(); ++i){ NSWindow *window = qt_mac_window_for(dialogs[i]); if (window && [window isKindOfClass:[NSPanel class]]) { - [static_cast<NSPanel *>(window) setWorksWhenModal:responsive]; - if (responsive && dialogs[i]->isVisible()){ + [static_cast<NSPanel *>(window) setWorksWhenModal:worksWhenModal]; + if (worksWhenModal && dialogs[i]->isVisible()){ [window orderFront:window]; } } } } -NSModalSession QEventDispatcherMacPrivate::activeModalSession() +void QEventDispatcherMacPrivate::updateChildrenWorksWhenModal() { - // Create (if needed) and return the modal session - // for the top-most modal dialog, if any: - if (cocoaModalSessionStack.isEmpty()) - return 0; - QCocoaModalSessionInfo &info = cocoaModalSessionStack.last(); - if (!info.widget) - return 0; - if (info.widget->testAttribute(Qt::WA_DontShowOnScreen)){ - // INVARIANT: We have a modal widget, but it's not visible on screen. - // This will e.g. be true for native dialogs. Make the dialog children - // of the previous modal dialog unresponsive, so that the current dialog - // (native or not) is the only reponsive dialog on screen: - int size = cocoaModalSessionStack.size(); + // Make the dialog children of the widget + // active. And make the dialog children of + // the previous modal dialog unactive again: + int size = cocoaModalSessionStack.size(); + if (size > 0){ + if (QWidget *prevModal = cocoaModalSessionStack[size-1].widget) + setChildrenWorksWhenModal(prevModal, true); if (size > 1){ if (QWidget *prevModal = cocoaModalSessionStack[size-2].widget) - qt_mac_setChildDialogsResponsive(prevModal, false); + setChildrenWorksWhenModal(prevModal, false); } - return 0; } +} - if (!info.session) { - QMacCocoaAutoReleasePool pool; - NSWindow *window = qt_mac_window_for(info.widget); - if (!window) - return 0; - // 'beginModalSessionForWindow' will give the event loop a spin, and as - // such, deliver Qt events. This might lead to inconsistent behaviour - // (especially if CocoaRequestModal is delivered), so we need to block: - QBoolBlocker block(blockSendPostedEvents, true); - info.session = [NSApp beginModalSessionForWindow:window]; - // Make the dialog children of the current modal dialog - // responsive. And make the dialog children of - // the previous modal dialog unresponsive again: - qt_mac_setChildDialogsResponsive(info.widget, true); - int size = cocoaModalSessionStack.size(); - if (size > 1){ - if (QWidget *prevModal = cocoaModalSessionStack[size-2].widget) - qt_mac_setChildDialogsResponsive(prevModal, false); - } - } - return info.session; +void QEventDispatcherMacPrivate::beginModalSession(QWidget *widget) +{ + // Add a new, empty (null), NSModalSession to the stack. + // It will become active the next time QEventDispatcher::processEvents is called. + // A QCocoaModalSessionInfo is considered pending to become active if the widget pointer + // is non-zero, and the session pointer is zero (it will become active upon a call to + // currentModalSession). A QCocoaModalSessionInfo is considered pending to be stopped if + // the widget pointer is zero, and the session pointer is non-zero (it will be fully + // stopped in endModalSession(). + QCocoaModalSessionInfo info = {widget, 0}; + cocoaModalSessionStack.push(info); + updateChildrenWorksWhenModal(); + currentModalSessionCached = 0; } -void QEventDispatcherMacPrivate::rebuildModalSessionStack(bool pop) +void QEventDispatcherMacPrivate::endModalSession(QWidget *widget) { - // Calling [NSApp stopModal], or [NSApp stop], will stop all modal dialogs - // in one go. So to to not confuse cocoa, we need to stop all our modal - // sessions as well. QMacEventDispatcher will make them modal again - // in the correct order as long as they are left on the cocoaModalSessionStack - // and a CocoaRequestModal is posted: - if (cocoaModalSessionStack.isEmpty()) - return; + // Mark all sessions attached to widget as pending to be stopped. We do this + // by setting the widget pointer to zero, but leave the session pointer. + // We don't tell cocoa to stop any sessions just yet, because cocoa only understands + // when we stop the _current_ modal session (which is the session on top of + // the stack, and might not belong to 'widget'). + int stackSize = cocoaModalSessionStack.size(); + for (int i=stackSize-1; i>=0; --i) { + QCocoaModalSessionInfo &info = cocoaModalSessionStack[i]; + if (info.widget == widget) + info.widget = 0; + } - QMacCocoaAutoReleasePool pool; - [NSApp stopModal]; - [NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined location:NSZeroPoint - modifierFlags:0 timestamp:0. windowNumber:0 context:0 - subtype:SHRT_MAX data1:0 data2:0] atStart:NO]; + // Now we stop, and remove, all sessions marked as pending + // to be stopped on _top_ of the stack, if any: + bool needToInterruptEventDispatcher = false; + bool needToUpdateChildrenWorksWhenModal = false; - for (int i=0; i<cocoaModalSessionStack.size(); ++i){ + for (int i=stackSize-1; i>=0; --i) { QCocoaModalSessionInfo &info = cocoaModalSessionStack[i]; + if (info.widget) + break; + cocoaModalSessionStack.remove(i); + needToUpdateChildrenWorksWhenModal = true; + currentModalSessionCached = 0; if (info.session) { [NSApp endModalSession:info.session]; - info.session = 0; + needToInterruptEventDispatcher = true; } } - if (pop) { - QCocoaModalSessionInfo info = cocoaModalSessionStack.pop(); - if (info.widget) - qt_mac_setChildDialogsResponsive(info.widget, false); - } - - if (!cocoaModalSessionStack.isEmpty()) { - // Since we now have pending modal sessions again, make - // sure that we enter modal for the one on the top later: - qApp->postEvent(qApp, new QEvent(QEvent::CocoaRequestModal)); - } else { - QCoreApplication::removePostedEvents(qApp, QEvent::CocoaRequestModal); - } + if (needToUpdateChildrenWorksWhenModal) + updateChildrenWorksWhenModal(); + if (needToInterruptEventDispatcher) + QEventDispatcherMac::instance()->interrupt(); } #endif @@ -839,6 +914,21 @@ QEventDispatcherMac::QEventDispatcherMac(QObject *parent) QEventDispatcherMacPrivate::waitingObserverCallback, &observerContext); CFRunLoopAddObserver(mainRunLoop(), d->waitingObserver, kCFRunLoopCommonModes); + + /* The first cycle in the loop adds the source and the events of the source + are not processed. + We use an observer to process the posted events for the first + execution of the loop. */ + CFRunLoopObserverContext firstTimeObserverContext; + bzero(&firstTimeObserverContext, sizeof(CFRunLoopObserverContext)); + firstTimeObserverContext.info = d; + d->firstTimeObserver = CFRunLoopObserverCreate(kCFAllocatorDefault, + kCFRunLoopEntry, + /* repeats = */ false, + 0, + QEventDispatcherMacPrivate::firstLoopEntry, + &firstTimeObserverContext); + CFRunLoopAddObserver(mainRunLoop(), d->firstTimeObserver, kCFRunLoopCommonModes); } void QEventDispatcherMacPrivate::waitingObserverCallback(CFRunLoopObserverRef, @@ -855,10 +945,9 @@ Boolean QEventDispatcherMacPrivate::postedEventSourceEqualCallback(const void *i return info1 == info2; } -void QEventDispatcherMacPrivate::postedEventsSourcePerformCallback(void *info) +inline static void processPostedEvents(QEventDispatcherMacPrivate *const d, const bool blockSendPostedEvents) { - QEventDispatcherMacPrivate *d = static_cast<QEventDispatcherMacPrivate *>(info); - if (blockSendPostedEvents) { + if (blockSendPostedEvents || d->interrupt) { CFRunLoopSourceSignal(d->postedEventsSource); } else { if (!d->threadData->canWait || (d->serialNumber != d->lastSerial)) { @@ -868,27 +957,43 @@ void QEventDispatcherMacPrivate::postedEventsSourcePerformCallback(void *info) } } -#ifdef QT_MAC_USE_COCOA -static void stopNSApp() +void QEventDispatcherMacPrivate::firstLoopEntry(CFRunLoopObserverRef ref, + CFRunLoopActivity activity, + void *info) { - QMacCocoaAutoReleasePool pool; - static const short NSAppShouldStopForQt = SHRT_MAX; - [NSApp stop:NSApp]; - [NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined location:NSZeroPoint - modifierFlags:0 timestamp:0. windowNumber:0 context:0 - subtype:NSAppShouldStopForQt data1:0 data2:0] atStart:NO]; + Q_UNUSED(ref); + Q_UNUSED(activity); + processPostedEvents(static_cast<QEventDispatcherMacPrivate *>(info), blockSendPostedEvents); +} + +void QEventDispatcherMacPrivate::postedEventsSourcePerformCallback(void *info) +{ + processPostedEvents(static_cast<QEventDispatcherMacPrivate *>(info), blockSendPostedEvents); } -#endif void QEventDispatcherMac::interrupt() { Q_D(QEventDispatcherMac); d->interrupt = true; wakeUp(); + #ifndef QT_MAC_USE_COCOA CFRunLoopStop(mainRunLoop()); #else - stopNSApp(); + QMacCocoaAutoReleasePool pool; + // In case we wait for more events inside + // processEvents (or NSApp run), post a dummy to wake it up: + static const short NSAppShouldStopForQt = SHRT_MAX; + [NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined location:NSZeroPoint + modifierFlags:0 timestamp:0. windowNumber:0 context:0 + subtype:NSAppShouldStopForQt data1:0 data2:0] atStart:NO]; + + if (d->activeModalSessionCount() == 0) { + // We should only stop NSApp if we actually started it (and + // not some 3rd party application, e.g. if we are a plugin). + if (d->nsAppRunCalledByQt) + [NSApp stop:NSApp]; + } #endif } @@ -924,7 +1029,57 @@ QEventDispatcherMac::~QEventDispatcherMac() CFRunLoopObserverInvalidate(d->waitingObserver); CFRelease(d->waitingObserver); + + CFRunLoopObserverInvalidate(d->firstTimeObserver); + CFRelease(d->firstTimeObserver); } +///////////////////////////////////////////////////////////////////////////// + +#ifdef QT_MAC_USE_COCOA + +QtMacInterruptDispatcherHelp* QtMacInterruptDispatcherHelp::instance = 0; + +QtMacInterruptDispatcherHelp::QtMacInterruptDispatcherHelp() : cancelled(false) +{ + // This is the whole point of encapsulation this code + // inside a class; we can make the code (inside destructor) + // execute on lower loop level: + deleteLater(); +} + +QtMacInterruptDispatcherHelp::~QtMacInterruptDispatcherHelp() +{ + if (cancelled) + return; + + instance = 0; + + if (QEventDispatcherMacPrivate::currentExecIsNSAppRun) { + int activeCount = QEventDispatcherMacPrivate::activeModalSessionCount(); + if (activeCount > 0) { + // The problem we now have hit: [NSApp stop] will not stop NSApp + // if a session is active; it will stop the session instead. + // So to stop NSApp, we need to temporarily stop all the + // sessions, then stop NSApp, then restart the session on top again. + // We need to do this to ensure that we're not stuck inside + // [NSApp run] when we really should be running a modal session: + QEventDispatcherMacPrivate::temporarilyStopAllModalSessions(); + } + } + // Always interrupt once more in case the modal session stack changed + // while processEvents was called manually from within the application: + QEventDispatcherMac::instance()->interrupt(); +} + +void QtMacInterruptDispatcherHelp::interruptLater() { + if (instance) { + instance->cancelled = true; + delete instance; + } + instance = new QtMacInterruptDispatcherHelp; +} + +#endif QT_END_NAMESPACE diff --git a/src/gui/kernel/qeventdispatcher_mac_p.h b/src/gui/kernel/qeventdispatcher_mac_p.h index 2792cfc..dfcb91f 100644 --- a/src/gui/kernel/qeventdispatcher_mac_p.h +++ b/src/gui/kernel/qeventdispatcher_mac_p.h @@ -172,15 +172,22 @@ public: #ifdef QT_MAC_USE_COCOA // The following variables help organizing modal sessions: static QStack<QCocoaModalSessionInfo> cocoaModalSessionStack; - static bool blockCocoaRequestModal; - static NSModalSession activeModalSession(); - static void rebuildModalSessionStack(bool pop); + static bool currentExecIsNSAppRun; + static bool nsAppRunCalledByQt; + static NSModalSession currentModalSessionCached; + static void updateChildrenWorksWhenModal(); + static NSModalSession currentModalSession(); + static int activeModalSessionCount(); + static void temporarilyStopAllModalSessions(); + static void beginModalSession(QWidget *widget); + static void endModalSession(QWidget *widget); #endif MacSocketHash macSockets; QList<void *> queuedUserInputEvents; // List of EventRef in Carbon, and NSEvent * in Cocoa CFRunLoopSourceRef postedEventsSource; CFRunLoopObserverRef waitingObserver; + CFRunLoopObserverRef firstTimeObserver; QAtomicInt serialNumber; int lastSerial; bool interrupt; @@ -190,8 +197,23 @@ private: static void activateTimer(CFRunLoopTimerRef, void *info); static void waitingObserverCallback(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info); + static void firstLoopEntry(CFRunLoopObserverRef ref, CFRunLoopActivity activity, void *info); }; +#ifdef QT_MAC_USE_COCOA +class QtMacInterruptDispatcherHelp : public QObject +{ + static QtMacInterruptDispatcherHelp *instance; + bool cancelled; + + QtMacInterruptDispatcherHelp(); + ~QtMacInterruptDispatcherHelp(); + + public: + static void interruptLater(); +}; +#endif + QT_END_NAMESPACE #endif // QEVENTDISPATCHER_MAC_P_H diff --git a/src/gui/kernel/qeventdispatcher_s60.cpp b/src/gui/kernel/qeventdispatcher_s60.cpp new file mode 100644 index 0000000..dcf83bc --- /dev/null +++ b/src/gui/kernel/qeventdispatcher_s60.cpp @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $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..94282b7 --- /dev/null +++ b/src/gui/kernel/qeventdispatcher_s60_p.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $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/qeventdispatcher_x11.cpp b/src/gui/kernel/qeventdispatcher_x11.cpp index ce1a11f..59977ec 100644 --- a/src/gui/kernel/qeventdispatcher_x11.cpp +++ b/src/gui/kernel/qeventdispatcher_x11.cpp @@ -105,7 +105,7 @@ bool QEventDispatcherX11::processEvents(QEventLoop::ProcessEventsFlags flags) // _qt_scrolldone protocols, queue all other // client messages if (event.xclient.format == 32) { - if (event.xclient.message_type == ATOM(WM_PROTOCOLS) || + if (event.xclient.message_type == ATOM(WM_PROTOCOLS) && (Atom) event.xclient.data.l[0] == ATOM(WM_TAKE_FOCUS)) { break; } else if (event.xclient.message_type == ATOM(_QT_SCROLL_DONE)) { diff --git a/src/gui/kernel/qformlayout.cpp b/src/gui/kernel/qformlayout.cpp index 7105db6..3e5dadc 100644 --- a/src/gui/kernel/qformlayout.cpp +++ b/src/gui/kernel/qformlayout.cpp @@ -252,7 +252,7 @@ QFormLayoutPrivate::QFormLayoutPrivate() : fieldGrowthPolicy(DefaultFieldGrowthPolicy), rowWrapPolicy(DefaultRowWrapPolicy), has_hfw(false), dirty(true), sizesDirty(true), expandVertical(0), expandHorizontal(0), labelAlignment(0), formAlignment(0), - hfw_width(-1), hfw_sh_height(-1), min_width(-1), + layoutWidth(-1), hfw_width(-1), hfw_sh_height(-1), min_width(-1), sh_width(-1), thresh_width(QLAYOUTSIZE_MAX), hSpacing(-1), vSpacing(-1) { } @@ -1006,10 +1006,8 @@ QStyle* QFormLayoutPrivate::getStyle() const \since 4.4 \brief The QFormLayout class manages forms of input widgets and their associated labels. - \ingroup appearance \ingroup geomanagement - \mainclass QFormLayout is a convenience layout class that lays out its children in a two-column form. The left column consists of labels diff --git a/src/gui/kernel/qgesture.cpp b/src/gui/kernel/qgesture.cpp new file mode 100644 index 0000000..4edf8a9 --- /dev/null +++ b/src/gui/kernel/qgesture.cpp @@ -0,0 +1,670 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgesture.h" +#include "private/qgesture_p.h" + +QT_BEGIN_NAMESPACE + + /*! + \class QGesture + \since 4.6 + \ingroup gestures + + \brief The QGesture class represents a gesture, containing properties that + describe the corresponding user input. + + Gesture objects are not constructed directly by developers. They are created by + the QGestureRecognizer object that is registered with the application; see + QGestureRecognizer::registerRecognizer(). + + \section1 Gesture Properties + + The class has a list of properties that can be queried by the user to get + some gesture-specific arguments. For example, the pinch gesture has a scale + factor that is exposed as a property. + + Developers of custom gesture recognizers can add additional properties in + order to provide additional information about a gesture. This can be done + by adding new dynamic properties to a QGesture object, or by subclassing + the QGesture class (or one of its subclasses). + + \section1 Lifecycle of a Gesture Object + + A QGesture instance is implicitly created when needed and is owned by Qt. + Developers should never destroy them or store them for later use as Qt may + destroy particular instances of them and create new ones to replace them. + + The registered gesture recognizer monitors the input events for the target + object via its \l{QGestureRecognizer::}{recognize()} function, updating the + properties of the gesture object as required. + + The gesture object may be delivered to the target object in a QGestureEvent if + the corresponding gesture is active or has just been canceled. Each event that + is delivered contains a list of gesture objects, since support for more than + one gesture may be enabled for the target object. Due to the way events are + handled in Qt, gesture events may be filtered by other objects. + + \sa QGestureEvent, QGestureRecognizer +*/ + +/*! + Constructs a new gesture object with the given \a parent. + + QGesture objects are created by gesture recognizers in the + QGestureRecognizer::create() function. +*/ +QGesture::QGesture(QObject *parent) + : QObject(*new QGesturePrivate, parent) +{ + d_func()->gestureType = Qt::CustomGesture; +} + +/*! + \internal +*/ +QGesture::QGesture(QGesturePrivate &dd, QObject *parent) + : QObject(dd, parent) +{ +} + +/*! + Destroys the gesture object. +*/ +QGesture::~QGesture() +{ +} + +/*! + \property QGesture::state + \brief the current state of the gesture +*/ + +/*! + \property QGesture::gestureType + \brief the type of the gesture +*/ + +/*! + \property QGesture::hotSpot + + \brief The point that is used to find the receiver for the gesture event. + + The hot-spot is a point in the global coordinate system, use + QWidget::mapFromGlobal() or QGestureEvent::mapToGraphicsScene() to get a + local hot-spot. + + The hot-spot should be set by the gesture recognizer to allow gesture event + delivery to a QGraphicsObject. +*/ + +/*! + \property QGesture::hasHotSpot + \brief whether the gesture has a hot-spot +*/ + +Qt::GestureType QGesture::gestureType() const +{ + return d_func()->gestureType; +} + +Qt::GestureState QGesture::state() const +{ + return d_func()->state; +} + +QPointF QGesture::hotSpot() const +{ + return d_func()->hotSpot; +} + +void QGesture::setHotSpot(const QPointF &value) +{ + Q_D(QGesture); + d->hotSpot = value; + d->isHotSpotSet = true; +} + +bool QGesture::hasHotSpot() const +{ + return d_func()->isHotSpotSet; +} + +void QGesture::unsetHotSpot() +{ + d_func()->isHotSpotSet = false; +} + +/*! + \property QGesture::gestureCancelPolicy + \brief the policy for deciding what happens on accepting a gesture + + On accepting one gesture Qt can automatically cancel other gestures + that belong to other targets. The policy is normally set to not cancel + any other gestures and can be set to cancel all active gestures in the + context. For example for all child widgets. +*/ + +/*! + \enum QGesture::GestureCancelPolicy + + This enum describes how accepting a gesture can cancel other gestures + automatically. + + \value CancelNone On accepting this gesture no other gestures will be affected. + + \value CancelAllInContext On accepting this gesture all gestures that are + active in the context (respecting the Qt::GestureFlag that were specified + when subscribed to the gesture) will be cancelled. +*/ + +void QGesture::setGestureCancelPolicy(GestureCancelPolicy policy) +{ + Q_D(QGesture); + d->gestureCancelPolicy = static_cast<uint>(policy); +} + +QGesture::GestureCancelPolicy QGesture::gestureCancelPolicy() const +{ + Q_D(const QGesture); + return static_cast<GestureCancelPolicy>(d->gestureCancelPolicy); +} + +/*! + \class QPanGesture + \since 4.6 + \brief The QPanGesture class describes a panning gesture made by the user. + \ingroup gestures + + \image pangesture.png + + \sa {Gestures Programming}, QPinchGesture, QSwipeGesture +*/ + +/*! + \property QPanGesture::totalOffset + \brief the total offset from the first input position to the current input + position + + The total offset measures the total change in position of the user's input + covered by the gesture on the input device. +*/ + +/*! + \property QPanGesture::lastOffset + \brief the last offset recorded for this gesture + + The last offset contains the change in position of the user's input as + reported in the \l offset property when a previous gesture event was + delivered for this gesture. + + If no previous event was delivered with information about this gesture + (i.e., this gesture object contains information about the first movement + in the gesture) then this property contains a zero size. +*/ + +/*! + \property QPanGesture::offset + \brief the total offset from the first input position to the current input + position + + The offset measures the total change in position of the user's input + covered by the gesture on the input device. +*/ + +/*! + \property QPanGesture::delta + \brief the offset from the previous input position to the current input + + This is essentially the same as the difference between offset() and + lastOffset(). +*/ + +/*! + \property QPanGesture::acceleration +*/ + +/*! + \internal +*/ +QPanGesture::QPanGesture(QObject *parent) + : QGesture(*new QPanGesturePrivate, parent) +{ + d_func()->gestureType = Qt::PanGesture; +} + + +QPointF QPanGesture::lastOffset() const +{ + return d_func()->lastOffset; +} + +QPointF QPanGesture::offset() const +{ + return d_func()->offset; +} + +QPointF QPanGesture::delta() const +{ + Q_D(const QPanGesture); + return d->offset - d->lastOffset; +} + +qreal QPanGesture::acceleration() const +{ + return d_func()->acceleration; +} + +void QPanGesture::setLastOffset(const QPointF &value) +{ + d_func()->lastOffset = value; +} + +void QPanGesture::setOffset(const QPointF &value) +{ + d_func()->offset = value; +} + +void QPanGesture::setAcceleration(qreal value) +{ + d_func()->acceleration = value; +} + +/*! + \class QPinchGesture + \since 4.6 + \brief The QPinchGesture class describes a pinch gesture made my the user. + \ingroup multitouch + \ingroup gestures + + A pinch gesture is a form of multitouch user input in which the user typically + touches two points on the input device with a thumb and finger, before moving + them closer together or further apart to change the scale factor, zoom, or level + of detail of the user interface. + + \image pinchgesture.png + + Instead of repeatedly applying the same pinching gesture, the user may + continue to touch the input device in one place, and apply a second touch + to a new point, continuing the gesture. When this occurs, gesture events + will continue to be delivered to the target object, containing an instance + of QPinchGesture in the Qt::GestureUpdated state. + + \sa {Gestures Programming}, QPanGesture, QSwipeGesture +*/ + +/*! + \enum QPinchGesture::ChangeFlag + + This enum describes the changes that can occur to the properties of + the gesture object. + + \value ScaleFactorChanged The scale factor held by scaleFactor changed. + \value RotationAngleChanged The rotation angle held by rotationAngle changed. + \value CenterPointChanged The center point held by centerPoint changed. + + \sa changeFlags, totalChangeFlags +*/ + +/*! + \property QPinchGesture::totalChangeFlags + \brief the property of the gesture that has change + + This property indicates which of the other properties has changed since the + gesture has started. You can use this information to determine which aspect + of your user interface needs to be updated. + + \sa changeFlags, scaleFactor, rotationAngle, centerPoint +*/ + +/*! + \property QPinchGesture::changeFlags + \brief the property of the gesture that has changed in the current step + + This property indicates which of the other properties has changed since + the previous gesture event included information about this gesture. You + can use this information to determine which aspect of your user interface + needs to be updated. + + \sa totalChangeFlags, scaleFactor, rotationAngle, centerPoint +*/ + +/*! + \property QPinchGesture::totalScaleFactor + \brief the total scale factor + + The total scale factor measures the total change in scale factor from the + original value to the current scale factor. + + \sa scaleFactor, lastScaleFactor +*/ +/*! + \property QPinchGesture::lastScaleFactor + \brief the last scale factor recorded for this gesture + + The last scale factor contains the scale factor reported in the + \l scaleFactor property when a previous gesture event included + information about this gesture. + + If no previous event was delivered with information about this gesture + (i.e., this gesture object contains information about the first movement + in the gesture) then this property contains zero. + + \sa scaleFactor, totalScaleFactor +*/ +/*! + \property QPinchGesture::scaleFactor + \brief the current scale factor + + The scale factor measures the scale factor associated with the distance + between two of the user's inputs on a multitouch device. + + \sa totalScaleFactor, lastScaleFactor +*/ + +/*! + \property QPinchGesture::totalRotationAngle + \brief the total angle covered by the gesture + + This total angle measures the complete angle covered by the gesture. Usually, this + is equal to the value held by the \l rotationAngle property, except in the case where + the user performs multiple rotations by removing and repositioning one of the touch + points, as described above. In this case, the total angle will be the sum of the + rotation angles for the multiple stages of the gesture. + + \sa rotationAngle, lastRotationAngle +*/ +/*! + \property QPinchGesture::lastRotationAngle + \brief the last reported angle covered by the gesture motion + + The last rotation angle is the angle as reported in the \l rotationAngle property + when a previous gesture event was delivered for this gesture. + + \sa rotationAngle, totalRotationAngle +*/ +/*! + \property QPinchGesture::rotationAngle + \brief the angle covered by the gesture motion + + \sa totalRotationAngle, lastRotationAngle +*/ + +/*! + \property QPinchGesture::startCenterPoint + \brief the starting position of the center point + + \sa centerPoint, lastCenterPoint +*/ +/*! + \property QPinchGesture::lastCenterPoint + \brief the last position of the center point recorded for this gesture + + \sa centerPoint, startCenterPoint +*/ +/*! + \property QPinchGesture::centerPoint + \brief the current center point + + The center point is the midpoint between the two input points in the gesture. + + \sa startCenterPoint, lastCenterPoint +*/ + +/*! + \internal +*/ +QPinchGesture::QPinchGesture(QObject *parent) + : QGesture(*new QPinchGesturePrivate, parent) +{ + d_func()->gestureType = Qt::PinchGesture; +} + +QPinchGesture::ChangeFlags QPinchGesture::totalChangeFlags() const +{ + return d_func()->totalChangeFlags; +} + +void QPinchGesture::setTotalChangeFlags(QPinchGesture::ChangeFlags value) +{ + d_func()->totalChangeFlags = value; +} + +QPinchGesture::ChangeFlags QPinchGesture::changeFlags() const +{ + return d_func()->changeFlags; +} + +void QPinchGesture::setChangeFlags(QPinchGesture::ChangeFlags value) +{ + d_func()->changeFlags = value; +} + +QPointF QPinchGesture::startCenterPoint() const +{ + return d_func()->startCenterPoint; +} + +QPointF QPinchGesture::lastCenterPoint() const +{ + return d_func()->lastCenterPoint; +} + +QPointF QPinchGesture::centerPoint() const +{ + return d_func()->centerPoint; +} + +void QPinchGesture::setStartCenterPoint(const QPointF &value) +{ + d_func()->startCenterPoint = value; +} + +void QPinchGesture::setLastCenterPoint(const QPointF &value) +{ + d_func()->lastCenterPoint = value; +} + +void QPinchGesture::setCenterPoint(const QPointF &value) +{ + d_func()->centerPoint = value; +} + + +qreal QPinchGesture::totalScaleFactor() const +{ + return d_func()->totalScaleFactor; +} + +qreal QPinchGesture::lastScaleFactor() const +{ + return d_func()->lastScaleFactor; +} + +qreal QPinchGesture::scaleFactor() const +{ + return d_func()->scaleFactor; +} + +void QPinchGesture::setTotalScaleFactor(qreal value) +{ + d_func()->totalScaleFactor = value; +} + +void QPinchGesture::setLastScaleFactor(qreal value) +{ + d_func()->lastScaleFactor = value; +} + +void QPinchGesture::setScaleFactor(qreal value) +{ + d_func()->scaleFactor = value; +} + + +qreal QPinchGesture::totalRotationAngle() const +{ + return d_func()->totalRotationAngle; +} + +qreal QPinchGesture::lastRotationAngle() const +{ + return d_func()->lastRotationAngle; +} + +qreal QPinchGesture::rotationAngle() const +{ + return d_func()->rotationAngle; +} + +void QPinchGesture::setTotalRotationAngle(qreal value) +{ + d_func()->totalRotationAngle = value; +} + +void QPinchGesture::setLastRotationAngle(qreal value) +{ + d_func()->lastRotationAngle = value; +} + +void QPinchGesture::setRotationAngle(qreal value) +{ + d_func()->rotationAngle = value; +} + +/*! + \class QSwipeGesture + \since 4.6 + \brief The QSwipeGesture class describes a swipe gesture made by the user. + \ingroup gestures + + \image swipegesture.png + + \sa {Gestures Programming}, QPanGesture, QPinchGesture +*/ + +/*! + \enum QSwipeGesture::SwipeDirection + + This enum describes the possible directions for the gesture's motion + along the horizontal and vertical axes. + + \value NoDirection The gesture had no motion associated with it on a particular axis. + \value Left The gesture involved a horizontal motion to the left. + \value Right The gesture involved a horizontal motion to the right. + \value Up The gesture involved an upward vertical motion. + \value Down The gesture involved a downward vertical motion. +*/ + +/*! + \property QSwipeGesture::horizontalDirection + \brief the horizontal direction of the gesture + + If the gesture has a horizontal component, the horizontal direction + is either Left or Right; otherwise, it is NoDirection. + + \sa verticalDirection, swipeAngle +*/ + +/*! + \property QSwipeGesture::verticalDirection + \brief the vertical direction of the gesture + + If the gesture has a vertical component, the vertical direction + is either Up or Down; otherwise, it is NoDirection. + + \sa horizontalDirection, swipeAngle +*/ + +/*! + \property QSwipeGesture::swipeAngle + \brief the angle of the motion associated with the gesture + + If the gesture has either a horizontal or vertical component, the + swipe angle describes the angle between the direction of motion and the + x-axis as defined using the standard widget + \l{The Coordinate System}{coordinate system}. + + \sa horizontalDirection, verticalDirection +*/ + +/*! + \internal +*/ +QSwipeGesture::QSwipeGesture(QObject *parent) + : QGesture(*new QSwipeGesturePrivate, parent) +{ + d_func()->gestureType = Qt::SwipeGesture; +} + +QSwipeGesture::SwipeDirection QSwipeGesture::horizontalDirection() const +{ + Q_D(const QSwipeGesture); + if (d->swipeAngle < 0 || d->swipeAngle == 90 || d->swipeAngle == 270) + return QSwipeGesture::NoDirection; + else if (d->swipeAngle < 90 || d->swipeAngle > 270) + return QSwipeGesture::Right; + else + return QSwipeGesture::Left; +} + +QSwipeGesture::SwipeDirection QSwipeGesture::verticalDirection() const +{ + Q_D(const QSwipeGesture); + if (d->swipeAngle <= 0 || d->swipeAngle == 180) + return QSwipeGesture::NoDirection; + else if (d->swipeAngle < 180) + return QSwipeGesture::Up; + else + return QSwipeGesture::Down; +} + +qreal QSwipeGesture::swipeAngle() const +{ + return d_func()->swipeAngle; +} + +void QSwipeGesture::setSwipeAngle(qreal value) +{ + d_func()->swipeAngle = value; +} + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qgesture.h b/src/gui/kernel/qgesture.h new file mode 100644 index 0000000..dd322ad --- /dev/null +++ b/src/gui/kernel/qgesture.h @@ -0,0 +1,227 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGESTURE_H +#define QGESTURE_H + +#include <QtCore/qobject.h> +#include <QtCore/qlist.h> +#include <QtCore/qdatetime.h> +#include <QtCore/qpoint.h> +#include <QtCore/qrect.h> +#include <QtCore/qmetatype.h> + +QT_BEGIN_HEADER + +Q_DECLARE_METATYPE(Qt::GestureState) + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QGesturePrivate; +class Q_GUI_EXPORT QGesture : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QGesture) + + Q_PROPERTY(Qt::GestureState state READ state) + Q_PROPERTY(Qt::GestureType gestureType READ gestureType) + Q_PROPERTY(QGesture::GestureCancelPolicy gestureCancelPolicy READ gestureCancelPolicy WRITE setGestureCancelPolicy) + Q_PROPERTY(QPointF hotSpot READ hotSpot WRITE setHotSpot RESET unsetHotSpot) + Q_PROPERTY(bool hasHotSpot READ hasHotSpot) + +public: + explicit QGesture(QObject *parent = 0); + ~QGesture(); + + Qt::GestureType gestureType() const; + + Qt::GestureState state() const; + + QPointF hotSpot() const; + void setHotSpot(const QPointF &value); + bool hasHotSpot() const; + void unsetHotSpot(); + + enum GestureCancelPolicy { + CancelNone = 0, + CancelAllInContext + }; + + void setGestureCancelPolicy(GestureCancelPolicy policy); + GestureCancelPolicy gestureCancelPolicy() const; + +protected: + QGesture(QGesturePrivate &dd, QObject *parent); + +private: + friend class QGestureEvent; + friend class QGestureRecognizer; + friend class QGestureManager; + friend class QGraphicsScenePrivate; +}; + +class QPanGesturePrivate; +class Q_GUI_EXPORT QPanGesture : public QGesture +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QPanGesture) + + Q_PROPERTY(QPointF lastOffset READ lastOffset WRITE setLastOffset) + Q_PROPERTY(QPointF offset READ offset WRITE setOffset) + Q_PROPERTY(QPointF delta READ delta STORED false) + Q_PROPERTY(qreal acceleration READ acceleration WRITE setAcceleration) + +public: + QPanGesture(QObject *parent = 0); + + QPointF lastOffset() const; + QPointF offset() const; + QPointF delta() const; + qreal acceleration() const; + + void setLastOffset(const QPointF &value); + void setOffset(const QPointF &value); + void setAcceleration(qreal value); + + friend class QPanGestureRecognizer; + friend class QWinNativePanGestureRecognizer; +}; + +class QPinchGesturePrivate; +class Q_GUI_EXPORT QPinchGesture : public QGesture +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QPinchGesture) + +public: + enum ChangeFlag { + ScaleFactorChanged = 0x1, + RotationAngleChanged = 0x2, + CenterPointChanged = 0x4 + }; + Q_DECLARE_FLAGS(ChangeFlags, ChangeFlag) + + Q_PROPERTY(ChangeFlags totalChangeFlags READ totalChangeFlags WRITE setTotalChangeFlags) + Q_PROPERTY(ChangeFlags changeFlags READ changeFlags WRITE setChangeFlags) + + Q_PROPERTY(qreal totalScaleFactor READ totalScaleFactor WRITE setTotalScaleFactor) + Q_PROPERTY(qreal lastScaleFactor READ lastScaleFactor WRITE setLastScaleFactor) + Q_PROPERTY(qreal scaleFactor READ scaleFactor WRITE setScaleFactor) + + Q_PROPERTY(qreal totalRotationAngle READ totalRotationAngle WRITE setTotalRotationAngle) + Q_PROPERTY(qreal lastRotationAngle READ lastRotationAngle WRITE setLastRotationAngle) + Q_PROPERTY(qreal rotationAngle READ rotationAngle WRITE setRotationAngle) + + Q_PROPERTY(QPointF startCenterPoint READ startCenterPoint WRITE setStartCenterPoint) + Q_PROPERTY(QPointF lastCenterPoint READ lastCenterPoint WRITE setLastCenterPoint) + Q_PROPERTY(QPointF centerPoint READ centerPoint WRITE setCenterPoint) + +public: + QPinchGesture(QObject *parent = 0); + + ChangeFlags totalChangeFlags() const; + void setTotalChangeFlags(ChangeFlags value); + + ChangeFlags changeFlags() const; + void setChangeFlags(ChangeFlags value); + + QPointF startCenterPoint() const; + QPointF lastCenterPoint() const; + QPointF centerPoint() const; + void setStartCenterPoint(const QPointF &value); + void setLastCenterPoint(const QPointF &value); + void setCenterPoint(const QPointF &value); + + qreal totalScaleFactor() const; + qreal lastScaleFactor() const; + qreal scaleFactor() const; + void setTotalScaleFactor(qreal value); + void setLastScaleFactor(qreal value); + void setScaleFactor(qreal value); + + qreal totalRotationAngle() const; + qreal lastRotationAngle() const; + qreal rotationAngle() const; + void setTotalRotationAngle(qreal value); + void setLastRotationAngle(qreal value); + void setRotationAngle(qreal value); + + friend class QPinchGestureRecognizer; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QPinchGesture::ChangeFlags) + +QT_BEGIN_NAMESPACE + +class QSwipeGesturePrivate; +class Q_GUI_EXPORT QSwipeGesture : public QGesture +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QSwipeGesture) + Q_ENUMS(SwipeDirection) + + Q_PROPERTY(SwipeDirection horizontalDirection READ horizontalDirection STORED false) + Q_PROPERTY(SwipeDirection verticalDirection READ verticalDirection STORED false) + Q_PROPERTY(qreal swipeAngle READ swipeAngle WRITE setSwipeAngle) + +public: + enum SwipeDirection { NoDirection, Left, Right, Up, Down }; + QSwipeGesture(QObject *parent = 0); + + SwipeDirection horizontalDirection() const; + SwipeDirection verticalDirection() const; + + qreal swipeAngle() const; + void setSwipeAngle(qreal value); + + friend class QSwipeGestureRecognizer; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QGesture::GestureCancelPolicy) +QT_END_HEADER + +#endif // QGESTURE_H diff --git a/src/gui/kernel/qgesture_p.h b/src/gui/kernel/qgesture_p.h new file mode 100644 index 0000000..ae2e287 --- /dev/null +++ b/src/gui/kernel/qgesture_p.h @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGESTURE_P_H +#define QGESTURE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qrect.h" +#include "qpoint.h" +#include "qdatetime.h" +#include "qgesture.h" +#include "private/qobject_p.h" + +QT_BEGIN_NAMESPACE + +class QGesturePrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QGesture) + +public: + QGesturePrivate() + : gestureType(Qt::CustomGesture), state(Qt::NoGesture), + isHotSpotSet(false), gestureCancelPolicy(0) + + { + } + + Qt::GestureType gestureType; + Qt::GestureState state; + QPointF hotSpot; + uint isHotSpotSet : 1; + uint gestureCancelPolicy : 2; +}; + +class QPanGesturePrivate : public QGesturePrivate +{ + Q_DECLARE_PUBLIC(QPanGesture) + +public: + QPanGesturePrivate() + : acceleration(0) + { + } + + QPointF lastOffset; + QPointF offset; + QPoint startPosition; + qreal acceleration; +}; + +class QPinchGesturePrivate : public QGesturePrivate +{ + Q_DECLARE_PUBLIC(QPinchGesture) + +public: + QPinchGesturePrivate() + : totalChangeFlags(0), changeFlags(0), + totalScaleFactor(0), lastScaleFactor(0), scaleFactor(0), + totalRotationAngle(0), lastRotationAngle(0), rotationAngle(0), + isNewSequence(true) + { + } + + QPinchGesture::ChangeFlags totalChangeFlags; + QPinchGesture::ChangeFlags changeFlags; + + QPointF startCenterPoint; + QPointF lastCenterPoint; + QPointF centerPoint; + + qreal totalScaleFactor; + qreal lastScaleFactor; + qreal scaleFactor; + + qreal totalRotationAngle; + qreal lastRotationAngle; + qreal rotationAngle; + + bool isNewSequence; + QPointF startPosition[2]; +}; + +class QSwipeGesturePrivate : public QGesturePrivate +{ + Q_DECLARE_PUBLIC(QSwipeGesture) + +public: + QSwipeGesturePrivate() + : horizontalDirection(QSwipeGesture::NoDirection), + verticalDirection(QSwipeGesture::NoDirection), + swipeAngle(0) + { + } + + QSwipeGesture::SwipeDirection horizontalDirection; + QSwipeGesture::SwipeDirection verticalDirection; + qreal swipeAngle; +}; + +QT_END_NAMESPACE + +#endif // QGESTURE_P_H diff --git a/src/gui/kernel/qgesturemanager.cpp b/src/gui/kernel/qgesturemanager.cpp new file mode 100644 index 0000000..628892d --- /dev/null +++ b/src/gui/kernel/qgesturemanager.cpp @@ -0,0 +1,707 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qgesturemanager_p.h" +#include "private/qstandardgestures_p.h" +#include "private/qwidget_p.h" +#include "private/qgesture_p.h" +#include "private/qgraphicsitem_p.h" +#include "private/qevent_p.h" +#include "qgesture.h" +#include "qevent.h" +#include "qgraphicsitem.h" + +#ifdef Q_WS_MAC +#include "qmacgesturerecognizer_mac_p.h" +#endif +#if defined(Q_OS_WIN) +#include "qwinnativepangesturerecognizer_win_p.h" +#endif + +#include "qdebug.h" + +// #define GESTURE_DEBUG +#ifndef GESTURE_DEBUG +# define DEBUG if (0) qDebug +#else +# define DEBUG qDebug +#endif + +QT_BEGIN_NAMESPACE + +QGestureManager *qt_gestureManager = 0; + +QGestureManager* QGestureManager::instance() +{ + if (!qt_gestureManager) + qt_gestureManager = new QGestureManager(qApp); + return qt_gestureManager; +} + +QGestureManager::QGestureManager(QObject *parent) + : QObject(parent), state(NotGesture), m_lastCustomGestureId(0) +{ + qRegisterMetaType<Qt::GestureState>(); + +#if defined(Q_WS_MAC) + registerGestureRecognizer(new QMacSwipeGestureRecognizer); + registerGestureRecognizer(new QMacPinchGestureRecognizer); + #if defined(QT_MAC_USE_COCOA) + registerGestureRecognizer(new QMacPanGestureRecognizer); + #endif +#else + registerGestureRecognizer(new QPanGestureRecognizer); + registerGestureRecognizer(new QPinchGestureRecognizer); +#if defined(Q_OS_WIN) + registerGestureRecognizer(new QWinNativePanGestureRecognizer); +#endif +#endif +} + +QGestureManager::~QGestureManager() +{ + qDeleteAll(m_recognizers.values()); + foreach (QGestureRecognizer *recognizer, m_obsoleteGestures.keys()) { + qDeleteAll(m_obsoleteGestures.value(recognizer)); + delete recognizer; + } + m_obsoleteGestures.clear(); +} + +Qt::GestureType QGestureManager::registerGestureRecognizer(QGestureRecognizer *recognizer) +{ + QGesture *dummy = recognizer->create(0); + if (!dummy) { + qWarning("QGestureManager::registerGestureRecognizer: " + "the recognizer fails to create a gesture object, skipping registration."); + return Qt::GestureType(0); + } + Qt::GestureType type = dummy->gestureType(); + if (type == Qt::CustomGesture) { + // generate a new custom gesture id + ++m_lastCustomGestureId; + type = Qt::GestureType(Qt::CustomGesture + m_lastCustomGestureId); + } + m_recognizers.insertMulti(type, recognizer); + delete dummy; + return type; +} + +void QGestureManager::unregisterGestureRecognizer(Qt::GestureType type) +{ + QList<QGestureRecognizer *> list = m_recognizers.values(type); + m_recognizers.remove(type); + foreach (QGesture *g, m_gestureToRecognizer.keys()) { + QGestureRecognizer *recognizer = m_gestureToRecognizer.value(g); + if (list.contains(recognizer)) { + m_deletedRecognizers.insert(g, recognizer); + m_gestureToRecognizer.remove(g); + } + } + + foreach (QGestureRecognizer *recognizer, list) { + QList<QGesture *> obsoleteGestures; + QMap<ObjectGesture, QList<QGesture *> >::Iterator iter = m_objectGestures.begin(); + while (iter != m_objectGestures.end()) { + ObjectGesture objectGesture = iter.key(); + if (objectGesture.gesture == type) + obsoleteGestures << iter.value(); + ++iter; + } + m_obsoleteGestures.insert(recognizer, obsoleteGestures); + } +} + +void QGestureManager::cleanupCachedGestures(QObject *target, Qt::GestureType type) +{ + QMap<ObjectGesture, QList<QGesture *> >::Iterator iter = m_objectGestures.begin(); + while (iter != m_objectGestures.end()) { + ObjectGesture objectGesture = iter.key(); + if (objectGesture.gesture == type && target == objectGesture.object.data()) { + qDeleteAll(iter.value()); + iter = m_objectGestures.erase(iter); + } else { + ++iter; + } + } +} + +// get or create a QGesture object that will represent the state for a given object, used by the recognizer +QGesture *QGestureManager::getState(QObject *object, QGestureRecognizer *recognizer, Qt::GestureType type) +{ + // if the widget is being deleted we should be carefull and not to + // create a new state, as it will create QWeakPointer which doesnt work + // from the destructor. + if (object->isWidgetType()) { + if (static_cast<QWidget *>(object)->d_func()->data.in_destructor) + return 0; + } else if (QGesture *g = qobject_cast<QGesture *>(object)) { + return g; + } else { + Q_ASSERT(qobject_cast<QGraphicsObject *>(object)); + } + + QList<QGesture *> states = + m_objectGestures.value(QGestureManager::ObjectGesture(object, type)); + // check if the QGesture for this recognizer has already been created + foreach (QGesture *state, states) { + if (m_gestureToRecognizer.value(state) == recognizer) + return state; + } + + Q_ASSERT(recognizer); + QGesture *state = recognizer->create(object); + if (!state) + return 0; + state->setParent(this); + if (state->gestureType() == Qt::CustomGesture) { + // if the recognizer didn't fill in the gesture type, then this + // is a custom gesture with autogenerated id and we fill it. + state->d_func()->gestureType = type; +#if defined(GESTURE_DEBUG) + state->setObjectName(QString::number((int)type)); +#endif + } + m_objectGestures[QGestureManager::ObjectGesture(object, type)].append(state); + m_gestureToRecognizer[state] = recognizer; + m_gestureOwners[state] = object; + + return state; +} + +bool QGestureManager::filterEventThroughContexts(const QMultiHash<QObject *, + Qt::GestureType> &contexts, + QEvent *event) +{ + QSet<QGesture *> triggeredGestures; + QSet<QGesture *> finishedGestures; + QSet<QGesture *> newMaybeGestures; + QSet<QGesture *> canceledGestures; + QSet<QGesture *> notGestures; + + // TODO: sort contexts by the gesture type and check if one of the contexts + // is already active. + + bool ret = false; + + // filter the event through recognizers + typedef QHash<QObject *, Qt::GestureType>::const_iterator ContextIterator; + for (ContextIterator cit = contexts.begin(), ce = contexts.end(); cit != ce; ++cit) { + Qt::GestureType gestureType = cit.value(); + QMap<Qt::GestureType, QGestureRecognizer *>::const_iterator + rit = m_recognizers.lowerBound(gestureType), + re = m_recognizers.upperBound(gestureType); + for (; rit != re; ++rit) { + QGestureRecognizer *recognizer = rit.value(); + QObject *target = cit.key(); + QGesture *state = getState(target, recognizer, gestureType); + if (!state) + continue; + QGestureRecognizer::Result result = recognizer->recognize(state, target, event); + QGestureRecognizer::Result type = result & QGestureRecognizer::ResultState_Mask; + result &= QGestureRecognizer::ResultHint_Mask; + if (type == QGestureRecognizer::TriggerGesture) { + DEBUG() << "QGestureManager:Recognizer: gesture triggered: " << state; + triggeredGestures << state; + } else if (type == QGestureRecognizer::FinishGesture) { + DEBUG() << "QGestureManager:Recognizer: gesture finished: " << state; + finishedGestures << state; + } else if (type == QGestureRecognizer::MayBeGesture) { + DEBUG() << "QGestureManager:Recognizer: maybe gesture: " << state; + newMaybeGestures << state; + } else if (type == QGestureRecognizer::CancelGesture) { + DEBUG() << "QGestureManager:Recognizer: not gesture: " << state; + notGestures << state; + } else if (type == QGestureRecognizer::Ignore) { + DEBUG() << "QGestureManager:Recognizer: ignored the event: " << state; + } else { + DEBUG() << "QGestureManager:Recognizer: hm, lets assume the recognizer" + << "ignored the event: " << state; + } + if (result & QGestureRecognizer::ConsumeEventHint) { + DEBUG() << "QGestureManager: we were asked to consume the event: " + << state; + ret = true; + } + } + } + + QSet<QGesture *> startedGestures = triggeredGestures - m_activeGestures; + triggeredGestures &= m_activeGestures; + + // check if a running gesture switched back to maybe state + QSet<QGesture *> activeToMaybeGestures = m_activeGestures & newMaybeGestures; + + // check if a running gesture switched back to not gesture state, + // i.e. were canceled + QSet<QGesture *> activeToCancelGestures = m_activeGestures & notGestures; + canceledGestures += activeToCancelGestures; + + // start timers for new gestures in maybe state + foreach (QGesture *state, newMaybeGestures) { + QBasicTimer &timer = m_maybeGestures[state]; + if (!timer.isActive()) + timer.start(3000, this); + } + // kill timers for gestures that were in maybe state + QSet<QGesture *> notMaybeGestures = (startedGestures | triggeredGestures + | finishedGestures | canceledGestures + | notGestures); + foreach(QGesture *gesture, notMaybeGestures) { + QHash<QGesture *, QBasicTimer>::iterator it = + m_maybeGestures.find(gesture); + if (it != m_maybeGestures.end()) { + it.value().stop(); + m_maybeGestures.erase(it); + } + } + + Q_ASSERT((startedGestures & finishedGestures).isEmpty()); + Q_ASSERT((startedGestures & newMaybeGestures).isEmpty()); + Q_ASSERT((startedGestures & canceledGestures).isEmpty()); + Q_ASSERT((finishedGestures & newMaybeGestures).isEmpty()); + Q_ASSERT((finishedGestures & canceledGestures).isEmpty()); + Q_ASSERT((canceledGestures & newMaybeGestures).isEmpty()); + + QSet<QGesture *> notStarted = finishedGestures - m_activeGestures; + if (!notStarted.isEmpty()) { + // there are some gestures that claim to be finished, but never started. + // probably those are "singleshot" gestures so we'll fake the started state. + foreach (QGesture *gesture, notStarted) + gesture->d_func()->state = Qt::GestureStarted; + QSet<QGesture *> undeliveredGestures; + deliverEvents(notStarted, &undeliveredGestures); + finishedGestures -= undeliveredGestures; + } + + m_activeGestures += startedGestures; + // sanity check: all triggered gestures should already be in active gestures list + Q_ASSERT((m_activeGestures & triggeredGestures).size() == triggeredGestures.size()); + m_activeGestures -= finishedGestures; + m_activeGestures -= activeToMaybeGestures; + m_activeGestures -= canceledGestures; + + // set the proper gesture state on each gesture + foreach (QGesture *gesture, startedGestures) + gesture->d_func()->state = Qt::GestureStarted; + foreach (QGesture *gesture, triggeredGestures) + gesture->d_func()->state = Qt::GestureUpdated; + foreach (QGesture *gesture, finishedGestures) + gesture->d_func()->state = Qt::GestureFinished; + foreach (QGesture *gesture, canceledGestures) + gesture->d_func()->state = Qt::GestureCanceled; + foreach (QGesture *gesture, activeToMaybeGestures) + gesture->d_func()->state = Qt::GestureFinished; + + if (!m_activeGestures.isEmpty() || !m_maybeGestures.isEmpty() || + !startedGestures.isEmpty() || !triggeredGestures.isEmpty() || + !finishedGestures.isEmpty() || !canceledGestures.isEmpty()) { + DEBUG() << "QGestureManager::filterEventThroughContexts:" + << "\n\tactiveGestures:" << m_activeGestures + << "\n\tmaybeGestures:" << m_maybeGestures.keys() + << "\n\tstarted:" << startedGestures + << "\n\ttriggered:" << triggeredGestures + << "\n\tfinished:" << finishedGestures + << "\n\tcanceled:" << canceledGestures; + } + + QSet<QGesture *> undeliveredGestures; + deliverEvents(startedGestures+triggeredGestures+finishedGestures+canceledGestures, + &undeliveredGestures); + + foreach (QGesture *g, startedGestures) { + if (undeliveredGestures.contains(g)) + continue; + if (g->gestureCancelPolicy() == QGesture::CancelAllInContext) { + DEBUG() << "lets try to cancel some"; + // find gestures in context in Qt::GestureStarted or Qt::GestureUpdated state and cancel them + cancelGesturesForChildren(g); + } + } + + m_activeGestures -= undeliveredGestures; + + // reset gestures that ended + QSet<QGesture *> endedGestures = + finishedGestures + canceledGestures + undeliveredGestures; + foreach (QGesture *gesture, endedGestures) { + recycle(gesture); + m_gestureTargets.remove(gesture); + } + return ret; +} + +// Cancel all gestures of children of the widget that original is associated with +void QGestureManager::cancelGesturesForChildren(QGesture *original) +{ + Q_ASSERT(original); + QWidget *originatingWidget = m_gestureTargets.value(original); + Q_ASSERT(originatingWidget); + + // iterate over all active gestures and all maybe gestures + // for each find the owner + // if the owner is part of our sub-hierarchy, cancel it. + + QSet<QGesture*> cancelledGestures; + QSet<QGesture*>::Iterator iter = m_activeGestures.begin(); + while (iter != m_activeGestures.end()) { + QWidget *widget = m_gestureTargets.value(*iter); + // note that we don't touch the gestures for our originatingWidget + if (widget != originatingWidget && originatingWidget->isAncestorOf(widget)) { + DEBUG() << " found a gesture to cancel" << (*iter); + (*iter)->d_func()->state = Qt::GestureCanceled; + cancelledGestures << *iter; + iter = m_activeGestures.erase(iter); + } else { + ++iter; + } + } + + // TODO handle 'maybe' gestures too + + // sort them per target widget by cherry picking from almostCanceledGestures and delivering + QSet<QGesture *> almostCanceledGestures = cancelledGestures; + while (!almostCanceledGestures.isEmpty()) { + QWidget *target = 0; + QSet<QGesture*> gestures; + iter = almostCanceledGestures.begin(); + // sort per target widget + while (iter != almostCanceledGestures.end()) { + QWidget *widget = m_gestureTargets.value(*iter); + if (target == 0) + target = widget; + if (target == widget) { + gestures << *iter; + iter = almostCanceledGestures.erase(iter); + } else { + ++iter; + } + } + Q_ASSERT(target); + + QSet<QGesture*> undeliveredGestures; + deliverEvents(gestures, &undeliveredGestures); + } + + for (iter = cancelledGestures.begin(); iter != cancelledGestures.end(); ++iter) + recycle(*iter); +} + +void QGestureManager::cleanupGesturesForRemovedRecognizer(QGesture *gesture) +{ + QGestureRecognizer *recognizer = m_deletedRecognizers.value(gesture); + Q_ASSERT(recognizer); + m_deletedRecognizers.remove(gesture); + if (m_deletedRecognizers.keys(recognizer).isEmpty()) { + // no more active gestures, cleanup! + qDeleteAll(m_obsoleteGestures.value(recognizer)); + m_obsoleteGestures.remove(recognizer); + delete recognizer; + } +} + +// return true if accepted (consumed) +bool QGestureManager::filterEvent(QWidget *receiver, QEvent *event) +{ + QSet<Qt::GestureType> types; + QMultiHash<QObject *, Qt::GestureType> contexts; + QWidget *w = receiver; + typedef QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator ContextIterator; + if (!w->d_func()->gestureContext.isEmpty()) { + for(ContextIterator it = w->d_func()->gestureContext.begin(), + e = w->d_func()->gestureContext.end(); it != e; ++it) { + types.insert(it.key()); + contexts.insertMulti(w, it.key()); + } + } + // find all gesture contexts for the widget tree + w = w->isWindow() ? 0 : w->parentWidget(); + while (w) + { + for (ContextIterator it = w->d_func()->gestureContext.begin(), + e = w->d_func()->gestureContext.end(); it != e; ++it) { + if (!(it.value() & Qt::DontStartGestureOnChildren)) { + if (!types.contains(it.key())) { + types.insert(it.key()); + contexts.insertMulti(w, it.key()); + } + } + } + if (w->isWindow()) + break; + w = w->parentWidget(); + } + return filterEventThroughContexts(contexts, event); +} + +#ifndef QT_NO_GRAPHICSVIEW +bool QGestureManager::filterEvent(QGraphicsObject *receiver, QEvent *event) +{ + QSet<Qt::GestureType> types; + QMultiHash<QObject *, Qt::GestureType> contexts; + QGraphicsObject *item = receiver; + if (!item->QGraphicsItem::d_func()->gestureContext.isEmpty()) { + typedef QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator ContextIterator; + for(ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.begin(), + e = item->QGraphicsItem::d_func()->gestureContext.end(); it != e; ++it) { + types.insert(it.key()); + contexts.insertMulti(item, it.key()); + } + } + // find all gesture contexts for the graphics object tree + item = item->parentObject(); + while (item) + { + typedef QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator ContextIterator; + for (ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.begin(), + e = item->QGraphicsItem::d_func()->gestureContext.end(); it != e; ++it) { + if (!(it.value() & Qt::DontStartGestureOnChildren)) { + if (!types.contains(it.key())) { + types.insert(it.key()); + contexts.insertMulti(item, it.key()); + } + } + } + item = item->parentObject(); + } + return filterEventThroughContexts(contexts, event); +} +#endif + +bool QGestureManager::filterEvent(QGesture *state, QEvent *event) +{ + QMultiHash<QObject *, Qt::GestureType> contexts; + contexts.insert(state, state->gestureType()); + return filterEventThroughContexts(contexts, event); +} + +void QGestureManager::getGestureTargets(const QSet<QGesture*> &gestures, + QMap<QWidget *, QList<QGesture *> > *conflicts, + QMap<QWidget *, QList<QGesture *> > *normal) +{ + typedef QHash<Qt::GestureType, QHash<QWidget *, QGesture *> > GestureByTypes; + GestureByTypes gestureByTypes; + + // sort gestures by types + foreach (QGesture *gesture, gestures) { + QWidget *receiver = m_gestureTargets.value(gesture, 0); + Q_ASSERT(receiver); + gestureByTypes[gesture->gestureType()].insert(receiver, gesture); + } + + // for each gesture type + foreach (Qt::GestureType type, gestureByTypes.keys()) { + QHash<QWidget *, QGesture *> gestures = gestureByTypes.value(type); + foreach (QWidget *widget, gestures.keys()) { + QWidget *w = widget->parentWidget(); + while (w) { + QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator it + = w->d_func()->gestureContext.find(type); + if (it != w->d_func()->gestureContext.end()) { + // i.e. 'w' listens to gesture 'type' + Qt::GestureFlags flags = it.value(); + if (!(it.value() & Qt::DontStartGestureOnChildren) && w != widget) { + // conflicting gesture! + (*conflicts)[widget].append(gestures[widget]); + break; + } + } + if (w->isWindow()) { + w = 0; + break; + } + w = w->parentWidget(); + } + if (!w) + (*normal)[widget].append(gestures[widget]); + } + } +} + +void QGestureManager::deliverEvents(const QSet<QGesture *> &gestures, + QSet<QGesture *> *undeliveredGestures) +{ + if (gestures.isEmpty()) + return; + + typedef QMap<QWidget *, QList<QGesture *> > GesturesPerWidget; + GesturesPerWidget conflictedGestures; + GesturesPerWidget normalStartedGestures; + + QSet<QGesture *> startedGestures; + // first figure out the initial receivers of gestures + for (QSet<QGesture *>::const_iterator it = gestures.begin(), + e = gestures.end(); it != e; ++it) { + QGesture *gesture = *it; + QWidget *target = m_gestureTargets.value(gesture, 0); + if (!target) { + // the gesture has just started and doesn't have a target yet. + Q_ASSERT(gesture->state() == Qt::GestureStarted); + if (gesture->hasHotSpot()) { + // guess the target widget using the hotspot of the gesture + QPoint pt = gesture->hotSpot().toPoint(); + if (QWidget *w = qApp->topLevelAt(pt)) { + target = w->childAt(w->mapFromGlobal(pt)); + } + } else { + // or use the context of the gesture + QObject *context = m_gestureOwners.value(gesture, 0); + if (context->isWidgetType()) + target = static_cast<QWidget *>(context); + } + if (target) + m_gestureTargets.insert(gesture, target); + } + + Qt::GestureType gestureType = gesture->gestureType(); + Q_ASSERT(gestureType != Qt::CustomGesture); + + if (target) { + if (gesture->state() == Qt::GestureStarted) { + startedGestures.insert(gesture); + } else { + normalStartedGestures[target].append(gesture); + } + } else { + DEBUG() << "QGestureManager::deliverEvent: could not find the target for gesture" + << gesture->gestureType(); + qWarning("QGestureManager::deliverEvent: could not find the target for gesture"); + undeliveredGestures->insert(gesture); + } + } + + getGestureTargets(startedGestures, &conflictedGestures, &normalStartedGestures); + DEBUG() << "QGestureManager::deliverEvents:" + << "\nstarted: " << startedGestures + << "\nconflicted: " << conflictedGestures + << "\nnormal: " << normalStartedGestures + << "\n"; + + // if there are conflicting gestures, send the GestureOverride event + for (GesturesPerWidget::const_iterator it = conflictedGestures.begin(), + e = conflictedGestures.end(); it != e; ++it) { + QWidget *receiver = it.key(); + QList<QGesture *> gestures = it.value(); + DEBUG() << "QGestureManager::deliverEvents: sending GestureOverride to" + << receiver + << "gestures:" << gestures; + QGestureEvent event(gestures); + event.t = QEvent::GestureOverride; + // mark event and individual gestures as ignored + event.ignore(); + foreach(QGesture *g, gestures) + event.setAccepted(g, false); + + QApplication::sendEvent(receiver, &event); + bool eventAccepted = event.isAccepted(); + foreach(QGesture *gesture, event.gestures()) { + if (eventAccepted || event.isAccepted(gesture)) { + QWidget *w = event.d_func()->targetWidgets.value(gesture->gestureType(), 0); + Q_ASSERT(w); + DEBUG() << "override event: gesture was accepted:" << gesture << w; + QList<QGesture *> &gestures = normalStartedGestures[w]; + gestures.append(gesture); + // override the target + m_gestureTargets[gesture] = w; + } else { + DEBUG() << "override event: gesture wasn't accepted. putting back:" << gesture; + QList<QGesture *> &gestures = normalStartedGestures[receiver]; + gestures.append(gesture); + } + } + } + + // delivering gestures that are not in conflicted state + for (GesturesPerWidget::const_iterator it = normalStartedGestures.begin(), + e = normalStartedGestures.end(); it != e; ++it) { + if (!it.value().isEmpty()) { + DEBUG() << "QGestureManager::deliverEvents: sending to" << it.key() + << "gestures:" << it.value(); + QGestureEvent event(it.value()); + QApplication::sendEvent(it.key(), &event); + bool eventAccepted = event.isAccepted(); + foreach (QGesture *gesture, event.gestures()) { + if (gesture->state() == Qt::GestureStarted && + (eventAccepted || event.isAccepted(gesture))) { + QWidget *w = event.d_func()->targetWidgets.value(gesture->gestureType(), 0); + Q_ASSERT(w); + DEBUG() << "started gesture was delivered and accepted by" << w; + m_gestureTargets[gesture] = w; + } + } + } + } +} + +void QGestureManager::timerEvent(QTimerEvent *event) +{ + QHash<QGesture *, QBasicTimer>::iterator it = m_maybeGestures.begin(), + e = m_maybeGestures.end(); + for (; it != e; ) { + QBasicTimer &timer = it.value(); + Q_ASSERT(timer.isActive()); + if (timer.timerId() == event->timerId()) { + timer.stop(); + QGesture *gesture = it.key(); + it = m_maybeGestures.erase(it); + DEBUG() << "QGestureManager::timerEvent: gesture stopped due to timeout:" + << gesture; + recycle(gesture); + } else { + ++it; + } + } +} + +void QGestureManager::recycle(QGesture *gesture) +{ + QGestureRecognizer *recognizer = m_gestureToRecognizer.value(gesture, 0); + if (recognizer) { + gesture->setGestureCancelPolicy(QGesture::CancelNone); + recognizer->reset(gesture); + } else { + cleanupGesturesForRemovedRecognizer(gesture); + } +} + +QT_END_NAMESPACE + +#include "moc_qgesturemanager_p.cpp" diff --git a/src/gui/kernel/qgesturemanager_p.h b/src/gui/kernel/qgesturemanager_p.h new file mode 100644 index 0000000..4efa10b --- /dev/null +++ b/src/gui/kernel/qgesturemanager_p.h @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGESTUREMANAGER_P_H +#define QGESTUREMANAGER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qobject.h" +#include "qbasictimer.h" +#include "private/qwidget_p.h" +#include "qgesturerecognizer.h" + +QT_BEGIN_NAMESPACE + +class QBasicTimer; +class QGraphicsObject; +class QGestureManager : public QObject +{ + Q_OBJECT +public: + QGestureManager(QObject *parent); + ~QGestureManager(); + + Qt::GestureType registerGestureRecognizer(QGestureRecognizer *recognizer); + void unregisterGestureRecognizer(Qt::GestureType type); + + bool filterEvent(QWidget *receiver, QEvent *event); + bool filterEvent(QGesture *receiver, QEvent *event); +#ifndef QT_NO_GRAPHICSVIEW + bool filterEvent(QGraphicsObject *receiver, QEvent *event); +#endif //QT_NO_GRAPHICSVIEW + + static QGestureManager* instance(); + + void cleanupCachedGestures(QObject *target, Qt::GestureType type); + + void recycle(QGesture *gesture); + +protected: + void timerEvent(QTimerEvent *event); + bool filterEventThroughContexts(const QMultiHash<QObject *, Qt::GestureType> &contexts, + QEvent *event); + +private: + QMultiMap<Qt::GestureType, QGestureRecognizer *> m_recognizers; + + QSet<QGesture *> m_activeGestures; + QHash<QGesture *, QBasicTimer> m_maybeGestures; + + enum State { + Gesture, + NotGesture, + MaybeGesture // this means timers are up and waiting for some + // more events, and input events are handled by + // gesture recognizer explicitely + } state; + + struct ObjectGesture + { + QWeakPointer<QObject> object; + Qt::GestureType gesture; + + ObjectGesture(QObject *o, const Qt::GestureType &g) : object(o), gesture(g) { } + inline bool operator<(const ObjectGesture &rhs) const + { + if (object.data() < rhs.object.data()) + return true; + if (object == rhs.object) + return gesture < rhs.gesture; + return false; + } + }; + + QMap<ObjectGesture, QList<QGesture *> > m_objectGestures; + QHash<QGesture *, QGestureRecognizer *> m_gestureToRecognizer; + QHash<QGesture *, QObject *> m_gestureOwners; + + QHash<QGesture *, QWidget *> m_gestureTargets; + + int m_lastCustomGestureId; + + QHash<QGestureRecognizer *, QList<QGesture *> > m_obsoleteGestures; + QHash<QGesture *, QGestureRecognizer *> m_deletedRecognizers; + void cleanupGesturesForRemovedRecognizer(QGesture *gesture); + + QGesture *getState(QObject *widget, QGestureRecognizer *recognizer, + Qt::GestureType gesture); + void deliverEvents(const QSet<QGesture *> &gestures, + QSet<QGesture *> *undeliveredGestures); + void getGestureTargets(const QSet<QGesture*> &gestures, + QMap<QWidget *, QList<QGesture *> > *conflicts, + QMap<QWidget *, QList<QGesture *> > *normal); + + void cancelGesturesForChildren(QGesture *originatingGesture); +}; + +extern QGestureManager *qt_gestureManager; + +QT_END_NAMESPACE + +#endif // QGESTUREMANAGER_P_H diff --git a/src/gui/kernel/qgesturerecognizer.cpp b/src/gui/kernel/qgesturerecognizer.cpp new file mode 100644 index 0000000..ed0bdcc --- /dev/null +++ b/src/gui/kernel/qgesturerecognizer.cpp @@ -0,0 +1,230 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgesturerecognizer.h" + +#include "private/qgesture_p.h" +#include "private/qgesturemanager_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QGestureRecognizer + \since 4.6 + \brief The QGestureRecognizer class provides the infrastructure for gesture recognition. + \ingroup gestures + + Gesture recognizers are responsible for creating and managing QGesture objects and + monitoring input events sent to QWidget and QGraphicsObject subclasses. + QGestureRecognizer is the base class for implementing custom gestures. + + Developers that only need to provide gesture recognition for standard gestures do not + need to use this class directly. Instances will be created behind the scenes by the + framework. + + \section1 Recognizing Gestures + + The process of recognizing gestures involves filtering input events sent to specific + objects, and modifying the associated QGesture objects to include relevant information + about the user's input. + + Gestures are created when the framework calls create() to handle user input + for a particular instance of a QWidget or QGraphicsObject subclass. A QGesture object + is created for each widget or item that is configured to use gestures. + + Once a QGesture has been created for a target object, the gesture recognizer will + receive events for it in its recognize() handler function. + + When a gesture is canceled, the reset() function is called, giving the recognizer the + chance to update the appropriate properties in the corresponding QGesture object. + + \section1 Supporting New Gestures + + To add support for new gestures, you need to derive from QGestureRecognizer to create + a custom recognizer class, construct an instance of this class, and register it with + the application by calling QGestureRecognizer::registerRecognizer(). You can also + subclass QGesture to create a custom gesture class, or rely on dynamic properties + to express specific details of the gesture you want to handle. + + Your custom QGestureRecognizer subclass needs to reimplement the recognize() + function to handle and filter the incoming input events for QWidget and + QGraphicsObject subclasses. Although the logic for gesture recognition is + implemented in this function, you can store persistent information about the + state of the recognition process in the QGesture object supplied. The + recognize() function must return a value of QGestureRecognizer::Result that + indicates the state of recognition for a given gesture and target object. + This determines whether or not a gesture event will be delivered to a target + object. + + If you choose to represent a gesture by a custom QGesture subclass, you will need to + reimplement the create() function to construct instances of your gesture class. + Similarly, you may need to reimplement the reset() function if your custom gesture + objects need to be specially handled when a gesture is canceled. + + \sa QGesture +*/ + +/*! + \enum QGestureRecognizer::ResultFlag + + This enum describes the result of the current event filtering step in + a gesture recognizer state machine. + + The result consists of a state value (one of Ignore, MayBeGesture, + TriggerGesture, FinishGesture, CancelGesture) and an optional hint + (ConsumeEventHint). + + \value Ignore The event does not change the state of the recognizer. + + \value MayBeGesture The event changed the internal state of the recognizer, + but it isn't clear yet if it is a gesture or not. The recognizer needs to + filter more events to decide. Gesture recognizers in the MayBeGesture state + may be reset automatically if they take too long to recognize gestures. + + \value TriggerGesture The gesture has been triggered and the appropriate + QGesture object will be delivered to the target as a part of a + QGestureEvent. + + \value FinishGesture The gesture has been finished successfully and the + appropriate QGesture object will be delivered to the target as a part of a + QGestureEvent. + + \value CancelGesture The event made it clear that it is not a gesture. If + the gesture recognizer was in GestureTriggered state before, then the + gesture is canceled and the appropriate QGesture object will be delivered + to the target as a part of a QGestureEvent. + + \value ConsumeEventHint This hint specifies that the gesture framework + should consume the filtered event and not deliver it to the receiver. + + \omitvalue ResultState_Mask + \omitvalue ResultHint_Mask + + \sa QGestureRecognizer::recognize() +*/ + +/*! + Constructs a new gesture recognizer object. +*/ +QGestureRecognizer::QGestureRecognizer() +{ +} + +/*! + Destroys the gesture recognizer. +*/ +QGestureRecognizer::~QGestureRecognizer() +{ +} + +/*! + This function is called by Qt to create a new QGesture object for the + given \a target (QWidget or QGraphicsObject). + + Reimplement this function to create a custom QGesture-derived gesture + object if necessary. +*/ +QGesture *QGestureRecognizer::create(QObject *target) +{ + Q_UNUSED(target); + return new QGesture; +} + +/*! + This function is called by the framework to reset a given \a gesture. + + Reimplement this function to implement additional requirements for custom QGesture + objects. This may be necessary if you implement a custom QGesture whose properties + need special handling when the gesture is reset. +*/ +void QGestureRecognizer::reset(QGesture *gesture) +{ + if (gesture) { + QGesturePrivate *d = gesture->d_func(); + d->state = Qt::NoGesture; + d->hotSpot = QPointF(); + d->isHotSpotSet = false; + } +} + +/*! + \fn QGestureRecognizer::recognize(QGesture *gesture, QObject *watched, QEvent *event) + + Handles the given \a event for the \a watched object, updating the state of the \a gesture + object as required, and returns a suitable result for the current recognition step. + + This function is called by the framework to allow the recognizer to filter input events + dispatched to QWidget or QGraphicsObject instances that it is monitoring. + + The result reflects how much of the gesture has been recognized. The state of the + \a gesture object is set depending on the result. + + \sa QGestureRecognizer::Result +*/ + +/*! + Registers the given \a recognizer in the gesture framework and returns a gesture ID + for it. + + The application takes ownership of the \a recognizer and returns the gesture type + ID associated with it. For gesture recognizers which handle custom QGesture + objects (i.e., those which return Qt::CustomGesture in a QGesture::gestureType() + function) the return value is a generated gesture ID with the Qt::CustomGesture + flag set. + + \sa unregisterRecognizer(), QGestureRecognizer::create(), QGesture +*/ +Qt::GestureType QGestureRecognizer::registerRecognizer(QGestureRecognizer *recognizer) +{ + return QGestureManager::instance()->registerGestureRecognizer(recognizer); +} + +/*! + Unregisters all gesture recognizers of the specified \a type. + + \sa registerRecognizer() +*/ +void QGestureRecognizer::unregisterRecognizer(Qt::GestureType type) +{ + QGestureManager::instance()->unregisterGestureRecognizer(type); +} + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qgesturerecognizer.h b/src/gui/kernel/qgesturerecognizer.h new file mode 100644 index 0000000..4eebf7c --- /dev/null +++ b/src/gui/kernel/qgesturerecognizer.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGESTURERECOGNIZER_H +#define QGESTURERECOGNIZER_H + +#include <QtCore/qglobal.h> +#include <QtCore/qnamespace.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QObject; +class QEvent; +class QGesture; +class Q_GUI_EXPORT QGestureRecognizer +{ +public: + enum ResultFlag + { + Ignore = 0x0001, + + MayBeGesture = 0x0002, + TriggerGesture = 0x0004, + FinishGesture = 0x0008, + CancelGesture = 0x0010, + + ResultState_Mask = 0x00ff, + + ConsumeEventHint = 0x0100, + // StoreEventHint = 0x0200, + // ReplayStoredEventsHint = 0x0400, + // DiscardStoredEventsHint = 0x0800, + + ResultHint_Mask = 0xff00 + }; + Q_DECLARE_FLAGS(Result, ResultFlag) + + QGestureRecognizer(); + virtual ~QGestureRecognizer(); + + virtual QGesture *create(QObject *target); + virtual Result recognize(QGesture *state, QObject *watched, + QEvent *event) = 0; + virtual void reset(QGesture *state); + + static Qt::GestureType registerRecognizer(QGestureRecognizer *recognizer); + static void unregisterRecognizer(Qt::GestureType type); +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QGestureRecognizer::Result) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QGESTURERECOGNIZER_H diff --git a/src/gui/kernel/qgridlayout.cpp b/src/gui/kernel/qgridlayout.cpp index bc45352..d644e3a 100644 --- a/src/gui/kernel/qgridlayout.cpp +++ b/src/gui/kernel/qgridlayout.cpp @@ -980,8 +980,7 @@ QRect QGridLayoutPrivate::cellRect(int row, int col) const \brief The QGridLayout class lays out widgets in a grid. \ingroup geomanagement - \ingroup appearance - \mainclass + QGridLayout takes the space made available to it (by its parent layout or by the parentWidget()), divides it up into rows and @@ -1034,18 +1033,19 @@ QRect QGridLayoutPrivate::cellRect(int row, int col) const other layouts into the cells of your grid layout using addWidget(), addItem(), and addLayout(). - QGridLayout also includes two margin widths: the margin() and the - spacing(). The margin is the width of the reserved space along - each of the QGridLayout's four sides. The spacing is the width of - the automatically allocated spacing between neighboring boxes. + QGridLayout also includes two margin widths: + the \l{getContentsMargins()}{contents margin} and the spacing(). + The contents margin is the width of the reserved space along each + of the QGridLayout's four sides. The spacing() is the width of the + automatically allocated spacing between neighboring boxes. - The default margin() and spacing() values are provided by the - style. The default margin Qt styles specify is 9 for child - widgets and 11 for windows. The spacing defaults to the same as + The default contents margin values are provided by the + \l{QStyle::pixelMetric()}{style}. The default value Qt styles specify + is 9 for child widgets and 11 for windows. The spacing defaults to the same as the margin width for a top-level layout, or to the same as the parent layout. - \sa QBoxLayout, QStackedLayout, {Layout Classes}, {Basic Layouts Example} + \sa QBoxLayout, QStackedLayout, {Layout Management}, {Basic Layouts Example} */ @@ -1078,7 +1078,7 @@ QGridLayout::QGridLayout() #ifdef QT3_SUPPORT /*! - \obsolete + \obsolete Constructs a new QGridLayout with \a nRows rows, \a nCols columns and parent widget, \a parent. \a parent may not be 0. The grid layout is called \a name. diff --git a/src/gui/kernel/qguieventdispatcher_glib.cpp b/src/gui/kernel/qguieventdispatcher_glib.cpp index 6e98428..f8a638c 100644 --- a/src/gui/kernel/qguieventdispatcher_glib.cpp +++ b/src/gui/kernel/qguieventdispatcher_glib.cpp @@ -120,7 +120,7 @@ static gboolean x11EventSourceDispatch(GSource *s, GSourceFunc callback, gpointe // _qt_scrolldone protocols, queue all other // client messages if (event.xclient.format == 32) { - if (event.xclient.message_type == ATOM(WM_PROTOCOLS) || + if (event.xclient.message_type == ATOM(WM_PROTOCOLS) && (Atom) event.xclient.data.l[0] == ATOM(WM_TAKE_FOCUS)) { break; } else if (event.xclient.message_type == ATOM(_QT_SCROLL_DONE)) { diff --git a/src/gui/kernel/qguifunctions_wince.cpp b/src/gui/kernel/qguifunctions_wince.cpp index 4bfc14b..58e12ee 100644 --- a/src/gui/kernel/qguifunctions_wince.cpp +++ b/src/gui/kernel/qguifunctions_wince.cpp @@ -215,13 +215,7 @@ int qt_wince_GetDIBits(HDC /*hdc*/ , HBITMAP hSourceBitmap, uint, uint, LPVOID l return ret; } -bool qt_wince_TextOutW(HDC hdc, int x, int y, LPWSTR lpString, UINT c) -{ - return ExtTextOutW(hdc, x, y, 0, NULL, lpString, c, NULL); -} - - -HINSTANCE qt_wince_ShellExecute(HWND hwnd, LPCTSTR, LPCTSTR file, LPCTSTR params, LPCTSTR dir, int showCmd) +HINSTANCE qt_wince_ShellExecute(HWND hwnd, LPCWSTR, LPCWSTR file, LPCWSTR params, LPCWSTR dir, int showCmd) { SHELLEXECUTEINFO info; info.hwnd = hwnd; @@ -253,21 +247,40 @@ COLORREF qt_wince_PALETTEINDEX( WORD /*wPaletteIndex*/) return 0; } -BOOL qt_wince_TextOut( HDC hdc, int nXStart, int nYStart, LPCTSTR lpString, int cbString ) -{ - return ExtTextOut( hdc, nXStart, nYStart - 16, 0, NULL, lpString, cbString, NULL ); -} - // Internal Qt ----------------------------------------------------- bool qt_wince_is_platform(const QString &platformString) { - TCHAR tszPlatform[64]; - if (SystemParametersInfo(SPI_GETPLATFORMTYPE, - sizeof(tszPlatform)/sizeof(*tszPlatform),tszPlatform,0)) - if (0 == _tcsicmp(reinterpret_cast<const wchar_t *> (platformString.utf16()), tszPlatform)) + wchar_t tszPlatform[64]; + if (SystemParametersInfo(SPI_GETPLATFORMTYPE, sizeof(tszPlatform) / sizeof(wchar_t), tszPlatform, 0)) + if (0 == _tcsicmp(reinterpret_cast<const wchar_t *> (platformString.utf16()), tszPlatform)) return true; return false; } +int qt_wince_get_build() +{ + OSVERSIONINFO osvi; + osvi.dwOSVersionInfoSize = sizeof(osvi); + if (GetVersionEx(&osvi)) { + return osvi.dwBuildNumber; + } + return 0; +} + +int qt_wince_get_version() +{ + OSVERSIONINFO osvi; + osvi.dwOSVersionInfoSize = sizeof(osvi); + if (GetVersionEx(&osvi)) { + return (osvi.dwMajorVersion * 10 + osvi.dwMinorVersion); + } + return 0; +} + +bool qt_wince_is_windows_mobile_65() +{ + return ((qt_wince_get_version() == 52) && (qt_wince_get_build() > 2000)); +} + bool qt_wince_is_pocket_pc() { return qt_wince_is_platform(QString::fromLatin1("PocketPC")); } @@ -316,17 +329,14 @@ void qt_wince_maximize(QWidget *widget) void qt_wince_minimize(HWND hwnd) { - uint exstyle = GetWindowLongW(hwnd, GWL_EXSTYLE); - uint style = GetWindowLongW(hwnd, GWL_STYLE); - RECT rect; - RECT crect = {0,0,0,0}; - GetWindowRect(hwnd, &rect); - AdjustWindowRectEx(&crect, style & ~WS_OVERLAPPED, FALSE, exstyle); - MoveWindow(hwnd, rect.left - crect.left, rect.top - crect.top, 0, 0, true); - SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong (hwnd, GWL_EXSTYLE) | WS_EX_NODRAG); #ifdef Q_OS_WINCE_WM ShowWindow(hwnd, SW_HIDE); #else + if (!IsWindowVisible(hwnd)) { + // Hack for an initial showMinimized. + // Without it, our widget doesn't appear in the task bar. + ShowWindow(hwnd, SW_SHOW); + } ShowWindow(hwnd, SW_MINIMIZE); #endif } diff --git a/src/gui/kernel/qguifunctions_wince.h b/src/gui/kernel/qguifunctions_wince.h index 8817c10..b7b30a9 100644 --- a/src/gui/kernel/qguifunctions_wince.h +++ b/src/gui/kernel/qguifunctions_wince.h @@ -73,10 +73,6 @@ int qt_wince_GetDIBits(HDC, HBITMAP, uint, uint, void*, LPBITMAPINFO, uint); // QWidget #define SW_SHOWMINIMIZED SW_MINIMIZE -// QPaintEngine -bool qt_wince_TextOutW(HDC, int, int, LPWSTR, UINT); -#define TextOutW(a,b,c,d,e) qt_wince_TextOutW(a,b,c,d,e) - // QRegion #define ALTERNATE 0 #define WINDING 1 @@ -128,7 +124,7 @@ typedef struct tagTTPOLYCURVE #define TT_PRIM_CSPLINE 3 #define ANSI_VAR_FONT 12 -HINSTANCE qt_wince_ShellExecute(HWND hwnd, LPCTSTR operation, LPCTSTR file, LPCTSTR params, LPCTSTR dir, int showCmd); +HINSTANCE qt_wince_ShellExecute(HWND hwnd, LPCWSTR operation, LPCWSTR file, LPCWSTR params, LPCWSTR dir, int showCmd); #define ShellExecute(a,b,c,d,e,f) qt_wince_ShellExecute(a,b,c,d,e,f) @@ -150,8 +146,6 @@ HWND qt_wince_SetClipboardViewer( // Graphics --------------------------------------------------------- COLORREF qt_wince_PALETTEINDEX( WORD wPaletteIndex ); #define PALETTEINDEX(a) qt_wince_PALETTEINDEX(a) -BOOL qt_wince_TextOut( HDC hdc, int nXStart, int nYStart, LPCTSTR lpString, int cbString ); -#define TextOut(a,b,c,d,e) qt_wince_TextOut(a,b,c,d,e) #endif // Q_OS_WINCE #endif // QGUIFUNCTIONS_WCE_H diff --git a/src/gui/kernel/qguiplatformplugin.cpp b/src/gui/kernel/qguiplatformplugin.cpp new file mode 100644 index 0000000..e6efec1 --- /dev/null +++ b/src/gui/kernel/qguiplatformplugin.cpp @@ -0,0 +1,298 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qguiplatformplugin_p.h" +#include <qdebug.h> +#include <qfile.h> +#include <qdir.h> +#include <qsettings.h> +#include "private/qfactoryloader_p.h" +#include "qstylefactory.h" +#include "qapplication.h" +#include "qplatformdefs.h" +#include "qicon.h" + +#ifdef Q_WS_WINCE +#include "qguifunctions_wince.h" +extern bool qt_wince_is_smartphone(); //qguifunctions_wince.cpp +extern bool qt_wince_is_mobile(); //qguifunctions_wince.cpp +extern bool qt_wince_is_pocket_pc(); //qguifunctions_wince.cpp +#endif + + +#if defined(Q_WS_X11) +#include <private/qkde_p.h> +#include <private/qgtkstyle_p.h> +#include <private/qt_x11_p.h> +#endif + + +QT_BEGIN_NAMESPACE + + +/*! \internal + Return (an construct if necesseray) the Gui Platform plugin. + + The plugin key to be loaded is inside the QT_PLATFORM_PLUGIN environment variable. + If it is not set, it will be the DESKTOP_SESSION on X11. + + If no plugin can be loaded, the default one is returned. + */ +QGuiPlatformPlugin *qt_guiPlatformPlugin() +{ + static QGuiPlatformPlugin *plugin; + if (!plugin) + { +#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) + + QString key = QString::fromLocal8Bit(qgetenv("QT_PLATFORM_PLUGIN")); +#ifdef Q_WS_X11 + if (key.isEmpty()) { + switch(X11->desktopEnvironment) { + case DE_KDE: + key = QString::fromLatin1("kde"); + break; + default: + key = QString::fromLocal8Bit(qgetenv("DESKTOP_SESSION")); + break; + } + } +#endif + + if (!key.isEmpty() && QApplication::desktopSettingsAware()) { + QFactoryLoader loader(QGuiPlatformPluginInterface_iid, QLatin1String("/gui_platform")); + plugin = qobject_cast<QGuiPlatformPlugin *>(loader.instance(key)); + } +#endif // QT_NO_LIBRARY + + if(!plugin) { + static QGuiPlatformPlugin def; + plugin = &def; + } + } + return plugin; +} + + +/* \class QPlatformPlugin + QGuiPlatformPlugin can be used to integrate Qt applications in a platform built on top of Qt. + The application developer should not know or use the plugin, it is only used by Qt internaly. + + But full platform that are built on top of Qt may provide a plugin so 3rd party Qt application + running in the platform are integrated. + */ + +/* + The constructor can be used to install hooks in Qt + */ +QGuiPlatformPlugin::QGuiPlatformPlugin(QObject *parent) : QObject(parent) {} +QGuiPlatformPlugin::~QGuiPlatformPlugin() {} + + +/* return the string key to be used by default the application */ +QString QGuiPlatformPlugin::styleName() +{ +#if defined(Q_WS_WIN) && defined(Q_WS_WINCE) + if (qt_wince_is_smartphone() || qt_wince_is_pocket_pc()) + return QLatin1String("WindowsMobile"); + else + return QLatin1String("WindowsCE"); +#elif defined(Q_WS_WIN) + if ((QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA + && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)) + return QLatin1String("WindowsVista"); + else if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP + && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)) + return QLatin1String("WindowsXP"); + else + return QLatin1String("Windows"); // default styles for Windows +#elif defined(Q_WS_X11) && defined(Q_OS_SOLARIS) + return QLatin1String("CDE"); // default style for X11 on Solaris +#elif defined(Q_WS_S60) + return QLatin1String("S60"); // default style for Symbian with S60 +#elif defined(Q_OS_SYMBIAN) + return QLatin1String("Windows"); // default style for Symbian without S60 +#elif defined(Q_WS_X11) && defined(Q_OS_IRIX) + return QLatin1String("SGI"); // default style for X11 on IRIX +#elif defined(Q_WS_QWS) + return QLatin1String("Plastique"); // default style for X11 and small devices +#elif defined(Q_WS_MAC) + return QLatin1String("Macintosh"); // default style for all Mac's +#elif defined(Q_WS_X11) + QString stylename; + switch(X11->desktopEnvironment) { + case DE_KDE: + stylename = QKde::kdeStyle(); + break; + case DE_GNOME: { + QStringList availableStyles = QStyleFactory::keys(); + // Set QGtkStyle for GNOME if available + QString gtkStyleKey = QString::fromLatin1("GTK+"); + if (availableStyles.contains(gtkStyleKey)) { + stylename = gtkStyleKey; + break; + } + if (X11->use_xrender) + stylename = QLatin1String("cleanlooks"); + else + stylename = QLatin1String("windows"); + break; + } + case DE_CDE: + stylename = QLatin1String("cde"); + break; + default: + // Don't do anything + break; + } + return stylename; +#endif +} + +/* return an aditional default palette (only work on X11) */ +QPalette QGuiPlatformPlugin::palette() +{ +#ifdef Q_WS_X11 + if (QApplication::desktopSettingsAware() && X11->desktopEnvironment == DE_KDE) + return QKde::kdePalette(); +#endif + + return QPalette(); +} + +/* the default icon theme name for QIcon::fromTheme. */ +QString QGuiPlatformPlugin::systemIconThemeName() +{ + QString result; +#ifdef Q_WS_X11 + if (X11->desktopEnvironment == DE_GNOME) { + result = QString::fromLatin1("gnome"); +#ifndef QT_NO_STYLE_GTK + result = QGtkStylePrivate::getGConfString(QLatin1String("/desktop/gnome/interface/icon_theme"), result); +#endif + } else if (X11->desktopEnvironment == DE_KDE) { + result = X11->desktopVersion >= 4 ? QString::fromLatin1("oxygen") : QString::fromLatin1("crystalsvg"); + QSettings settings(QKde::kdeHome() + QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat); + settings.beginGroup(QLatin1String("Icons")); + result = settings.value(QLatin1String("Theme"), result).toString(); + } +#endif + return result; +} + + +QStringList QGuiPlatformPlugin::iconThemeSearchPaths() +{ + QStringList paths; +#if defined(Q_WS_X11) + QString xdgDirString = QFile::decodeName(getenv("XDG_DATA_DIRS")); + if (xdgDirString.isEmpty()) + xdgDirString = QLatin1String("/usr/local/share/:/usr/share/"); + + QStringList xdgDirs = xdgDirString.split(QLatin1Char(':')); + + for (int i = 0 ; i < xdgDirs.size() ; ++i) { + QDir dir(xdgDirs[i]); + if (dir.exists()) + paths.append(dir.path() + QLatin1String("/icons")); + } + if (X11->desktopEnvironment == DE_KDE) { + paths << QLatin1Char(':') + QKde::kdeHome() + QLatin1String("/share/icons"); + QStringList kdeDirs = QFile::decodeName(getenv("KDEDIRS")).split(QLatin1Char(':')); + for (int i = 0 ; i< kdeDirs.count() ; ++i) { + QDir dir(QLatin1Char(':') + kdeDirs.at(i) + QLatin1String("/share/icons")); + if (dir.exists()) + paths.append(dir.path()); + } + } + + // Add home directory first in search path + QDir homeDir(QDir::homePath() + QLatin1String("/.icons")); + if (homeDir.exists()) + paths.prepend(homeDir.path()); +#endif + +#if defined(Q_WS_WIN) + paths.append(qApp->applicationDirPath() + QLatin1String("/icons")); +#elif defined(Q_WS_MAC) + paths.append(qApp->applicationDirPath() + QLatin1String("/../Resources/icons")); +#endif + return paths; +} + +/* backend for QFileIconProvider, null icon means default */ +QIcon QGuiPlatformPlugin::fileSystemIcon(const QFileInfo &) +{ + return QIcon(); +} + +/* Like QStyle::styleHint */ +int QGuiPlatformPlugin::platformHint(PlatformHint hint) +{ + int ret = 0; + switch(hint) + { + case PH_ToolButtonStyle: + ret = Qt::ToolButtonIconOnly; +#ifdef Q_WS_X11 + if (X11->desktopEnvironment == DE_KDE && X11->desktopVersion >= 4 + && QApplication::desktopSettingsAware()) { + ret = QKde::kdeToolButtonStyle(); + } +#endif + break; + case PH_ToolBarIconSize: +#ifdef Q_WS_X11 + if (X11->desktopEnvironment == DE_KDE && X11->desktopVersion >= 4 + && QApplication::desktopSettingsAware()) { + ret = QKde::kdeToolBarIconSize(); + } +#endif + //by default keep ret = 0 so QCommonStyle will use the style default + break; + default: + break; + } + return ret; +} + + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qguiplatformplugin_p.h b/src/gui/kernel/qguiplatformplugin_p.h new file mode 100644 index 0000000..2a70ee7 --- /dev/null +++ b/src/gui/kernel/qguiplatformplugin_p.h @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGUIPLATFORM_P_H +#define QGUIPLATFORM_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 <QtCore/qplugin.h> +#include <QtCore/qfactoryinterface.h> +#include <QtGui/qdialog.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QStyle; +class QPalette; +class QIcon; +class QFileDialog; +class QColorDialog; +class QFileInfo; + +struct Q_GUI_EXPORT QGuiPlatformPluginInterface : public QFactoryInterface +{ +}; + +#define QGuiPlatformPluginInterface_iid "com.nokia.qt.QGuiPlatformPluginInterface" + +Q_DECLARE_INTERFACE(QGuiPlatformPluginInterface, QGuiPlatformPluginInterface_iid) + +class Q_GUI_EXPORT QGuiPlatformPlugin : public QObject, public QGuiPlatformPluginInterface +{ + Q_OBJECT + Q_INTERFACES(QGuiPlatformPluginInterface:QFactoryInterface) + public: + explicit QGuiPlatformPlugin(QObject *parent = 0); + ~QGuiPlatformPlugin(); + + virtual QStringList keys() const { return QStringList() << QLatin1String("default"); }; + + virtual QString styleName(); + virtual QPalette palette(); + virtual QString systemIconThemeName(); + virtual QStringList iconThemeSearchPaths(); + virtual QIcon fileSystemIcon(const QFileInfo &); + + enum PlatformHint { PH_ToolButtonStyle, PH_ToolBarIconSize, PH_ItemView_ActivateItemOnSingleClick }; + virtual int platformHint(PlatformHint hint); + + + virtual void fileDialogDelete(QFileDialog *) {} + virtual bool fileDialogSetVisible(QFileDialog *, bool) { return false; } + virtual QDialog::DialogCode fileDialogResultCode(QFileDialog *) { return QDialog::Rejected; } + virtual void fileDialogSetDirectory(QFileDialog *, const QString &) {} + virtual QString fileDialogDirectory(const QFileDialog *) const { return QString(); } + virtual void fileDialogSelectFile(QFileDialog *, const QString &) {} + virtual QStringList fileDialogSelectedFiles(const QFileDialog *) const { return QStringList(); } + virtual void fileDialogSetFilter(QFileDialog *) {} + virtual void fileDialogSetNameFilters(QFileDialog *, const QStringList &) {} + virtual void fileDialogSelectNameFilter(QFileDialog *, const QString &) {} + virtual QString fileDialogSelectedNameFilter(const QFileDialog *) const { return QString(); } + + virtual void colorDialogDelete(QColorDialog *) {} + virtual bool colorDialogSetVisible(QColorDialog *, bool) { return false; } + virtual void colorDialogSetCurrentColor(QColorDialog *, const QColor &) {} +}; + +//internal +QGuiPlatformPlugin *qt_guiPlatformPlugin(); + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QGUIPLATFORMPLUGIN_H diff --git a/src/gui/kernel/qguivariant.cpp b/src/gui/kernel/qguivariant.cpp index e3900ad..59bdc36 100644 --- a/src/gui/kernel/qguivariant.cpp +++ b/src/gui/kernel/qguivariant.cpp @@ -60,6 +60,11 @@ #include "qregion.h" #include "qsizepolicy.h" #include "qtextformat.h" +#include "qmatrix4x4.h" +#include "qvector2d.h" +#include "qvector3d.h" +#include "qvector4d.h" +#include "qquaternion.h" #include "private/qvariant_p.h" @@ -148,6 +153,31 @@ static void construct(QVariant::Private *x, const void *copy) v_construct<QColor>(x, &color); break; } +#ifndef QT_NO_MATRIX4X4 + case QVariant::Matrix4x4: + v_construct<QMatrix4x4>(x, copy); + break; +#endif +#ifndef QT_NO_VECTOR2D + case QVariant::Vector2D: + v_construct<QVector2D>(x, copy); + break; +#endif +#ifndef QT_NO_VECTOR3D + case QVariant::Vector3D: + v_construct<QVector3D>(x, copy); + break; +#endif +#ifndef QT_NO_VECTOR4D + case QVariant::Vector4D: + v_construct<QVector4D>(x, copy); + break; +#endif +#ifndef QT_NO_QUATERNION + case QVariant::Quaternion: + v_construct<QQuaternion>(x, copy); + break; +#endif default: qcoreVariantHandler()->construct(x, copy); return; @@ -221,6 +251,31 @@ static void clear(QVariant::Private *d) case QVariant::Pen: v_clear<QPen>(d); break; +#ifndef QT_NO_MATRIX4X4 + case QVariant::Matrix4x4: + v_clear<QMatrix4x4>(d); + break; +#endif +#ifndef QT_NO_VECTOR2D + case QVariant::Vector2D: + v_clear<QVector2D>(d); + break; +#endif +#ifndef QT_NO_VECTOR3D + case QVariant::Vector3D: + v_clear<QVector3D>(d); + break; +#endif +#ifndef QT_NO_VECTOR4D + case QVariant::Vector4D: + v_clear<QVector4D>(d); + break; +#endif +#ifndef QT_NO_QUATERNION + case QVariant::Quaternion: + v_clear<QVector4D>(d); + break; +#endif default: qcoreVariantHandler()->clear(d); return; @@ -266,7 +321,26 @@ static bool isNull(const QVariant::Private *d) case QVariant::KeySequence: #endif case QVariant::Pen: +#ifndef QT_NO_MATRIX4X4 + case QVariant::Matrix4x4: +#endif break; +#ifndef QT_NO_VECTOR2D + case QVariant::Vector2D: + return v_cast<QVector2D>(d)->isNull(); +#endif +#ifndef QT_NO_VECTOR3D + case QVariant::Vector3D: + return v_cast<QVector3D>(d)->isNull(); +#endif +#ifndef QT_NO_VECTOR4D + case QVariant::Vector4D: + return v_cast<QVector4D>(d)->isNull(); +#endif +#ifndef QT_NO_QUATERNION + case QVariant::Quaternion: + return v_cast<QQuaternion>(d)->isNull(); +#endif default: return qcoreVariantHandler()->isNull(d); } @@ -326,6 +400,26 @@ static bool compare(const QVariant::Private *a, const QVariant::Private *b) #endif case QVariant::Pen: return *v_cast<QPen>(a) == *v_cast<QPen>(b); +#ifndef QT_NO_MATRIX4X4 + case QVariant::Matrix4x4: + return *v_cast<QMatrix4x4>(a) == *v_cast<QMatrix4x4>(b); +#endif +#ifndef QT_NO_VECTOR2D + case QVariant::Vector2D: + return *v_cast<QVector2D>(a) == *v_cast<QVector2D>(b); +#endif +#ifndef QT_NO_VECTOR3D + case QVariant::Vector3D: + return *v_cast<QVector3D>(a) == *v_cast<QVector3D>(b); +#endif +#ifndef QT_NO_VECTOR4D + case QVariant::Vector4D: + return *v_cast<QVector4D>(a) == *v_cast<QVector4D>(b); +#endif +#ifndef QT_NO_QUATERNION + case QVariant::Quaternion: + return *v_cast<QQuaternion>(a) == *v_cast<QQuaternion>(b); +#endif default: break; } @@ -513,6 +607,31 @@ static void streamDebug(QDebug dbg, const QVariant &v) case QVariant::Pen: dbg.nospace() << qvariant_cast<QPen>(v); break; +#ifndef QT_NO_MATRIX4X4 + case QVariant::Matrix4x4: + dbg.nospace() << qvariant_cast<QMatrix4x4>(v); + break; +#endif +#ifndef QT_NO_VECTOR2D + case QVariant::Vector2D: + dbg.nospace() << qvariant_cast<QVector2D>(v); + break; +#endif +#ifndef QT_NO_VECTOR3D + case QVariant::Vector3D: + dbg.nospace() << qvariant_cast<QVector3D>(v); + break; +#endif +#ifndef QT_NO_VECTOR4D + case QVariant::Vector4D: + dbg.nospace() << qvariant_cast<QVector4D>(v); + break; +#endif +#ifndef QT_NO_QUATERNION + case QVariant::Quaternion: + dbg.nospace() << qvariant_cast<QQuaternion>(v); + break; +#endif default: qcoreVariantHandler()->debugStream(dbg, v); break; @@ -596,6 +715,21 @@ Q_DECL_METATYPE_HELPER(QTextLength) Q_DECL_METATYPE_HELPER(QTextFormat) Q_DECL_METATYPE_HELPER(QMatrix) Q_DECL_METATYPE_HELPER(QTransform) +#ifndef QT_NO_MATRIX4X4 +Q_DECL_METATYPE_HELPER(QMatrix4x4) +#endif +#ifndef QT_NO_VECTOR2D +Q_DECL_METATYPE_HELPER(QVector2D) +#endif +#ifndef QT_NO_VECTOR3D +Q_DECL_METATYPE_HELPER(QVector3D) +#endif +#ifndef QT_NO_VECTOR4D +Q_DECL_METATYPE_HELPER(QVector4D) +#endif +#ifndef QT_NO_QUATERNION +Q_DECL_METATYPE_HELPER(QQuaternion) +#endif #ifdef QT_NO_DATASTREAM # define Q_IMPL_METATYPE_HELPER(TYPE) \ @@ -645,7 +779,32 @@ static const QMetaTypeGuiHelper qVariantGuiHelper[] = { Q_IMPL_METATYPE_HELPER(QTextLength), Q_IMPL_METATYPE_HELPER(QTextFormat), Q_IMPL_METATYPE_HELPER(QMatrix), - Q_IMPL_METATYPE_HELPER(QTransform) + Q_IMPL_METATYPE_HELPER(QTransform), +#ifndef QT_NO_MATRIX4X4 + Q_IMPL_METATYPE_HELPER(QMatrix4x4), +#else + {0, 0, 0, 0}, +#endif +#ifndef QT_NO_VECTOR2D + Q_IMPL_METATYPE_HELPER(QVector2D), +#else + {0, 0, 0, 0}, +#endif +#ifndef QT_NO_VECTOR3D + Q_IMPL_METATYPE_HELPER(QVector3D), +#else + {0, 0, 0, 0}, +#endif +#ifndef QT_NO_VECTOR4D + Q_IMPL_METATYPE_HELPER(QVector4D), +#else + {0, 0, 0, 0}, +#endif +#ifndef QT_NO_QUATERNION + Q_IMPL_METATYPE_HELPER(QQuaternion) +#else + {0, 0, 0, 0} +#endif }; static const QVariant::Handler *qt_guivariant_last_handler = 0; diff --git a/src/gui/kernel/qkde.cpp b/src/gui/kernel/qkde.cpp new file mode 100644 index 0000000..edc53ac --- /dev/null +++ b/src/gui/kernel/qkde.cpp @@ -0,0 +1,176 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qkde_p.h" +#include <QtCore/QLibrary> +#include <QtCore/QDir> +#include <QtCore/qdebug.h> +#include <QtCore/QSettings> +#include "QtGui/qstylefactory.h" +#include "qt_x11_p.h" + +#if defined(Q_WS_X11) + +QT_BEGIN_NAMESPACE + +/*! \internal +Gets the current KDE home path +like "/home/troll/.kde" +*/ +QString QKde::kdeHome() +{ + static QString kdeHomePath; + if (kdeHomePath.isEmpty()) { + kdeHomePath = QString::fromLocal8Bit(qgetenv("KDEHOME")); + if (kdeHomePath.isEmpty()) { + QDir homeDir(QDir::homePath()); + QString kdeConfDir(QLatin1String("/.kde")); + if (4 == X11->desktopVersion && homeDir.exists(QLatin1String(".kde4"))) + kdeConfDir = QLatin1String("/.kde4"); + kdeHomePath = QDir::homePath() + kdeConfDir; + } + } + return kdeHomePath; +} + +/*!\internal + Reads the color from the config, and store it in the palette with the given color role if found + */ +static bool kdeColor(QPalette *pal, QPalette::ColorRole role, const QSettings &kdeSettings, const QString &kde4Key, const QString &kde3Key = QString()) +{ + QVariant variant = kdeSettings.value(kde4Key); + if (!variant.isValid()) + QVariant variant = kdeSettings.value(kde3Key); + if (variant.isValid()) { + QStringList values = variant.toStringList(); + if (values.size() == 3) { + int r = values[0].toInt(); + int g = values[1].toInt(); + int b = values[2].toInt(); + pal->setBrush(role, QColor(r, g, b)); + return true; + } + } + return false; +} + + +/*!\internal + Returns the KDE palette +*/ +QPalette QKde::kdePalette() +{ + const QSettings theKdeSettings(QKde::kdeHome() + + QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat); + QPalette pal; + + // Setup KDE palette + kdeColor(&pal, QPalette::Button, theKdeSettings, QLatin1String("Colors:Button/BackgroundNormal"), QLatin1String("buttonBackground")); + kdeColor(&pal, QPalette::Window, theKdeSettings, QLatin1String("Colors:Window/BackgroundNormal"), QLatin1String("background")); + kdeColor(&pal, QPalette::Text, theKdeSettings, QLatin1String("Colors:View/ForegroundNormal"), QLatin1String("foreground")); + kdeColor(&pal, QPalette::WindowText, theKdeSettings, QLatin1String("Colors:Window/ForegroundNormal"), QLatin1String("windowForeground")); + kdeColor(&pal, QPalette::Base, theKdeSettings, QLatin1String("Colors:View/BackgroundNormal"), QLatin1String("windowBackground")); + kdeColor(&pal, QPalette::Highlight, theKdeSettings, QLatin1String("Colors:Selection/BackgroundNormal"), QLatin1String("selectBackground")); + kdeColor(&pal, QPalette::HighlightedText, theKdeSettings, QLatin1String("Colors:Selection/ForegroundNormal"), QLatin1String("selectForeground")); + kdeColor(&pal, QPalette::AlternateBase, theKdeSettings, QLatin1String("Colors:View/BackgroundAlternate"), QLatin1String("alternateBackground")); + kdeColor(&pal, QPalette::ButtonText, theKdeSettings, QLatin1String("Colors:Button/ForegroundNormal"), QLatin1String("buttonForeground")); + kdeColor(&pal, QPalette::Link, theKdeSettings, QLatin1String("Colors:View/ForegroundLink"), QLatin1String("linkColor")); + kdeColor(&pal, QPalette::LinkVisited, theKdeSettings, QLatin1String("Colors:View/ForegroundVisited"), QLatin1String("visitedLinkColor")); + //## TODO tooltip color + + return pal; +} + +/*!\internal + Returns the name of the QStyle to use. + (read from the kde config if needed) +*/ +QString QKde::kdeStyle() +{ + if (X11->desktopVersion >= 4) { + QSettings kdeSettings(QKde::kdeHome() + QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat); + QString style = kdeSettings.value(QLatin1String("widgetStyle"), QLatin1String("Oxygen")).toString(); + + QStringList availableStyles = QStyleFactory::keys(); + if(availableStyles.contains(style, Qt::CaseInsensitive)) + return style; + } + + if (X11->use_xrender) + return QLatin1String("plastique"); + else + return QLatin1String("windows"); +} + + +int QKde::kdeToolButtonStyle() +{ + QSettings settings(QKde::kdeHome() + QLatin1String("/share/config/kdeglobals"), + QSettings::IniFormat); + settings.beginGroup(QLatin1String("Toolbar style")); + QString toolbarStyle = settings.value(QLatin1String("ToolButtonStyle"), QLatin1String("TextBesideIcon")).toString(); + if (toolbarStyle == QLatin1String("TextBesideIcon")) + return Qt::ToolButtonTextBesideIcon; + else if (toolbarStyle == QLatin1String("TextOnly")) + return Qt::ToolButtonTextOnly; + else if (toolbarStyle == QLatin1String("TextUnderIcon")) + return Qt::ToolButtonTextUnderIcon; + + return Qt::ToolButtonTextBesideIcon; +} + +int QKde::kdeToolBarIconSize() +{ + static int iconSize = -1; + if (iconSize == -1) { + QSettings settings(QKde::kdeHome() + QLatin1String("/share/config/kdeglobals"), + QSettings::IniFormat); + settings.beginGroup(QLatin1String("ToolbarIcons")); + iconSize = settings.value(QLatin1String("Size")).toInt(); + } + return iconSize; +} + +QT_END_NAMESPACE + +#endif //Q_WS_X11 + diff --git a/src/gui/kernel/qkde_p.h b/src/gui/kernel/qkde_p.h new file mode 100644 index 0000000..c22a145 --- /dev/null +++ b/src/gui/kernel/qkde_p.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QKDE_H +#define QKDE_H + +#include <QtCore/qglobal.h> +#include <QtGui/QPalette> +#include <QtGui/QIcon> + +// +// 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. +// +#if defined(Q_WS_X11) + + +QT_BEGIN_NAMESPACE + +/*!\internal + This namespace contains helper function to help KDE integration + They are only used if we detect the use of KDE and the KDE platform plugin is not found (old KDE version) + Or if the detected KDE version is KDE3 +*/ +namespace QKde { + QString kdeHome(); + QString kdeStyle(); + QPalette kdePalette(); + int kdeToolButtonStyle(); + int kdeToolBarIconSize(); +} + + +QT_END_NAMESPACE + +#endif // Q_WS_X11 +#endif // QKDE_H diff --git a/src/gui/kernel/qkeymapper.cpp b/src/gui/kernel/qkeymapper.cpp index 3c4a650..283acf9 100644 --- a/src/gui/kernel/qkeymapper.cpp +++ b/src/gui/kernel/qkeymapper.cpp @@ -51,7 +51,6 @@ QT_BEGIN_NAMESPACE /*! \class QKeyMapper \since 4.2 - \ingroup application \internal \sa QObject @@ -116,6 +115,4 @@ QKeyMapperPrivate *qt_keymapper_private() return QKeyMapper::instance()->d_func(); } -Q_GUI_EXPORT QList<int> qt_keymapper_possibleKeys(QKeyEvent *e) { return QKeyMapper::instance()->possibleKeys(e); } - QT_END_NAMESPACE diff --git a/src/gui/kernel/qkeymapper_mac.cpp b/src/gui/kernel/qkeymapper_mac.cpp index b77cc0f..b7c2711 100644 --- a/src/gui/kernel/qkeymapper_mac.cpp +++ b/src/gui/kernel/qkeymapper_mac.cpp @@ -48,6 +48,7 @@ #include <qinputcontext.h> #include <private/qkeymapper_p.h> #include <private/qapplication_p.h> +#include <private/qmacinputcontext_p.h> QT_BEGIN_NAMESPACE @@ -160,6 +161,14 @@ Qt::KeyboardModifiers qt_mac_get_modifiers(int keys) ret |= Qt::KeyboardModifier(qt_mac_modifier_symbols[i].qt_code); } } + if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) { + Qt::KeyboardModifiers oldModifiers = ret; + ret &= ~(Qt::MetaModifier | Qt::ControlModifier); + if (oldModifiers & Qt::ControlModifier) + ret |= Qt::MetaModifier; + if (oldModifiers & Qt::MetaModifier) + ret |= Qt::ControlModifier; + } return ret; } static int qt_mac_get_mac_modifiers(Qt::KeyboardModifiers keys) @@ -176,6 +185,15 @@ static int qt_mac_get_mac_modifiers(Qt::KeyboardModifiers keys) ret |= qt_mac_modifier_symbols[i].mac_code; } } + + if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) { + int oldModifiers = ret; + ret &= ~(controlKeyBit | cmdKeyBit); + if (oldModifiers & controlKeyBit) + ret |= cmdKeyBit; + if (oldModifiers & cmdKeyBit) + ret |= controlKeyBit; + } return ret; } void qt_mac_send_modifiers_changed(quint32 modifiers, QObject *object) @@ -480,7 +498,8 @@ static bool translateKeyEventInternal(EventHandlerCallRef er, EventRef keyEvent, #ifdef QT_MAC_USE_COCOA if (outHandled) { qt_mac_eat_unicode_key = false; - CallNextEventHandler(er, keyEvent); + if (er) + CallNextEventHandler(er, keyEvent); *outHandled = qt_mac_eat_unicode_key; } #endif @@ -544,7 +563,7 @@ QKeyMapperPrivate::QKeyMapperPrivate() QKeyMapperPrivate::~QKeyMapperPrivate() { - clearMappings(); + deleteLayouts(); } bool @@ -639,7 +658,7 @@ QKeyMapperPrivate::updateKeyboard() } void -QKeyMapperPrivate::clearMappings() +QKeyMapperPrivate::deleteLayouts() { keyboard_mode = NullMode; for (int i = 0; i < 255; ++i) { @@ -648,6 +667,12 @@ QKeyMapperPrivate::clearMappings() keyLayout[i] = 0; } } +} + +void +QKeyMapperPrivate::clearMappings() +{ + deleteLayouts(); updateKeyboard(); } @@ -692,8 +717,14 @@ bool QKeyMapperPrivate::translateKeyEvent(QWidget *widget, EventHandlerCallRef e return true; } - if (qApp->inputContext() && qApp->inputContext()->isComposing()) + if (qApp->inputContext() && qApp->inputContext()->isComposing()) { + if (ekind == kEventRawKeyDown) { + QMacInputContext *context = qobject_cast<QMacInputContext*>(qApp->inputContext()); + if (context) + context->setLastKeydownEvent(event); + } return false; + } //get modifiers Qt::KeyboardModifiers modifiers; int qtKey; @@ -704,8 +735,10 @@ bool QKeyMapperPrivate::translateKeyEvent(QWidget *widget, EventHandlerCallRef e QString text(ourChar); /* This is actually wrong - but unfortunatly it is the best that can be done for now because of the Control/Meta mapping problems */ - if (modifiers & (Qt::ControlModifier | Qt::MetaModifier)) + if (modifiers & (Qt::ControlModifier | Qt::MetaModifier) + && !qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) { text = QString(); + } if (widget) { @@ -721,7 +754,8 @@ bool QKeyMapperPrivate::translateKeyEvent(QWidget *widget, EventHandlerCallRef e //is it of use to text services? If so we won't bother //with a QKeyEvent. qt_mac_eat_unicode_key = false; - CallNextEventHandler(er, event); + if (er) + CallNextEventHandler(er, event); extern bool qt_mac_menubar_is_open(); if (qt_mac_eat_unicode_key || qt_mac_menubar_is_open()) { return true; diff --git a/src/gui/kernel/qkeymapper_p.h b/src/gui/kernel/qkeymapper_p.h index 2ed4998..f1b4252 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..d272d6e --- /dev/null +++ b/src/gui/kernel/qkeymapper_s60.cpp @@ -0,0 +1,247 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $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 8138839..f95efa2 100644 --- a/src/gui/kernel/qkeymapper_win.cpp +++ b/src/gui/kernel/qkeymapper_win.cpp @@ -41,7 +41,7 @@ #include "qkeymapper_p.h" -#include <windows.h> +#include <qt_windows.h> #include <qdebug.h> #include <private/qevent_p.h> #include <private/qlocale_p.h> @@ -57,9 +57,7 @@ QT_BEGIN_NAMESPACE // Implemented elsewhere extern "C" LRESULT CALLBACK QtWndProc(HWND, UINT, WPARAM, LPARAM); -Q_CORE_EXPORT bool winPostMessage(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); -Q_CORE_EXPORT bool winPeekMessage(MSG* msg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, - UINT wRemoveMsg); + extern Q_CORE_EXPORT QLocale qt_localeFromLCID(LCID id); #ifndef LANG_PASHTO #define LANG_PASHTO 0x63 @@ -435,6 +433,23 @@ static const Qt::KeyboardModifiers ModsTbl[] = { Qt::NoModifier, // Fall-back to raw Key_* }; +/** + Remap return or action key to select key for windows mobile. +*/ +inline int winceKeyBend(int keyCode) +{ +#if defined(Q_OS_WINCE_WM) && defined(QT_KEYPAD_NAVIGATION) + // remap return or action key to select key for windows mobile. + // will be changed to a table remapping function in the next version (4.6/7). + if (keyCode == VK_RETURN && QApplication::keypadNavigationEnabled()) + return Qt::Key_Select; + else + return KeyTbl[keyCode]; +#else + return KeyTbl[keyCode]; +#endif +} + #if defined(Q_OS_WINCE) // Use the KeyTbl to resolve a Qt::Key out of the virtual keys. // In case it is not resolvable, continue using the virtual key itself. @@ -467,19 +482,14 @@ static inline int toKeyOrUnicode(int vk, int scancode, unsigned char *kbdBuffer, Q_ASSERT(vk > 0 && vk < 256); int code = 0; QChar unicodeBuffer[5]; - int res = 0; - if (QSysInfo::WindowsVersion < QSysInfo::WV_NT) - res = ToAscii(vk, scancode, kbdBuffer, reinterpret_cast<LPWORD>(unicodeBuffer), 0); - else - res = ToUnicode(vk, scancode, kbdBuffer, reinterpret_cast<LPWSTR>(unicodeBuffer), 5, 0); - + int res = ToUnicode(vk, scancode, kbdBuffer, reinterpret_cast<LPWSTR>(unicodeBuffer), 5, 0); if (res) code = unicodeBuffer[0].toUpper().unicode(); // Qt::Key_*'s are not encoded below 0x20, so try again, and DEL keys (0x7f) is encoded with a // proper Qt::Key_ code if (code < 0x20 || code == 0x7f) // Handles res==0 too - code = KeyTbl[vk]; + code = winceKeyBend(vk); if (isDeadkey) *isDeadkey = (res == -1); @@ -489,7 +499,7 @@ static inline int toKeyOrUnicode(int vk, int scancode, unsigned char *kbdBuffer, Q_GUI_EXPORT int qt_translateKeyCode(int vk) { - int code = (vk < 0 || vk > 255) ? 0 : KeyTbl[vk]; + int code = winceKeyBend((vk < 0 || vk > 255) ? 0 : vk); return code == Qt::Key_unknown ? 0 : code; } @@ -504,38 +514,6 @@ static inline int asciiToKeycode(char a, int state) return a & 0xff; } -static int inputcharset = CP_ACP; -static inline QChar wmchar_to_unicode(DWORD c) -{ - // qt_winMB2QString is the generalization of this function. - QT_WA({ - return QChar((ushort)c); - } , { - char mb[2]; - mb[0] = c & 0xff; - mb[1] = 0; - WCHAR wc[1]; - MultiByteToWideChar(inputcharset, MB_PRECOMPOSED, mb, -1, wc, 1); - return QChar(wc[0]); - }); -} - -static inline QChar imechar_to_unicode(DWORD c) -{ - // qt_winMB2QString is the generalization of this function. - QT_WA({ - return QChar((ushort)c); - } , { - char mb[3]; - mb[0] = (c >> 8) & 0xff; - mb[1] = c & 0xff; - mb[2] = 0; - WCHAR wc[1]; - MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, mb, -1, wc, 1); - return QChar(wc[0]); - }); -} - static inline bool isModifierKey(int code) { return (code >= Qt::Key_Shift) && (code <= Qt::Key_ScrollLock); @@ -621,10 +599,10 @@ QKeyMapperPrivate::QKeyMapperPrivate() QKeyMapperPrivate::~QKeyMapperPrivate() { - clearMappings(); + deleteLayouts(); } -void QKeyMapperPrivate::clearMappings() +void QKeyMapperPrivate::deleteLayouts() { for (int i = 0; i < 255; ++i) { if (keyLayout[i]) { @@ -632,46 +610,23 @@ void QKeyMapperPrivate::clearMappings() keyLayout[i] = 0; } } +} + +void QKeyMapperPrivate::clearMappings() +{ + deleteLayouts(); /* MAKELCID()'s first argument is a WORD, and GetKeyboardLayout() * returns a DWORD. */ -// LCID newLCID = MAKELCID(DWORD(GetKeyboardLayout(0)), SORT_DEFAULT); + + LCID newLCID = MAKELCID((DWORD)GetKeyboardLayout(0), SORT_DEFAULT); // keyboardInputLocale = qt_localeFromLCID(newLCID); - LCID newLCID = MAKELCID( - reinterpret_cast<long>(GetKeyboardLayout(0)), - SORT_DEFAULT - ); - keyboardInputLocale = qt_localeFromLCID(newLCID); + bool bidi = false; -#ifdef UNICODE - if (QSysInfo::WindowsVersion >= QSysInfo::WV_2000) { - WCHAR wchLCIDFontSig[16]; - if (GetLocaleInfoW(newLCID, - LOCALE_FONTSIGNATURE, - &wchLCIDFontSig[0], - (sizeof(wchLCIDFontSig)/sizeof(WCHAR))) - && (wchLCIDFontSig[7] & (WCHAR)0x0800)) + wchar_t LCIDFontSig[16]; + if (GetLocaleInfo(newLCID, LOCALE_FONTSIGNATURE, LCIDFontSig, sizeof(LCIDFontSig) / sizeof(wchar_t)) + && (LCIDFontSig[7] & (wchar_t)0x0800)) bidi = true; - } else -#endif //UNICODE - { - if (newLCID == 0x0859 || //Sindhi (Arabic script) - newLCID == 0x0460) //Kashmiri (Arabic script) - bidi = true;; - - switch (PRIMARYLANGID(newLCID)) - { - case LANG_ARABIC: - case LANG_HEBREW: - case LANG_URDU: - case LANG_FARSI: - case LANG_PASHTO: - //case LANG_UIGHUR: - case LANG_SYRIAC: - case LANG_DIVEHI: - bidi = true; - } - } keyboardInputDirection = bidi ? Qt::RightToLeft : Qt::LeftToRight; } @@ -751,7 +706,7 @@ void QKeyMapperPrivate::updatePossibleKeyCodes(unsigned char *kbdBuffer, quint32 keyLayout[vk_key]->qtKey[7] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey); keyLayout[vk_key]->deadkeys |= isDeadKey ? 0x80 : 0; // Add a fall back key for layouts which don't do composition and show non-latin1 characters - int fallbackKey = KeyTbl[vk_key]; + int fallbackKey = winceKeyBend(vk_key); if (!fallbackKey || fallbackKey == Qt::Key_unknown) { fallbackKey = 0; if (vk_key != keyLayout[vk_key]->qtKey[0] && vk_key < 0x5B && vk_key > 0x2F) @@ -760,7 +715,7 @@ void QKeyMapperPrivate::updatePossibleKeyCodes(unsigned char *kbdBuffer, quint32 keyLayout[vk_key]->qtKey[8] = fallbackKey; // If this vk_key a Dead Key - if (MapVirtualKey(vk_key, 2) & 0x80008000) { // (High-order dead key on Win 95 is 0x8000) + if (MapVirtualKey(vk_key, 2) & 0x80000000) { // Push a Space, then the original key through the low-level ToAscii functions. // We do this because these functions (ToAscii / ToUnicode) will alter the internal state of // the keyboard driver By doing the following, we set the keyboard driver state back to what @@ -837,13 +792,13 @@ bool QKeyMapperPrivate::translateKeyEvent(QWidget *widget, const MSG &msg, bool bool isNumpad = (msg.wParam >= VK_NUMPAD0 && msg.wParam <= VK_NUMPAD9); quint32 nModifiers = 0; - if (QSysInfo::WindowsVersion < QSysInfo::WV_NT || QSysInfo::WindowsVersion & QSysInfo::WV_CE_based) { +#if defined(Q_OS_WINCE) nModifiers |= (GetKeyState(VK_SHIFT ) < 0 ? ShiftAny : 0); nModifiers |= (GetKeyState(VK_CONTROL) < 0 ? ControlAny : 0); nModifiers |= (GetKeyState(VK_MENU ) < 0 ? AltAny : 0); nModifiers |= (GetKeyState(VK_LWIN ) < 0 ? MetaLeft : 0); nModifiers |= (GetKeyState(VK_RWIN ) < 0 ? MetaRight : 0); - } else { +#else // Map native modifiers to some bit representation nModifiers |= (GetKeyState(VK_LSHIFT ) & 0x80 ? ShiftLeft : 0); nModifiers |= (GetKeyState(VK_RSHIFT ) & 0x80 ? ShiftRight : 0); @@ -857,7 +812,8 @@ bool QKeyMapperPrivate::translateKeyEvent(QWidget *widget, const MSG &msg, bool nModifiers |= (GetKeyState(VK_CAPITAL ) & 0x01 ? CapsLock : 0); nModifiers |= (GetKeyState(VK_NUMLOCK ) & 0x01 ? NumLock : 0); nModifiers |= (GetKeyState(VK_SCROLL ) & 0x01 ? ScrollLock : 0); - } +#endif // Q_OS_WINCE + if (msg.lParam & ExtendedKey) nModifiers |= msg.lParam & ExtendedKey; @@ -870,12 +826,12 @@ bool QKeyMapperPrivate::translateKeyEvent(QWidget *widget, const MSG &msg, bool // Now we know enough to either have MapVirtualKey or our own keymap tell us if it's a deadkey bool isDeadKey = isADeadKey(msg.wParam, state) - || MapVirtualKey(msg.wParam, 2) & 0x80008000; // High-order on 95 is 0x8000 + || MapVirtualKey(msg.wParam, 2) & 0x80000000; // A multi-character key not found by our look-ahead if (msgType == WM_CHAR) { QString s; - QChar ch = wmchar_to_unicode(msg.wParam); + QChar ch = QChar((ushort)msg.wParam); if (!ch.isNull()) s += ch; @@ -886,7 +842,7 @@ bool QKeyMapperPrivate::translateKeyEvent(QWidget *widget, const MSG &msg, bool // Input method characters not found by our look-ahead else if (msgType == WM_IME_CHAR) { QString s; - QChar ch = imechar_to_unicode(msg.wParam); + QChar ch = QChar((ushort)msg.wParam); if (!ch.isNull()) s += ch; @@ -917,8 +873,8 @@ bool QKeyMapperPrivate::translateKeyEvent(QWidget *widget, const MSG &msg, bool } } else if (msgType == WM_KEYUP) { if (dirStatus == VK_LSHIFT - && (msg.wParam == VK_SHIFT && GetKeyState(VK_LCONTROL) - || msg.wParam == VK_CONTROL && GetKeyState(VK_LSHIFT))) { + && ((msg.wParam == VK_SHIFT && GetKeyState(VK_LCONTROL)) + || (msg.wParam == VK_CONTROL && GetKeyState(VK_LSHIFT)))) { k0 = q->sendKeyEvent(widget, grab, QEvent::KeyPress, Qt::Key_Direction_L, 0, QString(), false, 0, scancode, msg.wParam, nModifiers); @@ -927,8 +883,8 @@ bool QKeyMapperPrivate::translateKeyEvent(QWidget *widget, const MSG &msg, bool scancode, msg.wParam, nModifiers); dirStatus = 0; } else if (dirStatus == VK_RSHIFT - && (msg.wParam == VK_SHIFT && GetKeyState(VK_RCONTROL) - || msg.wParam == VK_CONTROL && GetKeyState(VK_RSHIFT))) { + && ( (msg.wParam == VK_SHIFT && GetKeyState(VK_RCONTROL)) + || (msg.wParam == VK_CONTROL && GetKeyState(VK_RSHIFT)))) { k0 = q->sendKeyEvent(widget, grab, QEvent::KeyPress, Qt::Key_Direction_R, 0, QString(), false, 0, scancode, msg.wParam, nModifiers); @@ -959,7 +915,7 @@ bool QKeyMapperPrivate::translateKeyEvent(QWidget *widget, const MSG &msg, bool // ..also if we're typing numbers on the keypad, while holding down the Alt modifier. int code = 0; if (isNumpad && (nModifiers & AltAny)) { - code = KeyTbl[msg.wParam]; + code = winceKeyBend(msg.wParam); } else if (!isDeadKey) { unsigned char kbdBuffer[256]; // Will hold the complete keyboard state GetKeyboardState(kbdBuffer); @@ -1050,11 +1006,9 @@ bool QKeyMapperPrivate::translateKeyEvent(QWidget *widget, const MSG &msg, bool : msgType == WM_IME_KEYDOWN ? WM_IME_CHAR : WM_SYSCHAR); QChar uch; - if (winPeekMessage(&wm_char, 0, charType, charType, PM_REMOVE)) { + if (PeekMessage(&wm_char, 0, charType, charType, PM_REMOVE)) { // Found a ?_CHAR - uch = charType == WM_IME_CHAR - ? imechar_to_unicode(wm_char.wParam) - : wmchar_to_unicode(wm_char.wParam); + uch = QChar((ushort)wm_char.wParam); if (msgType == WM_SYSKEYDOWN && uch.isLetter() && (msg.lParam & KF_ALTDOWN)) uch = uch.toLower(); // (See doc of WM_SYSCHAR) Alt-letter if (!code && !uch.row()) @@ -1067,7 +1021,7 @@ bool QKeyMapperPrivate::translateKeyEvent(QWidget *widget, const MSG &msg, bool // to find the correct key using the current message parameters & keyboard state. if (uch.isNull() && msgType == WM_IME_KEYDOWN) { BYTE keyState[256]; - WCHAR newKey[3] = {0}; + wchar_t newKey[3] = {0}; GetKeyboardState(keyState); int val = ToUnicode(vk_key, scancode, keyState, newKey, 2, 0); if (val == 1) { @@ -1085,18 +1039,10 @@ bool QKeyMapperPrivate::translateKeyEvent(QWidget *widget, const MSG &msg, bool uch = QChar(QLatin1Char(0x7f)); // Windows doesn't know this one. } else { if (msgType != WM_SYSKEYDOWN || !code) { - UINT map; - QT_WA({ - map = MapVirtualKey(msg.wParam, 2); - } , { - map = MapVirtualKeyA(msg.wParam, 2); - // High-order bit is 0x8000 on '95 - if (map & 0x8000) - map = (map^0x8000)|0x80000000; - }); + UINT map = MapVirtualKey(msg.wParam, 2); // If the high bit of the return value is set, it's a deadkey if (!(map & 0x80000000)) - uch = wmchar_to_unicode((DWORD)map); + uch = QChar((ushort)map); } } if (!code && !uch.row()) @@ -1237,6 +1183,8 @@ bool QKeyMapper::sendKeyEvent(QWidget *widget, bool grab, if (QApplicationPrivate::instance()->qt_tryAccelEvent(widget, &a)) return true; } +#else + Q_UNUSED(grab); #endif if (!widget->isEnabled()) return false; diff --git a/src/gui/kernel/qkeymapper_x11.cpp b/src/gui/kernel/qkeymapper_x11.cpp index 0ce77fe..8164589 100644 --- a/src/gui/kernel/qkeymapper_x11.cpp +++ b/src/gui/kernel/qkeymapper_x11.cpp @@ -714,47 +714,144 @@ extern bool qt_sm_blockUserInput; #define XK_KP_Delete 0xFF9F #endif -// the next lines are taken from XFree > 4.0 (X11/XF86keysyms.h), defining some special +// the next lines are taken on 10/2009 from X.org (X11/XF86keysym.h), defining some special // multimedia keys. They are included here as not every system has them. -#define XF86XK_Standby 0x1008FF10 -#define XF86XK_AudioLowerVolume 0x1008FF11 -#define XF86XK_AudioMute 0x1008FF12 -#define XF86XK_AudioRaiseVolume 0x1008FF13 -#define XF86XK_AudioPlay 0x1008FF14 -#define XF86XK_AudioStop 0x1008FF15 -#define XF86XK_AudioPrev 0x1008FF16 -#define XF86XK_AudioNext 0x1008FF17 -#define XF86XK_HomePage 0x1008FF18 -#define XF86XK_Calculator 0x1008FF1D -#define XF86XK_Mail 0x1008FF19 -#define XF86XK_Start 0x1008FF1A -#define XF86XK_Search 0x1008FF1B -#define XF86XK_AudioRecord 0x1008FF1C -#define XF86XK_Back 0x1008FF26 -#define XF86XK_Forward 0x1008FF27 -#define XF86XK_Stop 0x1008FF28 -#define XF86XK_Refresh 0x1008FF29 -#define XF86XK_Favorites 0x1008FF30 -#define XF86XK_AudioPause 0x1008FF31 -#define XF86XK_AudioMedia 0x1008FF32 -#define XF86XK_MyComputer 0x1008FF33 -#define XF86XK_OpenURL 0x1008FF38 -#define XF86XK_Launch0 0x1008FF40 -#define XF86XK_Launch1 0x1008FF41 -#define XF86XK_Launch2 0x1008FF42 -#define XF86XK_Launch3 0x1008FF43 -#define XF86XK_Launch4 0x1008FF44 -#define XF86XK_Launch5 0x1008FF45 -#define XF86XK_Launch6 0x1008FF46 -#define XF86XK_Launch7 0x1008FF47 -#define XF86XK_Launch8 0x1008FF48 -#define XF86XK_Launch9 0x1008FF49 -#define XF86XK_LaunchA 0x1008FF4A -#define XF86XK_LaunchB 0x1008FF4B -#define XF86XK_LaunchC 0x1008FF4C -#define XF86XK_LaunchD 0x1008FF4D -#define XF86XK_LaunchE 0x1008FF4E -#define XF86XK_LaunchF 0x1008FF4F +#define XF86XK_MonBrightnessUp 0x1008FF02 +#define XF86XK_MonBrightnessDown 0x1008FF03 +#define XF86XK_KbdLightOnOff 0x1008FF04 +#define XF86XK_KbdBrightnessUp 0x1008FF05 +#define XF86XK_KbdBrightnessDown 0x1008FF06 +#define XF86XK_Standby 0x1008FF10 +#define XF86XK_AudioLowerVolume 0x1008FF11 +#define XF86XK_AudioMute 0x1008FF12 +#define XF86XK_AudioRaiseVolume 0x1008FF13 +#define XF86XK_AudioPlay 0x1008FF14 +#define XF86XK_AudioStop 0x1008FF15 +#define XF86XK_AudioPrev 0x1008FF16 +#define XF86XK_AudioNext 0x1008FF17 +#define XF86XK_HomePage 0x1008FF18 +#define XF86XK_Mail 0x1008FF19 +#define XF86XK_Start 0x1008FF1A +#define XF86XK_Search 0x1008FF1B +#define XF86XK_AudioRecord 0x1008FF1C +#define XF86XK_Calculator 0x1008FF1D +#define XF86XK_Memo 0x1008FF1E +#define XF86XK_ToDoList 0x1008FF1F +#define XF86XK_Calendar 0x1008FF20 +#define XF86XK_PowerDown 0x1008FF21 +#define XF86XK_ContrastAdjust 0x1008FF22 +#define XF86XK_Back 0x1008FF26 +#define XF86XK_Forward 0x1008FF27 +#define XF86XK_Stop 0x1008FF28 +#define XF86XK_Refresh 0x1008FF29 +#define XF86XK_PowerOff 0x1008FF2A +#define XF86XK_WakeUp 0x1008FF2B +#define XF86XK_Eject 0x1008FF2C +#define XF86XK_ScreenSaver 0x1008FF2D +#define XF86XK_WWW 0x1008FF2E +#define XF86XK_Sleep 0x1008FF2F +#define XF86XK_Favorites 0x1008FF30 +#define XF86XK_AudioPause 0x1008FF31 +#define XF86XK_AudioMedia 0x1008FF32 +#define XF86XK_MyComputer 0x1008FF33 +#define XF86XK_LightBulb 0x1008FF35 +#define XF86XK_Shop 0x1008FF36 +#define XF86XK_History 0x1008FF37 +#define XF86XK_OpenURL 0x1008FF38 +#define XF86XK_AddFavorite 0x1008FF39 +#define XF86XK_HotLinks 0x1008FF3A +#define XF86XK_BrightnessAdjust 0x1008FF3B +#define XF86XK_Finance 0x1008FF3C +#define XF86XK_Community 0x1008FF3D +#define XF86XK_AudioRewind 0x1008FF3E +#define XF86XK_BackForward 0x1008FF3F +#define XF86XK_Launch0 0x1008FF40 +#define XF86XK_Launch1 0x1008FF41 +#define XF86XK_Launch2 0x1008FF42 +#define XF86XK_Launch3 0x1008FF43 +#define XF86XK_Launch4 0x1008FF44 +#define XF86XK_Launch5 0x1008FF45 +#define XF86XK_Launch6 0x1008FF46 +#define XF86XK_Launch7 0x1008FF47 +#define XF86XK_Launch8 0x1008FF48 +#define XF86XK_Launch9 0x1008FF49 +#define XF86XK_LaunchA 0x1008FF4A +#define XF86XK_LaunchB 0x1008FF4B +#define XF86XK_LaunchC 0x1008FF4C +#define XF86XK_LaunchD 0x1008FF4D +#define XF86XK_LaunchE 0x1008FF4E +#define XF86XK_LaunchF 0x1008FF4F +#define XF86XK_ApplicationLeft 0x1008FF50 +#define XF86XK_ApplicationRight 0x1008FF51 +#define XF86XK_Book 0x1008FF52 +#define XF86XK_CD 0x1008FF53 +#define XF86XK_Calculater 0x1008FF54 +#define XF86XK_Clear 0x1008FF55 +#define XF86XK_ClearGrab 0x1008FE21 +#define XF86XK_Close 0x1008FF56 +#define XF86XK_Copy 0x1008FF57 +#define XF86XK_Cut 0x1008FF58 +#define XF86XK_Display 0x1008FF59 +#define XF86XK_DOS 0x1008FF5A +#define XF86XK_Documents 0x1008FF5B +#define XF86XK_Excel 0x1008FF5C +#define XF86XK_Explorer 0x1008FF5D +#define XF86XK_Game 0x1008FF5E +#define XF86XK_Go 0x1008FF5F +#define XF86XK_iTouch 0x1008FF60 +#define XF86XK_LogOff 0x1008FF61 +#define XF86XK_Market 0x1008FF62 +#define XF86XK_Meeting 0x1008FF63 +#define XF86XK_MenuKB 0x1008FF65 +#define XF86XK_MenuPB 0x1008FF66 +#define XF86XK_MySites 0x1008FF67 +#define XF86XK_News 0x1008FF69 +#define XF86XK_OfficeHome 0x1008FF6A +#define XF86XK_Option 0x1008FF6C +#define XF86XK_Paste 0x1008FF6D +#define XF86XK_Phone 0x1008FF6E +#define XF86XK_Reply 0x1008FF72 +#define XF86XK_Reload 0x1008FF73 +#define XF86XK_RotateWindows 0x1008FF74 +#define XF86XK_RotationPB 0x1008FF75 +#define XF86XK_RotationKB 0x1008FF76 +#define XF86XK_Save 0x1008FF77 +#define XF86XK_Send 0x1008FF7B +#define XF86XK_Spell 0x1008FF7C +#define XF86XK_SplitScreen 0x1008FF7D +#define XF86XK_Support 0x1008FF7E +#define XF86XK_TaskPane 0x1008FF7F +#define XF86XK_Terminal 0x1008FF80 +#define XF86XK_Tools 0x1008FF81 +#define XF86XK_Travel 0x1008FF82 +#define XF86XK_Video 0x1008FF87 +#define XF86XK_Word 0x1008FF89 +#define XF86XK_Xfer 0x1008FF8A +#define XF86XK_ZoomIn 0x1008FF8B +#define XF86XK_ZoomOut 0x1008FF8C +#define XF86XK_Away 0x1008FF8D +#define XF86XK_Messenger 0x1008FF8E +#define XF86XK_WebCam 0x1008FF8F +#define XF86XK_MailForward 0x1008FF90 +#define XF86XK_Pictures 0x1008FF91 +#define XF86XK_Music 0x1008FF92 +#define XF86XK_Battery 0x1008FF93 +#define XF86XK_Bluetooth 0x1008FF94 +#define XF86XK_WLAN 0x1008FF95 +#define XF86XK_UWB 0x1008FF96 +#define XF86XK_AudioForward 0x1008FF97 +#define XF86XK_AudioRepeat 0x1008FF98 +#define XF86XK_AudioRandomPlay 0x1008FF99 +#define XF86XK_Subtitle 0x1008FF9A +#define XF86XK_AudioCycleTrack 0x1008FF9B +#define XF86XK_Time 0x1008FF9F +#define XF86XK_Select 0x1008FFA0 +#define XF86XK_View 0x1008FFA1 +#define XF86XK_TopMenu 0x1008FFA2 +#define XF86XK_Suspend 0x1008FFA7 +#define XF86XK_Hibernate 0x1008FFA8 + + // end of XF86keysyms.h // Special keys used by Qtopia, mapped into the X11 private keypad range. @@ -942,10 +1039,8 @@ static const unsigned int KeyTbl[] = { XK_dead_hook, Qt::Key_Dead_Hook, XK_dead_horn, Qt::Key_Dead_Horn, - // Special multimedia keys - // currently only tested with MS internet keyboard - - // browsing keys + // Special keys from X.org - This include multimedia keys, + // wireless/bluetooth/uwb keys, special launcher keys, etc. XF86XK_Back, Qt::Key_Back, XF86XK_Forward, Qt::Key_Forward, XF86XK_Stop, Qt::Key_Stop, @@ -955,8 +1050,6 @@ static const unsigned int KeyTbl[] = { XF86XK_OpenURL, Qt::Key_OpenUrl, XF86XK_HomePage, Qt::Key_HomePage, XF86XK_Search, Qt::Key_Search, - - // media keys XF86XK_AudioLowerVolume, Qt::Key_VolumeDown, XF86XK_AudioMute, Qt::Key_VolumeMute, XF86XK_AudioRaiseVolume, Qt::Key_VolumeUp, @@ -965,13 +1058,106 @@ static const unsigned int KeyTbl[] = { XF86XK_AudioPrev, Qt::Key_MediaPrevious, XF86XK_AudioNext, Qt::Key_MediaNext, XF86XK_AudioRecord, Qt::Key_MediaRecord, - - // launch keys XF86XK_Mail, Qt::Key_LaunchMail, XF86XK_MyComputer, Qt::Key_Launch0, - XF86XK_Calculator, Qt::Key_Launch1, + XF86XK_Calculator, Qt::Key_Calculator, + XF86XK_Memo, Qt::Key_Memo, + XF86XK_ToDoList, Qt::Key_ToDoList, + XF86XK_Calendar, Qt::Key_Calendar, + XF86XK_PowerDown, Qt::Key_PowerDown, + XF86XK_ContrastAdjust, Qt::Key_ContrastAdjust, XF86XK_Standby, Qt::Key_Standby, - + XF86XK_MonBrightnessUp, Qt::Key_MonBrightnessUp, + XF86XK_MonBrightnessDown, Qt::Key_MonBrightnessDown, + XF86XK_KbdLightOnOff, Qt::Key_KeyboardLightOnOff, + XF86XK_KbdBrightnessUp, Qt::Key_KeyboardBrightnessUp, + XF86XK_KbdBrightnessDown, Qt::Key_KeyboardBrightnessDown, + XF86XK_PowerOff, Qt::Key_PowerOff, + XF86XK_WakeUp, Qt::Key_WakeUp, + XF86XK_Eject, Qt::Key_Eject, + XF86XK_ScreenSaver, Qt::Key_ScreenSaver, + XF86XK_WWW, Qt::Key_WWW, + XF86XK_Sleep, Qt::Key_Sleep, + XF86XK_LightBulb, Qt::Key_LightBulb, + XF86XK_Shop, Qt::Key_Shop, + XF86XK_History, Qt::Key_History, + XF86XK_AddFavorite, Qt::Key_AddFavorite, + XF86XK_HotLinks, Qt::Key_HotLinks, + XF86XK_BrightnessAdjust, Qt::Key_BrightnessAdjust, + XF86XK_Finance, Qt::Key_Finance, + XF86XK_Community, Qt::Key_Community, + XF86XK_AudioRewind, Qt::Key_AudioRewind, + XF86XK_BackForward, Qt::Key_BackForward, + XF86XK_ApplicationLeft, Qt::Key_ApplicationLeft, + XF86XK_ApplicationRight, Qt::Key_ApplicationRight, + XF86XK_Book, Qt::Key_Book, + XF86XK_CD, Qt::Key_CD, + XF86XK_Calculater, Qt::Key_Calculator, + XF86XK_Clear, Qt::Key_Clear, + XF86XK_ClearGrab, Qt::Key_ClearGrab, + XF86XK_Close, Qt::Key_Close, + XF86XK_Copy, Qt::Key_Copy, + XF86XK_Cut, Qt::Key_Cut, + XF86XK_Display, Qt::Key_Display, + XF86XK_DOS, Qt::Key_DOS, + XF86XK_Documents, Qt::Key_Documents, + XF86XK_Excel, Qt::Key_Excel, + XF86XK_Explorer, Qt::Key_Explorer, + XF86XK_Game, Qt::Key_Game, + XF86XK_Go, Qt::Key_Go, + XF86XK_iTouch, Qt::Key_iTouch, + XF86XK_LogOff, Qt::Key_LogOff, + XF86XK_Market, Qt::Key_Market, + XF86XK_Meeting, Qt::Key_Meeting, + XF86XK_MenuKB, Qt::Key_MenuKB, + XF86XK_MenuPB, Qt::Key_MenuPB, + XF86XK_MySites, Qt::Key_MySites, + XF86XK_News, Qt::Key_News, + XF86XK_OfficeHome, Qt::Key_OfficeHome, + XF86XK_Option, Qt::Key_Option, + XF86XK_Paste, Qt::Key_Paste, + XF86XK_Phone, Qt::Key_Phone, + XF86XK_Reply, Qt::Key_Reply, + XF86XK_Reload, Qt::Key_Reload, + XF86XK_RotateWindows, Qt::Key_RotateWindows, + XF86XK_RotationPB, Qt::Key_RotationPB, + XF86XK_RotationKB, Qt::Key_RotationKB, + XF86XK_Save, Qt::Key_Save, + XF86XK_Send, Qt::Key_Send, + XF86XK_Spell, Qt::Key_Spell, + XF86XK_SplitScreen, Qt::Key_SplitScreen, + XF86XK_Support, Qt::Key_Support, + XF86XK_TaskPane, Qt::Key_TaskPane, + XF86XK_Terminal, Qt::Key_Terminal, + XF86XK_Tools, Qt::Key_Tools, + XF86XK_Travel, Qt::Key_Travel, + XF86XK_Video, Qt::Key_Video, + XF86XK_Word, Qt::Key_Word, + XF86XK_Xfer, Qt::Key_Xfer, + XF86XK_ZoomIn, Qt::Key_ZoomIn, + XF86XK_ZoomOut, Qt::Key_ZoomOut, + XF86XK_Away, Qt::Key_Away, + XF86XK_Messenger, Qt::Key_Messenger, + XF86XK_WebCam, Qt::Key_WebCam, + XF86XK_MailForward, Qt::Key_MailForward, + XF86XK_Pictures, Qt::Key_Pictures, + XF86XK_Music, Qt::Key_Music, + XF86XK_Battery, Qt::Key_Battery, + XF86XK_Bluetooth, Qt::Key_Bluetooth, + XF86XK_WLAN, Qt::Key_WLAN, + XF86XK_UWB, Qt::Key_UWB, + XF86XK_AudioForward, Qt::Key_AudioForward, + XF86XK_AudioRepeat, Qt::Key_AudioRepeat, + XF86XK_AudioRandomPlay, Qt::Key_AudioRandomPlay, + XF86XK_Subtitle, Qt::Key_Subtitle, + XF86XK_AudioCycleTrack, Qt::Key_AudioCycleTrack, + XF86XK_Time, Qt::Key_Time, + XF86XK_Select, Qt::Key_Select, + XF86XK_View, Qt::Key_View, + XF86XK_TopMenu, Qt::Key_TopMenu, + XF86XK_Bluetooth, Qt::Key_Bluetooth, + XF86XK_Suspend, Qt::Key_Suspend, + XF86XK_Hibernate, Qt::Key_Hibernate, XF86XK_Launch0, Qt::Key_Launch2, XF86XK_Launch1, Qt::Key_Launch3, XF86XK_Launch2, Qt::Key_Launch4, diff --git a/src/gui/kernel/qkeysequence.cpp b/src/gui/kernel/qkeysequence.cpp index 870ffee..1a76083 100644 --- a/src/gui/kernel/qkeysequence.cpp +++ b/src/gui/kernel/qkeysequence.cpp @@ -105,20 +105,39 @@ static bool operator<(int key, const MacSpecialKey &entry) static const MacSpecialKey * const MacSpecialKeyEntriesEnd = entries + NumEntries; -static QChar macSymbolForQtKey(int key) +QChar qt_macSymbolForQtKey(int key) { const MacSpecialKey *i = qBinaryFind(entries, MacSpecialKeyEntriesEnd, key); if (i == MacSpecialKeyEntriesEnd) return QChar(); - return QChar(i->macSymbol); + ushort macSymbol = i->macSymbol; + if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta) + && (macSymbol == kControlUnicode || macSymbol == kCommandUnicode)) { + if (macSymbol == kControlUnicode) + macSymbol = kCommandUnicode; + else + macSymbol = kControlUnicode; + } + + return QChar(macSymbol); } static int qtkeyForMacSymbol(const QChar ch) { + const ushort unicode = ch.unicode(); for (int i = 0; i < NumEntries; ++i) { const MacSpecialKey &entry = entries[i]; - if (entry.macSymbol == ch.unicode()) - return entry.key; + if (entry.macSymbol == unicode) { + int key = entry.key; + if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta) + && (unicode == kControlUnicode || unicode == kCommandUnicode)) { + if (unicode == kControlUnicode) + key = Qt::Key_Control; + else + key = Qt::Key_Meta; + } + return key; + } } return -1; } @@ -133,9 +152,8 @@ void Q_GUI_EXPORT qt_set_sequence_auto_mnemonic(bool b) { qt_sequence_no_mnemoni \brief The QKeySequence class encapsulates a key sequence as used by shortcuts. - \ingroup misc \ingroup shared - \mainclass + In its most common form, a key sequence describes a combination of keys that must be used together to perform some action. Key sequences @@ -207,70 +225,72 @@ void Q_GUI_EXPORT qt_set_sequence_auto_mnemonic(bool b) { qt_sequence_no_mnemoni 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 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 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 @@ -396,47 +416,139 @@ static const struct { { Qt::Key_Menu, QT_TRANSLATE_NOOP("QShortcut", "Menu") }, { Qt::Key_Help, QT_TRANSLATE_NOOP("QShortcut", "Help") }, - // Multimedia keys - { Qt::Key_Back, QT_TRANSLATE_NOOP("QShortcut", "Back") }, - { Qt::Key_Forward, QT_TRANSLATE_NOOP("QShortcut", "Forward") }, - { Qt::Key_Stop, QT_TRANSLATE_NOOP("QShortcut", "Stop") }, - { Qt::Key_Refresh, QT_TRANSLATE_NOOP("QShortcut", "Refresh") }, - { Qt::Key_VolumeDown, QT_TRANSLATE_NOOP("QShortcut", "Volume Down") }, - { Qt::Key_VolumeMute, QT_TRANSLATE_NOOP("QShortcut", "Volume Mute") }, - { Qt::Key_VolumeUp, QT_TRANSLATE_NOOP("QShortcut", "Volume Up") }, - { Qt::Key_BassBoost, QT_TRANSLATE_NOOP("QShortcut", "Bass Boost") }, - { Qt::Key_BassUp, QT_TRANSLATE_NOOP("QShortcut", "Bass Up") }, - { Qt::Key_BassDown, QT_TRANSLATE_NOOP("QShortcut", "Bass Down") }, - { Qt::Key_TrebleUp, QT_TRANSLATE_NOOP("QShortcut", "Treble Up") }, - { Qt::Key_TrebleDown, QT_TRANSLATE_NOOP("QShortcut", "Treble Down") }, - { Qt::Key_MediaPlay, QT_TRANSLATE_NOOP("QShortcut", "Media Play") }, - { Qt::Key_MediaStop, QT_TRANSLATE_NOOP("QShortcut", "Media Stop") }, - { Qt::Key_MediaPrevious,QT_TRANSLATE_NOOP("QShortcut", "Media Previous") }, - { Qt::Key_MediaNext, QT_TRANSLATE_NOOP("QShortcut", "Media Next") }, - { Qt::Key_MediaRecord, QT_TRANSLATE_NOOP("QShortcut", "Media Record") }, - { Qt::Key_HomePage, QT_TRANSLATE_NOOP("QShortcut", "Home Page") }, - { Qt::Key_Favorites, QT_TRANSLATE_NOOP("QShortcut", "Favorites") }, - { Qt::Key_Search, QT_TRANSLATE_NOOP("QShortcut", "Search") }, - { Qt::Key_Standby, QT_TRANSLATE_NOOP("QShortcut", "Standby") }, - { Qt::Key_OpenUrl, QT_TRANSLATE_NOOP("QShortcut", "Open URL") }, - { Qt::Key_LaunchMail, QT_TRANSLATE_NOOP("QShortcut", "Launch Mail") }, - { Qt::Key_LaunchMedia, QT_TRANSLATE_NOOP("QShortcut", "Launch Media") }, - { Qt::Key_Launch0, QT_TRANSLATE_NOOP("QShortcut", "Launch (0)") }, - { Qt::Key_Launch1, QT_TRANSLATE_NOOP("QShortcut", "Launch (1)") }, - { Qt::Key_Launch2, QT_TRANSLATE_NOOP("QShortcut", "Launch (2)") }, - { Qt::Key_Launch3, QT_TRANSLATE_NOOP("QShortcut", "Launch (3)") }, - { Qt::Key_Launch4, QT_TRANSLATE_NOOP("QShortcut", "Launch (4)") }, - { Qt::Key_Launch5, QT_TRANSLATE_NOOP("QShortcut", "Launch (5)") }, - { Qt::Key_Launch6, QT_TRANSLATE_NOOP("QShortcut", "Launch (6)") }, - { Qt::Key_Launch7, QT_TRANSLATE_NOOP("QShortcut", "Launch (7)") }, - { Qt::Key_Launch8, QT_TRANSLATE_NOOP("QShortcut", "Launch (8)") }, - { Qt::Key_Launch9, QT_TRANSLATE_NOOP("QShortcut", "Launch (9)") }, - { Qt::Key_LaunchA, QT_TRANSLATE_NOOP("QShortcut", "Launch (A)") }, - { Qt::Key_LaunchB, QT_TRANSLATE_NOOP("QShortcut", "Launch (B)") }, - { Qt::Key_LaunchC, QT_TRANSLATE_NOOP("QShortcut", "Launch (C)") }, - { Qt::Key_LaunchD, QT_TRANSLATE_NOOP("QShortcut", "Launch (D)") }, - { Qt::Key_LaunchE, QT_TRANSLATE_NOOP("QShortcut", "Launch (E)") }, - { Qt::Key_LaunchF, QT_TRANSLATE_NOOP("QShortcut", "Launch (F)") }, + // Special keys + // Includes multimedia, launcher, lan keys ( bluetooth, wireless ) + // window navigation + { Qt::Key_Back, QT_TRANSLATE_NOOP("QShortcut", "Back") }, + { Qt::Key_Forward, QT_TRANSLATE_NOOP("QShortcut", "Forward") }, + { Qt::Key_Stop, QT_TRANSLATE_NOOP("QShortcut", "Stop") }, + { Qt::Key_Refresh, QT_TRANSLATE_NOOP("QShortcut", "Refresh") }, + { Qt::Key_VolumeDown, QT_TRANSLATE_NOOP("QShortcut", "Volume Down") }, + { Qt::Key_VolumeMute, QT_TRANSLATE_NOOP("QShortcut", "Volume Mute") }, + { Qt::Key_VolumeUp, QT_TRANSLATE_NOOP("QShortcut", "Volume Up") }, + { Qt::Key_BassBoost, QT_TRANSLATE_NOOP("QShortcut", "Bass Boost") }, + { Qt::Key_BassUp, QT_TRANSLATE_NOOP("QShortcut", "Bass Up") }, + { Qt::Key_BassDown, QT_TRANSLATE_NOOP("QShortcut", "Bass Down") }, + { Qt::Key_TrebleUp, QT_TRANSLATE_NOOP("QShortcut", "Treble Up") }, + { Qt::Key_TrebleDown, QT_TRANSLATE_NOOP("QShortcut", "Treble Down") }, + { Qt::Key_MediaPlay, QT_TRANSLATE_NOOP("QShortcut", "Media Play") }, + { Qt::Key_MediaStop, QT_TRANSLATE_NOOP("QShortcut", "Media Stop") }, + { Qt::Key_MediaPrevious, QT_TRANSLATE_NOOP("QShortcut", "Media Previous") }, + { Qt::Key_MediaNext, QT_TRANSLATE_NOOP("QShortcut", "Media Next") }, + { Qt::Key_MediaRecord, QT_TRANSLATE_NOOP("QShortcut", "Media Record") }, + { Qt::Key_HomePage, QT_TRANSLATE_NOOP("QShortcut", "Home Page") }, + { Qt::Key_Favorites, QT_TRANSLATE_NOOP("QShortcut", "Favorites") }, + { Qt::Key_Search, QT_TRANSLATE_NOOP("QShortcut", "Search") }, + { Qt::Key_Standby, QT_TRANSLATE_NOOP("QShortcut", "Standby") }, + { Qt::Key_OpenUrl, QT_TRANSLATE_NOOP("QShortcut", "Open URL") }, + { Qt::Key_LaunchMail, QT_TRANSLATE_NOOP("QShortcut", "Launch Mail") }, + { Qt::Key_LaunchMedia, QT_TRANSLATE_NOOP("QShortcut", "Launch Media") }, + { Qt::Key_Launch0, QT_TRANSLATE_NOOP("QShortcut", "Launch (0)") }, + { Qt::Key_Launch1, QT_TRANSLATE_NOOP("QShortcut", "Launch (1)") }, + { Qt::Key_Launch2, QT_TRANSLATE_NOOP("QShortcut", "Launch (2)") }, + { Qt::Key_Launch3, QT_TRANSLATE_NOOP("QShortcut", "Launch (3)") }, + { Qt::Key_Launch4, QT_TRANSLATE_NOOP("QShortcut", "Launch (4)") }, + { Qt::Key_Launch5, QT_TRANSLATE_NOOP("QShortcut", "Launch (5)") }, + { Qt::Key_Launch6, QT_TRANSLATE_NOOP("QShortcut", "Launch (6)") }, + { Qt::Key_Launch7, QT_TRANSLATE_NOOP("QShortcut", "Launch (7)") }, + { Qt::Key_Launch8, QT_TRANSLATE_NOOP("QShortcut", "Launch (8)") }, + { Qt::Key_Launch9, QT_TRANSLATE_NOOP("QShortcut", "Launch (9)") }, + { Qt::Key_LaunchA, QT_TRANSLATE_NOOP("QShortcut", "Launch (A)") }, + { Qt::Key_LaunchB, QT_TRANSLATE_NOOP("QShortcut", "Launch (B)") }, + { Qt::Key_LaunchC, QT_TRANSLATE_NOOP("QShortcut", "Launch (C)") }, + { Qt::Key_LaunchD, QT_TRANSLATE_NOOP("QShortcut", "Launch (D)") }, + { Qt::Key_LaunchE, QT_TRANSLATE_NOOP("QShortcut", "Launch (E)") }, + { Qt::Key_LaunchF, QT_TRANSLATE_NOOP("QShortcut", "Launch (F)") }, + { Qt::Key_MonBrightnessUp, QT_TRANSLATE_NOOP("QShortcut", "Monitor Brightness Up") }, + { Qt::Key_MonBrightnessDown, QT_TRANSLATE_NOOP("QShortcut", "Monitor Brightness Down") }, + { Qt::Key_KeyboardLightOnOff, QT_TRANSLATE_NOOP("QShortcut", "Keyboard Light On/Off") }, + { Qt::Key_KeyboardBrightnessUp, QT_TRANSLATE_NOOP("QShortcut", "Keyboard Brightness Up") }, + { Qt::Key_KeyboardBrightnessDown, QT_TRANSLATE_NOOP("QShortcut", "Keyboard Brightness Down") }, + { Qt::Key_PowerOff, QT_TRANSLATE_NOOP("QShortcut", "Power Off") }, + { Qt::Key_WakeUp, QT_TRANSLATE_NOOP("QShortcut", "Wake Up") }, + { Qt::Key_Eject, QT_TRANSLATE_NOOP("QShortcut", "Eject") }, + { Qt::Key_ScreenSaver, QT_TRANSLATE_NOOP("QShortcut", "Screensaver") }, + { Qt::Key_WWW, QT_TRANSLATE_NOOP("QShortcut", "WWW") }, + { Qt::Key_Sleep, QT_TRANSLATE_NOOP("QShortcut", "Sleep") }, + { Qt::Key_LightBulb, QT_TRANSLATE_NOOP("QShortcut", "LightBulb") }, + { Qt::Key_Shop, QT_TRANSLATE_NOOP("QShortcut", "Shop") }, + { Qt::Key_History, QT_TRANSLATE_NOOP("QShortcut", "History") }, + { Qt::Key_AddFavorite, QT_TRANSLATE_NOOP("QShortcut", "Add Favorite") }, + { Qt::Key_HotLinks, QT_TRANSLATE_NOOP("QShortcut", "Hot Links") }, + { Qt::Key_BrightnessAdjust, QT_TRANSLATE_NOOP("QShortcut", "Adjust Brightness") }, + { Qt::Key_Finance, QT_TRANSLATE_NOOP("QShortcut", "Finance") }, + { Qt::Key_Community, QT_TRANSLATE_NOOP("QShortcut", "Community") }, + { Qt::Key_AudioRewind, QT_TRANSLATE_NOOP("QShortcut", "Audio Rewind") }, + { Qt::Key_BackForward, QT_TRANSLATE_NOOP("QShortcut", "Back Forward") }, + { Qt::Key_ApplicationLeft, QT_TRANSLATE_NOOP("QShortcut", "Application Left") }, + { Qt::Key_ApplicationRight, QT_TRANSLATE_NOOP("QShortcut", "Application Right") }, + { Qt::Key_Book, QT_TRANSLATE_NOOP("QShortcut", "Book") }, + { Qt::Key_CD, QT_TRANSLATE_NOOP("QShortcut", "CD") }, + { Qt::Key_Calculator, QT_TRANSLATE_NOOP("QShortcut", "Calculator") }, + { Qt::Key_Clear, QT_TRANSLATE_NOOP("QShortcut", "Clear") }, + { Qt::Key_ClearGrab, QT_TRANSLATE_NOOP("QShortcut", "Clear Grab") }, + { Qt::Key_Close, QT_TRANSLATE_NOOP("QShortcut", "Close") }, + { Qt::Key_Copy, QT_TRANSLATE_NOOP("QShortcut", "Copy") }, + { Qt::Key_Cut, QT_TRANSLATE_NOOP("QShortcut", "Cut") }, + { Qt::Key_Display, QT_TRANSLATE_NOOP("QShortcut", "Display") }, + { Qt::Key_DOS, QT_TRANSLATE_NOOP("QShortcut", "DOS") }, + { Qt::Key_Documents, QT_TRANSLATE_NOOP("QShortcut", "Documents") }, + { Qt::Key_Excel, QT_TRANSLATE_NOOP("QShortcut", "Spreadsheet") }, + { Qt::Key_Explorer, QT_TRANSLATE_NOOP("QShortcut", "Browser") }, + { Qt::Key_Game, QT_TRANSLATE_NOOP("QShortcut", "Game") }, + { Qt::Key_Go, QT_TRANSLATE_NOOP("QShortcut", "Go") }, + { Qt::Key_iTouch, QT_TRANSLATE_NOOP("QShortcut", "iTouch") }, + { Qt::Key_LogOff, QT_TRANSLATE_NOOP("QShortcut", "Logoff") }, + { Qt::Key_Market, QT_TRANSLATE_NOOP("QShortcut", "Market") }, + { Qt::Key_Meeting, QT_TRANSLATE_NOOP("QShortcut", "Meeting") }, + { Qt::Key_MenuKB, QT_TRANSLATE_NOOP("QShortcut", "Keyboard Menu") }, + { Qt::Key_MenuPB, QT_TRANSLATE_NOOP("QShortcut", "Menu PB") }, + { Qt::Key_MySites, QT_TRANSLATE_NOOP("QShortcut", "My Sites") }, + { Qt::Key_News, QT_TRANSLATE_NOOP("QShortcut", "News") }, + { Qt::Key_OfficeHome, QT_TRANSLATE_NOOP("QShortcut", "Home Office") }, + { Qt::Key_Option, QT_TRANSLATE_NOOP("QShortcut", "Option") }, + { Qt::Key_Paste, QT_TRANSLATE_NOOP("QShortcut", "Paste") }, + { Qt::Key_Phone, QT_TRANSLATE_NOOP("QShortcut", "Phone") }, + { Qt::Key_Reply, QT_TRANSLATE_NOOP("QShortcut", "Reply") }, + { Qt::Key_Reload, QT_TRANSLATE_NOOP("QShortcut", "Reload") }, + { Qt::Key_RotateWindows, QT_TRANSLATE_NOOP("QShortcut", "Rotate Windows") }, + { Qt::Key_RotationPB, QT_TRANSLATE_NOOP("QShortcut", "Rotation PB") }, + { Qt::Key_RotationKB, QT_TRANSLATE_NOOP("QShortcut", "Rotation KB") }, + { Qt::Key_Save, QT_TRANSLATE_NOOP("QShortcut", "Save") }, + { Qt::Key_Send, QT_TRANSLATE_NOOP("QShortcut", "Send") }, + { Qt::Key_Spell, QT_TRANSLATE_NOOP("QShortcut", "Spellchecker") }, + { Qt::Key_SplitScreen, QT_TRANSLATE_NOOP("QShortcut", "Split Screen") }, + { Qt::Key_Support, QT_TRANSLATE_NOOP("QShortcut", "Support") }, + { Qt::Key_TaskPane, QT_TRANSLATE_NOOP("QShortcut", "Task Panel") }, + { Qt::Key_Terminal, QT_TRANSLATE_NOOP("QShortcut", "Terminal") }, + { Qt::Key_Tools, QT_TRANSLATE_NOOP("QShortcut", "Tools") }, + { Qt::Key_Travel, QT_TRANSLATE_NOOP("QShortcut", "Travel") }, + { Qt::Key_Video, QT_TRANSLATE_NOOP("QShortcut", "Video") }, + { Qt::Key_Word, QT_TRANSLATE_NOOP("QShortcut", "Word Processor") }, + { Qt::Key_Xfer, QT_TRANSLATE_NOOP("QShortcut", "XFer") }, + { Qt::Key_ZoomIn, QT_TRANSLATE_NOOP("QShortcut", "Zoom In") }, + { Qt::Key_ZoomOut, QT_TRANSLATE_NOOP("QShortcut", "Zoom Out") }, + { Qt::Key_Away, QT_TRANSLATE_NOOP("QShortcut", "Away") }, + { Qt::Key_Messenger, QT_TRANSLATE_NOOP("QShortcut", "Messenger") }, + { Qt::Key_WebCam, QT_TRANSLATE_NOOP("QShortcut", "WebCam") }, + { Qt::Key_MailForward, QT_TRANSLATE_NOOP("QShortcut", "Mail Forward") }, + { Qt::Key_Pictures, QT_TRANSLATE_NOOP("QShortcut", "Pictures") }, + { Qt::Key_Music, QT_TRANSLATE_NOOP("QShortcut", "Music") }, + { Qt::Key_Battery, QT_TRANSLATE_NOOP("QShortcut", "Battery") }, + { Qt::Key_Bluetooth, QT_TRANSLATE_NOOP("QShortcut", "Bluetooth") }, + { Qt::Key_WLAN, QT_TRANSLATE_NOOP("QShortcut", "Wireless") }, + { Qt::Key_UWB, QT_TRANSLATE_NOOP("QShortcut", "Ultra Wide Band") }, + { Qt::Key_AudioForward, QT_TRANSLATE_NOOP("QShortcut", "Audio Forward") }, + { Qt::Key_AudioRepeat, QT_TRANSLATE_NOOP("QShortcut", "Audio Repeat") }, + { Qt::Key_AudioRandomPlay, QT_TRANSLATE_NOOP("QShortcut", "Audio Random Play") }, + { Qt::Key_Subtitle, QT_TRANSLATE_NOOP("QShortcut", "Subtitle") }, + { Qt::Key_AudioCycleTrack, QT_TRANSLATE_NOOP("QShortcut", "Audio Cycle Track") }, + { Qt::Key_Time, QT_TRANSLATE_NOOP("QShortcut", "Time") }, + { Qt::Key_Select, QT_TRANSLATE_NOOP("QShortcut", "Select") }, + { Qt::Key_View, QT_TRANSLATE_NOOP("QShortcut", "View") }, + { Qt::Key_TopMenu, QT_TRANSLATE_NOOP("QShortcut", "Top Menu") }, + { Qt::Key_Suspend, QT_TRANSLATE_NOOP("QShortcut", "Suspend") }, + { Qt::Key_Hibernate, QT_TRANSLATE_NOOP("QShortcut", "Hibernate") }, // -------------------------------------------------------------- // More consistent namings @@ -481,9 +593,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}, @@ -492,6 +604,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}, @@ -502,13 +615,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}, @@ -521,6 +635,7 @@ const QKeyBinding QKeySequencePrivate::keyBindings[] = { {QKeySequence::FindPrevious, 1, Qt::SHIFT | Qt::Key_F3, QApplicationPrivate::KB_Win}, {QKeySequence::ZoomIn, 1, Qt::CTRL | Qt::Key_Plus, QApplicationPrivate::KB_All}, {QKeySequence::NextChild, 0, Qt::CTRL | Qt::Key_Comma, QApplicationPrivate::KB_KDE}, + {QKeySequence::Preferences, 0, Qt::CTRL | Qt::Key_Comma, QApplicationPrivate::KB_Mac}, {QKeySequence::ZoomOut, 1, Qt::CTRL | Qt::Key_Minus, QApplicationPrivate::KB_All}, {QKeySequence::PreviousChild, 0, Qt::CTRL | Qt::Key_Period, QApplicationPrivate::KB_KDE}, {QKeySequence::HelpContents, 1, Qt::CTRL | Qt::Key_Question, QApplicationPrivate::KB_Mac}, @@ -538,6 +653,7 @@ const QKeyBinding QKeySequencePrivate::keyBindings[] = { {QKeySequence::New, 1, Qt::CTRL | Qt::Key_N, QApplicationPrivate::KB_All}, {QKeySequence::Open, 1, Qt::CTRL | Qt::Key_O, QApplicationPrivate::KB_All}, {QKeySequence::Print, 1, Qt::CTRL | Qt::Key_P, QApplicationPrivate::KB_All}, + {QKeySequence::Quit, 0, Qt::CTRL | Qt::Key_Q, QApplicationPrivate::KB_Gnome | QApplicationPrivate::KB_KDE | QApplicationPrivate::KB_Mac}, {QKeySequence::Refresh, 1, Qt::CTRL | Qt::Key_R, QApplicationPrivate::KB_Gnome | QApplicationPrivate::KB_Mac}, {QKeySequence::Replace, 0, Qt::CTRL | Qt::Key_R, QApplicationPrivate::KB_KDE}, {QKeySequence::Save, 1, Qt::CTRL | Qt::Key_S, QApplicationPrivate::KB_All}, @@ -547,7 +663,7 @@ const QKeyBinding QKeySequencePrivate::keyBindings[] = { {QKeySequence::Close, 0, Qt::CTRL | Qt::Key_W, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11}, {QKeySequence::Close, 1, Qt::CTRL | Qt::Key_W, QApplicationPrivate::KB_Mac}, {QKeySequence::Cut, 1, Qt::CTRL | Qt::Key_X, QApplicationPrivate::KB_All}, - {QKeySequence::Redo, 1, Qt::CTRL | Qt::Key_Y, QApplicationPrivate::KB_Win}, + {QKeySequence::Redo, 1, Qt::CTRL | Qt::Key_Y, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_S60}, {QKeySequence::Redo, 0, Qt::CTRL | Qt::Key_Y, QApplicationPrivate::KB_Mac},//different priority from above {QKeySequence::Undo, 1, Qt::CTRL | Qt::Key_Z, QApplicationPrivate::KB_All}, {QKeySequence::Back, 1, Qt::CTRL | Qt::Key_BracketLeft, QApplicationPrivate::KB_Mac}, @@ -559,15 +675,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}, @@ -576,16 +692,16 @@ const QKeyBinding QKeySequencePrivate::keyBindings[] = { {QKeySequence::FindPrevious, 0, Qt::CTRL | Qt::SHIFT | Qt::Key_G, QApplicationPrivate::KB_Win}, {QKeySequence::AddTab, 1, Qt::CTRL | Qt::SHIFT | Qt::Key_N, QApplicationPrivate::KB_KDE}, {QKeySequence::SaveAs, 0, Qt::CTRL | Qt::SHIFT | Qt::Key_S, QApplicationPrivate::KB_Gnome | QApplicationPrivate::KB_Mac}, - {QKeySequence::Redo, 0, Qt::CTRL | Qt::SHIFT | Qt::Key_Z, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11}, + {QKeySequence::Redo, 0, Qt::CTRL | Qt::SHIFT | Qt::Key_Z, QApplicationPrivate::KB_Win | QApplicationPrivate::KB_X11 | QApplicationPrivate::KB_S60}, {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}, @@ -669,12 +785,14 @@ const uint QKeySequencePrivate::numberOfKeyBindings = sizeof(QKeySequencePrivate \value NextChild Navigate to next tab or child window. \value Open Open document. \value Paste Paste. + \value Preferences Open the preferences dialog. \value PreviousChild Navigate to previous tab or child window. \value Print Print document. + \value Quit Quit the application. \value Redo Redo. \value Refresh Refresh or reload current document. \value Replace Find and replace. - \value SaveAs Save document after prompting the user for a file name. + \value SaveAs Save document after prompting the user for a file name. \value Save Save document. \value SelectAll Select all text. \value SelectEndOfBlock Extend selection to the end of a text block. This shortcut is only used on OS X. @@ -726,7 +844,9 @@ QKeySequence::QKeySequence(StandardKey key) */ QKeySequence::QKeySequence() { - d = new QKeySequencePrivate(); + static QKeySequencePrivate shared_empty; + d = &shared_empty; + d->ref.ref(); } /*! @@ -780,6 +900,21 @@ QKeySequence::QKeySequence(const QKeySequence& keysequence) d->ref.ref(); } +#ifdef Q_WS_MAC +static inline int maybeSwapShortcut(int shortcut) +{ + if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) { + uint oldshortcut = shortcut; + shortcut &= ~(Qt::CTRL | Qt::META); + if (oldshortcut & Qt::CTRL) + shortcut |= Qt::META; + if (oldshortcut & Qt::META) + shortcut |= Qt::CTRL; + } + return shortcut; +} +#endif + /*! \since 4.2 @@ -796,10 +931,16 @@ QList<QKeySequence> QKeySequence::keyBindings(StandardKey key) for (uint i = 0; i < QKeySequencePrivate::numberOfKeyBindings ; ++i) { QKeyBinding keyBinding = QKeySequencePrivate::keyBindings[i]; if (keyBinding.standardKey == key && (keyBinding.platform & platform)) { - if (keyBinding.priority > 0) - list.prepend(QKeySequence(QKeySequencePrivate::keyBindings[i].shortcut)); - else - list.append(QKeySequence(QKeySequencePrivate::keyBindings[i].shortcut)); + uint shortcut = +#ifdef Q_WS_MAC + maybeSwapShortcut(QKeySequencePrivate::keyBindings[i].shortcut); +#else + QKeySequencePrivate::keyBindings[i].shortcut; +#endif + if (keyBinding.priority > 0) + list.prepend(QKeySequence(shortcut)); + else + list.append(QKeySequence(shortcut)); } } return list; @@ -967,9 +1108,16 @@ int QKeySequencePrivate::decodeString(const QString &str, QKeySequence::Sequence gmodifs = globalModifs(); if (gmodifs->isEmpty()) { #ifdef Q_WS_MAC - *gmodifs << QModifKeyName(Qt::CTRL, QChar(kCommandUnicode)); + const bool dontSwap = qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta); + if (dontSwap) + *gmodifs << QModifKeyName(Qt::META, QChar(kCommandUnicode)); + else + *gmodifs << QModifKeyName(Qt::CTRL, QChar(kCommandUnicode)); *gmodifs << QModifKeyName(Qt::ALT, QChar(kOptionUnicode)); - *gmodifs << QModifKeyName(Qt::META, QChar(kControlUnicode)); + if (dontSwap) + *gmodifs << QModifKeyName(Qt::CTRL, QChar(kControlUnicode)); + else + *gmodifs << QModifKeyName(Qt::META, QChar(kControlUnicode)); *gmodifs << QModifKeyName(Qt::SHIFT, QChar(kShiftUnicode)); #endif *gmodifs << QModifKeyName(Qt::CTRL, QLatin1String("ctrl+")) @@ -1067,8 +1215,6 @@ int QKeySequencePrivate::decodeString(const QString &str, QKeySequence::Sequence if (found) break; } -#ifdef Q_WS_MAC -#endif } return ret; } @@ -1097,15 +1243,30 @@ QString QKeySequencePrivate::encodeString(int key, QKeySequence::SequenceFormat QString s; #if defined(Q_WS_MAC) if (nativeText) { - // On MAC the order is Meta, Alt, Shift, Control. - if ((key & Qt::META) == Qt::META) - s += macSymbolForQtKey(Qt::Key_Meta); - if ((key & Qt::ALT) == Qt::ALT) - s += macSymbolForQtKey(Qt::Key_Alt); - if ((key & Qt::SHIFT) == Qt::SHIFT) - s += macSymbolForQtKey(Qt::Key_Shift); - if ((key & Qt::CTRL) == Qt::CTRL) - s += macSymbolForQtKey(Qt::Key_Control); + // On Mac OS X the order (by default) is Meta, Alt, Shift, Control. + // If the AA_MacDontSwapCtrlAndMeta is enabled, then the order + // is Ctrl, Alt, Shift, Meta. The macSymbolForQtKey does this swap + // for us, which means that we have to adjust our order here. + // The upshot is a lot more infrastructure to keep the number of + // if tests down and the code relatively clean. + static const int ModifierOrder[] = { Qt::META, Qt::ALT, Qt::SHIFT, Qt::CTRL, 0 }; + static const int QtKeyOrder[] = { Qt::Key_Meta, Qt::Key_Alt, Qt::Key_Shift, Qt::Key_Control, 0 }; + static const int DontSwapModifierOrder[] = { Qt::CTRL, Qt::ALT, Qt::SHIFT, Qt::META, 0 }; + static const int DontSwapQtKeyOrder[] = { Qt::Key_Control, Qt::Key_Alt, Qt::Key_Shift, Qt::Key_Meta, 0 }; + const int *modifierOrder; + const int *qtkeyOrder; + if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) { + modifierOrder = DontSwapModifierOrder; + qtkeyOrder = DontSwapQtKeyOrder; + } else { + modifierOrder = ModifierOrder; + qtkeyOrder = QtKeyOrder; + } + + for (int i = 0; modifierOrder[i] != 0; ++i) { + if (key & modifierOrder[i]) + s += qt_macSymbolForQtKey(qtkeyOrder[i]); + } } else #endif { @@ -1138,7 +1299,7 @@ QString QKeySequencePrivate::encodeString(int key, QKeySequence::SequenceFormat int i=0; #if defined(Q_WS_MAC) if (nativeText) { - QChar ch = macSymbolForQtKey(key); + QChar ch = qt_macSymbolForQtKey(key); if (!ch.isNull()) p = ch; else diff --git a/src/gui/kernel/qkeysequence.h b/src/gui/kernel/qkeysequence.h index b6d8a70..d41902b 100644 --- a/src/gui/kernel/qkeysequence.h +++ b/src/gui/kernel/qkeysequence.h @@ -136,7 +136,9 @@ public: DeleteEndOfLine, InsertParagraphSeparator, InsertLineSeparator, - SaveAs + SaveAs, + Preferences, + Quit }; QKeySequence(); diff --git a/src/gui/kernel/qlayout.cpp b/src/gui/kernel/qlayout.cpp index 56a1218..70cd5a5 100644 --- a/src/gui/kernel/qlayout.cpp +++ b/src/gui/kernel/qlayout.cpp @@ -61,7 +61,10 @@ static int menuBarHeightForWidth(QWidget *menubar, int w) int result = menubar->heightForWidth(qMax(w, menubar->minimumWidth())); if (result != -1) return result; - result = menubar->sizeHint().height(); + result = menubar->sizeHint() + .expandedTo(menubar->minimumSize()) + .expandedTo(menubar->minimumSizeHint()) + .boundedTo(menubar->maximumSize()).height(); if (result != -1) return result; } @@ -72,7 +75,6 @@ static int menuBarHeightForWidth(QWidget *menubar, int w) \class QLayout \brief The QLayout class is the base class of geometry managers. - \ingroup appearance \ingroup geomanagement This is an abstract base class inherited by the concrete classes @@ -80,7 +82,7 @@ static int menuBarHeightForWidth(QWidget *menubar, int w) For users of QLayout subclasses or of QMainWindow there is seldom any need to use the basic functions provided by QLayout, such as - setSizeConstraint() or setMenuBar(). See \l{Layout Classes} + setSizeConstraint() or setMenuBar(). See \l{Layout Management} for more information. To make your own layout manager, implement the functions @@ -95,7 +97,7 @@ static int menuBarHeightForWidth(QWidget *menubar, int w) Geometry management stops when the layout manager is deleted. - \sa QLayoutItem, {Layout Classes}, {Basic Layouts Example}, + \sa QLayoutItem, {Layout Management}, {Basic Layouts Example}, {Border Layout Example}, {Flow Layout Example} */ @@ -145,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; + } } } } @@ -230,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; + } } } } @@ -1583,8 +1595,6 @@ QDataStream &operator>>(QDataStream &stream, QSizePolicy &policy) { return stream >> policy.data; } - -#endif - +#endif // QT_NO_DATASTREAM QT_END_NAMESPACE diff --git a/src/gui/kernel/qlayoutengine.cpp b/src/gui/kernel/qlayoutengine.cpp index 4f5991c..7b54c22 100644 --- a/src/gui/kernel/qlayoutengine.cpp +++ b/src/gui/kernel/qlayoutengine.cpp @@ -329,7 +329,7 @@ void qGeomCalc(QVector<QLayoutStruct> &chain, int start, int count, qDebug() << "qGeomCalc" << "start" << start << "count" << count << "pos" << pos << "space" << space << "spacer" << spacer; for (i = start; i < start + count; ++i) { - qDebug() << i << ":" << chain[i].minimumSize << chain[i].smartSizeHint() + qDebug() << i << ':' << chain[i].minimumSize << chain[i].smartSizeHint() << chain[i].maximumSize << "stretch" << chain[i].stretch << "empty" << chain[i].empty << "expansive" << chain[i].expansive << "spacing" << chain[i].spacing; diff --git a/src/gui/kernel/qlayoutitem.cpp b/src/gui/kernel/qlayoutitem.cpp index b2fe715..5f929ce 100644 --- a/src/gui/kernel/qlayoutitem.cpp +++ b/src/gui/kernel/qlayoutitem.cpp @@ -54,7 +54,8 @@ QT_BEGIN_NAMESPACE inline static QRect fromLayoutItemRect(QWidgetPrivate *priv, const QRect &rect) { - return priv->fromOrToLayoutItemRect(rect, -1); + return rect.adjusted(priv->leftLayoutItemMargin, priv->topLayoutItemMargin, + -priv->rightLayoutItemMargin, -priv->bottomLayoutItemMargin); } inline static QSize fromLayoutItemSize(QWidgetPrivate *priv, const QSize &size) @@ -64,7 +65,8 @@ inline static QSize fromLayoutItemSize(QWidgetPrivate *priv, const QSize &size) inline static QRect toLayoutItemRect(QWidgetPrivate *priv, const QRect &rect) { - return priv->fromOrToLayoutItemRect(rect, +1); + return rect.adjusted(-priv->leftLayoutItemMargin, -priv->topLayoutItemMargin, + priv->rightLayoutItemMargin, priv->bottomLayoutItemMargin); } inline static QSize toLayoutItemSize(QWidgetPrivate *priv, const QSize &size) @@ -85,7 +87,6 @@ QSizePolicy::operator QVariant() const \brief The QLayoutItem class provides an abstract item that a QLayout manipulates. - \ingroup appearance \ingroup geomanagement This is used by custom layouts. @@ -114,7 +115,6 @@ QSizePolicy::operator QVariant() const /*! \class QSpacerItem - \ingroup appearance \ingroup geomanagement \brief The QSpacerItem class provides blank space in a layout. @@ -142,7 +142,6 @@ QSizePolicy::operator QVariant() const /*! \class QWidgetItem - \ingroup appearance \ingroup geomanagement \brief The QWidgetItem class is a layout item that represents a widget. diff --git a/src/gui/kernel/qmacgesturerecognizer_mac.mm b/src/gui/kernel/qmacgesturerecognizer_mac.mm new file mode 100644 index 0000000..d842322 --- /dev/null +++ b/src/gui/kernel/qmacgesturerecognizer_mac.mm @@ -0,0 +1,262 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmacgesturerecognizer_mac_p.h" +#include "qgesture.h" +#include "qgesture_p.h" +#include "qevent.h" +#include "qevent_p.h" +#include "qwidget.h" +#include "qdebug.h" + +QT_BEGIN_NAMESPACE + +QMacSwipeGestureRecognizer::QMacSwipeGestureRecognizer() +{ +} + +QGesture *QMacSwipeGestureRecognizer::create(QObject * /*target*/) +{ + return new QSwipeGesture; +} + +QGestureRecognizer::Result +QMacSwipeGestureRecognizer::recognize(QGesture *gesture, QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::NativeGesture && obj->isWidgetType()) { + QNativeGestureEvent *ev = static_cast<QNativeGestureEvent*>(event); + switch (ev->gestureType) { + case QNativeGestureEvent::Swipe: { + QSwipeGesture *g = static_cast<QSwipeGesture *>(gesture); + g->setSwipeAngle(ev->angle); + return QGestureRecognizer::TriggerGesture | QGestureRecognizer::ConsumeEventHint; + break; } + default: + break; + } + } + + return QGestureRecognizer::Ignore; +} + +void QMacSwipeGestureRecognizer::reset(QGesture *gesture) +{ + QSwipeGesture *g = static_cast<QSwipeGesture *>(gesture); + g->setSwipeAngle(0); + QGestureRecognizer::reset(gesture); +} + +//////////////////////////////////////////////////////////////////////// + +QMacPinchGestureRecognizer::QMacPinchGestureRecognizer() +{ +} + +QGesture *QMacPinchGestureRecognizer::create(QObject * /*target*/) +{ + return new QPinchGesture; +} + +QGestureRecognizer::Result +QMacPinchGestureRecognizer::recognize(QGesture *gesture, QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::NativeGesture && obj->isWidgetType()) { + QPinchGesture *g = static_cast<QPinchGesture *>(gesture); + QNativeGestureEvent *ev = static_cast<QNativeGestureEvent*>(event); + switch(ev->gestureType) { + case QNativeGestureEvent::GestureBegin: + reset(gesture); + g->setStartCenterPoint(static_cast<QWidget*>(obj)->mapFromGlobal(ev->position)); + g->setCenterPoint(g->startCenterPoint()); + g->setChangeFlags(QPinchGesture::CenterPointChanged); + g->setTotalChangeFlags(g->totalChangeFlags() | g->changeFlags()); + return QGestureRecognizer::MayBeGesture | QGestureRecognizer::ConsumeEventHint; + case QNativeGestureEvent::Rotate: { + g->setLastScaleFactor(g->scaleFactor()); + g->setLastRotationAngle(g->rotationAngle()); + g->setRotationAngle(g->rotationAngle() + ev->percentage); + g->setChangeFlags(QPinchGesture::RotationAngleChanged); + g->setTotalChangeFlags(g->totalChangeFlags() | g->changeFlags()); + return QGestureRecognizer::TriggerGesture | QGestureRecognizer::ConsumeEventHint; + } + case QNativeGestureEvent::Zoom: + g->setLastScaleFactor(g->scaleFactor()); + g->setLastRotationAngle(g->rotationAngle()); + g->setScaleFactor(g->scaleFactor() + ev->percentage); + g->setChangeFlags(QPinchGesture::ScaleFactorChanged); + g->setTotalChangeFlags(g->totalChangeFlags() | g->changeFlags()); + return QGestureRecognizer::TriggerGesture | QGestureRecognizer::ConsumeEventHint; + case QNativeGestureEvent::GestureEnd: + return QGestureRecognizer::FinishGesture | QGestureRecognizer::ConsumeEventHint; + default: + break; + } + } + + return QGestureRecognizer::Ignore; +} + +void QMacPinchGestureRecognizer::reset(QGesture *gesture) +{ + QPinchGesture *g = static_cast<QPinchGesture *>(gesture); + g->setChangeFlags(0); + g->setTotalChangeFlags(0); + g->setScaleFactor(1.0f); + g->setTotalScaleFactor(1.0f); + g->setLastScaleFactor(1.0f); + g->setRotationAngle(0.0f); + g->setTotalRotationAngle(0.0f); + g->setLastRotationAngle(0.0f); + g->setCenterPoint(QPointF()); + g->setStartCenterPoint(QPointF()); + g->setLastCenterPoint(QPointF()); + QGestureRecognizer::reset(gesture); +} + +//////////////////////////////////////////////////////////////////////// + +#if defined(QT_MAC_USE_COCOA) + +QMacPanGestureRecognizer::QMacPanGestureRecognizer() : _panCanceled(true) +{ +} + +QGesture *QMacPanGestureRecognizer::create(QObject *target) +{ + if (!target) + return new QPanGesture; + + if (QWidget *w = qobject_cast<QWidget *>(target)) { + w->setAttribute(Qt::WA_AcceptTouchEvents); + w->setAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents); + return new QPanGesture; + } + return 0; +} + +QGestureRecognizer::Result +QMacPanGestureRecognizer::recognize(QGesture *gesture, QObject *target, QEvent *event) +{ + const int panBeginDelay = 300; + const int panBeginRadius = 3; + + QPanGesture *g = static_cast<QPanGesture *>(gesture); + + switch (event->type()) { + case QEvent::TouchBegin: { + const QTouchEvent *ev = static_cast<const QTouchEvent*>(event); + if (ev->touchPoints().size() == 1) { + reset(gesture); + _startPos = QCursor::pos(); + _panTimer.start(panBeginDelay, target); + _panCanceled = false; + return QGestureRecognizer::MayBeGesture; + } + break;} + case QEvent::TouchEnd: { + if (_panCanceled) + break; + + const QTouchEvent *ev = static_cast<const QTouchEvent*>(event); + if (ev->touchPoints().size() == 1) + return QGestureRecognizer::FinishGesture; + break;} + case QEvent::TouchUpdate: { + if (_panCanceled) + break; + + const QTouchEvent *ev = static_cast<const QTouchEvent*>(event); + if (ev->touchPoints().size() == 1) { + if (_panTimer.isActive()) { + // INVARIANT: Still in maybeGesture. Check if the user + // moved his finger so much that it makes sense to cancel the pan: + const QPointF p = QCursor::pos(); + if ((p - _startPos).manhattanLength() > panBeginRadius) { + _panCanceled = true; + _panTimer.stop(); + return QGestureRecognizer::CancelGesture; + } + } else { + const QPointF p = QCursor::pos(); + const QPointF posOffset = p - _startPos; + g->setLastOffset(g->offset()); + g->setOffset(QPointF(posOffset.x(), posOffset.y())); + return QGestureRecognizer::TriggerGesture; + } + } else if (_panTimer.isActive()) { + // I only want to cancel the pan if the user is pressing + // more than one finger, and the pan hasn't started yet: + _panCanceled = true; + _panTimer.stop(); + return QGestureRecognizer::CancelGesture; + } + break;} + case QEvent::Timer: { + QTimerEvent *ev = static_cast<QTimerEvent *>(event); + if (ev->timerId() == _panTimer.timerId()) { + _panTimer.stop(); + if (_panCanceled) + break; + // Begin new pan session! + _startPos = QCursor::pos(); + return QGestureRecognizer::TriggerGesture | QGestureRecognizer::ConsumeEventHint; + } + break; } + default: + break; + } + + return QGestureRecognizer::Ignore; +} + +void QMacPanGestureRecognizer::reset(QGesture *gesture) +{ + QPanGesture *g = static_cast<QPanGesture *>(gesture); + _startPos = QPointF(); + _panCanceled = true; + g->setOffset(QPointF(0, 0)); + g->setLastOffset(QPointF(0, 0)); + g->setAcceleration(qreal(1)); + QGestureRecognizer::reset(gesture); +} +#endif // QT_MAC_USE_COCOA + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qmacgesturerecognizer_mac_p.h b/src/gui/kernel/qmacgesturerecognizer_mac_p.h new file mode 100644 index 0000000..2dac56a --- /dev/null +++ b/src/gui/kernel/qmacgesturerecognizer_mac_p.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMACSWIPEGESTURERECOGNIZER_MAC_P_H +#define QMACSWIPEGESTURERECOGNIZER_MAC_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qtimer.h" +#include "qpoint.h" +#include "qgesturerecognizer.h" + +QT_BEGIN_NAMESPACE + +class QMacSwipeGestureRecognizer : public QGestureRecognizer +{ +public: + QMacSwipeGestureRecognizer(); + + QGesture *create(QObject *target); + QGestureRecognizer::Result recognize(QGesture *gesture, QObject *watched, QEvent *event); + void reset(QGesture *gesture); +}; + +class QMacPinchGestureRecognizer : public QGestureRecognizer +{ +public: + QMacPinchGestureRecognizer(); + + QGesture *create(QObject *target); + QGestureRecognizer::Result recognize(QGesture *gesture, QObject *watched, QEvent *event); + void reset(QGesture *gesture); +}; + +#if defined(QT_MAC_USE_COCOA) + +class QMacPanGestureRecognizer : public QObject, public QGestureRecognizer +{ +public: + QMacPanGestureRecognizer(); + + QGesture *create(QObject *target); + QGestureRecognizer::Result recognize(QGesture *gesture, QObject *watched, QEvent *event); + void reset(QGesture *gesture); +private: + QPointF _startPos; + QBasicTimer _panTimer; + bool _panCanceled; +}; + +#endif + +QT_END_NAMESPACE + +#endif // QMACSWIPEGESTURERECOGNIZER_MAC_P_H diff --git a/src/gui/kernel/qmime_mac.cpp b/src/gui/kernel/qmime_mac.cpp index 2bdc901..4d842df 100644 --- a/src/gui/kernel/qmime_mac.cpp +++ b/src/gui/kernel/qmime_mac.cpp @@ -68,9 +68,10 @@ #include "qmap.h" #include <private/qt_mac_p.h> + #ifdef Q_WS_MAC32 #include <QuickTime/QuickTime.h> -#include "qlibrary.h" +#include <qlibrary.h> #endif QT_BEGIN_NAMESPACE @@ -127,32 +128,43 @@ CFStringRef qt_mac_mime_typeUTI = CFSTR("com.pasteboard.trolltech.marker"); /*! \class QMacPasteboardMime - \brief The QMacPasteboardMime class maps open-standard MIME to Mac flavors. + \brief The QMacPasteboardMime class converts between a MIME type and a + \l{http://developer.apple.com/macosx/uniformtypeidentifiers.html}{Uniform + Type Identifier (UTI)} format. \since 4.2 - \ingroup io + \ingroup draganddrop - \ingroup misc - Qt's drag and drop support and clipboard facilities use the MIME - standard. On X11, this maps trivially to the Xdnd protocol, but on - Mac although some applications use MIME types to describe clipboard - formats, others use arbitrary non-standardized naming conventions, - or unnamed built-in Mac formats. + Qt's drag and drop and clipboard facilities use the MIME + standard. On X11, this maps trivially to the Xdnd protocol. On + Mac, although some applications use MIME to describe clipboard + contents, it is more common to use Apple's UTI format. + + QMacPasteboardMime's role is to bridge the gap between MIME and UTI; + By subclasses this class, one can extend Qt's drag and drop + and clipboard handling to convert to and from unsupported, or proprietary, UTI formats. - By instantiating subclasses of QMacPasteboardMime that provide conversions - between Mac flavors and MIME formats, you can convert proprietary - clipboard formats to MIME formats. + A subclass of QMacPasteboardMime will automatically be registered, and active, upon instantiation. - Qt has predefined support for the following Mac flavors: + Qt has predefined support for the following UTIs: \list - \i kScrapFlavorTypeUnicode - converted to "text/plain;charset=ISO-10646-UCS-2" - \i kScrapFlavorTypeText - converted to "text/plain;charset=system" or "text/plain" - \i kScrapFlavorTypePicture - converted to "application/x-qt-image" - \i typeFileURL - converted to "text/uri-list" + \i public.utf8-plain-text - converts to "text/plain" + \i public.utf16-plain-text - converts to "text/plain" + \i public.html - converts to "text/html" + \i public.url - converts to "text/uri-list" + \i public.file-url - converts to "text/uri-list" + \i public.tiff - converts to "application/x-qt-image" + \i com.apple.traditional-mac-plain-text - converts to "text/plain" + \i com.apple.pict - converts to "application/x-qt-image" \endlist - You can check if a MIME type is convertible using canConvert() and - can perform conversions with convertToMime() and convertFromMime(). + When working with MIME data, Qt will interate through all instances of QMacPasteboardMime to + find an instance that can convert to, or from, a specific MIME type. It will do this by calling + canConvert() on each instance, starting with (and choosing) the last created instance first. + The actual conversions will be done by using convertToMime() and convertFromMime(). + + \note The API uses the term "flavor" in some cases. This is for backwards + compatibility reasons, and should now be understood as UTIs. */ /*! \enum QMacPasteboardMime::QMacPasteboardMimeType @@ -206,7 +218,7 @@ QString QMacPasteboardMimeAny::flavorFor(const QString &mime) if(mime == QLatin1String("application/x-qt-mime-type-name")) return QString(); QString ret = QLatin1String("com.trolltech.anymime.") + mime; - return ret.replace(QLatin1String("/"), QLatin1String("--")); + return ret.replace(QLatin1Char('/'), QLatin1String("--")); } QString QMacPasteboardMimeAny::mimeFor(QString flav) @@ -382,7 +394,7 @@ QString QMacPasteboardMimeUnicodeText::flavorFor(const QString &mime) int i = mime.indexOf(QLatin1String("charset=")); if (i >= 0) { QString cs(mime.mid(i+8).toLower()); - i = cs.indexOf(QLatin1String(";")); + i = cs.indexOf(QLatin1Char(';')); if (i>=0) cs = cs.left(i); if (cs == QLatin1String("system")) @@ -495,6 +507,8 @@ QList<QByteArray> QMacPasteboardMimeHTMLText::convertFromMime(const QString &mim #ifdef Q_WS_MAC32 +// This can be removed once 10.6 is the minimum (or we have to require 64-bit) whichever comes first. + typedef ComponentResult (*PtrGraphicsImportSetDataHandle)(GraphicsImportComponent, Handle); typedef ComponentResult (*PtrGraphicsImportCreateCGImage)(GraphicsImportComponent, CGImageRef*, UInt32); typedef ComponentResult (*PtrGraphicsExportSetInputCGImage)(GraphicsExportComponent, CGImageRef); @@ -625,7 +639,9 @@ QList<QByteArray> QMacPasteboardMimePict::convertFromMime(const QString &mime, Q DisposeHandle(pic); return ret; } -#endif + + +#endif //Q_WS_MAC32 class QMacPasteboardMimeTiff : public QMacPasteboardMime { public: @@ -672,33 +688,11 @@ QVariant QMacPasteboardMimeTiff::convertToMime(const QString &mime, QList<QByteA return ret; const QByteArray &a = data.first(); QCFType<CGImageRef> image; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) { - QCFType<CFDataRef> data = CFDataCreateWithBytesNoCopy(0, - reinterpret_cast<const UInt8 *>(a.constData()), - a.size(), kCFAllocatorNull); - QCFType<CGImageSourceRef> imageSource = CGImageSourceCreateWithData(data, 0); - image = CGImageSourceCreateImageAtIndex(imageSource, 0, 0); - } else -#endif - { -#ifdef Q_WS_MAC32 - if (resolveMimeQuickTimeSymbols()) { - Handle tiff = NewHandle(a.size()); - memcpy(*tiff, a.constData(), a.size()); - GraphicsImportComponent graphicsImporter; - ComponentResult result = OpenADefaultComponent(GraphicsImporterComponentType, - kQTFileTypeTIFF, &graphicsImporter); - if (!result) - result = ptrGraphicsImportSetDataHandle(graphicsImporter, tiff); - if (!result) - result = ptrGraphicsImportCreateCGImage(graphicsImporter, &image, - kGraphicsImportCreateCGImageUsingCurrentSettings); - CloseComponent(graphicsImporter); - DisposeHandle(tiff); - } -#endif - } + QCFType<CFDataRef> tiffData = CFDataCreateWithBytesNoCopy(0, + reinterpret_cast<const UInt8 *>(a.constData()), + a.size(), kCFAllocatorNull); + QCFType<CGImageSourceRef> imageSource = CGImageSourceCreateWithData(tiffData, 0); + image = CGImageSourceCreateImageAtIndex(imageSource, 0, 0); if (image != 0) ret = QVariant(QPixmap::fromMacCGImageRef(image).toImage()); @@ -841,6 +835,80 @@ QList<QByteArray> QMacPasteboardMimeFileUri::convertFromMime(const QString &mime return ret; } +class QMacPasteboardMimeUrl : public QMacPasteboardMime { +public: + QMacPasteboardMimeUrl() : QMacPasteboardMime(MIME_ALL) { } + QString convertorName(); + + QString flavorFor(const QString &mime); + QString mimeFor(QString flav); + bool canConvert(const QString &mime, QString flav); + QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav); + QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav); +}; + +QString QMacPasteboardMimeUrl::convertorName() +{ + return QLatin1String("URL"); +} + +QString QMacPasteboardMimeUrl::flavorFor(const QString &mime) +{ + if(mime.startsWith(QLatin1String("text/uri-list"))) + return QLatin1String("public.url"); + return QString(); +} + +QString QMacPasteboardMimeUrl::mimeFor(QString flav) +{ + if(flav == QLatin1String("public.url")) + return QLatin1String("text/uri-list"); + return QString(); +} + +bool QMacPasteboardMimeUrl::canConvert(const QString &mime, QString flav) +{ + return flav == QLatin1String("public.url") + && mime == QLatin1String("text/uri-list"); +} + +QVariant QMacPasteboardMimeUrl::convertToMime(const QString &mime, QList<QByteArray> data, QString flav) +{ + if(!canConvert(mime, flav)) + return QVariant(); + + QList<QVariant> ret; + for (int i=0; i<data.size(); ++i) { + QUrl url = QUrl::fromEncoded(data.at(i)); + if (url.host().toLower() == QLatin1String("localhost")) + url.setHost(QString()); + url.setPath(url.path().normalized(QString::NormalizationForm_C)); + ret.append(url); + } + return QVariant(ret); +} + +QList<QByteArray> QMacPasteboardMimeUrl::convertFromMime(const QString &mime, QVariant data, QString flav) +{ + QList<QByteArray> ret; + if (!canConvert(mime, flav)) + return ret; + + QList<QVariant> urls = data.toList(); + for(int i=0; i<urls.size(); ++i) { + QUrl url = urls.at(i).toUrl(); + if (url.scheme().isEmpty()) + url.setScheme(QLatin1String("file")); + if (url.scheme().toLower() == QLatin1String("file")) { + if (url.host().isEmpty()) + url.setHost(QLatin1String("localhost")); + url.setPath(url.path().normalized(QString::NormalizationForm_D)); + } + ret.append(url.toEncoded()); + } + return ret; +} + #ifdef QT3_SUPPORT class QMacPasteboardMimeQt3Any : public QMacPasteboardMime { private: @@ -1037,12 +1105,16 @@ void QMacPasteboardMime::initialize() //standard types that we wrap new QMacPasteboardMimeTiff; #ifdef Q_WS_MAC32 - new QMacPasteboardMimePict; + // 10.6 does automatic synthesis to and from PICT to standard image types (like TIFF), + // so don't bother doing it ourselves, especially since it's not available in 64-bit. + if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_6) + new QMacPasteboardMimePict; #endif new QMacPasteboardMimeUnicodeText; new QMacPasteboardMimePlainText; new QMacPasteboardMimeHTMLText; new QMacPasteboardMimeFileUri; + new QMacPasteboardMimeUrl; new QMacPasteboardMimeTypeName; //make sure our "non-standard" types are always last! --Sam new QMacPasteboardMimeAny; diff --git a/src/gui/kernel/qmime_win.cpp b/src/gui/kernel/qmime_win.cpp index 6364a99..9b4f39c 100644 --- a/src/gui/kernel/qmime_win.cpp +++ b/src/gui/kernel/qmime_win.cpp @@ -170,7 +170,7 @@ static QByteArray getData(int cf, IDataObject *pDataObj) if (pDataObj->GetData(&formatetc, &s) == S_OK) { char szBuffer[4096]; ULONG actualRead = 0; - LARGE_INTEGER pos = {0, 0}; + LARGE_INTEGER pos = {{0, 0}}; //Move to front (can fail depending on the data model implemented) HRESULT hr = s.pstm->Seek(pos, STREAM_SEEK_SET, NULL); while(SUCCEEDED(hr)){ @@ -219,9 +219,7 @@ Q_GLOBAL_STATIC(QWindowsMimeList, theMimeList); /*! \class QWindowsMime \brief The QWindowsMime class maps open-standard MIME to Window Clipboard formats. - \ingroup io \ingroup draganddrop - \ingroup misc Qt's drag-and-drop and clipboard facilities use the MIME standard. On X11, this maps trivially to the Xdnd protocol, but on Windows @@ -281,11 +279,7 @@ QWindowsMime::~QWindowsMime() */ int QWindowsMime::registerMimeType(const QString &mime) { -#ifdef Q_OS_WINCE int f = RegisterClipboardFormat(reinterpret_cast<const wchar_t *> (mime.utf16())); -#else - int f = RegisterClipboardFormatA(mime.toLocal8Bit()); -#endif if (!f) qErrnoWarning("QWindowsMime::registerMimeType: Failed to register clipboard format"); @@ -401,9 +395,9 @@ QStringList QWindowsMime::allMimesForFormats(IDataObject *pDataObj) while (S_OK == fmtenum->Next(1, &fmtetc, 0)) { #if defined(QMIME_DEBUG) && !defined(Q_OS_WINCE) qDebug("QWindowsMime::allMimesForFormats()"); - char buf[256] = {0}; - GetClipboardFormatNameA(fmtetc.cfFormat, buf, 255); - qDebug("CF = %d : %s", fmtetc.cfFormat, buf); + wchar_t buf[256] = {0}; + GetClipboardFormatName(fmtetc.cfFormat, buf, 255); + qDebug("CF = %d : %s", fmtetc.cfFormat, QString::fromWCharArray(buf)); #endif for (int i=mimes.size()-1; i>=0; --i) { QString format = mimes.at(i)->mimeForFormat(fmtetc); @@ -504,7 +498,7 @@ bool QWindowsMimeText::convertFromMime(const FORMATETC &formatetc, const QMimeDa ++u; } res.truncate(ri); - const int byteLength = res.length()*2; + const int byteLength = res.length() * sizeof(ushort); QByteArray r(byteLength + 2, '\0'); memcpy(r.data(), res.unicode(), byteLength); r[byteLength] = 0; @@ -549,7 +543,7 @@ QVariant QWindowsMimeText::convertToMime(const QString &mime, LPDATAOBJECT pData QString str; QByteArray data = getData(CF_UNICODETEXT, pDataObj); if (!data.isEmpty()) { - str = QString::fromUtf16((const unsigned short *)data.data()); + str = QString::fromWCharArray((const wchar_t *)data.data()); str.replace(QLatin1String("\r\n"), QLatin1String("\n")); } else { data = getData(CF_TEXT, pDataObj); @@ -620,11 +614,7 @@ bool QWindowsMimeURI::convertFromMime(const FORMATETC &formatetc, const QMimeDat for (int i=0; i<urls.size(); i++) { QString fn = QDir::toNativeSeparators(urls.at(i).toLocalFile()); if (!fn.isEmpty()) { - QT_WA({ - size += sizeof(TCHAR)*(fn.length()+1); - } , { - size += fn.toLocal8Bit().length()+1; - }); + size += sizeof(ushort) * (fn.length() + 1); fileNames.append(fn); } } @@ -636,36 +626,22 @@ bool QWindowsMimeURI::convertFromMime(const FORMATETC &formatetc, const QMimeDat d->fNC = true; char* files = ((char*)d) + d->pFiles; - QT_WA({ - d->fWide = true; - TCHAR* f = (TCHAR*)files; - for (int i=0; i<fileNames.size(); i++) { - int l = fileNames.at(i).length(); - memcpy(f, fileNames.at(i).utf16(), l*sizeof(TCHAR)); - f += l; - *f++ = 0; - } - *f = 0; - } , { - d->fWide = false; - char* f = files; - for (int i=0; i<fileNames.size(); i++) { - QByteArray c = fileNames.at(i).toLocal8Bit(); - if (!c.isEmpty()) { - int l = c.length(); - memcpy(f, c.constData(), l); - f += l; - *f++ = 0; - } - } - *f = 0; - }); + d->fWide = true; + wchar_t* f = (wchar_t*)files; + for (int i=0; i<fileNames.size(); i++) { + int l = fileNames.at(i).length(); + memcpy(f, fileNames.at(i).utf16(), l * sizeof(ushort)); + f += l; + *f++ = 0; + } + *f = 0; + return setData(result, pmedium); } else if (getCf(formatetc) == CF_INETURL_W) { QList<QUrl> urls = mimeData->urls(); QByteArray result; QString url = urls.at(0).toString(); - result = QByteArray((const char *)url.utf16(), url.length() * 2); + result = QByteArray((const char *)url.utf16(), url.length() * sizeof(ushort)); result.append('\0'); result.append('\0'); return setData(result, pmedium); @@ -720,15 +696,15 @@ QVariant QWindowsMimeURI::convertToMime(const QString &mimeType, LPDATAOBJECT pD LPDROPFILES hdrop = (LPDROPFILES)data.data(); if (hdrop->fWide) { - const ushort* filesw = (const ushort*)(data.data() + hdrop->pFiles); - int i=0; + const wchar_t* filesw = (const wchar_t *)(data.data() + hdrop->pFiles); + int i = 0; while (filesw[i]) { - QString fileurl = QString::fromUtf16(filesw+i); + QString fileurl = QString::fromWCharArray(filesw + i); urls += QUrl::fromLocalFile(fileurl); i += fileurl.length()+1; } } else { - const char* files = (const char*)data.data() + hdrop->pFiles; + const char* files = (const char *)data.data() + hdrop->pFiles; int i=0; while (files[i]) { urls += QUrl::fromLocalFile(QString::fromLocal8Bit(files+i)); @@ -744,7 +720,7 @@ QVariant QWindowsMimeURI::convertToMime(const QString &mimeType, LPDATAOBJECT pD QByteArray data = getData(CF_INETURL_W, pDataObj); if (data.isEmpty()) return QVariant(); - return QUrl(QString::fromUtf16((const unsigned short *)data.constData())); + return QUrl(QString::fromWCharArray((const wchar_t *)data.constData())); } else if (canGetData(CF_INETURL, pDataObj)) { QByteArray data = getData(CF_INETURL, pDataObj); if (data.isEmpty()) @@ -852,7 +828,7 @@ QVariant QWindowsMimeHtml::convertToMime(const QString &mime, IDataObject *pData if (end > start && start > 0) { html = "<!--StartFragment-->" + html.mid(start, end - start); html += "<!--EndFragment-->"; - html.replace("\r", ""); + html.replace('\r', ""); result = QString::fromUtf8(html); } } @@ -913,11 +889,7 @@ private: QWindowsMimeImage::QWindowsMimeImage() { -#ifdef Q_OS_WINCE - CF_PNG = RegisterClipboardFormat(reinterpret_cast<const wchar_t *> (QString::fromLatin1("PNG").utf16())); -#else - CF_PNG = RegisterClipboardFormatA("PNG"); -#endif + CF_PNG = RegisterClipboardFormat(L"PNG"); } QVector<FORMATETC> QWindowsMimeImage::formatsForMime(const QString &mimeType, const QMimeData *mimeData) const @@ -1114,7 +1086,7 @@ bool QBuiltInMimes::convertFromMime(const FORMATETC &formatetc, const QMimeData ++u; } res.truncate(ri); - const int byteLength = res.length()*2; + const int byteLength = res.length() * sizeof(ushort); QByteArray r(byteLength + 2, '\0'); memcpy(r.data(), res.unicode(), byteLength); r[byteLength] = 0; @@ -1154,8 +1126,8 @@ QVariant QBuiltInMimes::convertToMime(const QString &mimeType, IDataObject *pDat qDebug("QBuiltInMimes::convertToMime()"); #endif if (mimeType == QLatin1String("text/html") && preferredType == QVariant::String) { - // text/html is in wide chars on windows (compatible with mozillia) - val = QString::fromUtf16((const unsigned short *)data.data()); + // text/html is in wide chars on windows (compatible with Mozilla) + val = QString::fromWCharArray((const wchar_t *)data.data()); } else { val = data; // it should be enough to return the data and let QMimeData do the rest. } @@ -1262,16 +1234,16 @@ QVector<FORMATETC> QLastResortMimes::formatsForMime(const QString &mimeType, con } return formatetcs; } -static const char *x_qt_windows_mime = "application/x-qt-windows-mime;value=\""; +static const char x_qt_windows_mime[] = "application/x-qt-windows-mime;value=\""; -bool isCustomMimeType(const QString &mimeType) +static bool isCustomMimeType(const QString &mimeType) { return mimeType.startsWith(QLatin1String(x_qt_windows_mime), Qt::CaseInsensitive); } -QString customMimeType(const QString &mimeType) +static QString customMimeType(const QString &mimeType) { - int len = QString(QLatin1String(x_qt_windows_mime)).length(); + int len = sizeof(x_qt_windows_mime) - 1; int n = mimeType.lastIndexOf(QLatin1Char('\"'))-len; return mimeType.mid(len, n); } @@ -1280,11 +1252,7 @@ bool QLastResortMimes::canConvertToMime(const QString &mimeType, IDataObject *pD { if (isCustomMimeType(mimeType)) { QString clipFormat = customMimeType(mimeType); -#ifdef Q_OS_WINCE int cf = RegisterClipboardFormat(reinterpret_cast<const wchar_t *> (clipFormat.utf16())); -#else - int cf = RegisterClipboardFormatA(clipFormat.toLocal8Bit()); -#endif return canGetData(cf, pDataObj); } else if (formats.keys(mimeType).isEmpty()) { // if it is not in there then register it an see if we can get it @@ -1304,11 +1272,7 @@ QVariant QLastResortMimes::convertToMime(const QString &mimeType, IDataObject *p QByteArray data; if (isCustomMimeType(mimeType)) { QString clipFormat = customMimeType(mimeType); -#ifdef Q_OS_WINCE int cf = RegisterClipboardFormat(reinterpret_cast<const wchar_t *> (clipFormat.utf16())); -#else - int cf = RegisterClipboardFormatA(clipFormat.toLocal8Bit()); -#endif data = getData(cf, pDataObj); } else if (formats.keys(mimeType).isEmpty()) { int cf = QWindowsMime::registerMimeType(mimeType); @@ -1325,46 +1289,38 @@ QVariant QLastResortMimes::convertToMime(const QString &mimeType, IDataObject *p QString QLastResortMimes::mimeForFormat(const FORMATETC &formatetc) const { QString format = formats.value(getCf(formatetc)); - if (format.isEmpty()) { - QByteArray ba; - QString clipFormat; - int len; - QT_WA({ - ba.resize(256*2); - len = GetClipboardFormatNameW(getCf(formatetc), (TCHAR*)ba.data(), 255); - if (len) - clipFormat = QString::fromUtf16((ushort *)ba.data(), len); - } , { - ba.resize(256); - len = GetClipboardFormatNameA(getCf(formatetc), ba.data(), 255); - if (len) - clipFormat = QString::fromLocal8Bit(ba.data(), len); - }); - if (len) { + if (!format.isEmpty()) + return format; + + wchar_t buffer[256]; + int len = GetClipboardFormatName(getCf(formatetc), buffer, 256); + + if (len) { + QString clipFormat = QString::fromWCharArray(buffer, len); #ifndef QT_NO_DRAGANDDROP - if (QInternalMimeData::canReadData(clipFormat)) - format = clipFormat; - else if((formatetc.cfFormat >= 0xC000)){ - //create the mime as custom. not registered. - if (!excludeList.contains(clipFormat, Qt::CaseInsensitive)) { - //check if this is a mime type - bool ianaType = false; - int sz = ianaTypes.size(); - for (int i = 0; i < sz; i++) { - if (clipFormat.startsWith(ianaTypes[i], Qt::CaseInsensitive)) { - ianaType = true; - break; - } + if (QInternalMimeData::canReadData(clipFormat)) + format = clipFormat; + else if((formatetc.cfFormat >= 0xC000)){ + //create the mime as custom. not registered. + if (!excludeList.contains(clipFormat, Qt::CaseInsensitive)) { + //check if this is a mime type + bool ianaType = false; + int sz = ianaTypes.size(); + for (int i = 0; i < sz; i++) { + if (clipFormat.startsWith(ianaTypes[i], Qt::CaseInsensitive)) { + ianaType = true; + break; } - if (!ianaType) - format = QLatin1String(x_qt_windows_mime) + clipFormat + QLatin1Char('\"'); - else - format = clipFormat; } + if (!ianaType) + format = QLatin1String(x_qt_windows_mime) + clipFormat + QLatin1Char('\"'); + else + format = clipFormat; } -#endif //QT_NO_DRAGANDDROP } +#endif //QT_NO_DRAGANDDROP } + return format; } diff --git a/src/gui/kernel/qmotifdnd_x11.cpp b/src/gui/kernel/qmotifdnd_x11.cpp index bcecff2..974e651 100644 --- a/src/gui/kernel/qmotifdnd_x11.cpp +++ b/src/gui/kernel/qmotifdnd_x11.cpp @@ -40,7 +40,7 @@ ****************************************************************************/ /* The following copyright notice pertains to the code as contributed -to Nokia, not to Nokia's modifications. It is replicated +to Qt, not to Nokia's modifications. It is replicated in doc/dnd.doc, where the documentation system can see it. */ /* Copyright 1996 Daniel Dardailler. diff --git a/src/gui/kernel/qmultitouch_mac.mm b/src/gui/kernel/qmultitouch_mac.mm new file mode 100644 index 0000000..2f6f9ca --- /dev/null +++ b/src/gui/kernel/qmultitouch_mac.mm @@ -0,0 +1,219 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <private/qmultitouch_mac_p.h> +#include <qcursor.h> + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 + +QT_BEGIN_NAMESPACE + +#ifdef QT_MAC_USE_COCOA + +QHash<qint64, QCocoaTouch*> QCocoaTouch::_currentTouches; +QPointF QCocoaTouch::_screenReferencePos; +QPointF QCocoaTouch::_trackpadReferencePos; +int QCocoaTouch::_idAssignmentCount = 0; +int QCocoaTouch::_touchCount = 0; +bool QCocoaTouch::_updateInternalStateOnly = true; + +QCocoaTouch::QCocoaTouch(NSTouch *nstouch) +{ + if (_currentTouches.size() == 0) + _idAssignmentCount = 0; + + _touchPoint.setId(_idAssignmentCount++); + _touchPoint.setPressure(1.0); + _identity = qint64([nstouch identity]); + _currentTouches.insert(_identity, this); + updateTouchData(nstouch, NSTouchPhaseBegan); +} + +QCocoaTouch::~QCocoaTouch() +{ + _currentTouches.remove(_identity); +} + +void QCocoaTouch::updateTouchData(NSTouch *nstouch, NSTouchPhase phase) +{ + if (_touchCount == 1) + _touchPoint.setState(toTouchPointState(phase) | Qt::TouchPointPrimary); + else + _touchPoint.setState(toTouchPointState(phase)); + + // From the normalized position on the trackpad, calculate + // where on screen the touchpoint should be according to the + // reference position: + NSPoint npos = [nstouch normalizedPosition]; + QPointF qnpos = QPointF(npos.x, 1 - npos.y); + _touchPoint.setNormalizedPos(qnpos); + + if (_touchPoint.id() == 0 && phase == NSTouchPhaseBegan) { + _trackpadReferencePos = qnpos; + _screenReferencePos = QCursor::pos(); + } + + NSSize dsize = [nstouch deviceSize]; + float ppiX = (qnpos.x() - _trackpadReferencePos.x()) * dsize.width; + float ppiY = (qnpos.y() - _trackpadReferencePos.y()) * dsize.height; + QPointF relativePos = _trackpadReferencePos - QPointF(ppiX, ppiY); + _touchPoint.setScreenPos(_screenReferencePos - relativePos); +} + +QCocoaTouch *QCocoaTouch::findQCocoaTouch(NSTouch *nstouch) +{ + qint64 identity = qint64([nstouch identity]); + if (_currentTouches.contains(identity)) + return _currentTouches.value(identity); + return 0; +} + +Qt::TouchPointState QCocoaTouch::toTouchPointState(NSTouchPhase nsState) +{ + Qt::TouchPointState qtState = Qt::TouchPointReleased; + switch (nsState) { + case NSTouchPhaseBegan: + qtState = Qt::TouchPointPressed; + break; + case NSTouchPhaseMoved: + qtState = Qt::TouchPointMoved; + break; + case NSTouchPhaseStationary: + qtState = Qt::TouchPointStationary; + break; + case NSTouchPhaseEnded: + case NSTouchPhaseCancelled: + qtState = Qt::TouchPointReleased; + break; + default: + break; + } + return qtState; +} + +QList<QTouchEvent::TouchPoint> +QCocoaTouch::getCurrentTouchPointList(NSEvent *event, bool acceptSingleTouch) +{ + QMap<int, QTouchEvent::TouchPoint> touchPoints; + NSSet *ended = [event touchesMatchingPhase:NSTouchPhaseEnded | NSTouchPhaseCancelled inView:nil]; + NSSet *active = [event + touchesMatchingPhase:NSTouchPhaseBegan | NSTouchPhaseMoved | NSTouchPhaseStationary + inView:nil]; + _touchCount = [active count]; + + // First: remove touches that were ended by the user. If we are + // currently not accepting single touches, a corresponding 'begin' + // has never been send to the app for these events. + // So should therefore not send the following removes either. + + for (int i=0; i<int([ended count]); ++i) { + NSTouch *touch = [[ended allObjects] objectAtIndex:i]; + QCocoaTouch *qcocoaTouch = findQCocoaTouch(touch); + if (qcocoaTouch) { + qcocoaTouch->updateTouchData(touch, [touch phase]); + if (!_updateInternalStateOnly) + touchPoints.insert(qcocoaTouch->_touchPoint.id(), qcocoaTouch->_touchPoint); + delete qcocoaTouch; + } + } + + bool wasUpdateInternalStateOnly = _updateInternalStateOnly; + _updateInternalStateOnly = !acceptSingleTouch && _touchCount < 2; + + // Next: update, or create, existing touches. + // We always keep track of all touch points, even + // when not accepting single touches. + + for (int i=0; i<int([active count]); ++i) { + NSTouch *touch = [[active allObjects] objectAtIndex:i]; + QCocoaTouch *qcocoaTouch = findQCocoaTouch(touch); + if (!qcocoaTouch) + qcocoaTouch = new QCocoaTouch(touch); + else + qcocoaTouch->updateTouchData(touch, wasUpdateInternalStateOnly ? NSTouchPhaseBegan : [touch phase]); + if (!_updateInternalStateOnly) + touchPoints.insert(qcocoaTouch->_touchPoint.id(), qcocoaTouch->_touchPoint); + } + + // Next: sadly, we need to check that our touch hash is in + // sync with cocoa. This is typically not the case after a system + // gesture happend (like a four-finger-swipe to show expose). + + if (_touchCount != _currentTouches.size()) { + // Remove all instances, and basically start from scratch: + touchPoints.clear(); + QList<QCocoaTouch *> list = _currentTouches.values(); + foreach (QCocoaTouch *qcocoaTouch, _currentTouches.values()) { + if (!_updateInternalStateOnly) { + qcocoaTouch->_touchPoint.setState(Qt::TouchPointReleased); + touchPoints.insert(qcocoaTouch->_touchPoint.id(), qcocoaTouch->_touchPoint); + } + delete qcocoaTouch; + } + _currentTouches.clear(); + _updateInternalStateOnly = !acceptSingleTouch; + return touchPoints.values(); + } + + // Finally: If this call _started_ to reject single + // touches, we need to fake a relase for the remaining + // touch now (and refake a begin for it later, if needed). + + if (_updateInternalStateOnly && !wasUpdateInternalStateOnly && !_currentTouches.isEmpty()) { + QCocoaTouch *qcocoaTouch = _currentTouches.values().first(); + qcocoaTouch->_touchPoint.setState(Qt::TouchPointReleased); + touchPoints.insert(qcocoaTouch->_touchPoint.id(), qcocoaTouch->_touchPoint); + // Since this last touch also will end up beeing the first + // touch (if the user adds a second finger without lifting + // the first), we promote it to be the primary touch: + qcocoaTouch->_touchPoint.setId(0); + _idAssignmentCount = 1; + } + + return touchPoints.values(); +} + +#endif + +QT_END_NAMESPACE + +#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 + diff --git a/src/gui/kernel/qmultitouch_mac_p.h b/src/gui/kernel/qmultitouch_mac_p.h new file mode 100644 index 0000000..33eb136 --- /dev/null +++ b/src/gui/kernel/qmultitouch_mac_p.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QMULTITOUCH_MAC_P_H +#define QMULTITOUCH_MAC_P_H + +#ifdef QT_MAC_USE_COCOA +#import <Cocoa/Cocoa.h> +#endif + +#include <qevent.h> +#include <qhash.h> +#include <QtCore> + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 + +QT_BEGIN_NAMESPACE + +#ifdef QT_MAC_USE_COCOA + +class QCocoaTouch +{ + public: + static QList<QTouchEvent::TouchPoint> getCurrentTouchPointList(NSEvent *event, bool acceptSingleTouch); + static void setMouseInDraggingState(bool inDraggingState); + + private: + static QHash<qint64, QCocoaTouch*> _currentTouches; + static QPointF _screenReferencePos; + static QPointF _trackpadReferencePos; + static int _idAssignmentCount; + static int _touchCount; + static bool _updateInternalStateOnly; + + QTouchEvent::TouchPoint _touchPoint; + qint64 _identity; + + QCocoaTouch(NSTouch *nstouch); + ~QCocoaTouch(); + + void updateTouchData(NSTouch *nstouch, NSTouchPhase phase); + static QCocoaTouch *findQCocoaTouch(NSTouch *nstouch); + static Qt::TouchPointState toTouchPointState(NSTouchPhase nsState); +}; + +#endif // QT_MAC_USE_COCOA + +QT_END_NAMESPACE + +#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 + +#endif // QMULTITOUCH_MAC_P_H + diff --git a/src/gui/kernel/qpalette.cpp b/src/gui/kernel/qpalette.cpp index 377effa..9d96aad 100644 --- a/src/gui/kernel/qpalette.cpp +++ b/src/gui/kernel/qpalette.cpp @@ -125,7 +125,7 @@ QDataStream &operator>>(QDataStream &s, QColorGroup &g) { return qt_stream_in_qcolorgroup(s, g); } -#endif +#endif // QT_NO_DATASTREAM /*! Constructs a palette with the specified \a active, \a disabled and @@ -158,7 +158,7 @@ void QPalette::setColorGroup(ColorGroup cg, const QColorGroup &g) g.brush(LinkVisited), g.brush(ToolTipBase), g.brush(ToolTipText)); } -#endif +#endif // QT3_SUPPORT /*! \fn const QColor &QPalette::color(ColorRole role) const @@ -399,8 +399,8 @@ void QPalette::setColorGroup(ColorGroup cg, const QColorGroup &g) \ingroup appearance \ingroup shared - \ingroup multimedia - \mainclass + \ingroup painting + A palette consists of three color groups: \e Active, \e Disabled, and \e Inactive. All widgets in Qt contain a palette and diff --git a/src/gui/kernel/qshortcut.cpp b/src/gui/kernel/qshortcut.cpp index fdb0db7..3aba2d0 100644 --- a/src/gui/kernel/qshortcut.cpp +++ b/src/gui/kernel/qshortcut.cpp @@ -63,7 +63,7 @@ QT_BEGIN_NAMESPACE \brief The QShortcut class is used to create keyboard shortcuts. \ingroup events - \mainclass + The QShortcut class provides a way of connecting keyboard shortcuts to Qt's \l{signals and slots} mechanism, so that @@ -163,7 +163,6 @@ public: void QShortcutPrivate::redoGrab(QShortcutMap &map) { Q_Q(QShortcut); - QWidget *parent = q->parentWidget(); if (!parent) { qWarning("QShortcut: No widget parent defined"); return; diff --git a/src/gui/kernel/qshortcutmap.cpp b/src/gui/kernel/qshortcutmap.cpp index fdd0326..4c5eb7a 100644 --- a/src/gui/kernel/qshortcutmap.cpp +++ b/src/gui/kernel/qshortcutmap.cpp @@ -61,8 +61,6 @@ QT_BEGIN_NAMESPACE -extern bool qt_mac_no_native_menubar; // qmenu_mac.cpp - // To enable verbose output uncomment below //#define DEBUG_QSHORTCUTMAP @@ -101,17 +99,17 @@ struct QShortcutEntry QObject *owner; }; -#ifndef QT_NO_DEBUG_STREAM +#if 0 //ndef QT_NO_DEBUG_STREAM /*! \internal QDebug operator<< for easy debug output of the shortcut entries. */ -QDebug &operator<<(QDebug &dbg, const QShortcutEntry *se) { +static QDebug &operator<<(QDebug &dbg, const QShortcutEntry *se) { if (!se) return dbg << "QShortcutEntry(0x0)"; dbg.nospace() << "QShortcutEntry(" << se->keyseq << "), id(" << se->id << "), enabled(" << se->enabled << "), autorepeat(" << se->autorepeat - << "), owner(" << se->owner << ")"; + << "), owner(" << se->owner << ')'; return dbg.space(); } #endif // QT_NO_DEBUGSTREAM @@ -148,9 +146,8 @@ public: QShortcutMap constructor. */ QShortcutMap::QShortcutMap() + : d_ptr(new QShortcutMapPrivate(this)) { - d_ptr = new QShortcutMapPrivate(this); - Q_ASSERT(d_ptr != 0); resetState(); } @@ -159,8 +156,6 @@ QShortcutMap::QShortcutMap() */ QShortcutMap::~QShortcutMap() { - delete d_ptr; - d_ptr = 0; } /*! \internal @@ -630,13 +625,13 @@ QKeySequence::SequenceMatch QShortcutMap::matches(const QKeySequence &seq1, bool QShortcutMap::correctContext(const QShortcutEntry &item) const { Q_ASSERT_X(item.owner, "QShortcutMap", "Shortcut has no owner. Illegal map state!"); - QWidget *active_window = qApp->activeWindow(); + QWidget *active_window = QApplication::activeWindow(); // popups do not become the active window, // so we fake it here to get the correct context // for the shortcut system. - if (qApp->activePopupWidget()) - active_window = qApp->activePopupWidget(); + if (QApplication::activePopupWidget()) + active_window = QApplication::activePopupWidget(); if (!active_window) return false; @@ -660,7 +655,7 @@ bool QShortcutMap::correctWidgetContext(Qt::ShortcutContext context, QWidget *w, { bool visible = w->isVisible(); #ifdef Q_WS_MAC - if (!qt_mac_no_native_menubar && qobject_cast<QMenuBar *>(w)) + if (!qApp->testAttribute(Qt::AA_DontUseNativeMenuBar) && qobject_cast<QMenuBar *>(w)) visible = true; #endif @@ -723,7 +718,7 @@ bool QShortcutMap::correctGraphicsWidgetContext(Qt::ShortcutContext context, QGr { bool visible = w->isVisible(); #ifdef Q_WS_MAC - if (!qt_mac_no_native_menubar && qobject_cast<QMenuBar *>(w)) + if (!qApp->testAttribute(Qt::AA_DontUseNativeMenuBar) && qobject_cast<QMenuBar *>(w)) visible = true; #endif @@ -878,7 +873,7 @@ void QShortcutMap::dispatchEvent(QKeyEvent *e) qDebug().nospace() << "QShortcutMap::dispatchEvent(): Sending QShortcutEvent(\"" << (QString)next->keyseq << "\", " << next->id << ", " - << (bool)(enabledShortcuts>1) << ") to object(" << next->owner << ")"; + << (bool)(enabledShortcuts>1) << ") to object(" << next->owner << ')'; #endif QShortcutEvent se(next->keyseq, next->id, enabledShortcuts>1); QApplication::sendEvent(const_cast<QObject *>(next->owner), &se); diff --git a/src/gui/kernel/qshortcutmap_p.h b/src/gui/kernel/qshortcutmap_p.h index 9d1b84c..12bc670 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/qsizepolicy.h b/src/gui/kernel/qsizepolicy.h index 334267e..2914a21 100644 --- a/src/gui/kernel/qsizepolicy.h +++ b/src/gui/kernel/qsizepolicy.h @@ -64,6 +64,7 @@ private: VMask = HMask << HSize, CTShift = 9, CTSize = 5, + WFHShift = CTShift + CTSize, CTMask = ((0x1 << CTSize) - 1) << CTShift, UnusedShift = CTShift + CTSize, UnusedSize = 2 @@ -199,19 +200,32 @@ private: QSizePolicy(int i) : data(i) { } quint32 data; +/* use bit flags instead, keep it here for improved readability for now + quint32 horzPolicy : 4; + quint32 vertPolicy : 4; + quint32 hfw : 1; + quint32 ctype : 5; + quint32 wfh : 1; + quint32 padding : 1; // we cannot use the highest bit + quint32 horStretch : 8; + quint32 verStretch : 8; +*/ + }; Q_DECLARE_OPERATORS_FOR_FLAGS(QSizePolicy::ControlTypes) +#ifndef QT_NO_DATASTREAM // implemented in qlayout.cpp Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QSizePolicy &); Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QSizePolicy &); +#endif inline void QSizePolicy::transpose() { Policy hData = horizontalPolicy(); Policy vData = verticalPolicy(); - uchar hStretch = horizontalStretch(); - uchar vStretch = verticalStretch(); + uchar hStretch = uchar(horizontalStretch()); + uchar vStretch = uchar(verticalStretch()); setHorizontalPolicy(vData); setVerticalPolicy(hData); setHorizontalStretch(vStretch); diff --git a/src/gui/kernel/qsizepolicy.qdoc b/src/gui/kernel/qsizepolicy.qdoc new file mode 100644 index 0000000..2dcb071 --- /dev/null +++ b/src/gui/kernel/qsizepolicy.qdoc @@ -0,0 +1,521 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QSizePolicy + \brief The QSizePolicy class is a layout attribute describing horizontal + and vertical resizing policy. + + \ingroup geomanagement + + The size policy of a widget is an expression of its willingness to + be resized in various ways, and affects how the widget is treated + by the \l{Layout Management}{layout engine}. Each widget returns a + QSizePolicy that describes the horizontal and vertical resizing + policy it prefers when being laid out. You can change this for + a specific widget by changing its QWidget::sizePolicy property. + + QSizePolicy contains two independent QSizePolicy::Policy values + and two stretch factors; one describes the widgets's horizontal + size policy, and the other describes its vertical size policy. It + also contains a flag to indicate whether the height and width of + its preferred size are related. + + The horizontal and vertical policies can be set in the + constructor, and altered using the setHorizontalPolicy() and + setVerticalPolicy() functions. The stretch factors can be set + using the setHorizontalStretch() and setVerticalStretch() + functions. The flag indicating whether the widget's + \l{QWidget::sizeHint()}{sizeHint()} is width-dependent (such as a + menu bar or a word-wrapping label) can be set using the + setHeightForWidth() function. + + The current size policies and stretch factors be retrieved using + the horizontalPolicy(), verticalPolicy(), horizontalStretch() and + verticalStretch() functions. Alternatively, use the transpose() + function to swap the horizontal and vertical policies and + stretches. The hasHeightForWidth() function returns the current + status of the flag indicating the size hint dependencies. + + Use the expandingDirections() function to determine whether the + associated widget can make use of more space than its + \l{QWidget::sizeHint()}{sizeHint()} function indicates, as well as + find out in which directions it can expand. + + Finally, the QSizePolicy class provides operators comparing this + size policy to a given policy, as well as a QVariant operator + storing this QSizePolicy as a QVariant object. + + \sa QSize, QWidget::sizeHint(), QWidget::sizePolicy, + QLayoutItem::sizeHint() +*/ + +/*! + \enum QSizePolicy::PolicyFlag + + These flags are combined together to form the various \l{Policy} + values: + + \value GrowFlag The widget can grow beyond its size hint if necessary. + \value ExpandFlag The widget should get as much space as possible. + \value ShrinkFlag The widget can shrink below its size hint if necessary. + \value IgnoreFlag The widget's size hint is ignored. The widget will get + as much space as possible. + + \sa Policy +*/ + +/*! + \enum QSizePolicy::Policy + + This enum describes the various per-dimension sizing types used + when constructing a QSizePolicy. + + \value Fixed The QWidget::sizeHint() is the only acceptable + alternative, so the widget can never grow or shrink (e.g. the + vertical direction of a push button). + + \value Minimum The sizeHint() is minimal, and sufficient. The + widget can be expanded, but there is no advantage to it being + larger (e.g. the horizontal direction of a push button). + It cannot be smaller than the size provided by sizeHint(). + + \value Maximum The sizeHint() is a maximum. The widget can be + shrunk any amount without detriment if other widgets need the + space (e.g. a separator line). + It cannot be larger than the size provided by sizeHint(). + + \value Preferred The sizeHint() is best, but the widget can be + shrunk and still be useful. The widget can be expanded, but there + is no advantage to it being larger than sizeHint() (the default + QWidget policy). + + \value Expanding The sizeHint() is a sensible size, but the + widget can be shrunk and still be useful. The widget can make use + of extra space, so it should get as much space as possible (e.g. + the horizontal direction of a horizontal slider). + + \value MinimumExpanding The sizeHint() is minimal, and sufficient. + The widget can make use of extra space, so it should get as much + space as possible (e.g. the horizontal direction of a horizontal + slider). + + \value Ignored The sizeHint() is ignored. The widget will get as + much space as possible. + + \sa PolicyFlag, setHorizontalPolicy(), setVerticalPolicy() +*/ + +/*! + \fn QSizePolicy::QSizePolicy() + + Constructs a QSizePolicy object with \l Fixed as its horizontal + and vertical policies. + + The policies can be altered using the setHorizontalPolicy() and + setVerticalPolicy() functions. Use the setHeightForWidth() + function if the preferred height of the widget is dependent on the + width of the widget (for example, a QLabel with line wrapping). + + \sa setHorizontalStretch(), setVerticalStretch() +*/ + +/*! + \fn QSizePolicy::QSizePolicy(Policy horizontal, Policy vertical) + + Constructs a QSizePolicy object with the given \a horizontal and + \a vertical policies, and DefaultType as the control type. + + Use setHeightForWidth() if the preferred height of the widget is + dependent on the width of the widget (for example, a QLabel with + line wrapping). + + \sa setHorizontalStretch(), setVerticalStretch() +*/ + +/*! + \fn QSizePolicy::QSizePolicy(Policy horizontal, Policy vertical, ControlType type) + \since 4.3 + + Constructs a QSizePolicy object with the given \a horizontal and + \a vertical policies, and the specified control \a type. + + Use setHeightForWidth() if the preferred height of the widget is + dependent on the width of the widget (for example, a QLabel with + line wrapping). + + \sa setHorizontalStretch(), setVerticalStretch(), controlType() +*/ + +/*! + \fn QSizePolicy::Policy QSizePolicy::horizontalPolicy() const + + Returns the horizontal component of the size policy. + + \sa setHorizontalPolicy(), verticalPolicy(), horizontalStretch() +*/ + +/*! + \fn QSizePolicy::Policy QSizePolicy::verticalPolicy() const + + Returns the vertical component of the size policy. + + \sa setVerticalPolicy(), horizontalPolicy(), verticalStretch() +*/ + +/*! + \fn void QSizePolicy::setHorizontalPolicy(Policy policy) + + Sets the horizontal component to the given \a policy. + + \sa horizontalPolicy(), setVerticalPolicy(), setHorizontalStretch() +*/ + +/*! + \fn void QSizePolicy::setVerticalPolicy(Policy policy) + + Sets the vertical component to the given \a policy. + + \sa verticalPolicy(), setHorizontalPolicy(), setVerticalStretch() +*/ + +/*! + \fn Qt::Orientations QSizePolicy::expandingDirections() const + + Returns whether a widget can make use of more space than the + QWidget::sizeHint() function indicates. + + A value of Qt::Horizontal or Qt::Vertical means that the widget + can grow horizontally or vertically (i.e., the horizontal or + vertical policy is \l Expanding or \l MinimumExpanding), whereas + Qt::Horizontal | Qt::Vertical means that it can grow in both + dimensions. + + \sa horizontalPolicy(), verticalPolicy() +*/ + +/*! + \fn ControlType QSizePolicy::controlType() const + \since 4.3 + + Returns the control type associated with the widget for which + this size policy applies. +*/ + +/*! + \fn void QSizePolicy::setControlType(ControlType type) + \since 4.3 + + Sets the control type associated with the widget for which this + size policy applies to \a type. + + The control type specifies the type of the widget for which this + size policy applies. It is used by some styles, notably + QMacStyle, to insert proper spacing between widgets. For example, + the Mac OS X Aqua guidelines specify that push buttons should be + separated by 12 pixels, whereas vertically stacked radio buttons + only require 6 pixels. + + \sa QStyle::layoutSpacing() +*/ + +/*! + \fn void QSizePolicy::setHeightForWidth(bool dependent) + + Sets the flag determining whether the widget's preferred height + depends on its width, to \a dependent. + + \sa hasHeightForWidth() +*/ + +/*! + \fn bool QSizePolicy::hasHeightForWidth() const + + Returns true if the widget's preferred height depends on its + width; otherwise returns false. + + \sa setHeightForWidth() +*/ + +/*! + \fn bool QSizePolicy::operator==(const QSizePolicy &other) const + + Returns true if this policy is equal to \a other; otherwise + returns false. + + \sa operator!=() +*/ + +/*! + \fn bool QSizePolicy::operator!=(const QSizePolicy &other) const + + Returns true if this policy is different from \a other; otherwise + returns false. + + \sa operator==() +*/ + +/*! + \fn int QSizePolicy::horizontalStretch() const + + Returns the horizontal stretch factor of the size policy. + + \sa setHorizontalStretch(), verticalStretch(), horizontalPolicy() +*/ + +/*! + \fn int QSizePolicy::verticalStretch() const + + Returns the vertical stretch factor of the size policy. + + \sa setVerticalStretch(), horizontalStretch(), verticalPolicy() +*/ + +/*! + \fn void QSizePolicy::setHorizontalStretch(uchar stretchFactor) + + Sets the horizontal stretch factor of the size policy to the given \a + stretchFactor. + + \sa horizontalStretch(), setVerticalStretch(), setHorizontalPolicy() +*/ + +/*! + \fn void QSizePolicy::setVerticalStretch(uchar stretchFactor) + + Sets the vertical stretch factor of the size policy to the given + \a stretchFactor. + + \sa verticalStretch(), setHorizontalStretch(), setVerticalPolicy() +*/ + +/*! + \fn void QSizePolicy::transpose() + + Swaps the horizontal and vertical policies and stretches. +*/ + +/*! + \enum QSizePolicy::ControlType + \since 4.3 + + This enum specifies the different types of widgets in terms of + layout interaction: + + \value DefaultType The default type, when none is specified. + \value ButtonBox A QDialogButtonBox instance. + \value CheckBox A QCheckBox instance. + \value ComboBox A QComboBox instance. + \value Frame A QFrame instance. + \value GroupBox A QGroupBox instance. + \value Label A QLabel instance. + \value Line A QFrame instance with QFrame::HLine or QFrame::VLine. + \value LineEdit A QLineEdit instance. + \value PushButton A QPushButton instance. + \value RadioButton A QRadioButton instance. + \value Slider A QAbstractSlider instance. + \value SpinBox A QAbstractSpinBox instance. + \value TabWidget A QTabWidget instance. + \value ToolButton A QToolButton instance. + + \sa setControlType(), controlType() +*/ + +#ifdef QT3_SUPPORT +/*! + \typedef QSizePolicy::SizeType + \compat + + Use the QSizePolicy::Policy enum instead. +*/ + +/*! + \enum QSizePolicy::ExpandData + \compat + + Use the Qt::Orientations enum instead. + + \value NoDirection Use 0 instead. + \value Horizontally Use Qt::Horizontal instead. + \value Vertically Use Qt::Vertical instead. + \value BothDirections Use Qt::Horizontal | Qt::Vertical instead. +*/ + +/*! + \fn bool QSizePolicy::mayShrinkHorizontally() const + + Use the horizontalPolicy() function combined with the + QSizePolicy::PolicyFlag enum instead. + + \oldcode + bool policy = mayShrinkHorizontally(); + \newcode + bool policy = horizontalPolicy() & QSizePolicy::ShrinkFlag; + \endcode +*/ + +/*! + \fn bool QSizePolicy::mayShrinkVertically() const + + Use the verticalPolicy() function combined with the + QSizePolicy::PolicyFlag enum instead. + + \oldcode + bool policy = mayShrinkVertically(); + \newcode + bool policy = verticalPolicy() & QSizePolicy::ShrinkFlag; + \endcode +*/ + +/*! + \fn bool QSizePolicy::mayGrowHorizontally() const + + Use the horizontalPolicy() function combined with the + QSizePolicy::PolicyFlag enum instead. + + \oldcode + bool policy = mayGrowHorizontally(); + \newcode + bool policy = horizontalPolicy() & QSizePolicy::GrowFlag; + \endcode +*/ + +/*! + \fn bool QSizePolicy::mayGrowVertically() const + + Use the verticalPolicy() function combined with the + QSizePolicy::PolicyFlag enum instead. + + \oldcode + bool policy = mayGrowVertically(); + \newcode + bool policy = verticalPolicy() & QSizePolicy::GrowFlag; + \endcode +*/ + +/*! + \fn Qt::QSizePolicy::Orientations QSizePolicy::expanding() const + + Use expandingDirections() instead. +*/ + +/*! + \fn QSizePolicy::QSizePolicy(Policy horizontal, Policy vertical, bool dependent) + + Use the QSizePolicy() constructor and the setHeightForWidth() + function instead. + + \oldcode + QSizePolicy *policy = new QSizePolicy(horizontal, vertical, dependent); + \newcode + QSizePolicy *policy = new QSizePolicy(horizontal, vertical); + policy->setHeightForWidth(dependent); + \endcode +*/ + +/*! + \fn QSizePolicy::QSizePolicy(Policy horizontal, Policy vertical, uchar horizontalStretch, + uchar verticalStretch, bool dependent) + + Use the QSizePolicy() constructor and call the + setHorizontalStretch(), setVerticalStretch(), and + setHeightForWidth() functions instead. + + \oldcode + QSizePolicy *policy = new QSizePolicy(horizontal, vertical, + horizontalStretch, verticalStretch, + dependent); + \newcode + QSizePolicy *policy = new QSizePolicy(horizontal, vertical); + policy->setHorizontalStretch(horizontalStretch); + policy->setVerticalStretch(verticalStretch); + policy->setHeightForWidth(dependent); + \endcode +*/ + +/*! + \fn QSizePolicy::Policy QSizePolicy::horData() const + + Use horizontalPolicy() instead. +*/ + +/*! + \fn QSizePolicy::Policy QSizePolicy::verData() const + + Use verticalPolicy() instead. +*/ + +/*! + \fn void QSizePolicy::setHorData(Policy policy) + + Use setHorizontalPolicy() instead. +*/ + +/*! + \fn void QSizePolicy::setVerData(Policy policy) + + Use setVerticalPolicy() instead. +*/ + +/*! + \fn uint QSizePolicy::horStretch() const + + Use horizontalStretch() instead. +*/ + +/*! + \fn uint QSizePolicy::verStretch() const + + Use verticalStretch() instead. +*/ + +/*! + \fn void QSizePolicy::setHorStretch(uchar stretch) + + Use setHorizontalStretch() instead. +*/ + +/*! + \fn void QSizePolicy::setVerStretch(uchar stretch) + + Use setVerticalStretch() instead. +*/ +#endif diff --git a/src/gui/kernel/qsoftkeymanager.cpp b/src/gui/kernel/qsoftkeymanager.cpp new file mode 100644 index 0000000..21795b4 --- /dev/null +++ b/src/gui/kernel/qsoftkeymanager.cpp @@ -0,0 +1,289 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qapplication.h" +#include "qevent.h" +#ifdef Q_WS_S60 +#include "qstyle.h" +#include "private/qt_s60_p.h" +#endif +#include "private/qsoftkeymanager_p.h" +#include "private/qobject_p.h" + +#ifndef QT_NO_SOFTKEYMANAGER +QT_BEGIN_NAMESPACE + +#ifdef Q_WS_S60 +static const int s60CommandStart = 6000; +#endif + +class QSoftKeyManagerPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QSoftKeyManager) + +public: + static void updateSoftKeys_sys(const QList<QAction*> &softKeys); + +private: + QHash<QAction*, Qt::Key> keyedActions; + static QSoftKeyManager *self; + static QWidget *softKeySource; +}; + +QWidget *QSoftKeyManagerPrivate::softKeySource = 0; +QSoftKeyManager *QSoftKeyManagerPrivate::self = 0; + +const char *QSoftKeyManager::standardSoftKeyText(StandardSoftKey standardKey) +{ + const char *softKeyText = 0; + switch (standardKey) { + case OkSoftKey: + softKeyText = QT_TRANSLATE_NOOP("QSoftKeyManager", "Ok"); + break; + case SelectSoftKey: + softKeyText = QT_TRANSLATE_NOOP("QSoftKeyManager", "Select"); + break; + case DoneSoftKey: + softKeyText = QT_TRANSLATE_NOOP("QSoftKeyManager", "Done"); + break; + case MenuSoftKey: + softKeyText = QT_TRANSLATE_NOOP("QSoftKeyManager", "Options"); + break; + case CancelSoftKey: + softKeyText = QT_TRANSLATE_NOOP("QSoftKeyManager", "Cancel"); + break; + default: + break; + }; + + return softKeyText; +} + +QSoftKeyManager *QSoftKeyManager::instance() +{ + if (!QSoftKeyManagerPrivate::self) + QSoftKeyManagerPrivate::self = new QSoftKeyManager; + + return QSoftKeyManagerPrivate::self; +} + +QSoftKeyManager::QSoftKeyManager() : QObject(*(new QSoftKeyManagerPrivate), 0) +{ +} + +QAction *QSoftKeyManager::createAction(StandardSoftKey standardKey, QWidget *actionWidget) +{ + const char* text = standardSoftKeyText(standardKey); + QAction *action = new QAction(QSoftKeyManager::tr(text), actionWidget); + QAction::SoftKeyRole softKeyRole = QAction::NoSoftKey; + switch (standardKey) { + case OkSoftKey: + case SelectSoftKey: + case DoneSoftKey: + case MenuSoftKey: + softKeyRole = QAction::PositiveSoftKey; + break; + case CancelSoftKey: + softKeyRole = QAction::NegativeSoftKey; + break; + } + action->setSoftKeyRole(softKeyRole); + return action; +} + +/*! \internal + + Creates a QAction and registers the 'triggered' signal to send the given key event to + \a actionWidget as a convenience. + +*/ +QAction *QSoftKeyManager::createKeyedAction(StandardSoftKey standardKey, Qt::Key key, QWidget *actionWidget) +{ + QScopedPointer<QAction> action(createAction(standardKey, actionWidget)); + + connect(action.data(), SIGNAL(triggered()), QSoftKeyManager::instance(), SLOT(sendKeyEvent())); + connect(action.data(), SIGNAL(destroyed(QObject*)), QSoftKeyManager::instance(), SLOT(cleanupHash(QObject*))); + QSoftKeyManager::instance()->d_func()->keyedActions.insert(action.data(), key); + return action.take(); +} + +void QSoftKeyManager::cleanupHash(QObject* obj) +{ + Q_D(QSoftKeyManager); + QAction *action = qobject_cast<QAction*>(obj); + d->keyedActions.remove(action); +} + +void QSoftKeyManager::sendKeyEvent() +{ + Q_D(QSoftKeyManager); + QAction *action = qobject_cast<QAction*>(sender()); + + if (!action) + return; + + Qt::Key keyToSend = d->keyedActions.value(action, Qt::Key_unknown); + + if (keyToSend != Qt::Key_unknown) + QApplication::postEvent(action->parentWidget(), + new QKeyEvent(QEvent::KeyPress, keyToSend, Qt::NoModifier)); +} + +void QSoftKeyManager::updateSoftKeys() +{ + QEvent *event = new QEvent(QEvent::UpdateSoftKeys); + QApplication::postEvent(QSoftKeyManager::instance(), event); +} + +bool QSoftKeyManager::event(QEvent *e) +{ + if (e->type() == QEvent::UpdateSoftKeys) { + QList<QAction*> softKeys; + QWidget *source = QApplication::focusWidget(); + do { + if (source) { + QList<QAction*> actions = source->actions(); + for (int i = 0; i < actions.count(); ++i) { + if (actions.at(i)->softKeyRole() != QAction::NoSoftKey) + softKeys.append(actions.at(i)); + } + + QWidget *parent = source->parentWidget(); + if (parent && softKeys.isEmpty()) + source = parent; + else + break; + } else { + source = QApplication::activeWindow(); + } + } while (source); + + QSoftKeyManagerPrivate::softKeySource = source; + if (source) + QSoftKeyManagerPrivate::updateSoftKeys_sys(softKeys); + return true; + } + return false; +} + +#ifdef Q_WS_S60 +void QSoftKeyManagerPrivate::updateSoftKeys_sys(const QList<QAction*> &softkeys) +{ + CEikButtonGroupContainer* nativeContainer = S60->buttonGroupContainer(); + nativeContainer->DrawableWindow()->SetOrdinalPosition(0); + nativeContainer->DrawableWindow()->SetPointerCapturePriority(1); //keep softkeys available in modal dialog + 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 on the LSK + case QAction::PositiveSoftKey: + position = 0; + break; + case QAction::SelectSoftKey: + position = 0; + break; + // Negative Actions on the RSK + case QAction::NegativeSoftKey: + needsExitButton = false; + position = 2; + break; + default: + break; + } + + command = (softKeyAction->objectName().contains("_q_menuSoftKeyAction")) + ? EAknSoftkeyOptions + : s60CommandStart + index; + + if (position != -1) { + const int underlineShortCut = QApplication::style()->styleHint(QStyle::SH_UnderlineShortcut); + QString iconText = softKeyAction->iconText(); + TPtrC text = qt_QString2TPtrC( underlineShortCut ? softKeyAction->text() : iconText); + QT_TRAP_THROWING(nativeContainer->SetCommandL(position, command, text)); + } + } + + Qt::WindowType sourceWindowType = QSoftKeyManagerPrivate::softKeySource->window()->windowType(); + if (needsExitButton && sourceWindowType != Qt::Dialog && sourceWindowType != Qt::Popup) + QT_TRAP_THROWING(nativeContainer->SetCommandL(2, EAknSoftkeyExit, qt_QString2TPtrC(QSoftKeyManager::tr("Exit")))); + + nativeContainer->DrawDeferred(); // 3.1 needs an extra invitation +} + +bool QSoftKeyManager::handleCommand(int command) +{ + if (command >= s60CommandStart && QSoftKeyManagerPrivate::softKeySource) { + int index = command - s60CommandStart; + const QList<QAction*>& softKeys = QSoftKeyManagerPrivate::softKeySource->actions(); + for (int i = 0, j = 0; i < softKeys.count(); ++i) { + QAction *action = softKeys.at(i); + if (action->softKeyRole() != QAction::NoSoftKey) { + if (j == index) { + QWidget *parent = action->parentWidget(); + if (parent && parent->isEnabled()) { + action->activate(QAction::Trigger); + return true; + } + } + j++; + } + } + } + + return false; +} + +#else + +void QSoftKeyManagerPrivate::updateSoftKeys_sys(const QList<QAction*> &) +{ +} + +#endif + +QT_END_NAMESPACE +#endif //QT_NO_SOFTKEYMANAGER diff --git a/src/gui/kernel/qsoftkeymanager_p.h b/src/gui/kernel/qsoftkeymanager_p.h new file mode 100644 index 0000000..796e080 --- /dev/null +++ b/src/gui/kernel/qsoftkeymanager_p.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSOFTKEYMANAGER_P_H +#define QSOFTKEYMANAGER_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 <QtCore/qobject.h> +#include "QtGui/qaction.h" + +QT_BEGIN_HEADER + +#ifndef QT_NO_SOFTKEYMANAGER +QT_BEGIN_NAMESPACE + +class QSoftKeyManagerPrivate; + +class Q_AUTOTEST_EXPORT QSoftKeyManager : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QSoftKeyManager) + +public: + + enum StandardSoftKey { + OkSoftKey, + SelectSoftKey, + DoneSoftKey, + MenuSoftKey, + CancelSoftKey + }; + + static void updateSoftKeys(); + static QAction *createAction(StandardSoftKey standardKey, QWidget *actionWidget); + static QAction *createKeyedAction(StandardSoftKey standardKey, Qt::Key key, QWidget *actionWidget); + +#ifdef Q_WS_S60 + static bool handleCommand(int); +#endif + +private: + QSoftKeyManager(); + static QSoftKeyManager *instance(); + static const char *standardSoftKeyText(StandardSoftKey standardKey); + +protected: + bool event(QEvent *e); + + Q_DISABLE_COPY(QSoftKeyManager) + +private Q_SLOTS: + void cleanupHash(QObject* obj); + void sendKeyEvent(); +}; + +QT_END_NAMESPACE +#endif //QT_NO_SOFTKEYMANAGER + +QT_END_HEADER + +#endif //QSOFTKEYMANAGER_P_H diff --git a/src/gui/kernel/qsound.cpp b/src/gui/kernel/qsound.cpp index 79be107..141439b 100644 --- a/src/gui/kernel/qsound.cpp +++ b/src/gui/kernel/qsound.cpp @@ -106,7 +106,7 @@ public: \brief The QSound class provides access to the platform audio facilities. \ingroup multimedia - \mainclass + Qt provides the most commonly required audio operation in GUI applications: asynchronously playing a sound file. This is most @@ -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_qws.cpp b/src/gui/kernel/qsound_qws.cpp index 7822f72..8595faa 100644 --- a/src/gui/kernel/qsound_qws.cpp +++ b/src/gui/kernel/qsound_qws.cpp @@ -53,16 +53,16 @@ #include "qhash.h" #include "qfileinfo.h" -#ifdef MEDIA_SERVER #include "qbytearray.h" #include "quuid.h" #include "qdatastream.h" #include "qcopchannel_qws.h" #include "qbuffer.h" + QT_BEGIN_NAMESPACE -QT_USE_NAMESPACE +#ifdef MEDIA_SERVER #define SERVER_CHANNEL "QPE/MediaServer" @@ -279,7 +279,7 @@ QAuBucketQWS::QAuBucketQWS( QAuServerQWS *server, QSound *sound, QObject* parent sound->setObjectName( m_id.toString() ); - m_channel = new QCopChannel(QString( QLatin1String("QPE/QSound/") ).append( m_id ), this ); + m_channel = new QCopChannel(QLatin1String("QPE/QSound/") + m_id, this ); connect( m_channel, SIGNAL(received(QString,QByteArray)), this, SLOT(processMessage(QString,QByteArray)) ); diff --git a/src/gui/kernel/qsound_s60.cpp b/src/gui/kernel/qsound_s60.cpp new file mode 100644 index 0000000..e4b7cec --- /dev/null +++ b/src/gui/kernel/qsound_s60.cpp @@ -0,0 +1,224 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $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; } + + void play(const QString& filename); + +protected: + void playCompleted(QAuBucketS60 *bucket, int error); + +protected: + QAuBucketS60 *bucket(QSound *s) + { + return (QAuBucketS60 *)QAuServer::bucket( s ); + } + + friend class QAuBucketS60; + + // static QSound::play(filename) cannot be stopped, meaning that playCompleted + // will get always called and QSound gets removed form this list. + QList<QSound *> staticPlayingSounds; +}; + +QAuServerS60::QAuServerS60(QObject *parent) : + QAuServer(parent) +{ + setObjectName(QLatin1String("QAuServerS60")); +} + +void QAuServerS60::play(const QString& filename) +{ + QSound *s = new QSound(filename); + staticPlayingSounds.append(s); + play(s); +} + +void QAuServerS60::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 { + if (staticPlayingSounds.removeAll(sound)) + delete 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)) {} + if (staticPlayingSounds.removeAll(sound)) + delete sound; + } +} + +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/qsound_win.cpp b/src/gui/kernel/qsound_win.cpp index 15bd19e..5051017 100644 --- a/src/gui/kernel/qsound_win.cpp +++ b/src/gui/kernel/qsound_win.cpp @@ -77,13 +77,8 @@ public: QAuServerWindows::QAuServerWindows(QObject* parent) : QAuServer(parent), current(0) { - QT_WA({ - mutex = CreateMutexW(0, 0, 0); - event = CreateEventW(0, FALSE, FALSE, 0); - } , { - mutex = CreateMutexA(0, 0, 0); - event = CreateEventA(0, FALSE, FALSE, 0); - }); + mutex = CreateMutex(0, 0, 0); + event = CreateEvent(0, FALSE, FALSE, 0); } QAuServerWindows::~QAuServerWindows() @@ -133,13 +128,9 @@ DWORD WINAPI SoundPlayProc(LPVOID param) if (loops == -1) flags |= SND_LOOP; - QT_WA({ - PlaySoundW((TCHAR*)filename.utf16(), 0, flags); - } , { - PlaySoundA(QFile::encodeName(filename).data(), 0, flags); - }); - if (sound && loops == 1) - server->decLoop(sound); + PlaySound((wchar_t*)filename.utf16(), 0, flags); + if (sound && loops == 1) + server->decLoop(sound); // GUI thread continues, but we are done as well. SetEvent(event); @@ -148,18 +139,13 @@ DWORD WINAPI SoundPlayProc(LPVOID param) QPointer<QSound> guarded_sound = sound; SetEvent(event); - for (int l = 0; l < loops && server->current; ++l) { - QT_WA( { - PlaySoundW( (TCHAR*)filename.utf16(), 0, SND_FILENAME|SND_SYNC ); - } , { - PlaySoundA( QFile::encodeName(filename).data(), 0, - SND_FILENAME|SND_SYNC ); - } ); - - if (guarded_sound) - server->decLoop(guarded_sound); - } - server->current = 0; + for (int l = 0; l < loops && server->current; ++l) { + PlaySound((wchar_t*)filename.utf16(), 0, SND_FILENAME | SND_SYNC); + + if (guarded_sound) + server->decLoop(guarded_sound); + } + server->current = 0; } ReleaseMutex(mutex); @@ -169,7 +155,7 @@ DWORD WINAPI SoundPlayProc(LPVOID param) void QAuServerWindows::playHelper(const QString &filename, int loop, QSound *snd) { if (loop == 0) - return; + return; // busy? if (WaitForSingleObject(mutex, 0) == WAIT_TIMEOUT) return; diff --git a/src/gui/kernel/qstackedlayout.cpp b/src/gui/kernel/qstackedlayout.cpp index c7793ef..98f2032 100644 --- a/src/gui/kernel/qstackedlayout.cpp +++ b/src/gui/kernel/qstackedlayout.cpp @@ -65,8 +65,6 @@ public: only one widget is visible at a time. \ingroup geomanagement - \ingroup appearance - \mainclass QStackedLayout can be used to create a user interface similar to the one provided by QTabWidget. There is also a convenience diff --git a/src/gui/kernel/qstandardgestures.cpp b/src/gui/kernel/qstandardgestures.cpp new file mode 100644 index 0000000..dfd49eb --- /dev/null +++ b/src/gui/kernel/qstandardgestures.cpp @@ -0,0 +1,259 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qstandardgestures_p.h" +#include "qgesture.h" +#include "qgesture_p.h" +#include "qevent.h" +#include "qwidget.h" +#include "qabstractscrollarea.h" + +QT_BEGIN_NAMESPACE + +QPanGestureRecognizer::QPanGestureRecognizer() +{ +} + +QGesture *QPanGestureRecognizer::create(QObject *target) +{ + if (target && target->isWidgetType()) { +#if defined(Q_OS_WIN) + // for scroll areas on Windows we want to use native gestures instead + if (!qobject_cast<QAbstractScrollArea *>(target->parent())) + static_cast<QWidget *>(target)->setAttribute(Qt::WA_AcceptTouchEvents); +#else + static_cast<QWidget *>(target)->setAttribute(Qt::WA_AcceptTouchEvents); +#endif + } + return new QPanGesture; +} + +QGestureRecognizer::Result QPanGestureRecognizer::recognize(QGesture *state, QObject *, QEvent *event) +{ + QPanGesture *q = static_cast<QPanGesture *>(state); + QPanGesturePrivate *d = q->d_func(); + + const QTouchEvent *ev = static_cast<const QTouchEvent *>(event); + + QGestureRecognizer::Result result; + + switch (event->type()) { + case QEvent::TouchBegin: { + result = QGestureRecognizer::MayBeGesture; + QTouchEvent::TouchPoint p = ev->touchPoints().at(0); + d->lastOffset = d->offset = QPointF(); + break; + } + case QEvent::TouchEnd: { + if (q->state() != Qt::NoGesture) { + if (ev->touchPoints().size() == 2) { + QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0); + QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1); + d->lastOffset = d->offset; + d->offset = + QPointF(p1.pos().x() - p1.startPos().x() + p2.pos().x() - p2.startPos().x(), + p1.pos().y() - p1.startPos().y() + p2.pos().y() - p2.startPos().y()) / 2; + } + result = QGestureRecognizer::FinishGesture; + } else { + result = QGestureRecognizer::CancelGesture; + } + break; + } + case QEvent::TouchUpdate: { + if (ev->touchPoints().size() >= 2) { + QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0); + QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1); + d->lastOffset = d->offset; + d->offset = + QPointF(p1.pos().x() - p1.startPos().x() + p2.pos().x() - p2.startPos().x(), + p1.pos().y() - p1.startPos().y() + p2.pos().y() - p2.startPos().y()) / 2; + if (d->offset.x() > 10 || d->offset.y() > 10 || + d->offset.x() < -10 || d->offset.y() < -10) { + result = QGestureRecognizer::TriggerGesture; + } else { + result = QGestureRecognizer::MayBeGesture; + } + } + break; + } + case QEvent::MouseButtonPress: + case QEvent::MouseMove: + case QEvent::MouseButtonRelease: + result = QGestureRecognizer::Ignore; + break; + default: + result = QGestureRecognizer::Ignore; + break; + } + return result; +} + +void QPanGestureRecognizer::reset(QGesture *state) +{ + QPanGesture *pan = static_cast<QPanGesture*>(state); + QPanGesturePrivate *d = pan->d_func(); + + d->lastOffset = d->offset = QPointF(); + d->acceleration = 0; + + QGestureRecognizer::reset(state); +} + + +// +// QPinchGestureRecognizer +// + +QPinchGestureRecognizer::QPinchGestureRecognizer() +{ +} + +QGesture *QPinchGestureRecognizer::create(QObject *target) +{ + if (target && target->isWidgetType()) { + static_cast<QWidget *>(target)->setAttribute(Qt::WA_AcceptTouchEvents); + } + return new QPinchGesture; +} + +QGestureRecognizer::Result QPinchGestureRecognizer::recognize(QGesture *state, QObject *, QEvent *event) +{ + QPinchGesture *q = static_cast<QPinchGesture *>(state); + QPinchGesturePrivate *d = q->d_func(); + + const QTouchEvent *ev = static_cast<const QTouchEvent *>(event); + + QGestureRecognizer::Result result; + + switch (event->type()) { + case QEvent::TouchBegin: { + result = QGestureRecognizer::MayBeGesture; + break; + } + case QEvent::TouchEnd: { + if (q->state() != Qt::NoGesture) { + result = QGestureRecognizer::FinishGesture; + } else { + result = QGestureRecognizer::CancelGesture; + } + break; + } + case QEvent::TouchUpdate: { + d->changeFlags = 0; + if (ev->touchPoints().size() == 2) { + QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0); + QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1); + + d->hotSpot = p1.screenPos(); + d->isHotSpotSet = true; + + if (d->isNewSequence) { + d->startPosition[0] = p1.screenPos(); + d->startPosition[1] = p2.screenPos(); + } + QLineF line(p1.screenPos(), p2.screenPos()); + QLineF tmp(line); + tmp.setLength(line.length() / 2.); + QPointF centerPoint = tmp.p2(); + + d->lastCenterPoint = d->centerPoint; + d->centerPoint = centerPoint; + d->changeFlags |= QPinchGesture::CenterPointChanged; + + const qreal scaleFactor = QLineF(p1.pos(), p2.pos()).length() + / QLineF(d->startPosition[0], d->startPosition[1]).length(); + if (d->isNewSequence) { + d->lastScaleFactor = scaleFactor; + } else { + d->lastScaleFactor = d->scaleFactor; + } + d->scaleFactor = scaleFactor; + d->totalScaleFactor += d->scaleFactor - d->lastScaleFactor; + d->changeFlags |= QPinchGesture::ScaleFactorChanged; + + const qreal rotationAngle = -line.angle(); + if (d->isNewSequence) + d->lastRotationAngle = rotationAngle; + else + d->lastRotationAngle = d->rotationAngle; + d->rotationAngle = rotationAngle; + d->totalRotationAngle += d->rotationAngle - d->lastRotationAngle; + d->changeFlags |= QPinchGesture::RotationAngleChanged; + + d->totalChangeFlags |= d->changeFlags; + d->isNewSequence = false; + result = QGestureRecognizer::TriggerGesture; + } else { + d->isNewSequence = true; + result = QGestureRecognizer::MayBeGesture; + } + break; + } + case QEvent::MouseButtonPress: + case QEvent::MouseMove: + case QEvent::MouseButtonRelease: + result = QGestureRecognizer::Ignore; + break; + default: + result = QGestureRecognizer::Ignore; + break; + } + return result; +} + +void QPinchGestureRecognizer::reset(QGesture *state) +{ + QPinchGesture *pinch = static_cast<QPinchGesture *>(state); + QPinchGesturePrivate *d = pinch->d_func(); + + d->totalChangeFlags = d->changeFlags = 0; + + d->startCenterPoint = d->lastCenterPoint = d->centerPoint = QPointF(); + d->totalScaleFactor = d->lastScaleFactor = d->scaleFactor = 0; + d->totalRotationAngle = d->lastRotationAngle = d->rotationAngle = 0; + + d->isNewSequence = true; + + QGestureRecognizer::reset(state); +} + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qstandardgestures_p.h b/src/gui/kernel/qstandardgestures_p.h new file mode 100644 index 0000000..e6f346c --- /dev/null +++ b/src/gui/kernel/qstandardgestures_p.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSTANDARDGESTURES_P_H +#define QSTANDARDGESTURES_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qgesturerecognizer.h" +#include "private/qgesture_p.h" + +QT_BEGIN_NAMESPACE + +class QPanGestureRecognizer : public QGestureRecognizer +{ +public: + QPanGestureRecognizer(); + + QGesture *create(QObject *target); + QGestureRecognizer::Result recognize(QGesture *state, QObject *watched, QEvent *event); + void reset(QGesture *state); +}; + +class QPinchGestureRecognizer : public QGestureRecognizer +{ +public: + QPinchGestureRecognizer(); + + QGesture *create(QObject *target); + + QGestureRecognizer::Result recognize(QGesture *state, QObject *watched, QEvent *event); + void reset(QGesture *state); +}; + +QT_END_NAMESPACE + +#endif // QSTANDARDGESTURES_P_H diff --git a/src/gui/kernel/qt_cocoa_helpers_mac.mm b/src/gui/kernel/qt_cocoa_helpers_mac.mm index 663d4df..c0fb8aa 100644 --- a/src/gui/kernel/qt_cocoa_helpers_mac.mm +++ b/src/gui/kernel/qt_cocoa_helpers_mac.mm @@ -74,9 +74,11 @@ ****************************************************************************/ #include <private/qcore_mac_p.h> +#include <qaction.h> #include <qwidget.h> #include <qdesktopwidget.h> #include <qevent.h> +#include <qpixmapcache.h> #include <private/qevent_p.h> #include <private/qt_cocoa_helpers_mac_p.h> #include <private/qt_mac_p.h> @@ -88,6 +90,52 @@ QT_BEGIN_NAMESPACE +Q_GLOBAL_STATIC(QMacWindowFader, macwindowFader); + +QMacWindowFader::QMacWindowFader() + : m_duration(0.250) +{ +} + +QMacWindowFader *QMacWindowFader::currentFader() +{ + return macwindowFader(); +} + +void QMacWindowFader::registerWindowToFade(QWidget *window) +{ + m_windowsToFade.append(window); +} + +void QMacWindowFader::performFade() +{ + const QWidgetList myWidgetsToFade = m_windowsToFade; + const int widgetCount = myWidgetsToFade.count(); +#if QT_MAC_USE_COCOA + QMacCocoaAutoReleasePool pool; + [NSAnimationContext beginGrouping]; + [[NSAnimationContext currentContext] setDuration:NSTimeInterval(m_duration)]; +#endif + + for (int i = 0; i < widgetCount; ++i) { + QWidget *widget = m_windowsToFade.at(i); + OSWindowRef window = qt_mac_window_for(widget); +#if QT_MAC_USE_COCOA + [[window animator] setAlphaValue:0.0]; + QTimer::singleShot(qRound(m_duration * 1000), widget, SLOT(hide())); +#else + TransitionWindowOptions options = {0, m_duration, 0, 0}; + TransitionWindowWithOptions(window, kWindowFadeTransitionEffect, kWindowHideTransitionAction, + 0, 1, &options); +#endif + } +#if QT_MAC_USE_COCOA + [NSAnimationContext endGrouping]; +#endif + m_duration = 0.250; + m_windowsToFade.clear(); +} + extern bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event); // qapplication.cpp; extern Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum); // qcocoaview.mm extern QWidget * mac_mouse_grabber; @@ -95,29 +143,26 @@ extern QWidget * mac_mouse_grabber; void macWindowFade(void * /*OSWindowRef*/ window, float durationSeconds) { OSWindowRef wnd = static_cast<OSWindowRef>(window); - if( wnd ) { + if (wnd) { + QWidget *widget; #if QT_MAC_USE_COCOA - QMacCocoaAutoReleasePool pool; - [NSAnimationContext beginGrouping]; - [[wnd animator] setAlphaValue:0.0]; - if (durationSeconds > 0) { - [[NSAnimationContext currentContext] setDuration:NSTimeInterval(durationSeconds)]; - } else { - durationSeconds = [[NSAnimationContext currentContext] duration]; - } - [NSAnimationContext endGrouping]; - QTimer::singleShot(qRound(durationSeconds * 1000), [wnd QT_MANGLE_NAMESPACE(qt_qwidget)], SLOT(hide())); + widget = [wnd QT_MANGLE_NAMESPACE(qt_qwidget)]; #else - if (durationSeconds <= 0) - durationSeconds = 0.15; - TransitionWindowOptions options = {0, durationSeconds, 0, 0}; - TransitionWindowWithOptions(wnd, kWindowFadeTransitionEffect, kWindowHideTransitionAction, 0, 1, &options); + const UInt32 kWidgetCreatorQt = kEventClassQt; + enum { + kWidgetPropertyQWidget = 'QWId' //QWidget * + }; + if (GetWindowProperty(static_cast<WindowRef>(window), kWidgetCreatorQt, kWidgetPropertyQWidget, sizeof(widget), 0, &widget) != noErr) + widget = 0; #endif - } + if (widget) { + QMacWindowFader::currentFader()->setFadeDuration(durationSeconds); + QMacWindowFader::currentFader()->registerWindowToFade(widget); + QMacWindowFader::currentFader()->performFade(); + } + } } - - bool macWindowIsTextured( void * /*OSWindowRef*/ window ) { OSWindowRef wnd = static_cast<OSWindowRef>(window); @@ -134,11 +179,10 @@ void macWindowToolbarShow(const QWidget *widget, bool show ) { OSWindowRef wnd = qt_mac_window_for(widget); #if QT_MAC_USE_COCOA - NSToolbar *toolbar = [wnd toolbar]; - if (toolbar) { + if (NSToolbar *toolbar = [wnd toolbar]) { QMacCocoaAutoReleasePool pool; if (show != [toolbar isVisible]) { - [wnd toggleToolbarShown:wnd]; + [toolbar setVisible:show]; } else { // The toolbar may be in sync, but we are not, update our framestrut. qt_widget_private(const_cast<QWidget *>(widget))->updateFrameStrut(); @@ -154,22 +198,21 @@ void macWindowToolbarSet( void * /*OSWindowRef*/ window, void *toolbarRef ) { OSWindowRef wnd = static_cast<OSWindowRef>(window); #if QT_MAC_USE_COCOA - [wnd setToolbar:static_cast<NSToolbar *>(toolbarRef)]; + [wnd setToolbar:static_cast<NSToolbar *>(toolbarRef)]; #else SetWindowToolbar(wnd, static_cast<HIToolbarRef>(toolbarRef)); #endif } -bool macWindowToolbarVisible( void * /*OSWindowRef*/ window ) +bool macWindowToolbarIsVisible( void * /*OSWindowRef*/ window ) { OSWindowRef wnd = static_cast<OSWindowRef>(window); #if QT_MAC_USE_COCOA - NSToolbar *toolbar = [wnd toolbar]; - if (toolbar) + if (NSToolbar *toolbar = [wnd toolbar]) return [toolbar isVisible]; return false; #else - return IsWindowToolbarVisible(wnd); + return IsWindowToolbarVisible(wnd); #endif } @@ -177,12 +220,12 @@ void macWindowSetHasShadow( void * /*OSWindowRef*/ window, bool hasShadow ) { OSWindowRef wnd = static_cast<OSWindowRef>(window); #if QT_MAC_USE_COCOA - [wnd setHasShadow:BOOL(hasShadow)]; + [wnd setHasShadow:BOOL(hasShadow)]; #else - if (hasShadow) - ChangeWindowAttributes(wnd, 0, kWindowNoShadowAttribute); - else - ChangeWindowAttributes(wnd, kWindowNoShadowAttribute, 0); + if (hasShadow) + ChangeWindowAttributes(wnd, 0, kWindowNoShadowAttribute); + else + ChangeWindowAttributes(wnd, kWindowNoShadowAttribute, 0); #endif } @@ -190,9 +233,9 @@ void macWindowFlush(void * /*OSWindowRef*/ window) { OSWindowRef wnd = static_cast<OSWindowRef>(window); #if QT_MAC_USE_COCOA - [wnd flushWindowIfNeeded]; + [wnd flushWindowIfNeeded]; #else - HIWindowFlush(wnd); + HIWindowFlush(wnd); #endif } @@ -309,6 +352,12 @@ Qt::MouseButton qt_mac_get_button(EventMouseButton button) return Qt::NoButton; } +void macSendToolbarChangeEvent(QWidget *widget) +{ + QToolBarChangeEvent ev(!(GetCurrentKeyModifiers() & cmdKey)); + qt_sendSpontaneousEvent(widget, &ev); +} + Q_GLOBAL_STATIC(QMacTabletHash, tablet_hash) QMacTabletHash *qt_mac_tablet_hash() { @@ -827,6 +876,10 @@ bool qt_mac_handleMouseEvent(void * /* NSView * */view, void * /* NSEvent * */ev QWidget *widgetToGetMouse = qwidget; QWidget *popup = qAppInstance()->activePopupWidget(); NSView *tmpView = theView; + if (mac_mouse_grabber && mac_mouse_grabber != widgetToGetMouse) { + widgetToGetMouse = mac_mouse_grabber; + tmpView = qt_mac_nativeview_for(widgetToGetMouse); + } if (popup && popup != qwidget->window()) { widgetToGetMouse = popup; @@ -1020,6 +1073,17 @@ void qt_mac_updateContentBorderMetricts(void * /*OSWindowRef */window, const ::H #endif } +void qt_mac_showBaseLineSeparator(void * /*OSWindowRef */window, bool show) +{ +#if QT_MAC_USE_COCOA + QMacCocoaAutoReleasePool pool; + OSWindowRef theWindow = static_cast<OSWindowRef>(window); + NSToolbar *macToolbar = [theWindow toolbar]; + if (macToolbar) + [macToolbar setShowsBaselineSeparator: show]; +#endif +} + QStringList qt_mac_NSArrayToQStringList(void *nsarray) { QStringList result; @@ -1079,4 +1143,118 @@ CGContextRef qt_mac_graphicsContextFor(QWidget *widget) return context; } +CGFloat qt_mac_get_scalefactor() +{ +#ifndef QT_MAC_USE_COCOA + return HIGetScaleFactor(); +#else + return [[NSScreen mainScreen] userSpaceScaleFactor]; +#endif +} + +QString qt_mac_get_pasteboardString(OSPasteboardRef paste) +{ + QMacCocoaAutoReleasePool pool; + NSPasteboard *pb = nil; + CFStringRef pbname; + if (PasteboardCopyName (paste, &pbname)) { + pb = [NSPasteboard generalPasteboard]; + } else { + pb = [NSPasteboard pasteboardWithName:reinterpret_cast<const NSString *>(pbname)]; + CFRelease (pbname); + } + if (pb) { + NSString *text = [pb stringForType:NSStringPboardType]; + if (text) + return qt_mac_NSStringToQString(text); + } + return QString(); +} + +QPixmap qt_mac_convert_iconref(const IconRef icon, int width, int height) +{ + QPixmap ret(width, height); + ret.fill(QColor(0, 0, 0, 0)); + + CGRect rect = CGRectMake(0, 0, width, height); + + CGContextRef ctx = qt_mac_cg_context(&ret); + CGAffineTransform old_xform = CGContextGetCTM(ctx); + CGContextConcatCTM(ctx, CGAffineTransformInvert(old_xform)); + CGContextConcatCTM(ctx, CGAffineTransformIdentity); + + ::RGBColor b; + b.blue = b.green = b.red = 255*255; + PlotIconRefInContext(ctx, &rect, kAlignNone, kTransformNone, &b, kPlotIconRefNormalFlags, icon); + CGContextRelease(ctx); + return ret; +} + +void qt_mac_constructQIconFromIconRef(const IconRef icon, const IconRef overlayIcon, QIcon *retIcon, QStyle::StandardPixmap standardIcon) +{ + int size = 16; + while (size <= 128) { + + const QString cacheKey = QLatin1String("qt_mac_constructQIconFromIconRef") + QString::number(standardIcon) + QString::number(size); + QPixmap mainIcon; + if (standardIcon >= QStyle::SP_CustomBase) { + mainIcon = qt_mac_convert_iconref(icon, size, size); + } else if (QPixmapCache::find(cacheKey, mainIcon) == false) { + mainIcon = qt_mac_convert_iconref(icon, size, size); + QPixmapCache::insert(cacheKey, mainIcon); + } + + if (overlayIcon) { + int littleSize = size / 2; + QPixmap overlayPix = qt_mac_convert_iconref(overlayIcon, littleSize, littleSize); + QPainter painter(&mainIcon); + painter.drawPixmap(size - littleSize, size - littleSize, overlayPix); + } + + retIcon->addPixmap(mainIcon); + size += size; // 16 -> 32 -> 64 -> 128 + } +} + +void qt_mac_menu_collapseSeparators(void */*NSMenu **/ theMenu, bool collapse) +{ + OSMenuRef menu = static_cast<OSMenuRef>(theMenu); + if (collapse) { + bool previousIsSeparator = true; // setting to true kills all the separators placed at the top. + NSMenuItem *previousItem = nil; + + NSArray *itemArray = [menu itemArray]; + for (unsigned int i = 0; i < [itemArray count]; ++i) { + NSMenuItem *item = reinterpret_cast<NSMenuItem *>([itemArray objectAtIndex:i]); + if ([item isSeparatorItem]) { + [item setHidden:previousIsSeparator]; + } + + if (![item isHidden]) { + previousItem = item; + previousIsSeparator = ([previousItem isSeparatorItem]); + } + } + + // We now need to check the final item since we don't want any separators at the end of the list. + if (previousItem && previousIsSeparator) + [previousItem setHidden:YES]; + } else { + NSArray *itemArray = [menu itemArray]; + for (unsigned int i = 0; i < [itemArray count]; ++i) { + NSMenuItem *item = reinterpret_cast<NSMenuItem *>([itemArray objectAtIndex:i]); + if (QAction *action = reinterpret_cast<QAction *>([item tag])) + [item setHidden:!action->isVisible()]; + } + } +} + +#ifdef QT_MAC_USE_COCOA +void qt_cocoaChangeOverrideCursor(const QCursor &cursor) +{ + QMacCocoaAutoReleasePool pool; + [static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(cursor)) set]; +} +#endif + QT_END_NAMESPACE diff --git a/src/gui/kernel/qt_cocoa_helpers_mac_p.h b/src/gui/kernel/qt_cocoa_helpers_mac_p.h index 3cc4eff..f11ccc5 100644 --- a/src/gui/kernel/qt_cocoa_helpers_mac_p.h +++ b/src/gui/kernel/qt_cocoa_helpers_mac_p.h @@ -116,14 +116,16 @@ typedef struct CGPoint NSPoint; QT_BEGIN_NAMESPACE Qt::MouseButtons qt_mac_get_buttons(int buttons); Qt::MouseButton qt_mac_get_button(EventMouseButton button); -void macWindowFade(void * /*OSWindowRef*/ window, float durationSeconds = 0); +void macWindowFade(void * /*OSWindowRef*/ window, float durationSeconds = 0.15); bool macWindowIsTextured(void * /*OSWindowRef*/ window); void macWindowToolbarShow(const QWidget *widget, bool show ); void macWindowToolbarSet( void * /*OSWindowRef*/ window, void* toolbarRef ); -bool macWindowToolbarVisible( void * /*OSWindowRef*/ window ); +bool macWindowToolbarIsVisible( void * /*OSWindowRef*/ window ); void macWindowSetHasShadow( void * /*OSWindowRef*/ window, bool hasShadow ); void macWindowFlush(void * /*OSWindowRef*/ window); +void macSendToolbarChangeEvent(QWidget *widget); void qt_mac_updateContentBorderMetricts(void * /*OSWindowRef */window, const ::HIContentBorderMetrics &metrics); +void qt_mac_showBaseLineSeparator(void * /*OSWindowRef */window, bool show); void * /*NSImage */qt_mac_create_nsimage(const QPixmap &pm); void qt_mac_update_mouseTracking(QWidget *widget); OSStatus qt_mac_drawCGImage(CGContextRef cg, const CGRect *inbounds, CGImageRef); @@ -131,7 +133,9 @@ bool qt_mac_checkForNativeSizeGrip(const QWidget *widget); void qt_dispatchTabletProximityEvent(void * /*NSEvent * */ tabletEvent); #ifdef QT_MAC_USE_COCOA bool qt_dispatchKeyEventWithCocoa(void * /*NSEvent * */ keyEvent, QWidget *widgetToGetEvent); +void qt_cocoaChangeOverrideCursor(const QCursor &cursor); #endif +void qt_mac_menu_collapseSeparators(void * /*NSMenu */ menu, bool collapse); bool qt_dispatchKeyEvent(void * /*NSEvent * */ keyEvent, QWidget *widgetToGetEvent); void qt_dispatchModifiersChanged(void * /*NSEvent * */flagsChangedEvent, QWidget *widgetToGetEvent); void qt_mac_dispatchNCMouseMessage(void */* NSWindow* */eventWindow, void */* NSEvent* */mouseEvent, @@ -143,6 +147,9 @@ struct ::TabletProximityRec; void qt_dispatchTabletProximityEvent(const ::TabletProximityRec &proxRec); Qt::KeyboardModifiers qt_cocoaModifiers2QtModifiers(ulong modifierFlags); Qt::KeyboardModifiers qt_cocoaDragOperation2QtModifiers(uint dragOperations); +QPixmap qt_mac_convert_iconref(const IconRef icon, int width, int height); +void qt_mac_constructQIconFromIconRef(const IconRef icon, const IconRef overlayIcon, QIcon *retIcon, + QStyle::StandardPixmap standardIcon = QStyle::SP_CustomBase); inline int flipYCoordinate(int y) { return QApplication::desktop()->screenGeometry(0).height() - y; @@ -162,6 +169,9 @@ void *qt_mac_QStringListToNSMutableArrayVoid(const QStringList &list); void qt_syncCocoaTitleBarButtons(OSWindowRef window, QWidget *widgetForWindow); +CGFloat qt_mac_get_scalefactor(); +QString qt_mac_get_pasteboardString(OSPasteboardRef paste); + #ifdef __OBJC__ inline NSMutableArray *qt_mac_QStringListToNSMutableArray(const QStringList &qstrlist) { return reinterpret_cast<NSMutableArray *>(qt_mac_QStringListToNSMutableArrayVoid(qstrlist)); } diff --git a/src/gui/kernel/qt_mac_p.h b/src/gui/kernel/qt_mac_p.h index 992dab5..a28cfa3 100644 --- a/src/gui/kernel/qt_mac_p.h +++ b/src/gui/kernel/qt_mac_p.h @@ -120,6 +120,21 @@ public: } }; +// Class for chaining to gether a bunch of fades. It pretty much is only used for qmenu fading. +class QMacWindowFader +{ + QWidgetList m_windowsToFade; + float m_duration; + Q_DISABLE_COPY(QMacWindowFader) +public: + QMacWindowFader(); // PLEASE DON'T CALL THIS. + static QMacWindowFader *currentFader(); + void registerWindowToFade(QWidget *window); + void setFadeDuration(float durationInSecs) { m_duration = durationInSecs; } + float fadeDuration() const { return m_duration; } + void performFade(); +}; + class Q_GUI_EXPORT QMacCocoaAutoReleasePool { private: diff --git a/src/gui/kernel/qt_s60_p.h b/src/gui/kernel/qt_s60_p.h new file mode 100644 index 0000000..789d89e --- /dev/null +++ b/src/gui/kernel/qt_s60_p.h @@ -0,0 +1,331 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $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 "qapplication.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 events seems to start with 0x10 +const TInt KInternalStatusPaneChange = 0x50000000; + +//this macro exists because EColor16MAP enum value doesn't exist in Symbian OS 9.2 +#define Q_SYMBIAN_ECOLOR16MAP TDisplayMode(13) + +class QS60Data +{ +public: + QS60Data(); + 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; + WId curWin; + int virtualMouseLastKey; + int virtualMouseAccel; + int virtualMouseMaxAccel; +#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS + int brokenPointerCursors : 1; +#endif + int hasTouchscreen : 1; + int mouseInteractionEnabled : 1; + int virtualMouseRequired : 1; + int qtOwnsS60Environment : 1; + int supportsPremultipliedAlpha : 1; + QApplication::QS60MainApplicationFactory s60ApplicationFactory; // typedef'ed pointer type + 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(); + + TTrapHandler *s60InstalledTrapHandler; +#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 isWindowOwning = 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(); + + void setFocusSafely(bool focus); + +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 ); +#ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER + void translateAdvancedPointerEvent(const TAdvancedPointerEvent *event); +#endif + +private: + static QSymbianControl *lastFocusedControl; + +private: + QWidget *qwidget; + bool m_ignoreFocusChanged; + QLongTapTimer* m_longTapDetector; + bool m_previousEventLongTap; +}; + +inline QS60Data::QS60Data() +{ + memclr(this, sizeof(QS60Data)); //zero init data +} + +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; + + S60->virtualMouseMaxAccel = qMax(S60->screenHeightInPixels, S60->screenWidthInPixels) / 20; + + 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_RGB888; + break; + case EColor16MU: + format = QImage::Format_RGB32; + break; + case EColor16MA: + format = QImage::Format_ARGB32; + break; + case Q_SYMBIAN_ECOLOR16MAP: + format = QImage::Format_ARGB32_Premultiplied; + break; + default: + format = QImage::Format_Invalid; + break; + } + return format; +} + +#ifndef QT_NO_CURSOR +void qt_symbian_setWindowCursor(const QCursor &cursor, const CCoeControl* wid); +void qt_symbian_setWindowGroupCursor(const QCursor &cursor, RWindowTreeNode &node); +void qt_symbian_setGlobalCursor(const QCursor &cursor); +void qt_symbian_set_cursor_visible(bool visible); +bool qt_symbian_is_cursor_visible(); +#endif + +QT_END_NAMESPACE + +#endif // QT_S60_P_H diff --git a/src/gui/kernel/qt_x11_p.h b/src/gui/kernel/qt_x11_p.h index 8676c49..9f08dc6 100644 --- a/src/gui/kernel/qt_x11_p.h +++ b/src/gui/kernel/qt_x11_p.h @@ -74,11 +74,19 @@ #include <X11/Xutil.h> #include <X11/Xos.h> #ifdef index -# undef index +# undef index #endif #ifdef rindex -# undef rindex +# undef rindex #endif +#ifdef Q_OS_VXWORS +# ifdef open +# undef open +# endif +# ifdef getpid +# undef getpid +# endif +#endif // Q_OS_VXWORKS #include <X11/Xatom.h> //#define QT_NO_SHAPE @@ -154,6 +162,10 @@ extern "C" { # include <X11/extensions/Xrender.h> #endif // QT_NO_XRENDER +#ifndef QT_NO_XSYNC +# include "X11/extensions/sync.h" +#endif + // #define QT_NO_XKB #ifndef QT_NO_XKB # include <X11/XKBlib.h> @@ -416,6 +428,7 @@ struct QX11Data // true if Qt is compiled w/ MIT-SHM support and MIT-SHM is supported on the connected Display bool use_mitshm; + bool use_mitshm_pixmaps; int mitshm_major; // true if Qt is compiled w/ Tablet support and we have a tablet. @@ -502,9 +515,9 @@ struct QX11Data int fc_hint_style; char *startupId; - char *originalStartupId; - DesktopEnvironment desktopEnvironment; + DesktopEnvironment desktopEnvironment : 8; + uint desktopVersion : 8; /* Used only for KDE */ /* Warning: if you modify this list, modify the names of atoms in qapplication_x11.cpp as well! */ enum X11Atom { @@ -514,6 +527,8 @@ struct QX11Data WM_TAKE_FOCUS, _NET_WM_PING, _NET_WM_CONTEXT_HELP, + _NET_WM_SYNC_REQUEST, + _NET_WM_SYNC_REQUEST_COUNTER, // ICCCM window state WM_STATE, @@ -530,10 +545,12 @@ struct QX11Data TARGETS, MULTIPLE, TIMESTAMP, + SAVE_TARGETS, CLIP_TEMPORARY, _QT_SELECTION, _QT_CLIPBOARD_SENTINEL, _QT_SELECTION_SENTINEL, + CLIPBOARD_MANAGER, RESOURCE_MANAGER, @@ -652,6 +669,10 @@ struct QX11Data _XEMBED, _XEMBED_INFO, + XWacomStylus, + XWacomCursor, + XWacomEraser, + NPredefinedAtoms, _QT_SETTINGS_TIMESTAMP = NPredefinedAtoms, diff --git a/src/gui/kernel/qtooltip.cpp b/src/gui/kernel/qtooltip.cpp index 212a786..4261808 100644 --- a/src/gui/kernel/qtooltip.cpp +++ b/src/gui/kernel/qtooltip.cpp @@ -73,7 +73,7 @@ QT_BEGIN_NAMESPACE widget. \ingroup helpsystem - \mainclass + The tip is a short piece of text reminding the user of the widget's function. It is drawn immediately below the given @@ -126,14 +126,15 @@ public: bool eventFilter(QObject *, QEvent *); - QBasicTimer hideTimer; + QBasicTimer hideTimer, expireTimer; + bool fadingOut; void reuseTip(const QString &text); void hideTip(); void hideTipImmediately(); void setTipRect(QWidget *w, const QRect &r); - void restartHideTimer(); + void restartExpireTimer(); bool tipChanged(const QPoint &pos, const QString &text, QObject *o); void placeTip(const QPoint &pos, QWidget *w); @@ -182,7 +183,6 @@ QTipLabel::QTipLabel(const QString &text, QWidget *w) setFrameStyle(QFrame::NoFrame); setAlignment(Qt::AlignLeft); setIndent(1); - setWordWrap(Qt::mightBeRichText(text)); qApp->installEventFilter(this); setWindowOpacity(style()->styleHint(QStyle::SH_ToolTipLabel_Opacity, 0, this) / 255.0); setMouseTracking(true); @@ -190,22 +190,24 @@ QTipLabel::QTipLabel(const QString &text, QWidget *w) reuseTip(text); } -void QTipLabel::restartHideTimer() +void QTipLabel::restartExpireTimer() { int time = 10000 + 40 * qMax(0, text().length()-100); - hideTimer.start(time, this); + expireTimer.start(time, this); + hideTimer.stop(); } void QTipLabel::reuseTip(const QString &text) { #ifndef QT_NO_STYLE_STYLESHEET - if (styleSheetParent) { + if (styleSheetParent){ disconnect(styleSheetParent, SIGNAL(destroyed()), QTipLabel::instance, SLOT(styleSheetParentDestroyed())); styleSheetParent = 0; } #endif + setWordWrap(Qt::mightBeRichText(text)); setText(text); QFontMetrics fm(font()); QSize extra(1, 0); @@ -213,7 +215,7 @@ void QTipLabel::reuseTip(const QString &text) if (fm.descent() == 2 && fm.ascent() >= 11) ++extra.rheight(); resize(sizeHint() + extra); - restartHideTimer(); + restartExpireTimer(); } void QTipLabel::paintEvent(QPaintEvent *ev) @@ -257,7 +259,8 @@ QTipLabel::~QTipLabel() void QTipLabel::hideTip() { - hideTimer.start(300, this); + if (!hideTimer.isActive()) + hideTimer.start(300, this); } void QTipLabel::hideTipImmediately() @@ -278,15 +281,17 @@ void QTipLabel::setTipRect(QWidget *w, const QRect &r) void QTipLabel::timerEvent(QTimerEvent *e) { - if (e->timerId() == hideTimer.timerId()){ + if (e->timerId() == hideTimer.timerId() + || e->timerId() == expireTimer.timerId()){ hideTimer.stop(); + expireTimer.stop(); #if defined(Q_WS_MAC) && !defined(QT_NO_EFFECTS) if (QApplication::isEffectEnabled(Qt::UI_FadeTooltip)){ // Fade out tip on mac (makes it invisible). // The tip will not be deleted until a new tip is shown. - // DRSWAT - Cocoa - macWindowFade(qt_mac_window_for(this)); + // DRSWAT - Cocoa + macWindowFade(qt_mac_window_for(this)); QTipLabel::instance->fadingOut = true; // will never be false again. } else @@ -426,7 +431,7 @@ bool QTipLabel::tipChanged(const QPoint &pos, const QString &text, QObject *o) void QToolTip::showText(const QPoint &pos, const QString &text, QWidget *w, const QRect &rect) { - if (QTipLabel::instance){ // a tip does already exist + if (QTipLabel::instance && QTipLabel::instance->isVisible()){ // a tip does already exist if (text.isEmpty()){ // empty text means hide current tip QTipLabel::instance->hideTip(); return; diff --git a/src/gui/kernel/qwhatsthis.cpp b/src/gui/kernel/qwhatsthis.cpp index ebfd9dd..0da3a9b 100644 --- a/src/gui/kernel/qwhatsthis.cpp +++ b/src/gui/kernel/qwhatsthis.cpp @@ -78,7 +78,7 @@ QT_BEGIN_NAMESPACE widget, i.e. answering the question "What's This?". \ingroup helpsystem - \mainclass + "What's This?" help is part of an application's online help system, and provides users with information about the @@ -194,9 +194,9 @@ QWhatsThat::QWhatsThat(const QString& txt, QWidget* parent, QWidget *showTextFor #ifndef QT_NO_CURSOR setCursor(Qt::ArrowCursor); #endif - QRect r; doc = 0; + ensurePolished(); // Ensures style sheet font before size calc if (Qt::mightBeRichText(text)) { doc = new QTextDocument(); doc->setUndoRedoEnabled(false); @@ -226,7 +226,9 @@ QWhatsThat::QWhatsThat(const QString& txt, QWidget* parent, QWidget *showTextFor text); } #if defined(Q_WS_WIN) - if ((QSysInfo::WindowsVersion&QSysInfo::WV_NT_based) > QSysInfo::WV_2000) { + if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP + && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)) + { BOOL shadow; SystemParametersInfo(SPI_GETDROPSHADOW, 0, &shadow, 0); shadowWidth = shadow ? 0 : 6; @@ -302,7 +304,9 @@ void QWhatsThat::paintEvent(QPaintEvent*) { bool drawShadow = true; #if defined(Q_WS_WIN) - if ((QSysInfo::WindowsVersion&QSysInfo::WV_NT_based) > QSysInfo::WV_2000) { + if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP + && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)) + { BOOL shadow; SystemParametersInfo(SPI_GETDROPSHADOW, 0, &shadow, 0); drawShadow = !shadow; @@ -347,6 +351,7 @@ void QWhatsThat::paintEvent(QPaintEvent*) rect.translate(-r.x(), -r.y()); p.setClipRect(rect); QAbstractTextDocumentLayout::PaintContext context; + context.palette.setBrush(QPalette::Text, context.palette.toolTipText()); doc->documentLayout()->draw(&p, context); } else diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index 85c1955..6a72cfa 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -82,6 +82,7 @@ #include "private/qstyle_p.h" #include "private/qinputcontext_p.h" #include "qfileinfo.h" +#include "private/qsoftkeymanager_p.h" #if defined (Q_WS_WIN) # include <private/qwininputcontext_p.h> @@ -92,6 +93,7 @@ # include "qx11info_x11.h" #endif +#include <private/qgraphicseffect_p.h> #include <private/qwindowsurface_p.h> #include <private/qbackingstore_p.h> #ifdef Q_WS_MAC @@ -99,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" @@ -107,8 +113,10 @@ #include "private/qgraphicsproxywidget_p.h" #include "QtGui/qabstractscrollarea.h" #include "private/qabstractscrollarea_p.h" +#include "private/qevent_p.h" #include "private/qgraphicssystem_p.h" +#include "private/qgesturemanager_p.h" // widget/widget data creation count //#define QWIDGET_EXTRA_DEBUG @@ -142,24 +150,6 @@ static inline bool hasBackingStoreSupport() #endif } -/*! - \internal - - Returns true if \a p or any of its parents enable the - Qt::BypassGraphicsProxyWidget window flag. Used in QWidget::show() and - QWidget::setParent() to determine whether it's necessary to embed the - widget into a QGraphicsProxyWidget or not. -*/ -static inline bool bypassGraphicsProxyWidget(QWidget *p) -{ - while (p) { - if (p->windowFlags() & Qt::BypassGraphicsProxyWidget) - return true; - p = p->parentWidget(); - } - return false; -} - #ifdef Q_WS_MAC # define QT_NO_PAINT_DEBUG #endif @@ -167,39 +157,53 @@ static inline bool bypassGraphicsProxyWidget(QWidget *p) extern bool qt_sendSpontaneousEvent(QObject*, QEvent*); // qapplication.cpp extern QDesktopWidget *qt_desktopWidget; // qapplication.cpp -QWidgetPrivate::QWidgetPrivate(int version) : - QObjectPrivate(version), extra(0), focus_child(0) - ,layout(0), widgetItem(0) - ,leftmargin(0), topmargin(0), rightmargin(0), bottommargin(0) - ,leftLayoutItemMargin(0), topLayoutItemMargin(0), rightLayoutItemMargin(0) - ,bottomLayoutItemMargin(0) - ,fg_role(QPalette::NoRole) - ,bg_role(QPalette::NoRole) - ,hd(0) - ,dirty(0) - ,needsFlush(0) - ,dirtyOpaqueChildren(1) - ,isOpaque(0) - ,inDirtyList(0) - ,isScrolled(0) - ,isMoved(0) - ,usesDoubleBufferedGLContext(0) -#ifdef Q_WS_WIN - ,noPaintOnScreen(0) -#endif - ,inheritedFontResolveMask(0) - ,inheritedPaletteResolveMask(0) +QWidgetPrivate::QWidgetPrivate(int version) + : QObjectPrivate(version) + , extra(0) + , focus_next(0) + , focus_prev(0) + , focus_child(0) + , layout(0) + , needsFlush(0) + , redirectDev(0) + , widgetItem(0) + , extraPaintEngine(0) + , polished(0) + , graphicsEffect(0) +#if !defined(QT_NO_IM) + , imHints(Qt::ImhNone) +#endif + , inheritedFontResolveMask(0) + , inheritedPaletteResolveMask(0) + , leftmargin(0) + , topmargin(0) + , rightmargin(0) + , bottommargin(0) + , leftLayoutItemMargin(0) + , topLayoutItemMargin(0) + , rightLayoutItemMargin(0) + , bottomLayoutItemMargin(0) + , hd(0) + , size_policy(QSizePolicy::Preferred, QSizePolicy::Preferred) + , fg_role(QPalette::NoRole) + , bg_role(QPalette::NoRole) + , dirtyOpaqueChildren(1) + , isOpaque(0) + , inDirtyList(0) + , isScrolled(0) + , isMoved(0) + , usesDoubleBufferedGLContext(0) #if defined(Q_WS_X11) - ,picture(0) -#endif -#ifdef Q_WS_MAC - ,needWindowChange(0) - ,isGLWidget(0) + , picture(0) +#elif defined(Q_WS_WIN) + , noPaintOnScreen(0) + , nativeGesturePanEnabled(0) +#elif defined(Q_WS_MAC) + , needWindowChange(0) + , isGLWidget(0) + , window_event(0) + , qd_hd(0) #endif - ,polished(0) - - , size_policy(QSizePolicy::Preferred, QSizePolicy::Preferred) - , redirectDev(0) { if (!qApp) { qFatal("QWidget: Must construct a QApplication before a QPaintDevice"); @@ -225,6 +229,8 @@ QWidgetPrivate::~QWidgetPrivate() if (extra) deleteExtra(); + + delete graphicsEffect; } QWindowSurface *QWidgetPrivate::createDefaultWindowSurface() @@ -442,7 +448,7 @@ void QWidget::setAutoFillBackground(bool enabled) \brief The QWidget class is the base class of all user interface objects. \ingroup basicwidgets - \mainclass + The widget is the atom of the user interface: it receives mouse, keyboard and other events from the window system, and paints a representation of @@ -493,7 +499,7 @@ void QWidget::setAutoFillBackground(bool enabled) been outlined to indicate their full sizes. If you want to use a QWidget to hold child widgets you will usually want to - add a layout to the parent QWidget. See \l{Layout Classes} for more + add a layout to the parent QWidget. See \l{Layout Management} for more information. @@ -851,8 +857,8 @@ void QWidget::setAutoFillBackground(bool enabled) \list \o X11: This feature relies on the use of an X server that supports ARGB visuals and a compositing window manager. - \o Windows: This feature requires Windows 2000 or later. The widget needs to have - the Qt::FramelessWindowHint window flag set for the translucency to work. + \o Windows: The widget needs to have the Qt::FramelessWindowHint window flag set + for the translucency to work. \endlist @@ -878,10 +884,35 @@ void QWidget::setAutoFillBackground(bool enabled) \endlist \sa QEvent, QPainter, QGridLayout, QBoxLayout + + \section1 Softkeys + + Since Qt 4.6, Softkeys are usually physical keys on a device that have a corresponding label or + other visual representation on the screen that is generally located next to its + physical counterpart. They are most often found on mobile phone platforms. In + modern touch based user interfaces it is also possible to have softkeys that do + not correspond to any physical keys. Softkeys differ from other onscreen labels + in that they are contextual. + + In Qt, contextual softkeys are added to a widget by calling addAction() and + passing a \c QAction with a softkey role set on it. When the widget + containing the softkey actions has focus, its softkeys should appear in + the user interface. Softkeys are discovered by traversing the widget + heirarchy so it is possible to define a single set of softkeys that are + present at all times by calling addAction() for a given top level widget. + + On some platforms, this concept overlaps with \c QMenuBar such that if no + other softkeys are found and the top level widget is a QMainWindow containing + a QMenuBar, the menubar actions may appear on one of the softkeys. + + Note: Currently softkeys are only supported on the Symbian Platform. + + \sa addAction(), QAction, QMenuBar + */ -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 /***************************************************************************** @@ -921,6 +952,26 @@ 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) + { +#ifdef QT_NO_EXCEPTIONS + Q_UNUSED(that); + Q_UNUSED(d); +#else + 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. @@ -950,7 +1001,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 @@ -961,8 +1017,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 @@ -971,7 +1032,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; + } } /*! @@ -1027,7 +1094,7 @@ void QWidgetPrivate::adjustFlags(Qt::WindowFlags &flags, QWidget *w) if (customize) ; // don't modify window flags if the user explicitely set them. else if (type == Qt::Dialog || type == Qt::Sheet) -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowContextHelpButtonHint | Qt::WindowCloseButtonHint; #else flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint; @@ -1043,11 +1110,11 @@ void QWidgetPrivate::adjustFlags(Qt::WindowFlags &flags, QWidget *w) void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f) { Q_Q(QWidget); - if (qApp->type() == QApplication::Tty) + 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) { @@ -1058,7 +1125,7 @@ void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f) q->data = &data; #ifndef QT_NO_THREAD - if (!q->parent()) { + if (!parent) { Q_ASSERT_X(q->thread() == qApp->thread(), "QWidget", "Widgets must be created in the GUI thread."); } @@ -1094,10 +1161,6 @@ void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f) if (f & Qt::MSWindowsOwnDC) q->setAttribute(Qt::WA_NativeWindow); -#ifdef Q_OS_WINCE - data.window_state_internal = 0; -#endif - q->setAttribute(Qt::WA_QuitOnClose); // might be cleared in adjustQuitOnCloseAttribute() adjustQuitOnCloseAttribute(); @@ -1253,7 +1316,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; @@ -1276,6 +1339,8 @@ void QWidget::create(WId window, bool initializeWindow, bool destroyOldWindow) d->setWindowIcon_sys(true); if (isWindow() && !d->topData()->iconText.isEmpty()) d->setWindowIconText_helper(d->topData()->iconText); + if (isWindow() && !d->topData()->caption.isEmpty()) + d->setWindowTitle_helper(d->topData()->caption); if (windowType() != Qt::Desktop) { d->updateSystemBackground(); @@ -1336,20 +1401,40 @@ QWidget::~QWidget() #ifdef QT3_SUPPORT if (QApplicationPrivate::main_widget == this) { // reset main widget QApplicationPrivate::main_widget = 0; - qApp->quit(); + QApplication::quit(); } #endif - clearFocus(); + QT_TRY { + clearFocus(); + } QT_CATCH(...) { + // swallow this problem because we are in a destructor + } d->setDirtyOpaqueRegion(); - if (isWindow() && isVisible() && internalWinId()) - hide(); -#if defined(Q_WS_WIN) || defined(Q_WS_X11) - else if (!internalWinId() && isVisible()) + 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) || defined (Q_WS_QWS) + else if (!internalWinId() && isVisible()) { + qApp->d_func()->sendSyntheticEnterLeave(this); +#ifdef Q_WS_QWS + } else if (isVisible()) { qApp->d_func()->sendSyntheticEnterLeave(this); #endif + } +#endif if (QWidgetBackingStore *bs = d->maybeBackingStore()) { bs->removeDirtyWidget(this); @@ -1363,17 +1448,25 @@ QWidget::~QWidget() // set all QPointers for this object to zero QObjectPrivate::clearGuards(this); + if (d->declarativeData) { + d->declarativeData->destroyed(this); + d->declarativeData = 0; // don't activate again in ~QObject + } + if (!d->children.isEmpty()) d->deleteChildren(); 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); @@ -1393,16 +1486,26 @@ 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); } + const WId oldWinId = data.winid; + data.winid = id; #if defined(Q_WS_X11) hd = id; // X11: hd == ident #endif if (mapper && id && !userDesktopWidget) { mapper->insert(data.winid, q); - uncreatedWidgets->remove(q); + } + + if(oldWinId != id) { + // Do not emit an event when the old winId is destroyed. This only + // happens (a) during widget destruction, and (b) immediately prior + // to creation of a new winId, for example as a result of re-parenting. + if(id != 0) { + QEvent e(QEvent::WinIdChange); + QCoreApplication::sendEvent(q, &e); + } } } @@ -1412,36 +1515,26 @@ void QWidgetPrivate::createTLExtra() createExtra(); if (!extra->topextra) { QTLWExtra* x = extra->topextra = new QTLWExtra; + x->icon = 0; + x->iconPixmap = 0; + x->backingStore = 0; x->windowSurface = 0; + x->sharedPainter = 0; + x->incw = x->inch = 0; + x->basew = x->baseh = 0; + x->frameStrut.setCoords(0, 0, 0, 0); + x->normalGeometry = QRect(0,0,-1,-1); + x->savedFlags = 0; x->opacity = 255; x->posFromMove = false; x->sizeAdjusted = false; x->inTopLevelResize = false; x->inRepaint = false; - x->backingStore = 0; - x->icon = 0; - x->iconPixmap = 0; - x->frameStrut.setCoords(0, 0, 0, 0); - x->incw = x->inch = 0; - x->basew = x->baseh = 0; - x->normalGeometry = QRect(0,0,-1,-1); -#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined(Q_WS_MAC) x->embedded = 0; -#endif -#if defined(Q_WS_X11) - x->parentWinId = 0; - x->spont_unmapped = 0; - x->dnd = 0; -#endif - x->savedFlags = 0; -#if defined(Q_WS_QWS) && !defined(QT_NO_QWS_MANAGER) - x->qwsManager = 0; -#endif - x->sharedPainter = 0; createTLSysExtra(); #ifdef QWIDGET_EXTRA_DEBUG - static int count = 0; - qDebug() << "tlextra" << ++count; + static int count = 0; + qDebug() << "tlextra" << ++count; #endif } } @@ -1455,27 +1548,30 @@ void QWidgetPrivate::createExtra() { if (!extra) { // if not exists extra = new QWExtra; - extra->minw = extra->minh = 0; - extra->maxw = extra->maxh = QWIDGETSIZE_MAX; + extra->glContext = 0; + extra->topextra = 0; +#ifndef QT_NO_GRAPHICSVIEW + extra->proxyWidget = 0; +#endif +#ifndef QT_NO_CURSOR + extra->curs = 0; +#endif + extra->minw = 0; + extra->minh = 0; + extra->maxw = QWIDGETSIZE_MAX; + extra->maxh = QWIDGETSIZE_MAX; + extra->customDpiX = 0; + extra->customDpiY = 0; extra->explicitMinSize = 0; extra->explicitMaxSize = 0; extra->autoFillBackground = 0; extra->nativeChildrenForced = 0; extra->inRenderWithPainter = 0; extra->hasMask = 0; -#ifndef QT_NO_CURSOR - extra->curs = 0; -#endif - extra->style = 0; - extra->topextra = 0; - extra->proxyWidget = 0; - extra->glContext = 0; - extra->customDpiX = 0; - extra->customDpiY = 0; createSysExtra(); #ifdef QWIDGET_EXTRA_DEBUG - static int count = 0; - qDebug() << "extra" << ++count; + static int count = 0; + qDebug() << "extra" << ++count; #endif } } @@ -1516,45 +1612,6 @@ void QWidgetPrivate::deleteExtra() } /* - Returns true if the background is inherited; otherwise returns - false. - - Mainly used in the paintOnScreen case. -*/ - -bool QWidgetPrivate::isBackgroundInherited() const -{ - Q_Q(const QWidget); - - // windows do not inherit their background - if (q->isWindow() || q->windowType() == Qt::SubWindow) - return false; - - if (q->testAttribute(Qt::WA_NoSystemBackground) || q->testAttribute(Qt::WA_OpaquePaintEvent)) - return false; - - const QPalette &pal = q->palette(); - QPalette::ColorRole bg = q->backgroundRole(); - QBrush brush = pal.brush(bg); - - // non opaque brushes leaves us no choice, we must inherit - if (!q->autoFillBackground() || !brush.isOpaque()) - return true; - - if (brush.style() == Qt::SolidPattern) { - // the background is just a solid color. If there is no - // propagated contents, then we claim as performance - // optimization that it was not inheritet. This is the normal - // case in standard Windows or Motif style. - const QWidget *w = q->parentWidget(); - if (!w->d_func()->isBackgroundInherited()) - return false; - } - - return true; -} - -/* Returns true if there are widgets above this which overlap with \a rect, which is in parent's coordinate system (same as crect). */ @@ -1579,9 +1636,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; } @@ -1645,12 +1702,13 @@ void QWidgetPrivate::propagatePaletteChange() { Q_Q(QWidget); // Propagate a new inherited mask to all children. - if (!q->parentWidget() && extra && extra->proxyWidget) { #ifndef QT_NO_GRAPHICSVIEW + if (!q->parentWidget() && extra && extra->proxyWidget) { QGraphicsProxyWidget *p = extra->proxyWidget; inheritedPaletteResolveMask = p->d_func()->inheritedPaletteResolveMask | p->palette().resolve(); + } else #endif //QT_NO_GRAPHICSVIEW - } else if (q->isWindow() && !q->testAttribute(Qt::WA_WindowPropagation)) { + if (q->isWindow() && !q->testAttribute(Qt::WA_WindowPropagation)) { inheritedPaletteResolveMask = 0; } int mask = data.pal.resolve() | inheritedPaletteResolveMask; @@ -1680,7 +1738,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 @@ -1735,12 +1793,29 @@ QRegion QWidgetPrivate::clipRegion() const return r; } +void QWidgetPrivate::invalidateGraphicsEffectsRecursively() +{ + Q_Q(QWidget); + QWidget *w = q; + do { + if (w->graphicsEffect()) { + QWidgetEffectSourcePrivate *sourced = + static_cast<QWidgetEffectSourcePrivate *>(w->graphicsEffect()->source()->d_func()); + if (!sourced->updateDueToGraphicsEffect) + w->graphicsEffect()->source()->d_func()->invalidateCache(); + } + w = w->parentWidget(); + } while (w); +} + void QWidgetPrivate::setDirtyOpaqueRegion() { Q_Q(QWidget); dirtyOpaqueChildren = true; + invalidateGraphicsEffectsRecursively(); + if (q->isWindow()) return; @@ -1754,18 +1829,6 @@ void QWidgetPrivate::setDirtyOpaqueRegion() pd->setDirtyOpaqueRegion(); } -QRegion QWidgetPrivate::getOpaqueRegion() const -{ - Q_Q(const QWidget); - - QRegion r = isOpaque ? q->rect() : getOpaqueChildren(); - if (extra && extra->hasMask) - r &= extra->mask; - if (r.isEmpty()) - return r; - return r & clipRect(); -} - const QRegion &QWidgetPrivate::getOpaqueChildren() const { if (!dirtyOpaqueChildren) @@ -1780,9 +1843,17 @@ const QRegion &QWidgetPrivate::getOpaqueChildren() const continue; const QPoint offset = child->geometry().topLeft(); - that->opaqueChildren += child->d_func()->getOpaqueRegion().translated(offset); + QWidgetPrivate *childd = child->d_func(); + QRegion r = childd->isOpaque ? child->rect() : childd->getOpaqueChildren(); + if (childd->extra && childd->extra->hasMask) + r &= childd->extra->mask; + if (r.isEmpty()) + continue; + r.translate(offset); + that->opaqueChildren += r; } + that->opaqueChildren &= q_func()->rect(); that->dirtyOpaqueChildren = false; return that->opaqueChildren; @@ -1822,12 +1893,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) { @@ -1835,7 +1908,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) { @@ -1847,7 +1920,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()) @@ -1858,7 +1932,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) @@ -1889,6 +1963,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) @@ -1900,24 +1979,6 @@ void QWidgetPrivate::clipToEffectiveMask(QRegion ®ion) const } } -bool QWidgetPrivate::hasBackground() const -{ - Q_Q(const QWidget); - if (!q->isWindow() && q->parentWidget() && q->parentWidget()->testAttribute(Qt::WA_PaintOnScreen)) - return true; - if (q->testAttribute(Qt::WA_PaintOnScreen)) - return true; - if (!q->testAttribute(Qt::WA_OpaquePaintEvent) && !q->testAttribute(Qt::WA_NoSystemBackground)) { - const QPalette &pal = q->palette(); - QPalette::ColorRole bg = q->backgroundRole(); - QBrush bgBrush = pal.brush(bg); - return (bgBrush.style() != Qt::NoBrush && - ((q->isWindow() || q->windowType() == Qt::SubWindow) - || (QPalette::ColorRole(bg_role) != QPalette::NoRole || (pal.resolve() & (1<<bg))))); - } - return false; -} - bool QWidgetPrivate::paintOnScreen() const { #if defined(Q_WS_QWS) @@ -1940,6 +2001,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)) { @@ -1987,6 +2054,9 @@ void QWidgetPrivate::setOpaque(bool opaque) #ifdef Q_WS_WIN winUpdateIsOpaque(); #endif +#ifdef Q_OS_SYMBIAN + s60UpdateIsOpaque(); +#endif } void QWidgetPrivate::updateIsTranslucent() @@ -2000,6 +2070,9 @@ void QWidgetPrivate::updateIsTranslucent() #ifdef Q_WS_WIN winUpdateIsOpaque(); #endif +#ifdef Q_OS_SYMBIAN + s60UpdateIsOpaque(); +#endif } /*! @@ -2020,10 +2093,9 @@ void QPixmap::fill( const QWidget *widget, const QPoint &off ) QPainter p(this); p.translate(-off); widget->d_func()->paintBackground(&p, QRect(off, size())); - } -static inline void fillRegion(QPainter *painter, const QRegion &rgn, const QPoint &offset, const QBrush &brush) +static inline void fillRegion(QPainter *painter, const QRegion &rgn, const QBrush &brush) { Q_ASSERT(painter); @@ -2032,26 +2104,53 @@ static inline void fillRegion(QPainter *painter, const QRegion &rgn, const QPoin // Optimize pattern filling on mac by using HITheme directly // when filling with the standard widget background. // Defined in qmacstyle_mac.cpp - extern void qt_mac_fill_background(QPainter *painter, const QRegion &rgn, const QPoint &offset, const QBrush &brush); - qt_mac_fill_background(painter, rgn, offset, brush); + extern void qt_mac_fill_background(QPainter *painter, const QRegion &rgn, const QBrush &brush); + qt_mac_fill_background(painter, rgn, brush); #else - const QRegion translated = rgn.translated(offset); - const QRect rect(translated.boundingRect()); - painter->setClipRegion(translated); - 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 if (brush.gradient() + && brush.gradient()->coordinateMode() == QGradient::ObjectBoundingMode) { + painter->save(); + painter->setClipRegion(rgn); + painter->fillRect(0, 0, painter->device()->width(), painter->device()->height(), brush); + painter->restore(); } else { const QVector<QRect> &rects = rgn.rects(); for (int i = 0; i < rects.size(); ++i) - painter->fillRect(rects.at(i).translated(offset), brush); + painter->fillRect(rects.at(i), brush); } } - -void QWidgetPrivate::paintBackground(QPainter *painter, const QRegion &rgn, const QPoint &offset, int flags) const +void QWidgetPrivate::paintBackground(QPainter *painter, const QRegion &rgn, int flags) const { Q_Q(const QWidget); +#ifndef QT_NO_SCROLLAREA + bool resetBrushOrigin = false; + QPointF oldBrushOrigin; + //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.data(); + QAbstractScrollAreaPrivate *priv = static_cast<QAbstractScrollAreaPrivate *>(scrollPrivate); + oldBrushOrigin = painter->brushOrigin(); + resetBrushOrigin = true; + painter->setBrushOrigin(-priv->contentsOffset()); + + } +#endif // QT_NO_SCROLLAREA + const QBrush autoFillBrush = q->palette().brush(q->backgroundRole()); if ((flags & DrawAsRoot) && !(q->autoFillBackground() && autoFillBrush.isOpaque())) { @@ -2060,18 +2159,23 @@ void QWidgetPrivate::paintBackground(QPainter *painter, const QRegion &rgn, cons if (!(flags & DontSetCompositionMode) && painter->paintEngine()->hasFeature(QPaintEngine::PorterDuff)) painter->setCompositionMode(QPainter::CompositionMode_Source); //copy alpha straight in #endif - fillRegion(painter, rgn, offset, bg); + fillRegion(painter, rgn, bg); } if (q->autoFillBackground()) - fillRegion(painter, rgn, offset, autoFillBrush); + fillRegion(painter, rgn, autoFillBrush); if (q->testAttribute(Qt::WA_StyledBackground)) { - painter->setClipRegion(rgn.translated(offset)); + painter->setClipRegion(rgn); QStyleOption opt; opt.initFrom(q); q->style()->drawPrimitive(QStyle::PE_Widget, &opt, painter, q); } + +#ifndef QT_NO_SCROLLAREA + if (resetBrushOrigin) + painter->setBrushOrigin(oldBrushOrigin); +#endif // QT_NO_SCROLLAREA } /* @@ -2091,8 +2195,8 @@ void QWidgetPrivate::deactivateWidgetCleanup() { Q_Q(QWidget); // If this was the active application window, reset it - if (qApp->activeWindow() == q) - qApp->setActiveWindow(0); + if (QApplication::activeWindow() == q) + QApplication::setActiveWindow(0); // If the is the active mouse press widget, reset it if (q == qt_button_down) qt_button_down = 0; @@ -2137,8 +2241,8 @@ QWidget *QWidget::find(WId id) against. If Qt is using Carbon, the {WId} is actually an HIViewRef. If Qt is using Cocoa, {WId} is a pointer to an NSView. - \note We recommend that you do not store this value as it is likely to - change at run-time. + This value may change at run-time. An event with type QEvent::WinIdChange + will be sent to the widget following a change in window system identifier. \sa find() */ @@ -2293,7 +2397,7 @@ QStyle *QWidget::style() const if (d->extra && d->extra->style) return d->extra->style; - return qApp->style(); + return QApplication::style(); } /*! @@ -2612,7 +2716,7 @@ bool QWidget::isMaximized() const */ Qt::WindowStates QWidget::windowState() const { - return (Qt::WindowStates)data->window_state; + return Qt::WindowStates(data->window_state); } /*!\internal @@ -2624,7 +2728,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); } @@ -2723,7 +2827,7 @@ void QWidget::showFullScreen() Calling this function only affects \l{isWindow()}{windows}. On X11, this function may not work properly with certain window - managers. See \l{geometry.html}{Window Geometry} for an explanation. + managers. See the \l{Window Geometry} documentation for an explanation. \sa setWindowState(), showNormal(), showMinimized(), show(), hide(), isVisible() */ @@ -2778,7 +2882,7 @@ void QWidget::showNormal() bool QWidget::isEnabledTo(QWidget* ancestor) const { const QWidget * w = this; - while (w && !w->testAttribute(Qt::WA_ForceDisabled) + while (!w->testAttribute(Qt::WA_ForceDisabled) && !w->isWindow() && w->parentWidget() && w->parentWidget() != ancestor) @@ -2962,17 +3066,23 @@ void QWidgetPrivate::setEnabled_helper(bool enable) if (q->testAttribute(Qt::WA_SetCursor) || q->isWindow()) { // enforce the windows behavior of clearing the cursor on // disabled widgets - extern void qt_x11_enforce_cursor(QWidget * w); // defined in qwidget_x11.cpp qt_x11_enforce_cursor(q); } #endif #if defined(Q_WS_MAC) setEnabled_helper_sys(enable); #endif -#if defined (Q_WS_WIN) - if (q->hasFocus()) - QInputContextPrivate::updateImeStatus(q, true); -#endif +#ifndef QT_NO_IM + if (q->testAttribute(Qt::WA_InputMethodEnabled) && q->hasFocus()) { + QInputContext *qic = inputContext(); + if (enable) { + qic->setFocusWidget(q); + } else { + qic->reset(); + qic->setFocusWidget(0); + } + } +#endif //QT_NO_IM QEvent e(QEvent::EnabledChange); QApplication::sendEvent(q, &e); #ifdef QT3_SUPPORT @@ -3067,8 +3177,8 @@ void QWidget::setDisabled(bool disable) \brief geometry of the widget relative to its parent including any window frame - See the \link geometry.html Window Geometry documentation\endlink - for an overview of geometry issues with windows. + See the \l{Window Geometry} documentation for an overview of geometry + issues with windows. By default, this property contains a value that depends on the user's platform and screen geometry. @@ -3094,8 +3204,8 @@ QRect QWidget::frameGeometry() const \brief the x coordinate of the widget relative to its parent including any window frame - See the \link geometry.html Window Geometry documentation\endlink - for an overview of window geometry. + See the \l{Window Geometry} documentation for an overview of geometry + issues with windows. By default, this property has a value of 0. @@ -3114,8 +3224,8 @@ int QWidget::x() const \brief the y coordinate of the widget relative to its parent and including any window frame - See the \link geometry.html Window Geometry documentation\endlink - for an overview of window geometry. + See the \l{Window Geometry} documentation for an overview of geometry + issues with windows. By default, this property has a value of 0. @@ -3147,8 +3257,8 @@ int QWidget::y() const \warning Calling move() or setGeometry() inside moveEvent() can lead to infinite recursion. - See the \link geometry.html Window Geometry documentation\endlink - for an overview of window geometry. + See the \l{Window Geometry} documentation for an overview of geometry + issues with windows. \sa frameGeometry, size x(), y() */ @@ -3178,8 +3288,8 @@ QPoint QWidget::pos() const \warning Calling setGeometry() inside resizeEvent() or moveEvent() can lead to infinite recursion. - See the \link geometry.html Window Geometry documentation\endlink - for an overview of window geometry. + See the \l{Window Geometry} documentation for an overview of geometry + issues with windows. By default, this property contains a value that depends on the user's platform and screen geometry. @@ -3228,12 +3338,12 @@ QPoint QWidget::pos() const \property QWidget::width \brief the width of the widget excluding any window frame - See the \link geometry.html Window Geometry documentation\endlink - for an overview of window geometry. + See the \l{Window Geometry} documentation for an overview of geometry + issues with windows. \note Do not use this function to find the width of a screen on a \l{QDesktopWidget}{multiple screen desktop}. Read - \l{multiple screens note}{this note} for details. + \l{QDesktopWidget#Screen Geometry}{this note} for details. By default, this property contains a value that depends on the user's platform and screen geometry. @@ -3245,12 +3355,12 @@ QPoint QWidget::pos() const \property QWidget::height \brief the height of the widget excluding any window frame - See the \link geometry.html Window Geometry documentation\endlink - for an overview of window geometry. + See the \l{Window Geometry} documentation for an overview of geometry + issues with windows. \note Do not use this function to find the height of a screen - on a \l {QDesktopWidget} {multiple screen desktop}. Read - \l {multiple screens note} {this note} for details. + on a \l{QDesktopWidget}{multiple screen desktop}. Read + \l{QDesktopWidget#Screen Geometry}{this note} for details. By default, this property contains a value that depends on the user's platform and screen geometry. @@ -3265,8 +3375,8 @@ QPoint QWidget::pos() const The rect property equals QRect(0, 0, width(), height()). - See the \link geometry.html Window Geometry documentation\endlink - for an overview of window geometry. + See the \l{Window Geometry} documentation for an overview of geometry + issues with windows. By default, this property contains a value that depends on the user's platform and screen geometry. @@ -3506,27 +3616,32 @@ bool QWidgetPrivate::setMinimumSize_helper(int &minw, int &minh) } } #endif + int mw = minw, mh = minh; + if (mw == QWIDGETSIZE_MAX) + mw = 0; + if (mh == QWIDGETSIZE_MAX) + mh = 0; if (minw > QWIDGETSIZE_MAX || minh > QWIDGETSIZE_MAX) { qWarning("QWidget::setMinimumSize: (%s/%s) " "The largest allowed size is (%d,%d)", q->objectName().toLocal8Bit().data(), q->metaObject()->className(), QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); - minw = qMin<int>(minw, QWIDGETSIZE_MAX); - minh = qMin<int>(minh, QWIDGETSIZE_MAX); + minw = mw = qMin<int>(minw, QWIDGETSIZE_MAX); + minh = mh = qMin<int>(minh, QWIDGETSIZE_MAX); } if (minw < 0 || minh < 0) { qWarning("QWidget::setMinimumSize: (%s/%s) Negative sizes (%d,%d) " "are not possible", q->objectName().toLocal8Bit().data(), q->metaObject()->className(), minw, minh); - minw = qMax(minw, 0); - minh = qMax(minh, 0); + minw = mw = qMax(minw, 0); + minh = mh = qMax(minh, 0); } createExtra(); - if (extra->minw == minw && extra->minh == minh) + if (extra->minw == mw && extra->minh == mh) return false; - extra->minw = minw; - extra->minh = minh; - extra->explicitMinSize = (minw ? Qt::Horizontal : 0) | (minh ? Qt::Vertical : 0); + extra->minw = mw; + extra->minh = mh; + extra->explicitMinSize = (mw ? Qt::Horizontal : 0) | (mh ? Qt::Vertical : 0); return true; } @@ -3586,7 +3701,8 @@ bool QWidgetPrivate::setMaximumSize_helper(int &maxw, int &maxh) return false; extra->maxw = maxw; extra->maxh = maxh; - extra->explicitMaxSize = (maxw != QWIDGETSIZE_MAX ? Qt::Horizontal : 0) | (maxh != QWIDGETSIZE_MAX ? Qt::Vertical : 0); + extra->explicitMaxSize = (maxw != QWIDGETSIZE_MAX ? Qt::Horizontal : 0) | + (maxh != QWIDGETSIZE_MAX ? Qt::Vertical : 0); return true; } @@ -3665,6 +3781,8 @@ void QWidget::setBaseSize(int basew, int baseh) This will override the default size constraints set by QLayout. + To remove constraints, set the size to QWIDGETSIZE_MAX. + Alternatively, if you want the widget to have a fixed size based on its contents, you can call QLayout::setSizeConstraint(QLayout::SetFixedSize); @@ -3706,7 +3824,8 @@ void QWidget::setFixedSize(int w, int h) else d->updateGeometry_helper(true); - resize(w, h); + if (w != QWIDGETSIZE_MAX || h != QWIDGETSIZE_MAX) + resize(w, h); } void QWidget::setMinimumWidth(int w) @@ -4079,6 +4198,10 @@ QPalette::ColorRole QWidget::backgroundRole() const If \a role is QPalette::NoRole, then the widget inherits its parent's background role. + Note that styles are free to choose any color from the palette. + You can modify the palette or set a style sheet if you don't + achieve the result you want with setBackgroundRole(). + \sa backgroundRole(), foregroundRole() */ @@ -4141,6 +4264,10 @@ QPalette::ColorRole QWidget::foregroundRole() const If \a role is QPalette::NoRole, the widget uses a foreground role that contrasts with the background role. + Note that styles are free to choose any color from the palette. + You can modify the palette or set a style sheet if you don't + achieve the result you want with setForegroundRole(). + \sa foregroundRole(), backgroundRole() */ void QWidget::setForegroundRole(QPalette::ColorRole role) @@ -4209,7 +4336,7 @@ const QPalette &QWidget::palette() const if (!isEnabled()) { data->pal.setCurrentColorGroup(QPalette::Disabled); } else if ((!isVisible() || isActiveWindow()) -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) +#if defined(Q_OS_WIN) && !defined(Q_WS_WINCE) && !QApplicationPrivate::isBlockedByModal(const_cast<QWidget *>(this)) #endif ) { @@ -4254,7 +4381,11 @@ QPalette QWidgetPrivate::naturalWidgetPalette(uint inheritedMask) const Q_Q(const QWidget); QPalette naturalPalette = QApplication::palette(q); if (!q->testAttribute(Qt::WA_StyleSheet) - && (!q->isWindow() || q->testAttribute(Qt::WA_WindowPropagation) || (extra && extra->proxyWidget))) { + && (!q->isWindow() || q->testAttribute(Qt::WA_WindowPropagation) +#ifndef QT_NO_GRAPHICSVIEW + || (extra && extra->proxyWidget) +#endif //QT_NO_GRAPHICSVIEW + )) { if (QWidget *p = q->parentWidget()) { if (!p->testAttribute(Qt::WA_StyleSheet)) { if (!naturalPalette.isCopyOf(QApplication::palette())) { @@ -4265,13 +4396,14 @@ QPalette QWidgetPrivate::naturalWidgetPalette(uint inheritedMask) const naturalPalette = p->palette(); } } - } else if (extra && extra->proxyWidget) { + } #ifndef QT_NO_GRAPHICSVIEW + else if (extra && extra->proxyWidget) { QPalette inheritedPalette = extra->proxyWidget->palette(); inheritedPalette.resolve(inheritedMask); naturalPalette = inheritedPalette.resolve(naturalPalette); -#endif //QT_NO_GRAPHICSVIEW } +#endif //QT_NO_GRAPHICSVIEW } naturalPalette.resolve(0); return naturalPalette; @@ -4389,7 +4521,11 @@ QFont QWidgetPrivate::naturalWidgetFont(uint inheritedMask) const Q_Q(const QWidget); QFont naturalFont = QApplication::font(q); if (!q->testAttribute(Qt::WA_StyleSheet) - && (!q->isWindow() || q->testAttribute(Qt::WA_WindowPropagation) || (extra && extra->proxyWidget))) { + && (!q->isWindow() || q->testAttribute(Qt::WA_WindowPropagation) +#ifndef QT_NO_GRAPHICSVIEW + || (extra && extra->proxyWidget) +#endif //QT_NO_GRAPHICSVIEW + )) { if (QWidget *p = q->parentWidget()) { if (!p->testAttribute(Qt::WA_StyleSheet)) { if (!naturalFont.isCopyOf(QApplication::font())) { @@ -4400,13 +4536,14 @@ QFont QWidgetPrivate::naturalWidgetFont(uint inheritedMask) const naturalFont = p->font(); } } - } else if (extra && extra->proxyWidget) { + } #ifndef QT_NO_GRAPHICSVIEW + else if (extra && extra->proxyWidget) { QFont inheritedFont = extra->proxyWidget->font(); inheritedFont.resolve(inheritedMask); naturalFont = inheritedFont.resolve(naturalFont); -#endif //QT_NO_GRAPHICSVIEW } +#endif //QT_NO_GRAPHICSVIEW } naturalFont.resolve(0); return naturalFont; @@ -4453,12 +4590,13 @@ void QWidgetPrivate::updateFont(const QFont &font) data.fnt.x11SetScreen(xinfo.screen()); #endif // Combine new mask with natural mask and propagate to children. - if (!q->parentWidget() && extra && extra->proxyWidget) { #ifndef QT_NO_GRAPHICSVIEW + if (!q->parentWidget() && extra && extra->proxyWidget) { QGraphicsProxyWidget *p = extra->proxyWidget; inheritedFontResolveMask = p->d_func()->inheritedFontResolveMask | p->font().resolve(); + } else #endif //QT_NO_GRAPHICSVIEW - } else if (q->isWindow() && !q->testAttribute(Qt::WA_WindowPropagation)) { + if (q->isWindow() && !q->testAttribute(Qt::WA_WindowPropagation)) { inheritedFontResolveMask = 0; } uint newMask = data.fnt.resolve() | inheritedFontResolveMask; @@ -4621,8 +4759,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); @@ -4802,7 +4941,7 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset, } const qreal opacity = painter->opacity(); - if (qFuzzyCompare(opacity + 1, qreal(1.0))) + if (qFuzzyIsNull(opacity)) return; // Fully transparent. Q_D(QWidget); @@ -4864,6 +5003,69 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset, d->extra->inRenderWithPainter = false; } +/*! + \brief The graphicsEffect function returns a pointer to the + widget's graphics effect. + + If the widget has no graphics effect, 0 is returned. + + \since 4.6 + + \sa setGraphicsEffect() +*/ +QGraphicsEffect *QWidget::graphicsEffect() const +{ + Q_D(const QWidget); + return d->graphicsEffect; +} + +/*! + + \brief The setGraphicsEffect function is for setting the widget's graphics effect. + + 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 + + \sa graphicsEffect() +*/ +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) @@ -4955,7 +5157,8 @@ void QWidgetPrivate::render_helper(QPainter *painter, const QPoint &targetOffset return; QPixmap pixmap(size); - if (!(renderFlags & QWidget::DrawWindowBackground)) + if (!(renderFlags & QWidget::DrawWindowBackground) + || !q->palette().brush(q->backgroundRole()).isOpaque()) pixmap.fill(Qt::transparent); q->render(&pixmap, QPoint(), toBePainted, renderFlags); @@ -5008,6 +5211,37 @@ 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; + if (sharedPainter->worldTransform() != sourced->lastEffectTransform) { + sourced->invalidateCache(); + sourced->lastEffectTransform = sharedPainter->worldTransform(); + } + 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; @@ -5040,26 +5274,14 @@ 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)) && !q->testAttribute(Qt::WA_OpaquePaintEvent) && !q->testAttribute(Qt::WA_NoSystemBackground)) { QPainter p(q); - QPoint scrollAreaOffset; - -#ifndef QT_NO_SCROLLAREA - QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea *>(q->parent()); - if (scrollArea && scrollArea->viewport() == q) { - QObjectData *scrollPrivate = static_cast<QWidget *>(scrollArea)->d_ptr; - QAbstractScrollAreaPrivate *priv = static_cast<QAbstractScrollAreaPrivate *>(scrollPrivate); - scrollAreaOffset = priv->contentsOffset(); - p.translate(-scrollAreaOffset); - } -#endif // QT_NO_SCROLLAREA - - paintBackground(&p, toBePainted, scrollAreaOffset, (asRoot || onScreen) ? flags | DrawAsRoot : 0); + paintBackground(&p, toBePainted, (asRoot || onScreen) ? flags | DrawAsRoot : 0); } if (!sharedPainter) @@ -5091,7 +5313,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(); @@ -5154,7 +5376,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 @@ -5172,7 +5394,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); @@ -5185,9 +5407,13 @@ void QWidgetPrivate::paintSiblingsRecursive(QPaintDevice *pdev, const QObjectLis , sharedPainter, backingStore); } - if (w->updatesEnabled() && (!w->d_func()->extra || !w->d_func()->extra->proxyWidget)) { + if (w->updatesEnabled() +#ifndef QT_NO_GRAPHICSVIEW + && (!w->d_func()->extra || !w->d_func()->extra->proxyWidget) +#endif //QT_NO_GRAPHICSVIEW + ) { QRegion wRegion(rgn); - wRegion &= w->data->crect; + wRegion &= wd->effectiveRectFor(w->data->crect); wRegion.translate(-widgetPos); if (hasMask) wRegion &= wd->extra->mask; @@ -5195,6 +5421,108 @@ 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, + QGraphicsEffectSource::PixmapPadMode mode) 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; + + if (mode == QGraphicsEffectSource::ExpandToEffectRectPadMode) { + effectRect = m_widget->graphicsEffect()->boundingRectFor(sourceRect).toAlignedRect(); + + } else if (mode == QGraphicsEffectSource::ExpandToTransparentBorderPadMode) { + effectRect = sourceRect.adjusted(-1, -1, 1, 1).toAlignedRect(); + + } else { + effectRect = 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; +} + +#ifndef QT_NO_GRAPHICSVIEW /*! \internal @@ -5203,7 +5531,7 @@ void QWidgetPrivate::paintSiblingsRecursive(QPaintDevice *pdev, const QObjectLis If successful, the function returns the proxy that embeds the widget, or 0 if no embedded widget was found. */ -QGraphicsProxyWidget * QWidgetPrivate::nearestGraphicsProxyWidget(QWidget *origin) +QGraphicsProxyWidget * QWidgetPrivate::nearestGraphicsProxyWidget(const QWidget *origin) { if (origin) { QWExtra *extra = origin->d_func()->extra; @@ -5213,6 +5541,7 @@ QGraphicsProxyWidget * QWidgetPrivate::nearestGraphicsProxyWidget(QWidget *origi } return 0; } +#endif /*! \property QWidget::locale @@ -5293,7 +5622,7 @@ static QString constructWindowTitleFromFilePath(const QString &filePath) #ifndef Q_WS_MAC QString appName = QApplication::applicationName(); if (!appName.isEmpty()) - windowTitle += QLatin1String(" ") + QChar(0x2014) + QLatin1String(" ") + appName; + windowTitle += QLatin1Char(' ') + QChar(0x2014) + QLatin1Char(' ') + appName; #endif return windowTitle; } @@ -5328,6 +5657,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); @@ -5339,16 +5679,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 @@ -5357,13 +5702,13 @@ QString qt_setWindowTitle_helperHelper(const QString &title, const QWidget *widg && widget->style()->styleHint(QStyle::SH_TitleBar_ModifyNotification, 0, widget)) cap.replace(lastIndex, 3, QWidget::tr("*")); else - cap.replace(lastIndex, 3, QLatin1String("")); + cap.remove(lastIndex, 3); } index = cap.indexOf(placeHolder, index); } - cap.replace(QLatin1String("[*][*]"), QLatin1String("[*]")); + cap.replace(QLatin1String("[*][*]"), placeHolder); return cap; } @@ -5371,9 +5716,8 @@ QString qt_setWindowTitle_helperHelper(const QString &title, const QWidget *widg void QWidgetPrivate::setWindowTitle_helper(const QString &title) { Q_Q(QWidget); - if (!q->testAttribute(Qt::WA_WState_Created)) - createWinId(); - setWindowTitle_sys(qt_setWindowTitle_helperHelper(title, q)); + if (q->testAttribute(Qt::WA_WState_Created)) + setWindowTitle_sys(qt_setWindowTitle_helperHelper(title, q)); } void QWidgetPrivate::setWindowIconText_helper(const QString &title) @@ -5398,7 +5742,7 @@ void QWidget::setWindowIconText(const QString &iconText) void QWidget::setWindowTitle(const QString &title) { - if (QWidget::windowTitle() == title) + if (QWidget::windowTitle() == title && !title.isEmpty() && !title.isNull()) return; Q_D(QWidget); @@ -5429,7 +5773,7 @@ QIcon QWidget::windowIcon() const return *d->extra->topextra->icon; w = w->parentWidget(); } - return qApp->windowIcon(); + return QApplication::windowIcon(); } void QWidgetPrivate::setWindowIcon_helper() @@ -5492,8 +5836,6 @@ QString QWidget::windowIconText() const \list \o The file name of the specified path, obtained using QFileInfo::fileName(). - \o An optional \c{*} character, if the \l windowModified property is set, - as per the Apple Human Interface Guidelines. \endlist On Windows and X11: @@ -5542,7 +5884,7 @@ void QWidgetPrivate::setWindowFilePath_helper(const QString &filePath) { if (extra->topextra && extra->topextra->caption.isEmpty()) { #ifdef Q_WS_MAC - setWindowTitle_helper(filePath); + setWindowTitle_helper(QFileInfo(filePath).fileName()); #else Q_Q(QWidget); Q_UNUSED(filePath); @@ -5675,6 +6017,8 @@ bool QWidget::hasFocus() const isActiveWindow() active window\endlink. The \a reason argument will be passed into any focus event sent from this function, it is used to give an explanation of what caused the widget to get focus. + If the window is not active, the widget will be given the focus when + the window becomes active. First, a focus out event is sent to the focus widget (if any) to tell it that it is about to lose the focus. Then a focus in event @@ -5692,7 +6036,7 @@ bool QWidget::hasFocus() const called from focusOutEvent() or focusInEvent(), you may get an infinite recursion. - \sa focus(), hasFocus(), clearFocus(), focusInEvent(), focusOutEvent(), + \sa hasFocus(), clearFocus(), focusInEvent(), focusOutEvent(), setFocusPolicy(), focusWidget(), QApplication::focusWidget(), grabKeyboard(), grabMouse(), {Keyboard Focus} */ @@ -5913,6 +6257,8 @@ QWidget *QWidget::focusWidget() const /*! Returns the next widget in this widget's focus chain. + + \sa previousInFocusChain() */ QWidget *QWidget::nextInFocusChain() const { @@ -5920,6 +6266,19 @@ QWidget *QWidget::nextInFocusChain() const } /*! + \brief The previousInFocusChain function returns the previous + widget in this widget's focus chain. + + \sa nextInFocusChain() + + \since 4.6 +*/ +QWidget *QWidget::previousInFocusChain() const +{ + return const_cast<QWidget *>(d_func()->focus_prev); +} + +/*! \property QWidget::isActiveWindow \brief whether this widget's window is the active window @@ -5937,7 +6296,7 @@ QWidget *QWidget::nextInFocusChain() const bool QWidget::isActiveWindow() const { QWidget *tlw = window(); - if(tlw == qApp->activeWindow() || (isVisible() && (tlw->windowType() == Qt::Popup))) + if(tlw == QApplication::activeWindow() || (isVisible() && (tlw->windowType() == Qt::Popup))) return true; #ifndef QT_NO_GRAPHICSVIEW @@ -5952,13 +6311,17 @@ 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 && !tlw->isModal() && (!tlw->parentWidget() || tlw->parentWidget()->isActiveWindow())) return true; - QWidget *w = qApp->activeWindow(); + QWidget *w = QApplication::activeWindow(); while(w && tlw->windowType() == Qt::Tool && !w->isModal() && w->parentWidget()) { w = w->parentWidget()->window(); @@ -6141,6 +6504,8 @@ void QWidgetPrivate::reparentFocusWidgets(QWidget * oldtlw) This function is called from QDesktopwidget::screen(QPoint) to find the closest screen for a point. + In directional KeypadNavigation, it is called to find the closest + widget to the current focus widget center. */ int QWidgetPrivate::pointToRect(const QPoint &p, const QRect &r) { @@ -6157,14 +6522,6 @@ int QWidgetPrivate::pointToRect(const QPoint &p, const QRect &r) return dx + dy; } -QRect QWidgetPrivate::fromOrToLayoutItemRect(const QRect &rect, int sign) const -{ - QRect r = rect; - r.adjust(-sign * leftLayoutItemMargin, -sign * topLayoutItemMargin, - +sign * rightLayoutItemMargin, +sign * bottomLayoutItemMargin); - return r; -} - /*! \property QWidget::frameSize \brief the size of the widget including any window frame @@ -6253,8 +6610,8 @@ void QWidget::setGeometry(const QRect &r) \snippet doc/src/snippets/code/src_gui_kernel_qwidget.cpp 11 - See the \link geometry.html Window Geometry documentation\endlink - for an overview of geometry issues with windows. + See the \l{Window Geometry} documentation for an overview of geometry + issues with windows. Use QMainWindow::saveState() to save the geometry and the state of toolbars and dock widgets. @@ -6295,8 +6652,8 @@ QByteArray QWidget::saveGeometry() const \snippet doc/src/snippets/code/src_gui_kernel_qwidget.cpp 12 - See the \link geometry.html Window Geometry documentation\endlink - for an overview of geometry issues with windows. + See the \l{Window Geometry} documentation for an overview of geometry + issues with windows. Use QMainWindow::restoreState() to restore the geometry and the state of toolbars and dock widgets. @@ -6413,14 +6770,14 @@ bool QWidget::restoreGeometry(const QByteArray &geometry) */ /*! - Sets the margins around the contents of the widget to have the - sizes \a left, \a top, \a right, and \a bottom. The margins are - used by the layout system, and may be used by subclasses to - specify the area to draw in (e.g. excluding the frame). + Sets the margins around the contents of the widget to have the sizes + \a left, \a top, \a right, and \a bottom. The margins are used by + the layout system, and may be used by subclasses to specify the area + to draw in (e.g. excluding the frame). - Changing the margins will trigger a resizeEvent(). + Changing the margins will trigger a resizeEvent(). - \sa contentsRect(), getContentsMargins() + \sa contentsRect(), getContentsMargins() */ void QWidget::setContentsMargins(int left, int top, int right, int bottom) { @@ -6451,7 +6808,30 @@ void QWidget::setContentsMargins(int left, int top, int right, int bottom) QApplication::sendEvent(this, &e); } -/*! Returns the widget's contents margins for \a left, \a top, \a +/*! + \overload + \since 4.6 + + \brief The setContentsMargins function sets the margins around the + widget's contents. + + Sets the margins around the contents of the widget to have the + sizes determined by \a margins. The margins are + used by the layout system, and may be used by subclasses to + specify the area to draw in (e.g. excluding the frame). + + Changing the margins will trigger a resizeEvent(). + + \sa contentsRect(), getContentsMargins() +*/ +void QWidget::setContentsMargins(const QMargins &margins) +{ + setContentsMargins(margins.left(), margins.top(), + margins.right(), margins.bottom()); +} + +/*! + Returns the widget's contents margins for \a left, \a top, \a right, and \a bottom. \sa setContentsMargins(), contentsRect() @@ -6470,6 +6850,20 @@ void QWidget::getContentsMargins(int *left, int *top, int *right, int *bottom) c } /*! + \since 4.6 + + \brief The contentsMargins function returns the widget's contents margins. + + \sa getContentsMargins(), setContentsMargins(), contentsRect() + */ +QMargins QWidget::contentsMargins() const +{ + Q_D(const QWidget); + return QMargins(d->leftmargin, d->topmargin, d->rightmargin, d->bottommargin); +} + + +/*! Returns the area inside the widget's margins. \sa setContentsMargins(), getContentsMargins() @@ -6751,7 +7145,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 @@ -6768,7 +7162,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 @@ -6850,7 +7244,7 @@ void QWidgetPrivate::hide_helper() // next bit tries to move the focus if the focus widget is now // hidden. if (wasVisible) { -#if defined(Q_WS_WIN) || defined(Q_WS_X11) +#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined (Q_WS_QWS) qApp->d_func()->sendSyntheticEnterLeave(q); #endif @@ -6888,9 +7282,12 @@ void QWidgetPrivate::hide_helper() widgets that are not visible. - Widgets are hidden if they were created as independent - windows or as children of visible widgets, or if hide() or setVisible(false) was called. - + Widgets are hidden if: + \list + \o they were created as independent windows, + \o they were created as children of visible widgets, + \o hide() or setVisible(false) was called. + \endlist */ @@ -6979,7 +7376,7 @@ void QWidget::setVisible(bool visible) d->show_helper(); -#if defined(Q_WS_WIN) || defined(Q_WS_X11) +#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined (Q_WS_QWS) qApp->d_func()->sendSyntheticEnterLeave(this); #endif } @@ -7094,7 +7491,7 @@ void QWidgetPrivate::hideChildren(bool spontaneous) widget->d_func()->hide_sys(); } } -#if defined(Q_WS_WIN) || defined(Q_WS_X11) +#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined (Q_WS_QWS) qApp->d_func()->sendSyntheticEnterLeave(widget); #endif #ifndef QT_NO_ACCESSIBILITY @@ -7136,7 +7533,7 @@ bool QWidgetPrivate::close_helper(CloseMode mode) #ifdef QT3_SUPPORT if (isMain) - qApp->quit(); + QApplication::quit(); #endif // Attempt to close the application only if this widget has the // WA_QuitOnClose flag set set and has a non-visible parent @@ -7261,8 +7658,7 @@ bool QWidget::isVisibleTo(QWidget* ancestor) const if (!ancestor) return isVisible(); const QWidget * w = this; - while (w - && !w->isHidden() + while (!w->isHidden() && !w->isWindow() && w->parentWidget() && w->parentWidget() != ancestor) @@ -7319,10 +7715,10 @@ QSize QWidgetPrivate::adjustedSize() const if (q->isWindow()) { Qt::Orientations exp; - if (QLayout *l = q->layout()) { - if (l->hasHeightForWidth()) - s.setHeight(l->totalHeightForWidth(s.width())); - exp = l->expandingDirections(); + if (layout) { + if (layout->hasHeightForWidth()) + s.setHeight(layout->totalHeightForWidth(s.width())); + exp = layout->expandingDirections(); } else { if (q->sizePolicy().hasHeightForWidth()) @@ -7338,7 +7734,7 @@ QSize QWidgetPrivate::adjustedSize() const #else // all others QRect screen = QApplication::desktop()->screenGeometry(q->pos()); #endif -#if defined (Q_OS_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 @@ -7380,6 +7776,10 @@ void QWidget::adjustSize() Q_D(QWidget); ensurePolished(); QSize s = d->adjustedSize(); + + if (d->layout) + d->layout->activate(); + if (s.isValid()) resize(s); } @@ -7525,6 +7925,9 @@ bool QWidget::event(QEvent *event) case QEvent::MouseButtonRelease: case QEvent::MouseButtonDblClick: case QEvent::MouseMove: + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: case QEvent::ContextMenu: #ifndef QT_NO_WHEELEVENT case QEvent::Wheel: @@ -7590,10 +7993,21 @@ bool QWidget::event(QEvent *event) #ifdef QT_KEYPAD_NAVIGATION if (!k->isAccepted() && QApplication::keypadNavigationEnabled() && !(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::ShiftModifier))) { - if (k->key() == Qt::Key_Up) - res = focusNextPrevChild(false); - else if (k->key() == Qt::Key_Down) - res = focusNextPrevChild(true); + if (QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder) { + if (k->key() == Qt::Key_Up) + res = focusNextPrevChild(false); + else if (k->key() == Qt::Key_Down) + res = focusNextPrevChild(true); + } else if (QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional) { + if (k->key() == Qt::Key_Up) + res = QWidgetPrivate::navigateToDirection(QWidgetPrivate::DirectionNorth); + else if (k->key() == Qt::Key_Right) + res = QWidgetPrivate::navigateToDirection(QWidgetPrivate::DirectionEast); + else if (k->key() == Qt::Key_Down) + res = QWidgetPrivate::navigateToDirection(QWidgetPrivate::DirectionSouth); + else if (k->key() == Qt::Key_Left) + res = QWidgetPrivate::navigateToDirection(QWidgetPrivate::DirectionWest); + } if (res) { k->accept(); break; @@ -7646,16 +8060,13 @@ bool QWidget::event(QEvent *event) } break; case QEvent::FocusIn: -#if defined(Q_WS_WIN) - QInputContextPrivate::updateImeStatus(this, true); +#ifdef QT_SOFTKEYS_ENABLED + QSoftKeyManager::updateSoftKeys(); #endif focusInEvent((QFocusEvent*)event); break; case QEvent::FocusOut: -#if defined(Q_WS_WIN) - QInputContextPrivate::updateImeStatus(this, false); -#endif focusOutEvent((QFocusEvent*)event); break; @@ -7801,6 +8212,12 @@ bool QWidget::event(QEvent *event) if (w && w->isVisible() && !w->isWindow()) QApplication::sendEvent(w, event); } + +#ifdef QT_SOFTKEYS_ENABLED + if (isWindow() && isActiveWindow()) + QSoftKeyManager::updateSoftKeys(); +#endif + break; } case QEvent::LanguageChange: @@ -7841,7 +8258,7 @@ bool QWidget::event(QEvent *event) QList<QObject*> childList = d->children; for (int i = 0; i < childList.size(); ++i) { QObject *o = childList.at(i); - if (o != qApp->activeModalWidget()) { + if (o != QApplication::activeModalWidget()) { if (qobject_cast<QWidget *>(o) && static_cast<QWidget *>(o)->isWindow()) { // do not forward the event to child windows, // QApplication does this for us @@ -7908,6 +8325,9 @@ bool QWidget::event(QEvent *event) case QEvent::ActionAdded: case QEvent::ActionRemoved: case QEvent::ActionChanged: +#ifdef QT_SOFTKEYS_ENABLED + QSoftKeyManager::updateSoftKeys(); +#endif actionEvent((QActionEvent*)event); break; #endif @@ -7930,6 +8350,46 @@ bool QWidget::event(QEvent *event) d->needWindowChange = false; break; #endif + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + { + QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event); + const QTouchEvent::TouchPoint &touchPoint = touchEvent->touchPoints().first(); + if (touchPoint.isPrimary()) + break; + + // fake a mouse event! + QEvent::Type eventType = QEvent::None; + switch (touchEvent->type()) { + case QEvent::TouchBegin: + eventType = QEvent::MouseButtonPress; + break; + case QEvent::TouchUpdate: + eventType = QEvent::MouseMove; + break; + case QEvent::TouchEnd: + eventType = QEvent::MouseButtonRelease; + break; + default: + Q_ASSERT(!true); + break; + } + if (eventType == QEvent::None) + break; + + QMouseEvent mouseEvent(eventType, + touchPoint.pos().toPoint(), + touchPoint.screenPos().toPoint(), + Qt::LeftButton, + Qt::LeftButton, + touchEvent->modifiers()); + (void) QApplication::sendEvent(this, &mouseEvent); + break; + } + case QEvent::Gesture: + event->ignore(); + break; #ifndef QT_NO_PROPERTIES case QEvent::DynamicPropertyChange: { const QByteArray &propName = static_cast<QDynamicPropertyChangeEvent *>(event)->propertyName(); @@ -7981,10 +8441,12 @@ void QWidget::changeEvent(QEvent * event) case QEvent::FontChange: case QEvent::StyleChange: { + Q_D(QWidget); update(); updateGeometry(); + if (d->layout) + d->layout->invalidate(); #ifdef Q_WS_QWS - Q_D(QWidget); if (isWindow()) d->data.fstrut_dirty = true; #endif @@ -8064,9 +8526,9 @@ void QWidget::mousePressEvent(QMouseEvent *event) if ((windowType() == Qt::Popup)) { event->accept(); QWidget* w; - while ((w = qApp->activePopupWidget()) && w != this){ + while ((w = QApplication::activePopupWidget()) && w != this){ w->close(); - if (qApp->activePopupWidget() == w) // widget does not want to dissappear + if (QApplication::activePopupWidget() == w) // widget does not want to dissappear w->hide(); // hide at least } if (!rect().contains(event->pos())){ @@ -8094,8 +8556,10 @@ void QWidget::mouseReleaseEvent(QMouseEvent *event) The default implementation generates a normal mouse press event. - Note that the widgets gets a mousePressEvent() and a - mouseReleaseEvent() before the mouseDoubleClickEvent(). + \note The widget will also receive mouse press and mouse release + events in addition to the double click event. It is up to the + developer to ensure that the application interprets these events + correctly. \sa mousePressEvent(), mouseReleaseEvent() mouseMoveEvent(), event(), QMouseEvent @@ -8476,7 +8940,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 { @@ -8485,11 +8949,60 @@ 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); +#ifndef QT_NO_IM + return d->imHints; +#else //QT_NO_IM + return 0; +#endif //QT_NO_IM +} + +void QWidget::setInputMethodHints(Qt::InputMethodHints hints) +{ +#ifndef QT_NO_IM + 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(); + } +#endif //QT_NO_IM +} + + #ifndef QT_NO_DRAGANDDROP /*! @@ -8806,7 +9319,7 @@ QRegion QWidget::mask() const The layout manager sets the geometry of the widget's children that have been added to the layout. - \sa setLayout(), sizePolicy(), {Layout Classes} + \sa setLayout(), sizePolicy(), {Layout Management} */ QLayout *QWidget::layout() const { @@ -8836,7 +9349,7 @@ QLayout *QWidget::layout() const The QWidget will take ownership of \a layout. - \sa layout(), {Layout Classes} + \sa layout(), {Layout Management} */ void QWidget::setLayout(QLayout *l) @@ -9261,11 +9774,12 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f) d->resolveLayoutDirection(); d->resolveLocale(); - // Note: GL widgets under Windows will always need a ParentChange - // event to handle recreation/rebinding of the GL context, hence - // the (f & Qt::MSWindowsOwnDC) clause + // Note: GL widgets under WGL or EGL will always need a ParentChange + // event to handle recreation/rebinding of the GL context, hence the + // (f & Qt::MSWindowsOwnDC) clause (which is set on QGLWidgets on all + // platforms). if (newParent -#ifdef Q_WS_WIN +#if defined(Q_WS_WIN) || defined(QT_OPENGL_ES) || (f & Qt::MSWindowsOwnDC) #endif ) { @@ -9687,7 +10201,8 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on) "QWidgetPrivate::high_attributes[] too small to contain all attributes in WidgetAttribute"); #ifdef Q_WS_WIN - if (attribute == Qt::WA_PaintOnScreen && on) { + // ### Don't use PaintOnScreen+paintEngine() to do native painting in 5.0 + if (attribute == Qt::WA_PaintOnScreen && on && !inherits("QGLWidget")) { // see qwidget_win.cpp, ::paintEngine for details paintEngine(); if (d->noPaintOnScreen) @@ -9815,28 +10330,8 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on) QEvent e(QEvent::MouseTrackingChange); QApplication::sendEvent(this, &e); break; } -#if !defined(QT_NO_DIRECT3D) && defined(Q_WS_WIN) - case Qt::WA_MSWindowsUseDirect3D: - if (!qApp->testAttribute(Qt::AA_MSWindowsUseDirect3DByDefault)) { - if (on) { - if (!d->extra) - d->createExtra(); - d->extra->had_auto_fill_bg = d->extra->autoFillBackground; - d->extra->had_no_system_bg = testAttribute(Qt::WA_NoSystemBackground); - d->extra->had_paint_on_screen = testAttribute(Qt::WA_PaintOnScreen); - // enforce the opaque widget state D3D needs - d->extra->autoFillBackground = true; - setAttribute(Qt::WA_PaintOnScreen); - setAttribute(Qt::WA_NoSystemBackground); - } else if (d->extra) { - d->extra->autoFillBackground = d->extra->had_auto_fill_bg; - setAttribute(Qt::WA_PaintOnScreen, d->extra->had_paint_on_screen); - setAttribute(Qt::WA_NoSystemBackground, d->extra->had_no_system_bg); - } - } - break; -#endif case Qt::WA_NativeWindow: { +#ifndef QT_NO_IM QInputContext *ic = 0; if (on && !internalWinId() && testAttribute(Qt::WA_InputMethodEnabled) && hasFocus()) { ic = d->inputContext(); @@ -9847,8 +10342,9 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on) parentWidget()->d_func()->enforceNativeChildren(); if (on && !internalWinId() && testAttribute(Qt::WA_WState_Created)) d->createWinId(); - if (ic) + if (ic && isEnabled()) ic->setFocusWidget(this); +#endif //QT_NO_IM break; } case Qt::WA_PaintOnScreen: @@ -9878,21 +10374,19 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on) #endif break; case Qt::WA_InputMethodEnabled: { -#if defined(Q_WS_WIN) || (defined(Q_WS_QWS) && !defined(QT_NO_QWS_INPUTMETHODS)) - if (hasFocus()) - QInputContextPrivate::updateImeStatus(this, true); -#endif +#ifndef QT_NO_IM QInputContext *ic = d->ic; if (!ic && (!on || hasFocus())) ic = d->inputContext(); if (ic) { - if (on && hasFocus() && ic->focusWidget() != this) { + if (on && hasFocus() && ic->focusWidget() != this && isEnabled()) { ic->setFocusWidget(this); } else if (!on && ic->focusWidget() == this) { ic->reset(); ic->setFocusWidget(0); } } +#endif //QT_NO_IM break; } case Qt::WA_WindowPropagation: @@ -9963,6 +10457,12 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on) } break; + case Qt::WA_AcceptTouchEvents: +#if defined(Q_WS_WIN) || defined(Q_WS_MAC) || defined(Q_WS_S60) + if (on) + d->registerTouchWindow(); +#endif + break; default: break; } @@ -9993,8 +10493,8 @@ bool QWidget::testAttribute_helper(Qt::WidgetAttribute attribute) const By default the value of this property is 1.0. - This feature is available on Embedded Linux, Mac OS X, X11 platforms that - support the Composite extension, and Windows 2000 and later. + This feature is available on Embedded Linux, Mac OS X, Windows, + and X11 platforms that support the Composite extension. This feature is not available on Windows CE. @@ -10318,7 +10818,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) { @@ -10965,6 +11465,91 @@ QRect QWidgetPrivate::frameStrut() const return maybeTopData() ? maybeTopData()->frameStrut : QRect(); } +#ifdef QT_KEYPAD_NAVIGATION +/*! + \internal + + Changes the focus from the current focusWidget to a widget in + the \a direction. + + Returns true, if there was a widget in that direction +*/ +bool QWidgetPrivate::navigateToDirection(Direction direction) +{ + QWidget *targetWidget = widgetInNavigationDirection(direction); + if (targetWidget) + targetWidget->setFocus(); + return (targetWidget != 0); +} + +/*! + \internal + + Searches for a widget that is positioned in the \a direction, starting + from the current focusWidget. + + Returns the pointer to a found widget or 0, if there was no widget in + that direction. +*/ +QWidget *QWidgetPrivate::widgetInNavigationDirection(Direction direction) +{ + const QWidget *sourceWidget = QApplication::focusWidget(); + if (!sourceWidget) + return 0; + const QRect sourceRect = sourceWidget->rect().translated(sourceWidget->mapToGlobal(QPoint())); + const int sourceX = + (direction == DirectionNorth || direction == DirectionSouth) ? + (sourceRect.left() + (sourceRect.right() - sourceRect.left()) / 2) + :(direction == DirectionEast ? sourceRect.right() : sourceRect.left()); + const int sourceY = + (direction == DirectionEast || direction == DirectionWest) ? + (sourceRect.top() + (sourceRect.bottom() - sourceRect.top()) / 2) + :(direction == DirectionSouth ? sourceRect.bottom() : sourceRect.top()); + const QPoint sourcePoint(sourceX, sourceY); + const QPoint sourceCenter = sourceRect.center(); + const QWidget *sourceWindow = sourceWidget->window(); + + QWidget *targetWidget = 0; + int shortestDistance = INT_MAX; + foreach(QWidget *targetCandidate, QApplication::allWidgets()) { + + const QRect targetCandidateRect = targetCandidate->rect().translated(targetCandidate->mapToGlobal(QPoint())); + + // For focus proxies, the child widget handling the focus can have keypad navigation focus, + // but the owner of the proxy cannot. + // Additionally, empty widgets should be ignored. + if (targetCandidate->focusProxy() || targetCandidateRect.isEmpty()) + continue; + + // Only navigate to a target widget that... + if ( targetCandidate != sourceWidget + // ...takes the focus, + && targetCandidate->focusPolicy() & Qt::TabFocus + // ...is above if DirectionNorth, + && !(direction == DirectionNorth && targetCandidateRect.bottom() > sourceRect.top()) + // ...is on the right if DirectionEast, + && !(direction == DirectionEast && targetCandidateRect.left() < sourceRect.right()) + // ...is below if DirectionSouth, + && !(direction == DirectionSouth && targetCandidateRect.top() < sourceRect.bottom()) + // ...is on the left if DirectionWest, + && !(direction == DirectionWest && targetCandidateRect.right() > sourceRect.left()) + // ...is enabled, + && targetCandidate->isEnabled() + // ...is visible, + && targetCandidate->isVisible() + // ...is in the same window, + && targetCandidate->window() == sourceWindow) { + const int targetCandidateDistance = pointToRect(sourcePoint, targetCandidateRect); + if (targetCandidateDistance < shortestDistance) { + shortestDistance = targetCandidateDistance; + targetWidget = targetCandidate; + } + } + } + return targetWidget; +} +#endif + /*! \preliminary \since 4.2 @@ -11123,8 +11708,6 @@ Q_GUI_EXPORT QWidgetPrivate *qt_widget_private(QWidget *widget) } - - #ifndef QT_NO_GRAPHICSVIEW /*! \since 4.5 @@ -11153,6 +11736,35 @@ QGraphicsProxyWidget *QWidget::graphicsProxyWidget() const Synonym for QList<QWidget *>. */ +/*! + Subscribes the widget to a given \a gesture with specific \a flags. + + \sa ungrabGesture(), QGestureEvent + \since 4.6 +*/ +void QWidget::grabGesture(Qt::GestureType gesture, Qt::GestureFlags flags) +{ + Q_D(QWidget); + d->gestureContext.insert(gesture, flags); + (void)QGestureManager::instance(); // create a gesture manager +} + +/*! + Unsubscribes the widget from a given \a gesture type + + \sa grabGesture(), QGestureEvent + \since 4.6 +*/ +void QWidget::ungrabGesture(Qt::GestureType gesture) +{ + Q_D(QWidget); + if (d->gestureContext.remove(gesture)) { + QGestureManager *manager = QGestureManager::instance(); + manager->cleanupCachedGestures(this, gesture); + } +} + + QT_END_NAMESPACE #include "moc_qwidget.cpp" @@ -11466,3 +12078,10 @@ void QWidget::clearMask() XRender extension is not supported on the X11 display, or if the handle could not be created. */ + +#ifdef Q_OS_SYMBIAN +void QWidgetPrivate::_q_delayedDestroy(WId winId) +{ + delete winId; +} +#endif diff --git a/src/gui/kernel/qwidget.h b/src/gui/kernel/qwidget.h index f66d590..05f0069 100644 --- a/src/gui/kernel/qwidget.h +++ b/src/gui/kernel/qwidget.h @@ -44,6 +44,7 @@ #include <QtGui/qwindowdefs.h> #include <QtCore/qobject.h> +#include <QtCore/qmargins.h> #include <QtGui/qpaintdevice.h> #include <QtGui/qpalette.h> #include <QtGui/qfont.h> @@ -95,6 +96,7 @@ class QIcon; class QWindowSurface; class QLocale; class QGraphicsProxyWidget; +class QGraphicsEffect; #if defined(Q_WS_X11) class QX11Info; #endif @@ -130,9 +132,6 @@ public: int alloc_region_index; // int alloc_region_revision; #endif -#if defined(Q_OS_WINCE) - uint window_state_internal : 4; -#endif QRect wrect; }; @@ -212,6 +211,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 { @@ -351,6 +351,12 @@ public: const QRegion &sourceRegion = QRegion(), RenderFlags renderFlags = RenderFlags(DrawWindowBackground | DrawChildren)); + QGraphicsEffect *graphicsEffect() const; + void setGraphicsEffect(QGraphicsEffect *effect); + + void grabGesture(Qt::GestureType type, Qt::GestureFlags flags = Qt::GestureFlags()); + void ungrabGesture(Qt::GestureType type); + public Q_SLOTS: void setWindowTitle(const QString &); #ifndef QT_NO_STYLE_STYLESHEET @@ -469,7 +475,7 @@ public Q_SLOTS: virtual void setVisible(bool visible); inline void setHidden(bool hidden) { setVisible(!hidden); } -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE inline void show() { setVisible(true); } #else void show(); @@ -521,7 +527,10 @@ public: QRegion visibleRegion() const; void setContentsMargins(int left, int top, int right, int bottom); + void setContentsMargins(const QMargins &margins); void getContentsMargins(int *left, int *top, int *right, int *bottom) const; + QMargins contentsMargins() const; + QRect contentsRect() const; public: @@ -539,6 +548,7 @@ public: QWidget *focusWidget() const; QWidget *nextInFocusChain() const; + QWidget *previousInFocusChain() const; // drag and drop bool acceptDrops() const; @@ -673,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: @@ -713,16 +727,17 @@ private: friend class QGLContext; friend class QGLWidget; friend class QGLWindowSurface; - friend class QVGWindowSurface; friend class QX11PaintEngine; friend class QWin32PaintEngine; friend class QShortcutPrivate; friend class QShortcutMap; friend class QWindowSurface; - friend class QD3DWindowSurface; friend class QGraphicsProxyWidget; friend class QGraphicsProxyWidgetPrivate; friend class QStyleSheetStyle; + friend struct QWidgetExceptionCleaner; + friend class QGestureManager; + friend class QWinNativePanGestureRecognizer; #ifdef Q_WS_MAC friend class QCoreGraphicsPaintEnginePrivate; @@ -744,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); @@ -755,6 +774,9 @@ private: private: Q_DISABLE_COPY(QWidget) Q_PRIVATE_SLOT(d_func(), void _q_showIfNotHidden()) +#ifdef Q_OS_SYMBIAN + Q_PRIVATE_SLOT(d_func(), void _q_delayedDestroy(WId winId)) +#endif QWidgetData *data; @@ -807,7 +829,7 @@ public: inline QT3_SUPPORT void setFont(const QFont &f, bool) { setFont(f); } inline QT3_SUPPORT void setPalette(const QPalette &p, bool) { setPalette(p); } enum BackgroundOrigin { WidgetOrigin, ParentOrigin, WindowOrigin, AncestorOrigin }; - inline QT3_SUPPORT void setBackgroundOrigin(BackgroundOrigin){}; + inline QT3_SUPPORT void setBackgroundOrigin(BackgroundOrigin) {} inline QT3_SUPPORT BackgroundOrigin backgroundOrigin() const { return WindowOrigin; } inline QT3_SUPPORT QPoint backgroundOffset() const { return QPoint(); } inline QT3_SUPPORT void repaint(bool) { repaint(); } diff --git a/src/gui/kernel/qwidget_mac.mm b/src/gui/kernel/qwidget_mac.mm index 89f2d02..278bd80 100644 --- a/src/gui/kernel/qwidget_mac.mm +++ b/src/gui/kernel/qwidget_mac.mm @@ -72,7 +72,6 @@ ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ** ****************************************************************************/ -//#define QT_RASTER_PAINTENGINE #include <private/qt_mac_p.h> #include <private/qeventdispatcher_mac_p.h> @@ -83,13 +82,11 @@ #include "qcursor.h" #include "qdesktopwidget.h" #include "qevent.h" +#include "qfileinfo.h" #include "qimage.h" #include "qlayout.h" #include "qmenubar.h" #include <private/qbackingstore_p.h> -#ifdef QT_RASTER_PAINTENGINE -# include <private/qpaintengine_raster_p.h> -#endif #include <private/qwindowsurface_mac_p.h> #include <private/qpaintengine_mac_p.h> #include "qpainter.h" @@ -110,6 +107,7 @@ #include <private/qcocoapanel_mac_p.h> #include "qwidget_p.h" +#include "qevent_p.h" #include "qdnd_p.h" #include <QtGui/qgraphicsproxywidget.h> @@ -303,6 +301,16 @@ 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]; +#else + Q_UNUSED(w); +#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)) @@ -390,21 +398,15 @@ QWidget *qt_mac_find_window(OSWindowRef window) inline static void qt_mac_set_fullscreen_mode(bool b) { - extern bool qt_mac_app_fullscreen; //qapplication_mac.cpp + extern bool qt_mac_app_fullscreen; //qapplication_mac.mm if(qt_mac_app_fullscreen == b) return; qt_mac_app_fullscreen = b; -#if QT_MAC_USE_COCOA - if(b) - SetSystemUIMode(kUIModeAllHidden, kUIOptionAutoShowMenuBar); - else + if (b) { + SetSystemUIMode(kUIModeAllSuppressed, 0); + } else { SetSystemUIMode(kUIModeNormal, 0); -#else - if(b) - HideMenuBar(); - else - ShowMenuBar(); -#endif + } } Q_GUI_EXPORT OSViewRef qt_mac_nativeview_for(const QWidget *w) @@ -511,16 +513,9 @@ static void qt_mac_release_window_group(WindowGroupRef group) SInt32 qt_mac_get_group_level(WindowClass wclass) { SInt32 group_level; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) { - CGWindowLevel tmpLevel; - GetWindowGroupLevelOfType(GetWindowGroupOfClass(wclass), kWindowGroupLevelActive, &tmpLevel); - group_level = tmpLevel; - } else -#endif - { - GetWindowGroupLevel(GetWindowGroupOfClass(wclass), &group_level); - } + CGWindowLevel tmpLevel; + GetWindowGroupLevelOfType(GetWindowGroupOfClass(wclass), kWindowGroupLevelActive, &tmpLevel); + group_level = tmpLevel; return group_level; } #endif @@ -734,6 +729,7 @@ static OSWindowRef qt_mac_create_window(QWidget *, WindowClass wclass, WindowAtt static EventTypeSpec window_events[] = { { kEventClassWindow, kEventWindowClose }, { kEventClassWindow, kEventWindowExpanded }, + { kEventClassWindow, kEventWindowHidden }, { kEventClassWindow, kEventWindowZoomed }, { kEventClassWindow, kEventWindowCollapsed }, { kEventClassWindow, kEventWindowToolbarSwitchMode }, @@ -741,12 +737,16 @@ static EventTypeSpec window_events[] = { { kEventClassWindow, kEventWindowProxyEndDrag }, { kEventClassWindow, kEventWindowResizeCompleted }, { kEventClassWindow, kEventWindowBoundsChanging }, - { kEventClassWindow, kEventWindowBoundsChanged }, { kEventClassWindow, kEventWindowGetRegion }, -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 { kEventClassWindow, kEventWindowGetClickModality }, -#endif { kEventClassWindow, kEventWindowTransitionCompleted }, +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 + { kEventClassGesture, kEventGestureStarted }, + { kEventClassGesture, kEventGestureEnded }, + { kEventClassGesture, kEventGestureMagnify }, + { kEventClassGesture, kEventGestureSwipe }, + { kEventClassGesture, kEventGestureRotate }, +#endif { kEventClassMouse, kEventMouseDown } }; static EventHandlerUPP mac_win_eventUPP = 0; @@ -775,7 +775,6 @@ OSStatus QWidgetPrivate::qt_window_event(EventHandlerCallRef er, EventRef event, QWidget *widget = qt_mac_find_window(wid); if(!widget) { handled_event = false; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 } else if(ekind == kEventWindowGetClickModality) { // Carbon will send us kEventWindowGetClickModality before every // mouse press / release event. By returning 'true', we tell Carbon @@ -786,7 +785,6 @@ OSStatus QWidgetPrivate::qt_window_event(EventHandlerCallRef er, EventRef event, // By also setting the current modal window back into the event, we // help Carbon determining which window is supposed to be raised. handled_event = qApp->activePopupWidget() ? true : false; -#endif } else if(ekind == kEventWindowClose) { widget->d_func()->close_helper(QWidgetPrivate::CloseWithSpontaneousEvent); QMenuBar::macUpdateMenuBar(); @@ -860,8 +858,7 @@ OSStatus QWidgetPrivate::qt_window_event(EventHandlerCallRef er, EventRef event, extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp qt_button_down = 0; } else if(ekind == kEventWindowToolbarSwitchMode) { - QToolBarChangeEvent ev(!(GetCurrentKeyModifiers() & cmdKey)); - QApplication::sendSpontaneousEvent(widget, &ev); + macSendToolbarChangeEvent(widget); HIToolbarRef toolbar; if (GetWindowToolbar(wid, &toolbar) == noErr) { if (toolbar) { @@ -909,90 +906,94 @@ OSStatus QWidgetPrivate::qt_window_event(EventHandlerCallRef er, EventRef event, SetEventParameter(mouseUpEvent, kEventParamMouseLocation, typeQDPoint, sizeof(pos), &pos); SendEventToApplication(mouseUpEvent); ReleaseEvent(mouseUpEvent); - } else if(ekind == kEventWindowBoundsChanging || ekind == kEventWindowBoundsChanged) { - // Panther doesn't send Changing for sheets, only changed, so only - // bother handling Changed event if we are on 10.3 and we are a - // sheet. - if (ekind == kEventWindowBoundsChanged - && (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4 - || !(widget->windowFlags() & Qt::Sheet))) { - handled_event = false; + } else if(ekind == kEventWindowBoundsChanging) { + UInt32 flags = 0; + GetEventParameter(event, kEventParamAttributes, typeUInt32, 0, + sizeof(flags), 0, &flags); + Rect nr; + GetEventParameter(event, kEventParamCurrentBounds, typeQDRectangle, 0, + sizeof(nr), 0, &nr); + + QRect newRect(nr.left, nr.top, nr.right - nr.left, nr.bottom - nr.top); + + QTLWExtra * const tlwExtra = widget->d_func()->maybeTopData(); + if (tlwExtra && tlwExtra->isSetGeometry == 1) { + widget->d_func()->setGeometry_sys_helper(newRect.left(), newRect.top(), newRect.width(), newRect.height(), tlwExtra->isMove); } else { - UInt32 flags = 0; - GetEventParameter(event, kEventParamAttributes, typeUInt32, 0, - sizeof(flags), 0, &flags); - Rect nr; - GetEventParameter(event, kEventParamCurrentBounds, typeQDRectangle, 0, - sizeof(nr), 0, &nr); - - QRect newRect(nr.left, nr.top, nr.right - nr.left, nr.bottom - nr.top); - - QTLWExtra * const tlwExtra = widget->d_func()->maybeTopData(); - if (tlwExtra && tlwExtra->isSetGeometry == 1) { - widget->d_func()->setGeometry_sys_helper(newRect.left(), newRect.top(), newRect.width(), newRect.height(), tlwExtra->isMove); - } else { - //implicitly removes the maximized bit - if((widget->data->window_state & Qt::WindowMaximized) && - IsWindowInStandardState(wid, 0, 0)) { - widget->data->window_state &= ~Qt::WindowMaximized; - QWindowStateChangeEvent e(Qt::WindowStates(widget->data->window_state - | Qt::WindowMaximized)); - QApplication::sendSpontaneousEvent(widget, &e); + //implicitly removes the maximized bit + if((widget->data->window_state & Qt::WindowMaximized) && + IsWindowInStandardState(wid, 0, 0)) { + widget->data->window_state &= ~Qt::WindowMaximized; + QWindowStateChangeEvent e(Qt::WindowStates(widget->data->window_state + | Qt::WindowMaximized)); + QApplication::sendSpontaneousEvent(widget, &e); - } + } - handled_event = false; - const QRect oldRect = widget->data->crect; - if((flags & kWindowBoundsChangeOriginChanged)) { - if(nr.left != oldRect.x() || nr.top != oldRect.y()) { - widget->data->crect.moveTo(nr.left, nr.top); - QMoveEvent qme(widget->data->crect.topLeft(), oldRect.topLeft()); - QApplication::sendSpontaneousEvent(widget, &qme); - } + handled_event = false; + const QRect oldRect = widget->data->crect; + if((flags & kWindowBoundsChangeOriginChanged)) { + if(nr.left != oldRect.x() || nr.top != oldRect.y()) { + widget->data->crect.moveTo(nr.left, nr.top); + QMoveEvent qme(widget->data->crect.topLeft(), oldRect.topLeft()); + QApplication::sendSpontaneousEvent(widget, &qme); } - if((flags & kWindowBoundsChangeSizeChanged)) { - if (widget->isWindow()) { - QSize newSize = QLayout::closestAcceptableSize(widget, newRect.size()); - int dh = newSize.height() - newRect.height(); - int dw = newSize.width() - newRect.width(); - if (dw != 0 || dh != 0) { - handled_event = true; // We want to change the bounds, so we handle the event - - // set the rect, so we can also do the resize down below (yes, we need to resize). - newRect.setBottom(newRect.bottom() + dh); - newRect.setRight(newRect.right() + dw); - - nr.left = newRect.x(); - nr.top = newRect.y(); - nr.right = nr.left + newRect.width(); - nr.bottom = nr.top + newRect.height(); - SetEventParameter(event, kEventParamCurrentBounds, typeQDRectangle, sizeof(Rect), &nr); - } + } + if((flags & kWindowBoundsChangeSizeChanged)) { + if (widget->isWindow()) { + QSize newSize = QLayout::closestAcceptableSize(widget, newRect.size()); + int dh = newSize.height() - newRect.height(); + int dw = newSize.width() - newRect.width(); + if (dw != 0 || dh != 0) { + handled_event = true; // We want to change the bounds, so we handle the event + + // set the rect, so we can also do the resize down below (yes, we need to resize). + newRect.setBottom(newRect.bottom() + dh); + newRect.setRight(newRect.right() + dw); + + nr.left = newRect.x(); + nr.top = newRect.y(); + nr.right = nr.left + newRect.width(); + nr.bottom = nr.top + newRect.height(); + SetEventParameter(event, kEventParamCurrentBounds, typeQDRectangle, sizeof(Rect), &nr); } + } - if (oldRect.width() != newRect.width() || oldRect.height() != newRect.height()) { - widget->data->crect.setSize(newRect.size()); - HIRect bounds = CGRectMake(0, 0, newRect.width(), newRect.height()); - - // If the WA_StaticContents attribute is set we can optimize the resize - // by only repainting the newly exposed area. We do this by disabling - // painting when setting the size of the view. The OS will invalidate - // the newly exposed area for us. - const bool staticContents = widget->testAttribute(Qt::WA_StaticContents); - const HIViewRef view = qt_mac_nativeview_for(widget); - if (staticContents) - HIViewSetDrawingEnabled(view, false); - HIViewSetFrame(view, &bounds); - if (staticContents) - HIViewSetDrawingEnabled(view, true); - - QResizeEvent qre(newRect.size(), oldRect.size()); - QApplication::sendSpontaneousEvent(widget, &qre); - qt_event_request_window_change(widget); - } + if (oldRect.width() != newRect.width() || oldRect.height() != newRect.height()) { + widget->data->crect.setSize(newRect.size()); + HIRect bounds = CGRectMake(0, 0, newRect.width(), newRect.height()); + + // If the WA_StaticContents attribute is set we can optimize the resize + // by only repainting the newly exposed area. We do this by disabling + // painting when setting the size of the view. The OS will invalidate + // the newly exposed area for us. + const bool staticContents = widget->testAttribute(Qt::WA_StaticContents); + const HIViewRef view = qt_mac_nativeview_for(widget); + if (staticContents) + HIViewSetDrawingEnabled(view, false); + HIViewSetFrame(view, &bounds); + if (staticContents) + HIViewSetDrawingEnabled(view, true); + + QResizeEvent qre(newRect.size(), oldRect.size()); + QApplication::sendSpontaneousEvent(widget, &qre); + qt_event_request_window_change(widget); } } } + } else if (ekind == kEventWindowHidden) { + // Make sure that we also hide any visible sheets on our window. + // Cocoa does the right thing for us. + const QObjectList children = widget->children(); + const int childCount = children.count(); + for (int i = 0; i < childCount; ++i) { + QObject *obj = children.at(i); + if (obj->isWidgetType()) { + QWidget *widget = static_cast<QWidget *>(obj); + if (qt_mac_is_macsheet(widget) && widget->isVisible()) + widget->hide(); + } + } } else { handled_event = false; } @@ -1030,6 +1031,76 @@ OSStatus QWidgetPrivate::qt_window_event(EventHandlerCallRef er, EventRef event, return SendEventToApplication(event); handled_event = false; break; } + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 + case kEventClassGesture: { + // First, find the widget that was under + // the mouse when the gesture happened: + HIPoint screenLocation; + if (GetEventParameter(event, kEventParamMouseLocation, typeHIPoint, 0, + sizeof(screenLocation), 0, &screenLocation) != noErr) { + handled_event = false; + break; + } + QWidget *widget = QApplication::widgetAt(screenLocation.x, screenLocation.y); + if (!widget) { + handled_event = false; + break; + } + + QNativeGestureEvent qNGEvent; + qNGEvent.position = QPoint(screenLocation.x, screenLocation.y); + + switch (ekind) { + case kEventGestureStarted: + qNGEvent.gestureType = QNativeGestureEvent::GestureBegin; + break; + case kEventGestureEnded: + qNGEvent.gestureType = QNativeGestureEvent::GestureEnd; + break; + case kEventGestureRotate: { + CGFloat amount; + if (GetEventParameter(event, kEventParamRotationAmount, typeCGFloat, 0, + sizeof(amount), 0, &amount) != noErr) { + handled_event = false; + break; + } + qNGEvent.gestureType = QNativeGestureEvent::Rotate; + qNGEvent.percentage = float(-amount); + break; } + case kEventGestureSwipe: { + HIPoint swipeDirection; + if (GetEventParameter(event, kEventParamSwipeDirection, typeHIPoint, 0, + sizeof(swipeDirection), 0, &swipeDirection) != noErr) { + handled_event = false; + break; + } + qNGEvent.gestureType = QNativeGestureEvent::Swipe; + if (swipeDirection.x == 1) + qNGEvent.angle = 180.0f; + else if (swipeDirection.x == -1) + qNGEvent.angle = 0.0f; + else if (swipeDirection.y == 1) + qNGEvent.angle = 90.0f; + else if (swipeDirection.y == -1) + qNGEvent.angle = 270.0f; + break; } + case kEventGestureMagnify: { + CGFloat amount; + if (GetEventParameter(event, kEventParamMagnificationAmount, typeCGFloat, 0, + sizeof(amount), 0, &amount) != noErr) { + handled_event = false; + break; + } + qNGEvent.gestureType = QNativeGestureEvent::Zoom; + qNGEvent.percentage = float(amount); + break; } + } + + QApplication::sendSpontaneousEvent(widget, &qNGEvent); + break; } +#endif // gestures + default: handled_event = false; } @@ -1129,23 +1200,9 @@ OSStatus QWidgetPrivate::qt_widget_event(EventHandlerCallRef er, EventRef event, //update handles GrafPtr qd = 0; CGContextRef cg = 0; -#ifndef QT_MAC_NO_QUICKDRAW - { - if(GetEventParameter(event, kEventParamGrafPort, typeGrafPtr, 0, sizeof(qd), 0, &qd) != noErr) { - GDHandle dev = 0; - GetGWorld(&qd, &dev); //just use the global port.. - } - } - bool end_cg_context = false; - if(GetEventParameter(event, kEventParamCGContextRef, typeCGContextRef, 0, sizeof(cg), 0, &cg) != noErr && qd) { - end_cg_context = true; - QDBeginCGContext(qd, &cg); - } -#else if(GetEventParameter(event, kEventParamCGContextRef, typeCGContextRef, 0, sizeof(cg), 0, &cg) != noErr) { Q_ASSERT(false); } -#endif widget->d_func()->hd = cg; widget->d_func()->qd_hd = qd; CGContextSaveGState(cg); @@ -1211,22 +1268,13 @@ OSStatus QWidgetPrivate::qt_widget_event(EventHandlerCallRef er, EventRef event, p.setClipping(false); if(was_unclipped) widget->setAttribute(Qt::WA_PaintUnclipped); - - QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea *>(widget->parent()); - QPoint scrollAreaOffset; - if (scrollArea && scrollArea->viewport() == widget) { - QAbstractScrollAreaPrivate *priv = static_cast<QAbstractScrollAreaPrivate *>(static_cast<QWidget *>(scrollArea)->d_ptr); - scrollAreaOffset = priv->contentsOffset(); - p.translate(-scrollAreaOffset); - } - - widget->d_func()->paintBackground(&p, qrgn, scrollAreaOffset, widget->isWindow() ? DrawAsRoot : 0); + widget->d_func()->paintBackground(&p, qrgn, widget->isWindow() ? DrawAsRoot : 0); if (widget->testAttribute(Qt::WA_TintedBackground)) { QColor tint = widget->palette().window().color(); tint.setAlphaF(.6); const QVector<QRect> &rects = qrgn.rects(); for (int i = 0; i < rects.size(); ++i) - p.fillRect(rects.at(i).translated(scrollAreaOffset), tint); + p.fillRect(rects.at(i), tint); } p.end(); if (!redirectionOffset.isNull()) @@ -1256,11 +1304,6 @@ OSStatus QWidgetPrivate::qt_widget_event(EventHandlerCallRef er, EventRef event, QApplication::sendSpontaneousEvent(widget, &e); if (!redirectionOffset.isNull()) widget->d_func()->restoreRedirected(); -#ifdef QT_RASTER_PAINTENGINE - if(engine && engine->type() == QPaintEngine::Raster) - static_cast<QRasterPaintEngine*>(engine)->flush(widget, - qrgn.boundingRect().topLeft()); -#endif //cleanup if (engine) @@ -1274,10 +1317,6 @@ OSStatus QWidgetPrivate::qt_widget_event(EventHandlerCallRef er, EventRef event, widget->d_func()->hd = 0; widget->d_func()->qd_hd = 0; CGContextRestoreGState(cg); -#ifndef QT_MAC_NO_QUICKDRAW - if(end_cg_context) - QDEndCGContext(qd, &cg); -#endif } else if(!HIObjectIsOfClass((HIObjectRef)hiview, kObjectQWidget)) { CallNextEventHandler(er, event); } @@ -1382,6 +1421,14 @@ OSStatus QWidgetPrivate::qt_widget_event(EventHandlerCallRef er, EventRef event, // Set dropWidget to zero, so qt_mac_dnd_event // doesn't get called a second time below: dropWidget = 0; + } else if (ekind == kEventControlDragLeave) { + dropWidget = QDragManager::self()->currentTarget(); + if (dropWidget) { + dropWidget->d_func()->qt_mac_dnd_event(kEventControlDragLeave, drag); + } + // Set dropWidget to zero, so qt_mac_dnd_event + // doesn't get called a second time below: + dropWidget = 0; } } } @@ -1598,24 +1645,6 @@ bool QWidgetPrivate::qt_create_root_win() return true; } -bool QWidgetPrivate::qt_recreate_root_win() -{ - if(!qt_root_win) //sanity check - return false; - //store old - OSWindowRef old_root_win = qt_root_win; - //recreate - qt_root_win = 0; - qt_create_root_win(); - //cleanup old window -#ifdef QT_MAC_USE_COCOA - [old_root_win release]; -#else - CFRelease(old_root_win); -#endif - return true; -} - bool QWidgetPrivate::qt_widget_rgn(QWidget *widget, short wcode, RgnHandle rgn, bool force = false) { bool ret = false; @@ -1716,17 +1745,11 @@ void QWidgetPrivate::determineWindowClass() bool framelessWindow = (flags & Qt::FramelessWindowHint || (customize && !(flags & Qt::WindowTitleHint))); if (framelessWindow) { if(wclass == kDocumentWindowClass) { - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) - wattr |= kWindowNoTitleBarAttribute; - else - wclass = kPlainWindowClass; + wattr |= kWindowNoTitleBarAttribute; } else if(wclass == kFloatingWindowClass) { - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) - wattr |= kWindowNoTitleBarAttribute; - else - wclass = kToolbarWindowClass; + wattr |= kWindowNoTitleBarAttribute; } else if (wclass == kMovableModalWindowClass) { - wclass = kModalWindowClass; + wclass = kModalWindowClass; } } else { if(wclass != kModalWindowClass) @@ -2024,14 +2047,10 @@ void QWidgetPrivate::finishCreateWindow_sys_Carbon(OSWindowRef windowRef) if (!desktop) SetAutomaticControlDragTrackingEnabledForWindow(windowRef, true); HIWindowChangeFeatures(windowRef, kWindowCanCollapse, 0); -#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) { - if (wattr & kWindowHideOnSuspendAttribute) - HIWindowChangeAvailability(windowRef, kHIWindowExposeHidden, 0); - else - HIWindowChangeAvailability(windowRef, 0, kHIWindowExposeHidden); - } -#endif + if (wattr & kWindowHideOnSuspendAttribute) + HIWindowChangeAvailability(windowRef, kHIWindowExposeHidden, 0); + else + HIWindowChangeAvailability(windowRef, 0, kHIWindowExposeHidden); if ((flags & Qt::WindowStaysOnTopHint)) ChangeWindowAttributes(windowRef, kWindowNoAttributes, kWindowHideOnSuspendAttribute); if (qt_mac_is_macdrawer(q) && parentWidget) @@ -2305,7 +2324,7 @@ void QWidgetPrivate::createWindow_sys() OSWindowRef windowRef = qt_mac_create_window(q, topExtra->wclass, wattr, data.crect); if (windowRef == 0) - qWarning("QWidget: Internal error: %s:%d: If you reach this error please contact Trolltech and include the\n" + qWarning("QWidget: Internal error: %s:%d: If you reach this error please contact Qt Support and include the\n" " WidgetFlags used in creating the widget.", __FILE__, __LINE__); #ifndef QT_MAC_USE_COCOA finishCreateWindow_sys_Carbon(windowRef); @@ -2524,9 +2543,10 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO setFocus_sys(); if (!topLevel && initializeWindow) setWSGeometry(); - if (destroyid) qt_mac_destructView(destroyid); + if (q->testAttribute(Qt::WA_AcceptTouchEvents)) + registerTouchWindow(); } /*! @@ -2564,7 +2584,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)) { @@ -2615,7 +2635,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 + } } } @@ -2666,7 +2690,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. @@ -2899,8 +2923,7 @@ void QWidgetPrivate::setWindowTitle_sys(const QString &caption) SetWindowTitleWithCFString(qt_mac_window_for(q), QCFString(caption)); #else QMacCocoaAutoReleasePool pool; - [qt_mac_window_for(q) - setTitle:reinterpret_cast<const NSString *>(static_cast<CFStringRef>(QCFString(caption)))]; + [qt_mac_window_for(q) setTitle:qt_mac_QStringToNSString(caption)]; #endif } } @@ -2922,7 +2945,8 @@ void QWidgetPrivate::setWindowFilePath_sys(const QString &filePath) Q_Q(QWidget); #ifdef QT_MAC_USE_COCOA QMacCocoaAutoReleasePool pool; - [qt_mac_window_for(q) setRepresentedFilename:reinterpret_cast<const NSString *>(static_cast<CFStringRef>(QCFString(filePath)))]; + QFileInfo fi(filePath); + [qt_mac_window_for(q) setRepresentedFilename:fi.exists() ? qt_mac_QStringToNSString(filePath) : @""]; #else bool validRef = false; FSRef ref; @@ -2935,21 +2959,10 @@ void QWidgetPrivate::setWindowFilePath_sys(const QString &filePath) } // Set the proxy regardless, since this is our way of clearing it as well, but ignore the // return value as well. - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) { - if (validRef) { - status = HIWindowSetProxyFSRef(qt_mac_window_for(q), &ref); - } else { - status = RemoveWindowProxy(qt_mac_window_for(q)); - } + if (validRef) { + status = HIWindowSetProxyFSRef(qt_mac_window_for(q), &ref); } else { - // Convert to an FSSpec and set it. It's deprecated but it works for where we don't have the other call. - if (validRef) { - FSSpec fsspec; - FSGetCatalogInfo(&ref, kFSCatInfoNone, 0, 0, &fsspec, 0); - status = SetWindowProxyFSSpec(qt_mac_window_for(q), &fsspec); - } else { - status = RemoveWindowProxy(qt_mac_window_for(q)); - } + status = RemoveWindowProxy(qt_mac_window_for(q)); } if (status != noErr) qWarning("QWidget::setWindowFilePath: Error setting proxyicon for path (%s):%ld", @@ -3004,10 +3017,17 @@ void QWidgetPrivate::setWindowIcon_sys(bool forceReset) #else QMacCocoaAutoReleasePool pool; NSButton *iconButton = [qt_mac_window_for(q) standardWindowButton:NSWindowDocumentIconButton]; + if (iconButton == nil) { + QCFString string(q->windowTitle()); + const NSString *tmpString = reinterpret_cast<const NSString *>((CFStringRef)string); + [qt_mac_window_for(q) setRepresentedURL:[NSURL fileURLWithPath:tmpString]]; + iconButton = [qt_mac_window_for(q) standardWindowButton:NSWindowDocumentIconButton]; + } if (icon.isNull()) { [iconButton setImage:nil]; } else { - NSImage *image = static_cast<NSImage *>(qt_mac_create_nsimage(*pm)); + QPixmap scaled = pm->scaled(QSize(16,16), Qt::KeepAspectRatio, Qt::SmoothTransformation); + NSImage *image = static_cast<NSImage *>(qt_mac_create_nsimage(scaled)); [iconButton setImage:image]; [image release]; } @@ -3023,8 +3043,7 @@ void QWidgetPrivate::setWindowIconText_sys(const QString &iconText) SetWindowAlternateTitle(qt_mac_window_for(q), QCFString(iconText)); #else QMacCocoaAutoReleasePool pool; - [qt_mac_window_for(q) - setMiniwindowTitle:reinterpret_cast<const NSString *>(static_cast<CFStringRef>(QCFString(iconText)))]; + [qt_mac_window_for(q) setMiniwindowTitle:qt_mac_QStringToNSString(iconText)]; #endif } } @@ -3038,6 +3057,7 @@ void QWidget::grabMouse() } } +#ifndef QT_NO_CURSOR void QWidget::grabMouse(const QCursor &) { if(isVisible() && !qt_nograb()) { @@ -3046,6 +3066,7 @@ void QWidget::grabMouse(const QCursor &) mac_mouse_grabber=this; } } +#endif void QWidget::releaseMouse() { @@ -3157,16 +3178,9 @@ void QWidgetPrivate::update_sys(const QRect &r) if (updateRedirectedToGraphicsProxyWidget(q, updateRect)) return; #ifndef QT_MAC_USE_COCOA -# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) { - dirtyOnWidget += updateRect; - HIRect r = CGRectMake(x, y, w, h); - HIViewSetNeedsDisplayInRect(qt_mac_nativeview_for(q), &r, true); - } else - #endif - { - q->update(QRegion(updateRect)); - } + dirtyOnWidget += updateRect; + HIRect r = CGRectMake(x, y, w, h); + HIViewSetNeedsDisplayInRect(qt_mac_nativeview_for(q), &r, true); #else [qt_mac_nativeview_for(q) setNeedsDisplayInRect:NSMakeRect(x, y, w, h)]; #endif @@ -3180,7 +3194,12 @@ void QWidgetPrivate::update_sys(const QRegion &rgn) return; dirtyOnWidget += rgn; #ifndef QT_MAC_USE_COCOA - HIViewSetNeedsDisplayInRegion(qt_mac_nativeview_for(q), QMacSmartQuickDrawRegion(rgn.toQDRgn()), true); + RgnHandle rgnHandle = rgn.toQDRgnForUpdate_sys(); + if (rgnHandle) + HIViewSetNeedsDisplayInRegion(qt_mac_nativeview_for(q), QMacSmartQuickDrawRegion(rgnHandle), true); + else { + HIViewSetNeedsDisplay(qt_mac_nativeview_for(q), true); // do a complete repaint on overflow. + } #else // Cocoa doesn't do regions, it seems more efficient to just update the bounding rect instead of a potential number of message passes for each rect. const QRect &boundingRect = rgn.boundingRect(); @@ -3272,10 +3291,13 @@ void QWidgetPrivate::show_sys() #else // sync the opacity value back (in case of a fade). [window setAlphaValue:q->windowOpacity()]; - [window makeKeyAndOrderFront:window]; + + // If this window is app modal, we need to start spinning + // a modal session for it. Interrupting + // the event dispatcher will make this happend: if (data.window_modality == Qt::ApplicationModal) - QCoreApplication::postEvent(qApp, new QEvent(QEvent::CocoaRequestModal)); + QEventDispatcherMac::instance()->interrupt(); #endif if (q->windowType() == Qt::Popup) { if (q->focusWidget()) @@ -3292,13 +3314,10 @@ void QWidgetPrivate::show_sys() [window miniaturize:window]; #endif } else if (!q->testAttribute(Qt::WA_ShowWithoutActivating)) { +#ifndef QT_MAC_USE_COCOA qt_event_request_activate(q); -#ifdef QT_MAC_USE_COCOA - if (q->windowModality() == Qt::ApplicationModal) { - // We call 'activeModalSession' early to force creation of q's modal - // session. This seems neccessary for child dialogs to pop to front: - QEventDispatcherMacPrivate::activeModalSession(); - } +#else + [qt_mac_window_for(q) makeKeyWindow]; #endif } } else if(topData()->embedded || !q->parentWidget() || q->parentWidget()->isVisible()) { @@ -3380,12 +3399,19 @@ void QWidgetPrivate::hide_sys() w = q->parentWidget()->window(); if(!w || (!w->isVisible() && !w->isMinimized())) { #ifndef QT_MAC_USE_COCOA - for(WindowPtr wp = GetFrontWindowOfClass(kDocumentWindowClass, true); - wp; wp = GetNextWindowOfClass(wp, kDocumentWindowClass, true)) { + for (WindowPtr wp = GetFrontWindowOfClass(kMovableModalWindowClass, true); + wp; wp = GetNextWindowOfClass(wp, kMovableModalWindowClass, true)) { if((w = qt_mac_find_window(wp))) break; } if (!w){ + for (WindowPtr wp = GetFrontWindowOfClass(kDocumentWindowClass, true); + wp; wp = GetNextWindowOfClass(wp, kDocumentWindowClass, true)) { + if((w = qt_mac_find_window(wp))) + break; + } + } + if (!w){ for(WindowPtr wp = GetFrontWindowOfClass(kSimpleWindowClass, true); wp; wp = GetNextWindowOfClass(wp, kSimpleWindowClass, true)) { if((w = qt_mac_find_window(wp))) @@ -3402,8 +3428,13 @@ void QWidgetPrivate::hide_sys() } #endif } - if(w && w->isVisible() && !w->isMinimized()) - qt_event_request_activate(w); + if(w && w->isVisible() && !w->isMinimized()) { +#ifndef QT_MAC_USE_COCOA + qt_event_request_activate(w); +#else + [qt_mac_window_for(w) makeKeyWindow]; +#endif + } } } else { invalidateBuffer(q->rect()); @@ -3887,8 +3918,6 @@ void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &oldRect) Qt coordinate system for parent X coordinate system for parent (relative to parent's wrect). */ - QRect validRange(-XCOORD_MAX,-XCOORD_MAX, 2*XCOORD_MAX, 2*XCOORD_MAX); - QRect wrectRange(-WRECT_MAX,-WRECT_MAX, 2*WRECT_MAX, 2*WRECT_MAX); QRect wrect; //xrect is the X geometry of my X widget. (starts out in parent's Qt coord sys, and ends up in parent's X coord sys) QRect xrect = data.crect; @@ -3910,6 +3939,7 @@ void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &oldRect) parentWRect = QRect(tmpRect.origin.x, tmpRect.origin.y, tmpRect.size.width, tmpRect.size.height); } else { + const QRect wrectRange(-WRECT_MAX,-WRECT_MAX, 2*WRECT_MAX, 2*WRECT_MAX); parentWRect = wrectRange; } } else { @@ -3965,15 +3995,24 @@ void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &oldRect) } } + const QRect validRange(-XCOORD_MAX,-XCOORD_MAX, 2*XCOORD_MAX, 2*XCOORD_MAX); if (!validRange.contains(xrect)) { // we are too big, and must clip - xrect &=wrectRange; + QPoint screenOffset(0, 0); // offset of the part being on screen + const QWidget *parentWidget = q->parentWidget(); + while (parentWidget && !parentWidget->isWindow()) { + screenOffset -= parentWidget->data->crect.topLeft(); + parentWidget = parentWidget->parentWidget(); + } + QRect cropRect(screenOffset.x() - WRECT_MAX, + screenOffset.y() - WRECT_MAX, + 2*WRECT_MAX, + 2*WRECT_MAX); + + xrect &=cropRect; wrect = xrect; - wrect.translate(-data.crect.topLeft()); - //parent's X coord system is equal to parent's Qt coord - //sys, so we don't need to map xrect. + wrect.translate(-data.crect.topLeft()); // translate wrect in my Qt coordinates } - } // unmap if we are outside the valid window system coord system @@ -4013,10 +4052,9 @@ void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &oldRect) qt_mac_update_widget_posisiton(q, oldRect, xrect); - if (jump) { - updateSystemBackground(); + if (jump) q->update(); - } + if (mapWindow && !dontShow) { q->setAttribute(Qt::WA_Mapped); #ifndef QT_MAC_USE_COCOA @@ -4178,12 +4216,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)); } } } @@ -4337,32 +4375,14 @@ void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r) OSViewRef view = qt_mac_nativeview_for(q); #ifndef QT_MAC_USE_COCOA HIRect scrollrect = CGRectMake(r.x(), r.y(), r.width(), r.height()); -# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) { - OSStatus err = _HIViewScrollRectWithOptions(view, valid_rect ? &scrollrect : 0, dx, dy, kHIViewScrollRectAdjustInvalid); - if (err) { - // The only parameter that can go wrong, is the rect. - qWarning("QWidget::scroll: Your rectangle was too big for the widget, clipping rect"); - scrollrect = CGRectMake(qMax(r.x(), 0), qMax(r.y(), 0), - qMin(r.width(), q->width()), qMin(r.height(), q->height())); - _HIViewScrollRectWithOptions(view, valid_rect ? &scrollrect : 0, dx, dy, kHIViewScrollRectAdjustInvalid); - } - } else { - if (HIViewGetNeedsDisplay(view)) { - q->update(valid_rect ? r : q->rect()); - return; - } - HIRect scrollrect = CGRectMake(r.x(), r.y(), r.width(), r.height()); - OSStatus err = HIViewScrollRect(view, valid_rect ? &scrollrect : 0, dx, dy); - if (err) { - // The only parameter that can go wrong, is the rect. - qWarning("QWidget::scroll: Your rectangle was too big for the widget, clipping rect"); - scrollrect = CGRectMake(qMax(r.x(), 0), qMax(r.y(), 0), - qMin(r.width(), q->width()), qMin(r.height(), q->height())); - HIViewScrollRect(view, valid_rect ? &scrollrect : 0, dx, dy); - } + OSStatus err = _HIViewScrollRectWithOptions(view, valid_rect ? &scrollrect : 0, dx, dy, kHIViewScrollRectAdjustInvalid); + if (err) { + // The only parameter that can go wrong, is the rect. + qWarning("QWidget::scroll: Your rectangle was too big for the widget, clipping rect"); + scrollrect = CGRectMake(qMax(r.x(), 0), qMax(r.y(), 0), + qMin(r.width(), q->width()), qMin(r.height(), q->height())); + _HIViewScrollRectWithOptions(view, valid_rect ? &scrollrect : 0, dx, dy, kHIViewScrollRectAdjustInvalid); } -# endif #else NSRect scrollRect = valid_rect ? NSMakeRect(r.x(), r.y(), r.width(), r.height()) : NSMakeRect(0, 0, q->width(), q->height()); @@ -4390,20 +4410,9 @@ void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r) } } - // ### Scroll the dirty regions as well, the following is not correct. - QRegion displayRegion = r.isNull() ? dirtyOnWidget : (dirtyOnWidget & r); - const QVector<QRect> &rects = dirtyOnWidget.rects(); - const QVector<QRect>::const_iterator end = rects.end(); - QVector<QRect>::const_iterator it = rects.begin(); - while (it != end) { - const QRect rect = *it; - const NSRect dirtyRect = NSMakeRect(rect.x() + dx, rect.y() + dy, - rect.width(), rect.height()); - [view setNeedsDisplayInRect:dirtyRect]; - ++it; - } - [view scrollRect:scrollRect by:NSMakeSize(dx, dy)]; - // Yes, we potentially send a duplicate area, but I think Cocoa can handle it. + NSSize deltaSize = NSMakeSize(dx, dy); + [view translateRectsNeedingDisplayInRect:scrollRect by:deltaSize]; + [view scrollRect:scrollRect by:deltaSize]; [view setNeedsDisplayInRect:deltaXRect]; [view setNeedsDisplayInRect:deltaYRect]; #endif // QT_MAC_USE_COCOA @@ -4473,11 +4482,13 @@ void QWidgetPrivate::deleteSysExtra() void QWidgetPrivate::createTLSysExtra() { + extra->topextra->resizer = 0; + extra->topextra->isSetGeometry = 0; + extra->topextra->isMove = 0; + extra->topextra->wattr = 0; extra->topextra->wclass = 0; extra->topextra->group = 0; extra->topextra->windowIcon = 0; - extra->topextra->resizer = 0; - extra->topextra->isSetGeometry = 0; extra->topextra->savedWindowAttributesFromMaximized = 0; } @@ -4532,6 +4543,23 @@ void QWidgetPrivate::registerDropSite(bool on) #endif } +void QWidgetPrivate::registerTouchWindow() +{ +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 + if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_6) + return; + Q_Q(QWidget); + if (!q->testAttribute(Qt::WA_WState_Created)) + return; +#ifndef QT_MAC_USE_COCOA + // Needs implementation! +#else + NSView *view = qt_mac_nativeview_for(q); + [view setAcceptsTouchEvents:YES]; +#endif +#endif +} + void QWidgetPrivate::setMask_sys(const QRegion ®ion) { Q_UNUSED(region); @@ -4552,14 +4580,6 @@ void QWidgetPrivate::setMask_sys(const QRegion ®ion) #endif } -extern "C" { - typedef struct CGSConnection *CGSConnectionRef; - typedef struct CGSWindow *CGSWindowRef; - extern OSStatus CGSSetWindowAlpha(CGSConnectionRef, CGSWindowRef, float); - extern CGSWindowRef GetNativeWindowFromWindowRef(WindowRef); - extern CGSConnectionRef _CGSDefaultConnection(); -} - void QWidgetPrivate::setWindowOpacity_sys(qreal level) { Q_Q(QWidget); @@ -4572,12 +4592,11 @@ void QWidgetPrivate::setWindowOpacity_sys(qreal level) if (!q->testAttribute(Qt::WA_WState_Created)) return; -#if QT_MAC_USE_COCOA OSWindowRef oswindow = qt_mac_window_for(q); +#if QT_MAC_USE_COCOA [oswindow setAlphaValue:level]; #else - CGSSetWindowAlpha(_CGSDefaultConnection(), - GetNativeWindowFromWindowRef(qt_mac_window_for(q)), level); + SetWindowAlpha(oswindow, level); #endif } @@ -4649,21 +4668,6 @@ Q_GLOBAL_STATIC(QPaintEngineCleanupHandler, engineHandler) QPaintEngine *QWidget::paintEngine() const { QPaintEngine *&pe = engineHandler()->engine; -#ifdef QT_RASTER_PAINTENGINE - if (!pe) { - if(qgetenv("QT_MAC_USE_COREGRAPHICS").isNull()) - pe = new QRasterPaintEngine(); - else - pe = new QCoreGraphicsPaintEngine(); - } - if (pe->isActive()) { - QPaintEngine *engine = - qgetenv("QT_MAC_USE_COREGRAPHICS").isNull() - ? (QPaintEngine*)new QRasterPaintEngine() : (QPaintEngine*)new QCoreGraphicsPaintEngine(); - engine->setAutoDestruct(true); - return engine; - } -#else if (!pe) pe = new QCoreGraphicsPaintEngine(); if (pe->isActive()) { @@ -4671,7 +4675,6 @@ QPaintEngine *QWidget::paintEngine() const engine->setAutoDestruct(true); return engine; } -#endif return pe; } @@ -4931,11 +4934,9 @@ void QWidgetPrivate::macUpdateMetalAttribute() if (layout) layout->updateHIToolBarStatus(); ChangeWindowAttributes(qt_mac_window_for(q), kWindowMetalAttribute, 0); - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) - ChangeWindowAttributes(qt_mac_window_for(q), kWindowMetalNoContentSeparatorAttribute, 0); + ChangeWindowAttributes(qt_mac_window_for(q), kWindowMetalNoContentSeparatorAttribute, 0); } else { - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) - ChangeWindowAttributes(qt_mac_window_for(q), 0, kWindowMetalNoContentSeparatorAttribute); + ChangeWindowAttributes(qt_mac_window_for(q), 0, kWindowMetalNoContentSeparatorAttribute); ChangeWindowAttributes(qt_mac_window_for(q), 0, kWindowMetalAttribute); if (layout) layout->updateHIToolBarStatus(); diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index 2b09220..8b03a85 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -57,9 +57,16 @@ #include "private/qobject_p.h" #include "QtCore/qrect.h" #include "QtCore/qlocale.h" +#include "QtCore/qset.h" #include "QtGui/qregion.h" #include "QtGui/qsizepolicy.h" #include "QtGui/qstyle.h" +#include "QtGui/qapplication.h" +#include <private/qgraphicseffect_p.h> +#include "QtGui/qgraphicsproxywidget.h" +#include "QtGui/qgraphicsscene.h" +#include "QtGui/qgraphicsview.h" +#include <private/qgesture_p.h> #ifdef Q_WS_WIN #include "QtCore/qt_windows.h" @@ -79,6 +86,11 @@ #include "QtGui/qscreen_qws.h" #endif +#if defined(Q_OS_SYMBIAN) +class RDrawableWindow; +class CCoeControl; +#endif + QT_BEGIN_NAMESPACE // Extra QWidget data @@ -99,93 +111,100 @@ class QWidgetItemV2; class QStyle; struct QTLWExtra { + // *************************** Cross-platform variables ***************************** + + // Regular pointers (keep them together to avoid gaps on 64 bits architectures). + QIcon *icon; // widget icon + QPixmap *iconPixmap; + QWidgetBackingStore *backingStore; + QWindowSurface *windowSurface; + QPainter *sharedPainter; + + // Implicit pointers (shared_null). QString caption; // widget caption QString iconText; // widget icon text QString role; // widget role QString filePath; // widget file path - QIcon *icon; // widget icon - QPixmap *iconPixmap; + + // Other variables. short incw, inch; // size increments + short basew, baseh; // base sizes // frame strut, don't use these directly, use QWidgetPrivate::frameStrut() instead. QRect frameStrut; + QRect normalGeometry; // used by showMin/maximized/FullScreen + Qt::WindowFlags savedFlags; // Save widget flags while showing fullscreen + + // *************************** Cross-platform bit fields **************************** uint opacity : 8; uint posFromMove : 1; uint sizeAdjusted : 1; uint inTopLevelResize : 1; uint inRepaint : 1; - QWidgetBackingStore *backingStore; -#if defined(Q_WS_WIN) - ulong savedFlags; // Save window flags while showing fullscreen - uint embedded : 1; // window is embedded in another application -#else - Qt::WindowFlags savedFlags; // Save widget flags while showing fullscreen -#endif - short basew, baseh; // base sizes -#if defined(Q_WS_X11) - WId parentWinId; // parent window Id (valid after reparenting) - uint embedded : 1; // window is embedded in another Qt application + uint embedded : 1; + + // *************************** Platform specific values (bit fields first) ********** +#if defined(Q_WS_X11) // <----------------------------------------------------------- X11 uint spont_unmapped: 1; // window was spontaneously unmapped uint dnd : 1; // DND properties installed uint validWMState : 1; // is WM_STATE valid? uint waitingForMapNotify : 1; // show() has been called, haven't got the MapNotify yet + WId parentWinId; // parent window Id (valid after reparenting) WId userTimeWindow; // window id that contains user-time timestamp when WM supports a _NET_WM_USER_TIME_WINDOW atom QPoint fullScreenOffset; +#ifndef QT_NO_XSYNC + WId syncUpdateCounter; + ulong syncRequestTimestamp; + qint32 newCounterValueHi; + quint32 newCounterValueLo; #endif -#if defined(Q_WS_MAC) +#elif defined(Q_WS_WIN) // <--------------------------------------------------------- WIN + HICON winIconBig; // internal big Windows icon + HICON winIconSmall; // internal small Windows icon +#elif defined(Q_WS_MAC) // <--------------------------------------------------------- MAC + uint resizer : 4; + uint isSetGeometry : 1; + uint isMove : 1; quint32 wattr; quint32 wclass; WindowGroupRef group; IconRef windowIcon; // the current window icon, if set with setWindowIcon_sys. quint32 savedWindowAttributesFromMaximized; // Saved attributes from when the calling updateMaximizeButton_sys() - uint resizer : 4; - uint isSetGeometry : 1; - uint isMove : 1; - uint embedded : 1; -#endif -#if defined(Q_WS_QWS) && !defined (QT_NO_QWS_MANAGER) +#elif defined(Q_WS_QWS) // <--------------------------------------------------------- QWS +#ifndef QT_NO_QWS_MANAGER QWSManager *qwsManager; #endif -#if defined(Q_WS_WIN) - HICON winIconBig; // internal big Windows icon - HICON winIconSmall; // internal small Windows icon #endif - QRect normalGeometry; // used by showMin/maximized/FullScreen - QWindowSurface *windowSurface; - QPainter *sharedPainter; }; struct QWExtra { - qint32 minw, minh; // minimum size - qint32 maxw, maxh; // maximum size - QPointer<QWidget> focus_proxy; -#ifndef QT_NO_CURSOR - QCursor *curs; -#endif + // *************************** Cross-platform variables ***************************** + + // Regular pointers (keep them together to avoid gaps on 64 bits architectures). + void *glContext; // if the widget is hijacked by QGLWindowSurface QTLWExtra *topextra; // only useful for TLWs +#ifndef QT_NO_GRAPHICSVIEW QGraphicsProxyWidget *proxyWidget; // if the widget is embedded - void *glContext; // if the widget is hijacked by QGLWindowSurface -#if defined(Q_WS_WIN) && !defined(QT_NO_DRAGANDDROP) - QOleDropTarget *dropTarget; // drop target - QList<QPointer<QWidget> > oleDropWidgets; #endif -#if defined(Q_WS_X11) - WId xDndProxy; // XDND forwarding to embedded windows +#ifndef QT_NO_CURSOR + QCursor *curs; #endif + QPointer<QStyle> style; + QPointer<QWidget> focus_proxy; + + // Implicit pointers (shared_empty/shared_null). QRegion mask; // widget mask + QString styleSheet; + + // Other variables. + qint32 minw; + qint32 minh; // minimum size + qint32 maxw; + qint32 maxh; // maximum size + quint16 customDpiX; + quint16 customDpiY; QSize staticContentsSize; -//bit flags at the end to improve packing -#if defined(Q_WS_WIN) - uint shown_mode : 8; // widget show mode -#ifndef QT_NO_DIRECT3D - uint had_paint_on_screen : 1; - uint had_no_system_bg : 1; - uint had_auto_fill_bg : 1; -#endif -#endif -#if defined(Q_WS_X11) - uint compress_events : 1; -#endif + // *************************** Cross-platform bit fields **************************** uint explicitMinSize : 2; uint explicitMaxSize : 2; uint autoFillBackground : 1; @@ -193,23 +212,81 @@ struct QWExtra { uint inRenderWithPainter : 1; uint hasMask : 1; - QPointer<QStyle> style; - QString styleSheet; - - quint16 customDpiX; - quint16 customDpiY; -#if defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA) + // *************************** Platform specific values (bit fields first) ********** +#if defined(Q_WS_WIN) // <----------------------------------------------------------- WIN +#ifndef QT_NO_DRAGANDDROP + QOleDropTarget *dropTarget; // drop target + QList<QPointer<QWidget> > oleDropWidgets; +#endif +#elif defined(Q_WS_X11) // <--------------------------------------------------------- X11 + uint compress_events : 1; + WId xDndProxy; // XDND forwarding to embedded windows +#elif defined(Q_WS_MAC) // <------------------------------------------------------ MAC +#ifdef QT_MAC_USE_COCOA // Cocoa Mask stuff QImage maskBits; CGImageRef imageMask; #endif +#elif defined(Q_OS_SYMBIAN) // <----------------------------------------------------- Symbian + uint activated : 1; // RWindowBase::Activated has been called + + // If set, QSymbianControl::Draw does not blit this widget + // This is to allow, for use cases such as video, widgets which, from the Qt point + // of view, are just placeholders in the scene. For these widgets, any necessary + // drawing to the UI framebuffer is done by the relevant Symbian subsystem. For + // video rendering, this would be an MMF controller, or MDF post-processor. + uint disableBlit : 1; +#endif }; +/*! + \internal + + Returns true if \a p or any of its parents enable the + Qt::BypassGraphicsProxyWidget window flag. Used in QWidget::show() and + QWidget::setParent() to determine whether it's necessary to embed the + widget into a QGraphicsProxyWidget or not. +*/ +static inline bool bypassGraphicsProxyWidget(const QWidget *p) +{ + while (p) { + if (p->windowFlags() & Qt::BypassGraphicsProxyWidget) + return true; + p = p->parentWidget(); + } + return false; +} + class Q_GUI_EXPORT QWidgetPrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QWidget) public: + // *************************** Cross-platform *************************************** + enum DrawWidgetFlags { + DrawAsRoot = 0x01, + DrawPaintOnScreen = 0x02, + DrawRecursive = 0x04, + DrawInvisible = 0x08, + DontSubtractOpaqueChildren = 0x10, + DontSetCompositionMode = 0x20, + DontDrawOpaqueChildren = 0x40 + }; + + enum CloseMode { + CloseNoEvent, + CloseWithEvent, + CloseWithSpontaneousEvent + }; + + enum Direction { + DirectionNorth = 0x01, + DirectionEast = 0x10, + DirectionSouth = 0x02, + DirectionWest = 0x20 + }; + + // Functions. explicit QWidgetPrivate(int version = QObjectPrivateVersion); ~QWidgetPrivate(); @@ -219,10 +296,6 @@ public: QPainter *sharedPainter() const; void setSharedPainter(QPainter *painter); QWidgetBackingStore *maybeBackingStore() const; -#ifdef Q_WS_QWS - void setMaxWindowState_helper(); - void setFullScreenSize_helper(); -#endif void init(QWidget *desktopWidget, Qt::WindowFlags f); void create_sys(WId window, bool initializeWindow, bool destroyOldWindow); void createRecursively(); @@ -243,22 +316,10 @@ public: QPalette naturalWidgetPalette(uint inheritedMask) const; void setMask_sys(const QRegion &); -#ifdef Q_WS_WIN - bool shouldShowMaximizeButton(); - void winUpdateIsOpaque(); -#endif - -#ifdef Q_WS_MAC - void macUpdateSizeAttribute(); - void macUpdateHideOnSuspend(); - void macUpdateOpaqueSizeGrip(); - void macUpdateIgnoreMouseEvents(); - void macUpdateMetalAttribute(); - void macUpdateIsOpaque(); - void setEnabled_helper_sys(bool enable); - bool isRealWindow() const; - void adjustWithinMaxAndMinSize(int &w, int &h); - void applyMaxAndMinSizeOnWindow(); +#ifdef Q_OS_SYMBIAN + void setSoftKeys_sys(const QList<QAction*> &softkeys); + void activateSymbianWindow(WId wid = 0); + void _q_delayedDestroy(WId winId); #endif void raise_sys(); @@ -285,20 +346,9 @@ public: void setStyle_helper(QStyle *newStyle, bool propagate, bool metalHack = false); void inheritStyle(); - bool isBackgroundInherited() const; - void setUpdatesEnabled_helper(bool ); - void paintBackground(QPainter *, const QRegion &, const QPoint & = QPoint(), int flags = DrawAsRoot) const; - enum DrawWidgetFlags { - DrawAsRoot = 0x01, - DrawPaintOnScreen = 0x02, - DrawRecursive = 0x04, - DrawInvisible = 0x08, - DontSubtractOpaqueChildren = 0x10, - DontSetCompositionMode = 0x20, - DontDrawOpaqueChildren = 0x40 - }; + void paintBackground(QPainter *, const QRegion &, int flags = DrawAsRoot) const; bool isAboutToShow() const; QRegion prepareToRender(const QRegion ®ion, QWidget::RenderFlags renderFlags); void render_helper(QPainter *painter, const QPoint &targetOffset, const QRegion &sourceRegion, @@ -317,14 +367,12 @@ public: QPainter *beginSharedPainter(); bool endSharedPainter(); - static QGraphicsProxyWidget * nearestGraphicsProxyWidget(QWidget *origin); +#ifndef QT_NO_GRAPHICSVIEW + static QGraphicsProxyWidget * nearestGraphicsProxyWidget(const QWidget *origin); +#endif QWindowSurface *createDefaultWindowSurface(); QWindowSurface *createDefaultWindowSurface_sys(); void repaint_sys(const QRegion &rgn); -#ifdef Q_WS_MAC - void update_sys(const QRect &rect); - void update_sys(const QRegion &rgn); -#endif QRect clipRect() const; QRegion clipRegion() const; @@ -335,42 +383,20 @@ public: void updateIsOpaque(); void setOpaque(bool opaque); void updateIsTranslucent(); - bool hasBackground() const; bool paintOnScreen() const; + void invalidateGraphicsEffectsRecursively(); - QRegion getOpaqueRegion() const; const QRegion &getOpaqueChildren() const; void setDirtyOpaqueRegion(); - QRegion opaqueChildren; - - enum CloseMode { - CloseNoEvent, - CloseWithEvent, - CloseWithSpontaneousEvent - }; bool close_helper(CloseMode mode); - bool compositeEvent(QEvent *e); void setWindowIcon_helper(); void setWindowIcon_sys(bool forceReset = false); void setWindowOpacity_sys(qreal opacity); - void adjustQuitOnCloseAttribute(); -#if defined(Q_WS_X11) - void setWindowRole(); - void sendStartupMessage(const char *message) const; - void setNetWmWindowTypes(); - void x11UpdateIsOpaque(); -#endif - -#if defined (Q_WS_WIN) - void reparentChildren(); -#endif - void scrollChildren(int dx, int dy); - void moveRect(const QRect &, int dx, int dy); void scrollRect(const QRect &, int dx, int dy); void invalidateBuffer_resizeHelper(const QPoint &oldPos, const QSize &oldSize); @@ -384,7 +410,6 @@ public: void reparentFocusWidgets(QWidget *oldtlw); static int pointToRect(const QPoint &p, const QRect &r); - QRect fromOrToLayoutItemRect(const QRect &rect, int sign) const; void setWinId(WId); void showChildren(bool spontaneous); @@ -394,9 +419,6 @@ public: void scroll_sys(int dx, int dy, const QRect &r); void deactivateWidgetCleanup(); void setGeometry_sys(int, int, int, int, bool); -#ifdef Q_WS_MAC - void setGeometry_sys_helper(int, int, int, int, bool); -#endif void sendPendingMoveAndResizeEvents(bool recursive = false, bool disableUpdates = false); void activateChildLayoutsRecursively(); void show_recursive(); @@ -408,45 +430,25 @@ public: void setEnabled_helper(bool); void registerDropSite(bool); -#if defined(Q_WS_WIN) && !defined(QT_NO_DRAGANDDROP) - QOleDropTarget *registerOleDnd(QWidget *widget); - void unregisterOleDnd(QWidget *widget, QOleDropTarget *target); -#endif static void adjustFlags(Qt::WindowFlags &flags, QWidget *w = 0); void updateFrameStrut(); QRect frameStrut() const; +#ifdef QT_KEYPAD_NAVIGATION + static bool navigateToDirection(Direction direction); + static QWidget *widgetInNavigationDirection(Direction direction); +#endif + void setWindowIconText_sys(const QString &cap); void setWindowIconText_helper(const QString &cap); void setWindowTitle_sys(const QString &cap); -#ifdef Q_OS_WIN - void grabMouseWhileInWindow(); -#endif - #ifndef QT_NO_CURSOR void setCursor_sys(const QCursor &cursor); void unsetCursor_sys(); #endif -#ifdef Q_WS_MAC - void setWindowModified_sys(bool b); - void updateMaximizeButton_sys(); - void setWindowFilePath_sys(const QString &filePath); - void createWindow_sys(); - void recreateMacWindow(); -#ifndef QT_MAC_USE_COCOA - void initWindowPtr(); - void finishCreateWindow_sys_Carbon(OSWindowRef windowRef); -#else - void finishCreateWindow_sys_Cocoa(void * /*NSWindow * */ windowRef); - void syncCocoaMask(); - void finishCocoaMaskSetup(); -#endif - void determineWindowClass(); - void transferChildren(); -#endif void setWindowTitle_helper(const QString &cap); void setWindowFilePath_helper(const QString &filePath); @@ -462,59 +464,137 @@ public: QInputContext *inputContext() const; -#if defined(Q_WS_QWS) - void moveSurface(QWindowSurface *surface, const QPoint &offset); - - QRegion localRequestedRegion() const; - QRegion localAllocatedRegion() const; + void setModal_sys(); - void blitToScreen(const QRegion &globalrgn); -#ifndef QT_NO_CURSOR - void updateCursor() const; + // This is an helper function that return the available geometry for + // a widget and takes care is this one is in QGraphicsView. + // If the widget is not embed in a scene then the geometry available is + // null, we let QDesktopWidget decide for us. + static QRect screenGeometry(const QWidget *widget) + { + QRect screen; +#ifndef QT_NO_GRAPHICSVIEW + QGraphicsProxyWidget *ancestorProxy = widget->d_func()->nearestGraphicsProxyWidget(widget); + //It's embedded if it has an ancestor + if (ancestorProxy) { + if (!bypassGraphicsProxyWidget(widget)) { + // One view, let be smart and return the viewport rect then the popup is aligned + if (ancestorProxy->scene()->views().size() == 1) { + QGraphicsView *view = ancestorProxy->scene()->views().at(0); + screen = view->mapToScene(view->viewport()->rect()).boundingRect().toRect(); + } else { + screen = ancestorProxy->scene()->sceneRect().toRect(); + } + } + } #endif + return screen; + } - QScreen* getScreen() const; + inline void setRedirected(QPaintDevice *replacement, const QPoint &offset) + { + Q_ASSERT(q_func()->testAttribute(Qt::WA_WState_InPaintEvent)); + redirectDev = replacement; + redirectOffset = offset; + } - friend class QWSManager; - friend class QWSManagerPrivate; - friend class QDecoration; -#endif + inline QPaintDevice *redirected(QPoint *offset) const + { + if (offset) + *offset = redirectDev ? redirectOffset : QPoint(); + return redirectDev; + } - static int instanceCounter; // Current number of widget instances - static int maxInstances; // Maximum number of widget instances + inline void restoreRedirected() + { redirectDev = 0; } -#ifdef QT_KEYPAD_NAVIGATION - static QPointer<QWidget> editingWidget; -#endif + inline void enforceNativeChildren() + { + if (!extra) + createExtra(); - QWidgetData data; + if (extra->nativeChildrenForced) + return; + extra->nativeChildrenForced = 1; + + for (int i = 0; i < children.size(); ++i) { + if (QWidget *child = qobject_cast<QWidget *>(children.at(i))) + child->setAttribute(Qt::WA_NativeWindow); + } + } + + inline bool nativeChildrenForced() const + { + 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()); + + inline QPoint mapToWS(const QPoint &p) const + { return p - data.wrect.topLeft(); } + + inline QPoint mapFromWS(const QPoint &p) const + { return p + data.wrect.topLeft(); } + + inline QRect mapToWS(const QRect &r) const + { QRect rr(r); rr.translate(-data.wrect.topLeft()); return rr; } + + inline QRect mapFromWS(const QRect &r) const + { QRect rr(r); rr.translate(data.wrect.topLeft()); return rr; } +#endif + // Variables. + // Regular pointers (keep them together to avoid gaps on 64 bit architectures). QWExtra *extra; QWidget *focus_next; QWidget *focus_prev; QWidget *focus_child; -#ifndef QT_NO_ACTION - QList<QAction*> actions; -#endif QLayout *layout; + QRegion *needsFlush; + QPaintDevice *redirectDev; QWidgetItemV2 *widgetItem; + QPaintEngine *extraPaintEngine; + mutable const QMetaObject *polished; + 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 *allWidgets; #if !defined(QT_NO_IM) QPointer<QInputContext> ic; + Qt::InputMethodHints imHints; +#endif +#ifdef QT_KEYPAD_NAVIGATION + static QPointer<QWidget> editingWidget; #endif - // All widgets are initially added into the uncreatedWidgets set. Once - // they receive a window id they are removed and added to the mapper - static QWidgetMapper *mapper; - static QWidgetSet *uncreatedWidgets; - - short leftmargin, topmargin, rightmargin, bottommargin; - - signed char leftLayoutItemMargin; - signed char topLayoutItemMargin; - signed char rightLayoutItemMargin; - signed char bottomLayoutItemMargin; - // ### TODO: reorganize private/extra/topextra to save memory - QPointer<QWidget> compositeChildGrab; + // Implicit pointers (shared_null/shared_empty). + QRegion opaqueChildren; + QRegion dirty; #ifndef QT_NO_TOOLTIP QString toolTip; #endif @@ -524,14 +604,38 @@ public: #ifndef QT_NO_WHATSTHIS QString whatsThis; #endif - QString accessibleName, accessibleDescription; +#ifndef QT_NO_ACCESSIBILITY + QString accessibleName; + QString accessibleDescription; +#endif + // Other variables. + uint inheritedFontResolveMask; + uint inheritedPaletteResolveMask; + short leftmargin; + short topmargin; + short rightmargin; + short bottommargin; + signed char leftLayoutItemMargin; + signed char topLayoutItemMargin; + signed char rightLayoutItemMargin; + signed char bottomLayoutItemMargin; + static int instanceCounter; // Current number of widget instances + static int maxInstances; // Maximum number of widget instances + Qt::HANDLE hd; + QWidgetData data; + QSizePolicy size_policy; + QLocale locale; + QPoint redirectOffset; +#ifndef QT_NO_ACTION + QList<QAction*> actions; +#endif + QMap<Qt::GestureType, Qt::GestureFlags> gestureContext; + + // Bit fields. + uint high_attributes[3]; // the low ones are in QWidget::widget_attributes QPalette::ColorRole fg_role : 8; QPalette::ColorRole bg_role : 8; - uint high_attributes[3]; // the low ones are in QWidget::widget_attributes - Qt::HANDLE hd; - QRegion dirty; - QRegion *needsFlush; uint dirtyOpaqueChildren : 1; uint isOpaque : 1; uint inDirtyList : 1; @@ -539,35 +643,36 @@ public: uint isMoved : 1; uint usesDoubleBufferedGLContext : 1; -#ifdef Q_WS_WIN - uint noPaintOnScreen : 1; // see qwidget_win.cpp ::paintEngine() -#endif - - uint inheritedFontResolveMask; - uint inheritedPaletteResolveMask; -#if defined(Q_WS_X11) + // *************************** Platform specific ************************************ +#if defined(Q_WS_X11) // <----------------------------------------------------------- X11 QX11Info xinfo; Qt::HANDLE picture; + static QWidget *mouseGrabber; + static QWidget *keyboardGrabber; + + void setWindowRole(); + void sendStartupMessage(const char *message) const; + void setNetWmWindowTypes(); + void x11UpdateIsOpaque(); + bool isBackgroundInherited() const; +#elif defined(Q_WS_WIN) // <--------------------------------------------------------- WIN + uint noPaintOnScreen : 1; // see qwidget_win.cpp ::paintEngine() + uint nativeGesturePanEnabled : 1; + + bool shouldShowMaximizeButton(); + void winUpdateIsOpaque(); + void reparentChildren(); +#ifndef QT_NO_DRAGANDDROP + QOleDropTarget *registerOleDnd(QWidget *widget); + void unregisterOleDnd(QWidget *widget, QOleDropTarget *target); #endif -#if defined(Q_WS_MAC) - enum PaintChildrenOPs { - PC_None = 0x00, - PC_Now = 0x01, - PC_NoPaint = 0x04, - PC_Later = 0x10 - }; - EventHandlerRef window_event; - bool qt_mac_dnd_event(uint, DragRef); - void toggleDrawers(bool); - //mac event functions - static bool qt_create_root_win(); - static void qt_clean_root_win(); - static bool qt_recreate_root_win(); - static bool qt_mac_update_sizer(QWidget *, int up = 0); - static OSStatus qt_window_event(EventHandlerCallRef er, EventRef event, void *); - static OSStatus qt_widget_event(EventHandlerCallRef er, EventRef event, void *); - static bool qt_widget_rgn(QWidget *, short, RgnHandle, bool); - static bool qt_widget_shape(QWidget *, short, HIMutableShapeRef, bool); + void grabMouseWhileInWindow(); + void registerTouchWindow(); + void winSetupGestures(); +#elif defined(Q_WS_MAC) // <--------------------------------------------------------- MAC + // This is new stuff + uint needWindowChange : 1; + uint isGLWidget : 1; // Each wiget keeps a list of all its child and grandchild OpenGL widgets. // This list is used to update the gl context whenever a parent and a granparent @@ -580,95 +685,146 @@ public: QWidget * widget; QWidget * lastUpdateWidget; }; - QList<GlWidgetInfo> glWidgets; // dirtyOnWidget contains the areas in the widget that needs to be repained, // in the same way as dirtyOnScreen does for the window. Areas are added in // dirtyWidget_sys and cleared in the paint event. In scroll_sys we then use // this information repaint invalid areas when widgets are scrolled. QRegion dirtyOnWidget; + EventHandlerRef window_event; + QList<GlWidgetInfo> glWidgets; //these are here just for code compat (HIViews) Qt::HANDLE qd_hd; - // This is new stuff - uint needWindowChange : 1; - uint isGLWidget : 1; -#endif - -#if defined(Q_WS_X11) || defined (Q_WS_WIN) || defined(Q_WS_MAC) -#ifdef Q_WS_MAC - void setWSGeometry(bool dontShow=false, const QRect &oldRect = QRect()); + void macUpdateSizeAttribute(); + void macUpdateHideOnSuspend(); + void macUpdateOpaqueSizeGrip(); + void macUpdateIgnoreMouseEvents(); + void macUpdateMetalAttribute(); + void macUpdateIsOpaque(); + void setEnabled_helper_sys(bool enable); + bool isRealWindow() const; + void adjustWithinMaxAndMinSize(int &w, int &h); + void applyMaxAndMinSizeOnWindow(); + void update_sys(const QRect &rect); + void update_sys(const QRegion &rgn); + void setGeometry_sys_helper(int, int, int, int, bool); + void setWindowModified_sys(bool b); + void updateMaximizeButton_sys(); + void setWindowFilePath_sys(const QString &filePath); + void createWindow_sys(); + void recreateMacWindow(); +#ifndef QT_MAC_USE_COCOA + void initWindowPtr(); + void finishCreateWindow_sys_Carbon(OSWindowRef windowRef); #else - void setWSGeometry(bool dontShow=false); + void finishCreateWindow_sys_Cocoa(void * /*NSWindow * */ windowRef); + void syncCocoaMask(); + void finishCocoaMaskSetup(); #endif + void determineWindowClass(); + void transferChildren(); + bool qt_mac_dnd_event(uint, DragRef); + void toggleDrawers(bool); + //mac event functions + static bool qt_create_root_win(); + static void qt_clean_root_win(); + static bool qt_mac_update_sizer(QWidget *, int up = 0); + static OSStatus qt_window_event(EventHandlerCallRef er, EventRef event, void *); + static OSStatus qt_widget_event(EventHandlerCallRef er, EventRef event, void *); + static bool qt_widget_rgn(QWidget *, short, RgnHandle, bool); + void registerTouchWindow(); +#elif defined(Q_WS_QWS) // <--------------------------------------------------------- QWS + void setMaxWindowState_helper(); + void setFullScreenSize_helper(); + void moveSurface(QWindowSurface *surface, const QPoint &offset); + QRegion localRequestedRegion() const; + QRegion localAllocatedRegion() const; - inline QPoint mapToWS(const QPoint &p) const - { return p - data.wrect.topLeft(); } - - inline QPoint mapFromWS(const QPoint &p) const - { return p + data.wrect.topLeft(); } - - inline QRect mapToWS(const QRect &r) const - { QRect rr(r); rr.translate(-data.wrect.topLeft()); return rr; } - - inline QRect mapFromWS(const QRect &r) const - { QRect rr(r); rr.translate(data.wrect.topLeft()); return rr; } + friend class QWSManager; + friend class QWSManagerPrivate; + friend class QDecoration; +#ifndef QT_NO_CURSOR + void updateCursor() const; +#endif + QScreen* getScreen() const; +#elif defined(Q_OS_SYMBIAN) // <--------------------------------------------------------- SYMBIAN + static QWidget *mouseGrabber; + static QWidget *keyboardGrabber; + void s60UpdateIsOpaque(); + void reparentChildren(); + void registerTouchWindow(); #endif - QPaintEngine *extraPaintEngine; +}; - mutable const QMetaObject *polished; +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; +}; - void setModal_sys(); - QSizePolicy size_policy; - QLocale locale; +class QWidgetEffectSourcePrivate : public QGraphicsEffectSourcePrivate +{ +public: + QWidgetEffectSourcePrivate(QWidget *widget) + : QGraphicsEffectSourcePrivate(), m_widget(widget), context(0), updateDueToGraphicsEffect(false) + {} -#ifdef Q_WS_X11 - static QWidget *mouseGrabber; - static QWidget *keyboardGrabber; -#endif - QPaintDevice *redirectDev; - QPoint redirectOffset; + inline void detach() + { m_widget->setGraphicsEffect(0); } - inline void setRedirected(QPaintDevice *replacement, const QPoint &offset) - { - Q_ASSERT(q_func()->testAttribute(Qt::WA_WState_InPaintEvent)); - redirectDev = replacement; - redirectOffset = offset; - } + inline const QGraphicsItem *graphicsItem() const + { return 0; } - inline QPaintDevice *redirected(QPoint *offset) const + inline const QWidget *widget() const + { return m_widget; } + + inline void update() { - if (offset) - *offset = redirectDev ? redirectOffset : QPoint(); - return redirectDev; + updateDueToGraphicsEffect = true; + m_widget->update(); + updateDueToGraphicsEffect = false; } - inline void restoreRedirected() - { redirectDev = 0; } + inline bool isPixmap() const + { return false; } - inline void enforceNativeChildren() + inline void effectBoundingRectChanged() { - if (!extra) - createExtra(); + // ### This function should take a rect parameter; then we can avoid + // updating too much on the parent widget. + if (QWidget *parent = m_widget->parentWidget()) + parent->update(); + else + update(); + } - if (extra->nativeChildrenForced) - return; - extra->nativeChildrenForced = 1; + inline const QStyleOption *styleOption() const + { return 0; } - for (int i = 0; i < children.size(); ++i) { - if (QWidget *child = qobject_cast<QWidget *>(children.at(i))) - child->setAttribute(Qt::WA_NativeWindow); - } - } + inline QRect deviceRect() const + { return m_widget->window()->rect(); } - inline bool nativeChildrenForced() const - { - return extra ? extra->nativeChildrenForced : false; - } + QRectF boundingRect(Qt::CoordinateSystem system) const; + void draw(QPainter *p); + QPixmap pixmap(Qt::CoordinateSystem system, QPoint *offset, + QGraphicsEffectSource::PixmapPadMode mode) const; - QSize adjustedSize() const; + QWidget *m_widget; + QWidgetPaintContext *context; + QTransform lastEffectTransform; + bool updateDueToGraphicsEffect; }; inline QWExtra *QWidgetPrivate::extraData() const diff --git a/src/gui/kernel/qwidget_qws.cpp b/src/gui/kernel/qwidget_qws.cpp index 24b3546..e299c6e 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)) { @@ -280,7 +280,7 @@ void QWidget::destroy(bool destroyWindow, bool destroySubWindows) QApplicationPrivate::leaveModal(this); else if ((windowType() == Qt::Popup)) qApp->d_func()->closePopup(this); - +#ifndef QT_NO_IM if (d->ic) { delete d->ic; d->ic =0; @@ -291,6 +291,7 @@ void QWidget::destroy(bool destroyWindow, bool destroySubWindows) if (qic) qic->widgetDestroyed(this); } +#endif //QT_NO_IM if ((windowType() == Qt::Desktop)) { } else { @@ -298,11 +299,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 +318,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); @@ -565,20 +571,6 @@ void QWidget::activateWindow() } } -/* - Should we require that q is a toplevel window ??? - - Used by QWSManager - */ -void QWidgetPrivate::blitToScreen(const QRegion &globalrgn) -{ - Q_Q(QWidget); - QWidget *win = q->window(); - QBrush bgBrush = win->palette().brush(win->backgroundRole()); - bool opaque = bgBrush.style() == Qt::NoBrush || bgBrush.isOpaque(); - QWidget::qwsDisplay()->repaintRegion(win->data->winid, win->windowFlags(), opaque, globalrgn); -} - void QWidgetPrivate::show_sys() { Q_Q(QWidget); @@ -590,6 +582,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) @@ -606,12 +607,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; @@ -652,7 +647,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); @@ -819,7 +815,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())); } } @@ -828,7 +824,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())); } } @@ -1037,6 +1033,9 @@ void QWidgetPrivate::deleteSysExtra() void QWidgetPrivate::createTLSysExtra() { +#ifndef QT_NO_QWS_MANAGER + extra->topextra->qwsManager = 0; +#endif } void QWidgetPrivate::deleteTLSysExtra() diff --git a/src/gui/kernel/qwidget_s60.cpp b/src/gui/kernel/qwidget_s60.cpp new file mode 100644 index 0000000..a6d8ed7 --- /dev/null +++ b/src/gui/kernel/qwidget_s60.cpp @@ -0,0 +1,1307 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $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 + +// This is necessary in order to be able to perform delayed invokation on slots +// which take arguments of type WId. One example is +// QWidgetPrivate::_q_delayedDestroy, which is used to delay destruction of +// CCoeControl objects until after the CONE event handler has finished running. +Q_DECLARE_METATYPE(WId) + +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::setWSGeometry(bool dontShow, const QRect &) +{ + // Note: based on x11 implementation + + static const int XCOORD_MAX = 16383; + static const int WRECT_MAX = 16383; + + Q_Q(QWidget); + + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + + /* + There are up to four different coordinate systems here: + Qt coordinate system for this widget. + Symbian coordinate system for this widget (relative to wrect). + Qt coordinate system for parent + Symbian coordinate system for parent (relative to parent's wrect). + */ + + QRect validRange(-XCOORD_MAX,-XCOORD_MAX, 2*XCOORD_MAX, 2*XCOORD_MAX); + QRect wrectRange(-WRECT_MAX,-WRECT_MAX, 2*WRECT_MAX, 2*WRECT_MAX); + QRect wrect; + //xrect is the Symbian geometry of my widget. (starts out in parent's Qt coord sys, and ends up in parent's Symbian coord sys) + QRect xrect = data.crect; + + const QWidget *const parent = q->parentWidget(); + QRect parentWRect = parent->data->wrect; + + if (parentWRect.isValid()) { + // parent is clipped, and we have to clip to the same limit as parent + if (!parentWRect.contains(xrect)) { + xrect &= parentWRect; + wrect = xrect; + //translate from parent's to my Qt coord sys + wrect.translate(-data.crect.topLeft()); + } + //translate from parent's Qt coords to parent's X coords + xrect.translate(-parentWRect.topLeft()); + + } else { + // parent is not clipped, we may or may not have to clip + + if (data.wrect.isValid() && QRect(QPoint(),data.crect.size()).contains(data.wrect)) { + // This is where the main optimization is: we are already + // clipped, and if our clip is still valid, we can just + // move our window, and do not need to move or clip + // children + + QRect vrect = xrect & parent->rect(); + vrect.translate(-data.crect.topLeft()); //the part of me that's visible through parent, in my Qt coords + if (data.wrect.contains(vrect)) { + xrect = data.wrect; + xrect.translate(data.crect.topLeft()); + if (data.winid) + data.winid->SetExtent(TPoint(xrect.x(), xrect.y()), TSize(xrect.width(), xrect.height())); + return; + } + } + + if (!validRange.contains(xrect)) { + // we are too big, and must clip + xrect &=wrectRange; + wrect = xrect; + wrect.translate(-data.crect.topLeft()); + //parent's X coord system is equal to parent's Qt coord + //sys, so we don't need to map xrect. + } + } + + // unmap if we are outside the valid window system coord system + bool outsideRange = !xrect.isValid(); + bool mapWindow = false; + if (q->testAttribute(Qt::WA_OutsideWSRange) != outsideRange) { + q->setAttribute(Qt::WA_OutsideWSRange, outsideRange); + if (outsideRange) { + if (data.winid) + data.winid->DrawableWindow()->SetVisible(EFalse); + q->setAttribute(Qt::WA_Mapped, false); + } else if (!q->isHidden()) { + mapWindow = true; + } + } + + if (outsideRange) + return; + + bool jump = (data.wrect != wrect); + data.wrect = wrect; + + // and now recursively for all children... + for (int i = 0; i < children.size(); ++i) { + QObject *object = children.at(i); + if (object->isWidgetType()) { + QWidget *w = static_cast<QWidget *>(object); + if (!w->isWindow() && w->testAttribute(Qt::WA_WState_Created)) + w->d_func()->setWSGeometry(jump); + } + } + + if (data.winid) { + // move ourselves to the new position and map (if necessary) after + // the movement. Rationale: moving unmapped windows is much faster + // than moving mapped windows + if (!parent->internalWinId()) + xrect.translate(parent->mapTo(q->nativeParentWidget(), QPoint(0, 0))); + + data.winid->SetExtent(TPoint(xrect.x(), xrect.y()), TSize(xrect.width(), xrect.height())); + } + + if (mapWindow and !dontShow) { + q->setAttribute(Qt::WA_Mapped); + if (q->internalWinId()) + q->internalWinId()->DrawableWindow()->SetVisible(ETrue); + } + + if (jump && data.winid) { + RWindow *const window = static_cast<RWindow *>(data.winid->DrawableWindow()); + window->Invalidate(TRect(0, 0, wrect.width(), wrect.height())); + } +} + +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); + + 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 *const destroyw = destroyOldWindow ? data.winid : 0; + + createExtra(); + if (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)); + + QScopedPointer<QSymbianControl> control( q_check_ptr(new QSymbianControl(q)) ); + QT_TRAP_THROWING(control->ConstructL(true, desktop)); + + // Symbian windows are always created in an inactive state + // We perform this assignment for the case where the window is being re-created + // as aa result of a call to setParent_sys, on either this widget or one of its + // ancestors. + extra->activated = 0; + + if (!desktop) { + TInt stackingFlags; + if ((q->windowType() & Qt::Popup) == Qt::Popup) { + stackingFlags = ECoeStackFlagRefusesAllKeys | ECoeStackFlagRefusesFocus; + } else { + stackingFlags = ECoeStackFlagStandard; + } + control->MakeVisible(false); + QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control.data(), ECoeStackPriorityDefault, stackingFlags)); + // Avoid keyboard focus to a hidden window. + control->setFocusSafely(false); + + RDrawableWindow *const drawableWindow = control->DrawableWindow(); + // Request mouse move events. + drawableWindow->PointerFilter(EPointerFilterEnterExit + | EPointerFilterMove | EPointerFilterDrag, 0); + drawableWindow->EnableVisibilityChangeEvents(); + + if (!isOpaque) { + RWindow *const window = static_cast<RWindow *>(drawableWindow); + const TDisplayMode displayMode = static_cast<TDisplayMode>(window->SetRequiredDisplayMode(EColor16MA)); + if (window->SetTransparencyAlphaChannel() == KErrNone) + window->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))); + + // We wait until the control is fully constructed before calling setWinId, because + // this generates a WinIdChanged event. + setWinId(control.take()); + + } else if (q->testAttribute(Qt::WA_NativeWindow) || paintOnScreen()) { // create native child widget + + QScopedPointer<QSymbianControl> control( q_check_ptr(new QSymbianControl(q)) ); + QT_TRAP_THROWING(control->ConstructL(!parentWidget)); + + // Symbian windows are always created in an inactive state + // We perform this assignment for the case where the window is being re-created + // as aa result of a call to setParent_sys, on either this widget or one of its + // ancestors. + extra->activated = 0; + + TInt stackingFlags; + if ((q->windowType() & Qt::Popup) == Qt::Popup) { + stackingFlags = ECoeStackFlagRefusesAllKeys | ECoeStackFlagRefusesFocus; + } else { + stackingFlags = ECoeStackFlagStandard; + } + control->MakeVisible(false); + QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control.data(), ECoeStackPriorityDefault, stackingFlags)); + // Avoid keyboard focus to a hidden window. + control->setFocusSafely(false); + + 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))); + + RDrawableWindow *const drawableWindow = control->DrawableWindow(); + // Request mouse move events. + drawableWindow->PointerFilter(EPointerFilterEnterExit + | EPointerFilterMove | EPointerFilterDrag, 0); + + if (q->isVisible() && q->testAttribute(Qt::WA_Mapped)) + activateSymbianWindow(control.data()); + + // We wait until the control is fully constructed before calling setWinId, because + // this generates a WinIdChanged event. + setWinId(control.take()); + } + + if (destroyw) { + destroyw->ControlEnv()->AppUi()->RemoveFromStack(destroyw); + + // Delay deletion of the control in case this function is called in the + // context of a CONE event handler such as + // CCoeControl::ProcessPointerEventL + QMetaObject::invokeMethod(q, "_q_delayedDestroy", + Qt::QueuedConnection, Q_ARG(WId, destroyw)); + } + + if (q->testAttribute(Qt::WA_AcceptTouchEvents)) + registerTouchWindow(); +} + + +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->internalWinId()) { + if (!extra->activated) + activateSymbianWindow(); + + QSymbianControl *id = static_cast<QSymbianControl *>(q->internalWinId()); + + id->MakeVisible(true); + + if(q->isWindow()) + id->setFocusSafely(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 + if(q->isWindow()) + setWindowIcon_sys(true); + } + + invalidateBuffer(q->rect()); +} + +void QWidgetPrivate::activateSymbianWindow(WId wid) +{ + Q_Q(QWidget); + + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + Q_ASSERT(q->testAttribute(Qt::WA_Mapped)); + Q_ASSERT(!extra->activated); + + if(!wid) + wid = q->internalWinId(); + + Q_ASSERT(wid); + + QT_TRAP_THROWING(wid->ActivateL()); + extra->activated = 1; +} + +void QWidgetPrivate::hide_sys() +{ + Q_Q(QWidget); + + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + deactivateWidgetCleanup(); + QSymbianControl *id = static_cast<QSymbianControl *>(q->internalWinId()); + + if (id) { + //Incorrect optimisation - for popup windows, Qt's focus is moved before + //hide_sys is called, resulting in the popup window keeping its elevated + //position in the CONE control stack. + //This can result in keyboard focus being in an invisible widget in some + //conditions - e.g. QTBUG-4733 + //if(id->IsFocused()) // Avoid unnecessary calls to FocusChanged() + id->setFocusSafely(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() + static_cast<QSymbianControl *>(q->effectiveWinId())->setFocusSafely(true); +} + +void QWidgetPrivate::raise_sys() +{ + Q_Q(QWidget); + + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + if (q->internalWinId()) { + q->internalWinId()->DrawableWindow()->SetOrdinalPosition(0); + + // If toplevel widget, raise app to foreground + if (q->isWindow()) + S60->wsSession().SetWindowGroupOrdinalPosition(S60->windowGroup().Identifier(), 0); + } +} + +void QWidgetPrivate::lower_sys() +{ + Q_Q(QWidget); + + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + if (q->internalWinId()) { + // If toplevel widget, lower app to background + if (q->isWindow()) + S60->wsSession().SetWindowGroupOrdinalPosition(S60->windowGroup().Identifier(), -1); + else + q->internalWinId()->DrawableWindow()->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)); + + if (q->internalWinId() && w->internalWinId()) { + RDrawableWindow *const thisWindow = q->internalWinId()->DrawableWindow(); + RDrawableWindow *const otherWindow = w->internalWinId()->DrawableWindow(); + thisWindow->SetOrdinalPosition(otherWindow->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 widget is native. Because Symbian windows cannot be + // re-parented, we must re-create the window. + const WId window = 0; + const bool initializeWindow = false; + const bool destroyOldWindow = true; + w->d_func()->create_sys(window, initializeWindow, destroyOldWindow); + } + // ### 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); + + QSymbianControl *old_winid = static_cast<QSymbianControl *>(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->setFocusSafely(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; + + RWindow *const window = static_cast<RWindow *>(q->effectiveWinId()->DrawableWindow()); + + if (!isOpaque) { + const TDisplayMode displayMode = static_cast<TDisplayMode>(window->SetRequiredDisplayMode(EColor16MA)); + if (window->SetTransparencyAlphaChannel() == KErrNone) + window->SetBackgroundColor(TRgb(255, 255, 255, 0)); + } else + window->SetTransparentRegion(TRegionFix<1>()); +} + +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); + } + + CFbsBitmap* nBitmap = pm.toSymbianCFbsBitmap(); + CFbsBitmap* nMask = mask.toSymbianCFbsBitmap(); + 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 + // Also this function is leaving, although it is not named as such. + const CFont * font; + QT_TRAP_THROWING(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); + } + + CFbsBitmap* nBitmap = pm.toSymbianCFbsBitmap(); + CFbsBitmap* nMask = mask.toSymbianCFbsBitmap(); + 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 *const window = q->internalWinId()->DrawableWindow(); + window->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 *const window = q->internalWinId()->DrawableWindow(); + window->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; +} + +void QWidgetPrivate::deleteTLSysExtra() +{ + delete extra->topextra->backingStore; + extra->topextra->backingStore = 0; +} + +void QWidgetPrivate::createSysExtra() +{ + extra->activated = 0; + extra->disableBlit = 0; +} + +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 */) +{ + +} + +void QWidgetPrivate::registerTouchWindow() +{ +#ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER + Q_Q(QWidget); + if (q->testAttribute(Qt::WA_WState_Created) && q->windowType() != Qt::Desktop) { + RWindow *rwindow = static_cast<RWindow *>(q->effectiveWinId()->DrawableWindow()); + rwindow->EnableAdvancedPointers(); + } +#endif +} + +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; + } + + // Native window case + const TPoint widgetScreenOffset = internalWinId()->PositionRelativeToScreen(); + const QPoint globalPos = QPoint(widgetScreenOffset.iX, widgetScreenOffset.iY) + pos; + return globalPos; +} + +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; + } + + // Native window case + const TPoint widgetScreenOffset = internalWinId()->PositionRelativeToScreen(); + const QPoint widgetPos = pos - QPoint(widgetScreenOffset.iX, widgetScreenOffset.iY); + return widgetPos; +} + +void QWidget::setWindowState(Qt::WindowStates newstate) +{ + Q_D(QWidget); + + Qt::WindowStates oldstate = windowState(); + if (oldstate == newstate) + return; + + if (isWindow()) { +#ifdef Q_WS_S60 + // Change window decoration visibility if switching to or from fullsccreen + // In addition decoration visibility is changed when the initial has been + // WindowNoState. + // The window decoration visibility has to be changed before doing actual + // window state change since in that order the availableGeometry will return + // directly the right size and we will avoid unnecessarty redraws + if ((oldstate & Qt::WindowFullScreen) != (newstate & Qt::WindowFullScreen) || + oldstate == Qt::WindowNoState) { + CEikStatusPane* statusPane = S60->statusPane(); + CEikButtonGroupContainer* buttonGroup = S60->buttonGroupContainer(); + if (newstate & Qt::WindowFullScreen) { + if (statusPane) + statusPane->MakeVisible(false); + if (buttonGroup) + buttonGroup->MakeVisible(false); + } else { + if (statusPane) + statusPane->MakeVisible(true); + if (buttonGroup) + buttonGroup->MakeVisible(true); + } + + } +#endif // Q_WS_S60 + + 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)) { + if (newstate & Qt::WindowFullScreen) { + const QRect normalGeometry = geometry(); + const QRect r = top->normalGeometry; + setGeometry(qApp->desktop()->screenGeometry(this)); + + top->normalGeometry = r; + if (top->normalGeometry.width() < 0) + top->normalGeometry = normalGeometry; + } else { + 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()) { + QSymbianControl *id = static_cast<QSymbianControl *>(effectiveWinId()); + if (id->IsFocused()) // Avoid unnecessary calls to FocusChanged() + id->setFocusSafely(false); + id->MakeVisible(false); + } + } else { + if (isVisible()) { + QSymbianControl *id = static_cast<QSymbianControl *>(effectiveWinId()); + id->MakeVisible(true); + if (!id->IsFocused()) // Avoid unnecessary calls to FocusChanged() + id->setFocusSafely(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(); + QSymbianControl *id = static_cast<QSymbianControl *>(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 + + if (QWidgetPrivate::mouseGrabber == this) + releaseMouse(); + if (QWidgetPrivate::keyboardGrabber == this) + releaseKeyboard(); + 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 (destroyWindow && !(windowType() == Qt::Desktop) && id) { + if (id->IsFocused()) // Avoid unnecessry calls to FocusChanged() + id->setFocusSafely(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; + +#ifndef QT_NO_CURSOR + QApplication::setOverrideCursor(cursor()); +#endif + } +} + +#ifndef QT_NO_CURSOR +void QWidget::grabMouse(const QCursor &cursor) +{ + 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; + + QApplication::setOverrideCursor(cursor); + } +} +#endif + +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; +#ifndef QT_NO_CURSOR + QApplication::restoreOverrideCursor(); +#endif + } +} + +void QWidget::activateWindow() +{ + Q_D(QWidget); + + QWidget *tlw = window(); + if (tlw->isVisible()) { + window()->createWinId(); + QSymbianControl *id = static_cast<QSymbianControl *>(tlw->internalWinId()); + id->setFocusSafely(true); + } +} + +#ifndef QT_NO_CURSOR + +void QWidgetPrivate::setCursor_sys(const QCursor &cursor) +{ + Q_UNUSED(cursor); + Q_Q(QWidget); + qt_symbian_set_cursor(q, false); +} + +void QWidgetPrivate::unsetCursor_sys() +{ + Q_Q(QWidget); + qt_symbian_set_cursor(q, false); +} +#endif + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qwidget_win.cpp b/src/gui/kernel/qwidget_win.cpp index 75daf2c..22a94b9 100644 --- a/src/gui/kernel/qwidget_win.cpp +++ b/src/gui/kernel/qwidget_win.cpp @@ -56,11 +56,9 @@ #include "private/qbackingstore_p.h" #include "private/qwindowsurface_raster_p.h" -#ifndef QT_NO_DIRECT3D -#include "private/qpaintengine_d3d_p.h" -#include "private/qwindowsurface_d3d_p.h" -#endif - +#include "qscrollbar.h" +#include "qabstractscrollarea.h" +#include <private/qabstractscrollarea_p.h> #include <qdebug.h> @@ -68,7 +66,7 @@ #include <private/qwininputcontext_p.h> #include <private/qpaintengine_raster_p.h> -#if defined(Q_OS_WINCE) +#if defined(Q_WS_WINCE) #include "qguifunctions_wince.h" QT_USE_NAMESPACE extern void qt_wince_maximize(QWidget *widget); //defined in qguifunctions_wince.cpp @@ -146,14 +144,8 @@ static void init_wintab_functions() if (!qt_is_gui_used) return; QLibrary library(QLatin1String("wintab32")); - QT_WA({ - ptrWTOpen = (PtrWTOpen)library.resolve("WTOpenW"); - ptrWTInfo = (PtrWTInfo)library.resolve("WTInfoW"); - } , { - ptrWTOpen = (PtrWTOpen)library.resolve("WTOpenA"); - ptrWTInfo = (PtrWTInfo)library.resolve("WTInfoA"); - }); - + ptrWTOpen = (PtrWTOpen)library.resolve("WTOpenW"); + ptrWTInfo = (PtrWTInfo)library.resolve("WTInfoW"); ptrWTClose = (PtrWTClose)library.resolve("WTClose"); ptrWTQueueSizeGet = (PtrWTQueueSizeGet)library.resolve("WTQueueSizeGet"); ptrWTQueueSizeSet = (PtrWTQueueSizeSet)library.resolve("WTQueueSizeSet"); @@ -169,6 +161,9 @@ static void qt_tablet_init() qt_tablet_widget = new QWidget(0); qt_tablet_widget->createWinId(); qt_tablet_widget->setObjectName(QLatin1String("Qt internal tablet widget")); + // We dont need this internal widget to appear in QApplication::topLevelWidgets() + if (QWidgetPrivate::allWidgets) + QWidgetPrivate::allWidgets->remove(qt_tablet_widget); LOGCONTEXT lcMine; qAddPostRoutine(qt_tablet_cleanup); struct tagAXIS tpOri[3]; @@ -257,7 +252,7 @@ extern "C" LRESULT CALLBACK QtWndProc(HWND, UINT, WPARAM, LPARAM); QWidget member functions *****************************************************************************/ -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyOldWindow) { Q_Q(QWidget); @@ -276,7 +271,7 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO HINSTANCE appinst = qWinAppInst(); HWND parentw, destroyw = 0; - WId id; + WId id = 0; QString windowClassName = qt_reg_winclass(q); @@ -293,25 +288,18 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO if (desktop && !q->testAttribute(Qt::WA_DontShowOnScreen)) { // desktop widget popup = false; // force this flags off - if (QSysInfo::WindowsVersion != QSysInfo::WV_NT && QSysInfo::WindowsVersion != QSysInfo::WV_95) - data.crect.setRect(GetSystemMetrics(76 /* SM_XVIRTUALSCREEN */), GetSystemMetrics(77 /* SM_YVIRTUALSCREEN */), + data.crect.setRect(GetSystemMetrics(76 /* SM_XVIRTUALSCREEN */), GetSystemMetrics(77 /* SM_YVIRTUALSCREEN */), GetSystemMetrics(78 /* SM_CXVIRTUALSCREEN */), GetSystemMetrics(79 /* SM_CYVIRTUALSCREEN */)); - else - data.crect.setRect(0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); } parentw = q->parentWidget() ? q->parentWidget()->effectiveWinId() : 0; -#ifdef UNICODE QString title; - const TCHAR *ttitle = 0; -#endif - QByteArray title95; int style = WS_CHILD; int exsty = 0; if (window) { - style = GetWindowLongA(window, GWL_STYLE); + style = GetWindowLong(window, GWL_STYLE); if (!style) qErrnoWarning("QWidget::create: GetWindowLong failed"); topLevel = false; // #### needed for some IE plugins?? @@ -367,12 +355,7 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO } if (flags & Qt::WindowTitleHint) { - QT_WA({ - title = q->isWindow() ? qAppName() : q->objectName(); - ttitle = (TCHAR*)title.utf16(); - } , { - title95 = q->isWindow() ? qAppName().toLocal8Bit() : q->objectName().toLatin1(); - }); + title = q->isWindow() ? qAppName() : q->objectName(); } // The Qt::WA_WState_Created flag is checked by translateConfigEvent() in @@ -385,13 +368,13 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO destroyw = data.winid; id = window; setWinId(window); - LONG res = SetWindowLongA(window, GWL_STYLE, style); + LONG res = SetWindowLong(window, GWL_STYLE, style); if (!res) qErrnoWarning("QWidget::create: Failed to set window style"); #ifdef _WIN64 - res = SetWindowLongPtrA( window, GWLP_WNDPROC, (LONG_PTR)QtWndProc ); + res = SetWindowLongPtr( window, GWLP_WNDPROC, (LONG_PTR)QtWndProc ); #else - res = SetWindowLongA( window, GWL_WNDPROC, (LONG)QtWndProc ); + res = SetWindowLong( window, GWL_WNDPROC, (LONG)QtWndProc ); #endif if (!res) qErrnoWarning("QWidget::create: Failed to set window procedure"); @@ -442,16 +425,10 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO } } - QT_WA({ - const TCHAR *cname = (TCHAR*)windowClassName.utf16(); - id = CreateWindowEx(exsty, cname, ttitle, style, - x, y, w, h, - parentw, 0, appinst, 0); - } , { - id = CreateWindowExA(exsty, windowClassName.toLatin1(), title95, style, - x, y, w, h, - parentw, 0, appinst, 0); - }); + id = CreateWindowEx(exsty, reinterpret_cast<const wchar_t *>(windowClassName.utf16()), + reinterpret_cast<const wchar_t *>(title.utf16()), style, + x, y, w, h, + parentw, NULL, appinst, NULL); if (!id) qErrnoWarning("QWidget::create: Failed to create window"); setWinId(id); @@ -463,16 +440,10 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO SetWindowPos(id, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); winUpdateIsOpaque(); } else if (q->testAttribute(Qt::WA_NativeWindow) || paintOnScreen()) { // create child widget - QT_WA({ - const TCHAR *cname = (TCHAR*)windowClassName.utf16(); - id = CreateWindowEx(exsty, cname, ttitle, style, - data.crect.left(), data.crect.top(), data.crect.width(), data.crect.height(), - parentw, NULL, appinst, NULL); - } , { - id = CreateWindowExA(exsty, windowClassName.toLatin1(), title95, style, - data.crect.left(), data.crect.top(), data.crect.width(), data.crect.height(), + id = CreateWindowEx(exsty, reinterpret_cast<const wchar_t *>(windowClassName.utf16()), + reinterpret_cast<const wchar_t *>(title.utf16()), style, + data.crect.left(), data.crect.top(), data.crect.width(), data.crect.height(), parentw, NULL, appinst, NULL); - }); if (!id) qErrnoWarning("QWidget::create: Failed to create window"); SetWindowPos(id, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); @@ -503,9 +474,23 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO } } + if (topLevel) { + if (data.window_flags & Qt::CustomizeWindowHint + && data.window_flags & Qt::WindowTitleHint) { + HMENU systemMenu = GetSystemMenu((HWND)q->internalWinId(), FALSE); + if (data.window_flags & Qt::WindowCloseButtonHint) + EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_ENABLED); + else + EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_GRAYED); + } + } + q->setAttribute(Qt::WA_WState_Created); // accept move/resize events hd = 0; // no display context + if (q->testAttribute(Qt::WA_AcceptTouchEvents)) + registerTouchWindow(); + if (window) { // got window from outside if (IsWindowVisible(window)) q->setAttribute(Qt::WA_WState_Visible); @@ -546,14 +531,14 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO } } -#endif //Q_OS_WINCE +#endif //Q_WS_WINCE 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); @@ -574,13 +559,17 @@ void QWidget::destroy(bool destroyWindow, bool destroySubWindows) if (destroyWindow && !(windowType() == Qt::Desktop) && internalWinId()) { DestroyWindow(internalWinId()); } -#ifdef Q_OS_WINCE +#ifdef Q_WS_WINCE if (destroyWindow && (windowType() == Qt::Desktop) && !GetDesktopWindow()) { DestroyWindow(internalWinId()); } #endif - d->setWinId(0); + QT_TRY { + d->setWinId(0); + } QT_CATCH (const std::bad_alloc &) { + // swallow - destructors must not throw + } } } @@ -615,7 +604,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 @@ -671,21 +660,11 @@ void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f) || (!q->isWindow() && q->parentWidget() && q->parentWidget()->testAttribute(Qt::WA_DropSiteRegistered))) q->setAttribute(Qt::WA_DropSiteRegistered, true); - - if (data.window_flags & Qt::CustomizeWindowHint - && data.window_flags & Qt::WindowTitleHint) { - HMENU systemMenu = GetSystemMenu((HWND)q->internalWinId(), FALSE); - if (data.window_flags & Qt::WindowCloseButtonHint) - EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_ENABLED); - else - EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_GRAYED); - } - -#ifdef Q_OS_WINCE +#ifdef Q_WS_WINCE // Show borderless toplevel windows in tasklist & NavBar if (!parent) { QString txt = q->windowTitle().isEmpty()?qAppName():q->windowTitle(); - SetWindowText(q->internalWinId(), (TCHAR*)txt.utf16()); + SetWindowText(q->internalWinId(), (wchar_t*)txt.utf16()); } #endif invalidateBuffer(q->rect()); @@ -746,8 +725,6 @@ QPoint QWidget::mapFromGlobal(const QPoint &pos) const void QWidgetPrivate::updateSystemBackground() {} -extern void qt_win_set_cursor(QWidget *, bool); // qapplication_win.cpp - #ifndef QT_NO_CURSOR void QWidgetPrivate::setCursor_sys(const QCursor &cursor) { @@ -770,30 +747,7 @@ void QWidgetPrivate::setWindowTitle_sys(const QString &caption) return; Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); - QT_WA({ - SetWindowText(q->internalWinId(), (TCHAR*)caption.utf16()); - } , { - SetWindowTextA(q->internalWinId(), caption.toLocal8Bit()); - }); -} - -/* - Create an icon mask the way Windows wants it using CreateBitmap. -*/ - -HBITMAP qt_createIconMask(const QBitmap &bitmap) -{ - QImage bm = bitmap.toImage().convertToFormat(QImage::Format_Mono); - int w = bm.width(); - int h = bm.height(); - int bpl = ((w+15)/16)*2; // bpl, 16 bit alignment - uchar *bits = new uchar[bpl*h]; - bm.invertPixels(); - for (int y=0; y<h; y++) - memcpy(bits+y*bpl, bm.scanLine(y), bpl); - HBITMAP hbm = CreateBitmap(w, h, 1, 1, bits); - delete [] bits; - return hbm; + SetWindowText(q->internalWinId(), (wchar_t*)caption.utf16()); } HICON qt_createIcon(QIcon icon, int xSize, int ySize, QPixmap **cache) @@ -805,27 +759,12 @@ HICON qt_createIcon(QIcon icon, int xSize, int ySize, QPixmap **cache) if (pm.isNull()) return 0; - QBitmap mask = pm.mask(); - if (mask.isNull()) { - mask = QBitmap(pm.size()); - mask.fill(Qt::color1); - } - - HBITMAP im = qt_createIconMask(mask); - ICONINFO ii; - ii.fIcon = true; - ii.hbmMask = im; - ii.hbmColor = pm.toWinHBITMAP(QPixmap::Alpha); - ii.xHotspot = 0; - ii.yHotspot = 0; - result = CreateIconIndirect(&ii); + result = pm.toWinHICON(); if (cache) { delete *cache; *cache = new QPixmap(pm);; } - DeleteObject(ii.hbmColor); - DeleteObject(im); } return result; } @@ -856,11 +795,11 @@ void QWidgetPrivate::setWindowIcon_sys(bool forceReset) GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), &(x->iconPixmap)); if (x->winIconBig) { - SendMessageA(q->internalWinId(), WM_SETICON, 0 /* ICON_SMALL */, (LPARAM)x->winIconSmall); - SendMessageA(q->internalWinId(), WM_SETICON, 1 /* ICON_BIG */, (LPARAM)x->winIconBig); + SendMessage(q->internalWinId(), WM_SETICON, 0 /* ICON_SMALL */, (LPARAM)x->winIconSmall); + SendMessage(q->internalWinId(), WM_SETICON, 1 /* ICON_BIG */, (LPARAM)x->winIconBig); } else { - SendMessageA(q->internalWinId(), WM_SETICON, 0 /* ICON_SMALL */, (LPARAM)x->winIconSmall); - SendMessageA(q->internalWinId(), WM_SETICON, 1 /* ICON_BIG */, (LPARAM)x->winIconSmall); + SendMessage(q->internalWinId(), WM_SETICON, 0 /* ICON_SMALL */, (LPARAM)x->winIconSmall); + SendMessage(q->internalWinId(), WM_SETICON, 1 /* ICON_BIG */, (LPARAM)x->winIconSmall); } } @@ -877,17 +816,17 @@ QCursor *qt_grab_cursor() } // The procedure does nothing, but is required for mousegrabbing to work -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE LRESULT CALLBACK qJournalRecordProc(int nCode, WPARAM wParam, LPARAM lParam) { return CallNextHookEx(journalRec, nCode, wParam, lParam); } -#endif //Q_OS_WINCE +#endif //Q_WS_WINCE /* Works only as long as pointer is inside the application's window, which is good enough for QDockWidget. - Doesn't call SetWindowsHookExA() - this function causes a system-wide + Doesn't call SetWindowsHookEx() - this function causes a system-wide freeze if any other app on the system installs a hook and fails to process events. */ void QWidgetPrivate::grabMouseWhileInWindow() @@ -905,26 +844,29 @@ void QWidgetPrivate::grabMouseWhileInWindow() } } -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE void QWidget::grabMouse() { if (!qt_nograb()) { if (mouseGrb) mouseGrb->releaseMouse(); - journalRec = SetWindowsHookExA(WH_JOURNALRECORD, (HOOKPROC)qJournalRecordProc, GetModuleHandleA(0), 0); + journalRec = SetWindowsHookEx(WH_JOURNALRECORD, (HOOKPROC)qJournalRecordProc, GetModuleHandle(0), 0); Q_ASSERT(testAttribute(Qt::WA_WState_Created)); SetCapture(effectiveWinId()); mouseGrb = this; +#ifndef QT_NO_CURSOR mouseGrbCur = new QCursor(mouseGrb->cursor()); +#endif } } +#ifndef QT_NO_CURSOR void QWidget::grabMouse(const QCursor &cursor) { if (!qt_nograb()) { if (mouseGrb) mouseGrb->releaseMouse(); - journalRec = SetWindowsHookExA(WH_JOURNALRECORD, (HOOKPROC)qJournalRecordProc, GetModuleHandleA(0), 0); + journalRec = SetWindowsHookEx(WH_JOURNALRECORD, (HOOKPROC)qJournalRecordProc, GetModuleHandle(0), 0); Q_ASSERT(testAttribute(Qt::WA_WState_Created)); SetCapture(effectiveWinId()); mouseGrbCur = new QCursor(cursor); @@ -932,6 +874,7 @@ void QWidget::grabMouse(const QCursor &cursor) mouseGrb = this; } } +#endif void QWidget::releaseMouse() { @@ -982,7 +925,7 @@ void QWidget::activateWindow() SetForegroundWindow(window()->internalWinId()); } -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE void QWidget::setWindowState(Qt::WindowStates newstate) { Q_D(QWidget); @@ -1031,18 +974,18 @@ void QWidget::setWindowState(Qt::WindowStates newstate) if (newstate & Qt::WindowFullScreen) { if (d->topData()->normalGeometry.width() < 0 && !(oldstate & Qt::WindowMaximized)) d->topData()->normalGeometry = geometry(); - d->topData()->savedFlags = GetWindowLongA(internalWinId(), GWL_STYLE); + d->topData()->savedFlags = Qt::WindowFlags(GetWindowLong(internalWinId(), GWL_STYLE)); #ifndef Q_FLATTEN_EXPOSE UINT style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP; #else UINT style = WS_POPUP; #endif - if (d->topData()->savedFlags & WS_SYSMENU) + if (ulong(d->topData()->savedFlags) & WS_SYSMENU) style |= WS_SYSMENU; if (isVisible()) style |= WS_VISIBLE; - SetWindowLongA(internalWinId(), GWL_STYLE, style); - QRect r = qApp->desktop()->screenGeometry(this); + SetWindowLong(internalWinId(), GWL_STYLE, style); + QRect r = QApplication::desktop()->screenGeometry(this); UINT swpf = SWP_FRAMECHANGED; if (newstate & Qt::WindowActive) swpf |= SWP_NOACTIVATE; @@ -1053,7 +996,7 @@ void QWidget::setWindowState(Qt::WindowStates newstate) UINT style = d->topData()->savedFlags; if (isVisible()) style |= WS_VISIBLE; - SetWindowLongA(internalWinId(), GWL_STYLE, style); + SetWindowLong(internalWinId(), GWL_STYLE, style); UINT swpf = SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE; if (newstate & Qt::WindowActive) @@ -1084,7 +1027,7 @@ void QWidget::setWindowState(Qt::WindowStates newstate) QWindowStateChangeEvent e(oldstate); QApplication::sendEvent(this, &e); } -#endif //Q_OS_WINCE +#endif //Q_WS_WINCE /* @@ -1097,7 +1040,7 @@ void QWidgetPrivate::hide_sys() Q_Q(QWidget); deactivateWidgetCleanup(); Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); -#ifdef Q_OS_WINCE +#ifdef Q_WS_WINCE if (!qt_wince_is_mobile() && q->isFullScreen()) { HWND handle = FindWindow(L"HHTaskBar", L""); if (handle) { @@ -1126,7 +1069,7 @@ void QWidgetPrivate::hide_sys() \internal Platform-specific part of QWidget::show(). */ -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE void QWidgetPrivate::show_sys() { Q_Q(QWidget); @@ -1192,9 +1135,11 @@ void QWidgetPrivate::show_sys() data.window_state |= Qt::WindowMaximized; } + winSetupGestures(); + invalidateBuffer(q->rect()); } -#endif //Q_OS_WINCE +#endif //Q_WS_WINCE void QWidgetPrivate::setFocus_sys() { @@ -1240,7 +1185,7 @@ void QWidgetPrivate::stackUnder_sys(QWidget* w) (In all comments below: s/X/Windows/g) */ -void QWidgetPrivate::setWSGeometry(bool dontShow) +void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &) { Q_Q(QWidget); Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); @@ -1398,7 +1343,7 @@ void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove) UINT style = top->savedFlags; if (q->isVisible()) style |= WS_VISIBLE; - SetWindowLongA(q->internalWinId(), GWL_STYLE, style); + SetWindowLong(q->internalWinId(), GWL_STYLE, style); UINT swpf = SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE; if (data.window_state & Qt::WindowActive) @@ -1413,7 +1358,7 @@ void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove) QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData(); const bool inTopLevelResize = tlwExtra ? tlwExtra->inTopLevelResize : false; const bool isTranslucentWindow = !isOpaque && ptrUpdateLayeredWindowIndirect && (data.window_flags & Qt::FramelessWindowHint) - && GetWindowLongA(q->internalWinId(), GWL_EXSTYLE) & Q_WS_EX_LAYERED; + && GetWindowLong(q->internalWinId(), GWL_EXSTYLE) & Q_WS_EX_LAYERED; if (q->testAttribute(Qt::WA_WState_ConfigPending)) { // processing config event if (q->internalWinId()) @@ -1452,7 +1397,7 @@ void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove) show_sys(); } else if (!q->testAttribute(Qt::WA_DontShowOnScreen)) { q->setAttribute(Qt::WA_OutsideWSRange, false); -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE // If the window is hidden and in maximized state or minimized, instead of moving the // window, set the normal position of the window. WINDOWPLACEMENT wndpl; @@ -1464,7 +1409,7 @@ void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove) SetWindowPlacement(q->internalWinId(), &wndpl); } else { #else - if (data.window_state_internal & Qt::WindowMaximized) { + if (data.window_state & Qt::WindowMaximized) { qt_wince_maximize(q); } else { #endif @@ -1573,7 +1518,7 @@ bool QWidgetPrivate::shouldShowMaximizeButton() void QWidgetPrivate::winUpdateIsOpaque() { -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE Q_Q(QWidget); if (!q->isWindow() || !q->testAttribute(Qt::WA_TranslucentBackground)) @@ -1583,26 +1528,26 @@ void QWidgetPrivate::winUpdateIsOpaque() return; if (!isOpaque && ptrUpdateLayeredWindowIndirect) { - SetWindowLongA(q->internalWinId(), GWL_EXSTYLE, - GetWindowLongA(q->internalWinId(), GWL_EXSTYLE) | Q_WS_EX_LAYERED); + SetWindowLong(q->internalWinId(), GWL_EXSTYLE, + GetWindowLong(q->internalWinId(), GWL_EXSTYLE) | Q_WS_EX_LAYERED); } else { - SetWindowLongA(q->internalWinId(), GWL_EXSTYLE, - GetWindowLongA(q->internalWinId(), GWL_EXSTYLE) & ~Q_WS_EX_LAYERED); + SetWindowLong(q->internalWinId(), GWL_EXSTYLE, + GetWindowLong(q->internalWinId(), GWL_EXSTYLE) & ~Q_WS_EX_LAYERED); } #endif } void QWidgetPrivate::setConstraints_sys() { -#ifndef Q_OS_WINCE_WM +#ifndef Q_WS_WINCE_WM Q_Q(QWidget); if (q->isWindow() && q->testAttribute(Qt::WA_WState_Created)) { - int style = GetWindowLongA(q->internalWinId(), GWL_STYLE); + int style = GetWindowLong(q->internalWinId(), GWL_STYLE); if (shouldShowMaximizeButton()) style |= WS_MAXIMIZEBOX; else style &= ~WS_MAXIMIZEBOX; - SetWindowLongA(q->internalWinId(), GWL_STYLE, style); + SetWindowLong(q->internalWinId(), GWL_STYLE, style); } #endif } @@ -1712,28 +1657,24 @@ int QWidget::metric(PaintDeviceMetric m) const return val; } -#ifndef Q_OS_WINCE void QWidgetPrivate::createSysExtra() { #ifndef QT_NO_DRAGANDDROP extra->dropTarget = 0; #endif -#ifndef QT_NO_DIRECT3D - extra->had_auto_fill_bg = 0; - extra->had_paint_on_screen = 0; - extra->had_no_system_bg = 0; -#endif } +#ifndef Q_WS_WINCE void QWidgetPrivate::deleteSysExtra() { } -#endif //Q_OS_WINCE +#endif //Q_WS_WINCE void QWidgetPrivate::createTLSysExtra() { - extra->topextra->winIconSmall = 0; + extra->topextra->savedFlags = 0; extra->topextra->winIconBig = 0; + extra->topextra->winIconSmall = 0; } void QWidgetPrivate::deleteTLSysExtra() @@ -1857,7 +1798,8 @@ void QWidgetPrivate::setMask_sys(const QRegion ®ion) OffsetRgn(wr, offset.x(), offset.y()); Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); - SetWindowRgn(data.winid, wr, true); + if (!SetWindowRgn(data.winid, wr, true)) + DeleteObject(wr); } void QWidgetPrivate::updateFrameStrut() @@ -1875,11 +1817,9 @@ void QWidgetPrivate::updateFrameStrut() RECT rect = {0,0,0,0}; QTLWExtra *top = topData(); - uint exstyle = QT_WA_INLINE(GetWindowLongW(q->internalWinId(), GWL_EXSTYLE), - GetWindowLongA(q->internalWinId(), GWL_EXSTYLE)); - uint style = QT_WA_INLINE(GetWindowLongW(q->internalWinId(), GWL_STYLE), - GetWindowLongA(q->internalWinId(), GWL_STYLE)); -#ifndef Q_OS_WINCE + uint exstyle = GetWindowLong(q->internalWinId(), GWL_EXSTYLE); + uint style = GetWindowLong(q->internalWinId(), GWL_STYLE); +#ifndef Q_WS_WINCE if (AdjustWindowRectEx(&rect, style & ~(WS_OVERLAPPED), FALSE, exstyle)) { #else if (AdjustWindowRectEx(&rect, style, FALSE, exstyle)) { @@ -1889,16 +1829,15 @@ void QWidgetPrivate::updateFrameStrut() } } -#ifndef Q_OS_WINCE +#ifndef Q_WS_WINCE void QWidgetPrivate::setWindowOpacity_sys(qreal level) { Q_Q(QWidget); - if (!isOpaque && ptrUpdateLayeredWindowIndirect && (data.window_flags & Qt::FramelessWindowHint)) { - if (GetWindowLongA(q->internalWinId(), GWL_EXSTYLE) & Q_WS_EX_LAYERED) { - Q_BLENDFUNCTION blend = {AC_SRC_OVER, 0, (int)(255.0 * level), Q_AC_SRC_ALPHA}; - Q_UPDATELAYEREDWINDOWINFO info = {sizeof(info), NULL, NULL, NULL, NULL, NULL, 0, &blend, Q_ULW_ALPHA, NULL}; - (*ptrUpdateLayeredWindowIndirect)(q->internalWinId(), &info); + if (!isOpaque && ptrUpdateLayeredWindow && (data.window_flags & Qt::FramelessWindowHint)) { + if (GetWindowLong(q->internalWinId(), GWL_EXSTYLE) & Q_WS_EX_LAYERED) { + BLENDFUNCTION blend = {AC_SRC_OVER, 0, (int)(255.0 * level), AC_SRC_ALPHA}; + ptrUpdateLayeredWindow(q->internalWinId(), NULL, NULL, NULL, NULL, NULL, 0, &blend, Q_ULW_ALPHA); } return; } @@ -1914,17 +1853,17 @@ void QWidgetPrivate::setWindowOpacity_sys(qreal level) if (!ptrSetLayeredWindowAttributes) return; - int wl = GetWindowLongA(q->internalWinId(), GWL_EXSTYLE); + int wl = GetWindowLong(q->internalWinId(), GWL_EXSTYLE); if (level != 1.0) { if ((wl&Q_WS_EX_LAYERED) == 0) - SetWindowLongA(q->internalWinId(), GWL_EXSTYLE, wl|Q_WS_EX_LAYERED); + SetWindowLong(q->internalWinId(), GWL_EXSTYLE, wl | Q_WS_EX_LAYERED); } else if (wl&Q_WS_EX_LAYERED) { - SetWindowLongA(q->internalWinId(), GWL_EXSTYLE, wl & ~Q_WS_EX_LAYERED); + SetWindowLong(q->internalWinId(), GWL_EXSTYLE, wl & ~Q_WS_EX_LAYERED); } - (*ptrSetLayeredWindowAttributes)(q->internalWinId(), 0, (int)(level * 255), Q_LWA_ALPHA); + ptrSetLayeredWindowAttributes(q->internalWinId(), 0, (int)(level * 255), Q_LWA_ALPHA); } -#endif //Q_OS_WINCE +#endif //Q_WS_WINCE // class QGlobalRasterPaintEngine: public QRasterPaintEngine // { @@ -1933,22 +1872,6 @@ void QWidgetPrivate::setWindowOpacity_sys(qreal level) // }; // Q_GLOBAL_STATIC(QGlobalRasterPaintEngine, globalRasterPaintEngine) -#ifndef QT_NO_DIRECT3D -static void cleanup_d3d_engine(); -Q_GLOBAL_STATIC_WITH_INITIALIZER(QDirect3DPaintEngine, _qt_d3dEngine, - { - qAddPostRoutine(cleanup_d3d_engine); - }) -static void cleanup_d3d_engine() -{ - _qt_d3dEngine()->cleanup(); -} -QDirect3DPaintEngine* qt_d3dEngine() -{ - return _qt_d3dEngine(); -} -#endif - #ifndef QT_NO_DIRECTDRAW static uchar *qt_primary_surface_bits; @@ -2004,8 +1927,8 @@ public: // in QOnScreenRasterPaintEngine() : QRasterPaintEngine(new QImage(qt_primary_surface_bits, - qApp->desktop()->width(), - qApp->desktop()->height(), + QApplication::desktop()->width(), + QApplication::desktop()->height(), qt_primary_surface_stride, qt_primary_surface_format)) { @@ -2061,19 +1984,6 @@ void qt_win_initialize_directdraw() { } QPaintEngine *QWidget::paintEngine() const { -#ifndef QT_NO_DIRECT3D - if ((qApp->testAttribute(Qt::AA_MSWindowsUseDirect3DByDefault) - || testAttribute(Qt::WA_MSWindowsUseDirect3D)) - && qt_d3dEngine()->hasDirect3DSupport()) - { - QDirect3DPaintEngine *engine = qt_d3dEngine(); - if (qApp->testAttribute(Qt::AA_MSWindowsUseDirect3DByDefault)) - engine->setFlushOnEnd(false); - else - engine->setFlushOnEnd(true); - return engine; - } -#endif #ifndef QT_NO_DIRECTDRAW QOnScreenRasterPaintEngine *pe = onScreenPaintEngine(); pe->widget = this; @@ -2102,13 +2012,6 @@ QPaintEngine *QWidget::paintEngine() const QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys() { Q_Q(QWidget); -#ifndef QT_NO_DIRECT3D - extern QDirect3DPaintEngine *qt_d3dEngine(); - if (qApp->testAttribute(Qt::AA_MSWindowsUseDirect3DByDefault) && (q->windowOpacity() == 1.0f) - && qt_d3dEngine()->hasDirect3DSupport()) { - return new QD3DWindowSurface(q); - } -#endif return new QRasterWindowSurface(q); } @@ -2116,11 +2019,66 @@ void QWidgetPrivate::setModal_sys() { } +void QWidgetPrivate::registerTouchWindow() +{ + Q_Q(QWidget); + // enable WM_TOUCH* messages on our window + if (q->testAttribute(Qt::WA_WState_Created) + && QApplicationPrivate::RegisterTouchWindow + && q->windowType() != Qt::Desktop) + QApplicationPrivate::RegisterTouchWindow(q->effectiveWinId(), 0); +} +void QWidgetPrivate::winSetupGestures() +{ + Q_Q(QWidget); + if (!q || !q->isVisible()) + return; + QApplicationPrivate *qAppPriv = QApplicationPrivate::instance(); + WId winid = q->internalWinId(); + + bool needh = false; + bool needv = false; + bool singleFingerPanEnabled = false; + + if (QAbstractScrollArea *asa = qobject_cast<QAbstractScrollArea*>(q->parent())) { + QScrollBar *hbar = asa->horizontalScrollBar(); + QScrollBar *vbar = asa->verticalScrollBar(); + Qt::ScrollBarPolicy hbarpolicy = asa->horizontalScrollBarPolicy(); + Qt::ScrollBarPolicy vbarpolicy = asa->verticalScrollBarPolicy(); + needh = (hbarpolicy == Qt::ScrollBarAlwaysOn || + (hbarpolicy == Qt::ScrollBarAsNeeded && hbar->minimum() < hbar->maximum())); + needv = (vbarpolicy == Qt::ScrollBarAlwaysOn || + (vbarpolicy == Qt::ScrollBarAsNeeded && vbar->minimum() < vbar->maximum())); + singleFingerPanEnabled = asa->d_func()->singleFingerPanEnabled; + if (!winid) + winid = q->winId(); // enforces the native winid on the viewport + } + if (winid && qAppPriv->SetGestureConfig) { + GESTURECONFIG gc[1]; + memset(gc, 0, sizeof(gc)); + gc[0].dwID = GID_PAN; + if (nativeGesturePanEnabled) { + gc[0].dwWant = GC_PAN; + if (needv && singleFingerPanEnabled) + gc[0].dwWant |= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY; + else + gc[0].dwBlock |= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY; + if (needh && singleFingerPanEnabled) + gc[0].dwWant |= GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY; + else + gc[0].dwBlock |= GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY; + } else { + gc[0].dwBlock = GC_PAN; + } + + qAppPriv->SetGestureConfig(winid, 0, sizeof(gc)/sizeof(gc[0]), gc, sizeof(gc[0])); + } +} QT_END_NAMESPACE -#ifdef Q_OS_WINCE +#ifdef Q_WS_WINCE # include "qwidget_wince.cpp" #endif diff --git a/src/gui/kernel/qwidget_wince.cpp b/src/gui/kernel/qwidget_wince.cpp index 19fd56a..2fe69e4 100644 --- a/src/gui/kernel/qwidget_wince.cpp +++ b/src/gui/kernel/qwidget_wince.cpp @@ -39,7 +39,7 @@ ** ****************************************************************************/ -#ifdef Q_OS_WINCE +#ifdef Q_WS_WINCE #include "qguifunctions_wince.h" @@ -188,11 +188,7 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO parentw = q->parentWidget() ? q->parentWidget()->effectiveWinId() : 0; -#ifdef UNICODE QString title; - const TCHAR *ttitle = 0; -#endif - QByteArray title95; int style = WS_CHILD; int exsty = WS_EX_NOPARENTNOTIFY; @@ -211,7 +207,7 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO style |= WS_SYSMENU; if (flags & Qt::WindowContextHelpButtonHint) exsty |= WS_EX_CONTEXTHELP; -#ifndef Q_OS_WINCE_WM +#ifndef Q_WS_WINCE_WM if (flags & Qt::WindowMinimizeButtonHint) style |= WS_MINIMIZEBOX; if (shouldShowMaximizeButton()) @@ -236,12 +232,7 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO } if (flags & Qt::WindowTitleHint) { - QT_WA({ - title = q->isWindow() ? qAppName() : q->objectName(); - ttitle = (TCHAR*)title.utf16(); - } , { - title95 = q->isWindow() ? qAppName().toLocal8Bit() : q->objectName().toLatin1(); - }); + title = q->isWindow() ? qAppName() : q->objectName(); } // The Qt::WA_WState_Created flag is checked by translateConfigEvent() in @@ -254,11 +245,11 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO destroyw = data.winid; id = window; setWinId(window); - LONG res = SetWindowLongA(window, GWL_STYLE, style); + LONG res = SetWindowLong(window, GWL_STYLE, style); if (!res) qErrnoWarning("QWidget::create: Failed to set window style"); - res = SetWindowLongA( window, GWL_WNDPROC, (LONG)QtWndProc ); + res = SetWindowLong( window, GWL_WNDPROC, (LONG)QtWndProc ); if (!res) qErrnoWarning("QWidget::create: Failed to set window procedure"); @@ -267,10 +258,10 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO if (!id) { //Create a dummy desktop RECT r; SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); - const TCHAR *cname = reinterpret_cast<const TCHAR *> (windowClassName.utf16()); - id = CreateWindow(cname, ttitle, style, - r.left, r.top, r.right - r.left, r.bottom - r.top, - 0, 0, appinst, 0); + id = CreateWindow(reinterpret_cast<const wchar_t *>(windowClassName.utf16()), + reinterpret_cast<const wchar_t *>(title.utf16()), style, + r.left, r.top, r.right - r.left, r.bottom - r.top, + 0, 0, appinst, 0); } setWinId(id); } else if (topLevel) { // create top-level widget @@ -303,8 +294,8 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO } } - const TCHAR *cname = reinterpret_cast<const TCHAR *> (windowClassName.utf16()); - id = CreateWindowEx(exsty, cname, ttitle, style, + id = CreateWindowEx(exsty, reinterpret_cast<const wchar_t *>(windowClassName.utf16()), + reinterpret_cast<const wchar_t *>(title.utf16()), style, x, y, w, h, 0, 0, appinst, 0); @@ -314,16 +305,9 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO if ((flags & Qt::WindowStaysOnTopHint) || (type == Qt::ToolTip)) SetWindowPos(id, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); } else if (q->testAttribute(Qt::WA_NativeWindow) || paintOnScreen()) { // create child widget - QT_WA({ - const TCHAR *cname = (TCHAR*)windowClassName.utf16(); - id = CreateWindowEx(exsty, cname, ttitle, style, - data.crect.left(), data.crect.top(), data.crect.width(), data.crect.height(), - parentw, NULL, appinst, NULL); - } , { - id = CreateWindowExA(exsty, windowClassName.toLatin1(), title95, style, - data.crect.left(), data.crect.top(), data.crect.width(), data.crect.height(), + id = CreateWindowEx(exsty, (wchar_t*)windowClassName.utf16(), (wchar_t*)title.utf16(), style, + data.crect.left(), data.crect.top(), data.crect.width(), data.crect.height(), parentw, NULL, appinst, NULL); - }); if (!id) qErrnoWarning("QWidget::create: Failed to create window"); SetWindowPos(id, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); @@ -414,7 +398,7 @@ void QWidgetPrivate::show_sys() { int sm = SW_SHOW; bool fakedMaximize = false; if (q->isWindow()) { -#ifndef Q_OS_WINCE_WM +#ifndef Q_WS_WINCE_WM if (q->isMinimized()) { sm = SW_SHOWMINIMIZED; } else if (q->isMaximized()) { @@ -432,6 +416,10 @@ void QWidgetPrivate::show_sys() { SetWindowLong(q->internalWinId(), GWL_STYLE, style | WS_MAXIMIZEBOX); } } else +#else + // Imitate minimizing on Windows mobile by hiding the widget. + if (q->isMinimized()) + sm = SW_HIDE; #endif if (q->isHidden()) { sm = SW_HIDE; @@ -444,17 +432,16 @@ void QWidgetPrivate::show_sys() { sm = SW_SHOWNOACTIVATE; } - if (!(data.window_state & Qt::WindowMinimized)) - ShowWindow(q->internalWinId(), sm); + ShowWindow(q->internalWinId(), sm); if (q->isMaximized() && q->isWindow()) qt_wince_maximize(q); -#ifndef Q_OS_WINCE_WM +#ifndef Q_WS_WINCE_WM if (!qt_wince_is_mobile() && q->isFullScreen()) { HWND handle = FindWindow(L"HHTaskBar", L""); if (handle) { - ShowWindow(handle, 0); + ShowWindow(handle, SW_HIDE); EnableWindow(handle, false); } } @@ -484,21 +471,15 @@ void QWidget::setWindowState(Qt::WindowStates newstate) return; int max = SW_SHOWNORMAL; - int min = SW_SHOWNOACTIVATE; - int normal = SW_SHOWNOACTIVATE; if ((oldstate & Qt::WindowMinimized) && !(newstate & Qt::WindowMinimized)) - newstate |= Qt::WindowActive; - if (newstate & Qt::WindowActive) { - max = SW_SHOWNORMAL; - min = SW_SHOWNORMAL; + newstate |= Qt::WindowActive; + if (newstate & Qt::WindowActive) normal = SW_SHOWNORMAL; - } if (isWindow()) { createWinId(); Q_ASSERT(testAttribute(Qt::WA_WState_Created)); - data->window_state_internal = newstate; // Ensure the initial size is valid, since we store it as normalGeometry below. if ((!testAttribute(Qt::WA_Resized) && !isVisible())) adjustSize(); @@ -509,13 +490,13 @@ void QWidget::setWindowState(Qt::WindowStates newstate) d->topData()->normalGeometry = geometry(); } if ((oldstate & Qt::WindowMaximized) != (newstate & Qt::WindowMaximized)) { - if (!(newstate & Qt::WindowMaximized)) { - int style = GetWindowLongW(internalWinId(), GWL_STYLE) | WS_BORDER | WS_POPUP | WS_CAPTION; + if (!(newstate & Qt::WindowMaximized)) { + int style = GetWindowLong(internalWinId(), GWL_STYLE) | WS_BORDER | WS_POPUP | WS_CAPTION; SetWindowLong(internalWinId(), GWL_STYLE, style); SetWindowLong(internalWinId(), GWL_EXSTYLE, GetWindowLong (internalWinId(), GWL_EXSTYLE) & ~ WS_EX_NODRAG); } - if (isVisible() && newstate & Qt::WindowMaximized) - qt_wince_maximize(this); + if (isVisible() && newstate & Qt::WindowMaximized) + qt_wince_maximize(this); if (isVisible() && !(newstate & Qt::WindowMinimized)) { ShowWindow(internalWinId(), (newstate & Qt::WindowMaximized) ? max : normal); if (!(newstate & Qt::WindowFullScreen)) { @@ -535,11 +516,11 @@ void QWidget::setWindowState(Qt::WindowStates newstate) if (newstate & Qt::WindowFullScreen) { if (d->topData()->normalGeometry.width() < 0 && !(oldstate & Qt::WindowMaximized)) d->topData()->normalGeometry = geometry(); - d->topData()->savedFlags = GetWindowLongA(internalWinId(), GWL_STYLE); + d->topData()->savedFlags = (Qt::WindowFlags)GetWindowLong(internalWinId(), GWL_STYLE); UINT style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP; if (isVisible()) style |= WS_VISIBLE; - SetWindowLongA(internalWinId(), GWL_STYLE, style); + SetWindowLong(internalWinId(), GWL_STYLE, style); QRect r = qApp->desktop()->screenGeometry(this); UINT swpf = SWP_FRAMECHANGED; if (newstate & Qt::WindowActive) @@ -550,7 +531,7 @@ void QWidget::setWindowState(Qt::WindowStates newstate) UINT style = d->topData()->savedFlags; if (isVisible()) style |= WS_VISIBLE; - SetWindowLongA(internalWinId(), GWL_STYLE, style); + SetWindowLong(internalWinId(), GWL_STYLE, style); UINT swpf = SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE; if (newstate & Qt::WindowActive) swpf |= SWP_NOACTIVATE; @@ -572,46 +553,28 @@ void QWidget::setWindowState(Qt::WindowStates newstate) } } if ((oldstate & Qt::WindowMinimized) != (newstate & Qt::WindowMinimized)) { - if (isVisible()) { - ShowWindow(internalWinId(), (newstate & Qt::WindowMinimized) ? min : - (newstate & Qt::WindowMaximized) ? max : normal); - if (newstate & Qt::WindowMaximized) - qt_wince_maximize(this); if (newstate & Qt::WindowMinimized) qt_wince_minimize(internalWinId()); + else if (newstate & Qt::WindowMaximized) { + ShowWindow(internalWinId(), max); + qt_wince_maximize(this); + } else { + ShowWindow(internalWinId(), normal); } } - if ((newstate & Qt::WindowMaximized) && !(newstate & Qt::WindowFullScreen)) { - QRect r = d->topData()->normalGeometry; -#ifdef Q_OS_WINCE_WM - if (!inherits("QDialog") && !inherits("QMdiArea") && !isVisible()) { - d->data.crect.setRect(0, 0, -1, -1); - } -#else - qt_wince_maximize(this); -#endif - } } data->window_state = newstate; - data->window_state_internal = newstate; QWindowStateChangeEvent e(oldstate); QApplication::sendEvent(this, &e); } - -void QWidgetPrivate::createSysExtra() { -#ifndef QT_NO_DRAGANDDROP - extra->dropTarget = 0; -#endif -} - void QWidgetPrivate::deleteSysExtra() { Q_Q(QWidget); if (!qt_wince_is_mobile() && q->isFullScreen()) { HWND handle = FindWindow(L"HHTaskBar", L""); if (handle) { - ShowWindow(handle, 1); + ShowWindow(handle, SW_SHOWNORMAL); EnableWindow(handle, true); } } @@ -704,4 +667,4 @@ void QWidget::show() QT_END_NAMESPACE -#endif Q_OS_WINCE +#endif // Q_WS_WINCE diff --git a/src/gui/kernel/qwidget_x11.cpp b/src/gui/kernel/qwidget_x11.cpp index c86927e..28676da 100644 --- a/src/gui/kernel/qwidget_x11.cpp +++ b/src/gui/kernel/qwidget_x11.cpp @@ -346,6 +346,10 @@ Q_GUI_EXPORT void qt_x11_enforce_cursor(QWidget * w) qt_x11_enforce_cursor(w, false); } +static Bool checkForConfigureAndExpose(Display *, XEvent *e, XPointer) +{ + return e->type == ConfigureNotify || e->type == Expose; +} Q_GUI_EXPORT void qt_x11_wait_for_window_manager(QWidget* w) { @@ -355,18 +359,42 @@ Q_GUI_EXPORT void qt_x11_wait_for_window_manager(QWidget* w) XEvent ev; QTime t; t.start(); + static const int maximumWaitTime = 2000; if (!w->testAttribute(Qt::WA_WState_Created)) return; - while (!XCheckTypedWindowEvent(X11->display, w->effectiveWinId(), ReparentNotify, &ev)) { - if (XCheckTypedWindowEvent(X11->display, w->effectiveWinId(), MapNotify, &ev)) - break; - if (t.elapsed() > 500) - return; // give up, no event available + + if (!(w->windowFlags() & Qt::X11BypassWindowManagerHint)) { + // if the window is not override-redirect, then the window manager + // will reparent us to the frame decoration window. + while (!XCheckTypedWindowEvent(X11->display, w->effectiveWinId(), ReparentNotify, &ev)) { + if (t.elapsed() > maximumWaitTime) + return; + qApp->syncX(); // non-busy wait + } + } + + while (!XCheckTypedWindowEvent(X11->display, w->effectiveWinId(), MapNotify, &ev)) { + if (t.elapsed() > maximumWaitTime) + return; qApp->syncX(); // non-busy wait } + qApp->x11ProcessEvent(&ev); - if (XCheckTypedWindowEvent(X11->display, w->effectiveWinId(), ConfigureNotify, &ev)) - qApp->x11ProcessEvent(&ev); + + // ok, seems like the window manager successfully reparented us, we'll wait + // for the first paint event to arrive, while handling ConfigureNotify in + // the arrival order + while(1) + { + if (XCheckIfEvent(X11->display, &ev, checkForConfigureAndExpose, 0)) { + qApp->x11ProcessEvent(&ev); + if (ev.type == Expose) + return; + } + if (t.elapsed() > maximumWaitTime) + return; + qApp->syncX(); // non-busy wait + } } void qt_change_net_wm_state(const QWidget* w, bool set, Atom one, Atom two = 0) @@ -490,14 +518,18 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO if (!window) initializeWindow = true; + QX11Info *parentXinfo = parentWidget ? &parentWidget->d_func()->xinfo : 0; + if (desktop && qt_x11_create_desktop_on_screen >= 0 && qt_x11_create_desktop_on_screen != xinfo.screen()) { // desktop on a certain screen other than the default requested QX11InfoData *xd = &X11->screens[qt_x11_create_desktop_on_screen]; xinfo.setX11Data(xd); - } else if (parentWidget && parentWidget->d_func()->xinfo.screen() != xinfo.screen()) { - xinfo = parentWidget->d_func()->xinfo; + } else if (parentXinfo && (parentXinfo->screen() != xinfo.screen() + || parentXinfo->visual() != xinfo.visual())) + { + xinfo = *parentXinfo; } //get display, screen number, root window and desktop geometry for @@ -512,6 +544,13 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO dialog = popup = false; // force these flags off data.crect.setRect(0, 0, sw, sh); } else if (topLevel && !q->testAttribute(Qt::WA_Resized)) { + QDesktopWidget *desktopWidget = qApp->desktop(); + if (desktopWidget->isVirtualDesktop()) { + QRect r = desktopWidget->screenGeometry(); + sw = r.width(); + sh = r.height(); + } + int width = sw / 2; int height = 4 * sh / 10; if (extra) { @@ -754,11 +793,14 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO qBound(1, data.crect.width(), XCOORD_MAX), qBound(1, data.crect.height(), XCOORD_MAX)); XStoreName(dpy, id, appName.data()); - Atom protocols[4]; + Atom protocols[5]; int n = 0; protocols[n++] = ATOM(WM_DELETE_WINDOW); // support del window protocol protocols[n++] = ATOM(WM_TAKE_FOCUS); // support take focus window protocol protocols[n++] = ATOM(_NET_WM_PING); // support _NET_WM_PING protocol +#ifndef QT_NO_XSYNC + protocols[n++] = ATOM(_NET_WM_SYNC_REQUEST); // support _NET_WM_SYNC_REQUEST protocol +#endif // QT_NO_XSYNC if (flags & Qt::WindowContextHelpButtonHint) protocols[n++] = ATOM(_NET_WM_CONTEXT_HELP); XSetWMProtocols(dpy, id, protocols, n); @@ -882,6 +924,43 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO #endif } +static void qt_x11_recreateWidget(QWidget *widget) +{ + if (widget->inherits("QGLWidget")) { + // We send QGLWidgets a ParentChange event which causes them to + // recreate their GL context, which in turn causes them to choose + // their visual again. Now that WA_TranslucentBackground is set, + // QGLContext::chooseVisual will select an ARGB visual. + QEvent e(QEvent::ParentChange); + QApplication::sendEvent(widget, &e); + } else { + // For regular widgets, reparent them with their parent which + // also triggers a recreation of the native window + QPoint pos = widget->pos(); + bool visible = widget->isVisible(); + if (visible) + widget->hide(); + + widget->setParent(widget->parentWidget(), widget->windowFlags()); + widget->move(pos); + if (visible) + widget->show(); + } +} + +static void qt_x11_recreateNativeWidgetsRecursive(QWidget *widget) +{ + if (widget->internalWinId()) + qt_x11_recreateWidget(widget); + + const QObjectList &children = widget->children(); + for (int i = 0; i < children.size(); ++i) { + QWidget *child = qobject_cast<QWidget*>(children.at(i)); + if (child) + qt_x11_recreateNativeWidgetsRecursive(child); + } +} + void QWidgetPrivate::x11UpdateIsOpaque() { #ifndef QT_NO_XRENDER @@ -892,25 +971,56 @@ void QWidgetPrivate::x11UpdateIsOpaque() bool topLevel = (data.window_flags & Qt::Window); int screen = xinfo.screen(); if (topLevel && X11->use_xrender - && X11->argbVisuals[screen] && xinfo.depth() != 32) { - // recreate widget - QPoint pos = q->pos(); - bool visible = q->isVisible(); - if (visible) - q->hide(); - q->setParent(q->parentWidget(), q->windowFlags()); - q->move(pos); - if (visible) - q->show(); + && X11->argbVisuals[screen] && xinfo.depth() != 32) + { + qt_x11_recreateNativeWidgetsRecursive(q); } #endif } +/* + Returns true if the background is inherited; otherwise returns + false. + + Mainly used in the paintOnScreen case. +*/ +bool QWidgetPrivate::isBackgroundInherited() const +{ + Q_Q(const QWidget); + + // windows do not inherit their background + if (q->isWindow() || q->windowType() == Qt::SubWindow) + return false; + + if (q->testAttribute(Qt::WA_NoSystemBackground) || q->testAttribute(Qt::WA_OpaquePaintEvent)) + return false; + + const QPalette &pal = q->palette(); + QPalette::ColorRole bg = q->backgroundRole(); + QBrush brush = pal.brush(bg); + + // non opaque brushes leaves us no choice, we must inherit + if (!q->autoFillBackground() || !brush.isOpaque()) + return true; + + if (brush.style() == Qt::SolidPattern) { + // the background is just a solid color. If there is no + // propagated contents, then we claim as performance + // optimization that it was not inheritet. This is the normal + // case in standard Windows or Motif style. + const QWidget *w = q->parentWidget(); + if (!w->d_func()->isBackgroundInherited()) + return false; + } + + return true; +} + 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); @@ -954,7 +1064,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)) @@ -989,7 +1103,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; @@ -1215,7 +1329,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())); @@ -1308,17 +1422,10 @@ void QWidgetPrivate::setWindowIcon_sys(bool forceReset) // already been set return; - XWMHints *h = 0; - if (q->internalWinId()) - h = XGetWMHints(X11->display, q->internalWinId()); - XWMHints wm_hints; - if (!h) { - memset(&wm_hints, 0, sizeof(wm_hints)); // make valgrind happy - h = &wm_hints; - } - // preparing images to set the _NET_WM_ICON property QIcon icon = q->windowIcon(); + QVector<long> icon_data; + Qt::HANDLE pixmap_handle = 0; if (!icon.isNull()) { QList<QSize> availableSizes = icon.availableSizes(); if(availableSizes.isEmpty()) { @@ -1328,7 +1435,6 @@ void QWidgetPrivate::setWindowIcon_sys(bool forceReset) availableSizes.push_back(QSize(64,64)); availableSizes.push_back(QSize(128,128)); } - QVector<long> icon_data; for(int i = 0; i < availableSizes.size(); ++i) { QSize size = availableSizes.at(i); QPixmap pixmap = icon.pixmap(size); @@ -1350,11 +1456,6 @@ void QWidgetPrivate::setWindowIcon_sys(bool forceReset) } } if (!icon_data.isEmpty()) { - if (q->internalWinId()) { - XChangeProperty(X11->display, q->internalWinId(), ATOM(_NET_WM_ICON), XA_CARDINAL, 32, - PropModeReplace, (unsigned char *) icon_data.data(), - icon_data.size()); - } extern QPixmap qt_toX11Pixmap(const QPixmap &pixmap); /* if the app is running on an unknown desktop, or it is not @@ -1368,22 +1469,44 @@ void QWidgetPrivate::setWindowIcon_sys(bool forceReset) // unknown DE or non-default visual/colormap, use 1bpp bitmap if (!forceReset || !topData->iconPixmap) topData->iconPixmap = new QBitmap(qt_toX11Pixmap(icon.pixmap(QSize(64,64)))); - h->icon_pixmap = topData->iconPixmap->handle(); + pixmap_handle = topData->iconPixmap->handle(); } else { // default depth, use a normal pixmap (even though this // 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)))); - h->icon_pixmap = static_cast<QX11PixmapData*>(topData->iconPixmap->data)->x11ConvertToDefaultDepth(); + pixmap_handle = static_cast<QX11PixmapData*>(topData->iconPixmap->data.data())->x11ConvertToDefaultDepth(); } - h->flags |= IconPixmapHint; - } else { - h->flags &= ~(IconPixmapHint | IconMaskHint); } } - if (q->internalWinId()) - XSetWMHints(X11->display, q->internalWinId(), h); + if (!q->internalWinId()) + return; + + if (!icon_data.isEmpty()) { + XChangeProperty(X11->display, q->internalWinId(), ATOM(_NET_WM_ICON), XA_CARDINAL, 32, + PropModeReplace, (unsigned char *) icon_data.data(), + icon_data.size()); + } else { + XDeleteProperty(X11->display, q->internalWinId(), ATOM(_NET_WM_ICON)); + } + + XWMHints *h = XGetWMHints(X11->display, q->internalWinId()); + XWMHints wm_hints; + if (!h) { + memset(&wm_hints, 0, sizeof(wm_hints)); // make valgrind happy + h = &wm_hints; + } + + if (pixmap_handle) { + h->icon_pixmap = pixmap_handle; + h->flags |= IconPixmapHint; + } else { + h->icon_pixmap = 0; + h->flags &= ~(IconPixmapHint | IconMaskHint); + } + + XSetWMHints(X11->display, q->internalWinId(), h); if (h != &wm_hints) XFree((char *)h); } @@ -1817,6 +1940,23 @@ void QWidgetPrivate::show_sys() if (setUserTime) qt_net_update_user_time(q, userTime); +#ifndef QT_NO_XSYNC + if (!topData()->syncUpdateCounter) { + XSyncValue value; + XSyncIntToValue(&value, 0); + topData()->syncUpdateCounter = XSyncCreateCounter(X11->display, value); + + XChangeProperty(X11->display, q->internalWinId(), + ATOM(_NET_WM_SYNC_REQUEST_COUNTER), + XA_CARDINAL, + 32, PropModeReplace, + (uchar *) &topData()->syncUpdateCounter, 1); + + topData()->newCounterValueHi = 0; + topData()->newCounterValueLo = 0; + } +#endif + if (!topData()->embedded && (topData()->validWMState || topData()->waitingForMapNotify) && !q->isMinimized()) { @@ -2151,7 +2291,7 @@ static void do_size_hints(QWidget* widget, QWExtra *x) parentWRect is the geometry of the parent's X rect, measured in parent's coord sys */ -void QWidgetPrivate::setWSGeometry(bool dontShow) +void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &) { Q_Q(QWidget); Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); @@ -2611,8 +2751,8 @@ int QWidget::metric(PaintDeviceMetric m) const void QWidgetPrivate::createSysExtra() { - extra->xDndProxy = 0; extra->compress_events = true; + extra->xDndProxy = 0; } void QWidgetPrivate::deleteSysExtra() @@ -2621,9 +2761,18 @@ void QWidgetPrivate::deleteSysExtra() void QWidgetPrivate::createTLSysExtra() { + extra->topextra->spont_unmapped = 0; + extra->topextra->dnd = 0; extra->topextra->validWMState = 0; extra->topextra->waitingForMapNotify = 0; + extra->topextra->parentWinId = 0; extra->topextra->userTimeWindow = 0; +#ifndef QT_NO_XSYNC + extra->topextra->syncUpdateCounter = 0; + extra->topextra->syncRequestTimestamp = 0; + extra->topextra->newCounterValueHi = 0; + extra->topextra->newCounterValueLo = 0; +#endif } void QWidgetPrivate::deleteTLSysExtra() diff --git a/src/gui/kernel/qwidgetaction.cpp b/src/gui/kernel/qwidgetaction.cpp index ee767d0..7dc2c67 100644 --- a/src/gui/kernel/qwidgetaction.cpp +++ b/src/gui/kernel/qwidgetaction.cpp @@ -54,6 +54,8 @@ QT_BEGIN_NAMESPACE for inserting custom widgets into action based containers, such as toolbars. + \ingroup mainwindow-classes + Most actions in an application are represented as items in menus or buttons in toolbars. However sometimes more complex widgets are necessary. For example a zoom action in a word processor may be @@ -100,9 +102,6 @@ QT_BEGIN_NAMESPACE DirectConnection. \endlist - \ingroup application - \mainclass - \sa QAction, QActionGroup, QWidget */ @@ -228,8 +227,8 @@ bool QWidgetAction::event(QEvent *event) if (event->type() == QEvent::ActionChanged) { if (d->defaultWidget) d->defaultWidget->setEnabled(isEnabled()); - foreach (QWidget *w, d->createdWidgets) - w->setEnabled(isEnabled()); + for (int i = 0; i < d->createdWidgets.count(); ++i) + d->createdWidgets.at(i)->setEnabled(isEnabled()); } return QAction::event(event); } diff --git a/src/gui/kernel/qwindowdefs.h b/src/gui/kernel/qwindowdefs.h index d2fd836..260c8b7 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/qwindowdefs_win.h b/src/gui/kernel/qwindowdefs_win.h index 8492bb2..cfaf4bc 100644 --- a/src/gui/kernel/qwindowdefs_win.h +++ b/src/gui/kernel/qwindowdefs_win.h @@ -122,7 +122,7 @@ QT_BEGIN_NAMESPACE Q_CORE_EXPORT HINSTANCE qWinAppInst(); Q_CORE_EXPORT HINSTANCE qWinAppPrevInst(); -Q_GUI_EXPORT int qWinAppCmdShow(); +Q_CORE_EXPORT int qWinAppCmdShow(); Q_GUI_EXPORT HDC qt_win_display_dc(); QT_END_NAMESPACE diff --git a/src/gui/kernel/qwinnativepangesturerecognizer_win.cpp b/src/gui/kernel/qwinnativepangesturerecognizer_win.cpp new file mode 100644 index 0000000..5fceb13 --- /dev/null +++ b/src/gui/kernel/qwinnativepangesturerecognizer_win.cpp @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qwinnativepangesturerecognizer_win_p.h" + +#include "qevent.h" +#include "qgraphicsitem.h" +#include "qgesture.h" + +#include "private/qgesture_p.h" +#include "private/qevent_p.h" +#include "private/qapplication_p.h" +#include "private/qwidget_p.h" + +QT_BEGIN_NAMESPACE + +QWinNativePanGestureRecognizer::QWinNativePanGestureRecognizer() +{ +} + +QGesture *QWinNativePanGestureRecognizer::create(QObject *target) +{ + if (!target) + return new QPanGesture; // a special case + if (!target->isWidgetType()) + return 0; + if (qobject_cast<QGraphicsObject *>(target)) + return 0; + + QWidget *q = static_cast<QWidget *>(target); + QWidgetPrivate *d = q->d_func(); + d->nativeGesturePanEnabled = true; + d->winSetupGestures(); + + return new QPanGesture; +} + +QGestureRecognizer::Result QWinNativePanGestureRecognizer::recognize(QGesture *state, + QObject *, + QEvent *event) +{ + QPanGesture *q = static_cast<QPanGesture*>(state); + QPanGesturePrivate *d = q->d_func(); + + QGestureRecognizer::Result result = QGestureRecognizer::Ignore; + if (event->type() == QEvent::NativeGesture) { + QNativeGestureEvent *ev = static_cast<QNativeGestureEvent*>(event); + switch(ev->gestureType) { + case QNativeGestureEvent::GestureBegin: + break; + case QNativeGestureEvent::Pan: + result = QGestureRecognizer::TriggerGesture; + event->accept(); + break; + case QNativeGestureEvent::GestureEnd: + if (q->state() == Qt::NoGesture) + return QGestureRecognizer::Ignore; // some other gesture has ended + result = QGestureRecognizer::FinishGesture; + break; + default: + return QGestureRecognizer::Ignore; + } + if (q->state() == Qt::NoGesture) { + d->lastOffset = d->offset = QPointF(); + d->startPosition = ev->position; + } else { + d->lastOffset = d->offset; + d->offset = QPointF(ev->position.x() - d->startPosition.x(), + ev->position.y() - d->startPosition.y()); + } + } + return result; +} + +void QWinNativePanGestureRecognizer::reset(QGesture *state) +{ + QPanGesture *pan = static_cast<QPanGesture*>(state); + QPanGesturePrivate *d = pan->d_func(); + + d->lastOffset = d->offset = QPointF(); + d->startPosition = QPoint(); + d->acceleration = 0; + + QGestureRecognizer::reset(state); +} + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qwinnativepangesturerecognizer_win_p.h b/src/gui/kernel/qwinnativepangesturerecognizer_win_p.h new file mode 100644 index 0000000..8fb0d50 --- /dev/null +++ b/src/gui/kernel/qwinnativepangesturerecognizer_win_p.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINNATIVEPANGESTURERECOGNIZER_WIN_P_H +#define QWINNATIVEPANGESTURERECOGNIZER_WIN_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QGestureRecognizer> + +QT_BEGIN_NAMESPACE + +class QWinNativePanGestureRecognizer : public QGestureRecognizer +{ +public: + QWinNativePanGestureRecognizer(); + + QGesture *create(QObject *target); + QGestureRecognizer::Result recognize(QGesture *state, QObject *watched, QEvent *event); + void reset(QGesture *state); +}; + +QT_END_NAMESPACE + +#endif // QWINNATIVEPANGESTURERECOGNIZER_WIN_P_H diff --git a/src/gui/kernel/qx11embed_x11.cpp b/src/gui/kernel/qx11embed_x11.cpp index 5579568..8333fbb 100644 --- a/src/gui/kernel/qx11embed_x11.cpp +++ b/src/gui/kernel/qx11embed_x11.cpp @@ -39,6 +39,7 @@ ** ****************************************************************************/ +#include "qplatformdefs.h" #include "qx11embed_x11.h" #include <qapplication.h> #include <qevent.h> @@ -122,8 +123,8 @@ QT_BEGIN_NAMESPACE emitted. There are XEmbed widgets available for KDE and GTK+. The GTK+ - equivalent of QX11EmbedWidget is GtkPlug. The KDE widget is called - QXEmbed. + equivalent of QX11EmbedWidget is GtkPlug. The corresponding KDE 3 + widget is called QXEmbed. \sa QX11EmbedContainer, {XEmbed Specification} */ @@ -176,8 +177,8 @@ QT_BEGIN_NAMESPACE features such as window activation and focus handling are then lost. - The GTK+ equivalent of QX11EmbedContainer is GtkSocket. The KDE - widget is called QXEmbed. + The GTK+ equivalent of QX11EmbedContainer is GtkSocket. The + corresponding KDE 3 widget is called QXEmbed. \sa QX11EmbedWidget, {XEmbed Specification} */ @@ -826,7 +827,7 @@ bool QX11EmbedWidget::x11Event(XEvent *event) &actual_format_return, &nitems_return, &bytes_after_return, &prop_return) == Success) { if (nitems_return > 1) { - if (((int * )prop_return)[1] & XEMBED_MAPPED) { + if (((long * )prop_return)[1] & XEMBED_MAPPED) { XMapWindow(x11Info().display(), internalWinId()); } else { XUnmapWindow(x11Info().display(), internalWinId()); @@ -1297,9 +1298,6 @@ bool QX11EmbedContainer::eventFilter(QObject *o, QEvent *event) // focus is set to our focus proxy. We want to intercept all // keypresses. if (o == window() && d->client) { - if (!d->isEmbedded() && d->activeContainer == this) - d->moveInputToProxy(); - if (d->clientIsXEmbed) { sendXEmbedMessage(d->client, x11Info().display(), XEMBED_WINDOW_ACTIVATE); } else { @@ -1307,6 +1305,8 @@ bool QX11EmbedContainer::eventFilter(QObject *o, QEvent *event) if (hasFocus()) XSetInputFocus(x11Info().display(), d->client, XRevertToParent, x11Time()); } + if (!d->isEmbedded()) + d->moveInputToProxy(); } break; case QEvent::WindowDeactivate: @@ -1671,9 +1671,9 @@ void QX11EmbedContainerPrivate::acceptClient(WId window) // Clients with the _XEMBED_INFO property are XEMBED clients. clientIsXEmbed = true; - unsigned int *p = (unsigned int *)prop_return; + long *p = (long *)prop_return; if (nitems_return >= 2) - clientversion = p[0]; + clientversion = (unsigned int)p[0]; } XFree(prop_return); @@ -1729,10 +1729,10 @@ void QX11EmbedContainerPrivate::acceptClient(WId window) checkGrab(); if (q->hasFocus()) { XSetInputFocus(q->x11Info().display(), client, XRevertToParent, x11Time()); - } else { - if (!isEmbedded()) - moveInputToProxy(); } + } else { + if (!isEmbedded()) + moveInputToProxy(); } emit q->clientIsEmbedded(); @@ -1749,11 +1749,9 @@ void QX11EmbedContainerPrivate::acceptClient(WId window) void QX11EmbedContainerPrivate::moveInputToProxy() { Q_Q(QX11EmbedContainer); - WId focus; - int revert_to; - XGetInputFocus(q->x11Info().display(), &focus, &revert_to); - if (focus != focusProxy->internalWinId()) - XSetInputFocus(q->x11Info().display(), focusProxy->internalWinId(), XRevertToParent, x11Time()); + // Following Owen Taylor's advice from the XEmbed specification to + // always use CurrentTime when no explicit user action is involved. + XSetInputFocus(q->x11Info().display(), focusProxy->internalWinId(), XRevertToParent, CurrentTime); } /*! \internal diff --git a/src/gui/kernel/qx11info_x11.cpp b/src/gui/kernel/qx11info_x11.cpp index b0f4983..2fed654 100644 --- a/src/gui/kernel/qx11info_x11.cpp +++ b/src/gui/kernel/qx11info_x11.cpp @@ -179,6 +179,7 @@ QX11InfoData* QX11Info::getX11Data(bool def) const QX11InfoData* res = 0; if (def) { res = new QX11InfoData; + res->ref = 0; res->screen = appScreen(); res->depth = appDepth(); res->cells = appCells(); @@ -189,8 +190,8 @@ QX11InfoData* QX11Info::getX11Data(bool def) const } else if (x11data) { res = new QX11InfoData; *res = *x11data; + res->ref = 0; } - res->ref = 0; return res; } diff --git a/src/gui/kernel/symbian.pri b/src/gui/kernel/symbian.pri new file mode 100644 index 0000000..69422dd --- /dev/null +++ b/src/gui/kernel/symbian.pri @@ -0,0 +1,7 @@ +symbian { + contains(QT_CONFIG, s60): LIBS+= $$QMAKE_LIBS_S60 + RESOURCES += symbian/symbianresources.qrc + + HEADERS += symbian/qsymbianevent.h + SOURCES += symbian/qsymbianevent.cpp +} diff --git a/src/gui/kernel/x11.pri b/src/gui/kernel/x11.pri index ac40f69..82de1b6 100644 --- a/src/gui/kernel/x11.pri +++ b/src/gui/kernel/x11.pri @@ -1,4 +1,4 @@ x11 { - contains(QT_CONFIG, nas): LIBS += -laudio -lXt + contains(QT_CONFIG, nas): LIBS_PRIVATE += -laudio -lXt } |