summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms')
-rw-r--r--src/plugins/platforms/android/android.pro3
-rw-r--r--src/plugins/platforms/android/opengl/opengl.pro30
-rw-r--r--src/plugins/platforms/android/raster/raster.pro19
-rw-r--r--src/plugins/platforms/android/src/android.json3
-rw-r--r--src/plugins/platforms/android/src/androidjniclipboard.cpp120
-rw-r--r--src/plugins/platforms/android/src/androidjniclipboard.h61
-rw-r--r--src/plugins/platforms/android/src/androidjniinput.cpp497
-rw-r--r--src/plugins/platforms/android/src/androidjniinput.h59
-rw-r--r--src/plugins/platforms/android/src/androidjnimain.cpp824
-rw-r--r--src/plugins/platforms/android/src/androidjnimain.h121
-rw-r--r--src/plugins/platforms/android/src/androidjnimenu.cpp405
-rw-r--r--src/plugins/platforms/android/src/androidjnimenu.h69
-rw-r--r--src/plugins/platforms/android/src/androidplatformplugin.cpp66
-rw-r--r--src/plugins/platforms/android/src/opengl/qandroidopenglcontext.cpp78
-rw-r--r--src/plugins/platforms/android/src/opengl/qandroidopenglcontext.h68
-rw-r--r--src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.cpp72
-rw-r--r--src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.h73
-rw-r--r--src/plugins/platforms/android/src/opengl/qeglfshooks_android.cpp132
-rw-r--r--src/plugins/platforms/android/src/qandroidassetsfileenginehandler.cpp288
-rw-r--r--src/plugins/platforms/android/src/qandroidassetsfileenginehandler.h60
-rw-r--r--src/plugins/platforms/android/src/qandroidinputcontext.cpp653
-rw-r--r--src/plugins/platforms/android/src/qandroidinputcontext.h132
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformclipboard.cpp79
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformclipboard.h63
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformfontdatabase.cpp79
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformfontdatabase.h58
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformintegration.cpp285
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformintegration.h164
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformmenu.cpp167
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformmenu.h91
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformmenubar.cpp109
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformmenubar.h74
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformmenuitem.cpp180
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformmenuitem.h99
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformservices.cpp83
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformservices.h61
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformtheme.cpp78
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformtheme.h56
-rw-r--r--src/plugins/platforms/android/src/raster/qandroidplatformscreen.cpp71
-rw-r--r--src/plugins/platforms/android/src/raster/qandroidplatformscreen.h59
-rw-r--r--src/plugins/platforms/android/src/raster/qandroidplatformwindow.cpp56
-rw-r--r--src/plugins/platforms/android/src/raster/qandroidplatformwindow.h60
-rw-r--r--src/plugins/platforms/android/src/raster/raster.pri7
-rw-r--r--src/plugins/platforms/android/src/src.pri47
-rw-r--r--src/plugins/platforms/cocoa/cocoa.pro5
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibility.h7
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibility.mm17
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h13
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm121
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h13
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm4
-rw-r--r--src/plugins/platforms/cocoa/qcocoabackingstore.mm10
-rw-r--r--src/plugins/platforms/cocoa/qcocoacursor.mm7
-rw-r--r--src/plugins/platforms/cocoa/qcocoaeventdispatcher.h12
-rw-r--r--src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm239
-rw-r--r--src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm34
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.mm16
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.mm28
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.mm41
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintrospection.mm4
-rw-r--r--src/plugins/platforms/cocoa/qcocoakeymapper.h1
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.h12
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.mm35
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenubar.mm4
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuitem.h5
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuitem.mm7
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuloader.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuloader.mm10
-rw-r--r--src/plugins/platforms/cocoa/qcocoanativeinterface.h19
-rw-r--r--src/plugins/platforms/cocoa/qcocoanativeinterface.mm37
-rw-r--r--src/plugins/platforms/cocoa/qcocoaprintersupport.h1
-rw-r--r--src/plugins/platforms/cocoa/qcocoaprintersupport.mm31
-rw-r--r--src/plugins/platforms/cocoa/qcocoasystemsettings.mm9
-rwxr-xr-xsrc/plugins/platforms/cocoa/qcocoasystemtrayicon.h2
-rwxr-xr-xsrc/plugins/platforms/cocoa/qcocoasystemtrayicon.mm47
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.h14
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm114
-rw-r--r--src/plugins/platforms/cocoa/qmacdefines_mac.h4
-rw-r--r--src/plugins/platforms/cocoa/qmultitouch_mac.mm5
-rw-r--r--src/plugins/platforms/cocoa/qmultitouch_mac_p.h4
-rw-r--r--src/plugins/platforms/cocoa/qnsview.h5
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm174
-rw-r--r--src/plugins/platforms/cocoa/qnsviewaccessibility.mm15
-rw-r--r--src/plugins/platforms/cocoa/qnswindowdelegate.h20
-rw-r--r--src/plugins/platforms/cocoa/qpaintengine_mac.mm25
-rw-r--r--src/plugins/platforms/cocoa/qpaintengine_mac_p.h41
-rw-r--r--src/plugins/platforms/cocoa/qprintengine_mac.mm56
-rw-r--r--src/plugins/platforms/cocoa/qprintengine_mac_p.h3
-rw-r--r--src/plugins/platforms/directfb/qdirectfbcursor.cpp5
-rw-r--r--src/plugins/platforms/eglfs/eglfs.pri44
-rw-r--r--src/plugins/platforms/eglfs/eglfs.pro46
-rw-r--r--src/plugins/platforms/eglfs/qeglfscontext.cpp22
-rw-r--r--src/plugins/platforms/eglfs/qeglfscursor.cpp7
-rw-r--r--src/plugins/platforms/eglfs/qeglfshooks.h20
-rw-r--r--src/plugins/platforms/eglfs/qeglfshooks_stub.cpp134
-rw-r--r--src/plugins/platforms/eglfs/qeglfsintegration.cpp52
-rw-r--r--src/plugins/platforms/eglfs/qeglfsintegration.h12
-rw-r--r--src/plugins/platforms/eglfs/qeglfsscreen.cpp13
-rw-r--r--src/plugins/platforms/eglfs/qeglfsscreen.h2
-rw-r--r--src/plugins/platforms/eglfs/qeglfswindow.cpp37
-rw-r--r--src/plugins/platforms/eglfs/qeglfswindow.h4
-rw-r--r--src/plugins/platforms/ios/ios.json3
-rw-r--r--src/plugins/platforms/ios/ios.pro3
-rw-r--r--src/plugins/platforms/ios/plugin.mm69
-rw-r--r--src/plugins/platforms/ios/plugin.pro36
-rw-r--r--src/plugins/platforms/ios/qiosapplicationdelegate.h53
-rw-r--r--src/plugins/platforms/ios/qiosapplicationdelegate.mm94
-rw-r--r--src/plugins/platforms/ios/qiosbackingstore.h70
-rw-r--r--src/plugins/platforms/ios/qiosbackingstore.mm125
-rw-r--r--src/plugins/platforms/ios/qioscontext.h91
-rw-r--r--src/plugins/platforms/ios/qioscontext.mm204
-rw-r--r--src/plugins/platforms/ios/qioseventdispatcher.h133
-rw-r--r--src/plugins/platforms/ios/qioseventdispatcher.mm322
-rw-r--r--src/plugins/platforms/ios/qiosglobal.h67
-rw-r--r--src/plugins/platforms/ios/qiosglobal.mm144
-rw-r--r--src/plugins/platforms/ios/qiosinputcontext.h73
-rw-r--r--src/plugins/platforms/ios/qiosinputcontext.mm142
-rw-r--r--src/plugins/platforms/ios/qiosintegration.h88
-rw-r--r--src/plugins/platforms/ios/qiosintegration.mm180
-rw-r--r--src/plugins/platforms/ios/qiosscreen.h88
-rw-r--r--src/plugins/platforms/ios/qiosscreen.mm238
-rw-r--r--src/plugins/platforms/ios/qiossoftwareinputhandler.h71
-rw-r--r--src/plugins/platforms/ios/qiostheme.h64
-rw-r--r--src/plugins/platforms/ios/qiostheme.mm96
-rw-r--r--src/plugins/platforms/ios/qiosviewcontroller.h46
-rw-r--r--src/plugins/platforms/ios/qiosviewcontroller.mm90
-rw-r--r--src/plugins/platforms/ios/qioswindow.h103
-rw-r--r--src/plugins/platforms/ios/qioswindow.mm523
-rw-r--r--src/plugins/platforms/ios/qtmain.mm93
-rw-r--r--src/plugins/platforms/ios/qtmain.pro8
-rw-r--r--src/plugins/platforms/kms/kms.pro5
-rw-r--r--src/plugins/platforms/kms/qkmscursor.cpp68
-rw-r--r--src/plugins/platforms/kms/qkmscursor.h10
-rw-r--r--src/plugins/platforms/kms/qkmsscreen.cpp12
-rw-r--r--src/plugins/platforms/minimalegl/qminimaleglbackingstore.cpp1
-rw-r--r--src/plugins/platforms/minimalegl/qminimaleglintegration.h3
-rw-r--r--src/plugins/platforms/offscreen/main.cpp67
-rw-r--r--src/plugins/platforms/offscreen/offscreen.json3
-rw-r--r--src/plugins/platforms/offscreen/offscreen.pro25
-rw-r--r--src/plugins/platforms/offscreen/qoffscreencommon.cpp229
-rw-r--r--src/plugins/platforms/offscreen/qoffscreencommon.h109
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenintegration.cpp162
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenintegration.h80
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenintegration_dummy.cpp47
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp252
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenintegration_x11.h108
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenwindow.cpp199
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenwindow.h86
-rw-r--r--src/plugins/platforms/platforms.pro9
-rw-r--r--src/plugins/platforms/qnx/qnx.pro7
-rw-r--r--src/plugins/platforms/qnx/qqnxabstractnavigator.cpp2
-rw-r--r--src/plugins/platforms/qnx/qqnxbpseventfilter.cpp24
-rw-r--r--src/plugins/platforms/qnx/qqnxbuffer.cpp2
-rw-r--r--src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp2
-rw-r--r--src/plugins/platforms/qnx/qqnxclipboard.cpp4
-rw-r--r--src/plugins/platforms/qnx/qqnxclipboard.h4
-rw-r--r--src/plugins/platforms/qnx/qqnxcursor.cpp78
-rw-r--r--src/plugins/platforms/qnx/qqnxcursor.h67
-rw-r--r--src/plugins/platforms/qnx/qqnxfiledialoghelper.cpp2
-rw-r--r--src/plugins/platforms/qnx/qqnxglcontext.cpp2
-rw-r--r--src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp4
-rw-r--r--src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp2
-rw-r--r--src/plugins/platforms/qnx/qqnxintegration.cpp4
-rw-r--r--src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp8
-rw-r--r--src/plugins/platforms/qnx/qqnxnavigatoreventhandler.h2
-rw-r--r--src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp2
-rw-r--r--src/plugins/platforms/qnx/qqnxnavigatorpps.cpp2
-rw-r--r--src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp2
-rw-r--r--src/plugins/platforms/qnx/qqnxrootwindow.cpp2
-rw-r--r--src/plugins/platforms/qnx/qqnxscreen.cpp56
-rw-r--r--src/plugins/platforms/qnx/qqnxscreen.h7
-rw-r--r--src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp4
-rw-r--r--src/plugins/platforms/qnx/qqnxscreeneventthread.cpp2
-rw-r--r--src/plugins/platforms/qnx/qqnxtheme.cpp4
-rw-r--r--src/plugins/platforms/qnx/qqnxvirtualkeyboardbps.cpp2
-rw-r--r--src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp2
-rw-r--r--src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h6
-rw-r--r--src/plugins/platforms/qnx/qqnxwindow.cpp64
-rw-r--r--src/plugins/platforms/qnx/qqnxwindow.h9
-rw-r--r--src/plugins/platforms/windows/accessible/iaccessible2.cpp233
-rw-r--r--src/plugins/platforms/windows/accessible/iaccessible2.h14
-rw-r--r--src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp65
-rw-r--r--src/plugins/platforms/windows/accessible/qwindowsaccessibility.h4
-rw-r--r--src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp183
-rw-r--r--src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h25
-rw-r--r--src/plugins/platforms/windows/qtwindows_additional.h4
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp94
-rw-r--r--src/plugins/platforms/windows/qwindowscursor.cpp35
-rw-r--r--src/plugins/platforms/windows/qwindowscursor.h5
-rw-r--r--src/plugins/platforms/windows/qwindowsdialoghelpers.cpp579
-rw-r--r--src/plugins/platforms/windows/qwindowsdialoghelpers.h10
-rw-r--r--src/plugins/platforms/windows/qwindowsdrag.cpp6
-rw-r--r--src/plugins/platforms/windows/qwindowsfontdatabase.cpp215
-rw-r--r--src/plugins/platforms/windows/qwindowsfontdatabase.h4
-rw-r--r--src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp96
-rw-r--r--src/plugins/platforms/windows/qwindowsfontdatabase_ft.h4
-rw-r--r--src/plugins/platforms/windows/qwindowsfontengine.cpp20
-rw-r--r--src/plugins/platforms/windows/qwindowsfontengine.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp6
-rw-r--r--src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsglcontext.cpp14
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.cpp42
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.h2
-rw-r--r--src/plugins/platforms/windows/qwindowskeymapper.cpp14
-rw-r--r--src/plugins/platforms/windows/qwindowsmime.cpp4
-rw-r--r--src/plugins/platforms/windows/qwindowsmousehandler.cpp4
-rw-r--r--src/plugins/platforms/windows/qwindowsmousehandler.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsservices.cpp4
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp218
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.h26
-rw-r--r--src/plugins/platforms/windows/windows.pro4
-rw-r--r--src/plugins/platforms/xcb/qglxintegration.cpp354
-rw-r--r--src/plugins/platforms/xcb/qglxintegration.h35
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp7
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h2
-rw-r--r--src/plugins/platforms/xcb/qxcbcursor.cpp34
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.cpp51
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.h12
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.cpp9
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp302
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h10
223 files changed, 13628 insertions, 1832 deletions
diff --git a/src/plugins/platforms/android/android.pro b/src/plugins/platforms/android/android.pro
new file mode 100644
index 0000000000..aa5ab4ddbd
--- /dev/null
+++ b/src/plugins/platforms/android/android.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+
+SUBDIRS += raster opengl
diff --git a/src/plugins/platforms/android/opengl/opengl.pro b/src/plugins/platforms/android/opengl/opengl.pro
new file mode 100644
index 0000000000..301c8e6e4c
--- /dev/null
+++ b/src/plugins/platforms/android/opengl/opengl.pro
@@ -0,0 +1,30 @@
+TARGET = qtforandroidGL
+
+PLUGIN_TYPE = platforms
+load(qt_plugin)
+
+# STATICPLUGIN needed because there's a Q_IMPORT_PLUGIN in androidjnimain.cpp
+# Yes, the plugin imports itself statically
+DEFINES += QT_STATICPLUGIN ANDROID_PLUGIN_OPENGL
+
+!equals(ANDROID_PLATFORM, android-9) {
+ INCLUDEPATH += $$NDK_ROOT/platforms/android-9/arch-$$ANDROID_ARCHITECTURE/usr/include
+ LIBS += -L$$NDK_ROOT/platforms/android-9/arch-$$ANDROID_ARCHITECTURE/usr/lib -ljnigraphics -landroid
+} else {
+ LIBS += -ljnigraphics -landroid
+}
+
+EGLFS_PLATFORM_HOOKS_SOURCES = $$PWD/../src/opengl/qeglfshooks_android.cpp
+
+INCLUDEPATH += $$PWD/../src/opengl/
+
+HEADERS += \
+ $$PWD/../src/opengl/qandroidopenglcontext.h \
+ $$PWD/../src/opengl/qandroidopenglplatformwindow.h
+
+SOURCES += \
+ $$PWD/../src/opengl/qandroidopenglcontext.cpp \
+ $$PWD/../src/opengl/qandroidopenglplatformwindow.cpp
+
+include($$PWD/../../eglfs/eglfs.pri)
+include($$PWD/../src/src.pri)
diff --git a/src/plugins/platforms/android/raster/raster.pro b/src/plugins/platforms/android/raster/raster.pro
new file mode 100644
index 0000000000..53d8ee7a2b
--- /dev/null
+++ b/src/plugins/platforms/android/raster/raster.pro
@@ -0,0 +1,19 @@
+TARGET = qtforandroid
+
+PLUGIN_TYPE = platforms
+
+# STATICPLUGIN needed because there's a Q_IMPORT_PLUGIN in androidjnimain.cpp
+# Yes, the plugin imports itself statically
+DEFINES += QT_STATICPLUGIN
+
+load(qt_plugin)
+
+!contains(ANDROID_PLATFORM, android-9) {
+ INCLUDEPATH += $$NDK_ROOT/platforms/android-9/arch-$$ANDROID_ARCHITECTURE/usr/include
+ LIBS += -L$$NDK_ROOT/platforms/android-9/arch-$$ANDROID_ARCHITECTURE/usr/lib -ljnigraphics -landroid
+} else {
+ LIBS += -ljnigraphics -landroid
+}
+
+include($$PWD/../src/src.pri)
+include($$PWD/../src/raster/raster.pri)
diff --git a/src/plugins/platforms/android/src/android.json b/src/plugins/platforms/android/src/android.json
new file mode 100644
index 0000000000..6843bd3301
--- /dev/null
+++ b/src/plugins/platforms/android/src/android.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "android" ]
+}
diff --git a/src/plugins/platforms/android/src/androidjniclipboard.cpp b/src/plugins/platforms/android/src/androidjniclipboard.cpp
new file mode 100644
index 0000000000..05270ac374
--- /dev/null
+++ b/src/plugins/platforms/android/src/androidjniclipboard.cpp
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "androidjniclipboard.h"
+#include "androidjnimain.h"
+
+using namespace QtAndroid;
+namespace QtAndroidClipboard
+{
+ // Clipboard support
+ static jmethodID m_registerClipboardManagerMethodID = 0;
+ static jmethodID m_setClipboardTextMethodID = 0;
+ static jmethodID m_hasClipboardTextMethodID = 0;
+ static jmethodID m_getClipboardTextMethodID = 0;
+ // Clipboard support
+
+ void setClipboardListener(QAndroidPlatformClipboard *listener)
+ {
+ Q_UNUSED(listener);
+
+ AttachedJNIEnv env;
+ if (!env.jniEnv)
+ return;
+
+ env.jniEnv->CallStaticVoidMethod(applicationClass(), m_registerClipboardManagerMethodID);
+ }
+
+ void setClipboardText(const QString &text)
+ {
+ AttachedJNIEnv env;
+ if (!env.jniEnv)
+ return;
+
+ jstring jtext = env.jniEnv->NewString(reinterpret_cast<const jchar *>(text.data()),
+ text.length());
+ env.jniEnv->CallStaticVoidMethod(applicationClass(), m_setClipboardTextMethodID, jtext);
+ env.jniEnv->DeleteLocalRef(jtext);
+ }
+
+ bool hasClipboardText()
+ {
+ AttachedJNIEnv env;
+ if (!env.jniEnv)
+ return false;
+
+ return env.jniEnv->CallStaticBooleanMethod(applicationClass(), m_hasClipboardTextMethodID);
+ }
+
+ QString clipboardText()
+ {
+ AttachedJNIEnv env;
+ if (!env.jniEnv)
+ return QString();
+
+ jstring text = reinterpret_cast<jstring>(env.jniEnv->CallStaticObjectMethod(applicationClass(),
+ m_getClipboardTextMethodID));
+ const jchar *jstr = env.jniEnv->GetStringChars(text, 0);
+ QString str(reinterpret_cast<const QChar *>(jstr), env.jniEnv->GetStringLength(text));
+ env.jniEnv->ReleaseStringChars(text, jstr);
+ return str;
+ }
+
+
+#define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
+ VAR = env->GetStaticMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
+ if (!VAR) { \
+ __android_log_print(ANDROID_LOG_FATAL, qtTagText(), methodErrorMsgFmt(), METHOD_NAME, METHOD_SIGNATURE); \
+ return false; \
+ }
+
+ bool registerNatives(JNIEnv *env)
+ {
+ jclass appClass = QtAndroid::applicationClass();
+
+ GET_AND_CHECK_STATIC_METHOD(m_registerClipboardManagerMethodID, appClass, "registerClipboardManager", "()V");
+ GET_AND_CHECK_STATIC_METHOD(m_setClipboardTextMethodID, appClass, "setClipboardText", "(Ljava/lang/String;)V");
+ GET_AND_CHECK_STATIC_METHOD(m_hasClipboardTextMethodID, appClass, "hasClipboardText", "()Z");
+ GET_AND_CHECK_STATIC_METHOD(m_getClipboardTextMethodID, appClass, "getClipboardText", "()Ljava/lang/String;");
+
+ return true;
+ }
+}
diff --git a/src/plugins/platforms/android/src/androidjniclipboard.h b/src/plugins/platforms/android/src/androidjniclipboard.h
new file mode 100644
index 0000000000..15cd93202e
--- /dev/null
+++ b/src/plugins/platforms/android/src/androidjniclipboard.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ANDROIDJNICLIPBOARD_H
+#define ANDROIDJNICLIPBOARD_H
+
+#include <jni.h>
+#include <QString>
+
+class QAndroidPlatformClipboard;
+namespace QtAndroidClipboard
+{
+ // Clipboard support
+ void setClipboardListener(QAndroidPlatformClipboard *listener);
+ void setClipboardText(const QString &text);
+ bool hasClipboardText();
+ QString clipboardText();
+ // Clipboard support
+
+ bool registerNatives(JNIEnv *env);
+}
+
+#endif // ANDROIDJNICLIPBOARD_H
diff --git a/src/plugins/platforms/android/src/androidjniinput.cpp b/src/plugins/platforms/android/src/androidjniinput.cpp
new file mode 100644
index 0000000000..da6156a330
--- /dev/null
+++ b/src/plugins/platforms/android/src/androidjniinput.cpp
@@ -0,0 +1,497 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "androidjniinput.h"
+#include "androidjnimain.h"
+#include "qandroidplatformintegration.h"
+
+#include <qpa/qwindowsysteminterface.h>
+#include <QTouchEvent>
+#include <QPointer>
+
+using namespace QtAndroid;
+
+namespace QtAndroidInput
+{
+ static jmethodID m_showSoftwareKeyboardMethodID = 0;
+ static jmethodID m_resetSoftwareKeyboardMethodID = 0;
+ static jmethodID m_hideSoftwareKeyboardMethodID = 0;
+ static jmethodID m_isSoftwareKeyboardVisibleMethodID = 0;
+ static jmethodID m_updateSelectionMethodID = 0;
+
+ static bool m_ignoreMouseEvents = false;
+
+ static QList<QWindowSystemInterface::TouchPoint> m_touchPoints;
+
+ static QPointer<QWindow> m_mouseGrabber;
+
+ void updateSelection(int selStart, int selEnd, int candidatesStart, int candidatesEnd)
+ {
+ AttachedJNIEnv env;
+ if (!env.jniEnv)
+ return;
+
+ env.jniEnv->CallStaticVoidMethod(applicationClass(), m_updateSelectionMethodID,
+ selStart, selEnd, candidatesStart, candidatesEnd);
+ }
+
+ void showSoftwareKeyboard(int left, int top, int width, int height, int inputHints)
+ {
+ AttachedJNIEnv env;
+ if (!env.jniEnv)
+ return;
+
+ env.jniEnv->CallStaticVoidMethod(applicationClass(),
+ m_showSoftwareKeyboardMethodID,
+ left,
+ top,
+ width,
+ height,
+ inputHints);
+ }
+
+ void resetSoftwareKeyboard()
+ {
+ AttachedJNIEnv env;
+ if (!env.jniEnv)
+ return;
+
+ env.jniEnv->CallStaticVoidMethod(applicationClass(), m_resetSoftwareKeyboardMethodID);
+ }
+
+ void hideSoftwareKeyboard()
+ {
+ AttachedJNIEnv env;
+ if (!env.jniEnv)
+ return;
+
+ env.jniEnv->CallStaticVoidMethod(applicationClass(), m_hideSoftwareKeyboardMethodID);
+ }
+
+ bool isSoftwareKeyboardVisible()
+ {
+ AttachedJNIEnv env;
+ if (!env.jniEnv)
+ return false;
+
+ return env.jniEnv->CallStaticBooleanMethod(applicationClass(), m_isSoftwareKeyboardVisibleMethodID);
+ }
+
+
+ static void mouseDown(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
+ {
+ if (m_ignoreMouseEvents)
+ return;
+
+ QPoint globalPos(x,y);
+ QWindow *tlw = topLevelWindowAt(globalPos);
+ m_mouseGrabber = tlw;
+ QPoint localPos = tlw ? (globalPos - tlw->position()) : globalPos;
+ QWindowSystemInterface::handleMouseEvent(tlw,
+ localPos,
+ globalPos,
+ Qt::MouseButtons(Qt::LeftButton));
+ }
+
+ static void mouseUp(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
+ {
+ QPoint globalPos(x,y);
+ QWindow *tlw = m_mouseGrabber.data();
+ if (!tlw)
+ tlw = topLevelWindowAt(globalPos);
+ QPoint localPos = tlw ? (globalPos -tlw->position()) : globalPos;
+ QWindowSystemInterface::handleMouseEvent(tlw, localPos, globalPos
+ , Qt::MouseButtons(Qt::NoButton));
+ m_ignoreMouseEvents = false;
+ m_mouseGrabber = 0;
+ }
+
+ static void mouseMove(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
+ {
+
+ if (m_ignoreMouseEvents)
+ return;
+
+ QPoint globalPos(x,y);
+ QWindow *tlw = m_mouseGrabber.data();
+ if (!tlw)
+ tlw = topLevelWindowAt(globalPos);
+ QPoint localPos = tlw ? (globalPos-tlw->position()) : globalPos;
+ QWindowSystemInterface::handleMouseEvent(tlw,
+ localPos,
+ globalPos,
+ Qt::MouseButtons(Qt::LeftButton));
+ }
+
+ static void longPress(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
+ {
+ m_ignoreMouseEvents = true;
+ QPoint globalPos(x,y);
+ QWindow *tlw = topLevelWindowAt(globalPos);
+ QPoint localPos = tlw ? (globalPos-tlw->position()) : globalPos;
+
+ // Release left button
+ QWindowSystemInterface::handleMouseEvent(tlw,
+ localPos,
+ globalPos,
+ Qt::MouseButtons(Qt::NoButton));
+
+ // Press right button
+ QWindowSystemInterface::handleMouseEvent(tlw,
+ localPos,
+ globalPos,
+ Qt::MouseButtons(Qt::RightButton));
+ }
+
+ static void touchBegin(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/)
+ {
+ m_touchPoints.clear();
+ }
+
+ static void touchAdd(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint id, jint action, jboolean /*primary*/, jint x, jint y, jfloat size, jfloat pressure)
+ {
+ Qt::TouchPointState state = Qt::TouchPointStationary;
+ switch (action) {
+ case 0:
+ state = Qt::TouchPointPressed;
+ break;
+ case 1:
+ state = Qt::TouchPointMoved;
+ break;
+ case 2:
+ state = Qt::TouchPointStationary;
+ break;
+ case 3:
+ state = Qt::TouchPointReleased;
+ break;
+ }
+
+ const int dw = desktopWidthPixels();
+ const int dh = desktopHeightPixels();
+ QWindowSystemInterface::TouchPoint touchPoint;
+ touchPoint.id = id;
+ touchPoint.pressure = pressure;
+ touchPoint.normalPosition = QPointF(double(x / dw), double(y / dh));
+ touchPoint.state = state;
+ touchPoint.area = QRectF(x - double(dw*size) / 2.0,
+ y - double(dh*size) / 2.0,
+ double(dw*size),
+ double(dh*size));
+ m_touchPoints.push_back(touchPoint);
+ }
+
+ static void touchEnd(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint action)
+ {
+ if (m_touchPoints.isEmpty())
+ return;
+
+ QEvent::Type eventType = QEvent::None;
+ switch (action) {
+ case 0:
+ eventType = QEvent::TouchBegin;
+ break;
+ case 1:
+ eventType = QEvent::TouchUpdate;
+ break;
+ case 2:
+ eventType = QEvent::TouchEnd;
+ break;
+ }
+
+ QAndroidPlatformIntegration *platformIntegration = QtAndroid::androidPlatformIntegration();
+ QTouchDevice *touchDevice = platformIntegration->touchDevice();
+ if (touchDevice == 0) {
+ touchDevice = new QTouchDevice;
+ touchDevice->setType(QTouchDevice::TouchScreen);
+ touchDevice->setCapabilities(QTouchDevice::Position
+ | QTouchDevice::Area
+ | QTouchDevice::Pressure
+ | QTouchDevice::NormalizedPosition);
+ QWindowSystemInterface::registerTouchDevice(touchDevice);
+ platformIntegration->setTouchDevice(touchDevice);
+ }
+
+ QWindow *window = QtAndroid::topLevelWindowAt(m_touchPoints.at(0).area.center().toPoint());
+ QWindowSystemInterface::handleTouchEvent(window, touchDevice, m_touchPoints);
+ }
+
+ static int mapAndroidKey(int key)
+ {
+ // 0--9 0x00000007 -- 0x00000010
+ if (key >= 0x00000007 && key <= 0x00000010)
+ return Qt::Key_0 + key - 0x00000007;
+
+ // A--Z 0x0000001d -- 0x00000036
+ if (key >= 0x0000001d && key <= 0x00000036)
+ return Qt::Key_A + key - 0x0000001d;
+
+ switch (key) {
+ case 0x00000039:
+ case 0x0000003a:
+ return Qt::Key_Alt;
+
+ case 0x0000004b:
+ return Qt::Key_Apostrophe;
+
+ case 0x00000004: // KEYCODE_BACK
+ return Qt::Key_Back;
+
+ case 0x00000049:
+ return Qt::Key_Backslash;
+
+ case 0x00000005:
+ return Qt::Key_Call;
+
+ case 0x0000001b:
+ return Qt::Key_WebCam;
+
+ case 0x0000001c:
+ return Qt::Key_Clear;
+
+ case 0x00000037:
+ return Qt::Key_Comma;
+
+ case 0x00000043:
+ return Qt::Key_Backspace;
+
+ case 0x00000017: // KEYCODE_DPAD_CENTER
+ return Qt::Key_Enter;
+
+ case 0x00000014: // KEYCODE_DPAD_DOWN
+ return Qt::Key_Down;
+
+ case 0x00000015: //KEYCODE_DPAD_LEFT
+ return Qt::Key_Left;
+
+ case 0x00000016: //KEYCODE_DPAD_RIGHT
+ return Qt::Key_Right;
+
+ case 0x00000013: //KEYCODE_DPAD_UP
+ return Qt::Key_Up;
+
+ case 0x00000006: //KEYCODE_ENDCALL
+ return Qt::Key_Hangup;
+
+ case 0x00000042:
+ return Qt::Key_Return;
+
+ case 0x00000041: //KEYCODE_ENVELOPE
+ return Qt::Key_LaunchMail;
+
+ case 0x00000046:
+ return Qt::Key_Equal;
+
+ case 0x00000040:
+ return Qt::Key_Explorer;
+
+ case 0x00000003:
+ return Qt::Key_Home;
+
+ case 0x00000047:
+ return Qt::Key_BracketLeft;
+
+ case 0x0000005a: // KEYCODE_MEDIA_FAST_FORWARD
+ return Qt::Key_Forward;
+
+ case 0x00000057:
+ return Qt::Key_MediaNext;
+
+ case 0x00000055:
+ return Qt::Key_MediaPlay;
+
+ case 0x00000058:
+ return Qt::Key_MediaPrevious;
+
+ case 0x00000059:
+ return Qt::Key_AudioRewind;
+
+ case 0x00000056:
+ return Qt::Key_MediaStop;
+
+ case 0x00000052: //KEYCODE_MENU
+ return Qt::Key_Menu;
+
+ case 0x00000045:
+ return Qt::Key_Minus;
+
+ case 0x0000005b:
+ return Qt::Key_VolumeMute;
+
+ case 0x0000004e:
+ return Qt::Key_NumLock;
+
+ case 0x00000038:
+ return Qt::Key_Period;
+
+ case 0x00000051:
+ return Qt::Key_Plus;
+
+ case 0x0000001a:
+ return Qt::Key_PowerOff;
+
+ case 0x00000048:
+ return Qt::Key_BracketRight;
+
+ case 0x00000054:
+ return Qt::Key_Search;
+
+ case 0x0000004a:
+ return Qt::Key_Semicolon;
+
+ case 0x0000003b:
+ case 0x0000003c:
+ return Qt::Key_Shift;
+
+ case 0x0000004c:
+ return Qt::Key_Slash;
+
+ case 0x00000001:
+ return Qt::Key_Left;
+
+ case 0x00000002:
+ return Qt::Key_Right;
+
+ case 0x0000003e:
+ return Qt::Key_Space;
+
+ case 0x0000003f: // KEYCODE_SYM
+ return Qt::Key_Meta;
+
+ case 0x0000003d:
+ return Qt::Key_Tab;
+
+ case 0x00000019:
+ return Qt::Key_VolumeDown;
+
+ case 0x00000018:
+ return Qt::Key_VolumeUp;
+
+ case 0x00000000: // KEYCODE_UNKNOWN
+ case 0x00000011: // KEYCODE_STAR ?!?!?
+ case 0x00000012: // KEYCODE_POUND ?!?!?
+ case 0x00000053: // KEYCODE_NOTIFICATION ?!?!?
+ case 0x0000004f: // KEYCODE_HEADSETHOOK ?!?!?
+ case 0x00000044: // KEYCODE_GRAVE ?!?!?
+ case 0x00000050: // KEYCODE_FOCUS ?!?!?
+ return Qt::Key_Any;
+
+ default:
+ return 0;
+ }
+ }
+
+ static void keyDown(JNIEnv */*env*/, jobject /*thiz*/, jint key, jint unicode, jint modifier)
+ {
+ Qt::KeyboardModifiers modifiers;
+ if (modifier & 1)
+ modifiers |= Qt::ShiftModifier;
+
+ if (modifier & 2)
+ modifiers |= Qt::AltModifier;
+
+ if (modifier & 4)
+ modifiers |= Qt::MetaModifier;
+
+ QWindowSystemInterface::handleKeyEvent(0,
+ QEvent::KeyPress,
+ mapAndroidKey(key),
+ modifiers,
+ QChar(unicode),
+ true);
+ }
+
+ static void keyUp(JNIEnv */*env*/, jobject /*thiz*/, jint key, jint unicode, jint modifier)
+ {
+ Qt::KeyboardModifiers modifiers;
+ if (modifier & 1)
+ modifiers |= Qt::ShiftModifier;
+
+ if (modifier & 2)
+ modifiers |= Qt::AltModifier;
+
+ if (modifier & 4)
+ modifiers |= Qt::MetaModifier;
+
+ QWindowSystemInterface::handleKeyEvent(0,
+ QEvent::KeyRelease,
+ mapAndroidKey(key),
+ modifiers,
+ QChar(unicode),
+ true);
+ }
+
+
+ static JNINativeMethod methods[] = {
+ {"touchBegin","(I)V",(void*)touchBegin},
+ {"touchAdd","(IIIZIIFF)V",(void*)touchAdd},
+ {"touchEnd","(II)V",(void*)touchEnd},
+ {"mouseDown", "(III)V", (void *)mouseDown},
+ {"mouseUp", "(III)V", (void *)mouseUp},
+ {"mouseMove", "(III)V", (void *)mouseMove},
+ {"longPress", "(III)V", (void *)longPress},
+ {"keyDown", "(III)V", (void *)keyDown},
+ {"keyUp", "(III)V", (void *)keyUp}
+ };
+
+#define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
+ VAR = env->GetStaticMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
+ if (!VAR) { \
+ __android_log_print(ANDROID_LOG_FATAL, qtTagText(), methodErrorMsgFmt(), METHOD_NAME, METHOD_SIGNATURE); \
+ return false; \
+ }
+
+ bool registerNatives(JNIEnv *env)
+ {
+ jclass appClass = QtAndroid::applicationClass();
+
+ if (env->RegisterNatives(appClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
+ __android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed");
+ return false;
+ }
+
+ GET_AND_CHECK_STATIC_METHOD(m_showSoftwareKeyboardMethodID, appClass, "showSoftwareKeyboard", "(IIIII)V");
+ GET_AND_CHECK_STATIC_METHOD(m_resetSoftwareKeyboardMethodID, appClass, "resetSoftwareKeyboard", "()V");
+ GET_AND_CHECK_STATIC_METHOD(m_hideSoftwareKeyboardMethodID, appClass, "hideSoftwareKeyboard", "()V");
+ GET_AND_CHECK_STATIC_METHOD(m_isSoftwareKeyboardVisibleMethodID, appClass, "isSoftwareKeyboardVisible", "()Z");
+ GET_AND_CHECK_STATIC_METHOD(m_updateSelectionMethodID, appClass, "updateSelection", "(IIII)V");
+ return true;
+ }
+}
diff --git a/src/plugins/platforms/android/src/androidjniinput.h b/src/plugins/platforms/android/src/androidjniinput.h
new file mode 100644
index 0000000000..a78c7519db
--- /dev/null
+++ b/src/plugins/platforms/android/src/androidjniinput.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ANDROIDJNIINPUT_H
+#define ANDROIDJNIINPUT_H
+#include <jni.h>
+
+namespace QtAndroidInput
+{
+ // Software keyboard support
+ void showSoftwareKeyboard(int top, int left, int width, int height, int inputHints);
+ void resetSoftwareKeyboard();
+ void hideSoftwareKeyboard();
+ bool isSoftwareKeyboardVisible();
+ void updateSelection(int selStart, int selEnd, int candidatesStart, int candidatesEnd);
+ // Software keyboard support
+
+ bool registerNatives(JNIEnv *env);
+}
+
+#endif // ANDROIDJNIINPUT_H
diff --git a/src/plugins/platforms/android/src/androidjnimain.cpp b/src/plugins/platforms/android/src/androidjnimain.cpp
new file mode 100644
index 0000000000..ae94e75e34
--- /dev/null
+++ b/src/plugins/platforms/android/src/androidjnimain.cpp
@@ -0,0 +1,824 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <dlfcn.h>
+#include <pthread.h>
+#include <qcoreapplication.h>
+#include <qimage.h>
+#include <qpoint.h>
+#include <qplugin.h>
+#include <qsemaphore.h>
+#include <qmutex.h>
+#include <qdebug.h>
+#include <qglobal.h>
+#include <qobjectdefs.h>
+#include <stdlib.h>
+
+#include "androidjnimain.h"
+#include "androidjniinput.h"
+#include "androidjniclipboard.h"
+#include "androidjnimenu.h"
+#include "qandroidplatformintegration.h"
+#include <QtWidgets/QApplication>
+
+#include <qabstracteventdispatcher.h>
+
+#include <android/bitmap.h>
+#include <android/asset_manager_jni.h>
+#include "qandroidassetsfileenginehandler.h"
+#include <android/api-level.h>
+
+#include <qpa/qwindowsysteminterface.h>
+
+#ifdef ANDROID_PLUGIN_OPENGL
+# include "qandroidopenglplatformwindow.h"
+#endif
+
+#if __ANDROID_API__ > 8
+# include <android/native_window_jni.h>
+#endif
+
+static jmethodID m_redrawSurfaceMethodID = 0;
+
+Q_IMPORT_PLUGIN(QAndroidPlatformIntegrationPlugin)
+
+static JavaVM *m_javaVM = NULL;
+static jclass m_applicationClass = NULL;
+static jobject m_classLoaderObject = NULL;
+static jmethodID m_loadClassMethodID = NULL;
+static AAssetManager *m_assetManager = NULL;
+static jobject m_resourcesObj;
+static jobject m_activityObject = NULL;
+
+static jclass m_bitmapClass = 0;
+static jmethodID m_createBitmapMethodID = 0;
+static jobject m_ARGB_8888_BitmapConfigValue = 0;
+static jobject m_RGB_565_BitmapConfigValue = 0;
+
+static jclass m_bitmapDrawableClass = 0;
+static jmethodID m_bitmapDrawableConstructorMethodID = 0;
+
+extern "C" typedef int (*Main)(int, char **); //use the standard main method to start the application
+static Main m_main = NULL;
+static void *m_mainLibraryHnd = NULL;
+static QList<QByteArray> m_applicationParams;
+
+#ifndef ANDROID_PLUGIN_OPENGL
+static jobject m_surface = NULL;
+#else
+static EGLNativeWindowType m_nativeWindow = 0;
+static QSemaphore m_waitForWindowSemaphore;
+static bool m_waitForWindow = false;
+
+static jfieldID m_surfaceFieldID = 0;
+#endif
+
+
+static QSemaphore m_quitAppSemaphore;
+static QMutex m_surfaceMutex(QMutex::Recursive);
+static QSemaphore m_pauseApplicationSemaphore;
+static QMutex m_pauseApplicationMutex;
+
+static QAndroidPlatformIntegration *m_androidPlatformIntegration = 0;
+
+static int m_desktopWidthPixels = 0;
+static int m_desktopHeightPixels = 0;
+
+static volatile bool m_pauseApplication;
+
+static AndroidAssetsFileEngineHandler *m_androidAssetsFileEngineHandler = 0;
+
+
+
+static const char m_qtTag[] = "Qt";
+static const char m_classErrorMsg[] = "Can't find class \"%s\"";
+static const char m_methodErrorMsg[] = "Can't find method \"%s%s\"";
+
+static inline void checkPauseApplication()
+{
+ m_pauseApplicationMutex.lock();
+ if (m_pauseApplication) {
+ m_pauseApplicationMutex.unlock();
+ m_pauseApplicationSemaphore.acquire(); // wait until surface is created
+
+ m_pauseApplicationMutex.lock();
+ m_pauseApplication = false;
+ m_pauseApplicationMutex.unlock();
+
+ //FIXME
+// QWindowSystemInterface::handleScreenAvailableGeometryChange(0);
+// QWindowSystemInterface::handleScreenGeometryChange(0);
+ } else {
+ m_pauseApplicationMutex.unlock();
+ }
+}
+
+namespace QtAndroid
+{
+#ifndef ANDROID_PLUGIN_OPENGL
+ void flushImage(const QPoint &pos, const QImage &image, const QRect &destinationRect)
+ {
+ checkPauseApplication();
+ QMutexLocker locker(&m_surfaceMutex);
+ if (!m_surface)
+ return;
+ AttachedJNIEnv env;
+ if (!env.jniEnv)
+ return;
+
+ int bpp = 2;
+ AndroidBitmapInfo info;
+ int ret;
+
+ if ((ret = AndroidBitmap_getInfo(env.jniEnv, m_surface, &info)) < 0) {
+ qWarning() << "AndroidBitmap_getInfo() failed ! error=" << ret;
+ m_javaVM->DetachCurrentThread();
+ return;
+ }
+
+ if (info.format != ANDROID_BITMAP_FORMAT_RGB_565) {
+ qWarning() << "Bitmap format is not RGB_565!";
+ m_javaVM->DetachCurrentThread();
+ return;
+ }
+
+ void *pixels;
+ unsigned char *screenBits;
+ if ((ret = AndroidBitmap_lockPixels(env.jniEnv, m_surface, &pixels)) < 0) {
+ qWarning() << "AndroidBitmap_lockPixels() failed! error=" << ret;
+ m_javaVM->DetachCurrentThread();
+ return;
+ }
+
+ screenBits = static_cast<unsigned char *>(pixels);
+ int sbpl = info.stride;
+ int swidth = info.width;
+ int sheight = info.height;
+
+ unsigned sposx = pos.x() + destinationRect.x();
+ unsigned sposy = pos.y() + destinationRect.y();
+
+ screenBits += sposy * sbpl;
+
+ unsigned ibpl = image.bytesPerLine();
+ unsigned iposx = destinationRect.x();
+ unsigned iposy = destinationRect.y();
+
+ const unsigned char *imageBits = static_cast<const unsigned char *>(image.bits());
+ imageBits += iposy * ibpl;
+
+ unsigned width = swidth - sposx < unsigned(destinationRect.width())
+ ? (swidth-sposx)
+ : destinationRect.width();
+ unsigned height = sheight - sposy < unsigned(destinationRect.height())
+ ? (sheight - sposy)
+ : destinationRect.height();
+
+ for (unsigned y = 0; y < height; y++) {
+ memcpy(screenBits + y*sbpl + sposx*bpp,
+ imageBits + y*ibpl + iposx*bpp,
+ width*bpp);
+ }
+ AndroidBitmap_unlockPixels(env.jniEnv, m_surface);
+
+ env.jniEnv->CallStaticVoidMethod(m_applicationClass,
+ m_redrawSurfaceMethodID,
+ jint(destinationRect.left()),
+ jint(destinationRect.top()),
+ jint(destinationRect.right() + 1),
+ jint(destinationRect.bottom() + 1));
+#warning FIXME dirty hack, figure out why it needs to add 1 to right and bottom !!!!
+ }
+
+#else // for #ifndef ANDROID_PLUGIN_OPENGL
+ EGLNativeWindowType nativeWindow(bool waitForWindow)
+ {
+ m_surfaceMutex.lock();
+ if (!m_nativeWindow && waitForWindow) {
+ m_waitForWindow = true;
+ m_surfaceMutex.unlock();
+ m_waitForWindowSemaphore.acquire();
+ m_waitForWindow = false;
+ return m_nativeWindow;
+ }
+ m_surfaceMutex.unlock();
+ return m_nativeWindow;
+ }
+
+ QSize nativeWindowSize()
+ {
+ if (m_nativeWindow == 0)
+ return QAndroidPlatformIntegration::defaultDesktopSize();
+
+ int width = ANativeWindow_getWidth(m_nativeWindow);
+ int height = ANativeWindow_getHeight(m_nativeWindow);
+
+ return QSize(width, height);
+ }
+#endif
+
+ void setAndroidPlatformIntegration(QAndroidPlatformIntegration *androidPlatformIntegration)
+ {
+ m_surfaceMutex.lock();
+ m_androidPlatformIntegration = androidPlatformIntegration;
+ m_surfaceMutex.unlock();
+ }
+
+ QAndroidPlatformIntegration *androidPlatformIntegration()
+ {
+ QMutexLocker locker(&m_surfaceMutex);
+ return m_androidPlatformIntegration;
+ }
+
+ QWindow *topLevelWindowAt(const QPoint &globalPos)
+ {
+ return m_androidPlatformIntegration
+ ? m_androidPlatformIntegration->screen()->topLevelAt(globalPos)
+ : 0;
+ }
+
+ int desktopWidthPixels()
+ {
+ return m_desktopWidthPixels;
+ }
+
+ int desktopHeightPixels()
+ {
+ return m_desktopHeightPixels;
+ }
+
+ JavaVM *javaVM()
+ {
+ return m_javaVM;
+ }
+
+ jclass findClass(const QString &className, JNIEnv *env)
+ {
+ return static_cast<jclass>(env->CallObjectMethod(m_classLoaderObject,
+ m_loadClassMethodID,
+ env->NewString(reinterpret_cast<const jchar *>(className.constData()),
+ jsize(className.length()))));
+ }
+
+ AAssetManager *assetManager()
+ {
+ return m_assetManager;
+ }
+
+ jclass applicationClass()
+ {
+ return m_applicationClass;
+ }
+
+ jobject activity()
+ {
+ return m_activityObject;
+ }
+
+ jobject createBitmap(QImage img, JNIEnv *env)
+ {
+ if (img.format() != QImage::Format_ARGB32 && img.format() != QImage::Format_RGB16)
+ img = img.convertToFormat(QImage::Format_ARGB32);
+
+ jobject bitmap = env->CallStaticObjectMethod(m_bitmapClass,
+ m_createBitmapMethodID,
+ img.width(),
+ img.height(),
+ img.format() == QImage::Format_ARGB32
+ ? m_ARGB_8888_BitmapConfigValue
+ : m_RGB_565_BitmapConfigValue);
+ if (!bitmap)
+ return 0;
+
+ AndroidBitmapInfo info;
+ if (AndroidBitmap_getInfo(env, bitmap, &info) < 0) {
+ env->DeleteLocalRef(bitmap);
+ return 0;
+ }
+
+ void *pixels;
+ if (AndroidBitmap_lockPixels(env, bitmap, &pixels) < 0) {
+ env->DeleteLocalRef(bitmap);
+ return 0;
+ }
+
+ if (info.stride == uint(img.bytesPerLine())
+ && info.width == uint(img.width())
+ && info.height == uint(img.height())) {
+ memcpy(pixels, img.constBits(), info.stride * info.height);
+ } else {
+ uchar *bmpPtr = static_cast<uchar *>(pixels);
+ const unsigned width = qMin(info.width, (uint)img.width()); //should be the same
+ const unsigned height = qMin(info.height, (uint)img.height()); //should be the same
+ for (unsigned y = 0; y < height; y++, bmpPtr += info.stride)
+ memcpy(bmpPtr, img.constScanLine(y), width);
+ }
+ AndroidBitmap_unlockPixels(env, bitmap);
+ return bitmap;
+ }
+
+ jobject createBitmapDrawable(jobject bitmap, JNIEnv *env)
+ {
+ if (!bitmap)
+ return 0;
+
+ return env->NewObject(m_bitmapDrawableClass,
+ m_bitmapDrawableConstructorMethodID,
+ m_resourcesObj,
+ bitmap);
+ }
+
+ const char *classErrorMsgFmt()
+ {
+ return m_classErrorMsg;
+ }
+
+ const char *methodErrorMsgFmt()
+ {
+ return m_methodErrorMsg;
+ }
+
+ const char *qtTagText()
+ {
+ return m_qtTag;
+ }
+}
+
+static jboolean startQtAndroidPlugin(JNIEnv* /*env*/, jobject /*object*//*, jobject applicationAssetManager*/)
+{
+#ifndef ANDROID_PLUGIN_OPENGL
+ m_surface = 0;
+#else
+ m_nativeWindow = 0;
+ m_waitForWindow = false;
+#endif
+
+ m_androidPlatformIntegration = 0;
+ m_androidAssetsFileEngineHandler = new AndroidAssetsFileEngineHandler();
+
+#ifdef ANDROID_PLUGIN_OPENGL
+ return true;
+#else
+ return false;
+#endif
+}
+
+static void *startMainMethod(void */*data*/)
+{
+ char const **params;
+ params = static_cast<char const **>(malloc(m_applicationParams.length() * sizeof(char *)));
+ for (int i = 0; i < m_applicationParams.size(); i++)
+ params[i] = static_cast<const char *>(m_applicationParams[i].constData());
+
+ int ret = m_main(m_applicationParams.length(), const_cast<char **>(params));
+
+ free(params);
+ Q_UNUSED(ret);
+
+ if (m_mainLibraryHnd) {
+ int res = dlclose(m_mainLibraryHnd);
+ if (res < 0)
+ qWarning() << "dlclose failed:" << dlerror();
+ }
+
+ QtAndroid::AttachedJNIEnv env;
+ if (!env.jniEnv)
+ return 0;
+
+ if (m_applicationClass) {
+ jmethodID quitApp = env.jniEnv->GetStaticMethodID(m_applicationClass, "quitApp", "()V");
+ env.jniEnv->CallStaticVoidMethod(m_applicationClass, quitApp);
+ }
+
+ return 0;
+}
+
+static jboolean startQtApplication(JNIEnv *env, jobject /*object*/, jstring paramsString, jstring environmentString)
+{
+ m_mainLibraryHnd = NULL;
+ const char *nativeString = env->GetStringUTFChars(environmentString, 0);
+ QByteArray string = nativeString;
+ env->ReleaseStringUTFChars(environmentString, nativeString);
+ m_applicationParams=string.split('\t');
+ foreach (string, m_applicationParams) {
+ if (putenv(string.constData()))
+ qWarning() << "Can't set environment" << string;
+ }
+
+ nativeString = env->GetStringUTFChars(paramsString, 0);
+ string = nativeString;
+ env->ReleaseStringUTFChars(paramsString, nativeString);
+
+ m_applicationParams=string.split('\t');
+
+ // Go home
+ QDir::setCurrent(QDir::homePath());
+
+ //look for main()
+ if (m_applicationParams.length()) {
+ // Obtain a handle to the main library (the library that contains the main() function).
+ // This library should already be loaded, and calling dlopen() will just return a reference to it.
+ m_mainLibraryHnd = dlopen(m_applicationParams.first().data(), 0);
+ if (m_mainLibraryHnd == NULL) {
+ qCritical() << "dlopen failed:" << dlerror();
+ return false;
+ }
+ m_main = (Main)dlsym(m_mainLibraryHnd, "main");
+ } else {
+ qWarning() << "No main library was specified; searching entire process (this is slow!)";
+ m_main = (Main)dlsym(RTLD_DEFAULT, "main");
+ }
+
+ if (!m_main) {
+ qCritical() << "dlsym failed:" << dlerror();
+ qCritical() << "Could not find main method";
+ return false;
+ }
+
+ pthread_t appThread;
+ return pthread_create(&appThread, NULL, startMainMethod, NULL) == 0;
+}
+
+static void pauseQtApp(JNIEnv */*env*/, jobject /*thiz*/)
+{
+ m_surfaceMutex.lock();
+ m_pauseApplicationMutex.lock();
+
+ if (m_androidPlatformIntegration)
+ m_androidPlatformIntegration->pauseApp();
+ m_pauseApplication = true;
+
+ m_pauseApplicationMutex.unlock();
+ m_surfaceMutex.unlock();
+}
+
+static void resumeQtApp(JNIEnv */*env*/, jobject /*thiz*/)
+{
+ m_surfaceMutex.lock();
+ m_pauseApplicationMutex.lock();
+ if (m_androidPlatformIntegration)
+ m_androidPlatformIntegration->resumeApp();
+
+ if (m_pauseApplication)
+ m_pauseApplicationSemaphore.release();
+
+ m_pauseApplicationMutex.unlock();
+ m_surfaceMutex.unlock();
+}
+
+static void quitQtAndroidPlugin(JNIEnv *env, jclass /*clazz*/)
+{
+#ifndef ANDROID_PLUGIN_OPENGL
+ if (m_surface) {
+ env->DeleteGlobalRef(m_surface);
+ m_surface = 0;
+ }
+#else
+ Q_UNUSED(env);
+#endif
+
+ m_androidPlatformIntegration = 0;
+ delete m_androidAssetsFileEngineHandler;
+}
+
+static void terminateQt(JNIEnv *env, jclass /*clazz*/)
+{
+#ifndef ANDROID_PLUGIN_OPENGL
+ if (m_surface)
+ env->DeleteGlobalRef(m_surface);
+#endif
+ env->DeleteGlobalRef(m_applicationClass);
+ env->DeleteGlobalRef(m_classLoaderObject);
+ env->DeleteGlobalRef(m_resourcesObj);
+ env->DeleteGlobalRef(m_activityObject);
+ env->DeleteGlobalRef(m_bitmapClass);
+ env->DeleteGlobalRef(m_ARGB_8888_BitmapConfigValue);
+ env->DeleteGlobalRef(m_RGB_565_BitmapConfigValue);
+ env->DeleteGlobalRef(m_bitmapDrawableClass);
+}
+
+#ifdef ANDROID_PLUGIN_OPENGL
+#if __ANDROID_API__ < 9
+struct FakeNativeWindow
+{
+ long long dummyNativeWindow;// force 64 bits alignment
+};
+
+class FakeSurface: public FakeNativeWindow
+{
+public:
+ virtual void FakeSurfaceMethod()
+ {
+ fakeSurface = 0;
+ }
+
+ int fakeSurface;
+};
+
+EGLNativeWindowType ANativeWindow_fromSurface(JNIEnv *env, jobject jSurface)
+{
+ FakeSurface *surface = static_cast<FakeSurface *>(env->GetIntField(jSurface, m_surfaceFieldID));
+ return static_cast<EGLNativeWindowType>(static_cast<FakeNativeWindow*>(surface));
+}
+#endif // __ANDROID_API__ < 9
+#endif // ANDROID_PLUGIN_OPENGL
+
+static void setSurface(JNIEnv *env, jobject /*thiz*/, jobject jSurface)
+{
+#ifndef ANDROID_PLUGIN_OPENGL
+ if (m_surface)
+ env->DeleteGlobalRef(m_surface);
+ m_surface = env->NewGlobalRef(jSurface);
+#else
+ m_surfaceMutex.lock();
+ EGLNativeWindowType nativeWindow = ANativeWindow_fromSurface(env, jSurface);
+ bool sameNativeWindow = (nativeWindow != 0 && nativeWindow == m_nativeWindow);
+
+ m_nativeWindow = nativeWindow;
+ if (m_waitForWindow)
+ m_waitForWindowSemaphore.release();
+ if (m_androidPlatformIntegration && !sameNativeWindow) {
+ m_surfaceMutex.unlock();
+ m_androidPlatformIntegration->surfaceChanged();
+ } else if (m_androidPlatformIntegration && sameNativeWindow) {
+ QAndroidOpenGLPlatformWindow *window = m_androidPlatformIntegration->primaryWindow();
+ QPlatformScreen *screen = m_androidPlatformIntegration->screen();
+ QSize size = QtAndroid::nativeWindowSize();
+
+ QRect geometry(QPoint(0, 0), size);
+ QWindowSystemInterface::handleScreenAvailableGeometryChange(screen->screen(), geometry);
+ QWindowSystemInterface::handleScreenGeometryChange(screen->screen(), geometry);
+
+ if (window != 0) {
+ window->lock();
+ window->scheduleResize(size);
+
+ QWindowSystemInterface::handleExposeEvent(window->window(),
+ QRegion(window->window()->geometry()));
+ window->unlock();
+ }
+
+ m_surfaceMutex.unlock();
+ } else {
+ m_surfaceMutex.unlock();
+ }
+#endif // for #ifndef ANDROID_PLUGIN_OPENGL
+}
+
+static void destroySurface(JNIEnv *env, jobject /*thiz*/)
+{
+#ifndef ANDROID_PLUGIN_OPENGL
+ if (m_surface) {
+ env->DeleteGlobalRef(m_surface);
+ m_surface = 0;
+ }
+#else
+ Q_UNUSED(env);
+ m_nativeWindow = 0;
+ if (m_androidPlatformIntegration != 0)
+ m_androidPlatformIntegration->invalidateNativeSurface();
+#endif
+}
+
+static void setDisplayMetrics(JNIEnv */*env*/, jclass /*clazz*/,
+ jint /*widthPixels*/, jint /*heightPixels*/,
+ jint desktopWidthPixels, jint desktopHeightPixels,
+ jdouble xdpi, jdouble ydpi)
+{
+ m_desktopWidthPixels = desktopWidthPixels;
+ m_desktopHeightPixels = desktopHeightPixels;
+
+ if (!m_androidPlatformIntegration) {
+ QAndroidPlatformIntegration::setDefaultDisplayMetrics(desktopWidthPixels,desktopHeightPixels,
+ qRound(double(desktopWidthPixels) / xdpi * 25.4),
+ qRound(double(desktopHeightPixels) / ydpi * 25.4));
+ } else {
+ m_androidPlatformIntegration->setDisplayMetrics(qRound(double(desktopWidthPixels) / xdpi * 25.4),
+ qRound(double(desktopHeightPixels) / ydpi * 25.4));
+ m_androidPlatformIntegration->setDesktopSize(desktopWidthPixels, desktopHeightPixels);
+ }
+}
+
+static void lockSurface(JNIEnv */*env*/, jobject /*thiz*/)
+{
+ m_surfaceMutex.lock();
+}
+
+static void unlockSurface(JNIEnv */*env*/, jobject /*thiz*/)
+{
+ m_surfaceMutex.unlock();
+}
+
+static void updateWindow(JNIEnv */*env*/, jobject /*thiz*/)
+{
+ if (!m_androidPlatformIntegration)
+ return;
+
+ if (QGuiApplication::instance() != 0) {
+ foreach (QWindow *w, QGuiApplication::topLevelWindows())
+ QWindowSystemInterface::handleExposeEvent(w, QRegion(w->geometry()));
+ }
+
+#ifndef ANDROID_PLUGIN_OPENGL
+ QAndroidPlatformScreen *screen = static_cast<QAndroidPlatformScreen *>(m_androidPlatformIntegration->screen());
+ QMetaObject::invokeMethod(screen, "setDirty", Qt::QueuedConnection, Q_ARG(QRect,screen->geometry()));
+#else
+ qWarning("updateWindow: Dirty screen not implemented yet on OpenGL");
+#endif
+}
+
+static void handleOrientationChanged(JNIEnv */*env*/, jobject /*thiz*/, jint newOrientation)
+{
+ if (m_androidPlatformIntegration == 0)
+ return;
+
+ Qt::ScreenOrientation screenOrientation = newOrientation == 1
+ ? Qt::PortraitOrientation
+ : Qt::LandscapeOrientation;
+ QPlatformScreen *screen = m_androidPlatformIntegration->screen();
+ QWindowSystemInterface::handleScreenOrientationChange(screen->screen(),
+ screenOrientation);
+}
+
+static JNINativeMethod methods[] = {
+ {"startQtAndroidPlugin", "()Z", (void *)startQtAndroidPlugin},
+ {"startQtApplication", "(Ljava/lang/String;Ljava/lang/String;)V", (void *)startQtApplication},
+ {"pauseQtApp", "()V", (void *)pauseQtApp},
+ {"resumeQtApp", "()V", (void *)resumeQtApp},
+ {"quitQtAndroidPlugin", "()V", (void *)quitQtAndroidPlugin},
+ {"terminateQt", "()V", (void *)terminateQt},
+ {"setDisplayMetrics", "(IIIIDD)V", (void *)setDisplayMetrics},
+ {"setSurface", "(Ljava/lang/Object;)V", (void *)setSurface},
+ {"destroySurface", "()V", (void *)destroySurface},
+ {"lockSurface", "()V", (void *)lockSurface},
+ {"unlockSurface", "()V", (void *)unlockSurface},
+ {"updateWindow", "()V", (void *)updateWindow},
+ {"handleOrientationChanged", "(I)V", (void *)handleOrientationChanged}
+};
+
+#define FIND_AND_CHECK_CLASS(CLASS_NAME) \
+clazz = env->FindClass(CLASS_NAME); \
+if (!clazz) { \
+ __android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_classErrorMsg, CLASS_NAME); \
+ return JNI_FALSE; \
+}
+
+#define GET_AND_CHECK_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
+VAR = env->GetMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
+if (!VAR) { \
+ __android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, METHOD_NAME, METHOD_SIGNATURE); \
+ return JNI_FALSE; \
+}
+
+#define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
+VAR = env->GetStaticMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
+if (!VAR) { \
+ __android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, METHOD_NAME, METHOD_SIGNATURE); \
+ return JNI_FALSE; \
+}
+
+#define GET_AND_CHECK_FIELD(VAR, CLASS, FIELD_NAME, FIELD_SIGNATURE) \
+VAR = env->GetFieldID(CLASS, FIELD_NAME, FIELD_SIGNATURE); \
+if (!VAR) { \
+ __android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, FIELD_NAME, FIELD_SIGNATURE); \
+ return JNI_FALSE; \
+}
+
+#define GET_AND_CHECK_STATIC_FIELD(VAR, CLASS, FIELD_NAME, FIELD_SIGNATURE) \
+VAR = env->GetStaticFieldID(CLASS, FIELD_NAME, FIELD_SIGNATURE); \
+if (!VAR) { \
+ __android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, FIELD_NAME, FIELD_SIGNATURE); \
+ return JNI_FALSE; \
+}
+
+static int registerNatives(JNIEnv *env)
+{
+ jclass clazz;
+ FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/QtNative");
+ m_applicationClass = static_cast<jclass>(env->NewGlobalRef(clazz));
+
+ if (env->RegisterNatives(m_applicationClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
+ __android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed");
+ return JNI_FALSE;
+ }
+
+ GET_AND_CHECK_STATIC_METHOD(m_redrawSurfaceMethodID, m_applicationClass, "redrawSurface", "(IIII)V");
+
+#ifdef ANDROID_PLUGIN_OPENGL
+ FIND_AND_CHECK_CLASS("android/view/Surface");
+#if __ANDROID_API__ < 9
+# define ANDROID_VIEW_SURFACE_JNI_ID "mSurface"
+#else
+# define ANDROID_VIEW_SURFACE_JNI_ID "mNativeSurface"
+#endif
+ GET_AND_CHECK_FIELD(m_surfaceFieldID, clazz, ANDROID_VIEW_SURFACE_JNI_ID, "I");
+#endif
+
+ jmethodID methodID;
+ GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "activity", "()Landroid/app/Activity;");
+ jobject activityObject = env->CallStaticObjectMethod(m_applicationClass, methodID);
+ m_activityObject = env->NewGlobalRef(activityObject);
+ GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "classLoader", "()Ljava/lang/ClassLoader;");
+ m_classLoaderObject = env->NewGlobalRef(env->CallStaticObjectMethod(m_applicationClass, methodID));
+
+ clazz = env->GetObjectClass(m_classLoaderObject);
+ GET_AND_CHECK_METHOD(m_loadClassMethodID, clazz, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
+
+ FIND_AND_CHECK_CLASS("android/content/ContextWrapper");
+ GET_AND_CHECK_METHOD(methodID, clazz, "getAssets", "()Landroid/content/res/AssetManager;");
+ m_assetManager = AAssetManager_fromJava(env, env->CallObjectMethod(activityObject, methodID));
+
+ GET_AND_CHECK_METHOD(methodID, clazz, "getResources", "()Landroid/content/res/Resources;");
+ m_resourcesObj = env->NewGlobalRef(env->CallObjectMethod(activityObject, methodID));
+
+ FIND_AND_CHECK_CLASS("android/graphics/Bitmap");
+ m_bitmapClass = static_cast<jclass>(env->NewGlobalRef(clazz));
+ GET_AND_CHECK_STATIC_METHOD(m_createBitmapMethodID, m_bitmapClass
+ , "createBitmap", "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
+
+ FIND_AND_CHECK_CLASS("android/graphics/Bitmap$Config");
+ jfieldID fieldId;
+ GET_AND_CHECK_STATIC_FIELD(fieldId, clazz, "ARGB_8888", "Landroid/graphics/Bitmap$Config;");
+ m_ARGB_8888_BitmapConfigValue = env->NewGlobalRef(env->GetStaticObjectField(clazz, fieldId));
+ GET_AND_CHECK_STATIC_FIELD(fieldId, clazz, "RGB_565", "Landroid/graphics/Bitmap$Config;");
+ m_RGB_565_BitmapConfigValue = env->NewGlobalRef(env->GetStaticObjectField(clazz, fieldId));
+
+ FIND_AND_CHECK_CLASS("android/graphics/drawable/BitmapDrawable");
+ m_bitmapDrawableClass = static_cast<jclass>(env->NewGlobalRef(clazz));
+ GET_AND_CHECK_METHOD(m_bitmapDrawableConstructorMethodID,
+ m_bitmapDrawableClass,
+ "<init>",
+ "(Landroid/content/res/Resources;Landroid/graphics/Bitmap;)V");
+
+ return JNI_TRUE;
+}
+
+Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void */*reserved*/)
+{
+ typedef union {
+ JNIEnv *nativeEnvironment;
+ void *venv;
+ } UnionJNIEnvToVoid;
+
+ __android_log_print(ANDROID_LOG_INFO, "Qt", "qt start");
+ UnionJNIEnvToVoid uenv;
+ uenv.venv = NULL;
+ m_javaVM = 0;
+
+ if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK) {
+ __android_log_print(ANDROID_LOG_FATAL, "Qt", "GetEnv failed");
+ return -1;
+ }
+
+ JNIEnv *env = uenv.nativeEnvironment;
+ if (!registerNatives(env)
+ || !QtAndroidInput::registerNatives(env)
+ || !QtAndroidClipboard::registerNatives(env)
+ || !QtAndroidMenu::registerNatives(env)) {
+ __android_log_print(ANDROID_LOG_FATAL, "Qt", "registerNatives failed");
+ return -1;
+ }
+
+ m_javaVM = vm;
+ return JNI_VERSION_1_4;
+}
diff --git a/src/plugins/platforms/android/src/androidjnimain.h b/src/plugins/platforms/android/src/androidjnimain.h
new file mode 100644
index 0000000000..618bd87cdb
--- /dev/null
+++ b/src/plugins/platforms/android/src/androidjnimain.h
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ANDROID_APP_H
+#define ANDROID_APP_H
+
+#include <android/log.h>
+
+#ifdef ANDROID_PLUGIN_OPENGL
+# include <EGL/eglplatform.h>
+#endif
+
+#include <QtCore/qsize.h>
+
+#include <jni.h>
+#include <android/asset_manager.h>
+
+class QImage;
+class QRect;
+class QPoint;
+class QThread;
+class QAndroidPlatformIntegration;
+class QWidget;
+class QString;
+class QWindow;
+
+namespace QtAndroid
+{
+ QAndroidPlatformIntegration *androidPlatformIntegration();
+ void setAndroidPlatformIntegration(QAndroidPlatformIntegration *androidPlatformIntegration);
+ void setQtThread(QThread *thread);
+
+ void setFullScreen(QWidget *widget);
+
+#ifndef ANDROID_PLUGIN_OPENGL
+ void flushImage(const QPoint &pos, const QImage &image, const QRect &rect);
+#else
+ EGLNativeWindowType nativeWindow(bool waitToCreate = true);
+ QSize nativeWindowSize();
+#endif
+
+ QWindow *topLevelWindowAt(const QPoint &globalPos);
+ int desktopWidthPixels();
+ int desktopHeightPixels();
+ JavaVM *javaVM();
+ jclass findClass(const QString &className, JNIEnv *env);
+ AAssetManager *assetManager();
+ jclass applicationClass();
+ jobject activity();
+
+ jobject createBitmap(QImage img, JNIEnv *env = 0);
+ jobject createBitmapDrawable(jobject bitmap, JNIEnv *env = 0);
+
+ struct AttachedJNIEnv
+ {
+ AttachedJNIEnv()
+ {
+ attached = false;
+ if (QtAndroid::javaVM()->GetEnv((void**)&jniEnv, JNI_VERSION_1_6) < 0) {
+ if (QtAndroid::javaVM()->AttachCurrentThread(&jniEnv, NULL) < 0) {
+ __android_log_print(ANDROID_LOG_ERROR, "Qt", "AttachCurrentThread failed");
+ jniEnv = 0;
+ return;
+ }
+ attached = true;
+ }
+ }
+
+ ~AttachedJNIEnv()
+ {
+ if (attached)
+ QtAndroid::javaVM()->DetachCurrentThread();
+ }
+ bool attached;
+ JNIEnv *jniEnv;
+ };
+ const char *classErrorMsgFmt();
+ const char *methodErrorMsgFmt();
+ const char *qtTagText();
+
+}
+#endif // ANDROID_APP_H
diff --git a/src/plugins/platforms/android/src/androidjnimenu.cpp b/src/plugins/platforms/android/src/androidjnimenu.cpp
new file mode 100644
index 0000000000..e49af0fdac
--- /dev/null
+++ b/src/plugins/platforms/android/src/androidjnimenu.cpp
@@ -0,0 +1,405 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "androidjnimenu.h"
+#include "androidjnimain.h"
+#include <qmutex.h>
+#include <qset.h>
+#include <qqueue.h>
+#include <android/log.h>
+#include "qandroidplatformmenubar.h"
+#include "qandroidplatformmenu.h"
+#include <qandroidplatformmenuitem.h>
+
+using namespace QtAndroid;
+
+namespace QtAndroidMenu
+{
+ static QQueue<QAndroidPlatformMenu *> pendingContextMenus;
+ static QAndroidPlatformMenu *visibleMenu = 0;
+ static QMutex visibleMenuMutex(QMutex::Recursive);
+
+ static QSet<QAndroidPlatformMenuBar *> menuBars;
+ static QAndroidPlatformMenuBar *visibleMenuBar = 0;
+ static QWindow *activeTopLevelWindow = 0;
+ static QMutex menuBarMutex(QMutex::Recursive);
+
+ static jmethodID openContextMenuMethodID = 0;
+ static jmethodID closeContextMenuMethodID = 0;
+ static jmethodID resetOptionsMenuMethodID = 0;
+
+ static jmethodID clearMenuMethodID = 0;
+ static jmethodID addMenuItemMethodID = 0;
+ static int menuNoneValue = 0;
+ static jmethodID setHeaderTitleContextMenuMethodID = 0;
+
+ static jmethodID setCheckableMenuItemMethodID = 0;
+ static jmethodID setCheckedMenuItemMethodID = 0;
+ static jmethodID setEnabledMenuItemMethodID = 0;
+ static jmethodID setIconMenuItemMethodID = 0;
+ static jmethodID setVisibleMenuItemMethodID = 0;
+
+ void resetMenuBar()
+ {
+ AttachedJNIEnv env;
+ if (env.jniEnv)
+ env.jniEnv->CallStaticVoidMethod(applicationClass(), resetOptionsMenuMethodID);
+ }
+
+ void showContextMenu(QAndroidPlatformMenu *menu, JNIEnv *env)
+ {
+ QMutexLocker lock(&visibleMenuMutex);
+ if (visibleMenu) {
+ pendingContextMenus.enqueue(menu);
+ } else {
+ visibleMenu = menu;
+ menu->aboutToShow();
+ if (env) {
+ env->CallStaticVoidMethod(applicationClass(), openContextMenuMethodID);
+ } else {
+ AttachedJNIEnv aenv;
+ if (aenv.jniEnv)
+ aenv.jniEnv->CallStaticVoidMethod(applicationClass(), openContextMenuMethodID);
+ }
+ }
+ }
+
+ void hideContextMenu(QAndroidPlatformMenu *menu)
+ {
+ QMutexLocker lock(&visibleMenuMutex);
+ if (visibleMenu == menu) {
+ AttachedJNIEnv env;
+ if (env.jniEnv)
+ env.jniEnv->CallStaticVoidMethod(applicationClass(), openContextMenuMethodID);
+ } else {
+ pendingContextMenus.removeOne(menu);
+ }
+ }
+
+ void syncMenu(QAndroidPlatformMenu */*menu*/)
+ {
+// QMutexLocker lock(&visibleMenuMutex);
+// if (visibleMenu == menu)
+// {
+// hideContextMenu(menu);
+// showContextMenu(menu);
+// }
+ }
+
+ void androidPlatformMenuDestroyed(QAndroidPlatformMenu *menu)
+ {
+ QMutexLocker lock(&visibleMenuMutex);
+ if (visibleMenu == menu)
+ visibleMenu = 0;
+ }
+
+ void setMenuBar(QAndroidPlatformMenuBar *menuBar, QWindow *window)
+ {
+ if (activeTopLevelWindow == window && visibleMenuBar != menuBar) {
+ visibleMenuBar = menuBar;
+ resetMenuBar();
+ }
+ }
+
+ void setActiveTopLevelWindow(QWindow *window)
+ {
+ QMutexLocker lock(&menuBarMutex);
+ if (activeTopLevelWindow == window)
+ return;
+
+ visibleMenuBar = 0;
+ activeTopLevelWindow = window;
+#ifdef ANDROID_PLUGIN_OPENGL
+ //only one toplevel window, so the menu bar always belongs to us
+ if (menuBars.size() == 1) {
+ visibleMenuBar = *menuBars.constBegin(); //since QSet doesn't have first()
+ } else
+#endif
+ foreach (QAndroidPlatformMenuBar *menuBar, menuBars) {
+ if (menuBar->parentWindow() == window) {
+ visibleMenuBar = menuBar;
+ break;
+ }
+ }
+
+ resetMenuBar();
+ }
+
+ void addMenuBar(QAndroidPlatformMenuBar *menuBar)
+ {
+ QMutexLocker lock(&menuBarMutex);
+ menuBars.insert(menuBar);
+ }
+
+ void removeMenuBar(QAndroidPlatformMenuBar *menuBar)
+ {
+ QMutexLocker lock(&menuBarMutex);
+ menuBars.remove(menuBar);
+ if (visibleMenuBar == menuBar)
+ resetMenuBar();
+ }
+
+ static void fillMenuItem(JNIEnv *env, jobject menuItem, bool checkable, bool checked, bool enabled, bool visible, const QIcon &icon=QIcon())
+ {
+ env->CallObjectMethod(menuItem, setCheckableMenuItemMethodID, checkable);
+ env->CallObjectMethod(menuItem, setCheckedMenuItemMethodID, checked);
+ env->CallObjectMethod(menuItem, setEnabledMenuItemMethodID, enabled);
+
+ if (!icon.isNull()) {
+ int sz = qMax(36, qgetenv("QT_ANDROID_APP_ICON_SIZE").toInt());
+ QImage img = icon.pixmap(QSize(sz,sz),
+ enabled
+ ? QIcon::Normal
+ : QIcon::Disabled,
+ QIcon::On).toImage();
+ env->CallObjectMethod(menuItem,
+ setIconMenuItemMethodID,
+ createBitmapDrawable(createBitmap(img, env), env));
+ }
+
+ env->CallObjectMethod(menuItem, setVisibleMenuItemMethodID, visible);
+ }
+
+ static int addAllMenuItemsToMenu(JNIEnv *env, jobject menu, QAndroidPlatformMenu *platformMenu) {
+ int order = 0;
+ QMutexLocker lock(platformMenu->menuItemsMutex());
+ foreach (QAndroidPlatformMenuItem *item, platformMenu->menuItems()) {
+ if (item->isSeparator())
+ continue;
+ jstring jtext = env->NewString(reinterpret_cast<const jchar *>(item->text().data()),
+ item->text().length());
+ jobject menuItem = env->CallObjectMethod(menu,
+ addMenuItemMethodID,
+ menuNoneValue,
+ int(item->tag()),
+ order++,
+ jtext);
+ env->DeleteLocalRef(jtext);
+ fillMenuItem(env,
+ menuItem,
+ item->isCheckable(),
+ item->isChecked(),
+ item->isEnabled(),
+ item->isVisible(),
+ item->icon());
+ }
+
+ return order;
+ }
+
+ static jboolean onPrepareOptionsMenu(JNIEnv *env, jobject /*thiz*/, jobject menu)
+ {
+ env->CallVoidMethod(menu, clearMenuMethodID);
+ QMutexLocker lock(&menuBarMutex);
+ if (!visibleMenuBar)
+ return JNI_FALSE;
+
+ const QAndroidPlatformMenuBar::PlatformMenusType &menus = visibleMenuBar->menus();
+ int order = 0;
+ QMutexLocker lockMenuBarMutex(visibleMenuBar->menusListMutex());
+ if (menus.size() == 1) { // Expand the menu
+ order = addAllMenuItemsToMenu(env, menu, static_cast<QAndroidPlatformMenu *>(menus.front()));
+ } else {
+ foreach (QAndroidPlatformMenu *item, menus) {
+ jstring jtext = env->NewString(reinterpret_cast<const jchar *>(item->text().data()),
+ item->text().length());
+ jobject menuItem = env->CallObjectMethod(menu,
+ addMenuItemMethodID,
+ menuNoneValue,
+ int(item->tag()),
+ order++,
+ jtext);
+ env->DeleteLocalRef(jtext);
+
+ fillMenuItem(env,
+ menuItem,
+ false,
+ false,
+ item->isEnabled(),
+ item->isVisible(),
+ item->icon());
+ }
+ }
+ return order ? JNI_TRUE : JNI_FALSE;
+ }
+
+ static jboolean onOptionsItemSelected(JNIEnv *env, jobject /*thiz*/, jint menuId, jboolean checked)
+ {
+ QMutexLocker lock(&menuBarMutex);
+ if (!visibleMenuBar)
+ return JNI_FALSE;
+
+ const QAndroidPlatformMenuBar::PlatformMenusType &menus = visibleMenuBar->menus();
+ if (menus.size() == 1) { // Expanded menu
+ QAndroidPlatformMenuItem *item = static_cast<QAndroidPlatformMenuItem *>(menus.front()->menuItemForTag(menuId));
+ if (item) {
+ if (item->menu()) {
+ showContextMenu(item->menu(), env);
+ } else {
+ if (item->isCheckable())
+ item->setChecked(checked);
+ item->activated();
+ }
+ }
+ } else {
+ QAndroidPlatformMenu *menu = static_cast<QAndroidPlatformMenu *>(visibleMenuBar->menuForTag(menuId));
+ if (menu)
+ showContextMenu(menu, env);
+ }
+
+ return JNI_TRUE;
+ }
+
+ static void onOptionsMenuClosed(JNIEnv */*env*/, jobject /*thiz*/, jobject /*menu*/)
+ {
+ }
+
+ static void onCreateContextMenu(JNIEnv *env, jobject /*thiz*/, jobject menu)
+ {
+ env->CallVoidMethod(menu, clearMenuMethodID);
+ QMutexLocker lock(&visibleMenuMutex);
+ if (!visibleMenu)
+ return;
+
+ jstring jtext = env->NewString(reinterpret_cast<const jchar*>(visibleMenu->text().data()),
+ visibleMenu->text().length());
+ env->CallObjectMethod(menu, setHeaderTitleContextMenuMethodID, jtext);
+ env->DeleteLocalRef(jtext);
+ addAllMenuItemsToMenu(env, menu, visibleMenu);
+ }
+
+ static jboolean onContextItemSelected(JNIEnv *env, jobject /*thiz*/, jint menuId, jboolean checked)
+ {
+ QMutexLocker lock(&visibleMenuMutex);
+ QAndroidPlatformMenuItem * item = static_cast<QAndroidPlatformMenuItem *>(visibleMenu->menuItemForTag(menuId));
+ if (item) {
+ if (item->menu()) {
+ showContextMenu(item->menu(), env);
+ } else {
+ if (item->isCheckable())
+ item->setChecked(checked);
+ item->activated();
+ }
+ }
+ return JNI_TRUE;
+ }
+
+ static void onContextMenuClosed(JNIEnv *env, jobject /*thiz*/, jobject /*menu*/)
+ {
+ QMutexLocker lock(&visibleMenuMutex);
+ if (!visibleMenu)
+ return;
+ visibleMenu->aboutToHide();
+ visibleMenu = 0;
+ if (!pendingContextMenus.empty())
+ showContextMenu(pendingContextMenus.dequeue(), env);
+ }
+
+ static JNINativeMethod methods[] = {
+ {"onPrepareOptionsMenu", "(Landroid/view/Menu;)Z", (void *)onPrepareOptionsMenu},
+ {"onOptionsItemSelected", "(IZ)Z", (void *)onOptionsItemSelected},
+ {"onOptionsMenuClosed", "(Landroid/view/Menu;)V", (void*)onOptionsMenuClosed},
+ {"onCreateContextMenu", "(Landroid/view/ContextMenu;)V", (void *)onCreateContextMenu},
+ {"onContextItemSelected", "(IZ)Z", (void *)onContextItemSelected},
+ {"onContextMenuClosed", "(Landroid/view/Menu;)V", (void*)onContextMenuClosed},
+ };
+
+#define FIND_AND_CHECK_CLASS(CLASS_NAME) \
+ clazz = env->FindClass(CLASS_NAME); \
+ if (!clazz) { \
+ __android_log_print(ANDROID_LOG_FATAL, qtTagText(), classErrorMsgFmt(), CLASS_NAME); \
+ return false; \
+ }
+
+#define GET_AND_CHECK_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
+ VAR = env->GetMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
+ if (!VAR) { \
+ __android_log_print(ANDROID_LOG_FATAL, qtTagText(), methodErrorMsgFmt(), METHOD_NAME, METHOD_SIGNATURE); \
+ return false; \
+ }
+
+#define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
+ VAR = env->GetStaticMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
+ if (!VAR) { \
+ __android_log_print(ANDROID_LOG_FATAL, qtTagText(), methodErrorMsgFmt(), METHOD_NAME, METHOD_SIGNATURE); \
+ return false; \
+ }
+
+#define GET_AND_CHECK_STATIC_FIELD(VAR, CLASS, FIELD_NAME, FIELD_SIGNATURE) \
+ VAR = env->GetStaticFieldID(CLASS, FIELD_NAME, FIELD_SIGNATURE); \
+ if (!VAR) { \
+ __android_log_print(ANDROID_LOG_FATAL, qtTagText(), methodErrorMsgFmt(), FIELD_NAME, FIELD_SIGNATURE); \
+ return false; \
+ }
+
+ bool registerNatives(JNIEnv *env)
+ {
+ jclass appClass = applicationClass();
+
+ if (env->RegisterNatives(appClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
+ __android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed");
+ return false;
+ }
+
+ GET_AND_CHECK_STATIC_METHOD(openContextMenuMethodID, appClass, "openContextMenu", "()V");
+ GET_AND_CHECK_STATIC_METHOD(closeContextMenuMethodID, appClass, "closeContextMenu", "()V");
+ GET_AND_CHECK_STATIC_METHOD(resetOptionsMenuMethodID, appClass, "resetOptionsMenu", "()V");
+
+ jclass clazz;
+ FIND_AND_CHECK_CLASS("android/view/Menu");
+ GET_AND_CHECK_METHOD(clearMenuMethodID, clazz, "clear", "()V");
+ GET_AND_CHECK_METHOD(addMenuItemMethodID, clazz, "add", "(IIILjava/lang/CharSequence;)Landroid/view/MenuItem;");
+ jfieldID menuNoneFiledId;
+ GET_AND_CHECK_STATIC_FIELD(menuNoneFiledId, clazz, "NONE", "I");
+ menuNoneValue = env->GetStaticIntField(clazz, menuNoneFiledId);
+
+ FIND_AND_CHECK_CLASS("android/view/ContextMenu");
+ GET_AND_CHECK_METHOD(setHeaderTitleContextMenuMethodID, clazz, "setHeaderTitle","(Ljava/lang/CharSequence;)Landroid/view/ContextMenu;");
+
+ FIND_AND_CHECK_CLASS("android/view/MenuItem");
+ GET_AND_CHECK_METHOD(setCheckableMenuItemMethodID, clazz, "setCheckable", "(Z)Landroid/view/MenuItem;");
+ GET_AND_CHECK_METHOD(setCheckedMenuItemMethodID, clazz, "setChecked", "(Z)Landroid/view/MenuItem;");
+ GET_AND_CHECK_METHOD(setEnabledMenuItemMethodID, clazz, "setEnabled", "(Z)Landroid/view/MenuItem;");
+ GET_AND_CHECK_METHOD(setIconMenuItemMethodID, clazz, "setIcon", "(Landroid/graphics/drawable/Drawable;)Landroid/view/MenuItem;");
+ GET_AND_CHECK_METHOD(setVisibleMenuItemMethodID, clazz, "setVisible", "(Z)Landroid/view/MenuItem;");
+ return true;
+ }
+}
diff --git a/src/plugins/platforms/android/src/androidjnimenu.h b/src/plugins/platforms/android/src/androidjnimenu.h
new file mode 100644
index 0000000000..7c5422f67b
--- /dev/null
+++ b/src/plugins/platforms/android/src/androidjnimenu.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ANDROIDJNIMENU_H
+#define ANDROIDJNIMENU_H
+
+#include <jni.h>
+
+class QAndroidPlatformMenuBar;
+class QAndroidPlatformMenu;
+class QAndroidPlatformMenuItem;
+class QWindow;
+
+namespace QtAndroidMenu
+{
+ // Menu support
+ void showContextMenu(QAndroidPlatformMenu *menu, JNIEnv *env = 0);
+ void hideContextMenu(QAndroidPlatformMenu *menu);
+ void syncMenu(QAndroidPlatformMenu *menu);
+ void androidPlatformMenuDestroyed(QAndroidPlatformMenu *menu);
+
+ void setMenuBar(QAndroidPlatformMenuBar *menuBar, QWindow *window);
+ void setActiveTopLevelWindow(QWindow *window);
+ void addMenuBar(QAndroidPlatformMenuBar *menuBar);
+ void removeMenuBar(QAndroidPlatformMenuBar *menuBar);
+
+ // Menu support
+ bool registerNatives(JNIEnv *env);
+}
+
+#endif // ANDROIDJNIMENU_H
diff --git a/src/plugins/platforms/android/src/androidplatformplugin.cpp b/src/plugins/platforms/android/src/androidplatformplugin.cpp
new file mode 100644
index 0000000000..71c5096e16
--- /dev/null
+++ b/src/plugins/platforms/android/src/androidplatformplugin.cpp
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qpa/qplatformintegrationplugin.h>
+#include "qandroidplatformintegration.h"
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidPlatformIntegrationPlugin: public QPlatformIntegrationPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "android.json")
+public:
+ QPlatformIntegration *create(const QString &key, const QStringList &paramList);
+};
+
+
+QPlatformIntegration *QAndroidPlatformIntegrationPlugin::create(const QString &key, const QStringList &paramList)
+{
+ Q_UNUSED(paramList);
+ if (key.toLower() == "android")
+ return new QAndroidPlatformIntegration(paramList);
+ return 0;
+}
+
+QT_END_NAMESPACE
+#include "androidplatformplugin.moc"
+
diff --git a/src/plugins/platforms/android/src/opengl/qandroidopenglcontext.cpp b/src/plugins/platforms/android/src/opengl/qandroidopenglcontext.cpp
new file mode 100644
index 0000000000..aa8ee57341
--- /dev/null
+++ b/src/plugins/platforms/android/src/opengl/qandroidopenglcontext.cpp
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidopenglcontext.h"
+#include "qandroidopenglplatformwindow.h"
+#include "qandroidplatformintegration.h"
+
+#include <QtCore/qdebug.h>
+#include <qpa/qwindowsysteminterface.h>
+
+QT_BEGIN_NAMESPACE
+
+QAndroidOpenGLContext::QAndroidOpenGLContext(const QAndroidPlatformIntegration *integration,
+ const QSurfaceFormat &format,
+ QPlatformOpenGLContext *share,
+ EGLDisplay display,
+ EGLenum eglApi)
+ : QEglFSContext(format, share, display, eglApi)
+ , m_platformIntegration(integration)
+{
+}
+
+void QAndroidOpenGLContext::swapBuffers(QPlatformSurface *surface)
+{
+ QEglFSContext::swapBuffers(surface);
+
+ QAndroidOpenGLPlatformWindow *primaryWindow = m_platformIntegration->primaryWindow();
+ if (primaryWindow == surface) {
+ primaryWindow->lock();
+ QSize size = primaryWindow->scheduledResize();
+ if (size.isValid()) {
+ QRect geometry(QPoint(0, 0), size);
+ primaryWindow->setGeometry(geometry);
+ primaryWindow->scheduleResize(QSize());
+ }
+ primaryWindow->unlock();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/src/opengl/qandroidopenglcontext.h b/src/plugins/platforms/android/src/opengl/qandroidopenglcontext.h
new file mode 100644
index 0000000000..c4c5a430ad
--- /dev/null
+++ b/src/plugins/platforms/android/src/opengl/qandroidopenglcontext.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDOPENGLCONTEXT_H
+#define QANDROIDOPENGLCONTEXT_H
+
+#include <QtCore/qreadwritelock.h>
+#include "qeglfscontext.h"
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidPlatformIntegration;
+class QAndroidOpenGLContext : public QEglFSContext
+{
+public:
+ QAndroidOpenGLContext(const QAndroidPlatformIntegration *integration,
+ const QSurfaceFormat &format,
+ QPlatformOpenGLContext *share,
+ EGLDisplay display,
+ EGLenum eglApi = EGL_OPENGL_ES_API);
+
+ void swapBuffers(QPlatformSurface *surface);
+
+private:
+ const QAndroidPlatformIntegration *m_platformIntegration;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDOPENGLCONTEXT_H
diff --git a/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.cpp b/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.cpp
new file mode 100644
index 0000000000..15c6559157
--- /dev/null
+++ b/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.cpp
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidopenglplatformwindow.h"
+#include "androidjnimain.h"
+#include <qpa/qwindowsysteminterface.h>
+
+QT_BEGIN_NAMESPACE
+
+QAndroidOpenGLPlatformWindow::QAndroidOpenGLPlatformWindow(QWindow *window)
+ : QEglFSWindow(window)
+{
+}
+
+bool QAndroidOpenGLPlatformWindow::isExposed() const
+{
+ return QtAndroid::nativeWindow(false) != 0 && QEglFSWindow::isExposed();
+}
+
+void QAndroidOpenGLPlatformWindow::invalidateSurface()
+{
+ QWindowSystemInterface::handleExposeEvent(window(), QRegion()); // Obscure event
+ QWindowSystemInterface::flushWindowSystemEvents();
+ QEglFSWindow::invalidateSurface();
+}
+
+void QAndroidOpenGLPlatformWindow::resetSurface()
+{
+ QEglFSWindow::resetSurface();
+ QWindowSystemInterface::handleExposeEvent(window(), QRegion(geometry())); // Expose event
+ QWindowSystemInterface::flushWindowSystemEvents();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.h b/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.h
new file mode 100644
index 0000000000..b835cb3246
--- /dev/null
+++ b/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDOPENGLPLATFORMWINDOW_H
+#define QANDROIDOPENGLPLATFORMWINDOW_H
+
+#include "qeglfswindow.h"
+#include <QtCore/qmutex.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidOpenGLPlatformWindow : public QEglFSWindow
+{
+public:
+ QAndroidOpenGLPlatformWindow(QWindow *window);
+
+ QSize scheduledResize() const { return m_scheduledResize; }
+ void scheduleResize(const QSize &size) { m_scheduledResize = size; }
+
+ void lock() { m_lock.lock(); }
+ void unlock() { m_lock.unlock(); }
+
+ bool isExposed() const;
+
+ void invalidateSurface();
+ void resetSurface();
+
+private:
+ QSize m_scheduledResize;
+ QMutex m_lock;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDOPENGLPLATFORMWINDOW_H
diff --git a/src/plugins/platforms/android/src/opengl/qeglfshooks_android.cpp b/src/plugins/platforms/android/src/opengl/qeglfshooks_android.cpp
new file mode 100644
index 0000000000..cd415843a7
--- /dev/null
+++ b/src/plugins/platforms/android/src/opengl/qeglfshooks_android.cpp
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qeglfshooks.h"
+#include "androidjnimain.h"
+#include "qandroidplatformintegration.h"
+
+#include <android/native_window.h>
+#include <jni.h>
+
+QT_BEGIN_NAMESPACE
+
+class QEglFSAndroidHooks: public QEglFSHooks
+{
+public:
+ void platformInit();
+ void platformDestroy();
+ EGLNativeDisplayType platformDisplay() const;
+ QSize screenSize() const;
+ QSizeF physicalScreenSize() const;
+ int screenDepth() const;
+ QSurfaceFormat surfaceFormatFor(const QSurfaceFormat &inputFormat) const;
+ EGLNativeWindowType createNativeWindow(const QSize &size, const QSurfaceFormat &format);
+ void destroyNativeWindow(EGLNativeWindowType window);
+ bool hasCapability(QPlatformIntegration::Capability cap) const;
+};
+
+void QEglFSAndroidHooks::platformInit()
+{
+}
+
+void QEglFSAndroidHooks::platformDestroy()
+{
+}
+
+EGLNativeDisplayType QEglFSAndroidHooks::platformDisplay() const
+{
+ return EGL_DEFAULT_DISPLAY;
+}
+
+QSize QEglFSAndroidHooks::screenSize() const
+{
+ return QtAndroid::nativeWindowSize();
+}
+
+QSizeF QEglFSAndroidHooks::physicalScreenSize() const
+{
+ return QSizeF(QAndroidPlatformIntegration::m_defaultPhysicalSizeWidth, QAndroidPlatformIntegration::m_defaultPhysicalSizeHeight);
+}
+
+
+EGLNativeWindowType QEglFSAndroidHooks::createNativeWindow(const QSize &size, const QSurfaceFormat &format)
+{
+ ANativeWindow *window = QtAndroid::nativeWindow();
+ if (window != 0)
+ ANativeWindow_acquire(window);
+
+ return window;
+}
+
+void QEglFSAndroidHooks::destroyNativeWindow(EGLNativeWindowType window)
+{
+ ANativeWindow_release(window);
+}
+
+bool QEglFSAndroidHooks::hasCapability(QPlatformIntegration::Capability capability) const
+{
+ switch (capability) {
+ case QPlatformIntegration::OpenGL: return true;
+ case QPlatformIntegration::ThreadedOpenGL: return true;
+ default: return false;
+ };
+}
+
+int QEglFSAndroidHooks::screenDepth() const
+{
+ // ### Hardcoded
+ return 32;
+}
+
+QSurfaceFormat QEglFSAndroidHooks::surfaceFormatFor(const QSurfaceFormat &inputFormat) const
+{
+ QSurfaceFormat ret(inputFormat);
+ ret.setAlphaBufferSize(8);
+ ret.setRedBufferSize(8);
+ ret.setGreenBufferSize(8);
+ ret.setBlueBufferSize(8);
+ return ret;
+}
+
+static QEglFSAndroidHooks eglFSAndroidHooks;
+QEglFSHooks *platformHooks = &eglFSAndroidHooks;
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/src/qandroidassetsfileenginehandler.cpp b/src/plugins/platforms/android/src/qandroidassetsfileenginehandler.cpp
new file mode 100644
index 0000000000..f3cb2586cc
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidassetsfileenginehandler.cpp
@@ -0,0 +1,288 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidassetsfileenginehandler.h"
+#include "androidjnimain.h"
+
+#include <QCoreApplication>
+
+class AndroidAbstractFileEngineIterator: public QAbstractFileEngineIterator
+{
+public:
+ AndroidAbstractFileEngineIterator(QDir::Filters filters,
+ const QStringList &nameFilters,
+ AAssetDir *asset,
+ const QString &path)
+ : QAbstractFileEngineIterator(filters, nameFilters)
+ {
+ AAssetDir_rewind(asset);
+ const char *fileName;
+ while ((fileName = AAssetDir_getNextFileName(asset)))
+ m_items << fileName;
+ m_index = -1;
+ m_path = path;
+ }
+
+ virtual QFileInfo currentFileInfo() const
+ {
+ return QFileInfo(currentFilePath());
+ }
+
+ virtual QString currentFileName() const
+ {
+ if (m_index < 0 || m_index >= m_items.size())
+ return QString();
+ return m_items[m_index];
+ }
+
+ virtual QString currentFilePath() const
+ {
+ return m_path + currentFileName();
+ }
+
+ virtual bool hasNext() const
+ {
+ return m_items.size() && (m_index < m_items.size() - 1);
+ }
+
+ virtual QString next()
+ {
+ if (!hasNext())
+ return QString();
+ m_index++;
+ return currentFileName();
+ }
+
+private:
+ QString m_path;
+ QStringList m_items;
+ int m_index;
+};
+
+class AndroidAbstractFileEngine: public QAbstractFileEngine
+{
+public:
+ explicit AndroidAbstractFileEngine(AAsset *asset, const QString &fileName)
+ {
+ m_assetDir = 0;
+ m_assetFile = asset;
+ m_fileName = fileName;
+ }
+
+ explicit AndroidAbstractFileEngine(AAssetDir *asset, const QString &fileName)
+ {
+ m_assetFile = 0;
+ m_assetDir = asset;
+ m_fileName = fileName;
+ if (!m_fileName.endsWith(QChar(QLatin1Char('/'))))
+ m_fileName += "/";
+ }
+
+ ~AndroidAbstractFileEngine()
+ {
+ close();
+ if (m_assetDir)
+ AAssetDir_close(m_assetDir);
+ }
+
+ virtual bool open(QIODevice::OpenMode openMode)
+ {
+ if (m_assetFile)
+ return openMode & QIODevice::ReadOnly;
+ return false;
+ }
+
+ virtual bool close()
+ {
+ if (m_assetFile) {
+ AAsset_close(m_assetFile);
+ m_assetFile = 0;
+ return true;
+ }
+ return false;
+ }
+
+ virtual qint64 size() const
+ {
+ if (m_assetFile)
+ return AAsset_getLength(m_assetFile);
+ return -1;
+ }
+
+ virtual qint64 pos() const
+ {
+ if (m_assetFile)
+ return AAsset_seek(m_assetFile, 0, SEEK_CUR);
+ return -1;
+ }
+
+ virtual bool seek(qint64 pos)
+ {
+ if (m_assetFile)
+ return pos == AAsset_seek(m_assetFile, pos, SEEK_SET);
+ return false;
+ }
+
+ virtual qint64 read(char *data, qint64 maxlen)
+ {
+ if (m_assetFile)
+ return AAsset_read(m_assetFile, data, maxlen);
+ return -1;
+ }
+
+ virtual bool isSequential() const
+ {
+ return false;
+ }
+
+ virtual bool caseSensitive() const
+ {
+ return true;
+ }
+
+ virtual bool isRelativePath() const
+ {
+ return false;
+ }
+
+ virtual FileFlags fileFlags(FileFlags type = FileInfoAll) const
+ {
+ FileFlags flags(ReadOwnerPerm|ReadUserPerm|ReadGroupPerm|ReadOtherPerm|ExistsFlag);
+ if (m_assetFile)
+ flags |= FileType;
+ if (m_assetDir)
+ flags |= DirectoryType;
+
+ return type & flags;
+ }
+
+ virtual QString fileName(FileName file = DefaultName) const
+ {
+ int pos;
+ switch (file) {
+ case DefaultName:
+ case AbsoluteName:
+ case CanonicalName:
+ return m_fileName;
+ case BaseName:
+ if ((pos = m_fileName.lastIndexOf(QChar(QLatin1Char('/')))) != -1)
+ return m_fileName.mid(pos);
+ else
+ return m_fileName;
+ case PathName:
+ case AbsolutePathName:
+ case CanonicalPathName:
+ if ((pos = m_fileName.lastIndexOf(QChar(QLatin1Char('/')))) != -1)
+ return m_fileName.left(pos);
+ else
+ return m_fileName;
+ default:
+ return QString();
+ }
+ }
+
+ virtual void setFileName(const QString &file)
+ {
+ if (file == m_fileName)
+ return;
+
+ m_fileName = file;
+ if (!m_fileName.endsWith(QChar(QLatin1Char('/'))))
+ m_fileName += "/";
+
+ close();
+ }
+
+ virtual Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames)
+ {
+ if (m_assetDir)
+ return new AndroidAbstractFileEngineIterator(filters, filterNames, m_assetDir, m_fileName);
+ return 0;
+ }
+
+private:
+ AAsset *m_assetFile;
+ AAssetDir *m_assetDir;
+ QString m_fileName;
+};
+
+
+AndroidAssetsFileEngineHandler::AndroidAssetsFileEngineHandler()
+{
+ m_assetManager = QtAndroid::assetManager();
+}
+
+AndroidAssetsFileEngineHandler::~AndroidAssetsFileEngineHandler()
+{
+}
+
+QAbstractFileEngine * AndroidAssetsFileEngineHandler::create(const QString &fileName) const
+{
+ if (fileName.isEmpty())
+ return 0;
+
+ if (!fileName.startsWith(QLatin1String("assets:/")))
+ return 0;
+
+ int prefixSize=8;
+
+ m_path.clear();
+ if (!fileName.endsWith(QLatin1Char('/'))) {
+ m_path = fileName.toUtf8();
+ AAsset *asset = AAssetManager_open(m_assetManager,
+ m_path.constData() + prefixSize,
+ AASSET_MODE_BUFFER);
+ if (asset)
+ return new AndroidAbstractFileEngine(asset, fileName);
+ }
+
+ if (!m_path.size())
+ m_path = fileName.left(fileName.length() - 1).toUtf8();
+
+ AAssetDir *assetDir = AAssetManager_openDir(m_assetManager, m_path.constData() + prefixSize);
+ if (assetDir) {
+ if (AAssetDir_getNextFileName(assetDir))
+ return new AndroidAbstractFileEngine(assetDir, fileName);
+ else
+ AAssetDir_close(assetDir);
+ }
+ return 0;
+}
diff --git a/src/plugins/platforms/android/src/qandroidassetsfileenginehandler.h b/src/plugins/platforms/android/src/qandroidassetsfileenginehandler.h
new file mode 100644
index 0000000000..9bff6a012e
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidassetsfileenginehandler.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDASSETSFILEENGINEHANDLER_H
+#define QANDROIDASSETSFILEENGINEHANDLER_H
+
+#include <QtCore/private/qabstractfileengine_p.h>
+#include <android/asset_manager.h>
+
+class AndroidAssetsFileEngineHandler: public QAbstractFileEngineHandler
+{
+public:
+ AndroidAssetsFileEngineHandler();
+ virtual ~AndroidAssetsFileEngineHandler();
+ QAbstractFileEngine *create(const QString &fileName) const;
+
+private:
+ AAssetManager *m_assetManager;
+ mutable QByteArray m_path;
+};
+
+#endif // QANDROIDASSETSFILEENGINEHANDLER_H
diff --git a/src/plugins/platforms/android/src/qandroidinputcontext.cpp b/src/plugins/platforms/android/src/qandroidinputcontext.cpp
new file mode 100644
index 0000000000..2180560b04
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidinputcontext.cpp
@@ -0,0 +1,653 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <android/log.h>
+
+#include "qandroidinputcontext.h"
+#include "androidjnimain.h"
+#include "androidjniinput.h"
+#include <QDebug>
+#include <qevent.h>
+#include <qguiapplication.h>
+#include <qsharedpointer.h>
+#include <qthread.h>
+#include <qinputmethod.h>
+#include <qwindow.h>
+
+#include <QTextCharFormat>
+
+QT_BEGIN_NAMESPACE
+
+static QAndroidInputContext *m_androidInputContext = 0;
+static char const *const QtNativeInputConnectionClassName = "org/qtproject/qt5/android/QtNativeInputConnection";
+static char const *const QtExtractedTextClassName = "org/qtproject/qt5/android/QtExtractedText";
+static jclass m_extractedTextClass = 0;
+static jmethodID m_classConstructorMethodID = 0;
+static jfieldID m_partialEndOffsetFieldID = 0;
+static jfieldID m_partialStartOffsetFieldID = 0;
+static jfieldID m_selectionEndFieldID = 0;
+static jfieldID m_selectionStartFieldID = 0;
+static jfieldID m_startOffsetFieldID = 0;
+static jfieldID m_textFieldID = 0;
+
+static jboolean commitText(JNIEnv *env, jobject /*thiz*/, jstring text, jint newCursorPosition)
+{
+ if (!m_androidInputContext)
+ return JNI_FALSE;
+
+ jboolean isCopy;
+ const jchar *jstr = env->GetStringChars(text, &isCopy);
+ QString str(reinterpret_cast<const QChar *>(jstr), env->GetStringLength(text));
+ env->ReleaseStringChars(text, jstr);
+
+ return m_androidInputContext->commitText(str, newCursorPosition);
+}
+
+static jboolean deleteSurroundingText(JNIEnv */*env*/, jobject /*thiz*/, jint leftLength, jint rightLength)
+{
+ if (!m_androidInputContext)
+ return JNI_FALSE;
+
+ return m_androidInputContext->deleteSurroundingText(leftLength, rightLength);
+}
+
+static jboolean finishComposingText(JNIEnv */*env*/, jobject /*thiz*/)
+{
+ if (!m_androidInputContext)
+ return JNI_FALSE;
+
+ return m_androidInputContext->finishComposingText();
+}
+
+static jint getCursorCapsMode(JNIEnv */*env*/, jobject /*thiz*/, jint reqModes)
+{
+ if (!m_androidInputContext)
+ return 0;
+
+ return m_androidInputContext->getCursorCapsMode(reqModes);
+}
+
+static jobject getExtractedText(JNIEnv *env, jobject /*thiz*/, int hintMaxChars, int hintMaxLines, jint flags)
+{
+ if (!m_androidInputContext)
+ return 0;
+
+ const QAndroidInputContext::ExtractedText &extractedText =
+ m_androidInputContext->getExtractedText(hintMaxChars, hintMaxLines, flags);
+
+ jobject object = env->NewObject(m_extractedTextClass, m_classConstructorMethodID);
+ env->SetIntField(object, m_partialStartOffsetFieldID, extractedText.partialStartOffset);
+ env->SetIntField(object, m_partialEndOffsetFieldID, extractedText.partialEndOffset);
+ env->SetIntField(object, m_selectionStartFieldID, extractedText.selectionStart);
+ env->SetIntField(object, m_selectionEndFieldID, extractedText.selectionEnd);
+ env->SetIntField(object, m_startOffsetFieldID, extractedText.startOffset);
+ env->SetObjectField(object,
+ m_textFieldID,
+ env->NewString(reinterpret_cast<const jchar *>(extractedText.text.constData()),
+ jsize(extractedText.text.length())));
+
+ return object;
+}
+
+static jstring getSelectedText(JNIEnv *env, jobject /*thiz*/, jint flags)
+{
+ if (!m_androidInputContext)
+ return 0;
+
+ const QString &text = m_androidInputContext->getSelectedText(flags);
+ return env->NewString(reinterpret_cast<const jchar *>(text.constData()), jsize(text.length()));
+}
+
+static jstring getTextAfterCursor(JNIEnv *env, jobject /*thiz*/, jint length, jint flags)
+{
+ if (!m_androidInputContext)
+ return 0;
+
+ const QString &text = m_androidInputContext->getTextAfterCursor(length, flags);
+ return env->NewString(reinterpret_cast<const jchar *>(text.constData()), jsize(text.length()));
+}
+
+static jstring getTextBeforeCursor(JNIEnv *env, jobject /*thiz*/, jint length, jint flags)
+{
+ if (!m_androidInputContext)
+ return 0;
+
+ const QString &text = m_androidInputContext->getTextBeforeCursor(length, flags);
+ return env->NewString(reinterpret_cast<const jchar *>(text.constData()), jsize(text.length()));
+}
+
+static jboolean setComposingText(JNIEnv *env, jobject /*thiz*/, jstring text, jint newCursorPosition)
+{
+ if (!m_androidInputContext)
+ return JNI_FALSE;
+
+ jboolean isCopy;
+ const jchar *jstr = env->GetStringChars(text, &isCopy);
+ QString str(reinterpret_cast<const QChar *>(jstr), env->GetStringLength(text));
+ env->ReleaseStringChars(text, jstr);
+
+ return m_androidInputContext->setComposingText(str, newCursorPosition);
+}
+
+static jboolean setSelection(JNIEnv */*env*/, jobject /*thiz*/, jint start, jint end)
+{
+ if (!m_androidInputContext)
+ return JNI_FALSE;
+
+ return m_androidInputContext->setSelection(start, end);
+}
+
+static jboolean selectAll(JNIEnv */*env*/, jobject /*thiz*/)
+{
+ if (!m_androidInputContext)
+ return JNI_FALSE;
+
+ return m_androidInputContext->selectAll();
+}
+
+static jboolean cut(JNIEnv */*env*/, jobject /*thiz*/)
+{
+ if (!m_androidInputContext)
+ return JNI_FALSE;
+
+ return m_androidInputContext->cut();
+}
+
+static jboolean copy(JNIEnv */*env*/, jobject /*thiz*/)
+{
+ if (!m_androidInputContext)
+ return JNI_FALSE;
+
+ return m_androidInputContext->copy();
+}
+
+static jboolean copyURL(JNIEnv */*env*/, jobject /*thiz*/)
+{
+ if (!m_androidInputContext)
+ return JNI_FALSE;
+
+ return m_androidInputContext->copyURL();
+}
+
+static jboolean paste(JNIEnv */*env*/, jobject /*thiz*/)
+{
+ if (!m_androidInputContext)
+ return JNI_FALSE;
+
+ return m_androidInputContext->paste();
+}
+
+
+static JNINativeMethod methods[] = {
+ {"commitText", "(Ljava/lang/String;I)Z", (void *)commitText},
+ {"deleteSurroundingText", "(II)Z", (void *)deleteSurroundingText},
+ {"finishComposingText", "()Z", (void *)finishComposingText},
+ {"getCursorCapsMode", "(I)I", (void *)getCursorCapsMode},
+ {"getExtractedText", "(III)Lorg/qtproject/qt5/android/QtExtractedText;", (void *)getExtractedText},
+ {"getSelectedText", "(I)Ljava/lang/String;", (void *)getSelectedText},
+ {"getTextAfterCursor", "(II)Ljava/lang/String;", (void *)getTextAfterCursor},
+ {"getTextBeforeCursor", "(II)Ljava/lang/String;", (void *)getTextBeforeCursor},
+ {"setComposingText", "(Ljava/lang/String;I)Z", (void *)setComposingText},
+ {"setSelection", "(II)Z", (void *)setSelection},
+ {"selectAll", "()Z", (void *)selectAll},
+ {"cut", "()Z", (void *)cut},
+ {"copy", "()Z", (void *)copy},
+ {"copyURL", "()Z", (void *)copyURL},
+ {"paste", "()Z", (void *)paste}
+};
+
+
+QAndroidInputContext::QAndroidInputContext():QPlatformInputContext()
+{
+ JNIEnv *env = 0;
+ if (QtAndroid::javaVM()->AttachCurrentThread(&env, NULL) < 0) {
+ qCritical() << "AttachCurrentThread failed";
+ return;
+ }
+
+ jclass clazz = QtAndroid::findClass(QtNativeInputConnectionClassName, env);
+ if (clazz == NULL) {
+ qCritical() << "Native registration unable to find class '"
+ << QtNativeInputConnectionClassName
+ << "'";
+ return;
+ }
+
+ if (env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
+ qCritical() << "RegisterNatives failed for '"
+ << QtNativeInputConnectionClassName
+ << "'";
+ return;
+ }
+
+ clazz = QtAndroid::findClass(QtExtractedTextClassName, env);
+ if (clazz == NULL) {
+ qCritical() << "Native registration unable to find class '"
+ << QtExtractedTextClassName
+ << "'";
+ return;
+ }
+
+ m_extractedTextClass = static_cast<jclass>(env->NewGlobalRef(clazz));
+ m_classConstructorMethodID = env->GetMethodID(m_extractedTextClass, "<init>", "()V");
+ if (m_classConstructorMethodID == NULL) {
+ qCritical() << "GetMethodID failed";
+ return;
+ }
+
+ m_partialEndOffsetFieldID = env->GetFieldID(m_extractedTextClass, "partialEndOffset", "I");
+ if (m_partialEndOffsetFieldID == NULL) {
+ qCritical() << "Can't find field partialEndOffset";
+ return;
+ }
+
+ m_partialStartOffsetFieldID = env->GetFieldID(m_extractedTextClass, "partialStartOffset", "I");
+ if (m_partialStartOffsetFieldID == NULL) {
+ qCritical() << "Can't find field partialStartOffset";
+ return;
+ }
+
+ m_selectionEndFieldID = env->GetFieldID(m_extractedTextClass, "selectionEnd", "I");
+ if (m_selectionEndFieldID == NULL) {
+ qCritical() << "Can't find field selectionEnd";
+ return;
+ }
+
+ m_selectionStartFieldID = env->GetFieldID(m_extractedTextClass, "selectionStart", "I");
+ if (m_selectionStartFieldID == NULL) {
+ qCritical() << "Can't find field selectionStart";
+ return;
+ }
+
+ m_startOffsetFieldID = env->GetFieldID(m_extractedTextClass, "startOffset", "I");
+ if (m_startOffsetFieldID == NULL) {
+ qCritical() << "Can't find field startOffset";
+ return;
+ }
+
+ m_textFieldID = env->GetFieldID(m_extractedTextClass, "text", "Ljava/lang/String;");
+ if (m_textFieldID == NULL) {
+ qCritical() << "Can't find field text";
+ return;
+ }
+ qRegisterMetaType<QInputMethodEvent *>("QInputMethodEvent*");
+ qRegisterMetaType<QInputMethodQueryEvent *>("QInputMethodQueryEvent*");
+ m_androidInputContext = this;
+}
+
+QAndroidInputContext::~QAndroidInputContext()
+{
+ m_androidInputContext = 0;
+ m_extractedTextClass = 0;
+ m_partialEndOffsetFieldID = 0;
+ m_partialStartOffsetFieldID = 0;
+ m_selectionEndFieldID = 0;
+ m_selectionStartFieldID = 0;
+ m_startOffsetFieldID = 0;
+ m_textFieldID = 0;
+}
+
+void QAndroidInputContext::reset()
+{
+ clear();
+ if (qGuiApp->focusObject())
+ QtAndroidInput::resetSoftwareKeyboard();
+ else
+ QtAndroidInput::hideSoftwareKeyboard();
+}
+
+void QAndroidInputContext::commit()
+{
+ finishComposingText();
+}
+
+void QAndroidInputContext::updateCursorPosition()
+{
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
+ if (!query.isNull()) {
+ const int cursorPos = query->value(Qt::ImCursorPosition).toInt();
+ QtAndroidInput::updateSelection(cursorPos, cursorPos, -1, -1); //selection empty and no pre-edit text
+ }
+}
+
+void QAndroidInputContext::update(Qt::InputMethodQueries queries)
+{
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(queries);
+ if (query.isNull())
+ return;
+#warning TODO extract the needed data from query
+}
+
+void QAndroidInputContext::invokeAction(QInputMethod::Action action, int cursorPosition)
+{
+#warning TODO Handle at least QInputMethod::ContextMenu action
+ Q_UNUSED(action)
+ Q_UNUSED(cursorPosition)
+
+ if (action == QInputMethod::Click)
+ commit();
+}
+
+QRectF QAndroidInputContext::keyboardRect() const
+{
+ return QPlatformInputContext::keyboardRect();
+}
+
+bool QAndroidInputContext::isAnimating() const
+{
+ return false;
+}
+
+void QAndroidInputContext::showInputPanel()
+{
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
+ if (query.isNull())
+ return;
+
+ disconnect(m_updateCursorPosConnection);
+ if (qGuiApp->focusObject()->metaObject()->indexOfSignal("cursorPositionChanged(int,int)") >= 0) // QLineEdit breaks the pattern
+ m_updateCursorPosConnection = connect(qGuiApp->focusObject(), SIGNAL(cursorPositionChanged(int,int)), this, SLOT(updateCursorPosition()));
+ else
+ m_updateCursorPosConnection = connect(qGuiApp->focusObject(), SIGNAL(cursorPositionChanged()), this, SLOT(updateCursorPosition()));
+ QRectF itemRect = qGuiApp->inputMethod()->inputItemRectangle();
+ QRect rect = qGuiApp->inputMethod()->inputItemTransform().mapRect(itemRect).toRect();
+ QWindow *window = qGuiApp->focusWindow();
+ if (window)
+ rect = QRect(window->mapToGlobal(rect.topLeft()), rect.size());
+
+ QtAndroidInput::showSoftwareKeyboard(rect.left(),
+ rect.top(),
+ rect.width(),
+ rect.height(),
+ query->value(Qt::ImHints).toUInt());
+}
+
+void QAndroidInputContext::hideInputPanel()
+{
+ QtAndroidInput::hideSoftwareKeyboard();
+}
+
+bool QAndroidInputContext::isInputPanelVisible() const
+{
+ return QtAndroidInput::isSoftwareKeyboardVisible();
+}
+
+bool QAndroidInputContext::isComposing() const
+{
+ return m_composingText.length();
+}
+
+void QAndroidInputContext::clear()
+{
+ m_composingText.clear();
+ m_extractedText.clear();
+}
+
+void QAndroidInputContext::sendEvent(QObject *receiver, QInputMethodEvent *event)
+{
+ QCoreApplication::sendEvent(receiver, event);
+}
+
+void QAndroidInputContext::sendEvent(QObject *receiver, QInputMethodQueryEvent *event)
+{
+ QCoreApplication::sendEvent(receiver, event);
+}
+
+jboolean QAndroidInputContext::commitText(const QString &text, jint /*newCursorPosition*/)
+{
+ m_composingText = text;
+ return finishComposingText();
+}
+
+jboolean QAndroidInputContext::deleteSurroundingText(jint leftLength, jint rightLength)
+{
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
+ if (query.isNull())
+ return JNI_TRUE;
+
+ m_composingText.clear();
+
+ QInputMethodEvent event;
+ event.setCommitString(QString(), -leftLength, leftLength+rightLength);
+ sendInputMethodEvent(&event);
+ clear();
+
+ return JNI_TRUE;
+}
+
+jboolean QAndroidInputContext::finishComposingText()
+{
+ QInputMethodEvent event;
+ event.setCommitString(m_composingText);
+ sendInputMethodEvent(&event);
+ clear();
+
+ return JNI_TRUE;
+}
+
+jint QAndroidInputContext::getCursorCapsMode(jint /*reqModes*/)
+{
+ jint res = 0;
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
+ if (query.isNull())
+ return res;
+
+ const uint qtInputMethodHints = query->value(Qt::ImHints).toUInt();
+
+ if (qtInputMethodHints & Qt::ImhPreferUppercase)
+ res = CAP_MODE_SENTENCES;
+
+ if (qtInputMethodHints & Qt::ImhUppercaseOnly)
+ res = CAP_MODE_CHARACTERS;
+
+ return res;
+}
+
+const QAndroidInputContext::ExtractedText &QAndroidInputContext::getExtractedText(jint hintMaxChars, jint /*hintMaxLines*/, jint /*flags*/)
+{
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
+ if (query.isNull())
+ return m_extractedText;
+
+ if (hintMaxChars)
+ m_extractedText.text = query->value(Qt::ImSurroundingText).toString().right(hintMaxChars);
+
+ m_extractedText.startOffset = query->value(Qt::ImCursorPosition).toInt();
+ const QString &selection = query->value(Qt::ImCurrentSelection).toString();
+ const int selLen = selection.length();
+ if (selLen) {
+ m_extractedText.selectionStart = query->value(Qt::ImAnchorPosition).toInt();
+ m_extractedText.selectionEnd = m_extractedText.startOffset;
+ }
+
+ return m_extractedText;
+}
+
+QString QAndroidInputContext::getSelectedText(jint /*flags*/)
+{
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
+ if (query.isNull())
+ return QString();
+
+ return query->value(Qt::ImCurrentSelection).toString();
+}
+
+QString QAndroidInputContext::getTextAfterCursor(jint length, jint /*flags*/)
+{
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
+ if (query.isNull())
+ return QString();
+
+ QString text = query->value(Qt::ImSurroundingText).toString();
+ if (!text.length())
+ return text;
+
+ int cursorPos = query->value(Qt::ImCursorPosition).toInt();
+ return text.mid(cursorPos, length);
+}
+
+QString QAndroidInputContext::getTextBeforeCursor(jint length, jint /*flags*/)
+{
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
+ if (query.isNull())
+ return QString();
+
+ QString text = query->value(Qt::ImSurroundingText).toString();
+ if (!text.length())
+ return text;
+
+ int cursorPos = query->value(Qt::ImCursorPosition).toInt();
+ const int wordLeftPos = cursorPos - length;
+ return text.mid(wordLeftPos > 0 ? wordLeftPos : 0, cursorPos);
+}
+
+jboolean QAndroidInputContext::setComposingText(const QString &text, jint newCursorPosition)
+{
+ if (newCursorPosition > 0)
+ newCursorPosition += text.length() - 1;
+ m_composingText = text;
+ QList<QInputMethodEvent::Attribute> attributes;
+ attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor,
+ newCursorPosition,
+ 1,
+ QVariant()));
+ // Show compose text underlined
+ QTextCharFormat underlined;
+ underlined.setFontUnderline(true);
+ attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,0, text.length(),
+ QVariant(underlined)));
+
+ QInputMethodEvent event(m_composingText, attributes);
+ sendInputMethodEvent(&event);
+
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
+ if (!query.isNull()) {
+ int cursorPos = query->value(Qt::ImCursorPosition).toInt();
+ int preeditLength = text.length();
+ QtAndroidInput::updateSelection(cursorPos+preeditLength, cursorPos+preeditLength, cursorPos, cursorPos+preeditLength);
+ }
+
+ return JNI_TRUE;
+}
+
+jboolean QAndroidInputContext::setSelection(jint start, jint end)
+{
+ QList<QInputMethodEvent::Attribute> attributes;
+ attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection,
+ start,
+ end - start,
+ QVariant()));
+
+ QInputMethodEvent event(QString(), attributes);
+ sendInputMethodEvent(&event);
+ return JNI_TRUE;
+}
+
+jboolean QAndroidInputContext::selectAll()
+{
+#warning TODO
+ return JNI_FALSE;
+}
+
+jboolean QAndroidInputContext::cut()
+{
+#warning TODO
+ return JNI_FALSE;
+}
+
+jboolean QAndroidInputContext::copy()
+{
+#warning TODO
+ return JNI_FALSE;
+}
+
+jboolean QAndroidInputContext::copyURL()
+{
+#warning TODO
+ return JNI_FALSE;
+}
+
+jboolean QAndroidInputContext::paste()
+{
+#warning TODO
+ return JNI_FALSE;
+}
+
+QSharedPointer<QInputMethodQueryEvent> QAndroidInputContext::focusObjectInputMethodQuery(Qt::InputMethodQueries queries)
+{
+#warning TODO make qGuiApp->focusObject() thread safe !!!
+ QObject *focusObject = qGuiApp->focusObject();
+ if (!focusObject)
+ return QSharedPointer<QInputMethodQueryEvent>();
+
+ QSharedPointer<QInputMethodQueryEvent> ret = QSharedPointer<QInputMethodQueryEvent>(new QInputMethodQueryEvent(queries));
+ if (qGuiApp->thread()==QThread::currentThread()) {
+ QCoreApplication::sendEvent(focusObject, ret.data());
+ } else {
+ QMetaObject::invokeMethod(this,
+ "sendEvent",
+ Qt::BlockingQueuedConnection,
+ Q_ARG(QObject*, focusObject),
+ Q_ARG(QInputMethodQueryEvent*, ret.data()));
+ }
+
+ return ret;
+}
+
+void QAndroidInputContext::sendInputMethodEvent(QInputMethodEvent *event)
+{
+#warning TODO make qGuiApp->focusObject() thread safe !!!
+ QObject *focusObject = qGuiApp->focusObject();
+ if (!focusObject)
+ return;
+
+ if (qGuiApp->thread() == QThread::currentThread()) {
+ QCoreApplication::sendEvent(focusObject, event);
+ } else {
+ QMetaObject::invokeMethod(this,
+ "sendEvent",
+ Qt::BlockingQueuedConnection,
+ Q_ARG(QObject*, focusObject),
+ Q_ARG(QInputMethodEvent*, event));
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/src/qandroidinputcontext.h b/src/plugins/platforms/android/src/qandroidinputcontext.h
new file mode 100644
index 0000000000..482aeffa50
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidinputcontext.h
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ANDROIDINPUTCONTEXT_H
+#define ANDROIDINPUTCONTEXT_H
+
+#include <qpa/qplatforminputcontext.h>
+#include <jni.h>
+#include <qevent.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidInputContext: public QPlatformInputContext
+{
+ Q_OBJECT
+ enum CapsMode
+ {
+ CAP_MODE_CHARACTERS = 0x00001000,
+ CAP_MODE_SENTENCES = 0x00004000,
+ CAP_MODE_WORDS = 0x00002000
+ };
+
+public:
+ struct ExtractedText
+ {
+ ExtractedText() { clear(); }
+
+ void clear()
+ {
+ partialEndOffset = partialStartOffset = selectionEnd = selectionStart = startOffset = -1;
+ text.clear();
+ }
+
+ int partialEndOffset;
+ int partialStartOffset;
+ int selectionEnd;
+ int selectionStart;
+ int startOffset;
+ QString text;
+ };
+
+public:
+ QAndroidInputContext();
+ ~QAndroidInputContext();
+ bool isValid() const { return true; }
+
+ void reset();
+ void commit();
+ void update(Qt::InputMethodQueries queries);
+ void invokeAction(QInputMethod::Action action, int cursorPosition);
+ QRectF keyboardRect() const;
+ bool isAnimating() const;
+ void showInputPanel();
+ void hideInputPanel();
+ bool isInputPanelVisible() const;
+
+ bool isComposing() const;
+ void clear();
+
+ //---------------//
+ jboolean commitText(const QString &text, jint newCursorPosition);
+ jboolean deleteSurroundingText(jint leftLength, jint rightLength);
+ jboolean finishComposingText();
+ jint getCursorCapsMode(jint reqModes);
+ const ExtractedText &getExtractedText(jint hintMaxChars, jint hintMaxLines, jint flags);
+ QString getSelectedText(jint flags);
+ QString getTextAfterCursor(jint length, jint flags);
+ QString getTextBeforeCursor(jint length, jint flags);
+ jboolean setComposingText(const QString &text, jint newCursorPosition);
+ jboolean setSelection(jint start, jint end);
+ jboolean selectAll();
+ jboolean cut();
+ jboolean copy();
+ jboolean copyURL();
+ jboolean paste();
+
+private:
+ QSharedPointer<QInputMethodQueryEvent> focusObjectInputMethodQuery(Qt::InputMethodQueries queries = Qt::ImQueryAll);
+ void sendInputMethodEvent(QInputMethodEvent *event);
+
+private slots:
+ virtual void sendEvent(QObject *receiver, QInputMethodEvent *event);
+ virtual void sendEvent(QObject *receiver, QInputMethodQueryEvent *event);
+ void updateCursorPosition();
+
+private:
+ ExtractedText m_extractedText;
+ QString m_composingText;
+ QMetaObject::Connection m_updateCursorPosConnection;
+};
+
+QT_END_NAMESPACE
+
+#endif // ANDROIDINPUTCONTEXT_H
diff --git a/src/plugins/platforms/android/src/qandroidplatformclipboard.cpp b/src/plugins/platforms/android/src/qandroidplatformclipboard.cpp
new file mode 100644
index 0000000000..bc48b4935b
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformclipboard.cpp
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidplatformclipboard.h"
+#include "androidjniclipboard.h"
+#ifndef QT_NO_CLIPBOARD
+#include <QMimeData>
+
+QT_BEGIN_NAMESPACE
+
+QAndroidPlatformClipboard::QAndroidPlatformClipboard()
+{
+ QtAndroidClipboard::setClipboardListener(this);
+}
+
+QMimeData *QAndroidPlatformClipboard::mimeData(QClipboard::Mode mode)
+{
+ if (QClipboard::Clipboard != mode || !QtAndroidClipboard::hasClipboardText())
+ return 0;
+
+ QMimeData *mimeData = new QMimeData();
+ mimeData->setText(QtAndroidClipboard::clipboardText());
+ return mimeData;
+}
+
+void QAndroidPlatformClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
+{
+ if (!data || !data->hasText() || QClipboard::Clipboard != mode)
+ return;
+
+ QtAndroidClipboard::setClipboardText(data->text());
+}
+
+bool QAndroidPlatformClipboard::supportsMode(QClipboard::Mode mode) const
+{
+ return QClipboard::Clipboard == mode;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_CLIPBOARD
diff --git a/src/plugins/platforms/android/src/qandroidplatformclipboard.h b/src/plugins/platforms/android/src/qandroidplatformclipboard.h
new file mode 100644
index 0000000000..644f326934
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformclipboard.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDPLATFORMCLIPBOARD_H
+#define QANDROIDPLATFORMCLIPBOARD_H
+
+#include <qpa/qplatformclipboard.h>
+
+#ifndef QT_NO_CLIPBOARD
+QT_BEGIN_NAMESPACE
+
+class QAndroidPlatformClipboard: public QPlatformClipboard
+{
+public:
+ QAndroidPlatformClipboard();
+
+ virtual QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard);
+ virtual void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard);
+ virtual bool supportsMode(QClipboard::Mode mode) const;
+};
+
+QT_END_NAMESPACE
+#endif // QT_NO_CLIPBOARD
+
+#endif // QANDROIDPLATFORMCLIPBOARD_H
diff --git a/src/plugins/platforms/android/src/qandroidplatformfontdatabase.cpp b/src/plugins/platforms/android/src/qandroidplatformfontdatabase.cpp
new file mode 100644
index 0000000000..7f68b44ed8
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformfontdatabase.cpp
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QDir>
+
+#include "qandroidplatformfontdatabase.h"
+
+QString QAndroidPlatformFontDatabase::fontDir() const
+{
+ return QLatin1String("/system/fonts");
+}
+
+void QAndroidPlatformFontDatabase::populateFontDatabase()
+{
+ QString fontpath = fontDir();
+
+ if (!QFile::exists(fontpath)) {
+ qFatal("QFontDatabase: Cannot find font directory %s - is Qt installed correctly?",
+ qPrintable(fontpath));
+ }
+
+ QDir dir(fontpath, QLatin1String("*.ttf"));
+ for (int i = 0; i < int(dir.count()); ++i) {
+ const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i]));
+ addTTFile(QByteArray(), file);
+ }
+}
+
+QStringList QAndroidPlatformFontDatabase::fallbacksForFamily(const QString &family,
+ QFont::Style style,
+ QFont::StyleHint styleHint,
+ QChar::Script script) const
+{
+ Q_UNUSED(family);
+ Q_UNUSED(style);
+ Q_UNUSED(script);
+ if (styleHint == QFont::Monospace)
+ return QString(qgetenv("QT_ANDROID_FONTS_MONOSPACE")).split(";");
+
+ return QString(qgetenv("QT_ANDROID_FONTS")).split(";");
+}
diff --git a/src/plugins/platforms/android/src/qandroidplatformfontdatabase.h b/src/plugins/platforms/android/src/qandroidplatformfontdatabase.h
new file mode 100644
index 0000000000..3cbfe95d36
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformfontdatabase.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDPLATFORMFONTDATABASE_H
+#define QANDROIDPLATFORMFONTDATABASE_H
+
+#include <QtPlatformSupport/private/qbasicfontdatabase_p.h>
+
+class QAndroidPlatformFontDatabase: public QBasicFontDatabase
+{
+public:
+ QString fontDir() const;
+ void populateFontDatabase();
+ QStringList fallbacksForFamily(const QString &family,
+ QFont::Style style,
+ QFont::StyleHint styleHint,
+ QChar::Script script) const;
+};
+
+#endif // QANDROIDPLATFORMFONTDATABASE_H
diff --git a/src/plugins/platforms/android/src/qandroidplatformintegration.cpp b/src/plugins/platforms/android/src/qandroidplatformintegration.cpp
new file mode 100644
index 0000000000..cbd0f26835
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformintegration.cpp
@@ -0,0 +1,285 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidplatformintegration.h"
+#include "qabstracteventdispatcher.h"
+#include "androidjnimain.h"
+#include <QtGui/private/qpixmap_raster_p.h>
+#include <qpa/qwindowsysteminterface.h>
+#include <QThread>
+#include <qpa/qplatformwindow.h>
+#include "qandroidplatformservices.h"
+#include "qandroidplatformfontdatabase.h"
+#include "qandroidplatformclipboard.h"
+#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h>
+
+#ifndef ANDROID_PLUGIN_OPENGL
+# include "qandroidplatformscreen.h"
+# include "qandroidplatformwindow.h"
+# include <QtPlatformSupport/private/qfbbackingstore_p.h>
+#else
+# include "qeglfswindow.h"
+# include "androidjnimenu.h"
+# include "qandroidopenglcontext.h"
+# include "qandroidopenglplatformwindow.h"
+# include "qeglfshooks.h"
+# include <QtGui/qopenglcontext.h>
+#endif
+
+#include "qandroidplatformtheme.h"
+
+QT_BEGIN_NAMESPACE
+
+int QAndroidPlatformIntegration::m_defaultGeometryWidth = 320;
+int QAndroidPlatformIntegration::m_defaultGeometryHeight = 455;
+int QAndroidPlatformIntegration::m_defaultPhysicalSizeWidth = 50;
+int QAndroidPlatformIntegration::m_defaultPhysicalSizeHeight = 71;
+
+void *QAndroidPlatformNativeInterface::nativeResourceForIntegration(const QByteArray &resource)
+{
+ if (resource=="JavaVM")
+ return QtAndroid::javaVM();
+ if (resource == "QtActivity")
+ return QtAndroid::activity();
+
+ return 0;
+}
+
+QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList &paramList)
+ : m_touchDevice(0)
+#ifdef ANDROID_PLUGIN_OPENGL
+ , m_primaryWindow(0)
+#endif
+{
+ Q_UNUSED(paramList);
+
+#ifndef ANDROID_PLUGIN_OPENGL
+ m_eventDispatcher = createUnixEventDispatcher();
+#endif
+
+ m_androidPlatformNativeInterface = new QAndroidPlatformNativeInterface();
+
+#ifndef ANDROID_PLUGIN_OPENGL
+ m_primaryScreen = new QAndroidPlatformScreen();
+ screenAdded(m_primaryScreen);
+ m_primaryScreen->setPhysicalSize(QSize(m_defaultPhysicalSizeWidth, m_defaultPhysicalSizeHeight));
+ m_primaryScreen->setGeometry(QRect(0, 0, m_defaultGeometryWidth, m_defaultGeometryHeight));
+#endif
+
+ m_mainThread = QThread::currentThread();
+ QtAndroid::setAndroidPlatformIntegration(this);
+
+ m_androidFDB = new QAndroidPlatformFontDatabase();
+ m_androidPlatformServices = new QAndroidPlatformServices();
+ m_androidPlatformClipboard = new QAndroidPlatformClipboard();
+}
+
+bool QAndroidPlatformIntegration::hasCapability(Capability cap) const
+{
+ switch (cap) {
+ case ThreadedPixmaps: return true;
+ default:
+#ifndef ANDROID_PLUGIN_OPENGL
+ return QPlatformIntegration::hasCapability(cap);
+#else
+ return QEglFSIntegration::hasCapability(cap);
+#endif
+ }
+}
+
+#ifndef ANDROID_PLUGIN_OPENGL
+QPlatformBackingStore *QAndroidPlatformIntegration::createPlatformBackingStore(QWindow *window) const
+{
+ return new QFbBackingStore(window);
+}
+
+QPlatformWindow *QAndroidPlatformIntegration::createPlatformWindow(QWindow *window) const
+{
+ return new QAndroidPlatformWindow(window);
+}
+
+QAbstractEventDispatcher *QAndroidPlatformIntegration::guiThreadEventDispatcher() const
+{
+ return m_eventDispatcher;
+}
+#else // !ANDROID_PLUGIN_OPENGL
+QPlatformWindow *QAndroidPlatformIntegration::createPlatformWindow(QWindow *window) const
+{
+ if (m_primaryWindow != 0) {
+ qWarning("QAndroidPlatformIntegration::createPlatformWindow: Unsupported case: More than "
+ "one top-level window created.");
+ }
+
+ m_primaryWindow = new QAndroidOpenGLPlatformWindow(window);
+ m_primaryWindow->requestActivateWindow();
+ QtAndroidMenu::setActiveTopLevelWindow(window);
+
+ return m_primaryWindow;
+}
+
+void QAndroidPlatformIntegration::invalidateNativeSurface()
+{
+ if (m_primaryWindow != 0)
+ m_primaryWindow->invalidateSurface();
+}
+
+void QAndroidPlatformIntegration::surfaceChanged()
+{
+ if (m_primaryWindow != 0)
+ m_primaryWindow->resetSurface();
+}
+
+QPlatformOpenGLContext *QAndroidPlatformIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
+{
+ return new QAndroidOpenGLContext(this,
+ QEglFSHooks::hooks()->surfaceFormatFor(context->format()),
+ context->shareHandle(),
+ display());
+}
+#endif // ANDROID_PLUGIN_OPENGL
+
+QAndroidPlatformIntegration::~QAndroidPlatformIntegration()
+{
+ delete m_androidPlatformNativeInterface;
+ delete m_androidFDB;
+ delete m_touchDevice;
+ QtAndroid::setAndroidPlatformIntegration(NULL);
+}
+QPlatformFontDatabase *QAndroidPlatformIntegration::fontDatabase() const
+{
+ return m_androidFDB;
+}
+
+#ifndef QT_NO_CLIPBOARD
+QPlatformClipboard *QAndroidPlatformIntegration::clipboard() const
+{
+static QAndroidPlatformClipboard *clipboard = 0;
+ if (!clipboard)
+ clipboard = new QAndroidPlatformClipboard;
+
+ return clipboard;
+}
+#endif
+
+QPlatformInputContext *QAndroidPlatformIntegration::inputContext() const
+{
+ return &m_platformInputContext;
+}
+
+QPlatformNativeInterface *QAndroidPlatformIntegration::nativeInterface() const
+{
+ return m_androidPlatformNativeInterface;
+}
+
+QPlatformServices *QAndroidPlatformIntegration::services() const
+{
+ return m_androidPlatformServices;
+}
+
+static const QLatin1String androidThemeName("android");
+QStringList QAndroidPlatformIntegration::themeNames() const
+{
+ return QStringList(QString(androidThemeName));
+}
+
+QPlatformTheme *QAndroidPlatformIntegration::createPlatformTheme(const QString &name) const
+{
+ if (androidThemeName == name)
+ return new QAndroidPlatformTheme;
+
+ return 0;
+}
+
+void QAndroidPlatformIntegration::setDefaultDisplayMetrics(int gw, int gh, int sw, int sh)
+{
+ m_defaultGeometryWidth = gw;
+ m_defaultGeometryHeight = gh;
+ m_defaultPhysicalSizeWidth = sw;
+ m_defaultPhysicalSizeHeight = sh;
+}
+
+void QAndroidPlatformIntegration::setDefaultDesktopSize(int gw, int gh)
+{
+ m_defaultGeometryWidth = gw;
+ m_defaultGeometryHeight = gh;
+}
+
+
+#ifndef ANDROID_PLUGIN_OPENGL
+void QAndroidPlatformIntegration::setDesktopSize(int width, int height)
+{
+ if (m_primaryScreen)
+ QMetaObject::invokeMethod(m_primaryScreen, "setGeometry", Qt::AutoConnection, Q_ARG(QRect, QRect(0,0,width, height)));
+}
+
+void QAndroidPlatformIntegration::setDisplayMetrics(int width, int height)
+{
+ if (m_primaryScreen)
+ QMetaObject::invokeMethod(m_primaryScreen, "setPhysicalSize", Qt::AutoConnection, Q_ARG(QSize, QSize(width, height)));
+}
+#else
+void QAndroidPlatformIntegration::setDesktopSize(int width, int height)
+{
+ m_defaultGeometryWidth = width;
+ m_defaultGeometryHeight = height;
+}
+
+void QAndroidPlatformIntegration::setDisplayMetrics(int width, int height)
+{
+ m_defaultPhysicalSizeWidth = width;
+ m_defaultPhysicalSizeHeight = height;
+}
+
+#endif
+
+void QAndroidPlatformIntegration::pauseApp()
+{
+ if (QAbstractEventDispatcher::instance(m_mainThread))
+ QAbstractEventDispatcher::instance(m_mainThread)->interrupt();
+}
+
+void QAndroidPlatformIntegration::resumeApp()
+{
+ if (QAbstractEventDispatcher::instance(m_mainThread))
+ QAbstractEventDispatcher::instance(m_mainThread)->wakeUp();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/src/qandroidplatformintegration.h b/src/plugins/platforms/android/src/qandroidplatformintegration.h
new file mode 100644
index 0000000000..3f8cc5a809
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformintegration.h
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDPLATFORMINTERATION_H
+#define QANDROIDPLATFORMINTERATION_H
+
+#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformmenu.h>
+#include <qpa/qplatformnativeinterface.h>
+#include <QtWidgets/QAction>
+
+#include <jni.h>
+#include "qandroidinputcontext.h"
+
+#ifndef ANDROID_PLUGIN_OPENGL
+# include "qandroidplatformscreen.h"
+#else
+# include "qeglfsintegration.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QDesktopWidget;
+class QAndroidPlatformServices;
+
+#ifdef ANDROID_PLUGIN_OPENGL
+class QAndroidOpenGLPlatformWindow;
+#endif
+
+class QAndroidPlatformNativeInterface: public QPlatformNativeInterface
+{
+public:
+ void *nativeResourceForIntegration(const QByteArray &resource);
+};
+
+class QAndroidPlatformIntegration
+#ifndef ANDROID_PLUGIN_OPENGL
+ : public QPlatformIntegration
+#else
+ : public QEglFSIntegration
+#endif
+{
+ friend class QAndroidPlatformScreen;
+
+public:
+ QAndroidPlatformIntegration(const QStringList &paramList);
+ ~QAndroidPlatformIntegration();
+
+ bool hasCapability(QPlatformIntegration::Capability cap) const;
+
+#ifndef ANDROID_PLUGIN_OPENGL
+ QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const;
+ QPlatformWindow *createPlatformWindow(QWindow *window) const;
+ QAbstractEventDispatcher *guiThreadEventDispatcher() const;
+ QAndroidPlatformScreen *screen() { return m_primaryScreen; }
+#else
+ QPlatformWindow *createPlatformWindow(QWindow *window) const;
+ void invalidateNativeSurface();
+ void surfaceChanged();
+ QAndroidOpenGLPlatformWindow *primaryWindow() const { return m_primaryWindow; }
+ QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const;
+#endif
+
+ virtual void setDesktopSize(int width, int height);
+ virtual void setDisplayMetrics(int width, int height);
+ bool isVirtualDesktop() { return true; }
+
+ QPlatformFontDatabase *fontDatabase() const;
+
+#ifndef QT_NO_CLIPBOARD
+ QPlatformClipboard *clipboard() const;
+#endif
+
+ QPlatformInputContext *inputContext() const;
+ QPlatformNativeInterface *nativeInterface() const;
+ QPlatformServices *services() const;
+
+ QStringList themeNames() const;
+ QPlatformTheme *createPlatformTheme(const QString &name) const;
+
+ void pauseApp();
+ void resumeApp();
+ static void setDefaultDisplayMetrics(int gw, int gh, int sw, int sh);
+ static void setDefaultDesktopSize(int gw, int gh);
+
+ static QSize defaultDesktopSize()
+ {
+ return QSize(m_defaultGeometryWidth, m_defaultGeometryHeight);
+ }
+
+ QTouchDevice *touchDevice() const { return m_touchDevice; }
+ void setTouchDevice(QTouchDevice *touchDevice) { m_touchDevice = touchDevice; }
+
+private:
+
+ friend class QEglFSAndroidHooks;
+
+ QTouchDevice *m_touchDevice;
+
+#ifndef ANDROID_PLUGIN_OPENGL
+ QAbstractEventDispatcher *m_eventDispatcher;
+ QAndroidPlatformScreen *m_primaryScreen;
+#else
+ mutable QAndroidOpenGLPlatformWindow *m_primaryWindow;
+#endif
+
+ QThread *m_mainThread;
+
+ static int m_defaultGeometryWidth;
+ static int m_defaultGeometryHeight;
+ static int m_defaultPhysicalSizeWidth;
+ static int m_defaultPhysicalSizeHeight;
+
+ QPlatformFontDatabase *m_androidFDB;
+ QImage *m_FbScreenImage;
+ QPainter *m_compositePainter;
+ QAndroidPlatformNativeInterface *m_androidPlatformNativeInterface;
+ QAndroidPlatformServices *m_androidPlatformServices;
+ QPlatformClipboard *m_androidPlatformClipboard;
+
+ mutable QAndroidInputContext m_platformInputContext;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/android/src/qandroidplatformmenu.cpp b/src/plugins/platforms/android/src/qandroidplatformmenu.cpp
new file mode 100644
index 0000000000..36247e86f9
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformmenu.cpp
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidplatformmenu.h"
+#include "qandroidplatformmenuitem.h"
+#include "androidjnimenu.h"
+
+QAndroidPlatformMenu::QAndroidPlatformMenu()
+{
+ m_tag = reinterpret_cast<quintptr>(this); // QMenu will overwrite this later, but we need a unique ID for QtQuick
+ m_enabled = true;
+ m_isVisible = true;
+}
+
+QAndroidPlatformMenu::~QAndroidPlatformMenu()
+{
+ QtAndroidMenu::androidPlatformMenuDestroyed(this);
+}
+
+void QAndroidPlatformMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before)
+{
+ QMutexLocker lock(&m_menuItemsMutex);
+ m_menuItems.insert(qFind(m_menuItems.begin(),
+ m_menuItems.end(),
+ static_cast<QAndroidPlatformMenuItem *>(before)),
+ static_cast<QAndroidPlatformMenuItem *>(menuItem));
+}
+
+void QAndroidPlatformMenu::removeMenuItem(QPlatformMenuItem *menuItem)
+{
+ QMutexLocker lock(&m_menuItemsMutex);
+ m_menuItems.erase(qFind(m_menuItems.begin(),
+ m_menuItems.end(),
+ static_cast<QAndroidPlatformMenuItem *>(menuItem)));
+}
+
+void QAndroidPlatformMenu::syncMenuItem(QPlatformMenuItem *menuItem)
+{
+ PlatformMenuItemsType::iterator it;
+ for (it = m_menuItems.begin(); it != m_menuItems.end(); ++it) {
+ if ((*it)->tag() == menuItem->tag())
+ break;
+ }
+
+ if (it != m_menuItems.end())
+ QtAndroidMenu::syncMenu(this);
+}
+
+void QAndroidPlatformMenu::syncSeparatorsCollapsible(bool enable)
+{
+ Q_UNUSED(enable)
+}
+
+void QAndroidPlatformMenu::setTag(quintptr tag)
+{
+ m_tag = tag;
+}
+
+quintptr QAndroidPlatformMenu::tag() const
+{
+ return m_tag;
+}
+
+void QAndroidPlatformMenu::setText(const QString &text)
+{
+ m_text = text;
+}
+
+QString QAndroidPlatformMenu::text() const
+{
+ return m_text;
+}
+
+void QAndroidPlatformMenu::setIcon(const QIcon &icon)
+{
+ m_icon = icon;
+}
+
+QIcon QAndroidPlatformMenu::icon() const
+{
+ return m_icon;
+}
+
+void QAndroidPlatformMenu::setEnabled(bool enabled)
+{
+ m_enabled = enabled;
+}
+
+bool QAndroidPlatformMenu::isEnabled() const
+{
+ return m_enabled;
+}
+
+void QAndroidPlatformMenu::setVisible(bool visible)
+{
+ m_isVisible = visible;
+}
+
+bool QAndroidPlatformMenu::isVisible() const
+{
+ return m_isVisible;
+}
+
+QPlatformMenuItem *QAndroidPlatformMenu::menuItemAt(int position) const
+{
+ if (position < m_menuItems.size())
+ return m_menuItems[position];
+ return 0;
+}
+
+QPlatformMenuItem *QAndroidPlatformMenu::menuItemForTag(quintptr tag) const
+{
+ foreach (QPlatformMenuItem *menuItem, m_menuItems) {
+ if (menuItem->tag() == tag)
+ return menuItem;
+ }
+
+ return 0;
+}
+
+QAndroidPlatformMenu::PlatformMenuItemsType QAndroidPlatformMenu::menuItems() const
+{
+ return m_menuItems;
+}
+
+QMutex *QAndroidPlatformMenu::menuItemsMutex()
+{
+ return &m_menuItemsMutex;
+}
diff --git a/src/plugins/platforms/android/src/qandroidplatformmenu.h b/src/plugins/platforms/android/src/qandroidplatformmenu.h
new file mode 100644
index 0000000000..20236cb636
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformmenu.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDPLATFORMMENU_H
+#define QANDROIDPLATFORMMENU_H
+
+#include <qpa/qplatformmenu.h>
+#include <qvector.h>
+#include <qmutex.h>
+
+class QAndroidPlatformMenuItem;
+class QAndroidPlatformMenu: public QPlatformMenu
+{
+public:
+ typedef QVector<QAndroidPlatformMenuItem *> PlatformMenuItemsType;
+
+public:
+ QAndroidPlatformMenu();
+ ~QAndroidPlatformMenu();
+
+ void insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before);
+ void removeMenuItem(QPlatformMenuItem *menuItem);
+ void syncMenuItem(QPlatformMenuItem *menuItem);
+ void syncSeparatorsCollapsible(bool enable);
+
+ void setTag(quintptr tag);
+ quintptr tag() const;
+ void setText(const QString &text);
+ QString text() const;
+ void setIcon(const QIcon &icon);
+ QIcon icon() const;
+ void setEnabled(bool enabled);
+ bool isEnabled() const;
+ void setVisible(bool visible);
+ bool isVisible() const;
+
+ QPlatformMenuItem *menuItemAt(int position) const;
+ QPlatformMenuItem *menuItemForTag(quintptr tag) const;
+
+ PlatformMenuItemsType menuItems() const;
+ QMutex *menuItemsMutex();
+
+private:
+ PlatformMenuItemsType m_menuItems;
+ quintptr m_tag;
+ QString m_text;
+ QIcon m_icon;
+ bool m_enabled;
+ bool m_isVisible;
+ QMutex m_menuItemsMutex;
+};
+
+#endif // QANDROIDPLATFORMMENU_H
diff --git a/src/plugins/platforms/android/src/qandroidplatformmenubar.cpp b/src/plugins/platforms/android/src/qandroidplatformmenubar.cpp
new file mode 100644
index 0000000000..ef1ac61356
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformmenubar.cpp
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidplatformmenubar.h"
+#include "qandroidplatformmenu.h"
+#include "androidjnimenu.h"
+
+
+QAndroidPlatformMenuBar::QAndroidPlatformMenuBar()
+{
+ m_parentWindow = 0;
+ QtAndroidMenu::addMenuBar(this);
+}
+
+QAndroidPlatformMenuBar::~QAndroidPlatformMenuBar()
+{
+ QtAndroidMenu::removeMenuBar(this);
+}
+
+void QAndroidPlatformMenuBar::insertMenu(QPlatformMenu *menu, QPlatformMenu *before)
+{
+ QMutexLocker lock(&m_menusListMutex);
+ m_menus.insert(qFind(m_menus.begin(),
+ m_menus.end(),
+ static_cast<QAndroidPlatformMenu *>(before)),
+ static_cast<QAndroidPlatformMenu *>(menu));
+}
+
+void QAndroidPlatformMenuBar::removeMenu(QPlatformMenu *menu)
+{
+ QMutexLocker lock(&m_menusListMutex);
+ m_menus.erase(qFind(m_menus.begin(),
+ m_menus.end(),
+ static_cast<QAndroidPlatformMenu *>(menu)));
+}
+
+void QAndroidPlatformMenuBar::syncMenu(QPlatformMenu *menu)
+{
+ QtAndroidMenu::syncMenu(static_cast<QAndroidPlatformMenu *>(menu));
+}
+
+void QAndroidPlatformMenuBar::handleReparent(QWindow *newParentWindow)
+{
+ m_parentWindow = newParentWindow;
+ QtAndroidMenu::setMenuBar(this, newParentWindow);
+}
+
+QPlatformMenu *QAndroidPlatformMenuBar::menuForTag(quintptr tag) const
+{
+ foreach (QPlatformMenu *menu, m_menus) {
+ if (menu->tag() == tag)
+ return menu;
+ }
+
+ return 0;
+}
+
+QWindow *QAndroidPlatformMenuBar::parentWindow() const
+{
+ return m_parentWindow;
+}
+
+QAndroidPlatformMenuBar::PlatformMenusType QAndroidPlatformMenuBar::menus() const
+{
+ return m_menus;
+}
+
+QMutex *QAndroidPlatformMenuBar::menusListMutex()
+{
+ return &m_menusListMutex;
+}
diff --git a/src/plugins/platforms/android/src/qandroidplatformmenubar.h b/src/plugins/platforms/android/src/qandroidplatformmenubar.h
new file mode 100644
index 0000000000..56915335c2
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformmenubar.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDPLATFORMMENUBAR_H
+#define QANDROIDPLATFORMMENUBAR_H
+
+#include <qpa/qplatformmenu.h>
+#include <qvector.h>
+#include <qmutex.h>
+
+class QAndroidPlatformMenu;
+class QAndroidPlatformMenuBar: public QPlatformMenuBar
+{
+public:
+ typedef QVector<QAndroidPlatformMenu *> PlatformMenusType;
+public:
+ QAndroidPlatformMenuBar();
+ ~QAndroidPlatformMenuBar();
+
+ void insertMenu(QPlatformMenu *menu, QPlatformMenu *before);
+ void removeMenu(QPlatformMenu *menu);
+ void syncMenu(QPlatformMenu *menu);
+ void handleReparent(QWindow *newParentWindow);
+ QPlatformMenu *menuForTag(quintptr tag) const;
+
+ QWindow *parentWindow() const;
+ PlatformMenusType menus() const;
+ QMutex *menusListMutex();
+
+private:
+ PlatformMenusType m_menus;
+ QWindow *m_parentWindow;
+ QMutex m_menusListMutex;
+};
+
+#endif // QANDROIDPLATFORMMENUBAR_H
diff --git a/src/plugins/platforms/android/src/qandroidplatformmenuitem.cpp b/src/plugins/platforms/android/src/qandroidplatformmenuitem.cpp
new file mode 100644
index 0000000000..bd37834d2a
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformmenuitem.cpp
@@ -0,0 +1,180 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidplatformmenuitem.h"
+#include "qandroidplatformmenu.h"
+
+QAndroidPlatformMenuItem::QAndroidPlatformMenuItem()
+{
+ m_tag = reinterpret_cast<quintptr>(this); // QMenu will overwrite this later, but we need a unique ID for QtQuick
+ m_menu = 0;
+ m_isVisible = true;
+ m_isSeparator = false;
+ m_role = NoRole;
+ m_isCheckable = false;
+ m_isChecked = false;
+ m_isEnabled = true;
+}
+
+void QAndroidPlatformMenuItem::setTag(quintptr tag)
+{
+ m_tag = tag;
+}
+
+quintptr QAndroidPlatformMenuItem::tag() const
+{
+ return m_tag;
+}
+
+void QAndroidPlatformMenuItem::setText(const QString &text)
+{
+ m_text = text;
+ if (m_menu)
+ m_menu->setText(m_text);
+}
+
+QString QAndroidPlatformMenuItem::text() const
+{
+ return m_text;
+}
+
+void QAndroidPlatformMenuItem::setIcon(const QIcon &icon)
+{
+ m_icon = icon;
+ if (m_menu)
+ m_menu->setIcon(m_icon);
+}
+
+QIcon QAndroidPlatformMenuItem::icon() const
+{
+ return m_icon;
+}
+
+void QAndroidPlatformMenuItem::setMenu(QPlatformMenu *menu)
+{
+ m_menu = static_cast<QAndroidPlatformMenu *>(menu);
+ if (!m_menu)
+ return;
+
+ m_menu->setText(m_text);
+ m_menu->setIcon(m_icon);
+ m_menu->setVisible(m_isVisible);
+ m_menu->setEnabled(m_isEnabled);
+}
+
+QAndroidPlatformMenu *QAndroidPlatformMenuItem::menu() const
+{
+ return m_menu;
+}
+
+void QAndroidPlatformMenuItem::setVisible(bool isVisible)
+{
+ m_isVisible = isVisible;
+ if (m_menu)
+ m_menu->setVisible(m_isVisible);
+}
+
+bool QAndroidPlatformMenuItem::isVisible() const
+{
+ return m_isVisible;
+}
+
+void QAndroidPlatformMenuItem::setIsSeparator(bool isSeparator)
+{
+ m_isSeparator = isSeparator;
+}
+
+bool QAndroidPlatformMenuItem::isSeparator() const
+{
+ return m_isSeparator;
+}
+
+void QAndroidPlatformMenuItem::setFont(const QFont &font)
+{
+ Q_UNUSED(font)
+}
+
+void QAndroidPlatformMenuItem::setRole(QPlatformMenuItem::MenuRole role)
+{
+ m_role = role;
+}
+
+QPlatformMenuItem::MenuRole QAndroidPlatformMenuItem::role() const
+{
+ return m_role;
+}
+
+void QAndroidPlatformMenuItem::setCheckable(bool checkable)
+{
+ m_isCheckable = checkable;
+}
+
+bool QAndroidPlatformMenuItem::isCheckable() const
+{
+ return m_isCheckable;
+}
+
+void QAndroidPlatformMenuItem::setChecked(bool isChecked)
+{
+ m_isChecked = isChecked;
+}
+
+bool QAndroidPlatformMenuItem::isChecked() const
+{
+ return m_isChecked;
+}
+
+void QAndroidPlatformMenuItem::setShortcut(const QKeySequence &shortcut)
+{
+ Q_UNUSED(shortcut)
+}
+
+void QAndroidPlatformMenuItem::setEnabled(bool enabled)
+{
+ m_isEnabled = enabled;
+ if (m_menu)
+ m_menu->setEnabled(m_isEnabled);
+}
+
+bool QAndroidPlatformMenuItem::isEnabled() const
+{
+ return m_isEnabled;
+}
diff --git a/src/plugins/platforms/android/src/qandroidplatformmenuitem.h b/src/plugins/platforms/android/src/qandroidplatformmenuitem.h
new file mode 100644
index 0000000000..5861e8e195
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformmenuitem.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDPLATFORMMENUITEM_H
+#define QANDROIDPLATFORMMENUITEM_H
+#include <qpa/qplatformmenu.h>
+
+class QAndroidPlatformMenu;
+
+class QAndroidPlatformMenuItem: public QPlatformMenuItem
+{
+public:
+ QAndroidPlatformMenuItem();
+ void setTag(quintptr tag);
+ quintptr tag() const;
+
+ void setText(const QString &text);
+ QString text() const;
+
+ void setIcon(const QIcon &icon);
+ QIcon icon() const;
+
+ void setMenu(QPlatformMenu *menu);
+ QAndroidPlatformMenu *menu() const;
+
+ void setVisible(bool isVisible);
+ bool isVisible() const;
+
+ void setIsSeparator(bool isSeparator);
+ bool isSeparator() const;
+
+ void setFont(const QFont &font);
+
+ void setRole(MenuRole role);
+ MenuRole role() const;
+
+ void setCheckable(bool checkable);
+ bool isCheckable() const;
+
+ void setChecked(bool isChecked);
+ bool isChecked() const;
+
+ void setShortcut(const QKeySequence &shortcut);
+
+ void setEnabled(bool enabled);
+ bool isEnabled() const;
+
+private:
+ quintptr m_tag;
+ QString m_text;
+ QIcon m_icon;
+ QAndroidPlatformMenu *m_menu;
+ bool m_isVisible;
+ bool m_isSeparator;
+ MenuRole m_role;
+ bool m_isCheckable;
+ bool m_isChecked;
+ bool m_isEnabled;
+};
+
+#endif // QANDROIDPLATFORMMENUITEM_H
diff --git a/src/plugins/platforms/android/src/qandroidplatformservices.cpp b/src/plugins/platforms/android/src/qandroidplatformservices.cpp
new file mode 100644
index 0000000000..841a9d4d51
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformservices.cpp
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidplatformservices.h"
+#include <QUrl>
+#include <QDir>
+#include <QDebug>
+
+QAndroidPlatformServices::QAndroidPlatformServices()
+{
+ JNIEnv *env;
+ if (QtAndroid::javaVM()->AttachCurrentThread(&env, NULL) < 0) {
+ qCritical() << "AttachCurrentThread failed";
+ return;
+ }
+
+ m_openURIMethodID = env->GetStaticMethodID(QtAndroid::applicationClass(),
+ "openURL",
+ "(Ljava/lang/String;)V");
+}
+
+bool QAndroidPlatformServices::openUrl(const QUrl &url)
+{
+ JNIEnv *env;
+ if (QtAndroid::javaVM()->AttachCurrentThread(&env, NULL) < 0) {
+ qCritical() << "AttachCurrentThread failed";
+ return false;
+ }
+
+ jstring string = env->NewString(reinterpret_cast<const jchar *>(url.toString().constData()),
+ url.toString().length());
+ env->CallStaticVoidMethod(QtAndroid::applicationClass(), m_openURIMethodID, string);
+ env->DeleteLocalRef(string);
+ return true;
+}
+
+bool QAndroidPlatformServices::openDocument(const QUrl &url)
+{
+ return openUrl(url);
+}
+
+QByteArray QAndroidPlatformServices::desktopEnvironment() const
+{
+ return QByteArray("Android");
+}
diff --git a/src/plugins/platforms/android/src/qandroidplatformservices.h b/src/plugins/platforms/android/src/qandroidplatformservices.h
new file mode 100644
index 0000000000..8368b19043
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformservices.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ANDROIDPLATFORMDESKTOPSERVICE_H
+#define ANDROIDPLATFORMDESKTOPSERVICE_H
+
+#include <qpa/qplatformservices.h>
+#include "androidjnimain.h"
+#include <jni.h>
+
+class QAndroidPlatformServices: public QPlatformServices
+{
+public:
+ QAndroidPlatformServices();
+ bool openUrl(const QUrl &url);
+ bool openDocument(const QUrl &url);
+ QByteArray desktopEnvironment() const;
+private:
+ jmethodID m_openURIMethodID;
+
+};
+
+#endif // ANDROIDPLATFORMDESKTOPSERVICE_H
diff --git a/src/plugins/platforms/android/src/qandroidplatformtheme.cpp b/src/plugins/platforms/android/src/qandroidplatformtheme.cpp
new file mode 100644
index 0000000000..25f2ade11a
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformtheme.cpp
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidplatformtheme.h"
+#include "qandroidplatformmenubar.h"
+#include "qandroidplatformmenu.h"
+#include "qandroidplatformmenuitem.h"
+#include <QVariant>
+#include <QFileInfo>
+
+QPlatformMenuBar *QAndroidPlatformTheme::createPlatformMenuBar() const
+{
+ return new QAndroidPlatformMenuBar;
+}
+
+QPlatformMenu *QAndroidPlatformTheme::createPlatformMenu() const
+{
+ return new QAndroidPlatformMenu;
+}
+
+QPlatformMenuItem *QAndroidPlatformTheme::createPlatformMenuItem() const
+{
+ return new QAndroidPlatformMenuItem;
+}
+
+QVariant QAndroidPlatformTheme::themeHint(ThemeHint hint) const
+{
+ switch (hint) {
+ case StyleNames:
+ if (qgetenv("QT_USE_ANDROID_NATIVE_STYLE").toInt()
+ && (!qgetenv("MINISTRO_ANDROID_STYLE_PATH").isEmpty()
+ || QFileInfo("/data/data/org.kde.necessitas.ministro/files/qt/style/style.json").exists())) {
+ return QStringList("android");
+ }
+ return QStringList("fusion");
+ break;
+ default:
+ return QPlatformTheme::themeHint(hint);
+ }
+}
diff --git a/src/plugins/platforms/android/src/qandroidplatformtheme.h b/src/plugins/platforms/android/src/qandroidplatformtheme.h
new file mode 100644
index 0000000000..263878ee16
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformtheme.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDPLATFORMTHEME_H
+#define QANDROIDPLATFORMTHEME_H
+
+#include <qpa/qplatformtheme.h>
+
+class QAndroidPlatformTheme: public QPlatformTheme
+{
+public:
+ virtual QPlatformMenuBar *createPlatformMenuBar() const;
+ virtual QPlatformMenu *createPlatformMenu() const;
+ virtual QPlatformMenuItem *createPlatformMenuItem() const;
+ virtual QVariant themeHint(ThemeHint hint) const;
+};
+
+#endif // QANDROIDPLATFORMTHEME_H
diff --git a/src/plugins/platforms/android/src/raster/qandroidplatformscreen.cpp b/src/plugins/platforms/android/src/raster/qandroidplatformscreen.cpp
new file mode 100644
index 0000000000..2779d7cffd
--- /dev/null
+++ b/src/plugins/platforms/android/src/raster/qandroidplatformscreen.cpp
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidplatformscreen.h"
+#include "qandroidplatformintegration.h"
+#include "androidjnimain.h"
+#include "androidjnimenu.h"
+
+QAndroidPlatformScreen::QAndroidPlatformScreen():QFbScreen()
+{
+ mGeometry = QRect(0, 0, QAndroidPlatformIntegration::m_defaultGeometryWidth, QAndroidPlatformIntegration::m_defaultGeometryHeight);
+ mFormat = QImage::Format_RGB16;
+ mDepth = 16;
+ mPhysicalSize.setHeight(QAndroidPlatformIntegration::m_defaultPhysicalSizeHeight);
+ mPhysicalSize.setWidth(QAndroidPlatformIntegration::m_defaultPhysicalSizeWidth);
+ initializeCompositor();
+}
+
+void QAndroidPlatformScreen::topWindowChanged(QWindow *w)
+{
+ QtAndroidMenu::setActiveTopLevelWindow(w);
+}
+
+QRegion QAndroidPlatformScreen::doRedraw()
+{
+ QRegion touched;
+ touched = QFbScreen::doRedraw();
+ if (touched.isEmpty())
+ return touched;
+
+ QtAndroid::flushImage(mGeometry.topLeft(), *mScreenImage, touched.boundingRect());
+ return touched;
+}
diff --git a/src/plugins/platforms/android/src/raster/qandroidplatformscreen.h b/src/plugins/platforms/android/src/raster/qandroidplatformscreen.h
new file mode 100644
index 0000000000..df08e43af4
--- /dev/null
+++ b/src/plugins/platforms/android/src/raster/qandroidplatformscreen.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDPLATFORMSCREEN_H
+#define QANDROIDPLATFORMSCREEN_H
+
+#include <QtPlatformSupport/private/qfbscreen_p.h>
+
+class QAndroidPlatformScreen: public QFbScreen
+{
+ Q_OBJECT
+public:
+ QAndroidPlatformScreen();
+ void topWindowChanged(QWindow *w);
+
+public slots:
+ QRegion doRedraw();
+
+};
+
+#endif
diff --git a/src/plugins/platforms/android/src/raster/qandroidplatformwindow.cpp b/src/plugins/platforms/android/src/raster/qandroidplatformwindow.cpp
new file mode 100644
index 0000000000..94a69c10c7
--- /dev/null
+++ b/src/plugins/platforms/android/src/raster/qandroidplatformwindow.cpp
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidplatformwindow.h"
+
+QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window) : QFbWindow(window)
+{
+}
+
+void QAndroidPlatformWindow::setGeometry(const QRect &rect)
+{
+ QFbWindow::setGeometry(rect);
+}
+
+void QAndroidPlatformWindow::propagateSizeHints()
+{
+ //shut up warning from default implementation
+}
diff --git a/src/plugins/platforms/android/src/raster/qandroidplatformwindow.h b/src/plugins/platforms/android/src/raster/qandroidplatformwindow.h
new file mode 100644
index 0000000000..3ee815fd69
--- /dev/null
+++ b/src/plugins/platforms/android/src/raster/qandroidplatformwindow.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ANDROIDPLATFORMWINDOW_H
+#define ANDROIDPLATFORMWINDOW_H
+#include <qobject.h>
+#include <QtPlatformSupport/private/qfbwindow_p.h>
+
+class QAndroidPlatformWindow: public QObject, public QFbWindow
+{
+ Q_OBJECT
+public:
+ explicit QAndroidPlatformWindow(QWindow *window);
+
+ void propagateSizeHints();
+
+public slots:
+ void setGeometry(const QRect &rect);
+
+};
+
+#endif // ANDROIDPLATFORMWINDOW_H
diff --git a/src/plugins/platforms/android/src/raster/raster.pri b/src/plugins/platforms/android/src/raster/raster.pri
new file mode 100644
index 0000000000..86e5aa235f
--- /dev/null
+++ b/src/plugins/platforms/android/src/raster/raster.pri
@@ -0,0 +1,7 @@
+INCLUDEPATH += $$PWD
+
+SOURCES += $$PWD/qandroidplatformscreen.cpp \
+ $$PWD/qandroidplatformwindow.cpp
+
+HEADERS += $$PWD/qandroidplatformscreen.h \
+ $$PWD/qandroidplatformwindow.h
diff --git a/src/plugins/platforms/android/src/src.pri b/src/plugins/platforms/android/src/src.pri
new file mode 100644
index 0000000000..76539b50ab
--- /dev/null
+++ b/src/plugins/platforms/android/src/src.pri
@@ -0,0 +1,47 @@
+load(qt_plugin)
+
+QT += core-private gui-private platformsupport-private
+
+CONFIG += qpa/genericunixfontdatabase
+
+OTHER_FILES += $$PWD/android.json
+
+INCLUDEPATH += $$PWD
+INCLUDEPATH += $$PWD/../../../../3rdparty/android/src
+
+SOURCES += $$PWD/androidplatformplugin.cpp \
+ $$PWD/androidjnimain.cpp \
+ $$PWD/androidjniinput.cpp \
+ $$PWD/androidjnimenu.cpp \
+ $$PWD/androidjniclipboard.cpp \
+ $$PWD/qandroidplatformintegration.cpp \
+ $$PWD/qandroidplatformservices.cpp \
+ $$PWD/qandroidassetsfileenginehandler.cpp \
+ $$PWD/qandroidinputcontext.cpp \
+ $$PWD/qandroidplatformfontdatabase.cpp \
+ $$PWD/qandroidplatformclipboard.cpp \
+ $$PWD/qandroidplatformtheme.cpp \
+ $$PWD/qandroidplatformmenubar.cpp \
+ $$PWD/qandroidplatformmenu.cpp \
+ $$PWD/qandroidplatformmenuitem.cpp
+
+
+HEADERS += $$PWD/qandroidplatformintegration.h \
+ $$PWD/androidjnimain.h \
+ $$PWD/androidjniinput.h \
+ $$PWD/androidjnimenu.h \
+ $$PWD/androidjniclipboard.h \
+ $$PWD/qandroidplatformservices.h \
+ $$PWD/qandroidassetsfileenginehandler.h \
+ $$PWD/qandroidinputcontext.h \
+ $$PWD/qandroidplatformfontdatabase.h \
+ $$PWD/qandroidplatformclipboard.h \
+ $$PWD/qandroidplatformtheme.h \
+ $$PWD/qandroidplatformmenubar.h \
+ $$PWD/qandroidplatformmenu.h \
+ $$PWD/qandroidplatformmenuitem.h
+
+
+#Non-standard install directory, QTBUG-29859
+DESTDIR = $$DESTDIR/android
+target.path = $${target.path}/android
diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro
index 83e2a88e6a..66c4e3c49c 100644
--- a/src/plugins/platforms/cocoa/cocoa.pro
+++ b/src/plugins/platforms/cocoa/cocoa.pro
@@ -78,7 +78,7 @@ HEADERS += qcocoaintegration.h \
RESOURCES += qcocoaresources.qrc
-LIBS += -framework Cocoa -framework IOKit
+LIBS += -framework Cocoa -framework Carbon -framework IOKit
QT += core-private gui-private platformsupport-private
@@ -102,8 +102,5 @@ OTHER_FILES += cocoa.json
# DEFINES += QT_COCOA_ENABLE_ACCESSIBILITY_INSPECTOR
# include ($$PWD/../../../../util/accessibilityinspector/accessibilityinspector.pri)
-# Accessibility is currently unstable and disabled.
-DEFINES += QT_NO_COCOA_ACCESSIBILITY
-
# Window debug support
#DEFINES += QT_COCOA_ENABLE_WINDOW_DEBUG
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.h b/src/plugins/platforms/cocoa/qcocoaaccessibility.h
index 0f1f96814f..3f0367d36a 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibility.h
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.h
@@ -44,9 +44,6 @@
#include <Cocoa/Cocoa.h>
#include <QtGui>
-
-#ifndef QT_NO_COCOA_ACCESSIBILITY
-
#include <qpa/qplatformaccessibility.h>
class QCococaAccessibility : public QPlatformAccessibility
@@ -81,7 +78,7 @@ namespace QCocoaAccessible {
*/
NSString *macRole(QAccessibleInterface *interface);
-bool shouldBeIgnrored(QAccessibleInterface *interface);
+bool shouldBeIgnored(QAccessibleInterface *interface);
NSString *getTranslatedAction(const QString &qtAction);
NSMutableArray *createTranslatedActionsList(const QStringList &qtActions);
QString translateAction(NSString *nsAction);
@@ -90,6 +87,4 @@ id getValueAttribute(QAccessibleInterface *interface);
}
-#endif // QT_NO_COCOA_ACCESSIBILITY
-
#endif
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
index 070f23f028..34192e85b0 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
@@ -41,11 +41,9 @@
#include "qcocoaaccessibility.h"
#include "qcocoaaccessibilityelement.h"
#include <qaccessible.h>
-#include <qaccessible2.h>
+#include <QtGui/private/qaccessible2_p.h>
#include <private/qcore_mac_p.h>
-#ifndef QT_NO_COCOA_ACCESSIBILITY
-
QCococaAccessibility::QCococaAccessibility()
{
@@ -62,7 +60,7 @@ void QCococaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
if (!object)
return;
- QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(object);
+ QAccessibleInterface *interface = event->accessibleInterface();
if (!interface)
return;
@@ -71,13 +69,11 @@ void QCococaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
case QAccessible::TextInserted :
case QAccessible::TextRemoved :
case QAccessible::TextUpdated : {
- QCocoaAccessibleElement *element = [QCocoaAccessibleElement createElementWithInterface : interface parent : nil];
+ QCocoaAccessibleElement *element = [QCocoaAccessibleElement createElementWithId : QAccessible::uniqueId(interface) parent : nil];
[element autorelease];
NSAccessibilityPostNotification(element, NSAccessibilityValueChangedNotification);
break; }
-
- default:
- delete interface;
+ default:
break;
}
}
@@ -178,7 +174,7 @@ NSString *macRole(QAccessibleInterface *interface)
the elements are still present in the accessibility tree but is
not used by the screen reader.
*/
-bool shouldBeIgnrored(QAccessibleInterface *interface)
+bool shouldBeIgnored(QAccessibleInterface *interface)
{
// Mac accessibility does not have an attribute that corresponds to the Invisible/Offscreen
// state. Ignore interfaces with those flags set.
@@ -280,6 +276,7 @@ QString translateAction(NSString *nsAction)
bool hasValueAttribute(QAccessibleInterface *interface)
{
+ Q_ASSERT(interface);
const QAccessible::Role qtrole = interface->role();
if (qtrole == QAccessible::EditableText
|| interface->valueInterface()) {
@@ -318,5 +315,3 @@ id getValueAttribute(QAccessibleInterface *interface)
}
} // namespace QCocoaAccessible
-
-#endif // QT_NO_COCOA_ACCESSIBILITY
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h
index 7ebe7a4e9d..c207cbee2d 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h
@@ -41,26 +41,25 @@
#ifndef QCOCOAACCESIBILITYELEMENT_H
#define QCOCOAACCESIBILITYELEMENT_H
+#include <QtCore/qglobal.h>
#import <Cocoa/Cocoa.h>
#import <AppKit/NSAccessibility.h>
-#ifndef QT_NO_COCOA_ACCESSIBILITY
+#import <qaccessible.h>
@class QCocoaAccessibleElement;
@interface QCocoaAccessibleElement : NSObject {
NSString *role;
- NSObject * parent;
- void *accessibleInterface;
+ NSObject *parent;
+ QAccessible::Id axid;
}
-- (id)initWithInterface:(void *)anQAccessibleInterface parent:(id)aParent;
-+ (QCocoaAccessibleElement *)createElementWithInterface:(void *)anQAccessibleInterface parent:(id)aParent;
+- (id)initWithId:(QAccessible::Id)anId parent:(id)aParent;
++ (QCocoaAccessibleElement *)createElementWithId:(QAccessible::Id)anId parent:(id)aParent;
@end
-#endif // QT_NO_COCOA_ACCESSIBILITY
-
#endif
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
index f5f37c5b00..1d6797e51a 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
@@ -43,52 +43,47 @@
#include "qcocoahelpers.h"
#include <QAccessible>
-#include "QAccessibleActionInterface"
+#include <QtGui/private/qaccessible2_p.h>
#import <AppKit/NSAccessibility.h>
-#ifndef QT_NO_COCOA_ACCESSIBILITY
-
-static QAccessibleInterface *acast(void *ptr)
-{
- return reinterpret_cast<QAccessibleInterface *>(ptr);
-}
-
@implementation QCocoaAccessibleElement
-- (id)initWithInterface:(void *)anQAccessibleInterface parent:(id)aParent
+- (id)initWithId:(QAccessible::Id)anId parent:(id)aParent
{
+ Q_ASSERT((int)anId < 0);
self = [super init];
if (self) {
- accessibleInterface = anQAccessibleInterface;
- role = QCocoaAccessible::macRole(acast(accessibleInterface));
+ axid = anId;
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
+ Q_ASSERT(iface);
+ role = QCocoaAccessible::macRole(iface);
parent = aParent;
}
return self;
}
-+ (QCocoaAccessibleElement *)createElementWithInterface:(void *)anQAccessibleInterface parent:(id)aParent
++ (QCocoaAccessibleElement *)createElementWithId:(QAccessible::Id)anId parent:(id)aParent
{
- return [[self alloc] initWithInterface:anQAccessibleInterface parent:aParent];
+ return [[self alloc] initWithId:anId parent:aParent];
}
- (void)dealloc {
[super dealloc];
- delete acast(accessibleInterface);
}
- (BOOL)isEqual:(id)object {
if ([object isKindOfClass:[QCocoaAccessibleElement class]]) {
QCocoaAccessibleElement *other = object;
- return acast(other->accessibleInterface)->object() == acast(accessibleInterface)->object();
+ return other->axid == axid;
} else {
return NO;
}
}
- (NSUInteger)hash {
- return qHash(acast(accessibleInterface)->object());
+ return axid;
}
//
@@ -99,6 +94,11 @@ static QAccessibleInterface *acast(void *ptr)
- (NSArray *)accessibilityAttributeNames {
static NSArray *defaultAttributes = nil;
+
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
+ if (!iface)
+ return defaultAttributes;
+
if (defaultAttributes == nil) {
defaultAttributes = [[NSArray alloc] initWithObjects:
NSAccessibilityRoleAttribute,
@@ -118,7 +118,7 @@ static QAccessibleInterface *acast(void *ptr)
NSMutableArray *attributes = [[NSMutableArray alloc] initWithCapacity : [defaultAttributes count]];
[attributes addObjectsFromArray : defaultAttributes];
- if (QCocoaAccessible::hasValueAttribute(acast(accessibleInterface))) {
+ if (QCocoaAccessible::hasValueAttribute(iface)) {
[attributes addObject : NSAccessibilityValueAttribute];
}
@@ -126,22 +126,33 @@ static QAccessibleInterface *acast(void *ptr)
}
- (id)accessibilityAttributeValue:(NSString *)attribute {
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
+ if (!iface) {
+ qWarning() << "Called attribute on invalid object: " << axid;
+ return nil;
+ }
+
if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) {
return role;
} else if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) {
return NSAccessibilityRoleDescription(role, nil);
} else if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
- int numKids = acast(accessibleInterface)->childCount();
+
+ int numKids = iface->childCount();
+ // qDebug() << "Children for: " << axid << iface << " are: " << numKids;
NSMutableArray *kids = [NSMutableArray arrayWithCapacity:numKids];
for (int i = 0; i < numKids; ++i) {
- QAccessibleInterface *childInterface = acast(accessibleInterface)->child(i);
- QCocoaAccessibleElement *element = [QCocoaAccessibleElement createElementWithInterface:(void*)childInterface parent:self];
+ QAccessibleInterface *child = iface->child(i);
+ Q_ASSERT(child);
+ QAccessible::Id childId = QAccessible::uniqueId(child);
+ //qDebug() << " kid: " << childId << child;
+ QCocoaAccessibleElement *element = [QCocoaAccessibleElement createElementWithId:childId parent:self];
[kids addObject: element];
[element release];
}
-
return kids;
+
} else if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
// Just check if the app thinks we're focused.
id focusedElement = [NSApp accessibilityAttributeValue:NSAccessibilityFocusedUIElementAttribute];
@@ -155,23 +166,23 @@ static QAccessibleInterface *acast(void *ptr)
// We're in the same top level element as our parent.
return [parent accessibilityAttributeValue:NSAccessibilityTopLevelUIElementAttribute];
} else if ([attribute isEqualToString:NSAccessibilityPositionAttribute]) {
- QPoint qtPosition = acast(accessibleInterface)->rect().topLeft();
- QSize qtSize = acast(accessibleInterface)->rect().size();
+ QPoint qtPosition = iface->rect().topLeft();
+ QSize qtSize = iface->rect().size();
return [NSValue valueWithPoint: NSMakePoint(qtPosition.x(), qt_mac_flipYCoordinate(qtPosition.y() + qtSize.height()))];
} else if ([attribute isEqualToString:NSAccessibilitySizeAttribute]) {
- QSize qtSize = acast(accessibleInterface)->rect().size();
+ QSize qtSize = iface->rect().size();
return [NSValue valueWithSize: NSMakeSize(qtSize.width(), qtSize.height())];
} else if ([attribute isEqualToString:NSAccessibilityDescriptionAttribute]) {
- return QCFString::toNSString(acast(accessibleInterface)->text(QAccessible::Name));
+ return QCFString::toNSString(iface->text(QAccessible::Name));
} else if ([attribute isEqualToString:NSAccessibilityEnabledAttribute]) {
- return [NSNumber numberWithBool:!acast(accessibleInterface)->state().disabled];
+ return [NSNumber numberWithBool:!iface->state().disabled];
} else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
// VoiceOver asks for the value attribute for all elements. Return nil
// if we don't want the element to have a value attribute.
- if (!QCocoaAccessible::hasValueAttribute(acast(accessibleInterface)))
+ if (!QCocoaAccessible::hasValueAttribute(iface))
return nil;
- return QCocoaAccessible::getValueAttribute(acast(accessibleInterface));
+ return QCocoaAccessible::getValueAttribute(iface);
}
return nil;
@@ -196,8 +207,11 @@ static QAccessibleInterface *acast(void *ptr)
- (NSArray *)accessibilityActionNames {
NSMutableArray * nsActions = [NSMutableArray new];
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
+ if (!iface)
+ return nsActions;
- QAccessibleActionInterface *actionInterface = acast(accessibleInterface)->actionInterface();
+ QAccessibleActionInterface *actionInterface = iface->actionInterface();
if (actionInterface) {
QStringList supportedActionNames = actionInterface->actionNames();
@@ -212,48 +226,58 @@ static QAccessibleInterface *acast(void *ptr)
}
- (NSString *)accessibilityActionDescription:(NSString *)action {
- QAccessibleActionInterface *actionInterface = acast(accessibleInterface)->actionInterface();
- QString qtAction = QCocoaAccessible::translateAction(action);
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
+ if (!iface)
+ return nil; // FIXME is that the right return type??
+ QAccessibleActionInterface *actionInterface = iface->actionInterface();
+ if (actionInterface) {
+ QString qtAction = QCocoaAccessible::translateAction(action);
- // Return a description from the action interface if this action is not known to the OS.
- if (qtAction.isEmpty()) {
- QString description = actionInterface->localizedActionDescription(qtAction);
- return QCFString::toNSString(description);
+ // Return a description from the action interface if this action is not known to the OS.
+ if (qtAction.isEmpty()) {
+ QString description = actionInterface->localizedActionDescription(qtAction);
+ return QCFString::toNSString(description);
+ }
}
return NSAccessibilityActionDescription(action);
}
- (void)accessibilityPerformAction:(NSString *)action {
- QAccessibleActionInterface *actionInterface = acast(accessibleInterface)->actionInterface();
- if (actionInterface) {
- actionInterface->doAction(QCocoaAccessible::translateAction(action));
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
+ if (iface) {
+ QAccessibleActionInterface *actionInterface = iface->actionInterface();
+ if (actionInterface) {
+ actionInterface->doAction(QCocoaAccessible::translateAction(action));
+ }
}
}
// misc
- (BOOL)accessibilityIsIgnored {
- return QCocoaAccessible::shouldBeIgnrored(acast(accessibleInterface));
+ return false; //QCocoaAccessible::shouldBeIgnored(QAccessible::accessibleInterface(id));
}
- (id)accessibilityHitTest:(NSPoint)point {
-
- if (!accessibleInterface)
- return NSAccessibilityUnignoredAncestor(self);
-
- if (!acast(accessibleInterface)->isValid())
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
+ if (!iface || !iface->isValid()) {
+// qDebug() << "Hit test: INVALID";
return NSAccessibilityUnignoredAncestor(self);
+ }
- QAccessibleInterface *childInterface = acast(accessibleInterface)->childAt(point.x, qt_mac_flipYCoordinate(point.y));
+ QAccessibleInterface *childInterface = iface->childAt(point.x, qt_mac_flipYCoordinate(point.y));
// No child found, meaning we hit this element.
if (!childInterface) {
- return NSAccessibilityUnignoredAncestor(self);
+// qDebug() << "Hit test returns: " << id << iface;
+ return self;
+ //return NSAccessibilityUnignoredAncestor(self);
}
+ QAccessible::Id childId = QAccessible::uniqueId(childInterface);
// hit a child, forward to child accessible interface.
- QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement createElementWithInterface:childInterface parent:self];
+ QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement createElementWithId:childId parent:self];
[accessibleElement autorelease];
return [accessibleElement accessibilityHitTest:point];
@@ -264,6 +288,3 @@ static QAccessibleInterface *acast(void *ptr)
}
@end
-
-#endif // QT_NO_COCOA_ACCESSIBILITY
-
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h
index 6dd7ea2fb3..e44b2d1b6d 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h
@@ -93,19 +93,6 @@
@class QT_MANGLE_NAMESPACE(QCocoaMenuLoader);
-#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5
-
-@protocol NSApplicationDelegate <NSObject>
-- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
-- (void)applicationDidFinishLaunching:(NSNotification *)aNotification;
-- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames;
-- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender;
-- (void)applicationDidBecomeActive:(NSNotification *)notification;
-- (void)applicationDidResignActive:(NSNotification *)notification;
-@end
-
-#endif
-
@interface QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) : NSObject <NSApplicationDelegate> {
bool startedQuit;
NSMenu *dockMenu;
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
index e756c375f3..f676d613bc 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
@@ -145,8 +145,9 @@ static void cleanupCocoaApplicationDelegate()
dockMenu = newMenu;
}
-- (NSMenu *)applicationDockMenu
+- (NSMenu *)applicationDockMenu:(NSApplication *)sender
{
+ Q_UNUSED(sender);
return [[dockMenu retain] autorelease];
}
@@ -206,7 +207,6 @@ static void cleanupCocoaApplicationDelegate()
// events while the event loop is still running.
const QWindowList topLevels = QGuiApplication::topLevelWindows();
for (int i = 0; i < topLevels.size(); ++i) {
- QWindow *window = topLevels.at(i);
topLevels.at(i)->close();
}
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
index 7f022da4c3..4881dcef71 100644
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
@@ -73,7 +73,9 @@ QPaintDevice *QCocoaBackingStore::paintDevice()
}
#endif
- m_qImage = QImage(m_requestedSize * scaleFactor, QImage::Format_ARGB32_Premultiplied);
+ QImage::Format format = window()->format().hasAlpha()
+ ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32;
+ m_qImage = QImage(m_requestedSize * scaleFactor, format);
m_qImage.setDevicePixelRatio(scaleFactor);
}
return &m_qImage;
@@ -90,8 +92,10 @@ void QCocoaBackingStore::flush(QWindow *win, const QRegion &region, const QPoint
// m_cgImage is only a reference to the data inside m_qImage, it is not a copy.
CGImageRelease(m_cgImage);
m_cgImage = 0;
- if (QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(win->handle()))
- [cocoaWindow->m_contentView flushBackingStore:this region:region offset:offset];
+ if (!m_qImage.isNull()) {
+ if (QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(win->handle()))
+ [cocoaWindow->m_qtView flushBackingStore:this region:region offset:offset];
+ }
}
void QCocoaBackingStore::resize(const QSize &size, const QRegion &)
diff --git a/src/plugins/platforms/cocoa/qcocoacursor.mm b/src/plugins/platforms/cocoa/qcocoacursor.mm
index a36a855bcd..12808b7041 100644
--- a/src/plugins/platforms/cocoa/qcocoacursor.mm
+++ b/src/plugins/platforms/cocoa/qcocoacursor.mm
@@ -65,8 +65,9 @@ void QCocoaCursor::changeCursor(QCursor *cursor, QWindow *window)
{
Q_UNUSED(window);
+ const Qt::CursorShape newShape = cursor ? cursor->shape() : Qt::ArrowCursor;
// Check for a suitable built-in NSCursor first:
- switch (cursor->shape()) {
+ switch (newShape) {
case Qt::ArrowCursor:
[[NSCursor arrowCursor] set];
break;
@@ -104,7 +105,7 @@ void QCocoaCursor::changeCursor(QCursor *cursor, QWindow *window)
default : {
// No suitable OS cursor exist, use cursors provided
// by Qt for the rest. Check for a cached cursor:
- NSCursor *cocoaCursor = m_cursors.value(cursor->shape());
+ NSCursor *cocoaCursor = m_cursors.value(newShape);
if (cocoaCursor && cursor->shape() == Qt::BitmapCursor) {
[cocoaCursor release];
cocoaCursor = 0;
@@ -115,7 +116,7 @@ void QCocoaCursor::changeCursor(QCursor *cursor, QWindow *window)
[[NSCursor arrowCursor] set];
return;
}
- m_cursors.insert(cursor->shape(), cocoaCursor);
+ m_cursors.insert(newShape, cocoaCursor);
}
[cocoaCursor set];
diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
index f63ac0d205..93476ee1b4 100644
--- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
+++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
@@ -93,6 +93,7 @@
#include <QtGui/qwindowdefs.h>
#include <QtCore/private/qabstracteventdispatcher_p.h>
#include <QtCore/private/qtimerinfo_unix_p.h>
+#include <QtPlatformSupport/private/qcfsocketnotifier_p.h>
#include <CoreFoundation/CoreFoundation.h>
@@ -132,16 +133,9 @@ public:
void wakeUp();
void interrupt();
void flush();
-};
-struct MacSocketInfo {
- MacSocketInfo() : socket(0), runloop(0), readNotifier(0), writeNotifier(0) {}
- CFSocketRef socket;
- CFRunLoopSourceRef runloop;
- QObject *readNotifier;
- QObject *writeNotifier;
+ friend void qt_mac_maybeCancelWaitForMoreEventsForwarder(QAbstractEventDispatcher *eventDispatcher);
};
-typedef QHash<int, MacSocketInfo *> MacSocketHash;
class QCocoaEventDispatcherPrivate : public QAbstractEventDispatcherPrivate
{
@@ -183,7 +177,7 @@ public:
void maybeCancelWaitForMoreEvents();
void ensureNSAppInitialized();
- MacSocketHash macSockets;
+ QCFSocketNotifier cfSocketNotifier;
QList<void *> queuedUserInputEvents; // NSEvent *
CFRunLoopSourceRef postedEventsSource;
CFRunLoopObserverRef waitingObserver;
diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
index a0734530c5..5c487b0bdd 100644
--- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
+++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
@@ -149,10 +149,10 @@ void QCocoaEventDispatcherPrivate::maybeStartCFRunLoopTimer()
CFTimeInterval oneyear = CFTimeInterval(3600. * 24. * 365.);
// Q: when should the CFRunLoopTimer fire for the first time?
- struct timeval tv;
+ struct timespec tv;
if (timerInfoList.timerWait(tv)) {
// A: when we have timers to fire, of course
- interval = qMax(tv.tv_sec + tv.tv_usec / 1000000., 0.0000001);
+ interval = qMax(tv.tv_sec + tv.tv_nsec / 1000000000., 0.0000001);
} else {
// this shouldn't really happen, but in case it does, set the timer to fire a some point in the distant future
interval = oneyear;
@@ -172,10 +172,10 @@ void QCocoaEventDispatcherPrivate::maybeStartCFRunLoopTimer()
CFTimeInterval interval;
// Q: when should the timer first next?
- struct timeval tv;
+ struct timespec tv;
if (timerInfoList.timerWait(tv)) {
// A: when we have timers to fire, of course
- interval = qMax(tv.tv_sec + tv.tv_usec / 1000000., 0.0000001);
+ interval = qMax(tv.tv_sec + tv.tv_nsec / 1000000000., 0.0000001);
} else {
// no timers can fire, but we cannot stop the CFRunLoopTimer, set the timer to fire at some
// point in the distant future (the timer interval is one year)
@@ -270,58 +270,6 @@ QCocoaEventDispatcher::registeredTimers(QObject *object) const
return d->timerInfoList.registeredTimers(object);
}
-/**************************************************************************
- Socket Notifiers
- *************************************************************************/
-void qt_mac_socket_callback(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef,
- const void *, void *info) {
- QCocoaEventDispatcherPrivate *const eventDispatcher
- = static_cast<QCocoaEventDispatcherPrivate *>(info);
- int nativeSocket = CFSocketGetNative(s);
- MacSocketInfo *socketInfo = eventDispatcher->macSockets.value(nativeSocket);
- QEvent notifierEvent(QEvent::SockAct);
-
- // There is a race condition that happen where we disable the notifier and
- // the kernel still has a notification to pass on. We then get this
- // notification after we've successfully disabled the CFSocket, but our Qt
- // notifier is now gone. The upshot is we have to check the notifier
- // everytime.
- if (callbackType == kCFSocketReadCallBack) {
- if (socketInfo->readNotifier)
- QGuiApplication::sendEvent(socketInfo->readNotifier, &notifierEvent);
- } else if (callbackType == kCFSocketWriteCallBack) {
- if (socketInfo->writeNotifier)
- QGuiApplication::sendEvent(socketInfo->writeNotifier, &notifierEvent);
- }
-
- eventDispatcher->maybeCancelWaitForMoreEvents();
-}
-
-/*
- Adds a loop source for the given socket to the current run loop.
-*/
-CFRunLoopSourceRef qt_mac_add_socket_to_runloop(const CFSocketRef socket)
-{
- CFRunLoopSourceRef loopSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket, 0);
- if (!loopSource)
- return 0;
-
- CFRunLoopAddSource(mainRunLoop(), loopSource, kCFRunLoopCommonModes);
- return loopSource;
-}
-
-/*
- Removes the loop source for the given socket from the current run loop.
-*/
-void qt_mac_remove_socket_from_runloop(const CFSocketRef socket, CFRunLoopSourceRef runloop)
-{
- Q_ASSERT(runloop);
- CFRunLoopRemoveSource(mainRunLoop(), runloop, kCFRunLoopCommonModes);
- CFSocketDisableCallBacks(socket, kCFSocketReadCallBack);
- CFSocketDisableCallBacks(socket, kCFSocketWriteCallBack);
- CFRunLoopSourceInvalidate(runloop);
-}
-
/*
Register a QSocketNotifier with the mac event system by creating a CFSocket with
with a read/write callback.
@@ -331,130 +279,14 @@ void qt_mac_remove_socket_from_runloop(const CFSocketRef socket, CFRunLoopSource
*/
void QCocoaEventDispatcher::registerSocketNotifier(QSocketNotifier *notifier)
{
- Q_ASSERT(notifier);
- int nativeSocket = notifier->socket();
- int type = notifier->type();
-#ifndef QT_NO_DEBUG
- if (nativeSocket < 0 || nativeSocket > FD_SETSIZE) {
- qWarning("QSocketNotifier: Internal error");
- return;
- } else if (notifier->thread() != thread()
- || thread() != QThread::currentThread()) {
- qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread");
- return;
- }
-#endif
-
Q_D(QCocoaEventDispatcher);
-
- if (type == QSocketNotifier::Exception) {
- qWarning("QSocketNotifier::Exception is not supported on Mac OS X");
- return;
- }
-
- // Check if we have a CFSocket for the native socket, create one if not.
- MacSocketInfo *socketInfo = d->macSockets.value(nativeSocket);
- if (!socketInfo) {
- socketInfo = new MacSocketInfo();
-
- // Create CFSocket, specify that we want both read and write callbacks (the callbacks
- // are enabled/disabled later on).
- const int callbackTypes = kCFSocketReadCallBack | kCFSocketWriteCallBack;
- CFSocketContext context = {0, d, 0, 0, 0};
- socketInfo->socket = CFSocketCreateWithNative(kCFAllocatorDefault, nativeSocket, callbackTypes, qt_mac_socket_callback, &context);
- if (CFSocketIsValid(socketInfo->socket) == false) {
- qWarning("QEventDispatcherMac::registerSocketNotifier: Failed to create CFSocket");
- return;
- }
-
- CFOptionFlags flags = CFSocketGetSocketFlags(socketInfo->socket);
- flags |= kCFSocketAutomaticallyReenableWriteCallBack; //QSocketNotifier stays enabled after a write
- flags &= ~kCFSocketCloseOnInvalidate; //QSocketNotifier doesn't close the socket upon destruction/invalidation
- CFSocketSetSocketFlags(socketInfo->socket, flags);
-
- // Add CFSocket to runloop.
- if(!(socketInfo->runloop = qt_mac_add_socket_to_runloop(socketInfo->socket))) {
- qWarning("QEventDispatcherMac::registerSocketNotifier: Failed to add CFSocket to runloop");
- CFSocketInvalidate(socketInfo->socket);
- CFRelease(socketInfo->socket);
- return;
- }
-
- // Disable both callback types by default. This must be done after
- // we add the CFSocket to the runloop, or else these calls will have
- // no effect.
- CFSocketDisableCallBacks(socketInfo->socket, kCFSocketReadCallBack);
- CFSocketDisableCallBacks(socketInfo->socket, kCFSocketWriteCallBack);
-
- d->macSockets.insert(nativeSocket, socketInfo);
- }
-
- // Increment read/write counters and select enable callbacks if necessary.
- if (type == QSocketNotifier::Read) {
- Q_ASSERT(socketInfo->readNotifier == 0);
- socketInfo->readNotifier = notifier;
- CFSocketEnableCallBacks(socketInfo->socket, kCFSocketReadCallBack);
- } else if (type == QSocketNotifier::Write) {
- Q_ASSERT(socketInfo->writeNotifier == 0);
- socketInfo->writeNotifier = notifier;
- CFSocketEnableCallBacks(socketInfo->socket, kCFSocketWriteCallBack);
- }
+ d->cfSocketNotifier.registerSocketNotifier(notifier);
}
-/*
- Unregister QSocketNotifer. The CFSocket correspoding to this notifier is
- removed from the runloop of this is the last notifier that users
- that CFSocket.
-*/
void QCocoaEventDispatcher::unregisterSocketNotifier(QSocketNotifier *notifier)
{
- Q_ASSERT(notifier);
- int nativeSocket = notifier->socket();
- int type = notifier->type();
-#ifndef QT_NO_DEBUG
- if (nativeSocket < 0 || nativeSocket > FD_SETSIZE) {
- qWarning("QSocketNotifier: Internal error");
- return;
- } else if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
- qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread");
- return;
- }
-#endif
-
Q_D(QCocoaEventDispatcher);
-
- if (type == QSocketNotifier::Exception) {
- qWarning("QSocketNotifier::Exception is not supported on Mac OS X");
- return;
- }
- MacSocketInfo *socketInfo = d->macSockets.value(nativeSocket);
- if (!socketInfo) {
- qWarning("QEventDispatcherMac::unregisterSocketNotifier: Tried to unregister a not registered notifier");
- return;
- }
-
- // Decrement read/write counters and disable callbacks if necessary.
- if (type == QSocketNotifier::Read) {
- Q_ASSERT(notifier == socketInfo->readNotifier);
- socketInfo->readNotifier = 0;
- CFSocketDisableCallBacks(socketInfo->socket, kCFSocketReadCallBack);
- } else if (type == QSocketNotifier::Write) {
- Q_ASSERT(notifier == socketInfo->writeNotifier);
- socketInfo->writeNotifier = 0;
- CFSocketDisableCallBacks(socketInfo->socket, kCFSocketWriteCallBack);
- }
-
- // Remove CFSocket from runloop if this was the last QSocketNotifier.
- if (socketInfo->readNotifier == 0 && socketInfo->writeNotifier == 0) {
- if (CFSocketIsValid(socketInfo->socket))
- qt_mac_remove_socket_from_runloop(socketInfo->socket, socketInfo->runloop);
- CFRunLoopSourceInvalidate(socketInfo->runloop);
- CFRelease(socketInfo->runloop);
- CFSocketInvalidate(socketInfo->socket);
- CFRelease(socketInfo->socket);
- delete socketInfo;
- d->macSockets.remove(nativeSocket);
- }
+ d->cfSocketNotifier.unregisterSocketNotifier(notifier);
}
bool QCocoaEventDispatcher::hasPendingEvents()
@@ -467,37 +299,35 @@ bool QCocoaEventDispatcher::hasPendingEvents()
static bool IsMouseOrKeyEvent( NSEvent* event )
{
bool result = false;
-
+
switch( [event type] )
{
- case NSLeftMouseDown:
- case NSLeftMouseUp:
- case NSRightMouseDown:
- case NSRightMouseUp:
+ case NSLeftMouseDown:
+ case NSLeftMouseUp:
+ case NSRightMouseDown:
+ case NSRightMouseUp:
case NSMouseMoved: // ??
- case NSLeftMouseDragged:
+ case NSLeftMouseDragged:
case NSRightMouseDragged:
- case NSMouseEntered:
- case NSMouseExited:
- case NSKeyDown:
- case NSKeyUp:
+ case NSMouseEntered:
+ case NSMouseExited:
+ case NSKeyDown:
+ case NSKeyUp:
case NSFlagsChanged: // key modifiers changed?
case NSCursorUpdate: // ??
- case NSScrollWheel:
- case NSTabletPoint:
- case NSTabletProximity:
- case NSOtherMouseDown:
- case NSOtherMouseUp:
+ case NSScrollWheel:
+ case NSTabletPoint:
+ case NSTabletProximity:
+ case NSOtherMouseDown:
+ case NSOtherMouseUp:
case NSOtherMouseDragged:
#ifndef QT_NO_GESTURES
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
case NSEventTypeGesture: // touch events
case NSEventTypeMagnify:
case NSEventTypeSwipe:
case NSEventTypeRotate:
case NSEventTypeBeginGesture:
case NSEventTypeEndGesture:
-#endif
#endif // QT_NO_GESTURES
result = true;
break;
@@ -809,7 +639,7 @@ static void setChildrenWorksWhenModal(QWindow *window, bool worksWhenModal)
Q_UNUSED(worksWhenModal)
// For NSPanels (but not NSWindows, sadly), we can set the flag
- // worksWhenModal, so that they are active even when they are not modal.
+ // worksWhenModal, so that they are active even when they are not modal.
/*
### not ported
QList<QDialog *> dialogs = window->findChildren<QDialog *>();
@@ -850,7 +680,7 @@ void QCocoaEventDispatcherPrivate::cleanupModalSessions()
// this to actually end the sessions for real (rather than at the
// point they were marked as stopped), is that ending a session
// when no other session runs below it on the stack will make cocoa
- // drop some events on the floor.
+ // drop some events on the floor.
QCocoaAutoReleasePool pool;
int stackSize = cocoaModalSessionStack.size();
@@ -942,11 +772,19 @@ QCocoaEventDispatcherPrivate::QCocoaEventDispatcherPrivate()
{
}
+void qt_mac_maybeCancelWaitForMoreEventsForwarder(QAbstractEventDispatcher *eventDispatcher)
+{
+ static_cast<QCocoaEventDispatcher *>(eventDispatcher)->d_func()->maybeCancelWaitForMoreEvents();
+}
+
QCocoaEventDispatcher::QCocoaEventDispatcher(QObject *parent)
: QAbstractEventDispatcher(*new QCocoaEventDispatcherPrivate, parent)
{
Q_D(QCocoaEventDispatcher);
+ d->cfSocketNotifier.setHostEventDispatcher(this);
+ d->cfSocketNotifier.setMaybeCancelWaitForMoreEventsCallback(qt_mac_maybeCancelWaitForMoreEventsForwarder);
+
// keep our sources running when modal loops are running
CFRunLoopAddCommonMode(mainRunLoop(), (CFStringRef) NSModalPanelRunLoopMode);
@@ -1021,7 +859,7 @@ void QCocoaEventDispatcherPrivate::processPostedEvents()
if (currentExecIsNSAppRun) {
// The event dispatcher has been interrupted. But since
// [NSApplication run] is running the event loop, we
- // delayed stopping it until now (to let cocoa process
+ // delayed stopping it until now (to let cocoa process
// pending cocoa events first).
if (currentModalSessionCached)
temporarilyStopAllModalSessions();
@@ -1129,17 +967,8 @@ QCocoaEventDispatcher::~QCocoaEventDispatcher()
[nsevent release];
}
- // Remove CFSockets from the runloop.
- for (MacSocketHash::ConstIterator it = d->macSockets.constBegin(); it != d->macSockets.constEnd(); ++it) {
- MacSocketInfo *socketInfo = (*it);
- if (CFSocketIsValid(socketInfo->socket)) {
- qt_mac_remove_socket_from_runloop(socketInfo->socket, socketInfo->runloop);
- CFRunLoopSourceInvalidate(socketInfo->runloop);
- CFRelease(socketInfo->runloop);
- CFSocketInvalidate(socketInfo->socket);
- CFRelease(socketInfo->socket);
- }
- }
+ d->cfSocketNotifier.removeSocketNotifiers();
+
CFRunLoopRemoveSource(mainRunLoop(), d->postedEventsSource, kCFRunLoopCommonModes);
CFRelease(d->postedEventsSource);
diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
index 61646041fb..297d81abab 100644
--- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
@@ -77,11 +77,7 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
@class QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate);
@interface QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate)
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
: NSObject<NSOpenSavePanelDelegate>
-#else
- : NSObject
-#endif
{
@public
NSOpenPanel *mOpenPanel;
@@ -216,7 +212,7 @@ static QString strippedText(QString s)
- (void)closePanel
{
*mCurrentSelection = QT_PREPEND_NAMESPACE(QCFString::toQString)([[mSavePanel URL] path]);
- if ([mSavePanel respondsToSelector:@selector(closePanel:)])
+ if ([mSavePanel respondsToSelector:@selector(close)])
[mSavePanel close];
if ([mSavePanel isSheet])
[NSApp endSheet: mSavePanel];
@@ -230,6 +226,7 @@ static QString strippedText(QString s)
bool selectable = (mOptions->acceptMode() == QFileDialogOptions::AcceptSave)
|| [self panel:nil shouldShowFilename:filepath];
+ [self updateProperties];
[mOpenPanel setAllowedFileTypes:nil];
[mOpenPanel setDirectoryURL:selectable ? [NSURL fileURLWithPath:QT_PREPEND_NAMESPACE(QCFString::toNSString)(info.filePath())]
: [NSURL fileURLWithPath:QT_PREPEND_NAMESPACE(QCFString::toNSString)(info.path())]];
@@ -274,6 +271,7 @@ static QString strippedText(QString s)
bool selectable = (mOptions->acceptMode() == QFileDialogOptions::AcceptSave)
|| [self panel:nil shouldShowFilename:filepath];
+ [self updateProperties];
[mSavePanel setDirectoryURL:selectable ? [NSURL fileURLWithPath:QT_PREPEND_NAMESPACE(QCFString::toNSString)(info.filePath())]
: [NSURL fileURLWithPath:QT_PREPEND_NAMESPACE(QCFString::toNSString)(info.path())]];
[mSavePanel setNameFieldStringValue:selectable ? QT_PREPEND_NAMESPACE(QCFString::toNSString)(info.fileName()) : nil];
@@ -405,6 +403,9 @@ static QString strippedText(QString s)
[mSavePanel setCanCreateDirectories:!(mOptions->testOption(QT_PREPEND_NAMESPACE(QFileDialogOptions::ReadOnly)))];
[mOpenPanel setAllowsMultipleSelection:(fileMode == QT_PREPEND_NAMESPACE(QFileDialogOptions::ExistingFiles))];
[mOpenPanel setResolvesAliases:!(mOptions->testOption(QT_PREPEND_NAMESPACE(QFileDialogOptions::DontResolveSymlinks)))];
+ [mOpenPanel setTitle:QCFString::toNSString(mOptions->windowTitle())];
+ [mSavePanel setTitle:QCFString::toNSString(mOptions->windowTitle())];
+ [mPopUpButton setHidden:chooseDirsOnly]; // TODO hide the whole sunken pane instead?
QStringList ext = [self acceptableExtensionsForSave];
const QString defaultSuffix = mOptions->defaultSuffix();
@@ -577,13 +578,16 @@ extern void qt_mac_to_pascal_string(QString s, Str255 str, TextEncoding encoding
void QCocoaFileDialogHelper::setDirectory(const QString &directory)
{
QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
- [delegate->mSavePanel setDirectoryURL:[NSURL fileURLWithPath:QCFString::toNSString(directory)]];
+ if (delegate)
+ [delegate->mSavePanel setDirectoryURL:[NSURL fileURLWithPath:QCFString::toNSString(directory)]];
}
QString QCocoaFileDialogHelper::directory() const
{
QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
- return QCFString::toQString([delegate->mSavePanel directory]);
+ if (delegate)
+ return QCFString::toQString([[delegate->mSavePanel directoryURL] path]);
+ return QString();
}
void QCocoaFileDialogHelper::selectFile(const QString &filename)
@@ -600,12 +604,16 @@ void QCocoaFileDialogHelper::selectFile(const QString &filename)
QStringList QCocoaFileDialogHelper::selectedFiles() const
{
QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
- return [delegate selectedFiles];
+ if (delegate)
+ return [delegate selectedFiles];
+ return QStringList();
}
void QCocoaFileDialogHelper::setFilter()
{
QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
+ if (!delegate)
+ return;
const SharedPointerFileDialogOptions &opts = options();
[delegate->mSavePanel setTitle:QCFString::toNSString(opts->windowTitle())];
if (opts->isLabelExplicitlySet(QFileDialogOptions::Accept))
@@ -618,9 +626,13 @@ void QCocoaFileDialogHelper::setFilter()
void QCocoaFileDialogHelper::selectNameFilter(const QString &filter)
{
+ if (!options())
+ return;
const int index = options()->nameFilters().indexOf(filter);
if (index != -1) {
QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
+ if (!delegate)
+ return;
[delegate->mPopUpButton selectItemAtIndex:index];
[delegate filterChanged:nil];
}
@@ -629,7 +641,11 @@ void QCocoaFileDialogHelper::selectNameFilter(const QString &filter)
QString QCocoaFileDialogHelper::selectedNameFilter() const
{
QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
+ if (!delegate)
+ return QString();
int index = [delegate->mPopUpButton indexOfSelectedItem];
+ if (index >= options()->nameFilters().count())
+ return QString();
return index != -1 ? options()->nameFilters().at(index) : QString();
}
@@ -675,6 +691,8 @@ bool QCocoaFileDialogHelper::showCocoaFilePanel(Qt::WindowModality windowModalit
{
createNSOpenSavePanelDelegate();
QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
+ if (!delegate)
+ return false;
if (windowModality == Qt::NonModal)
[delegate showModelessPanel];
else if (windowModality == Qt::WindowModal && parent)
diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
index d0f5a58e22..d4673baaef 100644
--- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm
+++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
@@ -49,11 +49,19 @@
#import <Cocoa/Cocoa.h>
QCocoaGLContext::QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share)
- : m_format(format)
+ : m_context(nil),
+ m_shareContext(nil),
+ m_format(format)
{
+ // we only support OpenGL contexts under Cocoa
+ if (m_format.renderableType() == QSurfaceFormat::DefaultRenderableType)
+ m_format.setRenderableType(QSurfaceFormat::OpenGL);
+ if (m_format.renderableType() != QSurfaceFormat::OpenGL)
+ return;
+
QCocoaAutoReleasePool pool; // For the SG Canvas render thread
- NSOpenGLPixelFormat *pixelFormat = static_cast <NSOpenGLPixelFormat *>(qcgl_createNSOpenGLPixelFormat(format));
+ NSOpenGLPixelFormat *pixelFormat = static_cast <NSOpenGLPixelFormat *>(qcgl_createNSOpenGLPixelFormat(m_format));
m_shareContext = share ? static_cast<QCocoaGLContext *>(share)->nsOpenGLContext() : nil;
m_context = [NSOpenGLContext alloc];
@@ -70,6 +78,10 @@ QCocoaGLContext::QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLCo
const GLint interval = 1;
[m_context setValues:&interval forParameter:NSOpenGLCPSwapInterval];
+ if (format.alphaBufferSize() > 0) {
+ int zeroOpacity = 0;
+ [m_context setValues:&zeroOpacity forParameter:NSOpenGLCPSurfaceOpacity];
+ }
}
QCocoaGLContext::~QCocoaGLContext()
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h
index 831ab579f5..c801d9d926 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.h
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.h
@@ -84,8 +84,6 @@ HIMutableShapeRef qt_mac_QRegionToHIMutableShape(const QRegion &region);
OSStatus qt_mac_drawCGImage(CGContextRef inContext, const CGRect *inBounds, CGImageRef inImage);
-CGFloat qt_mac_get_scalefactor();
-
QChar qt_mac_qtKey2CocoaKey(Qt::Key key);
Qt::Key qt_mac_cocoaKey2QtKey(QChar keyCode);
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm
index 20702c6837..5ec2cea362 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.mm
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm
@@ -47,6 +47,7 @@
#include <QtGui>
#include <qpa/qplatformscreen.h>
#include <private/qguiapplication_p.h>
+#include <private/qwindow_p.h>
#ifndef QT_NO_WIDGETS
#include <QtWidgets/QWidget>
@@ -474,11 +475,9 @@ CGColorSpaceRef qt_mac_genericColorSpace()
{
#if 0
if (!m_genericColorSpace) {
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) {
m_genericColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
} else
-#endif
{
m_genericColorSpace = CGColorSpaceCreateDeviceRGB();
}
@@ -586,10 +585,28 @@ QString qt_mac_applicationName()
return appName;
}
+/*
+ Mac window coordinates are in the first quadrant: 0, 0 is at the lower-left
+ corner of the primary screen. This function converts the given rect to an
+ NSRect for the window geometry, flipping from 4th quadrant to 1st quadrant
+ and simultaneously ensuring that as much of the window as possible will be
+ onscreen. If the rect is too tall for the screen, the OS will reduce the
+ window's height anyway; but by moving the window upwards we can have more
+ of it onscreen. But the application can still control the y coordinate
+ in case it really wants the window to be positioned partially offscreen.
+*/
NSRect qt_mac_flipRect(const QRect &rect, QWindow *window)
{
QPlatformScreen *onScreen = QPlatformScreen::platformScreenForWindow(window);
- int flippedY = onScreen->geometry().height() - rect.y() - rect.height();
+ int flippedY = onScreen->geometry().height() - (rect.y() + rect.height());
+
+ // In case of automatic positioning, try to put as much of the window onscreen as possible.
+ if (window->isTopLevel() && qt_window_private(const_cast<QWindow*>(window))->positionAutomatic && flippedY < 0)
+ flippedY = onScreen->geometry().height() - onScreen->availableGeometry().height() - onScreen->availableGeometry().y();
+#ifdef QT_COCOA_ENABLE_WINDOW_DEBUG
+ qDebug() << Q_FUNC_INFO << rect << "flippedY" << flippedY <<
+ "screen" << onScreen->geometry() << "available" << onScreen->availableGeometry();
+#endif
return NSMakeRect(rect.x(), flippedY, rect.width(), rect.height());
}
@@ -615,11 +632,6 @@ InvalidContext:
return err;
}
-CGFloat qt_mac_get_scalefactor()
-{
- return [[NSScreen mainScreen] userSpaceScaleFactor];
-}
-
Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum)
{
if (buttonNum == 0)
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h
index d667ac4a86..6e690dd51e 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.h
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.h
@@ -132,7 +132,7 @@ private:
QAbstractEventDispatcher *mEventDispatcher;
QScopedPointer<QPlatformInputContext> mInputContext;
-#ifndef QT_NO_COCOA_ACCESSIBILITY
+#ifndef QT_NO_ACCESSIBILITY
QScopedPointer<QPlatformAccessibility> mAccessibility;
#endif
QScopedPointer<QPlatformTheme> mPlatformTheme;
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm
index 7fcdab4d97..e2d867e623 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.mm
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm
@@ -90,11 +90,28 @@ void QCocoaScreen::updateGeometry()
{
NSScreen *nsScreen = osScreen();
NSRect frameRect = [nsScreen frame];
- m_geometry = QRect(frameRect.origin.x, frameRect.origin.y, frameRect.size.width, frameRect.size.height);
- NSRect visibleRect = [nsScreen visibleFrame];
- m_availableGeometry = QRect(visibleRect.origin.x,
- frameRect.size.height - (visibleRect.origin.y + visibleRect.size.height), // invert y
- visibleRect.size.width, visibleRect.size.height);
+
+ if (m_screenIndex == 0) {
+ m_geometry = QRect(frameRect.origin.x, frameRect.origin.y, frameRect.size.width, frameRect.size.height);
+ // This is the primary screen, the one that contains the menubar. Its origin should be
+ // (0, 0), and it's the only one whose available geometry differs from its full geometry.
+ NSRect visibleRect = [nsScreen visibleFrame];
+ m_availableGeometry = QRect(visibleRect.origin.x,
+ frameRect.size.height - (visibleRect.origin.y + visibleRect.size.height), // invert y
+ visibleRect.size.width, visibleRect.size.height);
+ } else {
+ // NSScreen origin is at the bottom-left corner, QScreen is at the top-left corner.
+ // When we get the NSScreen frame rect, we need to re-align its origin y coordinate
+ // w.r.t. the primary screen, whose origin is (0, 0).
+ NSRect r = [[[NSScreen screens] objectAtIndex:0] frame];
+ QRect referenceScreenGeometry = QRect(r.origin.x, r.origin.y, r.size.width, r.size.height);
+ m_geometry = QRect(frameRect.origin.x,
+ referenceScreenGeometry.height() - (frameRect.origin.y + frameRect.size.height),
+ frameRect.size.width, frameRect.size.height);
+
+ // Not primary screen. See above.
+ m_availableGeometry = m_geometry;
+ }
m_format = QImage::Format_RGB32;
m_depth = NSBitsPerPixelFromDepth([nsScreen depth]);
@@ -105,7 +122,9 @@ void QCocoaScreen::updateGeometry()
m_physicalSize = QSizeF(size.width, size.height);
m_logicalDpi.first = 72;
m_logicalDpi.second = 72;
- m_refreshRate = CGDisplayModeGetRefreshRate(CGDisplayCopyDisplayMode(dpy));
+ float refresh = CGDisplayModeGetRefreshRate(CGDisplayCopyDisplayMode(dpy));
+ if (refresh > 0)
+ m_refreshRate = refresh;
// Get m_name (brand/model of the monitor)
NSDictionary *deviceInfo = (NSDictionary *)IODisplayCreateInfoDictionary(CGDisplayIOServicePort(dpy), kIODisplayOnlyPreferredName);
@@ -170,13 +189,13 @@ QPixmap QCocoaScreen::grabWindow(WId window, int x, int y, int width, int height
windowSize.setHeight(windowRect.height());
}
- QPixmap windowPixmap(windowSize);
+ QPixmap windowPixmap(windowSize * devicePixelRatio());
windowPixmap.fill(Qt::transparent);
for (uint i = 0; i < displayCount; ++i) {
const CGRect bounds = CGDisplayBounds(displays[i]);
- int w = (width < 0 ? bounds.size.width : width);
- int h = (height < 0 ? bounds.size.height : height);
+ int w = (width < 0 ? bounds.size.width : width) * devicePixelRatio();
+ int h = (height < 0 ? bounds.size.height : height) * devicePixelRatio();
QRect displayRect = QRect(x, y, w, h);
QCFType<CGImageRef> image = CGDisplayCreateImageForRect(displays[i],
CGRectMake(displayRect.x(), displayRect.y(), displayRect.width(), displayRect.height()));
@@ -197,7 +216,7 @@ QCocoaIntegration::QCocoaIntegration()
: mFontDb(new QCoreTextFontDatabase())
, mEventDispatcher(new QCocoaEventDispatcher())
, mInputContext(new QCocoaInputContext)
-#ifndef QT_NO_COCOA_ACCESSIBILITY
+#ifndef QT_NO_ACCESSIBILITY
, mAccessibility(new QCococaAccessibility)
#endif
, mCocoaClipboard(new QCocoaClipboard)
@@ -376,7 +395,7 @@ QPlatformInputContext *QCocoaIntegration::inputContext() const
QPlatformAccessibility *QCocoaIntegration::accessibility() const
{
-#ifndef QT_NO_COCOA_ACCESSIBILITY
+#ifndef QT_NO_ACCESSIBILITY
return mAccessibility.data();
#else
return 0;
diff --git a/src/plugins/platforms/cocoa/qcocoaintrospection.mm b/src/plugins/platforms/cocoa/qcocoaintrospection.mm
index ffb6ae4294..806effc929 100644
--- a/src/plugins/platforms/cocoa/qcocoaintrospection.mm
+++ b/src/plugins/platforms/cocoa/qcocoaintrospection.mm
@@ -83,7 +83,6 @@ void qt_cocoa_change_implementation(Class baseClass, SEL originalSel, Class prox
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5)
#endif
{
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
// The following code replaces the _implementation_ for the selector we want to hack
// (originalSel) with the implementation found in proxyClass. Then it creates
// a new 'backup' method inside baseClass containing the old, original,
@@ -104,7 +103,6 @@ void qt_cocoa_change_implementation(Class baseClass, SEL originalSel, Class prox
Method backupMethod = class_getInstanceMethod(proxyClass, backupSel);
class_addMethod(baseClass, backupSel, originalImp, method_getTypeEncoding(backupMethod));
}
-#endif
}
}
@@ -114,11 +112,9 @@ void qt_cocoa_change_back_implementation(Class baseClass, SEL originalSel, SEL b
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5)
#endif
{
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
Method originalMethod = class_getInstanceMethod(baseClass, originalSel);
Method backupMethodInBaseClass = class_getInstanceMethod(baseClass, backupSel);
method_setImplementation(originalMethod, method_getImplementation(backupMethodInBaseClass));
-#endif
}
}
diff --git a/src/plugins/platforms/cocoa/qcocoakeymapper.h b/src/plugins/platforms/cocoa/qcocoakeymapper.h
index 324b753131..0629de9317 100644
--- a/src/plugins/platforms/cocoa/qcocoakeymapper.h
+++ b/src/plugins/platforms/cocoa/qcocoakeymapper.h
@@ -99,7 +99,6 @@ private:
const UCKeyboardLayout *unicode;
void *other;
} keyboard_layout_format;
- KeyboardLayoutRef currentKeyboardLayout;
KeyboardLayoutKind keyboard_kind;
UInt32 keyboard_dead;
KeyboardLayoutItem *keyLayout[256];
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.h b/src/plugins/platforms/cocoa/qcocoamenu.h
index 09b62a9bcd..439b7f1a75 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.h
+++ b/src/plugins/platforms/cocoa/qcocoamenu.h
@@ -51,8 +51,6 @@
@class NSMenu;
@class NSObject;
-QT_BEGIN_HEADER
-
QT_BEGIN_NAMESPACE
class QCocoaMenu : public QPlatformMenu
@@ -71,11 +69,17 @@ public:
void syncMenuItem(QPlatformMenuItem *menuItem);
void setEnabled(bool enabled);
void setVisible(bool visible);
+ void showPopup(const QWindow *parentWindow, QPoint pos, const QPlatformMenuItem *item);
+
void syncSeparatorsCollapsible(bool enable);
void syncModalState(bool modal);
- virtual void setText(const QString &text);
+ virtual void setIcon(const QIcon &icon) { Q_UNUSED(icon) }
+
+ void setText(const QString &text);
+ void setMinimumWidth(int width);
+ void setFont(const QFont &font);
void setParentItem(QCocoaMenuItem* item);
@@ -102,6 +106,4 @@ private:
QT_END_NAMESPACE
-QT_END_HEADER
-
#endif
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm
index 676f0683fa..0fe4c48510 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenu.mm
@@ -47,6 +47,8 @@
#include <QtCore/QtDebug>
#include "qcocoaapplication.h"
#include "qcocoamenuloader.h"
+#include "qcocoawindow.h"
+#import "qnsview.h"
static inline QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *getMenuLoader()
{
@@ -133,6 +135,20 @@ void QCocoaMenu::setText(const QString &text)
[m_nativeItem setTitle:QCFString::toNSString(stripped)];
}
+void QCocoaMenu::setMinimumWidth(int width)
+{
+ m_nativeMenu.minimumWidth = width;
+}
+
+void QCocoaMenu::setFont(const QFont &font)
+{
+ if (font.resolve()) {
+ NSFont *customMenuFont = [NSFont fontWithName:QCFString::toNSString(font.family())
+ size:font.pointSize()];
+ m_nativeMenu.font = customMenuFont;
+ }
+}
+
void QCocoaMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before)
{
QCocoaAutoReleasePool pool;
@@ -290,9 +306,26 @@ void QCocoaMenu::setVisible(bool visible)
[m_nativeItem setSubmenu:(visible ? m_nativeMenu : nil)];
}
+void QCocoaMenu::showPopup(const QWindow *parentWindow, QPoint pos, const QPlatformMenuItem *item)
+{
+ QCocoaWindow *cocoaWindow = parentWindow ? static_cast<QCocoaWindow *>(parentWindow->handle()) : 0;
+ NSView *view = cocoaWindow ? cocoaWindow->contentView() : nil;
+ NSMenuItem *nsItem = item ? ((QCocoaMenuItem *)item)->nsItem() : nil;
+ NSPoint nsPos = NSMakePoint(pos.x(), pos.y());
+ [m_nativeMenu popUpMenuPositioningItem:nsItem atLocation:nsPos inView:view];
+
+ // The call above blocks, and also swallows any mouse release event,
+ // so we need to clear any mouse button that triggered the menu popup.
+ if ([view isKindOfClass:[QNSView class]])
+ [(QNSView *)view resetMouseButtons];
+}
+
QPlatformMenuItem *QCocoaMenu::menuItemAt(int position) const
{
- return m_menuItems.at(position);
+ if (0 <= position && position < m_menuItems.count())
+ return m_menuItems.at(position);
+
+ return 0;
}
QPlatformMenuItem *QCocoaMenu::menuItemForTag(quintptr tag) const
diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm
index bae52c91b8..c0c8caed05 100644
--- a/src/plugins/platforms/cocoa/qcocoamenubar.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm
@@ -77,8 +77,10 @@ QCocoaMenuBar::~QCocoaMenuBar()
[m_nativeMenu release];
static_menubars.removeOne(this);
- if (m_window)
+ if (m_window && m_window->menubar() == this) {
m_window->setMenubar(0);
+ updateMenuBarImmediately();
+ }
}
void QCocoaMenuBar::insertMenu(QPlatformMenu *platformMenu, QPlatformMenu *before)
diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.h b/src/plugins/platforms/cocoa/qcocoamenuitem.h
index fe5193a50c..0e6d17343d 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuitem.h
+++ b/src/plugins/platforms/cocoa/qcocoamenuitem.h
@@ -51,8 +51,6 @@
@class NSMenuItem;
@class NSMenu;
-QT_BEGIN_HEADER
-
QT_BEGIN_NAMESPACE
class QCocoaMenu;
@@ -76,6 +74,7 @@ public:
void setFont(const QFont &font);
void setRole(MenuRole role);
void setShortcut(const QKeySequence& shortcut);
+ void setCheckable(bool checkable) { Q_UNUSED(checkable) }
void setChecked(bool isChecked);
void setEnabled(bool isEnabled);
@@ -110,8 +109,6 @@ private:
quintptr m_tag;
};
-QT_END_HEADER
-
QT_END_NAMESPACE
#endif
diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
index d78ff73bb6..40cffab3c9 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
@@ -195,7 +195,7 @@ NSMenuItem *QCocoaMenuItem::sync()
QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader();
switch (m_role) {
case ApplicationSpecificRole:
- mergeItem = [loader appSpecificMenuItem];
+ mergeItem = [loader appSpecificMenuItem:reinterpret_cast<NSInteger>(this)];
break;
case AboutRole:
mergeItem = [loader aboutMenuItem];
@@ -315,9 +315,12 @@ NSMenuItem *QCocoaMenuItem::sync()
return m_native;
}
+QT_BEGIN_NAMESPACE
+extern QString qt_mac_applicationmenu_string(int type);
+QT_END_NAMESPACE
+
QString QCocoaMenuItem::mergeText()
{
- extern QString qt_mac_applicationmenu_string(int type);
QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader();
if (m_native == [loader aboutMenuItem]) {
return qt_mac_applicationmenu_string(6).arg(qt_mac_applicationName());
diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.h b/src/plugins/platforms/cocoa/qcocoamenuloader.h
index f95f684e8c..a45ec0fa89 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuloader.h
+++ b/src/plugins/platforms/cocoa/qcocoamenuloader.h
@@ -79,7 +79,7 @@
- (NSMenuItem *)aboutMenuItem;
- (NSMenuItem *)aboutQtMenuItem;
- (NSMenuItem *)hideMenuItem;
-- (NSMenuItem *)appSpecificMenuItem;
+- (NSMenuItem *)appSpecificMenuItem:(NSInteger)tag;
- (IBAction)terminate:(id)sender;
- (IBAction)orderFrontStandardAboutPanel:(id)sender;
- (IBAction)hideOtherApplications:(id)sender;
diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.mm b/src/plugins/platforms/cocoa/qcocoamenuloader.mm
index 2a9dcec64b..726fe5c6d2 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuloader.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenuloader.mm
@@ -246,11 +246,17 @@ QT_END_NAMESPACE
return [[hideItem retain] autorelease];
}
-- (NSMenuItem *)appSpecificMenuItem
+- (NSMenuItem *)appSpecificMenuItem:(NSInteger)tag
{
+ NSMenuItem *item = [appMenu itemWithTag:tag];
+
+ // No reason to create the item if it already exists. See QTBUG-27202.
+ if (item)
+ return [[item retain] autorelease];
+
// Create an App-Specific menu item, insert it into the menu and return
// it as an autorelease item.
- NSMenuItem *item = [[NSMenuItem alloc] init];
+ item = [[NSMenuItem alloc] init];
NSInteger location;
if (lastAppSpecificItem == nil) {
diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.h b/src/plugins/platforms/cocoa/qcocoanativeinterface.h
index 9506f86238..ca84312059 100644
--- a/src/plugins/platforms/cocoa/qcocoanativeinterface.h
+++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.h
@@ -52,6 +52,7 @@ class QWidget;
class QPlatformPrinterSupport;
class QPrintEngine;
class QPlatformMenu;
+class QPlatformMenuBar;
class QCocoaNativeInterface : public QPlatformNativeInterface
{
@@ -99,9 +100,27 @@ private:
// Dock menu support
static void setDockMenu(QPlatformMenu *platformMenu);
+ // Function to return NSMenu * from QPlatformMenu
+ static void *qMenuToNSMenu(QPlatformMenu *platformMenu);
+
+ // Function to return NSMenu * from QPlatformMenuBar
+ static void *qMenuBarToNSMenu(QPlatformMenuBar *platformMenuBar);
+
// QImage <-> CGImage conversion functions
static CGImageRef qImageToCGImage(const QImage &image);
static QImage cgImageToQImage(CGImageRef image);
+
+ // Embedding NSViews as child QWindows
+ static void setWindowContentView(QPlatformWindow *window, void *nsViewContentView);
+
+ // Register if a window should deliver touch events. Enabling
+ // touch events has implications for delivery of other events,
+ // for example by causing scrolling event lag.
+ //
+ // The registration is ref-counted: multiple widgets can enable
+ // touch events, which then will be delivered until the widget
+ // deregisters.
+ static void registerTouchWindow(QWindow *window, bool enable);
};
#endif // QCOCOANATIVEINTERFACE_H
diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm
index bd3a909137..da53fe9c26 100644
--- a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm
+++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm
@@ -109,10 +109,18 @@ QPlatformNativeInterface::NativeResourceForIntegrationFunction QCocoaNativeInter
return NativeResourceForIntegrationFunction(QCocoaNativeInterface::registerDraggedTypes);
if (resource.toLower() == "setdockmenu")
return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setDockMenu);
+ if (resource.toLower() == "qmenutonsmenu")
+ return NativeResourceForIntegrationFunction(QCocoaNativeInterface::qMenuToNSMenu);
+ if (resource.toLower() == "qmenubartonsmenu")
+ return NativeResourceForIntegrationFunction(QCocoaNativeInterface::qMenuBarToNSMenu);
if (resource.toLower() == "qimagetocgimage")
return NativeResourceForIntegrationFunction(QCocoaNativeInterface::qImageToCGImage);
if (resource.toLower() == "cgimagetoqimage")
return NativeResourceForIntegrationFunction(QCocoaNativeInterface::cgImageToQImage);
+ if (resource.toLower() == "setwindowcontentview")
+ return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setWindowContentView);
+ if (resource.toLower() == "registertouchwindow")
+ return NativeResourceForIntegrationFunction(QCocoaNativeInterface::registerTouchWindow);
return 0;
}
@@ -184,8 +192,21 @@ void QCocoaNativeInterface::setDockMenu(QPlatformMenu *platformMenu)
{
QCocoaMenu *cocoaPlatformMenu = static_cast<QCocoaMenu *>(platformMenu);
NSMenu *menu = cocoaPlatformMenu->nsMenu();
- // setDockMenu seems to be undocumented, but this is what Qt 4 did.
- [NSApp setDockMenu: menu];
+ [NSApp QT_MANGLE_NAMESPACE(qt_setDockMenu): menu];
+}
+
+void *QCocoaNativeInterface::qMenuToNSMenu(QPlatformMenu *platformMenu)
+{
+ QCocoaMenu *cocoaPlatformMenu = static_cast<QCocoaMenu *>(platformMenu);
+ NSMenu *menu = cocoaPlatformMenu->nsMenu();
+ return reinterpret_cast<void *>(menu);
+}
+
+void *QCocoaNativeInterface::qMenuBarToNSMenu(QPlatformMenuBar *platformMenuBar)
+{
+ QCocoaMenuBar *cocoaPlatformMenuBar = static_cast<QCocoaMenuBar *>(platformMenuBar);
+ NSMenu *menu = cocoaPlatformMenuBar->nsMenu();
+ return reinterpret_cast<void *>(menu);
}
CGImageRef QCocoaNativeInterface::qImageToCGImage(const QImage &image)
@@ -198,5 +219,17 @@ QImage QCocoaNativeInterface::cgImageToQImage(CGImageRef image)
return qt_mac_toQImage(image);
}
+void QCocoaNativeInterface::setWindowContentView(QPlatformWindow *window, void *contentView)
+{
+ QCocoaWindow *cocoaPlatformWindow = static_cast<QCocoaWindow *>(window);
+ cocoaPlatformWindow->setContentView(reinterpret_cast<NSView *>(contentView));
+}
+
+void QCocoaNativeInterface::registerTouchWindow(QWindow *window, bool enable)
+{
+ QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle());
+ if (cocoaWindow)
+ cocoaWindow->registerTouch(enable);
+}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoaprintersupport.h b/src/plugins/platforms/cocoa/qcocoaprintersupport.h
index 040b687c4e..83cf1ffada 100644
--- a/src/plugins/platforms/cocoa/qcocoaprintersupport.h
+++ b/src/plugins/platforms/cocoa/qcocoaprintersupport.h
@@ -55,6 +55,7 @@ public:
QPrintEngine *createNativePrintEngine(QPrinter::PrinterMode printerMode) Q_DECL_OVERRIDE;
QPaintEngine *createPaintEngine(QPrintEngine *, QPrinter::PrinterMode printerMode) Q_DECL_OVERRIDE;
QList<QPrinter::PaperSize> supportedPaperSizes(const QPrinterInfo &) const Q_DECL_OVERRIDE;
+ QList<QPair<QString, QSizeF> > supportedSizesWithNames(const QPrinterInfo &) const Q_DECL_OVERRIDE;
QList<QPrinterInfo> availablePrinters() Q_DECL_OVERRIDE;
QPrinterInfo printerInfo(const QString &printerName) Q_DECL_OVERRIDE;
diff --git a/src/plugins/platforms/cocoa/qcocoaprintersupport.mm b/src/plugins/platforms/cocoa/qcocoaprintersupport.mm
index a48db02949..cfa23b7a30 100644
--- a/src/plugins/platforms/cocoa/qcocoaprintersupport.mm
+++ b/src/plugins/platforms/cocoa/qcocoaprintersupport.mm
@@ -138,3 +138,34 @@ QPrinterInfo QCocoaPrinterSupport::printerInfoFromPMPrinter(const PMPrinter &pri
return createPrinterInfo(name, description, location, makeAndModel, isDefault, 0);
}
+
+QList<QPair<QString, QSizeF> > QCocoaPrinterSupport::supportedSizesWithNames(const QPrinterInfo &printerInfo) const
+{
+ QList<QPair<QString, QSizeF> > returnValue;
+ if (printerInfo.isNull())
+ return returnValue;
+
+ PMPrinter printer = PMPrinterCreateFromPrinterID(QCFString::toCFStringRef(printerInfo.printerName()));
+ if (!printer)
+ return returnValue;
+
+ CFArrayRef array;
+ if (PMPrinterGetPaperList(printer, &array) != noErr) {
+ PMRelease(printer);
+ return returnValue;
+ }
+
+ int count = CFArrayGetCount(array);
+ for (int i = 0; i < count; ++i) {
+ PMPaper paper = static_cast<PMPaper>(const_cast<void *>(CFArrayGetValueAtIndex(array, i)));
+ double width, height;
+ if (PMPaperGetWidth(paper, &width) == noErr && PMPaperGetHeight(paper, &height) == noErr) {
+ static const double OnePointInMillimeters = 1.0 / 72.0 * 25.4;
+ QCFString paperName;
+ if (PMPaperCreateLocalizedName(paper, printer, &paperName) == noErr)
+ returnValue.append(qMakePair(QString(paperName), QSizeF(width * OnePointInMillimeters, height * OnePointInMillimeters)));
+ }
+ }
+ PMRelease(printer);
+ return returnValue;
+}
diff --git a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm
index 6f8d0fa22a..e613dbbd1b 100644
--- a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm
+++ b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm
@@ -95,6 +95,7 @@ QColor qt_mac_colorForThemeTextColor(ThemeTextColor themeColor)
case kThemeTextColorPushButtonInactive:
case kThemeTextColorTabFrontInactive:
case kThemeTextColorBevelButtonInactive:
+ case kThemeTextColorMenuItemDisabled:
return QColor(127, 127, 127, 255);
case kThemeTextColorMenuItemSelected:
return Qt::white;
@@ -164,7 +165,7 @@ static QMacPaletteMap mac_widget_colors[] = {
QMacPaletteMap(QPlatformTheme::TabBarPalette, kThemeTextColorTabFrontActive, kThemeTextColorTabFrontInactive),
QMacPaletteMap(QPlatformTheme::LabelPalette, kThemeTextColorPlacardActive, kThemeTextColorPlacardInactive),
QMacPaletteMap(QPlatformTheme::GroupBoxPalette, kThemeTextColorPlacardActive, kThemeTextColorPlacardInactive),
- QMacPaletteMap(QPlatformTheme::MenuPalette, kThemeTextColorPopupLabelActive, kThemeTextColorPopupLabelInactive),
+ QMacPaletteMap(QPlatformTheme::MenuPalette, kThemeTextColorMenuItemActive, kThemeTextColorMenuItemDisabled),
//### TODO: The zeros below gives white-on-black text.
QMacPaletteMap(QPlatformTheme::TextEditPalette, 0, 0),
QMacPaletteMap(QPlatformTheme::TextLineEditPalette, 0, 0),
@@ -179,14 +180,14 @@ QHash<QPlatformTheme::Palette, QPalette*> qt_mac_createRolePalettes()
if (mac_widget_colors[i].active != 0) {
qc = qt_mac_colorForThemeTextColor(mac_widget_colors[i].active);
pal.setColor(QPalette::Active, QPalette::Text, qc);
+ pal.setColor(QPalette::Inactive, QPalette::Text, qc);
pal.setColor(QPalette::Active, QPalette::WindowText, qc);
+ pal.setColor(QPalette::Inactive, QPalette::WindowText, qc);
pal.setColor(QPalette::Active, QPalette::HighlightedText, qc);
+ pal.setColor(QPalette::Inactive, QPalette::HighlightedText, qc);
qc = qt_mac_colorForThemeTextColor(mac_widget_colors[i].inactive);
- pal.setColor(QPalette::Inactive, QPalette::Text, qc);
pal.setColor(QPalette::Disabled, QPalette::Text, qc);
- pal.setColor(QPalette::Inactive, QPalette::WindowText, qc);
pal.setColor(QPalette::Disabled, QPalette::WindowText, qc);
- pal.setColor(QPalette::Inactive, QPalette::HighlightedText, qc);
pal.setColor(QPalette::Disabled, QPalette::HighlightedText, qc);
}
if (mac_widget_colors[i].paletteRole == QPlatformTheme::MenuPalette) {
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
index 89ab51cf05..61a6ba3e2f 100755
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
@@ -43,6 +43,8 @@
#ifndef QCOCOASYSTEMTRAYICON_P_H
#define QCOCOASYSTEMTRAYICON_P_H
+#include <QtCore/qglobal.h>
+
#ifndef QT_NO_SYSTEMTRAYICON
#include "QtCore/qstring.h"
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
index e092db8172..99f533b33a 100755
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
@@ -93,7 +93,11 @@ QT_USE_NAMESPACE
@class QT_MANGLE_NAMESPACE(QNSMenu);
@class QT_MANGLE_NAMESPACE(QNSImageView);
-@interface QT_MANGLE_NAMESPACE(QNSStatusItem) : NSObject {
+@interface QT_MANGLE_NAMESPACE(QNSStatusItem) : NSObject
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
+ <NSUserNotificationCenterDelegate>
+#endif
+ {
@public
QCocoaSystemTrayIcon *systray;
NSStatusItem *item;
@@ -108,6 +112,11 @@ QT_USE_NAMESPACE
-(QRectF)geometry;
- (void)triggerSelector:(id)sender button:(Qt::MouseButton)mouseButton;
- (void)doubleClickSelector:(id)sender;
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
+- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification;
+- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification;
+#endif
@end
@interface QT_MANGLE_NAMESPACE(QNSImageView) : NSImageView {
@@ -132,9 +141,19 @@ class QSystemTrayIconSys
public:
QSystemTrayIconSys(QCocoaSystemTrayIcon *sys) {
item = [[QT_MANGLE_NAMESPACE(QNSStatusItem) alloc] initWithSysTray:sys];
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
+ if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) {
+ [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:item];
+ }
+#endif
}
~QSystemTrayIconSys() {
[[[item item] view] setHidden: YES];
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
+ if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) {
+ [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:nil];
+ }
+#endif
[item release];
}
QT_MANGLE_NAMESPACE(QNSStatusItem) *item;
@@ -223,6 +242,18 @@ void QCocoaSystemTrayIcon::showMessage(const QString &title, const QString &mess
if (!m_sys)
return;
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
+ if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) {
+ NSUserNotification *notification = [[NSUserNotification alloc] init];
+ notification.title = [NSString stringWithUTF8String:title.toUtf8().data()];
+ notification.informativeText = [NSString stringWithUTF8String:message.toUtf8().data()];
+
+ [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
+
+ return;
+ }
+#endif
+
#ifdef QT_MAC_SYSTEMTRAY_USE_GROWL
// Make sure that we have Growl installed on the machine we are running on.
QCFType<CFURLRef> cfurl;
@@ -439,6 +470,20 @@ QT_END_NAMESPACE
emit systray->activated(QPlatformSystemTrayIcon::DoubleClick);
}
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
+- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification {
+ Q_UNUSED(center);
+ Q_UNUSED(notification);
+ return YES;
+}
+
+- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification {
+ Q_UNUSED(center);
+ Q_UNUSED(notification);
+ emit systray->messageClicked();
+}
+#endif
+
@end
class QSystemTrayIconQMenu : public QPlatformMenu
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h
index 7140a68d49..e1de5f0add 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.h
+++ b/src/plugins/platforms/cocoa/qcocoawindow.h
@@ -109,6 +109,7 @@ public:
void raise();
void lower();
bool isExposed() const;
+ bool isOpaque() const;
void propagateSizeHints();
void setOpacity(qreal level);
void setMask(const QRegion &region);
@@ -116,10 +117,13 @@ public:
bool setMouseGrabEnabled(bool grab);
QMargins frameMargins() const;
+ void requestActivateWindow();
+
WId winId() const;
void setParent(const QPlatformWindow *window);
NSView *contentView() const;
+ void setContentView(NSView *contentView);
void windowWillMove();
void windowDidMove();
@@ -143,9 +147,12 @@ public:
void setMenubar(QCocoaMenuBar *mb);
QCocoaMenuBar *menubar() const;
+ void registerTouch(bool enable);
+
qreal devicePixelRatio() const;
void exposeWindow();
void obscureWindow();
+ QWindow *childWindowAt(QPoint windowPoint);
protected:
// NSWindow handling. The QCocoaWindow/QNSView can either be displayed
// in an existing NSWindow or in one created by Qt.
@@ -163,13 +170,17 @@ public: // for QNSView
friend class QCocoaBackingStore;
friend class QCocoaNativeInterface;
- QNSView *m_contentView;
+ NSView *m_contentView;
+ QNSView *m_qtView;
NSWindow *m_nsWindow;
+ bool m_contentViewIsEmbedded; // true if the m_contentView is embedded in a "foregin" NSView hiearchy
+
QNSWindowDelegate *m_nsWindowDelegate;
Qt::WindowFlags m_windowFlags;
Qt::WindowState m_synchedWindowState;
Qt::WindowModality m_windowModality;
QPointer<QWindow> m_activePopupWindow;
+ QPointer<QWindow> m_underMouseWindow;
bool m_inConstructor;
QCocoaGLContext *m_glContext;
@@ -178,6 +189,7 @@ public: // for QNSView
bool m_hasModalSession;
bool m_frameStrutEventsEnabled;
bool m_isExposed;
+ int m_registerTouchCount;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index 7c665a35c5..e74f9dcfe0 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -58,6 +58,11 @@
#include <QDebug>
+enum {
+ defaultWindowWidth = 160,
+ defaultWindowHeight = 160
+};
+
static bool isMouseEvent(NSEvent *ev)
{
switch ([ev type]) {
@@ -186,6 +191,7 @@ static bool isMouseEvent(NSEvent *ev)
QCocoaWindow::QCocoaWindow(QWindow *tlw)
: QPlatformWindow(tlw)
, m_nsWindow(0)
+ , m_contentViewIsEmbedded(false)
, m_nsWindowDelegate(0)
, m_synchedWindowState(Qt::WindowActive)
, m_windowModality(Qt::NonModal)
@@ -195,13 +201,15 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw)
, m_hasModalSession(false)
, m_frameStrutEventsEnabled(false)
, m_isExposed(false)
+ , m_registerTouchCount(0)
{
#ifdef QT_COCOA_ENABLE_WINDOW_DEBUG
qDebug() << "QCocoaWindow::QCocoaWindow" << this;
#endif
QCocoaAutoReleasePool pool;
- m_contentView = [[QNSView alloc] initWithQWindow:tlw platformWindow:this];
+ m_qtView = [[QNSView alloc] initWithQWindow:tlw platformWindow:this];
+ m_contentView = m_qtView;
setGeometry(tlw->geometry());
recreateWindow(parent());
@@ -238,6 +246,10 @@ void QCocoaWindow::setGeometry(const QRect &rect)
void QCocoaWindow::setCocoaGeometry(const QRect &rect)
{
QCocoaAutoReleasePool pool;
+
+ if (m_contentViewIsEmbedded)
+ return;
+
if (m_nsWindow) {
NSRect bounds = qt_mac_flipRect(rect, window());
[m_nsWindow setContentSize : bounds.size];
@@ -250,6 +262,9 @@ void QCocoaWindow::setCocoaGeometry(const QRect &rect)
void QCocoaWindow::setVisible(bool visible)
{
QCocoaAutoReleasePool pool;
+ QCocoaWindow *parentCocoaWindow = 0;
+ if (window()->transientParent())
+ parentCocoaWindow = static_cast<QCocoaWindow *>(window()->transientParent()->handle());
#ifdef QT_COCOA_ENABLE_WINDOW_DEBUG
qDebug() << "QCocoaWindow::setVisible" << window() << visible;
#endif
@@ -257,10 +272,7 @@ void QCocoaWindow::setVisible(bool visible)
// We need to recreate if the modality has changed as the style mask will need updating
if (m_windowModality != window()->modality())
recreateWindow(parent());
- QCocoaWindow *parentCocoaWindow = 0;
- if (window()->transientParent()) {
- parentCocoaWindow = static_cast<QCocoaWindow *>(window()->transientParent()->handle());
-
+ if (parentCocoaWindow) {
// The parent window might have moved while this window was hidden,
// update the window geometry if there is a parent.
setGeometry(window()->geometry());
@@ -270,6 +282,10 @@ void QCocoaWindow::setVisible(bool visible)
if (window()->type() == Qt::Popup) {
// qDebug() << "transientParent and popup" << window()->type() << Qt::Popup << (window()->type() & Qt::Popup);
parentCocoaWindow->m_activePopupWindow = window();
+ // QTBUG-30266: a window should not be resizable while a transient popup is open
+ // Since this isn't a native popup, the window manager doesn't close the popup when you click outside
+ [parentCocoaWindow->m_nsWindow setStyleMask:
+ (parentCocoaWindow->windowStyleMask(parentCocoaWindow->m_windowFlags) & ~NSResizableWindowMask)];
}
}
@@ -331,6 +347,9 @@ void QCocoaWindow::setVisible(bool visible)
} else {
[m_contentView setHidden:YES];
}
+ if (parentCocoaWindow && window()->type() == Qt::Popup)
+ // QTBUG-30266: a window should not be resizable while a transient popup is open
+ [parentCocoaWindow->m_nsWindow setStyleMask:parentCocoaWindow->windowStyleMask(parentCocoaWindow->m_windowFlags)];
}
}
@@ -367,7 +386,7 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags)
NSInteger styleMask = NSBorderlessWindowMask;
if ((type & Qt::Popup) == Qt::Popup) {
- if (!windowIsPopupType(type))
+ if (!windowIsPopupType(type) && !(flags & Qt::FramelessWindowHint))
styleMask = (NSUtilityWindowMask | NSResizableWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask | NSTitledWindowMask);
} else {
@@ -409,6 +428,8 @@ void QCocoaWindow::setWindowFlags(Qt::WindowFlags flags)
NSInteger level = this->windowLevel(flags);
[m_nsWindow setStyleMask:styleMask];
[m_nsWindow setLevel:level];
+ [m_nsWindow setIgnoresMouseEvents:((flags & Qt::ToolTip) == Qt::ToolTip) ? YES : NO];
+ // TODO deal with WindowTransparentForInput; setIgnoresMouseEvents is too extreme, you can't click the titlebar
setWindowShadow(flags);
}
@@ -485,6 +506,14 @@ bool QCocoaWindow::isExposed() const
return m_isExposed;
}
+bool QCocoaWindow::isOpaque() const
+{
+ bool translucent = (window()->format().alphaBufferSize() > 0
+ || window()->opacity() < 1
+ || (m_qtView && [m_qtView hasMask]));
+ return !translucent;
+}
+
void QCocoaWindow::propagateSizeHints()
{
QCocoaAutoReleasePool pool;
@@ -525,18 +554,19 @@ void QCocoaWindow::propagateSizeHints()
void QCocoaWindow::setOpacity(qreal level)
{
- if (m_nsWindow)
+ if (m_nsWindow) {
[m_nsWindow setAlphaValue:level];
+ [m_nsWindow setOpaque: isOpaque()];
+ }
}
void QCocoaWindow::setMask(const QRegion &region)
{
- if (m_nsWindow) {
- [m_nsWindow setOpaque:NO];
+ if (m_nsWindow)
[m_nsWindow setBackgroundColor:[NSColor clearColor]];
- }
- [m_contentView setMaskRegion:&region];
+ [m_qtView setMaskRegion:&region];
+ [m_nsWindow setOpaque: isOpaque()];
}
bool QCocoaWindow::setKeyboardGrabEnabled(bool grab)
@@ -580,6 +610,19 @@ NSView *QCocoaWindow::contentView() const
return m_contentView;
}
+void QCocoaWindow::setContentView(NSView *contentView)
+{
+ // Remove and release the previous content view
+ [m_contentView removeFromSuperview];
+ [m_contentView release];
+
+ // Insert and retain the new content view
+ [contentView retain];
+ m_contentView = contentView;
+ m_qtView = 0; // The new content view is not a QNSView.
+ recreateWindow(parent()); // Adds the content view to parent NSView
+}
+
void QCocoaWindow::windowWillMove()
{
// Close any open popups on window move
@@ -592,7 +635,7 @@ void QCocoaWindow::windowWillMove()
void QCocoaWindow::windowDidMove()
{
- [m_contentView updateGeometry];
+ [m_qtView updateGeometry];
}
void QCocoaWindow::windowDidResize()
@@ -600,7 +643,7 @@ void QCocoaWindow::windowDidResize()
if (!m_nsWindow)
return;
- [m_contentView updateGeometry];
+ [m_qtView updateGeometry];
}
void QCocoaWindow::windowWillClose()
@@ -641,7 +684,9 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow)
m_nsWindowDelegate = 0;
}
- if (!parentWindow) {
+ if (window()->type() == Qt::SubWindow) {
+ // Subwindows don't have a NSWindow.
+ } else if (!parentWindow) {
// Create a new NSWindow if this is a top-level window.
m_nsWindow = createNSWindow();
setNSWindow(m_nsWindow);
@@ -665,11 +710,19 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow)
setOpacity(opacity);
}
+void QCocoaWindow::requestActivateWindow()
+{
+ NSWindow *window = [m_contentView window];
+ [ window makeFirstResponder : m_contentView ];
+ [ window makeKeyWindow ];
+}
+
NSWindow * QCocoaWindow::createNSWindow()
{
QCocoaAutoReleasePool pool;
- NSRect frame = qt_mac_flipRect(window()->geometry(), window());
+ QRect rect = initialGeometry(window(), window()->geometry(), defaultWindowWidth, defaultWindowHeight);
+ NSRect frame = qt_mac_flipRect(rect, window());
Qt::WindowType type = window()->type();
Qt::WindowFlags flags = window()->flags();
@@ -726,6 +779,12 @@ NSWindow * QCocoaWindow::createNSWindow()
NSInteger level = windowLevel(flags);
[createdWindow setLevel:level];
+
+ if (window()->format().alphaBufferSize() > 0) {
+ [createdWindow setBackgroundColor:[NSColor clearColor]];
+ [createdWindow setOpaque:NO];
+ }
+
m_windowModality = window()->modality();
return createdWindow;
}
@@ -734,7 +793,6 @@ void QCocoaWindow::setNSWindow(NSWindow *window)
{
m_nsWindowDelegate = [[QNSWindowDelegate alloc] initWithQCocoaWindow:this];
[window setDelegate:m_nsWindowDelegate];
- [window setAcceptsMouseMovedEvents:YES];
// Prevent Cocoa from releasing the window on close. Qt
// handles the close event asynchronously and we want to
@@ -842,6 +900,15 @@ QCocoaMenuBar *QCocoaWindow::menubar() const
return m_menubar;
}
+void QCocoaWindow::registerTouch(bool enable)
+{
+ m_registerTouchCount += enable ? 1 : -1;
+ if (m_registerTouchCount == 1)
+ [m_contentView setAcceptsTouchEvents:YES];
+ else if (m_registerTouchCount == 0)
+ [m_contentView setAcceptsTouchEvents:NO];
+}
+
qreal QCocoaWindow::devicePixelRatio() const
{
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
@@ -870,6 +937,21 @@ void QCocoaWindow::obscureWindow()
}
}
+QWindow *QCocoaWindow::childWindowAt(QPoint windowPoint)
+{
+ QWindow *targetWindow = window();
+ foreach (QObject *child, targetWindow->children()) {
+ if (QWindow *childWindow = qobject_cast<QWindow *>(child)) {
+ if (childWindow->geometry().contains(windowPoint)) {
+ QCocoaWindow* platformWindow = static_cast<QCocoaWindow*>(childWindow->handle());
+ targetWindow = platformWindow->childWindowAt(windowPoint - childWindow->position());
+ }
+ }
+ }
+
+ return targetWindow;
+}
+
QMargins QCocoaWindow::frameMargins() const
{
NSRect frameW = [m_nsWindow frame];
diff --git a/src/plugins/platforms/cocoa/qmacdefines_mac.h b/src/plugins/platforms/cocoa/qmacdefines_mac.h
index 18c1ac84de..c03b398836 100644
--- a/src/plugins/platforms/cocoa/qmacdefines_mac.h
+++ b/src/plugins/platforms/cocoa/qmacdefines_mac.h
@@ -79,15 +79,11 @@
*/
/* This is just many defines. Therefore it doesn't need things like:
-QT_BEGIN_HEADER
-
QT_BEGIN_NAMESPACE
QT_END_NAMESPACE
-QT_END_HEADER
-
Yes, it is an informative comment ;-)
*/
diff --git a/src/plugins/platforms/cocoa/qmultitouch_mac.mm b/src/plugins/platforms/cocoa/qmultitouch_mac.mm
index 337d962c7f..fc0048f998 100644
--- a/src/plugins/platforms/cocoa/qmultitouch_mac.mm
+++ b/src/plugins/platforms/cocoa/qmultitouch_mac.mm
@@ -42,8 +42,6 @@
#include "qmultitouch_mac_p.h"
#include "qcocoahelpers.h"
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
-
QT_BEGIN_NAMESPACE
QHash<qint64, QCocoaTouch*> QCocoaTouch::_currentTouches;
@@ -214,6 +212,3 @@ QCocoaTouch::getCurrentTouchPointList(NSEvent *event, bool acceptSingleTouch)
}
QT_END_NAMESPACE
-
-#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
-
diff --git a/src/plugins/platforms/cocoa/qmultitouch_mac_p.h b/src/plugins/platforms/cocoa/qmultitouch_mac_p.h
index 1244b8223f..736eb3f878 100644
--- a/src/plugins/platforms/cocoa/qmultitouch_mac_p.h
+++ b/src/plugins/platforms/cocoa/qmultitouch_mac_p.h
@@ -61,8 +61,6 @@
#include <qhash.h>
#include <QtCore>
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
-
QT_BEGIN_NAMESPACE
class QCocoaTouch
@@ -92,7 +90,5 @@ class QCocoaTouch
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/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h
index 853b4b99e1..e7ea3d8f8d 100644
--- a/src/plugins/platforms/cocoa/qnsview.h
+++ b/src/plugins/platforms/cocoa/qnsview.h
@@ -86,6 +86,11 @@ QT_END_NAMESPACE
- (BOOL)isFlipped;
- (BOOL)acceptsFirstResponder;
+- (BOOL)becomeFirstResponder;
+- (BOOL)hasMask;
+- (BOOL)isOpaque;
+
+- (void)resetMouseButtons;
- (void)handleMouseEvent:(NSEvent *)theEvent;
- (void)mouseDown:(NSEvent *)theEvent;
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index fae68493f1..3046b898df 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -174,6 +174,36 @@ static QTouchDevice *touchDevice = 0;
QWindowSystemInterface::handleExposeEvent(m_window, m_window->geometry());
}
+- (void)viewDidMoveToSuperview
+{
+ if (!(m_window->type() & Qt::SubWindow))
+ return;
+
+ if ([self superview]) {
+ m_platformWindow->m_contentViewIsEmbedded = true;
+ QWindowSystemInterface::handleGeometryChange(m_window, m_platformWindow->geometry());
+ QWindowSystemInterface::handleExposeEvent(m_window, m_platformWindow->geometry());
+ QWindowSystemInterface::flushWindowSystemEvents();
+ } else {
+ m_platformWindow->m_contentViewIsEmbedded = false;
+ }
+}
+
+- (void)viewWillMoveToWindow:(NSWindow *)newWindow
+{
+ // ### Merge "normal" window code path with this one for 5.1.
+ if (!(m_window->type() & Qt::SubWindow))
+ return;
+
+ if (newWindow) {
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(windowNotification:)
+ name:nil // Get all notifications
+ object:newWindow];
+ } else {
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:nil object:[self window]];
+ }
+}
- (void)updateGeometry
{
QRect geometry;
@@ -182,6 +212,9 @@ static QTouchDevice *touchDevice = 0;
NSRect rect = [self frame];
NSRect windowRect = [[self window] frame];
geometry = QRect(windowRect.origin.x, qt_mac_flipYCoordinate(windowRect.origin.y + rect.size.height), rect.size.width, rect.size.height);
+ } else if (m_window->type() & Qt::SubWindow) {
+ // embedded child window, use the frame rect ### merge with case below
+ geometry = qt_mac_toQRect([self bounds]);
} else {
// child window, use the frame rect
geometry = qt_mac_toQRect([self frame]);
@@ -199,9 +232,16 @@ static QTouchDevice *touchDevice = 0;
// an infinite loop when this notification is triggered again.)
m_platformWindow->QPlatformWindow::setGeometry(geometry);
+ // Don't send the geometry change if the QWindow is designated to be
+ // embedded in a foregin view hiearchy but has not actually been
+ // embedded yet - it's too early.
+ if ((m_window->type() & Qt::SubWindow) && !m_platformWindow->m_contentViewIsEmbedded)
+ return;
+
// Send a geometry change event to Qt, if it's ready to handle events
if (!m_platformWindow->m_inConstructor) {
QWindowSystemInterface::handleGeometryChange(m_window, geometry);
+ QWindowSystemInterface::handleExposeEvent(m_window, geometry);
QWindowSystemInterface::flushWindowSystemEvents();
}
}
@@ -265,6 +305,16 @@ static QTouchDevice *touchDevice = 0;
[self setNeedsDisplayInRect:NSMakeRect(br.x(), br.y(), br.width(), br.height())];
}
+- (BOOL) hasMask
+{
+ return m_maskData != 0;
+}
+
+- (BOOL) isOpaque
+{
+ return m_platformWindow->isOpaque();
+}
+
- (void) setMaskRegion:(const QRegion *)region
{
m_shouldInvalidateWindowShadow = true;
@@ -337,7 +387,12 @@ static QTouchDevice *touchDevice = 0;
);
CGImageRef bsCGImage = m_backingStore->getBackingStoreCGImage();
CGImageRef cleanImg = CGImageCreateWithImageInRect(bsCGImage, backingStoreRect);
- CGContextSetBlendMode(cgContext, kCGBlendModeCopy);
+
+ // Optimization: Copy frame buffer content instead of blending for
+ // top-level windows where Qt fills the entire window content area.
+ if (m_platformWindow->m_nsWindow)
+ CGContextSetBlendMode(cgContext, kCGBlendModeCopy);
+
CGContextDrawImage(cgContext, dirtyWindowRect, cleanImg);
// Clean-up:
@@ -353,14 +408,39 @@ static QTouchDevice *touchDevice = 0;
return YES;
}
+- (BOOL)becomeFirstResponder
+{
+ if (m_window->flags() & Qt::WindowTransparentForInput)
+ return NO;
+ QWindow *focusWindow = m_window;
+
+ // For widgets we need to do a bit of trickery as the window
+ // to activate is the window of the top-level widget.
+ if (m_window->metaObject()->className() == QStringLiteral("QWidgetWindow")) {
+ while (focusWindow->parent()) {
+ focusWindow = focusWindow->parent();
+ }
+ }
+ QWindowSystemInterface::handleWindowActivated(focusWindow);
+ return YES;
+}
+
- (BOOL)acceptsFirstResponder
{
+ if (m_window->flags() & Qt::WindowDoesNotAcceptFocus)
+ return NO;
+ if (m_window->flags() & Qt::WindowTransparentForInput)
+ return NO;
+ if ((m_window->flags() & Qt::ToolTip) == Qt::ToolTip)
+ return NO;
return YES;
}
- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent
{
- Q_UNUSED(theEvent);
+ Q_UNUSED(theEvent)
+ if (m_window->flags() & Qt::WindowTransparentForInput)
+ return NO;
return YES;
}
@@ -403,6 +483,11 @@ static QTouchDevice *touchDevice = 0;
}
}
+- (void)resetMouseButtons
+{
+ m_buttons = Qt::NoButton;
+}
+
- (void)handleMouseEvent:(NSEvent *)theEvent
{
QPoint qtWindowPoint, qtScreenPoint;
@@ -460,6 +545,8 @@ static QTouchDevice *touchDevice = 0;
- (void)mouseDown:(NSEvent *)theEvent
{
+ if (m_window->flags() & Qt::WindowTransparentForInput)
+ return [super mouseDown:theEvent];
m_sendUpAsRightButton = false;
if (m_platformWindow->m_activePopupWindow) {
QWindowSystemInterface::handleCloseEvent(m_platformWindow->m_activePopupWindow);
@@ -484,6 +571,8 @@ static QTouchDevice *touchDevice = 0;
- (void)mouseDragged:(NSEvent *)theEvent
{
+ if (m_window->flags() & Qt::WindowTransparentForInput)
+ return [super mouseDragged:theEvent];
if (!(m_buttons & Qt::LeftButton))
qWarning("QNSView mouseDragged: Internal mouse button tracking invalid (missing Qt::LeftButton)");
[self handleMouseEvent:theEvent];
@@ -491,6 +580,8 @@ static QTouchDevice *touchDevice = 0;
- (void)mouseUp:(NSEvent *)theEvent
{
+ if (m_window->flags() & Qt::WindowTransparentForInput)
+ return [super mouseUp:theEvent];
if (m_sendUpAsRightButton) {
m_buttons &= ~Qt::RightButton;
m_sendUpAsRightButton = false;
@@ -508,6 +599,7 @@ static QTouchDevice *touchDevice = 0;
if (NSIsEmptyRect([self visibleRect]))
return;
+ // Remove current trakcing areas:
QCocoaAutoReleasePool pool;
if (NSArray *trackingArray = [self trackingAreas]) {
NSUInteger size = [trackingArray count];
@@ -520,7 +612,7 @@ static QTouchDevice *touchDevice = 0;
// Ideally, we shouldn't have NSTrackingMouseMoved events included below, it should
// only be turned on if mouseTracking, hover is on or a tool tip is set.
// Unfortunately, Qt will send "tooltip" events on mouse moves, so we need to
- // turn it on in ALL case. That means EVERY QCocoaView gets to pay the cost of
+ // turn it on in ALL case. That means EVERY QWindow gets to pay the cost of
// mouse moves delivered to it (Apple recommends keeping it OFF because there
// is a performance hit). So it goes.
NSUInteger trackingOptions = NSTrackingMouseEnteredAndExited | NSTrackingActiveInActiveApp
@@ -535,30 +627,74 @@ static QTouchDevice *touchDevice = 0;
- (void)mouseMoved:(NSEvent *)theEvent
{
- [self handleMouseEvent:theEvent];
+ if (m_window->flags() & Qt::WindowTransparentForInput)
+ return [super mouseMoved:theEvent];
+
+ QPoint windowPoint, screenPoint;
+ [self convertFromEvent:theEvent toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
+ QWindow *childWindow = m_platformWindow->childWindowAt(windowPoint);
+
+ // Top-level windows generate enter-leave events for sub-windows.
+ // Qt wants to know which window (if any) will be entered at the
+ // the time of the leave. This is dificult to accomplish by
+ // handling mouseEnter and mouseLeave envents, since they are sent
+ // individually to different views.
+ if (m_platformWindow->m_nsWindow && childWindow) {
+ if (childWindow != m_platformWindow->m_underMouseWindow) {
+ QWindowSystemInterface::handleEnterLeaveEvent(childWindow, m_platformWindow->m_underMouseWindow, windowPoint, screenPoint);
+ m_platformWindow->m_underMouseWindow = childWindow;
+ }
+ }
+
+ // Cocoa keeps firing mouse move events for obscured parent views. Qt should not
+ // send those events so filter them out here.
+ if (childWindow != m_window)
+ return;
+
+ [self handleMouseEvent: theEvent];
}
- (void)mouseEntered:(NSEvent *)theEvent
{
+ if (m_window->flags() & Qt::WindowTransparentForInput)
+ return [super mouseEntered:theEvent];
+
+ // Top-level windows generate enter events for sub-windows.
+ if (!m_platformWindow->m_nsWindow)
+ return;
+
QPoint windowPoint, screenPoint;
[self convertFromEvent:theEvent toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
- QWindowSystemInterface::handleEnterEvent(m_window, windowPoint, screenPoint);
+ m_platformWindow->m_underMouseWindow = m_platformWindow->childWindowAt(windowPoint);
+ QWindowSystemInterface::handleEnterEvent(m_platformWindow->m_underMouseWindow, windowPoint, screenPoint);
}
- (void)mouseExited:(NSEvent *)theEvent
{
+ if (m_window->flags() & Qt::WindowTransparentForInput)
+ return [super mouseExited:theEvent];
Q_UNUSED(theEvent);
- QWindowSystemInterface::handleLeaveEvent(m_window);
+
+ // Top-level windows generate leave events for sub-windows.
+ if (!m_platformWindow->m_nsWindow)
+ return;
+
+ QWindowSystemInterface::handleLeaveEvent(m_platformWindow->m_underMouseWindow);
+ m_platformWindow->m_underMouseWindow = 0;
}
- (void)rightMouseDown:(NSEvent *)theEvent
{
+ if (m_window->flags() & Qt::WindowTransparentForInput)
+ return [super rightMouseDown:theEvent];
m_buttons |= Qt::RightButton;
[self handleMouseEvent:theEvent];
}
- (void)rightMouseDragged:(NSEvent *)theEvent
{
+ if (m_window->flags() & Qt::WindowTransparentForInput)
+ return [super rightMouseDragged:theEvent];
if (!(m_buttons & Qt::RightButton))
qWarning("QNSView rightMouseDragged: Internal mouse button tracking invalid (missing Qt::RightButton)");
[self handleMouseEvent:theEvent];
@@ -566,18 +702,24 @@ static QTouchDevice *touchDevice = 0;
- (void)rightMouseUp:(NSEvent *)theEvent
{
+ if (m_window->flags() & Qt::WindowTransparentForInput)
+ return [super rightMouseUp:theEvent];
m_buttons &= ~Qt::RightButton;
[self handleMouseEvent:theEvent];
}
- (void)otherMouseDown:(NSEvent *)theEvent
{
+ if (m_window->flags() & Qt::WindowTransparentForInput)
+ return [super otherMouseDown:theEvent];
m_buttons |= cocoaButton2QtButton([theEvent buttonNumber]);
[self handleMouseEvent:theEvent];
}
- (void)otherMouseDragged:(NSEvent *)theEvent
{
+ if (m_window->flags() & Qt::WindowTransparentForInput)
+ return [super otherMouseDragged:theEvent];
if (!(m_buttons & ~(Qt::LeftButton | Qt::RightButton)))
qWarning("QNSView otherMouseDragged: Internal mouse button tracking invalid (missing Qt::MiddleButton or Qt::ExtraButton*)");
[self handleMouseEvent:theEvent];
@@ -585,6 +727,8 @@ static QTouchDevice *touchDevice = 0;
- (void)otherMouseUp:(NSEvent *)theEvent
{
+ if (m_window->flags() & Qt::WindowTransparentForInput)
+ return [super otherMouseUp:theEvent];
m_buttons &= ~cocoaButton2QtButton([theEvent buttonNumber]);
[self handleMouseEvent:theEvent];
}
@@ -620,6 +764,8 @@ static QTouchDevice *touchDevice = 0;
#ifndef QT_NO_WHEELEVENT
- (void)scrollWheel:(NSEvent *)theEvent
{
+ if (m_window->flags() & Qt::WindowTransparentForInput)
+ return [super scrollWheel:theEvent];
const EventRef carbonEvent = (EventRef)[theEvent eventRef];
const UInt32 carbonEventKind = carbonEvent ? ::GetEventKind(carbonEvent) : 0;
const bool scrollEvent = carbonEventKind == kEventMouseScroll;
@@ -727,6 +873,7 @@ static QTouchDevice *touchDevice = 0;
ulong nativeModifiers = [nsevent modifierFlags];
Qt::KeyboardModifiers modifiers = [self convertKeyModifiers: nativeModifiers];
NSString *charactersIgnoringModifiers = [nsevent charactersIgnoringModifiers];
+ NSString *characters = [nsevent characters];
// [from Qt 4 impl] There is no way to get the scan code from carbon. But we cannot
// use the value 0, since it indicates that the event originates from somewhere
@@ -739,9 +886,12 @@ static QTouchDevice *touchDevice = 0;
QChar ch;
int keyCode;
- if ([charactersIgnoringModifiers length] > 0) {
- // convert the first character into a key code
- ch = QChar([charactersIgnoringModifiers characterAtIndex:0]);
+ if ([charactersIgnoringModifiers length] > 0) { // convert the first character into a key code
+ if ((modifiers & Qt::ControlModifier) && ([characters length] != 0)) {
+ ch = QChar([characters characterAtIndex:0]);
+ } else {
+ ch = QChar([charactersIgnoringModifiers characterAtIndex:0]);
+ }
keyCode = [self convertKeyCode:ch];
} else {
// might be a dead key
@@ -757,7 +907,7 @@ static QTouchDevice *touchDevice = 0;
// ignore text for the U+F700-U+F8FF range. This is used by Cocoa when
// delivering function keys (e.g. arrow keys, backspace, F1-F35, etc.)
if ([charactersIgnoringModifiers length] == 1 && (ch.unicode() < 0xf700 || ch.unicode() > 0xf8ff))
- text = QCFString::toQString([nsevent characters]);
+ text = QCFString::toQString(characters);
if (m_composingText.isEmpty())
m_sendKeyEvent = !QWindowSystemInterface::tryHandleShortcutEvent(m_window, timestamp, keyCode, modifiers, text);
@@ -785,11 +935,15 @@ static QTouchDevice *touchDevice = 0;
- (void)keyDown:(NSEvent *)nsevent
{
+ if (m_window->flags() & Qt::WindowTransparentForInput)
+ return [super keyDown:nsevent];
[self handleKeyEvent:nsevent eventType:int(QEvent::KeyPress)];
}
- (void)keyUp:(NSEvent *)nsevent
{
+ if (m_window->flags() & Qt::WindowTransparentForInput)
+ return [super keyUp:nsevent];
[self handleKeyEvent:nsevent eventType:int(QEvent::KeyRelease)];
}
diff --git a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm
index 8ee39bf767..e3b8cf6532 100644
--- a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm
+++ b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm
@@ -46,13 +46,11 @@
#include "qcocoaaccessibility.h"
#include "qcocoaaccessibilityelement.h"
-#include "QAccessibleActionInterface"
+#include <QtGui/private/qaccessible2_p.h>
#include <QtCore/QDebug>
#import <AppKit/NSAccessibility.h>
-#ifndef QT_NO_COCOA_ACCESSIBILITY
-
@implementation QNSView (QNSViewAccessibility)
// The QNSView is a container that the user does not interact directly with:
@@ -77,7 +75,10 @@
int numKids = m_accessibleRoot->childCount();
NSMutableArray *kids = [NSMutableArray arrayWithCapacity:numKids];
for (int i = 0; i < numKids; ++i) {
- QCocoaAccessibleElement *element = [QCocoaAccessibleElement createElementWithInterface: m_accessibleRoot->child(i) parent:self ];
+ QAccessibleInterface *child = m_accessibleRoot->child(i);
+ Q_ASSERT(child);
+ QAccessible::Id childAxid = QAccessible::uniqueId(child);
+ QCocoaAccessibleElement *element = [QCocoaAccessibleElement createElementWithId:childAxid parent:self];
[kids addObject: element];
[element release];
}
@@ -99,12 +100,10 @@
}
// Hit a child, forward to child accessible interface.
-
- QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement createElementWithInterface: childInterface parent:self ];
+ QAccessible::Id childAxid = QAccessible::uniqueId(childInterface);
+ QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement createElementWithId:childAxid parent:self ];
[accessibleElement autorelease];
return [accessibleElement accessibilityHitTest:point];
}
@end
-
-#endif // QT_NO_COCOA_ACCESSIBILITY
diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.h b/src/plugins/platforms/cocoa/qnswindowdelegate.h
index 53bbeb1318..98ad7b8c9d 100644
--- a/src/plugins/platforms/cocoa/qnswindowdelegate.h
+++ b/src/plugins/platforms/cocoa/qnswindowdelegate.h
@@ -46,26 +46,6 @@
#include "qcocoawindow.h"
-#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5
-@protocol NSWindowDelegate <NSObject>
-//- (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)proposedFrameSize;
-//- (void)windowDidMiniaturize:(NSNotification*)notification;
-- (void)windowDidResize:(NSNotification *)notification;
-- (void)windowWillClose:(NSNotification *)notification;
-//- (NSRect)windowWillUseStandardFrame:(NSWindow *)window defaultFrame:(NSRect)defaultFrame;
-- (void)windowDidMove:(NSNotification *)notification;
-//- (BOOL)windowShouldClose:(id)window;
-//- (void)windowDidDeminiaturize:(NSNotification *)notification;
-//- (void)windowDidBecomeMain:(NSNotification*)notification;
-//- (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;
-//- (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame;
-@end
-#endif
-
@interface QNSWindowDelegate : NSObject <NSWindowDelegate>
{
QCocoaWindow *m_cocoaWindow;
diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac.mm b/src/plugins/platforms/cocoa/qpaintengine_mac.mm
index 101be611ad..301beb11c1 100644
--- a/src/plugins/platforms/cocoa/qpaintengine_mac.mm
+++ b/src/plugins/platforms/cocoa/qpaintengine_mac.mm
@@ -90,14 +90,11 @@ static void qt_mac_clip_cg(CGContextRef hd, const QRegion &rgn, CGAffineTransfor
if (rgn.isEmpty()) {
CGContextAddRect(hd, CGRectMake(0, 0, 0, 0));
} else {
-#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) {
QCFType<HIMutableShapeRef> shape = qt_mac_QRegionToHIMutableShape(rgn);
Q_ASSERT(!HIShapeIsEmpty(shape));
HIShapeReplacePathInCGContext(shape, hd);
- } else
-#endif
- {
+ } else {
QVector<QRect> rects = rgn.rects();
const int count = rects.size();
for (int i = 0; i < count; i++) {
@@ -338,11 +335,9 @@ CGColorSpaceRef QCoreGraphicsPaintEngine::macGenericColorSpace()
{
#if 0
if (!m_genericColorSpace) {
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) {
m_genericColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
} else
-#endif
{
m_genericColorSpace = CGColorSpaceCreateDeviceRGB();
}
@@ -1185,7 +1180,6 @@ extern "C" {
void
QCoreGraphicsPaintEngine::updateCompositionMode(QPainter::CompositionMode mode)
{
-#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) {
int cg_mode = kCGBlendModeNormal;
switch (mode) {
@@ -1267,11 +1261,9 @@ QCoreGraphicsPaintEngine::updateCompositionMode(QPainter::CompositionMode mode)
if (cg_mode > -1) {
CGContextSetBlendMode(d_func()->hd, CGBlendMode(cg_mode));
}
- } else
-#endif
- // The standard porter duff ops.
- if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_3
+ } else if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_3
&& mode <= QPainter::CompositionMode_Xor) {
+ // The standard porter duff ops.
int cg_mode = kCGCompositeModeCopy;
switch (mode) {
case QPainter::CompositionMode_SourceOver:
@@ -1317,7 +1309,6 @@ QCoreGraphicsPaintEngine::updateCompositionMode(QPainter::CompositionMode mode)
if (cg_mode > -1)
CGContextSetCompositeOperation(d_func()->hd, CGCompositeMode(cg_mode));
} else {
-#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
bool needPrivateAPI = false;
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) {
int cg_mode = kCGBlendModeNormal;
@@ -1367,7 +1358,6 @@ QCoreGraphicsPaintEngine::updateCompositionMode(QPainter::CompositionMode mode)
else
CGContextSetCompositeOperation(d_func()->hd, CGCompositeMode(cg_mode));
}
-#endif
}
}
@@ -1376,13 +1366,8 @@ QCoreGraphicsPaintEngine::updateRenderHints(QPainter::RenderHints hints)
{
Q_D(QCoreGraphicsPaintEngine);
CGContextSetShouldAntialias(d->hd, hints & QPainter::Antialiasing);
- static const CGFloat ScaleFactor = qt_mac_get_scalefactor();
- if (ScaleFactor > 1.) {
- CGContextSetInterpolationQuality(d->hd, kCGInterpolationHigh);
- } else {
- CGContextSetInterpolationQuality(d->hd, (hints & QPainter::SmoothPixmapTransform) ?
- kCGInterpolationHigh : kCGInterpolationNone);
- }
+ CGContextSetInterpolationQuality(d->hd, (hints & QPainter::SmoothPixmapTransform) ?
+ kCGInterpolationHigh : kCGInterpolationNone);
bool textAntialiasing = (hints & QPainter::TextAntialiasing) == QPainter::TextAntialiasing;
if (!textAntialiasing || d->disabledSmoothFonts) {
d->disabledSmoothFonts = !textAntialiasing;
diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac_p.h b/src/plugins/platforms/cocoa/qpaintengine_mac_p.h
index 2763a14690..08ede4cdd6 100644
--- a/src/plugins/platforms/cocoa/qpaintengine_mac_p.h
+++ b/src/plugins/platforms/cocoa/qpaintengine_mac_p.h
@@ -122,8 +122,6 @@ public:
void drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
{ QPaintEngine::drawPolygon(points, pointCount, mode); }
- bool supportsTransformations(qreal, const QTransform &) const { return true; };
-
protected:
friend class QMacPrintEngine;
friend class QMacPrintEnginePrivate;
@@ -210,45 +208,6 @@ inline void QCoreGraphicsPaintEnginePrivate::restoreGraphicsState()
CGContextRestoreGState(hd);
}
-class QMacQuartzPaintDevice : public QPaintDevice
-{
-public:
- QMacQuartzPaintDevice(CGContextRef cg, int width, int height, int bytesPerLine)
- : mCG(cg), mWidth(width), mHeight(height), mBytesPerLine(bytesPerLine)
- { }
- int devType() const { return QInternal::MacQuartz; }
- CGContextRef cgContext() const { return mCG; }
- int metric(PaintDeviceMetric metric) const {
- switch (metric) {
- case PdmWidth:
- return mWidth;
- case PdmHeight:
- return mHeight;
- case PdmWidthMM:
- return (qt_defaultDpiX() * mWidth) / 2.54;
- case PdmHeightMM:
- return (qt_defaultDpiY() * mHeight) / 2.54;
- case PdmNumColors:
- return 0;
- case PdmDepth:
- return 32;
- case PdmDpiX:
- case PdmPhysicalDpiX:
- return qt_defaultDpiX();
- case PdmDpiY:
- case PdmPhysicalDpiY:
- return qt_defaultDpiY();
- }
- return 0;
- }
- QPaintEngine *paintEngine() const { qWarning("This function should never be called."); return 0; }
-private:
- CGContextRef mCG;
- int mWidth;
- int mHeight;
- int mBytesPerLine;
-};
-
QT_END_NAMESPACE
#endif // QPAINTENGINE_MAC_P_H
diff --git a/src/plugins/platforms/cocoa/qprintengine_mac.mm b/src/plugins/platforms/cocoa/qprintengine_mac.mm
index 54019372bc..4748005f1a 100644
--- a/src/plugins/platforms/cocoa/qprintengine_mac.mm
+++ b/src/plugins/platforms/cocoa/qprintengine_mac.mm
@@ -180,6 +180,38 @@ QPrinter::PaperSize QMacPrintEnginePrivate::paperSize() const
return QPlatformPrinterSupport::convertQSizeFToPaperSize(sizef);
}
+void QMacPrintEnginePrivate::setPaperName(const QString &name)
+{
+ Q_Q(QMacPrintEngine);
+ PMPrinter printer;
+
+ if (PMSessionGetCurrentPrinter(session(), &printer) == noErr) {
+ CFArrayRef array;
+ if (PMPrinterGetPaperList(printer, &array) != noErr) {
+ PMRelease(printer);
+ return;
+ }
+ int count = CFArrayGetCount(array);
+ for (int i = 0; i < count; ++i) {
+ PMPaper paper = static_cast<PMPaper>(const_cast<void *>(CFArrayGetValueAtIndex(array, i)));
+ QCFString paperName;
+ if (PMPaperCreateLocalizedName(paper, printer, &paperName) == noErr) {
+ if (QString(paperName) == name) {
+ PMPageFormat tmp;
+ PMCreatePageFormatWithPMPaper(&tmp, paper);
+ PMCopyPageFormat(tmp, format());
+ q->setProperty(QPrintEngine::PPK_Orientation, orient);
+ if (PMSessionValidatePageFormat(session(), format(), kPMDontWantBoolean) != noErr) {
+ // Don't know, warn for the moment.
+ qWarning("QMacPrintEngine, problem setting paper name");
+ }
+ }
+ }
+ }
+ PMRelease(printer);
+ }
+}
+
QList<QVariant> QMacPrintEnginePrivate::supportedResolutions() const
{
Q_ASSERT_X(printInfo, "QMacPrinterEngine::supportedResolutions",
@@ -190,23 +222,7 @@ QList<QVariant> QMacPrintEnginePrivate::supportedResolutions() const
if (PMSessionGetCurrentPrinter(session(), &printer) == noErr) {
PMResolution res;
OSStatus status = PMPrinterGetPrinterResolutionCount(printer, &resCount);
- if (status == kPMNotImplemented) {
-#if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5)
- // *Sigh* we have to use the non-indexed version.
- if (PMPrinterGetPrinterResolution(printer, kPMMinSquareResolution, &res) == noErr)
- resolutions.append(int(res.hRes));
- if (PMPrinterGetPrinterResolution(printer, kPMMaxSquareResolution, &res) == noErr) {
- QVariant var(int(res.hRes));
- if (!resolutions.contains(var))
- resolutions.append(var);
- }
- if (PMPrinterGetPrinterResolution(printer, kPMDefaultResolution, &res) == noErr) {
- QVariant var(int(res.hRes));
- if (!resolutions.contains(var))
- resolutions.append(var);
- }
-#endif
- } else if (status == noErr) {
+ if (status == noErr) {
// According to the docs, index start at 1.
for (UInt32 i = 1; i <= resCount; ++i) {
if (PMPrinterGetIndexedPrinterResolution(printer, i, &res) == noErr)
@@ -617,6 +633,9 @@ void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va
case PPK_PaperSize:
d->setPaperSize(QPrinter::PaperSize(value.toInt()));
break;
+ case PPK_PaperName:
+ d->setPaperName(value.toString());
+ break;
case PPK_PrinterName: {
bool printerNameSet = false;
OSStatus status = noErr;
@@ -755,6 +774,9 @@ QVariant QMacPrintEngine::property(PrintEnginePropertyKey key) const
case PPK_PaperSize:
ret = d->paperSize();
break;
+ case PPK_PaperName:
+ ret = QCFString::toQString([d->printInfo localizedPaperName]);
+ break;
case PPK_PaperRect: {
QRect r;
PMRect macrect;
diff --git a/src/plugins/platforms/cocoa/qprintengine_mac_p.h b/src/plugins/platforms/cocoa/qprintengine_mac_p.h
index e122cc5822..28183118d8 100644
--- a/src/plugins/platforms/cocoa/qprintengine_mac_p.h
+++ b/src/plugins/platforms/cocoa/qprintengine_mac_p.h
@@ -53,6 +53,8 @@
// We mean it.
//
+#include <QtCore/qglobal.h>
+
#ifndef QT_NO_PRINTER
#include <QtPrintSupport/qprinter.h>
@@ -142,6 +144,7 @@ public:
bool newPage_helper();
void setPaperSize(QPrinter::PaperSize ps);
QPrinter::PaperSize paperSize() const;
+ void setPaperName(const QString &name);
QList<QVariant> supportedResolutions() const;
inline bool isPrintSessionInitialized() const
{
diff --git a/src/plugins/platforms/directfb/qdirectfbcursor.cpp b/src/plugins/platforms/directfb/qdirectfbcursor.cpp
index afddba3482..b03af51b1a 100644
--- a/src/plugins/platforms/directfb/qdirectfbcursor.cpp
+++ b/src/plugins/platforms/directfb/qdirectfbcursor.cpp
@@ -59,8 +59,9 @@ void QDirectFBCursor::changeCursor(QCursor *cursor, QWindow *)
int ySpot;
QPixmap map;
- if (cursor->shape() != Qt::BitmapCursor) {
- m_image->set(cursor->shape());
+ const Qt::CursorShape newShape = cursor ? cursor->shape() : Qt::ArrowCursor;
+ if (newShape != Qt::BitmapCursor) {
+ m_image->set(newShape);
xSpot = m_image->hotspot().x();
ySpot = m_image->hotspot().y();
QImage *i = m_image->image();
diff --git a/src/plugins/platforms/eglfs/eglfs.pri b/src/plugins/platforms/eglfs/eglfs.pri
new file mode 100644
index 0000000000..eb66e17479
--- /dev/null
+++ b/src/plugins/platforms/eglfs/eglfs.pri
@@ -0,0 +1,44 @@
+QT += core-private gui-private platformsupport-private
+
+#DEFINES += QEGL_EXTRA_DEBUG
+
+#Avoid X11 header collision
+DEFINES += MESA_EGL_NO_X11_HEADERS
+
+#To test the hooks on x11 (xlib), comment the above define too
+#EGLFS_PLATFORM_HOOKS_SOURCES += qeglfshooks_x11.cpp
+#LIBS += -lX11
+
+SOURCES += $$PWD/qeglfsintegration.cpp \
+ $$PWD/qeglfswindow.cpp \
+ $$PWD/qeglfsbackingstore.cpp \
+ $$PWD/qeglfsscreen.cpp \
+ $$PWD/qeglfshooks_stub.cpp \
+ $$PWD/qeglfscursor.cpp \
+ $$PWD/qeglfscontext.cpp
+
+HEADERS += $$PWD/qeglfsintegration.h \
+ $$PWD/qeglfswindow.h \
+ $$PWD/qeglfsbackingstore.h \
+ $$PWD/qeglfsscreen.h \
+ $$PWD/qeglfscursor.h \
+ $$PWD/qeglfshooks.h \
+ $$PWD/qeglfscontext.h
+
+QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF
+
+INCLUDEPATH += $$PWD
+
+!isEmpty(EGLFS_PLATFORM_HOOKS_SOURCES) {
+ HEADERS += $$EGLFS_PLATFORM_HOOKS_HEADERS
+ SOURCES += $$EGLFS_PLATFORM_HOOKS_SOURCES
+ LIBS += $$EGLFS_PLATFORM_HOOKS_LIBS
+ DEFINES += EGLFS_PLATFORM_HOOKS
+}
+
+CONFIG += egl qpa/genericunixfontdatabase
+
+RESOURCES += $$PWD/cursor.qrc
+
+OTHER_FILES += \
+ $$PWD/eglfs.json
diff --git a/src/plugins/platforms/eglfs/eglfs.pro b/src/plugins/platforms/eglfs/eglfs.pro
index 45059a9cb9..8827f7680c 100644
--- a/src/plugins/platforms/eglfs/eglfs.pro
+++ b/src/plugins/platforms/eglfs/eglfs.pro
@@ -4,48 +4,6 @@ PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = QEglFSIntegrationPlugin
load(qt_plugin)
-QT += core-private gui-private platformsupport-private
+SOURCES += $$PWD/main.cpp
-#DEFINES += QEGL_EXTRA_DEBUG
-
-#Avoid X11 header collision
-DEFINES += MESA_EGL_NO_X11_HEADERS
-
-#To test the hooks on x11 (xlib), comment the above define too
-#EGLFS_PLATFORM_HOOKS_SOURCES += qeglfshooks_x11.cpp
-#LIBS += -lX11
-
-SOURCES = main.cpp \
- qeglfsintegration.cpp \
- qeglfswindow.cpp \
- qeglfsbackingstore.cpp \
- qeglfsscreen.cpp \
- qeglfshooks_stub.cpp \
- qeglfscursor.cpp \
- qeglfscontext.cpp
-
-HEADERS = qeglfsintegration.h \
- qeglfswindow.h \
- qeglfsbackingstore.h \
- qeglfsscreen.h \
- qeglfscursor.h \
- qeglfshooks.h \
- qeglfscontext.h
-
-QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF
-
-INCLUDEPATH += $$PWD
-
-!isEmpty(EGLFS_PLATFORM_HOOKS_SOURCES) {
- HEADERS += $$EGLFS_PLATFORM_HOOKS_HEADERS
- SOURCES += $$EGLFS_PLATFORM_HOOKS_SOURCES
- LIBS += $$EGLFS_PLATFORM_HOOKS_LIBS
- DEFINES += EGLFS_PLATFORM_HOOKS
-}
-
-CONFIG += egl qpa/genericunixfontdatabase
-
-RESOURCES += cursor.qrc
-
-OTHER_FILES += \
- eglfs.json
+include(eglfs.pri)
diff --git a/src/plugins/platforms/eglfs/qeglfscontext.cpp b/src/plugins/platforms/eglfs/qeglfscontext.cpp
index 66b42d64e7..51439646c6 100644
--- a/src/plugins/platforms/eglfs/qeglfscontext.cpp
+++ b/src/plugins/platforms/eglfs/qeglfscontext.cpp
@@ -43,14 +43,17 @@
#include "qeglfswindow.h"
#include "qeglfscursor.h"
#include "qeglfshooks.h"
+#include "qeglfsintegration.h"
+#include <QtPlatformSupport/private/qeglpbuffer_p.h>
+#include <QtGui/QSurface>
#include <QtDebug>
QT_BEGIN_NAMESPACE
QEglFSContext::QEglFSContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share,
EGLDisplay display, EGLenum eglApi)
- : QEGLPlatformContext(hooks->surfaceFormatFor(format), share, display, eglApi)
+ : QEGLPlatformContext(QEglFSHooks::hooks()->surfaceFormatFor(format), share, display, QEglFSIntegration::chooseConfig(display, QEglFSHooks::hooks()->surfaceFormatFor(format)), eglApi)
{
}
@@ -61,17 +64,22 @@ bool QEglFSContext::makeCurrent(QPlatformSurface *surface)
EGLSurface QEglFSContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface)
{
- QEglFSWindow *window = static_cast<QEglFSWindow *>(surface);
- return window->surface();
+ if (surface->surface()->surfaceClass() == QSurface::Window)
+ return static_cast<QEglFSWindow *>(surface)->surface();
+ else
+ return static_cast<QEGLPbuffer *>(surface)->pbuffer();
}
void QEglFSContext::swapBuffers(QPlatformSurface *surface)
{
- QEglFSWindow *window = static_cast<QEglFSWindow *>(surface);
- // draw the cursor
- if (QEglFSCursor *cursor = static_cast<QEglFSCursor *>(window->screen()->cursor()))
- cursor->paintOnScreen();
+ if (surface->surface()->surfaceClass() == QSurface::Window) {
+ QEglFSWindow *window = static_cast<QEglFSWindow *>(surface);
+ // draw the cursor
+ if (QEglFSCursor *cursor = static_cast<QEglFSCursor *>(window->screen()->cursor()))
+ cursor->paintOnScreen();
+ }
+ QEglFSHooks::hooks()->waitForVSync();
QEGLPlatformContext::swapBuffers(surface);
}
diff --git a/src/plugins/platforms/eglfs/qeglfscursor.cpp b/src/plugins/platforms/eglfs/qeglfscursor.cpp
index c245b1b5bb..9dc836b8b1 100644
--- a/src/plugins/platforms/eglfs/qeglfscursor.cpp
+++ b/src/plugins/platforms/eglfs/qeglfscursor.cpp
@@ -196,15 +196,16 @@ void QEglFSCursor::changeCursor(QCursor *cursor, QWindow *window)
bool QEglFSCursor::setCurrentCursor(QCursor *cursor)
{
- if (m_cursor.shape == cursor->shape() && cursor->shape() != Qt::BitmapCursor)
+ const Qt::CursorShape newShape = cursor ? cursor->shape() : Qt::ArrowCursor;
+ if (m_cursor.shape == newShape && newShape != Qt::BitmapCursor)
return false;
if (m_cursor.shape == Qt::BitmapCursor) {
m_cursor.customCursorImage = QImage(); // in case render() never uploaded it
}
- m_cursor.shape = cursor->shape();
- if (cursor->shape() != Qt::BitmapCursor) { // standard cursor
+ m_cursor.shape = newShape;
+ if (newShape != Qt::BitmapCursor) { // standard cursor
const float ws = (float)m_cursorAtlas.cursorWidth / m_cursorAtlas.width,
hs = (float)m_cursorAtlas.cursorHeight / m_cursorAtlas.height;
m_cursor.textureRect = QRectF(ws * (m_cursor.shape % m_cursorAtlas.cursorsPerRow),
diff --git a/src/plugins/platforms/eglfs/qeglfshooks.h b/src/plugins/platforms/eglfs/qeglfshooks.h
index 2d095ba934..c4ac7185fb 100644
--- a/src/plugins/platforms/eglfs/qeglfshooks.h
+++ b/src/plugins/platforms/eglfs/qeglfshooks.h
@@ -55,10 +55,11 @@ class QEglFSScreen;
class QEglFSHooks
{
public:
- virtual ~QEglFSHooks() {};
+ virtual ~QEglFSHooks() {}
virtual void platformInit();
virtual void platformDestroy();
virtual EGLNativeDisplayType platformDisplay() const;
+ virtual QSizeF physicalScreenSize() const;
virtual QSize screenSize() const;
virtual int screenDepth() const;
virtual QImage::Format screenFormat() const;
@@ -67,15 +68,22 @@ public:
virtual void destroyNativeWindow(EGLNativeWindowType window);
virtual bool hasCapability(QPlatformIntegration::Capability cap) const;
virtual QEglFSCursor *createCursor(QEglFSScreen *screen) const;
-};
+ virtual bool filterConfig(EGLDisplay display, EGLConfig config) const;
+ virtual void waitForVSync() const;
+
+ virtual const char *fbDeviceName() const;
+ static QEglFSHooks *hooks()
+ {
#ifdef EGLFS_PLATFORM_HOOKS
-extern QEglFSHooks *platformHooks;
-static QEglFSHooks *hooks = platformHooks;
+ extern QEglFSHooks *platformHooks;
+ return platformHooks;
#else
-extern QEglFSHooks stubHooks;
-static QEglFSHooks *hooks = &stubHooks;
+ extern QEglFSHooks stubHooks;
+ return &stubHooks;
#endif
+ }
+};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp b/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp
index e9a22ea605..8200fa70b2 100644
--- a/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp
+++ b/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp
@@ -46,15 +46,32 @@
#include <linux/fb.h>
#include <sys/ioctl.h>
+#include <private/qmath_p.h>
+#include <private/qcore_unix_p.h>
+
QT_BEGIN_NAMESPACE
+// file descriptor for the frame buffer
+// this is a global static to keep the QEglFSHooks interface as clean as possible
+static int framebuffer = -1;
+
+const char *QEglFSHooks::fbDeviceName() const
+{
+ return "/dev/fb0";
+}
+
void QEglFSHooks::platformInit()
{
- Q_UNUSED(hooks);
+ framebuffer = qt_safe_open(fbDeviceName(), O_RDONLY);
+
+ if (framebuffer == -1)
+ qWarning("EGLFS: Failed to open %s", fbDeviceName());
}
void QEglFSHooks::platformDestroy()
{
+ if (framebuffer != -1)
+ close(framebuffer);
}
EGLNativeDisplayType QEglFSHooks::platformDisplay() const
@@ -62,6 +79,55 @@ EGLNativeDisplayType QEglFSHooks::platformDisplay() const
return EGL_DEFAULT_DISPLAY;
}
+QSizeF QEglFSHooks::physicalScreenSize() const
+{
+ static QSizeF size;
+ if (size.isEmpty()) {
+
+ // Note: in millimeters
+ int width = qgetenv("QT_QPA_EGLFS_PHYSICAL_WIDTH").toInt();
+ int height = qgetenv("QT_QPA_EGLFS_PHYSICAL_HEIGHT").toInt();
+
+ if (width && height) {
+ // no need to read fb0
+ size.setWidth(width);
+ size.setHeight(height);
+ return size;
+ }
+
+ struct fb_var_screeninfo vinfo;
+ int w = -1;
+ int h = -1;
+
+ if (framebuffer != -1) {
+ if (ioctl(framebuffer, FBIOGET_VSCREENINFO, &vinfo) == -1) {
+ qWarning("EGLFS: Could not query variable screen info.");
+ } else {
+ w = vinfo.width;
+ h = vinfo.height;
+ }
+ }
+
+ const int defaultPhysicalDpi = 100;
+ size.setWidth(w <= 0 ? vinfo.xres * Q_MM_PER_INCH / defaultPhysicalDpi : qreal(w));
+ size.setHeight(h <= 0 ? vinfo.yres * Q_MM_PER_INCH / defaultPhysicalDpi : qreal(h));
+
+ if (w <= 0 || h <= 0) {
+ qWarning("EGLFS: Unable to query physical screen size, defaulting to %d dpi.\n"
+ "EGLFS: To override, set QT_QPA_EGLFS_PHYSICAL_WIDTH "
+ "and QT_QPA_EGLFS_PHYSICAL_HEIGHT (in millimeters).",
+ defaultPhysicalDpi);
+ }
+
+ // override fb0 from environment var setting
+ if (width)
+ size.setWidth(width);
+ if (height)
+ size.setWidth(height);
+ }
+ return size;
+}
+
QSize QEglFSHooks::screenSize() const
{
static QSize size;
@@ -78,17 +144,28 @@ QSize QEglFSHooks::screenSize() const
}
struct fb_var_screeninfo vinfo;
- int fd = open("/dev/fb0", O_RDONLY);
- if (fd != -1) {
- if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) == -1)
- qWarning("Could not query variable screen info.");
- else
- size = QSize(vinfo.xres, vinfo.yres);
+ int xres = -1;
+ int yres = -1;
+
+ if (framebuffer != -1) {
+ if (ioctl(framebuffer, FBIOGET_VSCREENINFO, &vinfo) == -1) {
+ qWarning("EGLFS: Could not query variable screen info.");
+ } else {
+ xres = vinfo.xres;
+ yres = vinfo.yres;
+ }
+ }
+
+ const int defaultWidth = 800;
+ const int defaultHeight = 600;
+ size.setWidth(xres <= 0 ? defaultWidth : xres);
+ size.setHeight(yres <= 0 ? defaultHeight : yres);
- close(fd);
- } else {
- qWarning("Failed to open /dev/fb0 to detect screen resolution.");
+ if (xres <= 0 || yres <= 0) {
+ qWarning("EGLFS: Unable to query screen resolution, defaulting to %dx%d.\n"
+ "EGLFS: To override, set QT_QPA_EGLFS_WIDTH and QT_QPA_EGLFS_HEIGHT.",
+ defaultWidth, defaultHeight);
}
// override fb0 from environment var setting
@@ -107,21 +184,25 @@ int QEglFSHooks::screenDepth() const
if (depth == 0) {
struct fb_var_screeninfo vinfo;
- int fd = open("/dev/fb0", O_RDONLY);
- if (fd != -1) {
- if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) == -1)
- qWarning("Could not query variable screen info.");
+ if (framebuffer != -1) {
+ if (ioctl(framebuffer, FBIOGET_VSCREENINFO, &vinfo) == -1)
+ qWarning("EGLFS: Could not query variable screen info.");
else
depth = vinfo.bits_per_pixel;
+ }
+
+ const int defaultDepth = 32;
+
+ if (depth <= 0) {
+ depth = defaultDepth;
- close(fd);
- } else {
- qWarning("Failed to open /dev/fb0 to detect screen depth.");
+ qWarning("EGLFS: Unable to query screen depth, defaulting to %d.\n"
+ "EGLFS: To override, set QT_QPA_EGLFS_DEPTH.", defaultDepth);
}
}
- return depth == 0 ? 32 : depth;
+ return depth;
}
QImage::Format QEglFSHooks::screenFormat() const
@@ -134,6 +215,11 @@ QSurfaceFormat QEglFSHooks::surfaceFormatFor(const QSurfaceFormat &inputFormat)
return inputFormat;
}
+bool QEglFSHooks::filterConfig(EGLDisplay, EGLConfig) const
+{
+ return true;
+}
+
EGLNativeWindowType QEglFSHooks::createNativeWindow(const QSize &size, const QSurfaceFormat &format)
{
Q_UNUSED(size);
@@ -158,6 +244,18 @@ QEglFSCursor *QEglFSHooks::createCursor(QEglFSScreen *screen) const
return 0;
}
+void QEglFSHooks::waitForVSync() const
+{
+#if defined(FBIO_WAITFORVSYNC)
+ static const bool forceSync = qgetenv("QT_QPA_EGLFS_FORCEVSYNC").toInt();
+ if (forceSync && framebuffer != -1) {
+ int arg = 0;
+ if (ioctl(framebuffer, FBIO_WAITFORVSYNC, &arg) == -1)
+ qWarning("Could not wait for vsync.");
+ }
+#endif
+}
+
#ifndef EGLFS_PLATFORM_HOOKS
QEglFSHooks stubHooks;
#endif
diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/qeglfsintegration.cpp
index 0dcde9ca36..64e11b4e07 100644
--- a/src/plugins/platforms/eglfs/qeglfsintegration.cpp
+++ b/src/plugins/platforms/eglfs/qeglfsintegration.cpp
@@ -49,9 +49,11 @@
#include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h>
#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h>
+#include <QtPlatformSupport/private/qeglconvenience_p.h>
#include <QtPlatformSupport/private/qeglplatformcontext_p.h>
+#include <QtPlatformSupport/private/qeglpbuffer_p.h>
-#if !defined(QT_NO_EVDEV)
+#if !defined(QT_NO_EVDEV) && !defined(Q_OS_ANDROID)
#include <QtPlatformSupport/private/qevdevmousemanager_p.h>
#include <QtPlatformSupport/private/qevdevkeyboardmanager_p.h>
#include <QtPlatformSupport/private/qevdevtouch_p.h>
@@ -61,8 +63,11 @@
#include <QtGui/QSurfaceFormat>
#include <QtGui/QOpenGLContext>
#include <QtGui/QScreen>
+#include <QtGui/QOffscreenSurface>
#include <qpa/qplatformcursor.h>
+#include <qpa/qplatforminputcontextfactory_p.h>
+
#include "qeglfscontext.h"
#include <EGL/egl.h>
@@ -74,13 +79,13 @@ QEglFSIntegration::QEglFSIntegration()
{
QGuiApplicationPrivate::instance()->setEventDispatcher(mEventDispatcher);
-#if !defined(QT_NO_EVDEV)
+#if !defined(QT_NO_EVDEV) && !defined(Q_OS_ANDROID)
new QEvdevKeyboardManager(QLatin1String("EvdevKeyboard"), QString() /* spec */, this);
new QEvdevMouseManager(QLatin1String("EvdevMouse"), QString() /* spec */, this);
new QEvdevTouchScreenHandlerThread(QString() /* spec */, this);
#endif
- hooks->platformInit();
+ QEglFSHooks::hooks()->platformInit();
EGLint major, minor;
@@ -89,7 +94,7 @@ QEglFSIntegration::QEglFSIntegration()
qFatal("EGL error");
}
- mDisplay = eglGetDisplay(hooks ? hooks->platformDisplay() : EGL_DEFAULT_DISPLAY);
+ mDisplay = eglGetDisplay(QEglFSHooks::hooks() ? QEglFSHooks::hooks()->platformDisplay() : EGL_DEFAULT_DISPLAY);
if (mDisplay == EGL_NO_DISPLAY) {
qWarning("Could not open egl display\n");
qFatal("EGL error");
@@ -112,6 +117,8 @@ QEglFSIntegration::QEglFSIntegration()
mScreen = new QEglFSScreen(mDisplay);
screenAdded(mScreen);
+
+ mInputContext = QPlatformInputContextFactory::create();
}
QEglFSIntegration::~QEglFSIntegration()
@@ -119,13 +126,13 @@ QEglFSIntegration::~QEglFSIntegration()
delete mScreen;
eglTerminate(mDisplay);
- hooks->platformDestroy();
+ QEglFSHooks::hooks()->platformDestroy();
}
bool QEglFSIntegration::hasCapability(QPlatformIntegration::Capability cap) const
{
// We assume that devices will have more and not less capabilities
- if (hooks && hooks->hasCapability(cap))
+ if (QEglFSHooks::hooks() && QEglFSHooks::hooks()->hasCapability(cap))
return true;
switch (cap) {
@@ -150,7 +157,13 @@ QPlatformBackingStore *QEglFSIntegration::createPlatformBackingStore(QWindow *wi
QPlatformOpenGLContext *QEglFSIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
- return new QEglFSContext(context->format(), 0 /*share*/, mDisplay);
+ return new QEglFSContext(QEglFSHooks::hooks()->surfaceFormatFor(context->format()), context->shareHandle(), mDisplay);
+}
+
+QPlatformOffscreenSurface *QEglFSIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const
+{
+ QEglFSScreen *screen = static_cast<QEglFSScreen *>(surface->screen()->handle());
+ return new QEGLPbuffer(screen->display(), QEglFSHooks::hooks()->surfaceFormatFor(surface->requestedFormat()), surface);
}
QPlatformFontDatabase *QEglFSIntegration::fontDatabase() const
@@ -201,4 +214,29 @@ void *QEglFSIntegration::nativeResourceForContext(const QByteArray &resource, QO
return 0;
}
+EGLConfig QEglFSIntegration::chooseConfig(EGLDisplay display, const QSurfaceFormat &format)
+{
+ class Chooser : public QEglConfigChooser {
+ public:
+ Chooser(EGLDisplay display, QEglFSHooks *hooks)
+ : QEglConfigChooser(display)
+ , m_hooks(hooks)
+ {
+ }
+
+ protected:
+ bool filterConfig(EGLConfig config) const
+ {
+ return m_hooks->filterConfig(display(), config) && QEglConfigChooser::filterConfig(config);
+ }
+
+ private:
+ QEglFSHooks *m_hooks;
+ };
+
+ Chooser chooser(display, QEglFSHooks::hooks());
+ chooser.setSurfaceFormat(format);
+ return chooser.chooseConfig();
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.h b/src/plugins/platforms/eglfs/qeglfsintegration.h
index 42b132b73a..bf044d6919 100644
--- a/src/plugins/platforms/eglfs/qeglfsintegration.h
+++ b/src/plugins/platforms/eglfs/qeglfsintegration.h
@@ -48,8 +48,6 @@
#include <qpa/qplatformnativeinterface.h>
#include <qpa/qplatformscreen.h>
-QT_BEGIN_HEADER
-
QT_BEGIN_NAMESPACE
class QEglFSIntegration : public QPlatformIntegration, public QPlatformNativeInterface
@@ -63,6 +61,7 @@ public:
QPlatformWindow *createPlatformWindow(QWindow *window) const;
QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const;
QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const;
+ QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const;
QPlatformNativeInterface *nativeInterface() const;
QPlatformFontDatabase *fontDatabase() const;
@@ -75,14 +74,21 @@ public:
void *nativeResourceForIntegration(const QByteArray &resource);
void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context);
+ QPlatformScreen *screen() const { return mScreen; }
+ static EGLConfig chooseConfig(EGLDisplay display, const QSurfaceFormat &format);
+
+ EGLDisplay display() const { return mDisplay; }
+
+ QPlatformInputContext *inputContext() const { return mInputContext; }
+
private:
EGLDisplay mDisplay;
QAbstractEventDispatcher *mEventDispatcher;
QPlatformFontDatabase *mFontDb;
QPlatformScreen *mScreen;
+ QPlatformInputContext *mInputContext;
};
QT_END_NAMESPACE
-QT_END_HEADER
#endif // QEGLFSINTEGRATION_H
diff --git a/src/plugins/platforms/eglfs/qeglfsscreen.cpp b/src/plugins/platforms/eglfs/qeglfsscreen.cpp
index 1bc1e944de..83f50dd382 100644
--- a/src/plugins/platforms/eglfs/qeglfsscreen.cpp
+++ b/src/plugins/platforms/eglfs/qeglfsscreen.cpp
@@ -56,7 +56,7 @@ QEglFSScreen::QEglFSScreen(EGLDisplay dpy)
static int hideCursor = qgetenv("QT_QPA_EGLFS_HIDECURSOR").toInt();
if (!hideCursor) {
- if (QEglFSCursor *customCursor = hooks->createCursor(this))
+ if (QEglFSCursor *customCursor = QEglFSHooks::hooks()->createCursor(this))
m_cursor = customCursor;
else
m_cursor = new QEglFSCursor(this);
@@ -70,17 +70,22 @@ QEglFSScreen::~QEglFSScreen()
QRect QEglFSScreen::geometry() const
{
- return QRect(QPoint(0, 0), hooks->screenSize());
+ return QRect(QPoint(0, 0), QEglFSHooks::hooks()->screenSize());
}
int QEglFSScreen::depth() const
{
- return hooks->screenDepth();
+ return QEglFSHooks::hooks()->screenDepth();
}
QImage::Format QEglFSScreen::format() const
{
- return hooks->screenFormat();
+ return QEglFSHooks::hooks()->screenFormat();
+}
+
+QSizeF QEglFSScreen::physicalSize() const
+{
+ return QEglFSHooks::hooks()->physicalScreenSize();
}
QPlatformCursor *QEglFSScreen::cursor() const
diff --git a/src/plugins/platforms/eglfs/qeglfsscreen.h b/src/plugins/platforms/eglfs/qeglfsscreen.h
index 309791d6c2..8d3c5dbaec 100644
--- a/src/plugins/platforms/eglfs/qeglfsscreen.h
+++ b/src/plugins/platforms/eglfs/qeglfsscreen.h
@@ -63,6 +63,8 @@ public:
int depth() const;
QImage::Format format() const;
+ QSizeF physicalSize() const;
+
QPlatformCursor *cursor() const;
EGLDisplay display() const { return m_dpy; }
diff --git a/src/plugins/platforms/eglfs/qeglfswindow.cpp b/src/plugins/platforms/eglfs/qeglfswindow.cpp
index ceb04901c4..68cef6253e 100644
--- a/src/plugins/platforms/eglfs/qeglfswindow.cpp
+++ b/src/plugins/platforms/eglfs/qeglfswindow.cpp
@@ -76,18 +76,36 @@ void QEglFSWindow::create()
return;
if (window()->type() == Qt::Desktop) {
- QRect rect(QPoint(), hooks->screenSize());
+ QRect rect(QPoint(), QEglFSHooks::hooks()->screenSize());
QPlatformWindow::setGeometry(rect);
QWindowSystemInterface::handleGeometryChange(window(), rect);
return;
}
EGLDisplay display = (static_cast<QEglFSScreen *>(window()->screen()->handle()))->display();
- QSurfaceFormat platformFormat = hooks->surfaceFormatFor(window()->requestedFormat());
- EGLConfig config = q_configFromGLFormat(display, platformFormat);
- m_format = q_glFormatFromConfig(display, config);
- m_window = hooks->createNativeWindow(hooks->screenSize(), m_format);
- m_surface = eglCreateWindowSurface(display, config, m_window, NULL);
+ QSurfaceFormat platformFormat = QEglFSHooks::hooks()->surfaceFormatFor(window()->requestedFormat());
+ m_config = QEglFSIntegration::chooseConfig(display, platformFormat);
+ m_format = q_glFormatFromConfig(display, m_config);
+ resetSurface();
+}
+
+void QEglFSWindow::invalidateSurface()
+{
+ // Native surface has been deleted behind our backs
+ m_window = 0;
+ if (m_surface != 0) {
+ EGLDisplay display = (static_cast<QEglFSScreen *>(window()->screen()->handle()))->display();
+ eglDestroySurface(display, m_surface);
+ m_surface = 0;
+ }
+}
+
+void QEglFSWindow::resetSurface()
+{
+ EGLDisplay display = static_cast<QEglFSScreen *>(screen())->display();
+
+ m_window = QEglFSHooks::hooks()->createNativeWindow(QEglFSHooks::hooks()->screenSize(), m_format);
+ m_surface = eglCreateWindowSurface(display, m_config, m_window, NULL);
if (m_surface == EGL_NO_SURFACE) {
EGLint error = eglGetError();
eglTerminate(display);
@@ -98,13 +116,13 @@ void QEglFSWindow::create()
void QEglFSWindow::destroy()
{
if (m_surface) {
- EGLDisplay display = (static_cast<QEglFSScreen *>(window()->screen()->handle()))->display();
+ EGLDisplay display = static_cast<QEglFSScreen *>(screen())->display();
eglDestroySurface(display, m_surface);
m_surface = 0;
}
if (m_window) {
- hooks->destroyNativeWindow(m_window);
+ QEglFSHooks::hooks()->destroyNativeWindow(m_window);
m_window = 0;
}
}
@@ -113,9 +131,8 @@ void QEglFSWindow::setGeometry(const QRect &)
{
// We only support full-screen windows
QRect rect(screen()->availableGeometry());
- QWindowSystemInterface::handleGeometryChange(window(), rect);
-
QPlatformWindow::setGeometry(rect);
+ QWindowSystemInterface::handleGeometryChange(window(), rect);
}
void QEglFSWindow::setWindowState(Qt::WindowState)
diff --git a/src/plugins/platforms/eglfs/qeglfswindow.h b/src/plugins/platforms/eglfs/qeglfswindow.h
index 706bbddd22..a351b4a6f4 100644
--- a/src/plugins/platforms/eglfs/qeglfswindow.h
+++ b/src/plugins/platforms/eglfs/qeglfswindow.h
@@ -65,10 +65,14 @@ public:
void create();
void destroy();
+ virtual void invalidateSurface();
+ virtual void resetSurface();
+
private:
WId m_winid;
EGLSurface m_surface;
EGLNativeWindowType m_window;
+ EGLConfig m_config;
QSurfaceFormat m_format;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/ios.json b/src/plugins/platforms/ios/ios.json
new file mode 100644
index 0000000000..f0b766dae1
--- /dev/null
+++ b/src/plugins/platforms/ios/ios.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "ios" ]
+}
diff --git a/src/plugins/platforms/ios/ios.pro b/src/plugins/platforms/ios/ios.pro
new file mode 100644
index 0000000000..842ff17f1c
--- /dev/null
+++ b/src/plugins/platforms/ios/ios.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+
+SUBDIRS += plugin.pro qtmain.pro
diff --git a/src/plugins/platforms/ios/plugin.mm b/src/plugins/platforms/ios/plugin.mm
new file mode 100644
index 0000000000..a93b6037ad
--- /dev/null
+++ b/src/plugins/platforms/ios/plugin.mm
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qpa/qplatformintegrationplugin.h>
+#include <qpa/qplatformthemeplugin.h>
+#include "qiosintegration.h"
+
+QT_BEGIN_NAMESPACE
+
+class QIOSIntegrationPlugin : public QPlatformIntegrationPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "ios.json")
+ public:
+ QPlatformIntegration *create(const QString&, const QStringList&);
+};
+
+QPlatformIntegration * QIOSIntegrationPlugin::create(const QString& system, const QStringList& paramList)
+{
+ Q_UNUSED(paramList);
+ if (system.toLower() == "ios")
+ return new QIOSIntegration;
+
+ return 0;
+}
+
+QT_END_NAMESPACE
+
+#include "plugin.moc"
+
+Q_IMPORT_PLUGIN(QIOSIntegrationPlugin)
diff --git a/src/plugins/platforms/ios/plugin.pro b/src/plugins/platforms/ios/plugin.pro
new file mode 100644
index 0000000000..591a0a67ed
--- /dev/null
+++ b/src/plugins/platforms/ios/plugin.pro
@@ -0,0 +1,36 @@
+TARGET = qios
+
+PLUGIN_TYPE = platforms
+load(qt_plugin)
+
+QT += core-private gui-private platformsupport-private
+LIBS += -framework UIKit -framework QuartzCore
+
+OBJECTIVE_SOURCES = \
+ plugin.mm \
+ qiosintegration.mm \
+ qioswindow.mm \
+ qiosscreen.mm \
+ qioseventdispatcher.mm \
+ qiosbackingstore.mm \
+ qiosapplicationdelegate.mm \
+ qiosviewcontroller.mm \
+ qioscontext.mm \
+ qiosinputcontext.mm \
+ qiostheme.mm \
+ qiosglobal.mm
+
+HEADERS = \
+ qiosintegration.h \
+ qioswindow.h \
+ qiosscreen.h \
+ qioseventdispatcher.h \
+ qiosbackingstore.h \
+ qiosapplicationdelegate.h \
+ qiosviewcontroller.h \
+ qioscontext.h \
+ qiosinputcontext.h \
+ qiostheme.h \
+ qiosglobal.h
+
+#HEADERS = qiossoftwareinputhandler.h
diff --git a/src/plugins/platforms/ios/qiosapplicationdelegate.h b/src/plugins/platforms/ios/qiosapplicationdelegate.h
new file mode 100644
index 0000000000..442b37f1b3
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosapplicationdelegate.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#import <UIKit/UIKit.h>
+#import <QtGui/QtGui>
+
+@interface QIOSApplicationDelegate : UIResponder <UIApplicationDelegate>
+
+@property (strong, nonatomic) UIWindow *window;
+
+@end
+
+@interface QIOSMainWrapperApplicationDelegate : QIOSApplicationDelegate
+@end
+
diff --git a/src/plugins/platforms/ios/qiosapplicationdelegate.mm b/src/plugins/platforms/ios/qiosapplicationdelegate.mm
new file mode 100644
index 0000000000..41a3fff84f
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosapplicationdelegate.mm
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#import "qiosapplicationdelegate.h"
+#include "qioswindow.h"
+#include <QtCore/QtCore>
+
+@implementation QIOSApplicationDelegate
+
+@synthesize window;
+
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
+{
+ Q_UNUSED(application)
+ Q_UNUSED(launchOptions)
+
+ return YES;
+}
+
+- (void)applicationWillResignActive:(UIApplication *)application
+{
+ Q_UNUSED(application)
+}
+
+- (void)applicationDidEnterBackground:(UIApplication *)application
+{
+ Q_UNUSED(application)
+}
+
+- (void)applicationWillEnterForeground:(UIApplication *)application
+{
+ Q_UNUSED(application)
+ // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
+}
+
+- (void)applicationDidBecomeActive:(UIApplication *)application
+{
+ Q_UNUSED(application)
+ // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
+}
+
+- (void)applicationWillTerminate:(UIApplication *)application
+{
+ Q_UNUSED(application)
+ // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
+}
+
+- (void)dealloc
+{
+ [window release];
+ [super dealloc];
+}
+
+@end
+
+
diff --git a/src/plugins/platforms/ios/qiosbackingstore.h b/src/plugins/platforms/ios/qiosbackingstore.h
new file mode 100644
index 0000000000..c110f0e4d1
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosbackingstore.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QIOSBACKINGSTORE_H
+#define QIOSBACKINGSTORE_H
+
+#include <qpa/qplatformbackingstore.h>
+
+QT_BEGIN_NAMESPACE
+
+class QIOSBackingStore : public QPlatformBackingStore
+{
+public:
+ QIOSBackingStore(QWindow *window);
+ ~QIOSBackingStore();
+
+ QPaintDevice *paintDevice();
+
+ void beginPaint(const QRegion &);
+ void endPaint();
+
+ void flush(QWindow *window, const QRegion &region, const QPoint &offset);
+ void resize(const QSize &size, const QRegion &staticContents);
+
+private:
+ QOpenGLContext *m_context;
+ QPaintDevice *m_device;
+};
+
+QT_END_NAMESPACE
+
+#endif // QIOSBACKINGSTORE_H
diff --git a/src/plugins/platforms/ios/qiosbackingstore.mm b/src/plugins/platforms/ios/qiosbackingstore.mm
new file mode 100644
index 0000000000..566ff3a672
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosbackingstore.mm
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qiosbackingstore.h"
+#include "qioswindow.h"
+
+#include <QtGui/QOpenGLContext>
+#include <QtGui/QOpenGLPaintDevice>
+
+#include <QtDebug>
+
+QIOSBackingStore::QIOSBackingStore(QWindow *window)
+ : QPlatformBackingStore(window)
+ , m_context(new QOpenGLContext)
+ , m_device(0)
+{
+ m_context->setFormat(window->requestedFormat());
+ m_context->setScreen(window->screen());
+ m_context->create();
+}
+
+QIOSBackingStore::~QIOSBackingStore()
+{
+ delete m_context;
+ delete m_device;
+}
+
+void QIOSBackingStore::beginPaint(const QRegion &)
+{
+ // Needed to prevent QOpenGLContext::makeCurrent() from failing
+ window()->setSurfaceType(QSurface::OpenGLSurface);
+
+ m_context->makeCurrent(window());
+
+ static_cast<QOpenGLPaintDevice *>(paintDevice())->setSize(window()->size());
+ QIOSWindow *iosWindow = static_cast<QIOSWindow *>(window()->handle());
+ static_cast<QOpenGLPaintDevice *>(paintDevice())->setSize(window()->size() * iosWindow->devicePixelRatio());
+}
+
+QPaintDevice *QIOSBackingStore::paintDevice()
+{
+ if (!m_device) {
+ QIOSWindow *iosWindow = static_cast<QIOSWindow *>(window()->handle());
+ QOpenGLPaintDevice *openGLDevice = new QOpenGLPaintDevice(window()->size() * iosWindow->devicePixelRatio());
+ openGLDevice->setDevicePixelRatio(iosWindow->devicePixelRatio());
+ m_device = openGLDevice;
+ }
+
+ return m_device;
+}
+
+void QIOSBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
+{
+ Q_UNUSED(region);
+ Q_UNUSED(offset);
+
+ if (window != this->window()) {
+ // We skip flushing raster-based child windows, to avoid the extra cost of copying from the
+ // parent FBO into the child FBO. Since the child is already drawn inside the parent FBO, it
+ // will become visible when flushing the parent. The only case we end up not supporting is if
+ // the child window overlaps a sibling window that's draws using a separate QOpenGLContext.
+ return;
+ }
+ m_context->swapBuffers(window);
+}
+
+void QIOSBackingStore::endPaint()
+{
+ // Calling makeDone() on the context here would be an option,
+ // but is not needed, and would actually add some overhead.
+}
+
+void QIOSBackingStore::resize(const QSize &size, const QRegion &staticContents)
+{
+ Q_UNUSED(staticContents);
+
+ // Resizing the backing store would in our case mean resizing the QWindow,
+ // as we cheat and use an QOpenGLPaintDevice that we target at the window.
+ // That's probably not what the user intended, so we ignore resizes of the
+ // backing store and always keep the paint device's size in sync with the
+ // window size in beginPaint().
+
+ if (size != window()->size())
+ qWarning() << "QIOSBackingStore needs to have the same size as its window";
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qioscontext.h b/src/plugins/platforms/ios/qioscontext.h
new file mode 100644
index 0000000000..082ec4794c
--- /dev/null
+++ b/src/plugins/platforms/ios/qioscontext.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QIOSCONTEXT_H
+#define QIOSCONTEXT_H
+
+#include <qpa/qplatformopenglcontext.h>
+
+@class EAGLContext;
+
+QT_BEGIN_NAMESPACE
+
+class QIOSContext : public QObject, public QPlatformOpenGLContext
+{
+ Q_OBJECT
+
+public:
+ QIOSContext(QOpenGLContext *context);
+ ~QIOSContext();
+
+ QSurfaceFormat format() const;
+
+ void swapBuffers(QPlatformSurface *surface);
+
+ bool makeCurrent(QPlatformSurface *surface);
+ void doneCurrent();
+
+ GLuint defaultFramebufferObject(QPlatformSurface *) const;
+ QFunctionPointer getProcAddress(const QByteArray &procName);
+
+private Q_SLOTS:
+ void windowDestroyed(QObject *object);
+
+private:
+ EAGLContext *m_eaglContext;
+ QSurfaceFormat m_format;
+
+ struct FramebufferObject {
+ GLuint handle;
+ GLuint colorRenderbuffer;
+ GLuint depthRenderbuffer;
+ GLint renderbufferWidth;
+ GLint renderbufferHeight;
+ };
+
+ static void deleteBuffers(const FramebufferObject &framebufferObject);
+
+ mutable QHash<QWindow *, FramebufferObject> m_framebufferObjects;
+};
+
+QT_END_NAMESPACE
+
+#endif // QIOSCONTEXT_H
diff --git a/src/plugins/platforms/ios/qioscontext.mm b/src/plugins/platforms/ios/qioscontext.mm
new file mode 100644
index 0000000000..d3966964e0
--- /dev/null
+++ b/src/plugins/platforms/ios/qioscontext.mm
@@ -0,0 +1,204 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qioscontext.h"
+#include "qioswindow.h"
+
+#include <dlfcn.h>
+
+#include <QtGui/QOpenGlContext>
+
+#import <OpenGLES/EAGL.h>
+#import <QuartzCore/CAEAGLLayer.h>
+
+QIOSContext::QIOSContext(QOpenGLContext *context)
+ : QPlatformOpenGLContext()
+ , m_eaglContext([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2])
+{
+ // Start out with the requested format
+ QSurfaceFormat format = context->format();
+
+ format.setRenderableType(QSurfaceFormat::OpenGLES);
+ format.setMajorVersion(2);
+ format.setMinorVersion(0);
+
+ // Even though iOS internally double-buffers its rendering, we
+ // report single-buffered here since the buffer remains unchanged
+ // when swapping unlesss you manually clear it yourself.
+ format.setSwapBehavior(QSurfaceFormat::SingleBuffer);
+
+ m_format = format;
+}
+
+QIOSContext::~QIOSContext()
+{
+ [EAGLContext setCurrentContext:m_eaglContext];
+
+ foreach (const FramebufferObject &framebufferObject, m_framebufferObjects)
+ deleteBuffers(framebufferObject);
+
+ [EAGLContext setCurrentContext:nil];
+ [m_eaglContext release];
+}
+
+void QIOSContext::deleteBuffers(const FramebufferObject &framebufferObject)
+{
+ if (framebufferObject.handle)
+ glDeleteFramebuffers(1, &framebufferObject.handle);
+ if (framebufferObject.colorRenderbuffer)
+ glDeleteRenderbuffers(1, &framebufferObject.colorRenderbuffer);
+ if (framebufferObject.depthRenderbuffer)
+ glDeleteRenderbuffers(1, &framebufferObject.depthRenderbuffer);
+}
+
+QSurfaceFormat QIOSContext::format() const
+{
+ return m_format;
+}
+
+bool QIOSContext::makeCurrent(QPlatformSurface *surface)
+{
+ Q_ASSERT(surface && surface->surface()->surfaceType() == QSurface::OpenGLSurface);
+
+ [EAGLContext setCurrentContext:m_eaglContext];
+ glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebufferObject(surface));
+
+ return true;
+}
+
+void QIOSContext::doneCurrent()
+{
+ [EAGLContext setCurrentContext:nil];
+}
+
+void QIOSContext::swapBuffers(QPlatformSurface *surface)
+{
+ Q_ASSERT(surface && surface->surface()->surfaceType() == QSurface::OpenGLSurface);
+ Q_ASSERT(surface->surface()->surfaceClass() == QSurface::Window);
+ QWindow *window = static_cast<QWindow *>(surface->surface());
+ Q_ASSERT(m_framebufferObjects.contains(window));
+
+ [EAGLContext setCurrentContext:m_eaglContext];
+ glBindRenderbuffer(GL_RENDERBUFFER, m_framebufferObjects[window].colorRenderbuffer);
+ [m_eaglContext presentRenderbuffer:GL_RENDERBUFFER];
+}
+
+GLuint QIOSContext::defaultFramebufferObject(QPlatformSurface *surface) const
+{
+ Q_ASSERT(surface && surface->surface()->surfaceClass() == QSurface::Window);
+ QWindow *window = static_cast<QWindow *>(surface->surface());
+
+ FramebufferObject &framebufferObject = m_framebufferObjects[window];
+
+ // Set up an FBO for the window if it hasn't been created yet
+ if (!framebufferObject.handle) {
+ [EAGLContext setCurrentContext:m_eaglContext];
+
+ glGenFramebuffers(1, &framebufferObject.handle);
+ glBindFramebuffer(GL_FRAMEBUFFER, framebufferObject.handle);
+
+ glGenRenderbuffers(1, &framebufferObject.colorRenderbuffer);
+ glBindRenderbuffer(GL_RENDERBUFFER, framebufferObject.colorRenderbuffer);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
+ framebufferObject.colorRenderbuffer);
+
+ if (m_format.depthBufferSize() > 0 || m_format.stencilBufferSize() > 0) {
+ glGenRenderbuffers(1, &framebufferObject.depthRenderbuffer);
+ glBindRenderbuffer(GL_RENDERBUFFER, framebufferObject.depthRenderbuffer);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
+ framebufferObject.depthRenderbuffer);
+
+ if (m_format.stencilBufferSize() > 0)
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
+ framebufferObject.depthRenderbuffer);
+ }
+
+ connect(window, SIGNAL(destroyed(QObject*)), this, SLOT(windowDestroyed(QObject*)));
+ }
+
+ // Ensure that the FBO's buffers match the size of the window
+ QIOSWindow *platformWindow = static_cast<QIOSWindow *>(surface);
+ if (framebufferObject.renderbufferWidth != platformWindow->effectiveWidth() ||
+ framebufferObject.renderbufferHeight != platformWindow->effectiveHeight()) {
+
+ glBindRenderbuffer(GL_RENDERBUFFER, framebufferObject.colorRenderbuffer);
+ UIView *view = reinterpret_cast<UIView *>(platformWindow->winId());
+ CAEAGLLayer *layer = static_cast<CAEAGLLayer *>(view.layer);
+ [m_eaglContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:layer];
+
+ glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &framebufferObject.renderbufferWidth);
+ glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &framebufferObject.renderbufferHeight);
+
+ if (framebufferObject.depthRenderbuffer) {
+ glBindRenderbuffer(GL_RENDERBUFFER, framebufferObject.depthRenderbuffer);
+
+ // FIXME: Support more fine grained control over depth/stencil buffer sizes
+ if (m_format.stencilBufferSize() > 0)
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES,
+ framebufferObject.renderbufferWidth, framebufferObject.renderbufferHeight);
+ else
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
+ framebufferObject.renderbufferWidth, framebufferObject.renderbufferHeight);
+ }
+
+ if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
+ NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER));
+ }
+
+ return framebufferObject.handle;
+}
+
+void QIOSContext::windowDestroyed(QObject *object)
+{
+ QWindow *window = static_cast<QWindow *>(object);
+ if (m_framebufferObjects.contains(window)) {
+ deleteBuffers(m_framebufferObjects[window]);
+ m_framebufferObjects.remove(window);
+ }
+}
+
+QFunctionPointer QIOSContext::getProcAddress(const QByteArray& functionName)
+{
+ return reinterpret_cast<QFunctionPointer>(dlsym(RTLD_NEXT, functionName.constData()));
+}
+
+#include "moc_qioscontext.cpp"
+
diff --git a/src/plugins/platforms/ios/qioseventdispatcher.h b/src/plugins/platforms/ios/qioseventdispatcher.h
new file mode 100644
index 0000000000..53a75618ce
--- /dev/null
+++ b/src/plugins/platforms/ios/qioseventdispatcher.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/****************************************************************************
+**
+** Copyright (c) 2007-2008, Apple, Inc.
+**
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+**
+** * Redistributions of source code must retain the above copyright notice,
+** this list of conditions and the following disclaimer.
+**
+** * Redistributions in binary form must reproduce the above copyright notice,
+** this list of conditions and the following disclaimer in the documentation
+** and/or other materials provided with the distribution.
+**
+** * Neither the name of Apple, Inc. nor the names of its contributors
+** may be used to endorse or promote products derived from this software
+** without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
+****************************************************************************/
+
+#ifndef QEVENTDISPATCHER_IOS_P_H
+#define QEVENTDISPATCHER_IOS_P_H
+
+#include <QtCore/qabstracteventdispatcher.h>
+#include <QtCore/private/qtimerinfo_unix_p.h>
+#include <QtPlatformSupport/private/qcfsocketnotifier_p.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+QT_BEGIN_NAMESPACE
+
+class QIOSEventDispatcher : public QAbstractEventDispatcher
+{
+ Q_OBJECT
+
+public:
+ explicit QIOSEventDispatcher(QObject *parent = 0);
+ ~QIOSEventDispatcher();
+
+ bool processEvents(QEventLoop::ProcessEventsFlags flags);
+ bool hasPendingEvents();
+
+ void registerSocketNotifier(QSocketNotifier *notifier);
+ void unregisterSocketNotifier(QSocketNotifier *notifier);
+
+ void registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object);
+ bool unregisterTimer(int timerId);
+ bool unregisterTimers(QObject *object);
+ QList<QAbstractEventDispatcher::TimerInfo> registeredTimers(QObject *object) const;
+
+ int remainingTime(int timerId);
+
+ void wakeUp();
+ void interrupt();
+ void flush();
+
+private:
+ bool m_interrupted;
+
+ CFRunLoopSourceRef m_postedEventsRunLoopSource;
+ CFRunLoopSourceRef m_blockingTimerRunLoopSource;
+
+ QTimerInfoList m_timerInfoList;
+ CFRunLoopTimerRef m_runLoopTimerRef;
+
+ QCFSocketNotifier m_cfSocketNotifier;
+
+ void processPostedEvents();
+ void maybeStartCFRunLoopTimer();
+ void maybeStopCFRunLoopTimer();
+
+ static void postedEventsRunLoopCallback(void *info);
+ static void nonBlockingTimerRunLoopCallback(CFRunLoopTimerRef, void *info);
+ static void blockingTimerRunLoopCallback(void *info);
+};
+
+QT_END_NAMESPACE
+
+#endif // QEVENTDISPATCHER_IOS_P_H
diff --git a/src/plugins/platforms/ios/qioseventdispatcher.mm b/src/plugins/platforms/ios/qioseventdispatcher.mm
new file mode 100644
index 0000000000..e9bf039047
--- /dev/null
+++ b/src/plugins/platforms/ios/qioseventdispatcher.mm
@@ -0,0 +1,322 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qioseventdispatcher.h"
+#import "qiosapplicationdelegate.h"
+#include <qdebug.h>
+#include <qpa/qwindowsysteminterface.h>
+#include <QtCore/QThread>
+#include <QtCore/private/qcoreapplication_p.h>
+#include <UIKit/UIApplication.h>
+
+QT_BEGIN_NAMESPACE
+QT_USE_NAMESPACE
+
+static Boolean runLoopSourceEqualCallback(const void *info1, const void *info2)
+{
+ return info1 == info2;
+}
+
+void QIOSEventDispatcher::postedEventsRunLoopCallback(void *info)
+{
+ QIOSEventDispatcher *self = static_cast<QIOSEventDispatcher *>(info);
+ self->processPostedEvents();
+}
+
+void QIOSEventDispatcher::nonBlockingTimerRunLoopCallback(CFRunLoopTimerRef, void *info)
+{
+ // The (one and only) CFRunLoopTimer has fired, which means that at least
+ // one QTimer should now fire as well. Note that CFRunLoopTimer's callback will
+ // never recurse. So if the app starts a new QEventLoop within this callback, other
+ // timers will stop working. The work-around is to forward the callback to a
+ // dedicated CFRunLoopSource that can recurse:
+ QIOSEventDispatcher *self = static_cast<QIOSEventDispatcher *>(info);
+ CFRunLoopSourceSignal(self->m_blockingTimerRunLoopSource);
+}
+
+void QIOSEventDispatcher::blockingTimerRunLoopCallback(void *info)
+{
+ // TODO:
+ // We also need to block this new timer source
+ // along with the posted event source when calling processEvents()
+ // "manually" to prevent livelock deep in CFRunLoop.
+
+ QIOSEventDispatcher *self = static_cast<QIOSEventDispatcher *>(info);
+ self->m_timerInfoList.activateTimers();
+ self->maybeStartCFRunLoopTimer();
+}
+
+void QIOSEventDispatcher::maybeStartCFRunLoopTimer()
+{
+ // Find out when the next registered timer should fire, and schedule
+ // runLoopTimer accordingly. If the runLoopTimer does not yet exist, and
+ // at least one timer is registered, start by creating the timer:
+ if (m_timerInfoList.isEmpty()) {
+ Q_ASSERT(m_runLoopTimerRef == 0);
+ return;
+ }
+
+ CFAbsoluteTime ttf = CFAbsoluteTimeGetCurrent();
+ CFTimeInterval interval;
+
+ if (m_runLoopTimerRef == 0) {
+ // start the CFRunLoopTimer
+ CFTimeInterval oneyear = CFTimeInterval(3600. * 24. * 365.);
+
+ // calculate when the next timer should fire:
+ struct timespec tv;
+ if (m_timerInfoList.timerWait(tv)) {
+ interval = qMax(tv.tv_sec + tv.tv_nsec / 1000000000., 0.0000001);
+ } else {
+ // this shouldn't really happen, but in case it does, set the timer
+ // to fire a some point in the distant future:
+ interval = oneyear;
+ }
+
+ ttf += interval;
+ CFRunLoopTimerContext info = { 0, this, 0, 0, 0 };
+ // create the timer with a large interval, as recommended by the CFRunLoopTimerSetNextFireDate()
+ // documentation, since we will adjust the timer's time-to-fire as needed to keep Qt timers working
+ m_runLoopTimerRef = CFRunLoopTimerCreate(0, ttf, oneyear, 0, 0, QIOSEventDispatcher::nonBlockingTimerRunLoopCallback, &info);
+ Q_ASSERT(m_runLoopTimerRef != 0);
+
+ CFRunLoopAddTimer(CFRunLoopGetMain(), m_runLoopTimerRef, kCFRunLoopCommonModes);
+ } else {
+ struct timespec tv;
+ // Calculate when the next timer should fire:
+ if (m_timerInfoList.timerWait(tv)) {
+ interval = qMax(tv.tv_sec + tv.tv_nsec / 1000000000., 0.0000001);
+ } else {
+ // no timers can fire, but we cannot stop the CFRunLoopTimer, set the timer to fire at some
+ // point in the distant future (the timer interval is one year)
+ interval = CFRunLoopTimerGetInterval(m_runLoopTimerRef);
+ }
+
+ ttf += interval;
+ CFRunLoopTimerSetNextFireDate(m_runLoopTimerRef, ttf);
+ }
+}
+
+void QIOSEventDispatcher::maybeStopCFRunLoopTimer()
+{
+ if (m_runLoopTimerRef == 0)
+ return;
+
+ CFRunLoopTimerInvalidate(m_runLoopTimerRef);
+ CFRelease(m_runLoopTimerRef);
+ m_runLoopTimerRef = 0;
+}
+
+void QIOSEventDispatcher::processPostedEvents()
+{
+ QWindowSystemInterface::sendWindowSystemEvents(QEventLoop::AllEvents);
+}
+
+QIOSEventDispatcher::QIOSEventDispatcher(QObject *parent)
+ : QAbstractEventDispatcher(parent)
+ , m_interrupted(false)
+ , m_runLoopTimerRef(0)
+{
+ m_cfSocketNotifier.setHostEventDispatcher(this);
+
+ CFRunLoopRef mainRunLoop = CFRunLoopGetMain();
+ CFRunLoopSourceContext context;
+ bzero(&context, sizeof(CFRunLoopSourceContext));
+ context.equal = runLoopSourceEqualCallback;
+ context.info = this;
+
+ // source used to handle timers:
+ context.perform = QIOSEventDispatcher::blockingTimerRunLoopCallback;
+ m_blockingTimerRunLoopSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
+ Q_ASSERT(m_blockingTimerRunLoopSource);
+ CFRunLoopAddSource(mainRunLoop, m_blockingTimerRunLoopSource, kCFRunLoopCommonModes);
+
+ // source used to handle posted events:
+ context.perform = QIOSEventDispatcher::postedEventsRunLoopCallback;
+ m_postedEventsRunLoopSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
+ Q_ASSERT(m_postedEventsRunLoopSource);
+ CFRunLoopAddSource(mainRunLoop, m_postedEventsRunLoopSource, kCFRunLoopCommonModes);
+}
+
+QIOSEventDispatcher::~QIOSEventDispatcher()
+{
+ CFRunLoopRef mainRunLoop = CFRunLoopGetMain();
+ CFRunLoopRemoveSource(mainRunLoop, m_postedEventsRunLoopSource, kCFRunLoopCommonModes);
+ CFRelease(m_postedEventsRunLoopSource);
+
+ qDeleteAll(m_timerInfoList);
+ maybeStopCFRunLoopTimer();
+ CFRunLoopRemoveSource(CFRunLoopGetMain(), m_blockingTimerRunLoopSource, kCFRunLoopCommonModes);
+ CFRelease(m_blockingTimerRunLoopSource);
+
+ m_cfSocketNotifier.removeSocketNotifiers();
+}
+
+bool QIOSEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
+{
+ m_interrupted = false;
+ bool eventsProcessed = false;
+
+ bool excludeUserEvents = flags & QEventLoop::ExcludeUserInputEvents;
+ bool execFlagSet = (flags & QEventLoop::DialogExec) || (flags & QEventLoop::EventLoopExec);
+ bool useExecMode = execFlagSet && !excludeUserEvents;
+
+ if (useExecMode) {
+ NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
+ while ([runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]] && !m_interrupted);
+ eventsProcessed = true;
+ } else {
+ if (!(flags & QEventLoop::WaitForMoreEvents))
+ wakeUp();
+ eventsProcessed = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
+ }
+ return eventsProcessed;
+}
+
+bool QIOSEventDispatcher::hasPendingEvents()
+{
+ qDebug() << __FUNCTION__ << "not implemented";
+ return false;
+}
+
+void QIOSEventDispatcher::registerSocketNotifier(QSocketNotifier *notifier)
+{
+ m_cfSocketNotifier.registerSocketNotifier(notifier);
+}
+
+void QIOSEventDispatcher::unregisterSocketNotifier(QSocketNotifier *notifier)
+{
+ m_cfSocketNotifier.unregisterSocketNotifier(notifier);
+}
+
+void QIOSEventDispatcher::registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *obj)
+{
+#ifndef QT_NO_DEBUG
+ if (timerId < 1 || interval < 0 || !obj) {
+ qWarning("QIOSEventDispatcher::registerTimer: invalid arguments");
+ return;
+ } else if (obj->thread() != thread() || thread() != QThread::currentThread()) {
+ qWarning("QIOSEventDispatcher: timers cannot be started from another thread");
+ return;
+ }
+#endif
+
+ m_timerInfoList.registerTimer(timerId, interval, timerType, obj);
+ maybeStartCFRunLoopTimer();
+}
+
+bool QIOSEventDispatcher::unregisterTimer(int timerId)
+{
+#ifndef QT_NO_DEBUG
+ if (timerId < 1) {
+ qWarning("QIOSEventDispatcher::unregisterTimer: invalid argument");
+ return false;
+ } else if (thread() != QThread::currentThread()) {
+ qWarning("QObject::killTimer: timers cannot be stopped from another thread");
+ return false;
+ }
+#endif
+
+ bool returnValue = m_timerInfoList.unregisterTimer(timerId);
+ m_timerInfoList.isEmpty() ? maybeStopCFRunLoopTimer() : maybeStartCFRunLoopTimer();
+ return returnValue;
+}
+
+bool QIOSEventDispatcher::unregisterTimers(QObject *object)
+{
+#ifndef QT_NO_DEBUG
+ if (!object) {
+ qWarning("QIOSEventDispatcher::unregisterTimers: invalid argument");
+ return false;
+ } else if (object->thread() != thread() || thread() != QThread::currentThread()) {
+ qWarning("QObject::killTimers: timers cannot be stopped from another thread");
+ return false;
+ }
+#endif
+
+ bool returnValue = m_timerInfoList.unregisterTimers(object);
+ m_timerInfoList.isEmpty() ? maybeStopCFRunLoopTimer() : maybeStartCFRunLoopTimer();
+ return returnValue;
+}
+
+QList<QAbstractEventDispatcher::TimerInfo> QIOSEventDispatcher::registeredTimers(QObject *object) const
+{
+#ifndef QT_NO_DEBUG
+ if (!object) {
+ qWarning("QIOSEventDispatcher:registeredTimers: invalid argument");
+ return QList<TimerInfo>();
+ }
+#endif
+
+ return m_timerInfoList.registeredTimers(object);
+}
+
+int QIOSEventDispatcher::remainingTime(int timerId)
+{
+#ifndef QT_NO_DEBUG
+ if (timerId < 1) {
+ qWarning("QIOSEventDispatcher::remainingTime: invalid argument");
+ return -1;
+ }
+#endif
+
+ return m_timerInfoList.timerRemainingTime(timerId);
+}
+
+void QIOSEventDispatcher::wakeUp()
+{
+ CFRunLoopSourceSignal(m_postedEventsRunLoopSource);
+ CFRunLoopWakeUp(CFRunLoopGetMain());
+}
+
+void QIOSEventDispatcher::interrupt()
+{
+ wakeUp();
+ m_interrupted = true;
+}
+
+void QIOSEventDispatcher::flush()
+{
+ // X11 only.
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/plugins/platforms/ios/qiosglobal.h b/src/plugins/platforms/ios/qiosglobal.h
new file mode 100644
index 0000000000..3be9f8bb21
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosglobal.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QIOSGLOBAL_H
+#define QIOSGLOBAL_H
+
+#import <UIKit/UIKit.h>
+#include <QtCore/QtCore>
+
+@class QIOSViewController;
+
+QT_BEGIN_NAMESPACE
+
+class QPlatformScreen;
+
+bool isQtApplication();
+QIOSViewController *rootViewController();
+
+CGRect toCGRect(const QRect &rect);
+QRect fromCGRect(const CGRect &rect);
+CGPoint toCGPoint(const QPoint &point);
+QPoint fromCGPoint(const CGPoint &point);
+Qt::ScreenOrientation toQtScreenOrientation(UIDeviceOrientation uiDeviceOrientation);
+UIDeviceOrientation fromQtScreenOrientation(Qt::ScreenOrientation qtOrientation);
+QRect fromPortraitToPrimary(const QRect &rect, QPlatformScreen *screen);
+
+QT_END_NAMESPACE
+
+#endif // QIOSGLOBAL_H
diff --git a/src/plugins/platforms/ios/qiosglobal.mm b/src/plugins/platforms/ios/qiosglobal.mm
new file mode 100644
index 0000000000..5860078372
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosglobal.mm
@@ -0,0 +1,144 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qiosglobal.h"
+#include "qiosapplicationdelegate.h"
+#include "qiosviewcontroller.h"
+#include "qiosscreen.h"
+
+QT_BEGIN_NAMESPACE
+
+bool isQtApplication()
+{
+ // Returns true if the plugin is in full control of the whole application. This means
+ // that we control the application delegate and the top view controller, and can take
+ // actions that impacts all parts of the application. The opposite means that we are
+ // embedded inside a native iOS application, and should be more focused on playing along
+ // with native UIControls, and less inclined to change structures that lies outside the
+ // scope of our QWindows/UIViews.
+ static bool isQt = ([[UIApplication sharedApplication].delegate isKindOfClass:[QIOSApplicationDelegate class]]);
+ return isQt;
+}
+
+QIOSViewController *rootViewController()
+{
+ static QIOSViewController *c = isQtApplication() ?
+ static_cast<QIOSViewController *>([UIApplication sharedApplication].delegate.window.rootViewController) : nil;
+ return c;
+}
+
+CGRect toCGRect(const QRect &rect)
+{
+ return CGRectMake(rect.x(), rect.y(), rect.width(), rect.height());
+}
+
+QRect fromCGRect(const CGRect &rect)
+{
+ return QRect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
+}
+
+CGPoint toCGPoint(const QPoint &point)
+{
+ return CGPointMake(point.x(), point.y());
+}
+
+QPoint fromCGPoint(const CGPoint &point)
+{
+ return QPoint(point.x, point.y);
+}
+
+Qt::ScreenOrientation toQtScreenOrientation(UIDeviceOrientation uiDeviceOrientation)
+{
+ Qt::ScreenOrientation qtOrientation;
+ switch (uiDeviceOrientation) {
+ case UIDeviceOrientationPortraitUpsideDown:
+ qtOrientation = Qt::InvertedPortraitOrientation;
+ break;
+ case UIDeviceOrientationLandscapeLeft:
+ qtOrientation = Qt::InvertedLandscapeOrientation;
+ break;
+ case UIDeviceOrientationLandscapeRight:
+ qtOrientation = Qt::LandscapeOrientation;
+ break;
+ case UIDeviceOrientationFaceUp:
+ case UIDeviceOrientationFaceDown:
+ qtOrientation = static_cast<Qt::ScreenOrientation>(-1); // not supported ATM.
+ break;
+ default:
+ qtOrientation = Qt::PortraitOrientation;
+ break;
+ }
+ return qtOrientation;
+}
+
+UIDeviceOrientation fromQtScreenOrientation(Qt::ScreenOrientation qtOrientation)
+{
+ UIDeviceOrientation uiOrientation;
+ switch (qtOrientation) {
+ case Qt::LandscapeOrientation:
+ uiOrientation = UIDeviceOrientationLandscapeRight;
+ break;
+ case Qt::InvertedLandscapeOrientation:
+ uiOrientation = UIDeviceOrientationLandscapeLeft;
+ break;
+ case Qt::InvertedPortraitOrientation:
+ uiOrientation = UIDeviceOrientationPortraitUpsideDown;
+ break;
+ case Qt::PrimaryOrientation:
+ case Qt::PortraitOrientation:
+ default:
+ uiOrientation = UIDeviceOrientationPortrait;
+ break;
+ }
+ return uiOrientation;
+}
+
+QRect fromPortraitToPrimary(const QRect &rect, QPlatformScreen *screen)
+{
+ // UIScreen is always in portrait. Use this function to convert CGRects
+ // aligned with UIScreen into whatever is the current orientation of QScreen.
+ QRect geometry = screen->geometry();
+ return geometry.width() < geometry.height() ? rect
+ : QRect(rect.y(), geometry.width() - rect.width() - rect.x(), rect.height(), rect.width());
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/plugins/platforms/ios/qiosinputcontext.h b/src/plugins/platforms/ios/qiosinputcontext.h
new file mode 100644
index 0000000000..176ad05733
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosinputcontext.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QIOSINPUTCONTEXT_H
+#define QIOSINPUTCONTEXT_H
+
+#include <UIKit/UIKit.h>
+
+#include <qpa/qplatforminputcontext.h>
+
+QT_BEGIN_NAMESPACE
+
+@class QIOSKeyboardListener;
+
+class QIOSInputContext : public QPlatformInputContext
+{
+public:
+ QIOSInputContext();
+ ~QIOSInputContext();
+
+ QRectF keyboardRect() const;
+ void showInputPanel();
+ void hideInputPanel();
+ bool isInputPanelVisible() const;
+
+ void focusViewChanged(UIView *view);
+
+private:
+ QIOSKeyboardListener *m_keyboardListener;
+ UIView *m_focusView;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm
new file mode 100644
index 0000000000..1d3ab12de9
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosinputcontext.mm
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qiosglobal.h"
+#include "qiosinputcontext.h"
+#include "qioswindow.h"
+#include <QGuiApplication>
+
+@interface QIOSKeyboardListener : NSObject {
+@public
+ QIOSInputContext *m_context;
+ BOOL m_keyboardVisible;
+ QRectF m_keyboardRect;
+}
+@end
+
+@implementation QIOSKeyboardListener
+
+- (id)initWithQIOSInputContext:(QIOSInputContext *)context
+{
+ self = [super init];
+ if (self) {
+ m_context = context;
+ m_keyboardVisible = NO;
+ // After the keyboard became undockable (iOS5), UIKeyboardWillShow/UIKeyboardWillHide
+ // no longer works for all cases. So listen to keyboard frame changes instead:
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(keyboardDidChangeFrame:)
+ name:@"UIKeyboardDidChangeFrameNotification" object:nil];
+ }
+ return self;
+}
+
+- (void) dealloc
+{
+ [[NSNotificationCenter defaultCenter]
+ removeObserver:self
+ name:@"UIKeyboardDidChangeFrameNotification" object:nil];
+ [super dealloc];
+}
+
+- (void) keyboardDidChangeFrame:(NSNotification *)notification
+{
+ CGRect frame;
+ [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&frame];
+
+ m_keyboardRect = fromPortraitToPrimary(fromCGRect(frame), QGuiApplication::primaryScreen()->handle());
+ m_context->emitKeyboardRectChanged();
+
+ BOOL visible = CGRectIntersectsRect(frame, [UIScreen mainScreen].bounds);
+ if (m_keyboardVisible != visible) {
+ m_keyboardVisible = visible;
+ m_context->emitInputPanelVisibleChanged();
+ }
+}
+
+@end
+
+QIOSInputContext::QIOSInputContext()
+ : QPlatformInputContext()
+ , m_keyboardListener([[QIOSKeyboardListener alloc] initWithQIOSInputContext:this])
+ , m_focusView(0)
+{
+}
+
+QIOSInputContext::~QIOSInputContext()
+{
+ [m_keyboardListener release];
+ [m_focusView release];
+}
+
+QRectF QIOSInputContext::keyboardRect() const
+{
+ return m_keyboardListener->m_keyboardRect;
+}
+
+void QIOSInputContext::showInputPanel()
+{
+ // Documentation tells that one should call (and recall, if necessary) becomeFirstResponder/resignFirstResponder
+ // to show/hide the keyboard. This is slightly inconvenient, since there exist no API to get the current first
+ // responder. Rather than searching for it from the top, we let the active QIOSWindow tell us which view to use.
+ // Note that Qt will forward keyevents to whichever QObject that needs it, regardless of which UIView the input
+ // actually came from. So in this respect, we're undermining iOS' responder chain.
+ [m_focusView becomeFirstResponder];
+}
+
+void QIOSInputContext::hideInputPanel()
+{
+ [m_focusView resignFirstResponder];
+}
+
+bool QIOSInputContext::isInputPanelVisible() const
+{
+ return m_keyboardListener->m_keyboardVisible;
+}
+
+void QIOSInputContext::focusViewChanged(UIView *view)
+{
+ if ([m_focusView isFirstResponder])
+ [view becomeFirstResponder];
+ [m_focusView release];
+ m_focusView = [view retain];
+}
diff --git a/src/plugins/platforms/ios/qiosintegration.h b/src/plugins/platforms/ios/qiosintegration.h
new file mode 100644
index 0000000000..329a0a3d9b
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosintegration.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPLATFORMINTEGRATION_UIKIT_H
+#define QPLATFORMINTEGRATION_UIKIT_H
+
+#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformnativeinterface.h>
+#include <qpa/qwindowsysteminterface.h>
+
+QT_BEGIN_NAMESPACE
+
+class QIOSIntegration : public QPlatformIntegration, public QPlatformNativeInterface
+{
+public:
+ QIOSIntegration();
+ ~QIOSIntegration();
+
+ bool hasCapability(Capability cap) const;
+
+ QPlatformWindow *createPlatformWindow(QWindow *window) const;
+ QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const;
+
+ QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const;
+
+ QPlatformFontDatabase *fontDatabase() const;
+ QPlatformInputContext *inputContext() const;
+
+ QVariant styleHint(StyleHint hint) const;
+
+ QStringList themeNames() const;
+ QPlatformTheme *createPlatformTheme(const QString &name) const;
+
+ QAbstractEventDispatcher *guiThreadEventDispatcher() const;
+ QPlatformNativeInterface *nativeInterface() const;
+
+ void *nativeResourceForWindow(const QByteArray &resource, QWindow *window);
+
+ QTouchDevice *touchDevice();
+private:
+ QPlatformFontDatabase *m_fontDatabase;
+ QPlatformInputContext *m_inputContext;
+ QPlatformScreen *m_screen;
+ QTouchDevice *m_touchDevice;
+};
+
+QT_END_NAMESPACE
+
+#endif
+
diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm
new file mode 100644
index 0000000000..c7541c3e38
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosintegration.mm
@@ -0,0 +1,180 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qiosintegration.h"
+#include "qioswindow.h"
+#include "qiosbackingstore.h"
+#include "qiosscreen.h"
+#include "qioseventdispatcher.h"
+#include "qioscontext.h"
+#include "qiosinputcontext.h"
+#include "qiostheme.h"
+
+#include <QtPlatformSupport/private/qcoretextfontdatabase_p.h>
+
+#include <QtDebug>
+
+QT_BEGIN_NAMESPACE
+
+QIOSIntegration::QIOSIntegration()
+ : m_fontDatabase(new QCoreTextFontDatabase)
+ , m_inputContext(new QIOSInputContext)
+ , m_screen(new QIOSScreen(QIOSScreen::MainScreen))
+{
+ if (![UIApplication sharedApplication]) {
+ qWarning()
+ << "Error: You are creating QApplication before calling UIApplicationMain.\n"
+ << "If you are writing a native iOS application, and only want to use Qt for\n"
+ << "parts of the application, a good place to create QApplication is from within\n"
+ << "'applicationDidFinishLaunching' inside your UIApplication delegate.\n"
+ << "If you instead create a cross-platform Qt application and do not intend to call\n"
+ << "UIApplicationMain, you need to link in libqtmain.a, and substitute main with qt_main.\n"
+ << "This is normally done automatically by qmake.\n";
+ exit(-1);
+ }
+
+ screenAdded(m_screen);
+
+ m_touchDevice = new QTouchDevice;
+ m_touchDevice->setType(QTouchDevice::TouchScreen);
+ m_touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::NormalizedPosition);
+ QWindowSystemInterface::registerTouchDevice(m_touchDevice);
+}
+
+QIOSIntegration::~QIOSIntegration()
+{
+ delete m_touchDevice;
+}
+
+bool QIOSIntegration::hasCapability(Capability cap) const
+{
+ switch (cap) {
+ case OpenGL:
+ return true;
+ case MultipleWindows:
+ return true;
+ default:
+ return QPlatformIntegration::hasCapability(cap);
+ }
+}
+
+QPlatformWindow *QIOSIntegration::createPlatformWindow(QWindow *window) const
+{
+ return new QIOSWindow(window);
+}
+
+// Used when the QWindow's surface type is set by the client to QSurface::RasterSurface
+QPlatformBackingStore *QIOSIntegration::createPlatformBackingStore(QWindow *window) const
+{
+ return new QIOSBackingStore(window);
+}
+
+// Used when the QWindow's surface type is set by the client to QSurface::OpenGLSurface
+QPlatformOpenGLContext *QIOSIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
+{
+ Q_UNUSED(context);
+ return new QIOSContext(context);
+}
+
+QAbstractEventDispatcher *QIOSIntegration::guiThreadEventDispatcher() const
+{
+ return new QIOSEventDispatcher();
+}
+
+QPlatformFontDatabase * QIOSIntegration::fontDatabase() const
+{
+ return m_fontDatabase;
+}
+
+QPlatformInputContext *QIOSIntegration::inputContext() const
+{
+ return m_inputContext;
+}
+
+QVariant QIOSIntegration::styleHint(StyleHint hint) const
+{
+ switch (hint) {
+ case ShowIsFullScreen:
+ return true;
+ default:
+ return QPlatformIntegration::styleHint(hint);
+ }
+}
+
+QStringList QIOSIntegration::themeNames() const
+{
+ return QStringList(QLatin1String(QIOSTheme::name));
+}
+
+QPlatformTheme *QIOSIntegration::createPlatformTheme(const QString &name) const
+{
+ if (name == QLatin1String(QIOSTheme::name))
+ return new QIOSTheme;
+
+ return QPlatformIntegration::createPlatformTheme(name);
+}
+
+QPlatformNativeInterface *QIOSIntegration::nativeInterface() const
+{
+ return const_cast<QIOSIntegration *>(this);
+}
+
+void *QIOSIntegration::nativeResourceForWindow(const QByteArray &resource, QWindow *window)
+{
+ if (!window || !window->handle())
+ return 0;
+
+ QByteArray lowerCaseResource = resource.toLower();
+
+ QIOSWindow *platformWindow = static_cast<QIOSWindow *>(window->handle());
+
+ if (lowerCaseResource == "uiview")
+ return reinterpret_cast<void *>(platformWindow->winId());
+
+ return 0;
+}
+
+QTouchDevice *QIOSIntegration::touchDevice()
+{
+ return m_touchDevice;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiosscreen.h b/src/plugins/platforms/ios/qiosscreen.h
new file mode 100644
index 0000000000..40c7a3ccf7
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosscreen.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QIOSSCREEN_H
+#define QIOSSCREEN_H
+
+#include <UIKit/UIKit.h>
+
+#include <qpa/qplatformscreen.h>
+
+@class QIOSOrientationListener;
+
+QT_BEGIN_NAMESPACE
+
+class QIOSScreen : public QPlatformScreen
+{
+public:
+ QIOSScreen(unsigned int screenIndex);
+ ~QIOSScreen();
+
+ enum ScreenIndex { MainScreen = 0 };
+
+ QRect geometry() const;
+ QRect availableGeometry() const;
+ int depth() const;
+ QImage::Format format() const;
+ QSizeF physicalSize() const;
+ QDpi logicalDpi() const;
+ qreal devicePixelRatio() const;
+
+ Qt::ScreenOrientation nativeOrientation() const;
+ Qt::ScreenOrientation orientation() const;
+ void setOrientationUpdateMask(Qt::ScreenOrientations mask);
+
+ UIScreen *uiScreen() const;
+
+ void setPrimaryOrientation(Qt::ScreenOrientation orientation);
+
+private:
+ UIScreen *m_uiScreen;
+ QRect m_geometry;
+ QRect m_availableGeometry;
+ int m_depth;
+ QSizeF m_physicalSize;
+ QIOSOrientationListener *m_orientationListener;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/ios/qiosscreen.mm b/src/plugins/platforms/ios/qiosscreen.mm
new file mode 100644
index 0000000000..3265ed8e37
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosscreen.mm
@@ -0,0 +1,238 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qiosglobal.h"
+#include "qiosscreen.h"
+#include "qioswindow.h"
+#include <qpa/qwindowsysteminterface.h>
+#include "qiosapplicationdelegate.h"
+#include "qiosviewcontroller.h"
+
+#include <sys/sysctl.h>
+
+@interface QIOSOrientationListener : NSObject {
+ @public
+ QIOSScreen *m_screen;
+}
+- (id) initWithQIOSScreen:(QIOSScreen *)screen;
+@end
+
+@implementation QIOSOrientationListener
+
+- (id) initWithQIOSScreen:(QIOSScreen *)screen
+{
+ self = [super init];
+ if (self) {
+ m_screen = screen;
+ [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(orientationChanged:)
+ name:@"UIDeviceOrientationDidChangeNotification" object:nil];
+ }
+ return self;
+}
+
+- (void) dealloc
+{
+ [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
+ [[NSNotificationCenter defaultCenter]
+ removeObserver:self
+ name:@"UIDeviceOrientationDidChangeNotification" object:nil];
+ [super dealloc];
+}
+
+- (void) orientationChanged:(NSNotification *)notification
+{
+ Q_UNUSED(notification);
+ Qt::ScreenOrientation orientation = toQtScreenOrientation([UIDevice currentDevice].orientation);
+ if (orientation != -1)
+ QWindowSystemInterface::handleScreenOrientationChange(m_screen->screen(), orientation);
+}
+
+@end
+
+/*!
+ Returns the model identifier of the device.
+
+ When running under the simulator, the identifier will not
+ match the simulated device, but will be x86_64 or i386.
+*/
+static QString deviceModelIdentifier()
+{
+ static const char key[] = "hw.machine";
+
+ size_t size;
+ sysctlbyname(key, NULL, &size, NULL, 0);
+
+ char value[size];
+ sysctlbyname(key, &value, &size, NULL, 0);
+
+ return QString::fromLatin1(value);
+}
+
+QIOSScreen::QIOSScreen(unsigned int screenIndex)
+ : QPlatformScreen()
+ , m_uiScreen([[UIScreen screens] objectAtIndex:qMin(screenIndex, [[UIScreen screens] count] - 1)])
+ , m_orientationListener(0)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ QString deviceIdentifier = deviceModelIdentifier();
+
+ if (deviceIdentifier == QStringLiteral("iPhone2,1") /* iPhone 3GS */
+ || deviceIdentifier == QStringLiteral("iPod3,1") /* iPod touch 3G */) {
+ m_depth = 18;
+ } else {
+ m_depth = 24;
+ }
+
+ int unscaledDpi = 163; // Regular iPhone DPI
+ if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad
+ && deviceIdentifier != QStringLiteral("iPad2,5") /* iPad Mini */) {
+ unscaledDpi = 132;
+ };
+
+ CGRect bounds = [m_uiScreen bounds];
+ m_geometry = QRect(bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
+
+ CGRect frame = m_uiScreen.applicationFrame;
+ m_availableGeometry = QRect(frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
+
+ const qreal millimetersPerInch = 25.4;
+ m_physicalSize = QSizeF(m_geometry.size()) / unscaledDpi * millimetersPerInch;
+
+ if (isQtApplication()) {
+ // When in a non-mixed environment, let QScreen follow the current interface orientation:
+ setPrimaryOrientation(toQtScreenOrientation(rootViewController().interfaceOrientation));
+ }
+
+ [pool release];
+}
+
+QIOSScreen::~QIOSScreen()
+{
+ [m_orientationListener release];
+}
+
+QRect QIOSScreen::geometry() const
+{
+ return m_geometry;
+}
+
+QRect QIOSScreen::availableGeometry() const
+{
+ return m_availableGeometry;
+}
+
+int QIOSScreen::depth() const
+{
+ return m_depth;
+}
+
+QImage::Format QIOSScreen::format() const
+{
+ return QImage::Format_ARGB32_Premultiplied;
+}
+
+QSizeF QIOSScreen::physicalSize() const
+{
+ return m_physicalSize;
+}
+
+QDpi QIOSScreen::logicalDpi() const
+{
+ return QDpi(72, 72);
+}
+
+qreal QIOSScreen::devicePixelRatio() const
+{
+ return [m_uiScreen scale];
+}
+
+Qt::ScreenOrientation QIOSScreen::nativeOrientation() const
+{
+ return Qt::PortraitOrientation;
+}
+
+Qt::ScreenOrientation QIOSScreen::orientation() const
+{
+ return toQtScreenOrientation([UIDevice currentDevice].orientation);
+}
+
+void QIOSScreen::setOrientationUpdateMask(Qt::ScreenOrientations mask)
+{
+ if (m_orientationListener && mask == Qt::PrimaryOrientation) {
+ [m_orientationListener release];
+ m_orientationListener = 0;
+ } else if (!m_orientationListener) {
+ m_orientationListener = [[QIOSOrientationListener alloc] initWithQIOSScreen:this];
+ }
+}
+
+void QIOSScreen::setPrimaryOrientation(Qt::ScreenOrientation orientation)
+{
+ // Note that UIScreen never changes orientation, but QScreen should. To work around
+ // this, we let QIOSViewController call us whenever interface orientation changes, and
+ // use that as primary orientation. After all, the viewcontrollers geometry is what we
+ // place QWindows on top of. A problem with this approach is that QIOSViewController is
+ // not in use in a mixed environment, which results in no change to primary orientation.
+ // We see that as acceptable since Qt should most likely not interfere with orientation
+ // for that case anyway.
+ bool portrait = screen()->isPortrait(orientation);
+ if (portrait && m_geometry.width() < m_geometry.height())
+ return;
+
+ // Switching portrait/landscape means swapping width/height (and adjusting x/y):
+ m_geometry = QRect(0, 0, m_geometry.height(), m_geometry.width());
+ m_physicalSize = QSizeF(m_physicalSize.height(), m_physicalSize.width());
+ m_availableGeometry = fromPortraitToPrimary(fromCGRect(m_uiScreen.applicationFrame), this);
+
+ QWindowSystemInterface::handleScreenGeometryChange(screen(), m_geometry);
+ QWindowSystemInterface::handleScreenAvailableGeometryChange(screen(), m_availableGeometry);
+}
+
+UIScreen *QIOSScreen::uiScreen() const
+{
+ return m_uiScreen;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiossoftwareinputhandler.h b/src/plugins/platforms/ios/qiossoftwareinputhandler.h
new file mode 100644
index 0000000000..5dad6b8d86
--- /dev/null
+++ b/src/plugins/platforms/ios/qiossoftwareinputhandler.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QIOSSOFTWAREINPUTHANDLER_H
+#define QIOSSOFTWAREINPUTHANDLER_H
+
+#include <QtCore/QObject>
+#include <QtCore/QPointer>
+#include <QtWidgets/QWidget>
+
+QT_BEGIN_NAMESPACE
+
+class QIOSSoftwareInputHandler : public QObject
+{
+ Q_OBJECT
+
+public:
+ QIOSSoftwareInputHandler() : m_CurrentFocusWidget(0), m_CurrentFocusObject(0) {}
+ bool eventFilter(QObject *obj, QEvent *event);
+
+private slots:
+ void activeFocusChanged(bool focus);
+
+private:
+ bool closeSoftwareInputPanel(QWidget *widget);
+
+ QPointer<QWidget> m_currentFocusWidget;
+ QPointer<QObject> m_currentFocusObject;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/ios/qiostheme.h b/src/plugins/platforms/ios/qiostheme.h
new file mode 100644
index 0000000000..5ccbcac710
--- /dev/null
+++ b/src/plugins/platforms/ios/qiostheme.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QIOSTHEME_H
+#define QIOSTHEME_H
+
+#include <qpa/qplatformtheme.h>
+
+QT_BEGIN_NAMESPACE
+
+class QIOSTheme : public QPlatformTheme
+{
+public:
+ QIOSTheme();
+ ~QIOSTheme();
+
+ QVariant themeHint(ThemeHint hint) const;
+
+ const QFont *font(Font type = SystemFont) const;
+
+ static const char *name;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/ios/qiostheme.mm b/src/plugins/platforms/ios/qiostheme.mm
new file mode 100644
index 0000000000..f98781f8a7
--- /dev/null
+++ b/src/plugins/platforms/ios/qiostheme.mm
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qiostheme.h"
+
+#include <QtCore/QStringList>
+#include <QtCore/QVariant>
+
+#include <QtGui/QFont>
+
+#include <UIKit/UIFont.h>
+#include <UIKit/UIInterface.h>
+
+QT_BEGIN_NAMESPACE
+
+const char *QIOSTheme::name = "ios";
+
+QIOSTheme::QIOSTheme()
+{
+}
+
+QIOSTheme::~QIOSTheme()
+{
+}
+
+QVariant QIOSTheme::themeHint(ThemeHint hint) const
+{
+ switch (hint) {
+ case QPlatformTheme::StyleNames:
+ return QStringList(QStringLiteral("fusion"));
+ default:
+ return QPlatformTheme::themeHint(hint);
+ }
+}
+
+const QFont *QIOSTheme::font(Font type) const
+{
+ static QHash<QPlatformTheme::Font, QFont *> fonts;
+ if (fonts.isEmpty()) {
+ // The real system font on iOS is '.Helvetica Neue UI', as returned by both [UIFont systemFontOfSize]
+ // and CTFontCreateUIFontForLanguage(kCTFontSystemFontType, ...), but this font is not included when
+ // populating the available fonts in QCoreTextFontDatabase::populateFontDatabase(), since the font
+ // is internal to iOS and not supposed to be used by applications. We could potentially add this
+ // font to the font-database, but it would then show up when enumerating user fonts from Qt
+ // applications since we don't have a flag in Qt to mark a font as a private system font.
+ // For now we hard-code the font to Helvetica, which should be very close to the actual
+ // system font.
+ QLatin1String systemFontFamilyName("Helvetica");
+ fonts.insert(QPlatformTheme::SystemFont, new QFont(systemFontFamilyName, [UIFont systemFontSize]));
+ fonts.insert(QPlatformTheme::SmallFont, new QFont(systemFontFamilyName, [UIFont smallSystemFontSize]));
+ fonts.insert(QPlatformTheme::LabelFont, new QFont(systemFontFamilyName, [UIFont labelFontSize]));
+ fonts.insert(QPlatformTheme::PushButtonFont, new QFont(systemFontFamilyName, [UIFont buttonFontSize]));
+ }
+
+ return fonts.value(type, 0);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiosviewcontroller.h b/src/plugins/platforms/ios/qiosviewcontroller.h
new file mode 100644
index 0000000000..d5a61cb3f4
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosviewcontroller.h
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#import <UIKit/UIKit.h>
+
+@interface QIOSViewController : UIViewController
+@end
+
diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm
new file mode 100644
index 0000000000..c52bfd7345
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosviewcontroller.mm
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#import "qiosviewcontroller.h"
+
+#include <QtGui/QGuiApplication>
+#include <QtGui/QScreen>
+#include "qiosscreen.h"
+#include "qiosglobal.h"
+
+@implementation QIOSViewController
+
+- (void)viewDidLoad
+{
+#ifdef QT_DEBUG
+ if (!self.nibName)
+ self.view.backgroundColor = [UIColor magentaColor];
+#endif
+}
+
+-(BOOL)shouldAutorotate
+{
+ // For now we assume that if the application doesn't listen to orientation
+ // updates it means it would like to enable auto-rotation, and vice versa.
+ if (QGuiApplication *guiApp = qobject_cast<QGuiApplication *>(qApp))
+ return !guiApp->primaryScreen()->orientationUpdateMask();
+ else
+ return YES; // Startup case: QGuiApplication is not ready yet.
+
+ // FIXME: Investigate a proper Qt API for auto-rotation and orientation locking
+}
+
+-(NSUInteger)supportedInterfaceOrientations
+{
+ // We need to tell iOS that we support all orientations in order to set
+ // status bar orientation when application content orientation changes.
+ return UIInterfaceOrientationMaskAll;
+}
+
+- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
+{
+ Q_UNUSED(duration);
+ Qt::ScreenOrientation orientation = toQtScreenOrientation(toInterfaceOrientation);
+ if (orientation == -1)
+ return;
+
+ QIOSScreen *qiosScreen = static_cast<QIOSScreen *>(QGuiApplication::primaryScreen()->handle());
+ qiosScreen->setPrimaryOrientation(orientation);
+}
+
+@end
+
diff --git a/src/plugins/platforms/ios/qioswindow.h b/src/plugins/platforms/ios/qioswindow.h
new file mode 100644
index 0000000000..cefb6f9388
--- /dev/null
+++ b/src/plugins/platforms/ios/qioswindow.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QIOSWINDOW_H
+#define QIOSWINDOW_H
+
+#include <qpa/qplatformwindow.h>
+#include <qpa/qwindowsysteminterface.h>
+
+#import <UIKit/UIKit.h>
+
+class QIOSContext;
+class QIOSWindow;
+
+@interface UIView (QIOS)
+@property(readonly) QWindow *qwindow;
+@end
+
+QT_BEGIN_NAMESPACE
+
+class QIOSWindow : public QPlatformWindow
+{
+public:
+ explicit QIOSWindow(QWindow *window);
+ ~QIOSWindow();
+
+ void setGeometry(const QRect &rect);
+
+ void setWindowState(Qt::WindowState state);
+ void setParent(const QPlatformWindow *window);
+ void handleContentOrientationChange(Qt::ScreenOrientation orientation);
+ void setVisible(bool visible);
+
+ void raise() { raiseOrLower(true); }
+ void lower() { raiseOrLower(false); }
+ void requestActivateWindow();
+
+ qreal devicePixelRatio() const;
+ int effectiveWidth() const;
+ int effectiveHeight() const;
+
+ WId winId() const { return WId(m_view); };
+
+ QList<QWindowSystemInterface::TouchPoint> &touchPoints() { return m_touchPoints; }
+ QHash<UITouch *, int> &activeTouches() { return m_activeTouches; }
+ int &touchId() { return m_touchId; }
+
+private:
+ UIView *m_view;
+ QList<QWindowSystemInterface::TouchPoint> m_touchPoints;
+ QHash<UITouch *, int> m_activeTouches;
+ int m_touchId;
+
+ QRect m_requestedGeometry;
+ int m_windowLevel;
+ qreal m_devicePixelRatio;
+
+ void raiseOrLower(bool raise);
+ void updateWindowLevel();
+ bool blockedByModal();
+};
+
+QT_END_NAMESPACE
+
+#endif // QIOSWINDOW_H
diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm
new file mode 100644
index 0000000000..e4fb5e2e1c
--- /dev/null
+++ b/src/plugins/platforms/ios/qioswindow.mm
@@ -0,0 +1,523 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qiosglobal.h"
+#include "qioswindow.h"
+#include "qioscontext.h"
+#include "qiosinputcontext.h"
+#include "qiosscreen.h"
+#include "qiosapplicationdelegate.h"
+#include "qiosviewcontroller.h"
+#include "qiosintegration.h"
+#include <QtGui/private/qguiapplication_p.h>
+#include <qpa/qplatformintegration.h>
+
+#import <QuartzCore/CAEAGLLayer.h>
+
+#include <QtGui/QKeyEvent>
+#include <qpa/qwindowsysteminterface.h>
+
+#include <QtDebug>
+
+@interface EAGLView : UIView <UIKeyInput>
+{
+@public
+ UITextAutocapitalizationType autocapitalizationType;
+ UITextAutocorrectionType autocorrectionType;
+ BOOL enablesReturnKeyAutomatically;
+ UIKeyboardAppearance keyboardAppearance;
+ UIKeyboardType keyboardType;
+ UIReturnKeyType returnKeyType;
+ BOOL secureTextEntry;
+ QIOSWindow *m_qioswindow;
+}
+
+@property(nonatomic) UITextAutocapitalizationType autocapitalizationType;
+@property(nonatomic) UITextAutocorrectionType autocorrectionType;
+@property(nonatomic) BOOL enablesReturnKeyAutomatically;
+@property(nonatomic) UIKeyboardAppearance keyboardAppearance;
+@property(nonatomic) UIKeyboardType keyboardType;
+@property(nonatomic) UIReturnKeyType returnKeyType;
+@property(nonatomic, getter=isSecureTextEntry) BOOL secureTextEntry;
+
+@end
+
+@implementation EAGLView
+
++ (Class)layerClass
+{
+ return [CAEAGLLayer class];
+}
+
+-(id)initWithQIOSWindow:(QIOSWindow *)window
+{
+ if (self = [self initWithFrame:toCGRect(window->geometry())])
+ m_qioswindow = window;
+
+ return self;
+}
+
+- (id)initWithFrame:(CGRect)frame
+{
+ if ((self = [super initWithFrame:frame])) {
+ // Set up EAGL layer
+ CAEAGLLayer *eaglLayer = static_cast<CAEAGLLayer *>(self.layer);
+ eaglLayer.opaque = TRUE;
+ eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSNumber numberWithBool:YES], kEAGLDrawablePropertyRetainedBacking,
+ kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
+
+ // Set up text input
+ autocapitalizationType = UITextAutocapitalizationTypeNone;
+ autocorrectionType = UITextAutocorrectionTypeNo;
+ enablesReturnKeyAutomatically = NO;
+ keyboardAppearance = UIKeyboardAppearanceDefault;
+ keyboardType = UIKeyboardTypeDefault;
+ returnKeyType = UIReturnKeyDone;
+ secureTextEntry = NO;
+
+ if (isQtApplication())
+ self.hidden = YES;
+
+ self.multipleTouchEnabled = YES;
+ }
+
+ return self;
+}
+
+- (void)layoutSubviews
+{
+ // This method is the de facto way to know that view has been resized,
+ // or otherwise needs invalidation of its buffers. Note though that we
+ // do not get this callback when the view just changes its position, so
+ // the position of our QWindow (and platform window) will only get updated
+ // when the size is also changed.
+
+ if (!CGAffineTransformIsIdentity(self.transform))
+ qWarning() << m_qioswindow->window()
+ << "is backed by a UIView that has a transform set. This is not supported.";
+
+ QRect geometry = fromCGRect(self.frame);
+ m_qioswindow->QPlatformWindow::setGeometry(geometry);
+ QWindowSystemInterface::handleGeometryChange(m_qioswindow->window(), geometry);
+
+ // If we have a new size here we need to resize the FBO's corresponding buffers,
+ // but we defer that to when the application calls makeCurrent.
+
+ [super layoutSubviews];
+}
+
+/*
+ Touch handling:
+
+ UIKit generates [Began -> Moved -> Ended] event sequences for
+ each touch point. The iOS plugin tracks each individual
+ touch and assigns it an id for use by Qt. The id counter is
+ incremented on each began and decrement as follows:
+ 1) by one when the most recent touch ends.
+ 2) to zero when all touches ends.
+
+ The TouchPoint list is reused between events.
+*/
+- (void)updateTouchList:(NSSet *)touches withState:(Qt::TouchPointState)state
+{
+ QList<QWindowSystemInterface::TouchPoint> &touchPoints = m_qioswindow->touchPoints();
+ QHash<UITouch *, int> &activeTouches = m_qioswindow->activeTouches();
+
+ // Mark all touch points as stationary
+ for (QList<QWindowSystemInterface::TouchPoint>::iterator it = touchPoints.begin(); it != touchPoints.end(); ++it)
+ it->state = Qt::TouchPointStationary;
+
+ // Update changed touch points with the new state
+ for (UITouch *touch in touches) {
+ const int touchId = activeTouches.value(touch);
+ QWindowSystemInterface::TouchPoint &touchPoint = touchPoints[touchId];
+ touchPoint.state = state;
+ if (state == Qt::TouchPointPressed)
+ touchPoint.pressure = 1.0;
+ else if (state == Qt::TouchPointReleased)
+ touchPoint.pressure = 0.0;
+
+ // Set position
+ QRect viewGeometry = fromCGRect(self.frame);
+ QPoint touchViewLocation = fromCGPoint([touch locationInView:self]);
+ QPoint touchScreenLocation = touchViewLocation + viewGeometry.topLeft();
+ touchPoint.area = QRectF(touchScreenLocation , QSize(0, 0));
+
+ CGSize fullscreenSize = self.window.rootViewController.view.bounds.size;
+ touchPoint.normalPosition = QPointF(touchScreenLocation.x() / fullscreenSize.width, touchScreenLocation.y() / fullscreenSize.height);
+ }
+}
+
+- (void) sendTouchEventWithTimestamp:(ulong)timeStamp
+{
+ // Send touch event synchronously
+ QIOSIntegration *iosIntegration = static_cast<QIOSIntegration *>(QGuiApplicationPrivate::platformIntegration());
+ QWindowSystemInterface::handleTouchEvent(m_qioswindow->window(), timeStamp,
+ iosIntegration->touchDevice(), m_qioswindow->touchPoints());
+ QWindowSystemInterface::flushWindowSystemEvents();
+}
+
+- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ QWindow *window = m_qioswindow->window();
+
+ // Transfer focus to the touched window:
+ if (window != QGuiApplication::focusWindow())
+ m_qioswindow->requestActivateWindow();
+
+ // Track Cocoa touch id to Qt touch id. The UITouch pointer is constant
+ // for the touch duration.
+ QHash<UITouch *, int> &activeTouches = m_qioswindow->activeTouches();
+ QList<QWindowSystemInterface::TouchPoint> &touchPoints = m_qioswindow->touchPoints();
+ for (UITouch *touch in touches)
+ activeTouches.insert(touch, m_qioswindow->touchId()++);
+
+ // Create new touch points if needed.
+ int newTouchPointsNeeded = m_qioswindow->touchId() - touchPoints.count();
+ for (int i = 0; i < newTouchPointsNeeded; ++i) {
+ QWindowSystemInterface::TouchPoint touchPoint;
+ touchPoint.id = touchPoints.count(); // id is the index in the touchPoints list.
+ touchPoints.append(touchPoint);
+ }
+
+ [self updateTouchList:touches withState:Qt::TouchPointPressed];
+ [self sendTouchEventWithTimestamp:ulong(event.timestamp * 1000)];
+}
+
+- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ [self updateTouchList:touches withState:Qt::TouchPointMoved];
+ [self sendTouchEventWithTimestamp:ulong(event.timestamp * 1000)];
+}
+
+- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ [self updateTouchList:touches withState:Qt::TouchPointReleased];
+ [self sendTouchEventWithTimestamp:ulong(event.timestamp * 1000)];
+
+ // Remove ended touch points from the active set (event processing has completed at this point)
+ QHash<UITouch *, int> &activeTouches = m_qioswindow->activeTouches();
+ for (UITouch *touch in touches) {
+ int id = activeTouches.take(touch);
+
+ // If this touch is the most recent touch we can reuse its id
+ if (id == m_qioswindow->touchId() - 1)
+ --m_qioswindow->touchId();
+ }
+
+ // Reset the touch id when there are no more active touches
+ if (activeTouches.isEmpty())
+ m_qioswindow->touchId() = 0;
+}
+
+- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ Q_UNUSED(touches) // ### can a subset of the active touches be cancelled?
+
+ // Clear current touch points
+ m_qioswindow->activeTouches().clear();
+ m_qioswindow->touchId() = 0;
+
+ // Send cancel touch event synchronously
+ QIOSIntegration *iosIntegration = static_cast<QIOSIntegration *>(QGuiApplicationPrivate::platformIntegration());
+ QWindowSystemInterface::handleTouchCancelEvent(m_qioswindow->window(), ulong(event.timestamp * 1000), iosIntegration->touchDevice());
+ QWindowSystemInterface::flushWindowSystemEvents();
+}
+
+@synthesize autocapitalizationType;
+@synthesize autocorrectionType;
+@synthesize enablesReturnKeyAutomatically;
+@synthesize keyboardAppearance;
+@synthesize keyboardType;
+@synthesize returnKeyType;
+@synthesize secureTextEntry;
+
+- (BOOL)canBecomeFirstResponder
+{
+ return YES;
+}
+
+- (BOOL)hasText
+{
+ return YES;
+}
+
+- (void)insertText:(NSString *)text
+{
+ QString string = QString::fromUtf8([text UTF8String]);
+ int key = 0;
+ if ([text isEqualToString:@"\n"])
+ key = (int)Qt::Key_Return;
+
+ // Send key event to window system interface
+ QWindowSystemInterface::handleKeyEvent(
+ 0, QEvent::KeyPress, key, Qt::NoModifier, string, false, int(string.length()));
+ QWindowSystemInterface::handleKeyEvent(
+ 0, QEvent::KeyRelease, key, Qt::NoModifier, string, false, int(string.length()));
+}
+
+- (void)deleteBackward
+{
+ // Send key event to window system interface
+ QWindowSystemInterface::handleKeyEvent(
+ 0, QEvent::KeyPress, (int)Qt::Key_Backspace, Qt::NoModifier);
+ QWindowSystemInterface::handleKeyEvent(
+ 0, QEvent::KeyRelease, (int)Qt::Key_Backspace, Qt::NoModifier);
+}
+
+@end
+
+@implementation UIView (QIOS)
+
+- (QWindow *)qwindow
+{
+ if ([self isKindOfClass:[EAGLView class]])
+ return static_cast<EAGLView *>(self)->m_qioswindow->window();
+ return nil;
+}
+
+@end
+
+QT_BEGIN_NAMESPACE
+
+QIOSWindow::QIOSWindow(QWindow *window)
+ : QPlatformWindow(window)
+ , m_view([[EAGLView alloc] initWithQIOSWindow:this])
+ , m_touchId(0)
+ , m_requestedGeometry(QPlatformWindow::geometry())
+ , m_windowLevel(0)
+ , m_devicePixelRatio(1.0)
+{
+ setParent(parent());
+ setWindowState(window->windowState());
+
+ // Retina support: get screen scale factor and set it in the content view.
+ // This will make framebufferObject() create a 2x frame buffer on retina
+ // displays. Also set m_devicePixelRatio which is used for scaling the
+ // paint device.
+ if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)] == YES) {
+ m_devicePixelRatio = [[UIScreen mainScreen] scale];
+ [m_view setContentScaleFactor: m_devicePixelRatio];
+ }
+}
+
+QIOSWindow::~QIOSWindow()
+{
+ [m_view removeFromSuperview];
+ [m_view release];
+}
+
+bool QIOSWindow::blockedByModal()
+{
+ QWindow *modalWindow = QGuiApplication::modalWindow();
+ return modalWindow && modalWindow != window();
+}
+
+void QIOSWindow::setVisible(bool visible)
+{
+ QPlatformWindow::setVisible(visible);
+ m_view.hidden = !visible;
+
+ if (!isQtApplication())
+ return;
+
+ // Since iOS doesn't do window management the way a Qt application
+ // expects, we need to raise and activate windows ourselves:
+ if (visible)
+ updateWindowLevel();
+
+ if (blockedByModal()) {
+ if (visible)
+ raise();
+ return;
+ }
+
+ if (visible) {
+ requestActivateWindow();
+ } else {
+ // Activate top-most visible QWindow:
+ NSArray *subviews = rootViewController().view.subviews;
+ for (int i = int(subviews.count) - 1; i >= 0; --i) {
+ UIView *view = [subviews objectAtIndex:i];
+ if (!view.hidden) {
+ if (QWindow *window = view.qwindow) {
+ static_cast<QIOSWindow *>(window->handle())->requestActivateWindow();
+ break;
+ }
+ }
+ }
+ }
+}
+
+void QIOSWindow::setGeometry(const QRect &rect)
+{
+ // If the window is in fullscreen, just bookkeep the requested
+ // geometry in case the window goes into Qt::WindowNoState later:
+ m_requestedGeometry = rect;
+ if (window()->windowState() & (Qt::WindowMaximized | Qt::WindowFullScreen))
+ return;
+
+ // Since we don't support transformations on the UIView, we can set the frame
+ // directly and let UIKit deal with translating that into bounds and center.
+ // Changing the size of the view will end up in a call to -[EAGLView layoutSubviews]
+ // which will update QWindowSystemInterface with the new size.
+ m_view.frame = toCGRect(rect);
+}
+
+void QIOSWindow::setWindowState(Qt::WindowState state)
+{
+ // FIXME: Figure out where or how we should disable/enable the statusbar.
+ // Perhaps setting QWindow to maximized should also mean that we'll show
+ // the statusbar, and vice versa for fullscreen?
+
+ switch (state) {
+ case Qt::WindowMaximized:
+ case Qt::WindowFullScreen: {
+ // Since UIScreen does not take orientation into account when
+ // reporting geometry, we need to look at the top view instead:
+ CGSize fullscreenSize = m_view.window.rootViewController.view.bounds.size;
+ m_view.frame = CGRectMake(0, 0, fullscreenSize.width, fullscreenSize.height);
+ m_view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+ break; }
+ default:
+ m_view.frame = toCGRect(m_requestedGeometry);
+ m_view.autoresizingMask = UIViewAutoresizingNone;
+ break;
+ }
+}
+
+void QIOSWindow::setParent(const QPlatformWindow *parentWindow)
+{
+ if (parentWindow) {
+ UIView *parentView = reinterpret_cast<UIView *>(parentWindow->winId());
+ [parentView addSubview:m_view];
+ } else if (isQtApplication()) {
+ [rootViewController().view addSubview:m_view];
+ }
+}
+
+void QIOSWindow::requestActivateWindow()
+{
+ // Note that several windows can be active at the same time if they exist in the same
+ // hierarchy (transient children). But only one window can be QGuiApplication::focusWindow().
+ // Dispite the name, 'requestActivateWindow' means raise and transfer focus to the window:
+ if (blockedByModal())
+ return;
+
+ raise();
+ QPlatformInputContext *context = QGuiApplicationPrivate::platformIntegration()->inputContext();
+ static_cast<QIOSInputContext *>(context)->focusViewChanged(m_view);
+ QPlatformWindow::requestActivateWindow();
+}
+
+void QIOSWindow::raiseOrLower(bool raise)
+{
+ // Re-insert m_view at the correct index among its sibling views
+ // (QWindows) according to their current m_windowLevel:
+ if (!isQtApplication())
+ return;
+
+ NSArray *subviews = m_view.superview.subviews;
+ if (subviews.count == 1)
+ return;
+
+ for (int i = int(subviews.count) - 1; i >= 0; --i) {
+ UIView *view = static_cast<UIView *>([subviews objectAtIndex:i]);
+ if (view.hidden || view == m_view)
+ continue;
+ int level = static_cast<QIOSWindow *>(view.qwindow->handle())->m_windowLevel;
+ if (m_windowLevel > level || (raise && m_windowLevel == level)) {
+ [m_view.superview insertSubview:m_view aboveSubview:view];
+ return;
+ }
+ }
+ [m_view.superview insertSubview:m_view atIndex:0];
+}
+
+void QIOSWindow::updateWindowLevel()
+{
+ Qt::WindowType type = static_cast<Qt::WindowType>(int(window()->flags() & Qt::WindowType_Mask));
+
+ if (type == Qt::ToolTip)
+ m_windowLevel = 120;
+ else if (window()->flags() & Qt::WindowStaysOnTopHint)
+ m_windowLevel = 100;
+ else if (window()->isModal())
+ m_windowLevel = 30;
+ else if (type & Qt::Popup & ~Qt::Window)
+ m_windowLevel = 20;
+ else if (type == Qt::Tool)
+ m_windowLevel = 10;
+ else
+ m_windowLevel = 0;
+
+ // A window should be in at least the same m_windowLevel as its parent:
+ QWindow *transientParent = window()->transientParent();
+ QIOSWindow *transientParentWindow = transientParent ? static_cast<QIOSWindow *>(transientParent->handle()) : 0;
+ if (transientParentWindow)
+ m_windowLevel = qMax(transientParentWindow->m_windowLevel, m_windowLevel);
+}
+
+void QIOSWindow::handleContentOrientationChange(Qt::ScreenOrientation orientation)
+{
+ // Keep the status bar in sync with content orientation. This will ensure
+ // that the task bar (and associated gestures) are aligned correctly:
+ UIDeviceOrientation uiOrientation = fromQtScreenOrientation(orientation);
+ [[UIApplication sharedApplication] setStatusBarOrientation:uiOrientation animated:NO];
+}
+
+qreal QIOSWindow::devicePixelRatio() const
+{
+ return m_devicePixelRatio;
+}
+
+int QIOSWindow::effectiveWidth() const
+{
+ return geometry().width() * m_devicePixelRatio;
+}
+
+int QIOSWindow::effectiveHeight() const
+{
+ return geometry().height() * m_devicePixelRatio;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qtmain.mm b/src/plugins/platforms/ios/qtmain.mm
new file mode 100644
index 0000000000..916224f936
--- /dev/null
+++ b/src/plugins/platforms/ios/qtmain.mm
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qiosapplicationdelegate.h"
+#include "qiosviewcontroller.h"
+
+int main(int argc, char *argv[])
+{
+ @autoreleasepool {
+ return UIApplicationMain(argc, argv, nil, NSStringFromClass([QIOSMainWrapperApplicationDelegate class]));
+ }
+}
+
+extern int qt_main(int argc, char *argv[]);
+
+@implementation QIOSMainWrapperApplicationDelegate
+
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
+{
+ self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
+ self.window.rootViewController = [[[QIOSViewController alloc] init] autorelease];
+
+#ifdef QT_DEBUG
+ self.window.backgroundColor = [UIColor cyanColor];
+#endif
+
+ [self.window makeKeyAndVisible];
+
+ // We schedule the main-redirection for the next eventloop pass so that we
+ // can return from this function and let UIApplicationMain finish its job.
+ [NSTimer scheduledTimerWithTimeInterval:.01f target:self
+ selector:@selector(runUserMain) userInfo:nil repeats:NO];
+
+ if ([QIOSApplicationDelegate instancesRespondToSelector:_cmd])
+ return [super application:application didFinishLaunchingWithOptions:launchOptions];
+ else
+ return YES;
+}
+
+- (void)runUserMain
+{
+ NSArray *arguments = [[NSProcessInfo processInfo] arguments];
+ int argc = arguments.count;
+ char **argv = new char*[argc];
+ for (int i = 0; i < argc; ++i) {
+ NSString *arg = [arguments objectAtIndex:i];
+ argv[i] = reinterpret_cast<char *>(malloc([arg lengthOfBytesUsingEncoding:[NSString defaultCStringEncoding]]));
+ strcpy(argv[i], [arg cStringUsingEncoding:[NSString defaultCStringEncoding]]);
+ }
+
+ qt_main(argc, argv);
+ delete[] argv;
+}
+
+@end
diff --git a/src/plugins/platforms/ios/qtmain.pro b/src/plugins/platforms/ios/qtmain.pro
new file mode 100644
index 0000000000..cbcb272217
--- /dev/null
+++ b/src/plugins/platforms/ios/qtmain.pro
@@ -0,0 +1,8 @@
+TARGET = qiosmain
+
+PLUGIN_TYPE = platforms
+load(qt_plugin)
+
+QT += gui-private
+
+OBJECTIVE_SOURCES = qtmain.mm
diff --git a/src/plugins/platforms/kms/kms.pro b/src/plugins/platforms/kms/kms.pro
index c0300e0960..711cf9e5c7 100644
--- a/src/plugins/platforms/kms/kms.pro
+++ b/src/plugins/platforms/kms/kms.pro
@@ -4,9 +4,10 @@ PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = QKmsIntegrationPlugin
load(qt_plugin)
-QT += core-private gui-private platformsupport-private opengl-private
+QT += core-private gui-private platformsupport-private
+qtHaveModule(opengl):QT += opengl-private
-DEFINES += MESA_EGL_NO_X11_HEADERS
+DEFINES += MESA_EGL_NO_X11_HEADERS __GBM__
CONFIG += link_pkgconfig egl qpa/genericunixfontdatabase
diff --git a/src/plugins/platforms/kms/qkmscursor.cpp b/src/plugins/platforms/kms/qkmscursor.cpp
index d9345ce89b..da5dc9bb06 100644
--- a/src/plugins/platforms/kms/qkmscursor.cpp
+++ b/src/plugins/platforms/kms/qkmscursor.cpp
@@ -48,22 +48,17 @@ QT_BEGIN_NAMESPACE
QKmsCursor::QKmsCursor(QKmsScreen *screen)
: m_screen(screen),
m_graphicsBufferManager(screen->device()->gbmDevice()),
+ m_cursorBufferObject(gbm_bo_create(m_graphicsBufferManager, 64, 64, GBM_FORMAT_ARGB8888,
+ GBM_BO_USE_CURSOR_64X64|GBM_BO_USE_WRITE)),
+ m_cursorImage(new QPlatformCursorImage(0, 0, 0, 0, 0, 0)),
m_moved(false)
{
- gbm_bo *bo = gbm_bo_create(m_graphicsBufferManager, 64, 64,
- GBM_BO_FORMAT_ARGB8888,
- GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_RENDERING);
-
- m_eglImage = eglCreateImageKHR(m_screen->device()->eglDisplay(), 0, EGL_NATIVE_PIXMAP_KHR,
- bo, 0);
- gbm_bo_destroy(bo);
- m_cursorImage = new QPlatformCursorImage(0, 0, 0, 0, 0, 0);
}
QKmsCursor::~QKmsCursor()
{
- drmModeSetCursor(m_screen->device()->fd(), m_screen->crtcId(),
- 0, 0, 0);
+ drmModeSetCursor(m_screen->device()->fd(), m_screen->crtcId(), 0, 0, 0);
+ gbm_bo_destroy(m_cursorBufferObject);
}
void QKmsCursor::pointerEvent(const QMouseEvent &event)
@@ -78,57 +73,30 @@ void QKmsCursor::pointerEvent(const QMouseEvent &event)
}
}
-void QKmsCursor::changeCursor(QCursor *widgetCursor, QWindow *window)
+void QKmsCursor::changeCursor(QCursor *windowCursor, QWindow *window)
{
Q_UNUSED(window)
if (!m_moved)
drmModeMoveCursor(m_screen->device()->fd(), m_screen->crtcId(), 0, 0);
- if (widgetCursor->shape() != Qt::BitmapCursor) {
- m_cursorImage->set(widgetCursor->shape());
- } else {
- m_cursorImage->set(widgetCursor->pixmap().toImage(),
- widgetCursor->hotSpot().x(),
- widgetCursor->hotSpot().y());
- }
-
- if ((m_cursorImage->image()->width() > 64) || (m_cursorImage->image()->width() > 64)) {
- qWarning("failed to set hardware cursor: larger than 64x64.");
- return;
- }
-
- QImage cursorImage = m_cursorImage->image()->convertToFormat(QImage::Format_RGB32);
-
- //Load cursor image into EGLImage
- GLuint cursorTexture;
- glGenTextures(1, &cursorTexture);
- glBindTexture(GL_TEXTURE_2D, cursorTexture);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
-
- //TODO: Format may be wrong here, need a color icon to test.
- if (m_eglImage != EGL_NO_IMAGE_KHR) {
- glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_eglImage);
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, cursorImage.width(),
- cursorImage.height(), GL_RGBA,
- GL_UNSIGNED_BYTE, cursorImage.constBits());
+ const Qt::CursorShape newShape = windowCursor ? windowCursor->shape() : Qt::ArrowCursor;
+ if (newShape != Qt::BitmapCursor) {
+ m_cursorImage->set(newShape);
} else {
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cursorImage.width(),
- cursorImage.height(), 0, GL_RGBA,
- GL_UNSIGNED_BYTE, cursorImage.constBits());
+ m_cursorImage->set(windowCursor->pixmap().toImage(),
+ windowCursor->hotSpot().x(),
+ windowCursor->hotSpot().y());
}
- //EGLImage needs to contain sprite before calling this:
- gbm_bo *bufferObject = gbm_bo_import(m_graphicsBufferManager, GBM_BO_IMPORT_EGL_IMAGE,
- m_eglImage, GBM_BO_USE_CURSOR_64X64);
- quint32 handle = gbm_bo_get_handle(bufferObject).u32;
+ if ((m_cursorImage->image()->width() > 64) || (m_cursorImage->image()->width() > 64))
+ qWarning("Warning: cursor larger than 64x64; only 64x64 pixels will be shown.");
- gbm_bo_destroy(bufferObject);
+ QImage cursorImage = m_cursorImage->image()->
+ convertToFormat(QImage::Format_ARGB32).copy(0, 0, 64, 64);
+ gbm_bo_write(m_cursorBufferObject, cursorImage.constBits(), cursorImage.byteCount());
+ quint32 handle = gbm_bo_get_handle(m_cursorBufferObject).u32;
int status = drmModeSetCursor(m_screen->device()->fd(),
m_screen->crtcId(), handle, 64, 64);
diff --git a/src/plugins/platforms/kms/qkmscursor.h b/src/plugins/platforms/kms/qkmscursor.h
index fda47ebedc..ee65b01e36 100644
--- a/src/plugins/platforms/kms/qkmscursor.h
+++ b/src/plugins/platforms/kms/qkmscursor.h
@@ -44,15 +44,11 @@
#include <qpa/qplatformcursor.h>
-#define EGL_EGLEXT_PROTOTYPES 1
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
QT_BEGIN_NAMESPACE
class QKmsScreen;
class gbm_device;
+class gbm_bo;
class QKmsCursor : public QPlatformCursor
{
@@ -61,12 +57,12 @@ public:
~QKmsCursor();
void pointerEvent(const QMouseEvent &event);
- void changeCursor(QCursor *widgetCursor, QWindow *window);
+ void changeCursor(QCursor *windowCursor, QWindow *window);
private:
QKmsScreen *m_screen;
gbm_device *m_graphicsBufferManager;
- EGLImageKHR m_eglImage;
+ gbm_bo *m_cursorBufferObject;
QPlatformCursorImage *m_cursorImage;
bool m_moved;
};
diff --git a/src/plugins/platforms/kms/qkmsscreen.cpp b/src/plugins/platforms/kms/qkmsscreen.cpp
index 123dcc283f..892f7bb01f 100644
--- a/src/plugins/platforms/kms/qkmsscreen.cpp
+++ b/src/plugins/platforms/kms/qkmsscreen.cpp
@@ -124,10 +124,14 @@ void QKmsScreen::initializeScreenMode()
drmModeConnector *connector = drmModeGetConnector(m_device->fd(), m_connectorId);
drmModeModeInfo *mode = 0;
- if (connector->count_modes > 0)
- mode = &connector->modes[0];
- else
- mode = &builtin_1024x768;
+ for (int i = 0; i < connector->count_modes; ++i) {
+ if (connector->modes[i].type & DRM_MODE_TYPE_PREFERRED) {
+ mode = &connector->modes[i];
+ break;
+ }
+ }
+ if (!mode)
+ mode = mode = &builtin_1024x768;
drmModeEncoder *encoder = drmModeGetEncoder(m_device->fd(), connector->encoders[0]);
if (encoder == 0)
diff --git a/src/plugins/platforms/minimalegl/qminimaleglbackingstore.cpp b/src/plugins/platforms/minimalegl/qminimaleglbackingstore.cpp
index da89100359..cb245f2e5c 100644
--- a/src/plugins/platforms/minimalegl/qminimaleglbackingstore.cpp
+++ b/src/plugins/platforms/minimalegl/qminimaleglbackingstore.cpp
@@ -49,6 +49,7 @@ QT_BEGIN_NAMESPACE
QMinimalEglBackingStore::QMinimalEglBackingStore(QWindow *window)
: QPlatformBackingStore(window)
, m_context(new QOpenGLContext)
+ , m_device(0)
{
m_context->setFormat(window->requestedFormat());
m_context->setScreen(window->screen());
diff --git a/src/plugins/platforms/minimalegl/qminimaleglintegration.h b/src/plugins/platforms/minimalegl/qminimaleglintegration.h
index fb86c967e1..dba7504033 100644
--- a/src/plugins/platforms/minimalegl/qminimaleglintegration.h
+++ b/src/plugins/platforms/minimalegl/qminimaleglintegration.h
@@ -47,8 +47,6 @@
#include <qpa/qplatformintegration.h>
#include <qpa/qplatformscreen.h>
-QT_BEGIN_HEADER
-
QT_BEGIN_NAMESPACE
class QMinimalEglIntegration : public QPlatformIntegration
@@ -75,6 +73,5 @@ private:
};
QT_END_NAMESPACE
-QT_END_HEADER
#endif // QMINIMALEGLINTEGRATION_H
diff --git a/src/plugins/platforms/offscreen/main.cpp b/src/plugins/platforms/offscreen/main.cpp
new file mode 100644
index 0000000000..ca7dc1d18b
--- /dev/null
+++ b/src/plugins/platforms/offscreen/main.cpp
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <qpa/qplatformintegrationplugin.h>
+#include "qoffscreenintegration.h"
+
+QT_BEGIN_NAMESPACE
+
+class QOffscreenIntegrationPlugin : public QPlatformIntegrationPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "offscreen.json")
+public:
+ QPlatformIntegration *create(const QString&, const QStringList&);
+};
+
+QPlatformIntegration *QOffscreenIntegrationPlugin::create(const QString& system, const QStringList& paramList)
+{
+ Q_UNUSED(paramList);
+ if (system.toLower() == "offscreen")
+ return QOffscreenIntegration::createOffscreenIntegration();
+
+ return 0;
+}
+
+QT_END_NAMESPACE
+
+#include "main.moc"
diff --git a/src/plugins/platforms/offscreen/offscreen.json b/src/plugins/platforms/offscreen/offscreen.json
new file mode 100644
index 0000000000..6e87744de0
--- /dev/null
+++ b/src/plugins/platforms/offscreen/offscreen.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "offscreen" ]
+}
diff --git a/src/plugins/platforms/offscreen/offscreen.pro b/src/plugins/platforms/offscreen/offscreen.pro
new file mode 100644
index 0000000000..270e3ce228
--- /dev/null
+++ b/src/plugins/platforms/offscreen/offscreen.pro
@@ -0,0 +1,25 @@
+TARGET = qoffscreen
+
+PLUGIN_TYPE = platforms
+load(qt_plugin)
+
+QT += core-private gui-private platformsupport-private
+
+SOURCES = main.cpp \
+ qoffscreenintegration.cpp \
+ qoffscreenwindow.cpp \
+ qoffscreencommon.cpp
+
+HEADERS = qoffscreenintegration.h \
+ qoffscreenwindow.h \
+ qoffscreencommon.h
+
+OTHER_FILES += offscreen.json
+
+contains(QT_CONFIG, xcb):contains(QT_CONFIG, opengl):!contains(QT_CONFIG, opengles2) {
+ SOURCES += qoffscreenintegration_x11.cpp
+ HEADERS += qoffscreenintegration_x11.h
+ system(echo "Using X11 offscreen integration with GLX")
+} else {
+ SOURCES += qoffscreenintegration_dummy.cpp
+}
diff --git a/src/plugins/platforms/offscreen/qoffscreencommon.cpp b/src/plugins/platforms/offscreen/qoffscreencommon.cpp
new file mode 100644
index 0000000000..069b20693d
--- /dev/null
+++ b/src/plugins/platforms/offscreen/qoffscreencommon.cpp
@@ -0,0 +1,229 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qoffscreencommon.h"
+#include "qoffscreenwindow.h"
+
+#include <QtGui/private/qpixmap_raster_p.h>
+#include <QtGui/private/qguiapplication_p.h>
+
+#include <qpa/qplatformcursor.h>
+#include <qpa/qplatformwindow.h>
+
+QT_BEGIN_NAMESPACE
+
+QPlatformWindow *QOffscreenScreen::windowContainingCursor = 0;
+
+class QOffscreenCursor : public QPlatformCursor
+{
+public:
+ QOffscreenCursor() : m_pos(10, 10) {}
+
+ QPoint pos() const { return m_pos; }
+ void setPos(const QPoint &pos)
+ {
+ m_pos = pos;
+ QWindowList wl = QGuiApplication::topLevelWindows();
+ QWindow *containing = 0;
+ foreach (QWindow *w, wl) {
+ if (w->type() != Qt::Desktop && w->isExposed() && w->geometry().contains(pos)) {
+ containing = w;
+ break;
+ }
+ }
+
+ QPoint local = pos;
+ if (containing)
+ local -= containing->position();
+
+ QWindow *previous = QOffscreenScreen::windowContainingCursor ? QOffscreenScreen::windowContainingCursor->window() : 0;
+
+ if (containing != previous)
+ QWindowSystemInterface::handleEnterLeaveEvent(containing, previous, local, pos);
+
+ QWindowSystemInterface::handleMouseEvent(containing, local, pos, QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers());
+
+ QOffscreenScreen::windowContainingCursor = containing ? containing->handle() : 0;
+ }
+
+ void changeCursor(QCursor *windowCursor, QWindow *window)
+ {
+ Q_UNUSED(windowCursor);
+ Q_UNUSED(window);
+ }
+
+private:
+ QPoint m_pos;
+};
+
+QOffscreenScreen::QOffscreenScreen()
+ : m_geometry(0, 0, 800, 600)
+ , m_cursor(new QOffscreenCursor)
+{
+}
+
+QPixmap QOffscreenScreen::grabWindow(WId id, int x, int y, int width, int height) const
+{
+ QRect rect(x, y, width, height);
+
+ QOffscreenWindow *window = QOffscreenWindow::windowForWinId(id);
+ if (!window || window->window()->type() == Qt::Desktop) {
+ QWindowList wl = QGuiApplication::topLevelWindows();
+ QWindow *containing = 0;
+ foreach (QWindow *w, wl) {
+ if (w->type() != Qt::Desktop && w->isExposed() && w->geometry().contains(rect)) {
+ containing = w;
+ break;
+ }
+ }
+
+ if (!containing)
+ return QPixmap();
+
+ id = containing->winId();
+ rect = rect.translated(-containing->geometry().topLeft());
+ }
+
+ QOffscreenBackingStore *store = QOffscreenBackingStore::backingStoreForWinId(id);
+ if (store)
+ return store->grabWindow(id, rect);
+ return QPixmap();
+}
+
+QOffscreenBackingStore::QOffscreenBackingStore(QWindow *window)
+ : QPlatformBackingStore(window)
+{
+}
+
+QOffscreenBackingStore::~QOffscreenBackingStore()
+{
+ clearHash();
+}
+
+QPaintDevice *QOffscreenBackingStore::paintDevice()
+{
+ return &m_image;
+}
+
+void QOffscreenBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
+{
+ Q_UNUSED(region);
+
+ if (m_image.size().isEmpty())
+ return;
+
+ QSize imageSize = m_image.size();
+
+ QRegion clipped = QRect(0, 0, window->width(), window->height());
+ clipped &= QRect(0, 0, imageSize.width(), imageSize.height()).translated(-offset);
+
+ QRect bounds = clipped.boundingRect().translated(offset);
+
+ if (bounds.isNull())
+ return;
+
+ WId id = window->winId();
+
+ m_windowAreaHash[id] = bounds;
+ m_backingStoreForWinIdHash[id] = this;
+}
+
+void QOffscreenBackingStore::resize(const QSize &size, const QRegion &)
+{
+ QImage::Format format = QGuiApplication::primaryScreen()->handle()->format();
+ if (m_image.size() != size)
+ m_image = QImage(size, format);
+ clearHash();
+}
+
+extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset);
+
+bool QOffscreenBackingStore::scroll(const QRegion &area, int dx, int dy)
+{
+ if (m_image.isNull())
+ return false;
+
+ const QVector<QRect> rects = area.rects();
+ for (int i = 0; i < rects.size(); ++i)
+ qt_scrollRectInImage(m_image, rects.at(i), QPoint(dx, dy));
+
+ return true;
+}
+
+QPixmap QOffscreenBackingStore::grabWindow(WId window, const QRect &rect) const
+{
+ QRect area = m_windowAreaHash.value(window, QRect());
+ if (area.isNull())
+ return QPixmap();
+
+ QRect adjusted = rect;
+ if (adjusted.width() <= 0)
+ adjusted.setWidth(area.width());
+ if (adjusted.height() <= 0)
+ adjusted.setHeight(area.height());
+
+ adjusted = adjusted.translated(area.topLeft()) & area;
+
+ if (adjusted.isEmpty())
+ return QPixmap();
+
+ return QPixmap::fromImage(m_image.copy(adjusted));
+}
+
+QOffscreenBackingStore *QOffscreenBackingStore::backingStoreForWinId(WId id)
+{
+ return m_backingStoreForWinIdHash.value(id, 0);
+}
+
+void QOffscreenBackingStore::clearHash()
+{
+ QList<WId> ids = m_windowAreaHash.keys();
+ foreach (WId id, ids) {
+ QHash<WId, QOffscreenBackingStore *>::iterator it = m_backingStoreForWinIdHash.find(id);
+ if (it.value() == this)
+ m_backingStoreForWinIdHash.remove(id);
+ }
+ m_windowAreaHash.clear();
+}
+
+QHash<WId, QOffscreenBackingStore *> QOffscreenBackingStore::m_backingStoreForWinIdHash;
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/offscreen/qoffscreencommon.h b/src/plugins/platforms/offscreen/qoffscreencommon.h
new file mode 100644
index 0000000000..a5df7d05d3
--- /dev/null
+++ b/src/plugins/platforms/offscreen/qoffscreencommon.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOFFSCREENCOMMON_H
+#define QOFFSCREENCOMMON_H
+
+#include <qpa/qplatformbackingstore.h>
+#include <qpa/qplatformdrag.h>
+#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformscreen.h>
+#include <qpa/qplatformwindow.h>
+
+#include <qscopedpointer.h>
+#include <qimage.h>
+#include <qhash.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOffscreenScreen : public QPlatformScreen
+{
+public:
+ QOffscreenScreen();
+
+ QRect geometry() const { return m_geometry; }
+ int depth() const { return 32; }
+ QImage::Format format() const { return QImage::Format_RGB32; }
+ QPlatformCursor *cursor() const { return m_cursor.data(); }
+
+ QPixmap grabWindow(WId window, int x, int y, int width, int height) const;
+
+ static QPlatformWindow *windowContainingCursor;
+
+public:
+ QRect m_geometry;
+ QScopedPointer<QPlatformCursor> m_cursor;
+};
+
+class QOffscreenDrag : public QPlatformDrag
+{
+public:
+ QMimeData *platformDropData() { return 0; }
+ Qt::DropAction drag(QDrag *) { return Qt::IgnoreAction; }
+};
+
+class QOffscreenBackingStore : public QPlatformBackingStore
+{
+public:
+ QOffscreenBackingStore(QWindow *window);
+ ~QOffscreenBackingStore();
+
+ QPaintDevice *paintDevice();
+ void flush(QWindow *window, const QRegion &region, const QPoint &offset);
+ void resize(const QSize &size, const QRegion &staticContents);
+ bool scroll(const QRegion &area, int dx, int dy);
+
+ QPixmap grabWindow(WId window, const QRect &rect) const;
+
+ static QOffscreenBackingStore *backingStoreForWinId(WId id);
+
+private:
+ void clearHash();
+
+ QImage m_image;
+ QHash<WId, QRect> m_windowAreaHash;
+
+ static QHash<WId, QOffscreenBackingStore *> m_backingStoreForWinIdHash;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
new file mode 100644
index 0000000000..e3fcc7ebb0
--- /dev/null
+++ b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qoffscreenintegration.h"
+#include "qoffscreenwindow.h"
+#include "qoffscreencommon.h"
+
+#if defined(Q_OS_UNIX)
+#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h>
+#if defined(Q_OS_MAC)
+#include <qpa/qplatformfontdatabase.h>
+#else
+#include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h>
+#endif
+#elif defined(Q_OS_WIN)
+#include <QtPlatformSupport/private/qbasicfontdatabase_p.h>
+#include <QtCore/private/qeventdispatcher_win_p.h>
+#endif
+
+#include <QtGui/private/qpixmap_raster_p.h>
+#include <QtGui/private/qguiapplication_p.h>
+
+#include <qpa/qplatformservices.h>
+
+QT_BEGIN_NAMESPACE
+
+template <typename BaseEventDispatcher>
+class QOffscreenEventDispatcher : public BaseEventDispatcher
+{
+public:
+ explicit QOffscreenEventDispatcher(QObject *parent = 0)
+ : BaseEventDispatcher(parent)
+ {
+ }
+
+ bool processEvents(QEventLoop::ProcessEventsFlags flags)
+ {
+ bool didSendEvents = QWindowSystemInterface::sendWindowSystemEvents(flags);
+
+ return BaseEventDispatcher::processEvents(flags) || didSendEvents;
+ }
+
+ bool hasPendingEvents()
+ {
+ return BaseEventDispatcher::hasPendingEvents()
+ || QWindowSystemInterface::windowSystemEventsQueued();
+ }
+
+ void flush()
+ {
+ if (qApp)
+ qApp->sendPostedEvents();
+ BaseEventDispatcher::flush();
+ }
+};
+
+QOffscreenIntegration::QOffscreenIntegration()
+{
+#if defined(Q_OS_UNIX)
+ m_eventDispatcher = createUnixEventDispatcher();
+#if defined(Q_OS_MAC)
+ m_fontDatabase.reset(new QPlatformFontDatabase());
+#else
+ m_fontDatabase.reset(new QGenericUnixFontDatabase());
+#endif
+#elif defined(Q_OS_WIN)
+ m_eventDispatcher = new QOffscreenEventDispatcher<QEventDispatcherWin32>();
+ m_fontDatabase.reset(new QBasicFontDatabase());
+#endif
+
+ m_drag.reset(new QOffscreenDrag);
+ m_services.reset(new QPlatformServices);
+
+ QGuiApplicationPrivate::instance()->setEventDispatcher(m_eventDispatcher);
+ screenAdded(new QOffscreenScreen);
+}
+
+QOffscreenIntegration::~QOffscreenIntegration()
+{
+}
+
+bool QOffscreenIntegration::hasCapability(QPlatformIntegration::Capability cap) const
+{
+ switch (cap) {
+ case ThreadedPixmaps: return true;
+ case MultipleWindows: return true;
+ default: return QPlatformIntegration::hasCapability(cap);
+ }
+}
+
+QPlatformWindow *QOffscreenIntegration::createPlatformWindow(QWindow *window) const
+{
+ Q_UNUSED(window);
+ QPlatformWindow *w = new QOffscreenWindow(window);
+ w->requestActivateWindow();
+ return w;
+}
+
+QPlatformBackingStore *QOffscreenIntegration::createPlatformBackingStore(QWindow *window) const
+{
+ return new QOffscreenBackingStore(window);
+}
+
+QAbstractEventDispatcher *QOffscreenIntegration::guiThreadEventDispatcher() const
+{
+ return m_eventDispatcher;
+}
+
+QPlatformFontDatabase *QOffscreenIntegration::fontDatabase() const
+{
+ return m_fontDatabase.data();
+}
+
+QPlatformDrag *QOffscreenIntegration::drag() const
+{
+ return m_drag.data();
+}
+
+QPlatformServices *QOffscreenIntegration::services() const
+{
+ return m_services.data();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration.h b/src/plugins/platforms/offscreen/qoffscreenintegration.h
new file mode 100644
index 0000000000..eb03100ec9
--- /dev/null
+++ b/src/plugins/platforms/offscreen/qoffscreenintegration.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOFFSCREENINTEGRATION_H
+#define QOFFSCREENINTEGRATION_H
+
+#include <qpa/qplatformintegration.h>
+
+#include <qscopedpointer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOffscreenBackendData;
+
+class QOffscreenIntegration : public QPlatformIntegration
+{
+public:
+ QOffscreenIntegration();
+ ~QOffscreenIntegration();
+
+ bool hasCapability(QPlatformIntegration::Capability cap) const;
+
+ QPlatformWindow *createPlatformWindow(QWindow *window) const;
+ QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const;
+ QPlatformDrag *drag() const;
+ QPlatformServices *services() const;
+
+ QPlatformFontDatabase *fontDatabase() const;
+ QAbstractEventDispatcher *guiThreadEventDispatcher() const;
+
+ static QOffscreenIntegration *createOffscreenIntegration();
+
+private:
+ QAbstractEventDispatcher *m_eventDispatcher;
+ QScopedPointer<QPlatformFontDatabase> m_fontDatabase;
+ QScopedPointer<QPlatformDrag> m_drag;
+ QScopedPointer<QPlatformServices> m_services;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration_dummy.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration_dummy.cpp
new file mode 100644
index 0000000000..8bc1b17a56
--- /dev/null
+++ b/src/plugins/platforms/offscreen/qoffscreenintegration_dummy.cpp
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qoffscreenintegration.h"
+
+QOffscreenIntegration *QOffscreenIntegration::createOffscreenIntegration()
+{
+ return new QOffscreenIntegration;
+}
diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp
new file mode 100644
index 0000000000..6c6c516a4e
--- /dev/null
+++ b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp
@@ -0,0 +1,252 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qoffscreenintegration_x11.h"
+
+#include <QByteArray>
+#include <QOpenGLContext>
+
+#include <X11/Xlib.h>
+#include <GL/glx.h>
+
+#include <QtPlatformSupport/private/qglxconvenience_p.h>
+
+#include <qpa/qplatformsurface.h>
+#include <qsurface.h>
+
+QT_BEGIN_NAMESPACE
+
+QOffscreenIntegration *QOffscreenIntegration::createOffscreenIntegration()
+{
+ return new QOffscreenX11Integration;
+}
+
+bool QOffscreenX11Integration::hasCapability(QPlatformIntegration::Capability cap) const
+{
+ switch (cap) {
+ case OpenGL: return true;
+ case ThreadedOpenGL: return true;
+ default: return QOffscreenIntegration::hasCapability(cap);
+ }
+}
+
+QPlatformOpenGLContext *QOffscreenX11Integration::createPlatformOpenGLContext(QOpenGLContext *context) const
+{
+ if (!m_connection)
+ m_connection.reset(new QOffscreenX11Connection);
+
+ return new QOffscreenX11GLXContext(m_connection->x11Info(), context);
+}
+
+QOffscreenX11Connection::QOffscreenX11Connection()
+{
+ XInitThreads();
+
+ QByteArray displayName = qgetenv("DISPLAY");
+ Display *display = XOpenDisplay(displayName.constData());
+ m_display = display;
+ m_screenNumber = DefaultScreen(display);
+}
+
+QOffscreenX11Connection::~QOffscreenX11Connection()
+{
+ XCloseDisplay((Display *)m_display);
+}
+
+class QOffscreenX11Info
+{
+public:
+ QOffscreenX11Info(QOffscreenX11Connection *connection)
+ : m_connection(connection)
+ {
+ }
+
+ Display *display() const {
+ return (Display *)m_connection->display();
+ }
+
+ Window root() const {
+ return DefaultRootWindow(display());
+ }
+
+ int screenNumber() const {
+ return m_connection->screenNumber();
+ }
+
+private:
+ QOffscreenX11Connection *m_connection;
+};
+
+QOffscreenX11Info *QOffscreenX11Connection::x11Info()
+{
+ if (!m_x11Info)
+ m_x11Info.reset(new QOffscreenX11Info(this));
+ return m_x11Info.data();
+}
+
+class QOffscreenX11GLXContextData
+{
+public:
+ QOffscreenX11Info *x11;
+ QSurfaceFormat format;
+ GLXContext context;
+ GLXContext shareContext;
+ Window window;
+};
+
+static Window createDummyWindow(QOffscreenX11Info *x11, XVisualInfo *visualInfo)
+{
+ Colormap cmap = XCreateColormap(x11->display(), x11->root(), visualInfo->visual, AllocNone);
+ XSetWindowAttributes a;
+ a.background_pixel = WhitePixel(x11->display(), x11->screenNumber());
+ a.border_pixel = BlackPixel(x11->display(), x11->screenNumber());
+ a.colormap = cmap;
+
+ Window window = XCreateWindow(x11->display(), x11->root(),
+ 0, 0, 100, 100,
+ 0, visualInfo->depth, InputOutput, visualInfo->visual,
+ CWBackPixel|CWBorderPixel|CWColormap, &a);
+ XFreeColormap(x11->display(), cmap);
+ return window;
+}
+
+static Window createDummyWindow(QOffscreenX11Info *x11, GLXFBConfig config)
+{
+ XVisualInfo *visualInfo = glXGetVisualFromFBConfig(x11->display(), config);
+ if (!visualInfo)
+ qFatal("Could not initialize GLX");
+ Window window = createDummyWindow(x11, visualInfo);
+ XFree(visualInfo);
+ return window;
+}
+
+QOffscreenX11GLXContext::QOffscreenX11GLXContext(QOffscreenX11Info *x11, QOpenGLContext *context)
+ : d(new QOffscreenX11GLXContextData)
+{
+ d->x11 = x11;
+ d->format = context->format();
+
+ d->shareContext = 0;
+ if (context->shareHandle())
+ d->shareContext = static_cast<QOffscreenX11GLXContext *>(context->shareHandle())->d->context;
+
+ GLXFBConfig config = qglx_findConfig(x11->display(), x11->screenNumber(), d->format);
+ if (config) {
+ d->context = glXCreateNewContext(x11->display(), config, GLX_RGBA_TYPE, d->shareContext, true);
+ if (!d->context && d->shareContext) {
+ d->shareContext = 0;
+ // re-try without a shared glx context
+ d->context = glXCreateNewContext(x11->display(), config, GLX_RGBA_TYPE, 0, true);
+ }
+
+ // Get the basic surface format details
+ if (d->context)
+ qglx_surfaceFormatFromGLXFBConfig(&d->format, x11->display(), config, d->context);
+
+ // Create a temporary window so that we can make the new context current
+ d->window = createDummyWindow(x11, config);
+ } else {
+ XVisualInfo *visualInfo = qglx_findVisualInfo(x11->display(), 0, &d->format);
+ if (!visualInfo)
+ qFatal("Could not initialize GLX");
+ d->context = glXCreateContext(x11->display(), visualInfo, d->shareContext, true);
+ if (!d->context && d->shareContext) {
+ // re-try without a shared glx context
+ d->shareContext = 0;
+ d->context = glXCreateContext(x11->display(), visualInfo, 0, true);
+ }
+
+ d->window = createDummyWindow(x11, visualInfo);
+ XFree(visualInfo);
+ }
+}
+
+QOffscreenX11GLXContext::~QOffscreenX11GLXContext()
+{
+ glXDestroyContext(d->x11->display(), d->context);
+ XDestroyWindow(d->x11->display(), d->window);
+}
+
+bool QOffscreenX11GLXContext::makeCurrent(QPlatformSurface *surface)
+{
+ QSize size = surface->surface()->size();
+
+ XResizeWindow(d->x11->display(), d->window, size.width(), size.height());
+ XSync(d->x11->display(), true);
+
+ if (glXMakeCurrent(d->x11->display(), d->window, d->context)) {
+ glViewport(0, 0, size.width(), size.height());
+ return true;
+ }
+
+ return false;
+}
+
+void QOffscreenX11GLXContext::doneCurrent()
+{
+ glXMakeCurrent(d->x11->display(), 0, 0);
+}
+
+void QOffscreenX11GLXContext::swapBuffers(QPlatformSurface *)
+{
+}
+
+void (*QOffscreenX11GLXContext::getProcAddress(const QByteArray &procName)) ()
+{
+ return (void (*)())glXGetProcAddressARB(reinterpret_cast<const GLubyte *>(procName.constData()));
+}
+
+QSurfaceFormat QOffscreenX11GLXContext::format() const
+{
+ return d->format;
+}
+
+bool QOffscreenX11GLXContext::isSharing() const
+{
+ return d->shareContext;
+}
+
+bool QOffscreenX11GLXContext::isValid() const
+{
+ return d->context && d->window;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.h b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.h
new file mode 100644
index 0000000000..9afa302b04
--- /dev/null
+++ b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOFFSCREENINTEGRATION_X11_H
+#define QOFFSCREENINTEGRATION_X11_H
+
+#include "qoffscreenintegration.h"
+
+#include <qglobal.h>
+#include <qscopedpointer.h>
+
+#include <qpa/qplatformopenglcontext.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOffscreenX11Connection;
+class QOffscreenX11Info;
+
+class QOffscreenX11Integration : public QOffscreenIntegration
+{
+public:
+ bool hasCapability(QPlatformIntegration::Capability cap) const;
+
+ QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const;
+
+private:
+ mutable QScopedPointer<QOffscreenX11Connection> m_connection;
+};
+
+class QOffscreenX11Connection {
+public:
+ QOffscreenX11Connection();
+ ~QOffscreenX11Connection();
+
+ QOffscreenX11Info *x11Info();
+
+ void *display() const { return m_display; }
+ int screenNumber() const { return m_screenNumber; }
+
+private:
+ void *m_display;
+ int m_screenNumber;
+
+ QScopedPointer<QOffscreenX11Info> m_x11Info;
+};
+
+class QOffscreenX11GLXContextData;
+
+class QOffscreenX11GLXContext : public QPlatformOpenGLContext
+{
+public:
+ QOffscreenX11GLXContext(QOffscreenX11Info *x11, QOpenGLContext *context);
+ ~QOffscreenX11GLXContext();
+
+ bool makeCurrent(QPlatformSurface *surface);
+ void doneCurrent();
+ void swapBuffers(QPlatformSurface *surface);
+ void (*getProcAddress(const QByteArray &procName)) ();
+
+ QSurfaceFormat format() const;
+ bool isSharing() const;
+ bool isValid() const;
+
+private:
+ QScopedPointer<QOffscreenX11GLXContextData> d;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/offscreen/qoffscreenwindow.cpp b/src/plugins/platforms/offscreen/qoffscreenwindow.cpp
new file mode 100644
index 0000000000..702ef2300c
--- /dev/null
+++ b/src/plugins/platforms/offscreen/qoffscreenwindow.cpp
@@ -0,0 +1,199 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qoffscreenwindow.h"
+#include "qoffscreencommon.h"
+
+#include <qpa/qplatformscreen.h>
+#include <qpa/qwindowsysteminterface.h>
+
+#include <private/qwindow_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QOffscreenWindow::QOffscreenWindow(QWindow *window)
+ : QPlatformWindow(window)
+ , m_positionIncludesFrame(false)
+ , m_visible(false)
+ , m_pendingGeometryChangeOnShow(true)
+{
+ if (window->windowState() == Qt::WindowNoState)
+ setGeometry(window->geometry());
+ else
+ setWindowState(window->windowState());
+
+ QWindowSystemInterface::flushWindowSystemEvents();
+
+ static WId counter = 0;
+ m_winId = ++counter;
+
+ m_windowForWinIdHash[m_winId] = this;
+}
+
+QOffscreenWindow::~QOffscreenWindow()
+{
+ if (QOffscreenScreen::windowContainingCursor == this)
+ QOffscreenScreen::windowContainingCursor = 0;
+ m_windowForWinIdHash.remove(m_winId);
+}
+
+void QOffscreenWindow::setGeometry(const QRect &rect)
+{
+ if (window()->windowState() != Qt::WindowNoState)
+ return;
+
+ m_positionIncludesFrame = qt_window_private(window())->positionPolicy == QWindowPrivate::WindowFrameInclusive;
+
+ setFrameMarginsEnabled(true);
+ setGeometryImpl(rect);
+
+ m_normalGeometry = geometry();
+}
+
+void QOffscreenWindow::setGeometryImpl(const QRect &rect)
+{
+ QRect adjusted = rect;
+ if (adjusted.width() <= 0)
+ adjusted.setWidth(1);
+ if (adjusted.height() <= 0)
+ adjusted.setHeight(1);
+
+ if (m_positionIncludesFrame) {
+ adjusted.translate(m_margins.left(), m_margins.top());
+ } else {
+ // make sure we're not placed off-screen
+ if (adjusted.left() < m_margins.left())
+ adjusted.translate(m_margins.left(), 0);
+ if (adjusted.top() < m_margins.top())
+ adjusted.translate(0, m_margins.top());
+ }
+
+ QPlatformWindow::setGeometry(adjusted);
+
+ if (m_visible) {
+ QWindowSystemInterface::handleGeometryChange(window(), adjusted);
+ QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), adjusted.size()));
+ } else {
+ m_pendingGeometryChangeOnShow = true;
+ }
+}
+
+void QOffscreenWindow::setVisible(bool visible)
+{
+ if (visible == m_visible)
+ return;
+
+ if (visible) {
+ if (window()->type() != Qt::ToolTip)
+ QWindowSystemInterface::handleWindowActivated(window());
+
+ if (m_pendingGeometryChangeOnShow) {
+ m_pendingGeometryChangeOnShow = false;
+ QWindowSystemInterface::handleGeometryChange(window(), geometry());
+ }
+ }
+
+ if (visible) {
+ QRect rect(QPoint(), geometry().size());
+ QWindowSystemInterface::handleExposeEvent(window(), rect);
+ } else {
+ QWindowSystemInterface::handleExposeEvent(window(), QRegion());
+ }
+
+ m_visible = visible;
+}
+
+void QOffscreenWindow::requestActivateWindow()
+{
+ if (m_visible)
+ QWindowSystemInterface::handleWindowActivated(window());
+}
+
+WId QOffscreenWindow::winId() const
+{
+ return m_winId;
+}
+
+QMargins QOffscreenWindow::frameMargins() const
+{
+ return m_margins;
+}
+
+void QOffscreenWindow::setFrameMarginsEnabled(bool enabled)
+{
+ if (enabled && !(window()->flags() & Qt::FramelessWindowHint))
+ m_margins = QMargins(2, 2, 2, 2);
+ else
+ m_margins = QMargins(0, 0, 0, 0);
+}
+
+void QOffscreenWindow::setWindowState(Qt::WindowState state)
+{
+ setFrameMarginsEnabled(state != Qt::WindowFullScreen);
+ m_positionIncludesFrame = false;
+
+ switch (state) {
+ case Qt::WindowFullScreen:
+ setGeometryImpl(screen()->geometry());
+ break;
+ case Qt::WindowMaximized:
+ setGeometryImpl(screen()->availableGeometry().adjusted(m_margins.left(), m_margins.top(), -m_margins.right(), -m_margins.bottom()));
+ break;
+ case Qt::WindowMinimized:
+ break;
+ case Qt::WindowNoState:
+ setGeometryImpl(m_normalGeometry);
+ break;
+ default:
+ break;
+ }
+
+ QWindowSystemInterface::handleWindowStateChanged(window(), state);
+}
+
+QOffscreenWindow *QOffscreenWindow::windowForWinId(WId id)
+{
+ return m_windowForWinIdHash.value(id, 0);
+}
+
+QHash<WId, QOffscreenWindow *> QOffscreenWindow::m_windowForWinIdHash;
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/offscreen/qoffscreenwindow.h b/src/plugins/platforms/offscreen/qoffscreenwindow.h
new file mode 100644
index 0000000000..cd1cf8e0aa
--- /dev/null
+++ b/src/plugins/platforms/offscreen/qoffscreenwindow.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOFFSCREENWINDOW_H
+#define QOFFSCREENWINDOW_H
+
+#include <qpa/qplatformbackingstore.h>
+#include <qpa/qplatformwindow.h>
+
+#include <qhash.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOffscreenWindow : public QPlatformWindow
+{
+public:
+ QOffscreenWindow(QWindow *window);
+ ~QOffscreenWindow();
+
+ void setGeometry(const QRect &rect);
+ void setWindowState(Qt::WindowState state);
+
+ QMargins frameMargins() const;
+
+ void setVisible(bool visible);
+ void requestActivateWindow();
+
+ WId winId() const;
+
+ static QOffscreenWindow *windowForWinId(WId id);
+
+private:
+ void setFrameMarginsEnabled(bool enabled);
+ void setGeometryImpl(const QRect &rect);
+
+ QRect m_normalGeometry;
+ QMargins m_margins;
+ bool m_positionIncludesFrame;
+ bool m_visible;
+ bool m_pendingGeometryChangeOnShow;
+ WId m_winId;
+
+ static QHash<WId, QOffscreenWindow *> m_windowForWinIdHash;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro
index 828867c3a7..92664826ab 100644
--- a/src/plugins/platforms/platforms.pro
+++ b/src/plugins/platforms/platforms.pro
@@ -1,12 +1,17 @@
TEMPLATE = subdirs
-SUBDIRS += minimal
+android:!android-no-sdk: SUBDIRS += android
+
+SUBDIRS += minimal offscreen
contains(QT_CONFIG, xcb) {
SUBDIRS += xcb
}
-mac:!ios: SUBDIRS += cocoa
+mac {
+ ios: SUBDIRS += ios
+ else: SUBDIRS += cocoa
+}
win32: SUBDIRS += windows
diff --git a/src/plugins/platforms/qnx/qnx.pro b/src/plugins/platforms/qnx/qnx.pro
index 8367513fc5..203cdebda9 100644
--- a/src/plugins/platforms/qnx/qnx.pro
+++ b/src/plugins/platforms/qnx/qnx.pro
@@ -39,6 +39,7 @@ CONFIG(blackberry) {
#DEFINES += QQNXSCREEN_DEBUG
#DEFINES += QQNXVIRTUALKEYBOARD_DEBUG
#DEFINES += QQNXWINDOW_DEBUG
+#DEFINES += QQNXCURSOR_DEBUG
SOURCES = main.cpp \
@@ -54,7 +55,8 @@ SOURCES = main.cpp \
qqnxnavigatoreventhandler.cpp \
qqnxabstractnavigator.cpp \
qqnxabstractvirtualkeyboard.cpp \
- qqnxservices.cpp
+ qqnxservices.cpp \
+ qqnxcursor.cpp
HEADERS = main.h \
qqnxbuffer.h \
@@ -70,7 +72,8 @@ HEADERS = main.h \
qqnxnavigatoreventhandler.h \
qqnxabstractnavigator.h \
qqnxabstractvirtualkeyboard.h \
- qqnxservices.h
+ qqnxservices.h \
+ qqnxcursor.h
LIBS += -lscreen
diff --git a/src/plugins/platforms/qnx/qqnxabstractnavigator.cpp b/src/plugins/platforms/qnx/qqnxabstractnavigator.cpp
index 08da98d690..5a94bff14e 100644
--- a/src/plugins/platforms/qnx/qqnxabstractnavigator.cpp
+++ b/src/plugins/platforms/qnx/qqnxabstractnavigator.cpp
@@ -44,7 +44,7 @@
#include <QDebug>
#include <QUrl>
-#ifdef QQNXNAVIGATOR_DEBUG
+#if defined(QQNXNAVIGATOR_DEBUG)
#define qNavigatorDebug qDebug
#else
#define qNavigatorDebug QT_NO_QDEBUG_MACRO
diff --git a/src/plugins/platforms/qnx/qqnxbpseventfilter.cpp b/src/plugins/platforms/qnx/qqnxbpseventfilter.cpp
index 2d19537896..d94d3c092a 100644
--- a/src/plugins/platforms/qnx/qqnxbpseventfilter.cpp
+++ b/src/plugins/platforms/qnx/qqnxbpseventfilter.cpp
@@ -53,7 +53,7 @@
#include <bps/navigator.h>
#include <bps/screen.h>
-#ifdef QQNXBPSEVENTFILTER_DEBUG
+#if defined(QQNXBPSEVENTFILTER_DEBUG)
#define qBpsEventFilterDebug qDebug
#else
#define qBpsEventFilterDebug QT_NO_QDEBUG_MACRO
@@ -87,7 +87,7 @@ void QQnxBpsEventFilter::installOnEventDispatcher(QAbstractEventDispatcher *disp
{
qBpsEventFilterDebug() << Q_FUNC_INFO << "dispatcher=" << dispatcher;
- if (navigator_request_events(0) != BPS_SUCCESS)
+ if (navigator_request_events(NAVIGATOR_EXTENDED_DATA) != BPS_SUCCESS)
qWarning("QQNX: failed to register for navigator events");
dispatcher->installNativeEventFilter(this);
@@ -210,6 +210,26 @@ bool QQnxBpsEventFilter::handleNavigatorEvent(bps_event_t *event)
m_navigatorEventHandler->handleExit();
break;
+ case NAVIGATOR_WINDOW_STATE: {
+ qBpsEventFilterDebug() << Q_FUNC_INFO << "WINDOW STATE event";
+ const navigator_window_state_t state = navigator_event_get_window_state(event);
+ const QByteArray id(navigator_event_get_groupid(event));
+
+ switch (state) {
+ case NAVIGATOR_WINDOW_FULLSCREEN:
+ m_navigatorEventHandler->handleWindowGroupStateChanged(id, Qt::WindowFullScreen);
+ break;
+ case NAVIGATOR_WINDOW_THUMBNAIL:
+ m_navigatorEventHandler->handleWindowGroupStateChanged(id, Qt::WindowMinimized);
+ break;
+ case NAVIGATOR_WINDOW_INVISIBLE:
+ m_navigatorEventHandler->handleWindowGroupDeactivated(id);
+ break;
+ }
+
+ break;
+ }
+
case NAVIGATOR_WINDOW_ACTIVE: {
qBpsEventFilterDebug() << Q_FUNC_INFO << "WINDOW ACTIVE event";
const QByteArray id(navigator_event_get_groupid(event));
diff --git a/src/plugins/platforms/qnx/qqnxbuffer.cpp b/src/plugins/platforms/qnx/qqnxbuffer.cpp
index 9007af7f70..c5e99a2001 100644
--- a/src/plugins/platforms/qnx/qqnxbuffer.cpp
+++ b/src/plugins/platforms/qnx/qqnxbuffer.cpp
@@ -46,7 +46,7 @@
#include <errno.h>
#include <sys/mman.h>
-#ifdef QQNXBUFFER_DEBUG
+#if defined(QQNXBUFFER_DEBUG)
#define qBufferDebug qDebug
#else
#define qBufferDebug QT_NO_QDEBUG_MACRO
diff --git a/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp b/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp
index 152b732556..2f531efd8b 100644
--- a/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp
+++ b/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp
@@ -49,7 +49,7 @@
#include <QtCore/QSocketNotifier>
#include <QtCore/private/qcore_unix_p.h>
-#ifdef QQNXBUTTON_DEBUG
+#if defined(QQNXBUTTON_DEBUG)
#define qButtonDebug qDebug
#else
#define qButtonDebug QT_NO_QDEBUG_MACRO
diff --git a/src/plugins/platforms/qnx/qqnxclipboard.cpp b/src/plugins/platforms/qnx/qqnxclipboard.cpp
index 8286febd35..dfd1345eed 100644
--- a/src/plugins/platforms/qnx/qqnxclipboard.cpp
+++ b/src/plugins/platforms/qnx/qqnxclipboard.cpp
@@ -39,7 +39,7 @@
**
****************************************************************************/
-#ifndef QT_NO_CLIPBOARD
+#if !defined(QT_NO_CLIPBOARD)
#include "qqnxclipboard.h"
@@ -53,7 +53,7 @@
#include <clipboard/clipboard.h>
#include <errno.h>
-#ifdef QQNXCLIPBOARD_DEBUG
+#if defined(QQNXCLIPBOARD_DEBUG)
#define qClipboardDebug qDebug
#else
#define qClipboardDebug QT_NO_QDEBUG_MACRO
diff --git a/src/plugins/platforms/qnx/qqnxclipboard.h b/src/plugins/platforms/qnx/qqnxclipboard.h
index 0b75393efd..561b57299e 100644
--- a/src/plugins/platforms/qnx/qqnxclipboard.h
+++ b/src/plugins/platforms/qnx/qqnxclipboard.h
@@ -42,7 +42,9 @@
#ifndef QQNXCLIPBOARD_H
#define QQNXCLIPBOARD_H
-#ifndef QT_NO_CLIPBOARD
+#include <QtCore/qglobal.h>
+
+#if !defined(QT_NO_CLIPBOARD)
#include <qpa/qplatformclipboard.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/qnx/qqnxcursor.cpp b/src/plugins/platforms/qnx/qqnxcursor.cpp
new file mode 100644
index 0000000000..3cf857bb27
--- /dev/null
+++ b/src/plugins/platforms/qnx/qqnxcursor.cpp
@@ -0,0 +1,78 @@
+/***************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqnxcursor.h"
+
+#include <QtCore/QDebug>
+
+#if defined(QQNXCURSOR_DEBUG)
+#define qCursorDebug qDebug
+#else
+#define qCursorDebug QT_NO_QDEBUG_MACRO
+#endif
+
+QT_BEGIN_NAMESPACE
+
+QQnxCursor::QQnxCursor()
+{
+}
+
+#if !defined(QT_NO_CURSOR)
+void QQnxCursor::changeCursor(QCursor *windowCursor, QWindow *window)
+{
+ Q_UNUSED(windowCursor);
+ Q_UNUSED(window);
+}
+#endif
+
+void QQnxCursor::setPos(const QPoint &pos)
+{
+ qCursorDebug() << "QQnxCursor::setPos -" << pos;
+ m_pos = pos;
+}
+
+QPoint QQnxCursor::pos() const
+{
+ qCursorDebug() << "QQnxCursor::pos -" << m_pos;
+ return m_pos;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/qnx/qqnxcursor.h b/src/plugins/platforms/qnx/qqnxcursor.h
new file mode 100644
index 0000000000..b62c299040
--- /dev/null
+++ b/src/plugins/platforms/qnx/qqnxcursor.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQNXCURSOR_H
+#define QQNXCURSOR_H
+
+#include <qpa/qplatformcursor.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQnxCursor : public QPlatformCursor
+{
+public:
+ QQnxCursor();
+
+#if !defined(QT_NO_CURSOR)
+ void changeCursor(QCursor *windowCursor, QWindow *window);
+#endif
+ void setPos(const QPoint &pos);
+
+ QPoint pos() const;
+
+private:
+ QPoint m_pos;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQNXCURSOR_H
diff --git a/src/plugins/platforms/qnx/qqnxfiledialoghelper.cpp b/src/plugins/platforms/qnx/qqnxfiledialoghelper.cpp
index 79d7c7d9ca..0325a33268 100644
--- a/src/plugins/platforms/qnx/qqnxfiledialoghelper.cpp
+++ b/src/plugins/platforms/qnx/qqnxfiledialoghelper.cpp
@@ -51,7 +51,7 @@
#include <QTimer>
#include <QWindow>
-#ifdef QQNXFILEDIALOGHELPER_DEBUG
+#if defined(QQNXFILEDIALOGHELPER_DEBUG)
#define qFileDialogHelperDebug qDebug
#else
#define qFileDialogHelperDebug QT_NO_QDEBUG_MACRO
diff --git a/src/plugins/platforms/qnx/qqnxglcontext.cpp b/src/plugins/platforms/qnx/qqnxglcontext.cpp
index 1c2ec23fa9..f77bb73614 100644
--- a/src/plugins/platforms/qnx/qqnxglcontext.cpp
+++ b/src/plugins/platforms/qnx/qqnxglcontext.cpp
@@ -50,7 +50,7 @@
#include <QtGui/QOpenGLContext>
#include <QtGui/QScreen>
-#ifdef QQNXGLCONTEXT_DEBUG
+#if defined(QQNXGLCONTEXT_DEBUG)
#define qGLContextDebug qDebug
#else
#define qGLContextDebug QT_NO_QDEBUG_MACRO
diff --git a/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp b/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp
index 0d8f430c73..97a361158e 100644
--- a/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp
+++ b/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp
@@ -61,13 +61,13 @@
#include <process.h>
#include <sys/keycodes.h>
-#ifdef QQNXINPUTCONTEXT_IMF_EVENT_DEBUG
+#if defined(QQNXINPUTCONTEXT_IMF_EVENT_DEBUG)
#define qInputContextIMFEventDebug qDebug
#else
#define qInputContextIMFEventDebug QT_NO_QDEBUG_MACRO
#endif
-#ifdef QQNXINPUTCONTEXT_DEBUG
+#if defined(QQNXINPUTCONTEXT_DEBUG)
#define qInputContextDebug qDebug
#else
#define qInputContextDebug QT_NO_QDEBUG_MACRO
diff --git a/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp b/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp
index 71b925357a..f444d34b5e 100644
--- a/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp
+++ b/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp
@@ -47,7 +47,7 @@
#include <QtCore/QDebug>
#include <QtGui/QGuiApplication>
-#ifdef QQNXINPUTCONTEXT_DEBUG
+#if defined(QQNXINPUTCONTEXT_DEBUG)
#define qInputContextDebug qDebug
#else
#define qInputContextDebug QT_NO_QDEBUG_MACRO
diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp
index f3cfdab9c6..5ea4fef698 100644
--- a/src/plugins/platforms/qnx/qqnxintegration.cpp
+++ b/src/plugins/platforms/qnx/qqnxintegration.cpp
@@ -96,7 +96,7 @@
#include <errno.h>
-#ifdef QQNXINTEGRATION_DEBUG
+#if defined(QQNXINTEGRATION_DEBUG)
#define qIntegrationDebug qDebug
#else
#define qIntegrationDebug QT_NO_QDEBUG_MACRO
@@ -495,6 +495,8 @@ void QQnxIntegration::createDisplay(screen_display_t display, bool isPrimary)
QObject::connect(m_navigatorEventHandler, SIGNAL(rotationChanged(int)), screen, SLOT(setRotation(int)));
QObject::connect(m_navigatorEventHandler, SIGNAL(windowGroupActivated(QByteArray)), screen, SLOT(activateWindowGroup(QByteArray)));
QObject::connect(m_navigatorEventHandler, SIGNAL(windowGroupDeactivated(QByteArray)), screen, SLOT(deactivateWindowGroup(QByteArray)));
+ QObject::connect(m_navigatorEventHandler, SIGNAL(windowGroupStateChanged(QByteArray,Qt::WindowState)),
+ screen, SLOT(windowGroupStateChanged(QByteArray,Qt::WindowState)));
}
void QQnxIntegration::removeDisplay(QQnxScreen *screen)
diff --git a/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp b/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp
index 19fa9c5a9f..30dbb330d7 100644
--- a/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp
+++ b/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp
@@ -45,7 +45,7 @@
#include <QGuiApplication>
#include <qpa/qwindowsysteminterface.h>
-#ifdef QQNXNAVIGATOREVENTHANDLER_DEBUG
+#if defined(QQNXNAVIGATOREVENTHANDLER_DEBUG)
#define qNavigatorEventHandlerDebug qDebug
#else
#define qNavigatorEventHandlerDebug QT_NO_QDEBUG_MACRO
@@ -106,4 +106,10 @@ void QQnxNavigatorEventHandler::handleWindowGroupDeactivated(const QByteArray &i
Q_EMIT windowGroupDeactivated(id);
}
+void QQnxNavigatorEventHandler::handleWindowGroupStateChanged(const QByteArray &id, Qt::WindowState state)
+{
+ qNavigatorEventHandlerDebug() << Q_FUNC_INFO << id;
+ Q_EMIT windowGroupStateChanged(id, state);
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.h b/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.h
index 2068163473..cce3921a27 100644
--- a/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.h
+++ b/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.h
@@ -58,11 +58,13 @@ public:
void handleExit();
void handleWindowGroupActivated(const QByteArray &id);
void handleWindowGroupDeactivated(const QByteArray &id);
+ void handleWindowGroupStateChanged(const QByteArray &id, Qt::WindowState state);
Q_SIGNALS:
void rotationChanged(int angle);
void windowGroupActivated(const QByteArray &id);
void windowGroupDeactivated(const QByteArray &id);
+ void windowGroupStateChanged(const QByteArray &id, Qt::WindowState state);
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp b/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp
index 9fa8294815..640944fb45 100644
--- a/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp
+++ b/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp
@@ -55,7 +55,7 @@
#include <sys/types.h>
#include <sys/stat.h>
-#ifdef QQNXNAVIGATOREVENTNOTIFIER_DEBUG
+#if defined(QQNXNAVIGATOREVENTNOTIFIER_DEBUG)
#define qNavigatorEventNotifierDebug qDebug
#else
#define qNavigatorEventNotifierDebug QT_NO_QDEBUG_MACRO
diff --git a/src/plugins/platforms/qnx/qqnxnavigatorpps.cpp b/src/plugins/platforms/qnx/qqnxnavigatorpps.cpp
index 92a94e0a39..1656ab029b 100644
--- a/src/plugins/platforms/qnx/qqnxnavigatorpps.cpp
+++ b/src/plugins/platforms/qnx/qqnxnavigatorpps.cpp
@@ -44,7 +44,7 @@
#include <QDebug>
#include <private/qcore_unix_p.h>
-#ifdef QQNXNAVIGATOR_DEBUG
+#if defined(QQNXNAVIGATOR_DEBUG)
#define qNavigatorDebug qDebug
#else
#define qNavigatorDebug QT_NO_QDEBUG_MACRO
diff --git a/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp b/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp
index 47a72f173b..7204e5bce9 100644
--- a/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp
+++ b/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp
@@ -46,7 +46,7 @@
#include <errno.h>
-#ifdef QQNXRASTERBACKINGSTORE_DEBUG
+#if defined(QQNXRASTERBACKINGSTORE_DEBUG)
#define qRasterBackingStoreDebug qDebug
#else
#define qRasterBackingStoreDebug QT_NO_QDEBUG_MACRO
diff --git a/src/plugins/platforms/qnx/qqnxrootwindow.cpp b/src/plugins/platforms/qnx/qqnxrootwindow.cpp
index b01d468647..198801a832 100644
--- a/src/plugins/platforms/qnx/qqnxrootwindow.cpp
+++ b/src/plugins/platforms/qnx/qqnxrootwindow.cpp
@@ -46,7 +46,7 @@
#include <QtCore/QUuid>
#include <QtCore/QDebug>
-#ifdef QQNXROOTWINDOW_DEBUG
+#if defined(QQNXROOTWINDOW_DEBUG)
#define qRootWindowDebug qDebug
#else
#define qRootWindowDebug QT_NO_QDEBUG_MACRO
diff --git a/src/plugins/platforms/qnx/qqnxscreen.cpp b/src/plugins/platforms/qnx/qqnxscreen.cpp
index 1e58f047ab..7614abdc6a 100644
--- a/src/plugins/platforms/qnx/qqnxscreen.cpp
+++ b/src/plugins/platforms/qnx/qqnxscreen.cpp
@@ -41,6 +41,7 @@
#include "qqnxscreen.h"
#include "qqnxwindow.h"
+#include "qqnxcursor.h"
#include <QtCore/QThread>
#include <QtCore/QDebug>
@@ -48,7 +49,7 @@
#include <errno.h>
-#ifdef QQNXSCREEN_DEBUG
+#if defined(QQNXSCREEN_DEBUG)
#define qScreenDebug qDebug
#else
#define qScreenDebug QT_NO_QDEBUG_MACRO
@@ -110,7 +111,8 @@ QQnxScreen::QQnxScreen(screen_context_t screenContext, screen_display_t display,
m_posted(false),
m_keyboardHeight(0),
m_nativeOrientation(Qt::PrimaryOrientation),
- m_platformContext(0)
+ m_platformContext(0),
+ m_cursor(new QQnxCursor())
{
qScreenDebug() << Q_FUNC_INFO;
// Cache initial orientation of this display
@@ -149,6 +151,10 @@ QQnxScreen::QQnxScreen(screen_context_t screenContext, screen_display_t display,
QQnxScreen::~QQnxScreen()
{
qScreenDebug() << Q_FUNC_INFO;
+ Q_FOREACH (QQnxWindow *childWindow, m_childWindows)
+ childWindow->setScreen(0);
+
+ delete m_cursor;
}
static int defaultDepth()
@@ -492,6 +498,11 @@ void QQnxScreen::onWindowPost(QQnxWindow *window)
}
}
+QPlatformCursor * QQnxScreen::cursor() const
+{
+ return m_cursor;
+}
+
void QQnxScreen::keyboardHeightChanged(int height)
{
if (height == m_keyboardHeight)
@@ -542,6 +553,21 @@ void QQnxScreen::windowClosed(void *window)
removeOverlayWindow(windowHandle);
}
+void QQnxScreen::windowGroupStateChanged(const QByteArray &id, Qt::WindowState state)
+{
+ qScreenDebug() << Q_FUNC_INFO;
+
+ if (!rootWindow() || id != rootWindow()->groupName())
+ return;
+
+ QWindow * const window = topMostChildWindow();
+
+ if (!window)
+ return;
+
+ QWindowSystemInterface::handleWindowStateChanged(window, state);
+}
+
void QQnxScreen::activateWindowGroup(const QByteArray &id)
{
qScreenDebug() << Q_FUNC_INFO;
@@ -549,13 +575,12 @@ void QQnxScreen::activateWindowGroup(const QByteArray &id)
if (!rootWindow() || id != rootWindow()->groupName())
return;
- if (!m_childWindows.isEmpty()) {
- // We're picking up the last window of the list here
- // because this list is ordered by stacking order.
- // Last window is effectively the one on top.
- QWindow * const window = m_childWindows.last()->window();
- QWindowSystemInterface::handleWindowActivated(window);
- }
+ QWindow * const window = topMostChildWindow();
+
+ if (!window)
+ return;
+
+ QWindowSystemInterface::handleWindowActivated(window);
}
void QQnxScreen::deactivateWindowGroup(const QByteArray &id)
@@ -577,4 +602,17 @@ QSharedPointer<QQnxRootWindow> QQnxScreen::rootWindow() const
return m_rootWindow;
}
+QWindow * QQnxScreen::topMostChildWindow() const
+{
+ if (!m_childWindows.isEmpty()) {
+
+ // We're picking up the last window of the list here
+ // because this list is ordered by stacking order.
+ // Last window is effectively the one on top.
+ return m_childWindows.last()->window();
+ }
+
+ return 0;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/qnx/qqnxscreen.h b/src/plugins/platforms/qnx/qqnxscreen.h
index 2851c13c52..41dc675599 100644
--- a/src/plugins/platforms/qnx/qqnxscreen.h
+++ b/src/plugins/platforms/qnx/qqnxscreen.h
@@ -95,10 +95,13 @@ public:
QSharedPointer<QQnxRootWindow> rootWindow() const;
+ QPlatformCursor *cursor() const;
+
public Q_SLOTS:
void setRotation(int rotation);
void newWindowCreated(void *window);
void windowClosed(void *window);
+ void windowGroupStateChanged(const QByteArray &id, Qt::WindowState state);
void activateWindowGroup(const QByteArray &id);
void deactivateWindowGroup(const QByteArray &id);
@@ -112,6 +115,8 @@ private:
void addOverlayWindow(screen_window_t window);
void removeOverlayWindow(screen_window_t window);
+ QWindow *topMostChildWindow() const;
+
screen_context_t m_screenContext;
screen_display_t m_display;
mutable QSharedPointer<QQnxRootWindow> m_rootWindow;
@@ -130,6 +135,8 @@ private:
QList<QQnxWindow *> m_childWindows;
QList<screen_window_t> m_overlays;
+
+ QPlatformCursor *m_cursor;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp
index 4412bb34bd..57cfdc5eb6 100644
--- a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp
+++ b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp
@@ -50,7 +50,7 @@
#include <errno.h>
#include <sys/keycodes.h>
-#ifdef QQNXSCREENEVENT_DEBUG
+#if defined(QQNXSCREENEVENT_DEBUG)
#define qScreenEventDebug qDebug
#else
#define qScreenEventDebug QT_NO_QDEBUG_MACRO
@@ -347,6 +347,8 @@ void QQnxScreenEventHandler::handleTouchEvent(screen_event_t event, int qnxType)
qFatal("QQNX: failed to query event position, errno=%d", errno);
}
+ QCursor::setPos(pos[0], pos[1]);
+
// get window coordinates of touch
errno = 0;
int windowPos[2];
diff --git a/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp b/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp
index 8f262a7083..f3f660bc03 100644
--- a/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp
+++ b/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp
@@ -49,7 +49,7 @@
#include <cctype>
-#ifdef QQNXSCREENEVENTTHREAD_DEBUG
+#if defined(QQNXSCREENEVENTTHREAD_DEBUG)
#define qScreenEventThreadDebug qDebug
#else
#define qScreenEventThreadDebug QT_NO_QDEBUG_MACRO
diff --git a/src/plugins/platforms/qnx/qqnxtheme.cpp b/src/plugins/platforms/qnx/qqnxtheme.cpp
index e8e9e39388..733b7223b6 100644
--- a/src/plugins/platforms/qnx/qqnxtheme.cpp
+++ b/src/plugins/platforms/qnx/qqnxtheme.cpp
@@ -80,10 +80,10 @@ QPlatformDialogHelper *QQnxTheme::createPlatformDialogHelper(DialogType type) co
case QPlatformTheme::FileDialog:
return new QQnxFileDialogHelper(m_integration);
#endif
-#ifndef QT_NO_COLORDIALOG
+#if !defined(QT_NO_COLORDIALOG)
case QPlatformTheme::ColorDialog:
#endif
-#ifndef QT_NO_FONTDIALOG
+#if !defined(QT_NO_FONTDIALOG)
case QPlatformTheme::FontDialog:
#endif
default:
diff --git a/src/plugins/platforms/qnx/qqnxvirtualkeyboardbps.cpp b/src/plugins/platforms/qnx/qqnxvirtualkeyboardbps.cpp
index 3d2f49aa6c..11eb4a5082 100644
--- a/src/plugins/platforms/qnx/qqnxvirtualkeyboardbps.cpp
+++ b/src/plugins/platforms/qnx/qqnxvirtualkeyboardbps.cpp
@@ -47,7 +47,7 @@
#include <bps/locale.h>
#include <bps/virtualkeyboard.h>
-#ifdef QQNXVIRTUALKEYBOARD_DEBUG
+#if defined(QQNXVIRTUALKEYBOARD_DEBUG)
#define qVirtualKeyboardDebug qDebug
#else
#define qVirtualKeyboardDebug QT_NO_QDEBUG_MACRO
diff --git a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp
index ab912927bb..e810b47c22 100644
--- a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp
+++ b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp
@@ -56,7 +56,7 @@
#include <sys/types.h>
#include <unistd.h>
-#ifdef QQNXVIRTUALKEYBOARD_DEBUG
+#if defined(QQNXVIRTUALKEYBOARD_DEBUG)
#define qVirtualKeyboardDebug qDebug
#else
#define qVirtualKeyboardDebug QT_NO_QDEBUG_MACRO
diff --git a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h
index eb41b2efd0..6048868b08 100644
--- a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h
+++ b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h
@@ -39,8 +39,8 @@
**
****************************************************************************/
-#ifndef VIRTUALKEYBOARDPPS_H_
-#define VIRTUALKEYBOARDPPS_H_
+#ifndef VIRTUALKEYBOARDPPS_H
+#define VIRTUALKEYBOARDPPS_H
#include "qqnxabstractvirtualkeyboard.h"
@@ -97,4 +97,4 @@ private:
static const size_t ms_bufferSize;
};
-#endif /* VIRTUALKEYBOARDPPS_H_ */
+#endif // VIRTUALKEYBOARDPPS_H
diff --git a/src/plugins/platforms/qnx/qqnxwindow.cpp b/src/plugins/platforms/qnx/qqnxwindow.cpp
index ab9c94772b..f1bebee9b2 100644
--- a/src/plugins/platforms/qnx/qqnxwindow.cpp
+++ b/src/plugins/platforms/qnx/qqnxwindow.cpp
@@ -40,7 +40,7 @@
****************************************************************************/
#include "qqnxwindow.h"
-#ifndef QT_NO_OPENGL
+#if !defined(QT_NO_OPENGL)
#include "qqnxglcontext.h"
#endif
#include "qqnxintegration.h"
@@ -53,7 +53,12 @@
#include <errno.h>
-#ifdef QQNXWINDOW_DEBUG
+#if defined(Q_OS_BLACKBERRY)
+#include <sys/pps.h>
+#include <bps/navigator.h>
+#endif
+
+#if defined(QQNXWINDOW_DEBUG)
#define qWindowDebug qDebug
#else
#define qWindowDebug QT_NO_QDEBUG_MACRO
@@ -67,7 +72,7 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context)
m_window(0),
m_currentBufferIndex(-1),
m_previousBufferIndex(-1),
-#ifndef QT_NO_OPENGL
+#if !defined(QT_NO_OPENGL)
m_platformOpenGLContext(0),
#endif
m_screen(0),
@@ -156,7 +161,8 @@ QQnxWindow::~QQnxWindow()
// Remove from parent's Hierarchy.
removeFromParent();
- m_screen->updateHierarchy();
+ if (m_screen)
+ m_screen->updateHierarchy();
// Cleanup QNX window and its buffers
screen_destroy_window(m_window);
@@ -272,9 +278,9 @@ void QQnxWindow::setVisible(bool visible)
window()->requestActivate();
if (window()->isTopLevel()) {
- if (visible) {
- QWindowSystemInterface::handleExposeEvent(window(), window()->geometry());
- } else {
+ QWindowSystemInterface::handleExposeEvent(window(), window()->geometry());
+
+ if (!visible) {
// Flush the context, otherwise it won't disappear immediately
screen_flush_context(m_screenContext, 0);
}
@@ -347,7 +353,7 @@ void QQnxWindow::setBufferSize(const QSize &size)
// Create window buffers if they do not exist
if (m_bufferSize.isEmpty()) {
-#ifndef QT_NO_OPENGL
+#if !defined(QT_NO_OPENGL)
// Get pixel format from EGL config if using OpenGL;
// otherwise inherit pixel format of window's screen
if (m_platformOpenGLContext != 0) {
@@ -497,6 +503,11 @@ void QQnxWindow::setScreen(QQnxScreen *platformScreen)
{
qWindowDebug() << Q_FUNC_INFO << "window =" << window() << "platformScreen =" << platformScreen;
+ if (platformScreen == 0) { // The screen has been destroyed
+ m_screen = 0;
+ return;
+ }
+
if (m_screen == platformScreen)
return;
@@ -539,7 +550,7 @@ void QQnxWindow::removeFromParent()
m_parentWindow = 0;
else
qFatal("QQnxWindow: Window Hierarchy broken; window has parent, but parent hasn't got child.");
- } else {
+ } else if (m_screen) {
m_screen->removeWindow(this);
}
}
@@ -618,12 +629,20 @@ void QQnxWindow::setWindowState(Qt::WindowState state)
switch (state) {
- // WindowMinimized is not supported - navigator does not have an API to minimize a window
// WindowActive is not an accepted parameter according to the docs
- case Qt::WindowMinimized:
case Qt::WindowActive:
return;
+ case Qt::WindowMinimized:
+ minimize();
+
+ if (m_unmaximizedGeometry.isValid())
+ setGeometry(m_unmaximizedGeometry);
+ else
+ setGeometry(m_screen->geometry());
+
+ break;
+
case Qt::WindowMaximized:
case Qt::WindowFullScreen:
m_unmaximizedGeometry = geometry();
@@ -647,7 +666,7 @@ void QQnxWindow::gainedFocus()
QWindowSystemInterface::handleWindowActivated(window());
}
-#ifndef QT_NO_OPENGL
+#if !defined(QT_NO_OPENGL)
void QQnxWindow::setPlatformOpenGLContext(QQnxGLContext *platformOpenGLContext)
{
// This function does not take ownership of the platform gl context.
@@ -683,6 +702,27 @@ void QQnxWindow::blitFrom(QQnxWindow *sourceWindow, const QPoint &sourceOffset,
blitHelper(sourceBuffer, targetBuffer, sourceOffset, QPoint(0, 0), targetRegion, true);
}
+void QQnxWindow::minimize()
+{
+#if defined(Q_OS_BLACKBERRY) && !defined(Q_OS_BLACKBERRY_TABLET)
+ qWindowDebug() << Q_FUNC_INFO;
+
+ pps_encoder_t encoder;
+
+ pps_encoder_initialize(&encoder, false);
+ pps_encoder_add_string(&encoder, "msg", "minimizeWindow");
+
+ if (navigator_raw_write(pps_encoder_buffer(&encoder),
+ pps_encoder_length(&encoder)) != BPS_SUCCESS) {
+ qWindowDebug() << Q_FUNC_INFO << "navigator_raw_write failed:" << strerror(errno);
+ }
+
+ pps_encoder_cleanup(&encoder);
+#else
+ qWarning("Qt::WindowMinimized is not supported by this OS version");
+#endif
+}
+
void QQnxWindow::updateZorder(int &topZorder)
{
errno = 0;
diff --git a/src/plugins/platforms/qnx/qqnxwindow.h b/src/plugins/platforms/qnx/qqnxwindow.h
index 90226bb9a4..4a327fd54b 100644
--- a/src/plugins/platforms/qnx/qqnxwindow.h
+++ b/src/plugins/platforms/qnx/qqnxwindow.h
@@ -49,7 +49,7 @@
#include <QtGui/QImage>
#include <QtCore/QMutex>
-#ifndef QT_NO_OPENGL
+#if !defined(QT_NO_OPENGL)
#include <EGL/egl.h>
#endif
@@ -60,7 +60,7 @@ QT_BEGIN_NAMESPACE
// all surfaces double buffered
#define MAX_BUFFER_COUNT 2
-#ifndef QT_NO_OPENGL
+#if !defined(QT_NO_OPENGL)
class QQnxGLContext;
#endif
class QQnxScreen;
@@ -108,7 +108,7 @@ public:
QQnxScreen *screen() const { return m_screen; }
const QList<QQnxWindow*>& children() const { return m_childWindows; }
-#ifndef QT_NO_OPENGL
+#if !defined(QT_NO_OPENGL)
void setPlatformOpenGLContext(QQnxGLContext *platformOpenGLContext);
QQnxGLContext *platformOpenGLContext() const { return m_platformOpenGLContext; }
#endif
@@ -116,6 +116,7 @@ public:
QQnxWindow *findWindow(screen_window_t windowHandle);
void blitFrom(QQnxWindow *sourceWindow, const QPoint &sourceOffset, const QRegion &targetRegion);
+ void minimize();
private:
QRect setGeometryHelper(const QRect &rect);
@@ -143,7 +144,7 @@ private:
QRegion m_previousDirty;
QRegion m_scrolled;
-#ifndef QT_NO_OPENGL
+#if !defined(QT_NO_OPENGL)
QQnxGLContext *m_platformOpenGLContext;
#endif
QQnxScreen *m_screen;
diff --git a/src/plugins/platforms/windows/accessible/iaccessible2.cpp b/src/plugins/platforms/windows/accessible/iaccessible2.cpp
index 164bd6eed9..b1afd7aca3 100644
--- a/src/plugins/platforms/windows/accessible/iaccessible2.cpp
+++ b/src/plugins/platforms/windows/accessible/iaccessible2.cpp
@@ -44,7 +44,7 @@
#include "iaccessible2.h"
#include "qwindowsaccessibility.h"
-#include <QtGui/qaccessible2.h>
+#include <QtGui/private/qaccessible2_p.h>
#include <QtGui/qclipboard.h>
#include <QtWidgets/qapplication.h>
#include <QtCore/qdebug.h>
@@ -230,6 +230,10 @@ HRESULT STDMETHODCALLTYPE AccessibleRelation::get_targets(
**************************************************************/
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::QueryInterface(REFIID id, LPVOID *iface)
{
+ QAccessibleInterface *accessible = accessibleInterface();
+ if (!accessible)
+ return E_NOINTERFACE;
+
HRESULT hr = QWindowsMsaaAccessible::QueryInterface(id, iface);
if (!SUCCEEDED(hr)) {
if (id == IID_IServiceProvider) {
@@ -301,10 +305,11 @@ ULONG STDMETHODCALLTYPE QWindowsIA2Accessible::Release()
**************************************************************/
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nRelations(long *nRelations)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
if (!nRelations)
return E_INVALIDARG;
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
return getRelationsHelper(0, 0, 0, nRelations);
@@ -312,10 +317,11 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nRelations(long *nRelations
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_relation(long relationIndex, IAccessibleRelation **relation)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
if (!relation)
return E_INVALIDARG;
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
return getRelationsHelper(relation, relationIndex, 1);
@@ -330,8 +336,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_relations(long maxRelations
IAccessibleRelation **relations,
long *nRelations)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
return getRelationsHelper(relations, 0, maxRelations, nRelations);
@@ -340,8 +347,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_relations(long maxRelations
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::role(long *ia2role)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
long r = accessible->role();
@@ -386,8 +394,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_groupPosition(long *groupLe
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_states(AccessibleStates *states)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
if (!states)
return E_POINTER;
@@ -462,23 +471,23 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_localizedExtendedStates(lon
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_uniqueID(long *outUniqueID)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
- // ### FIXME SERIOUSLY, NOT A STABLE SOLUTION IF NODES ARE DELETED ETC
- // Return 0 if no object and no parent. This is really an error case.
- uint uid = uniqueID();
- accessibleDebug("uniqueID: %08x", uid);
- *outUniqueID = (long)uid;
- return uid ? S_OK : S_FALSE;
+ accessibleDebug("uniqueID: %08x", id);
+
+ *outUniqueID = (long)id;
+ return int(id) < 0 ? S_OK : S_FALSE;
}
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_windowHandle(HWND *windowHandle)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
return GetWindow(windowHandle);
}
@@ -486,8 +495,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_windowHandle(HWND *windowHa
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_indexInParent(long *indexInParent)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
if (!indexInParent)
return E_INVALIDARG;
@@ -497,7 +507,6 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_indexInParent(long *indexIn
return S_FALSE;
}
int indexOfChild = par->indexOfChild(accessible);
- delete par;
Q_ASSERT(indexOfChild >= 0);
*indexInParent = indexOfChild;
return S_OK;
@@ -505,8 +514,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_indexInParent(long *indexIn
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_locale(IA2Locale *locale)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
IA2Locale res;
QLocale l;
@@ -519,8 +529,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_locale(IA2Locale *locale)
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_attributes(BSTR *attributes)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
*attributes = 0;//QStringToBSTR(QString());
return S_FALSE;
@@ -531,8 +542,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_attributes(BSTR *attributes
**************************************************************/
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::nActions(long *nActions)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
*nActions = 0;
@@ -543,8 +555,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::nActions(long *nActions)
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::doAction(long actionIndex)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
if (QAccessibleActionInterface *actionIface = actionInterface()) {
const QStringList actionNames = actionIface->actionNames();
@@ -559,8 +572,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::doAction(long actionIndex)
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_description(long actionIndex, BSTR *description)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
*description = 0;
if (QAccessibleActionInterface *actionIface = actionInterface()) {
@@ -575,8 +589,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_description(long actionInde
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_keyBinding(long actionIndex, long nMaxBindings, BSTR **keyBindings, long *nBindings)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
Q_UNUSED(nMaxBindings);
BSTR *arrayOfBindingsToReturn = 0;
@@ -603,8 +618,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_keyBinding(long actionIndex
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_name(long actionIndex, BSTR *name)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
*name = 0;
if (QAccessibleActionInterface *actionIface = actionInterface()) {
@@ -619,8 +635,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_name(long actionIndex, BSTR
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_localizedName(long actionIndex, BSTR *localizedName)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
*localizedName = 0;
if (QAccessibleActionInterface *actionIface = actionInterface()) {
@@ -639,13 +656,15 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_localizedName(long actionIn
**************************************************************/
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_locationInParent(long *x, long *y)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
QPoint topLeft = accessible->rect().topLeft();
- if (QAccessibleInterface *parentIface = accessible->parent())
+ QAccessibleInterface *parentIface = accessible->parent();
+ if (parentIface && parentIface->isValid())
topLeft -= parentIface->rect().topLeft();
*x = topLeft.x();
@@ -655,8 +674,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_locationInParent(long *x, l
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_foreground(IA2Color *foreground)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
// IA2Color is a typedef for long
@@ -666,8 +686,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_foreground(IA2Color *foregr
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_background(IA2Color *background)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
// IA2Color is a typedef for long
@@ -686,6 +707,8 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_background(IA2Color *backgr
*/
QString QWindowsIA2Accessible::textForRange(int startOffset, int endOffset) const
{
+ QAccessibleInterface *accessible = accessibleInterface();
+
if (QAccessibleTextInterface *textIface = accessible->textInterface()) {
if (endOffset == IA2_TEXT_OFFSET_LENGTH)
endOffset = textIface->characterCount();
@@ -703,6 +726,7 @@ QString QWindowsIA2Accessible::textForRange(int startOffset, int endOffset) cons
*/
void QWindowsIA2Accessible::replaceTextFallback(long startOffset, long endOffset, const QString &txt)
{
+ QAccessibleInterface *accessible = accessibleInterface();
QString t = textForRange(0, -1);
if (endOffset == IA2_TEXT_OFFSET_LENGTH)
endOffset = t.length();
@@ -716,6 +740,7 @@ void QWindowsIA2Accessible::replaceTextFallback(long startOffset, long endOffset
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::copyText(long startOffset, long endOffset)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
#ifndef QT_NO_CLIPBOARD
const QString t = textForRange(startOffset, endOffset);
@@ -728,6 +753,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::copyText(long startOffset, long
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::deleteText(long startOffset, long endOffset)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
if (QAccessibleEditableTextInterface *editableTextIface = accessible->editableTextInterface())
editableTextIface->deleteText(startOffset, endOffset);
@@ -738,6 +764,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::deleteText(long startOffset, lo
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::insertText(long offset, BSTR *text)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
const QString txt(BSTRToQString(*text));
if (QAccessibleEditableTextInterface *editableTextIface = accessible->editableTextInterface())
@@ -749,6 +776,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::insertText(long offset, BSTR *t
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::cutText(long startOffset, long endOffset)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
#ifndef QT_NO_CLIPBOARD
const QString t = textForRange(startOffset, endOffset);
@@ -765,6 +793,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::cutText(long startOffset, long
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::pasteText(long offset)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
#ifndef QT_NO_CLIPBOARD
const QString txt = QGuiApplication::clipboard()->text();
@@ -780,6 +809,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::pasteText(long offset)
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::replaceText(long startOffset, long endOffset, BSTR *text)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
const QString txt(BSTRToQString(*text));
if (QAccessibleEditableTextInterface *editableTextIface = accessible->editableTextInterface())
@@ -800,8 +830,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::setAttributes(long /*startOffse
**************************************************************/
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_cellAt( long row, long column, IUnknown **cell)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
*cell = 0;
@@ -816,8 +847,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_cellAt( long row, long colu
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_caption( IUnknown **captionInterface)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
*captionInterface = 0;
@@ -830,8 +862,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_caption( IUnknown **caption
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_columnDescription( long column, BSTR *description)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
*description = 0;
@@ -845,8 +878,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_columnDescription( long col
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nColumns( long *columnCount)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
if (QAccessibleTableInterface *tableIface = tableInterface()) {
@@ -858,8 +892,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nColumns( long *columnCount
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nRows(long *rowCount)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
if (QAccessibleTableInterface *tableIface = tableInterface()) {
@@ -871,8 +906,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nRows(long *rowCount)
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nSelectedCells(long *cellCount)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
if (QAccessibleTableInterface *tableIface = tableInterface()) {
@@ -884,8 +920,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nSelectedCells(long *cellCo
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nSelectedColumns(long *columnCount)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
if (QAccessibleTableInterface *tableIface = tableInterface()) {
@@ -897,8 +934,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nSelectedColumns(long *colu
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nSelectedRows(long *rowCount)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
if (QAccessibleTableInterface *tableIface = tableInterface()) {
@@ -910,8 +948,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nSelectedRows(long *rowCoun
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowDescription(long row, BSTR *description)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
*description = 0;
@@ -925,10 +964,11 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowDescription(long row, BS
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_selectedCells(IUnknown ***cells, long *nSelectedCells)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
Q_UNUSED(cells);
Q_UNUSED(nSelectedCells);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
QList<QAccessibleInterface*> selectedCells = tableInterface()->selectedCells();
@@ -937,8 +977,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_selectedCells(IUnknown ***c
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_selectedColumns(long **selectedColumns, long *nColumns)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
if (QAccessibleTableInterface *tableIface = tableInterface()) {
@@ -957,8 +998,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_selectedColumns(long **sele
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_selectedRows(long **selectedRows, long *nRows)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
if (QAccessibleTableInterface *tableIface = tableInterface()) {
@@ -977,8 +1019,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_selectedRows(long **selecte
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_summary(IUnknown **summaryInterface)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
*summaryInterface = 0;
@@ -991,8 +1034,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_summary(IUnknown **summaryI
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_isColumnSelected(long column, boolean *isSelected)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
if (QAccessibleTableInterface *tableIface = tableInterface()) {
@@ -1004,8 +1048,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_isColumnSelected(long colum
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_isRowSelected(long row, boolean *isSelected)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
if (QAccessibleTableInterface *tableIface = tableInterface()) {
@@ -1017,8 +1062,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_isRowSelected(long row, boo
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::selectRow(long row)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
if (QAccessibleTableInterface *tableIface = tableInterface()) {
@@ -1030,8 +1076,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::selectRow(long row)
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::selectColumn(long column)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
if (QAccessibleTableInterface *tableIface = tableInterface()) {
@@ -1043,8 +1090,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::selectColumn(long column)
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::unselectRow(long row)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
if (QAccessibleTableInterface *tableIface = tableInterface()) {
@@ -1056,8 +1104,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::unselectRow(long row)
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::unselectColumn(long column)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
if (QAccessibleTableInterface *tableIface = tableInterface()) {
@@ -1069,8 +1118,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::unselectColumn(long column)
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_modelChange( IA2TableModelChange * /*modelChange*/)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
return E_NOTIMPL;
}
@@ -1080,8 +1130,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_modelChange( IA2TableModelC
\**************************************************************/
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_columnExtent(long *nColumnsSpanned)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
*nColumnsSpanned = tableCellInterface()->columnExtent();
@@ -1091,8 +1142,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_columnExtent(long *nColumns
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_columnHeaderCells(IUnknown ***cellAccessibles,
long *nColumnHeaderCells)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
const QList<QAccessibleInterface*> headerCells = tableCellInterface()->columnHeaderCells();
return wrapListOfCells(headerCells, cellAccessibles, nColumnHeaderCells);
@@ -1100,8 +1152,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_columnHeaderCells(IUnknown
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_columnIndex(long *columnIndex)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
*columnIndex = tableCellInterface()->columnIndex();
return S_OK;
@@ -1109,8 +1162,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_columnIndex(long *columnInd
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowExtent(long *nRowsSpanned)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
*nRowsSpanned = tableCellInterface()->rowExtent();
return S_OK;
@@ -1119,8 +1173,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowExtent(long *nRowsSpanne
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowHeaderCells(IUnknown ***cellAccessibles,
long *nRowHeaderCells)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
const QList<QAccessibleInterface*> headerCells = tableCellInterface()->rowHeaderCells();
return wrapListOfCells(headerCells, cellAccessibles, nRowHeaderCells);
@@ -1128,8 +1183,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowHeaderCells(IUnknown ***
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowIndex(long *rowIndex)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
*rowIndex = tableCellInterface()->rowIndex();
return S_OK;
@@ -1137,8 +1193,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowIndex(long *rowIndex)
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_isSelected( boolean *isSelected)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
*isSelected = tableCellInterface()->isSelected();
return S_OK;
@@ -1148,8 +1205,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowColumnExtents(long *row,
long *rowExtents, long *columnExtents,
boolean *isSelected)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
tableCellInterface()->rowColumnExtents((int*)row, (int*)column, (int*)rowExtents, (int*)columnExtents, (bool*)isSelected);
@@ -1158,8 +1216,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_rowColumnExtents(long *row,
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_table(IUnknown **table)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
QAccessibleInterface *tableIface = tableCellInterface()->table();
@@ -1174,6 +1233,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_table(IUnknown **table)
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::addSelection(long startOffset,
long endOffset)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
if (QAccessibleTextInterface *text = textInterface()) {
text->addSelection(startOffset, endOffset);
@@ -1187,6 +1247,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_attributes(long offset,
long *endOffset,
BSTR *textAttributes)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
if (QAccessibleTextInterface *text = textInterface()) {
const QString attrs = text->attributes(offset, (int*)startOffset, (int*)endOffset);
@@ -1198,6 +1259,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_attributes(long offset,
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_caretOffset(long *offset)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
if (QAccessibleTextInterface *text = textInterface()) {
*offset = text->cursorPosition();
@@ -1214,6 +1276,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_characterExtents(long offse
long *width,
long *height)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
if (QAccessibleTextInterface *text = textInterface()) {
QRect rect = text->characterRect(offset);
@@ -1227,6 +1290,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_characterExtents(long offse
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nSelections(long *nSelections)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
if (QAccessibleTextInterface *text = textInterface()) {
*nSelections = text->selectionCount();
@@ -1240,6 +1304,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_offsetAtPoint(long x,
enum IA2CoordinateType coordType,
long *offset)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
if (QAccessibleTextInterface *text = textInterface()) {
QPoint screenPos = mapToScreenPos(coordType, x, y);
@@ -1254,6 +1319,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_selection(long selectionInd
long *startOffset,
long *endOffset)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
if (QAccessibleTextInterface *text = textInterface()) {
text->selection(selectionIndex, (int*)startOffset, (int*)endOffset);
@@ -1266,6 +1332,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_text(long startOffset,
long endOffset,
BSTR *text)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
if (QAccessibleTextInterface *textif = textInterface()) {
const QString t = textif->text(startOffset, endOffset);
@@ -1284,6 +1351,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_textBeforeOffset(long offse
long *endOffset,
BSTR *text)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
if (QAccessibleTextInterface *textIface = textInterface()) {
const QString txt = textIface->textBeforeOffset(offset, (QAccessible2::BoundaryType)boundaryType, (int*)startOffset, (int*)endOffset);
@@ -1303,6 +1371,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_textAfterOffset(
long *endOffset,
BSTR *text)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
if (QAccessibleTextInterface *textIface = textInterface()) {
const QString txt = textIface->textAfterOffset(offset, (QAccessible2::BoundaryType)boundaryType, (int*)startOffset, (int*)endOffset);
@@ -1321,6 +1390,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_textAtOffset(long offset,
long *endOffset,
BSTR *text)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
if (QAccessibleTextInterface *textIface = textInterface()) {
const QString txt = textIface->textAtOffset(offset, (QAccessible2::BoundaryType)boundaryType, (int*)startOffset, (int*)endOffset);
@@ -1335,6 +1405,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_textAtOffset(long offset,
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::removeSelection(long selectionIndex)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
if (QAccessibleTextInterface *textIface = textInterface()) {
textIface->removeSelection(selectionIndex);
@@ -1345,6 +1416,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::removeSelection(long selectionI
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::setCaretOffset(long offset)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
if (QAccessibleTextInterface *textIface = textInterface()) {
textIface->setCursorPosition(offset);
@@ -1357,6 +1429,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::setSelection(long selectionInde
long startOffset,
long endOffset)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
if (QAccessibleTextInterface *textIface = textInterface()) {
textIface->setSelection(selectionIndex, startOffset, endOffset);
@@ -1367,6 +1440,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::setSelection(long selectionInde
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_nCharacters(long *nCharacters)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
if (QAccessibleTextInterface *textIface = textInterface()) {
*nCharacters = textIface->characterCount();
@@ -1379,6 +1453,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::scrollSubstringTo(long startInd
long endIndex,
enum IA2ScrollType scrollType)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
if (QAccessibleTextInterface *textIface = textInterface()) {
Q_UNUSED(scrollType); //###
@@ -1420,8 +1495,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_oldText(IA2TextSegment *old
**************************************************************/
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_currentValue(VARIANT *currentValue)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
if (QAccessibleValueInterface *valueIface = valueInterface()) {
const QVariant var = valueIface->currentValue();
@@ -1435,8 +1511,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_currentValue(VARIANT *curre
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::setCurrentValue(VARIANT value)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
HRESULT hr = S_FALSE;
if (QAccessibleValueInterface *valueIface = valueInterface()) {
@@ -1451,8 +1528,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::setCurrentValue(VARIANT value)
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_maximumValue(VARIANT *maximumValue)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
if (QAccessibleValueInterface *valueIface = valueInterface()) {
const QVariant var = valueIface->maximumValue();
@@ -1465,8 +1543,9 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_maximumValue(VARIANT *maxim
HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_minimumValue(VARIANT *minimumValue)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
if (QAccessibleValueInterface *valueIface = valueInterface()) {
const QVariant var = valueIface->minimumValue();
@@ -1538,6 +1617,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::QueryService(REFGUID guidServic
*/
HRESULT QWindowsIA2Accessible::getRelationsHelper(IAccessibleRelation **relations, int startIndex, long maxRelations, long *nRelations /* = 0*/)
{
+ QAccessibleInterface *accessible = accessibleInterface();
if (nRelations)
*nRelations = 0;
typedef QPair<QAccessibleInterface *, QAccessible::Relation> RelationEntry;
@@ -1587,37 +1667,6 @@ HRESULT QWindowsIA2Accessible::wrapListOfCells(const QList<QAccessibleInterface*
return count > 0 ? S_OK : S_FALSE;
}
-uint QWindowsIA2Accessible::uniqueID() const
-{
- uint uid = 0;
- if (QObject *obj = accessible->object())
- uid = qHash(obj);
-
- if (!uid) {
- QAccessibleInterface *acc = accessible;
- QVector<int> indexOfNodes;
- while (acc && !acc->object()) {
- QAccessibleInterface *par = acc->parent();
- indexOfNodes.append(par->indexOfChild(acc));
- if (acc != accessible)
- delete acc;
- acc = par;
- }
- if (acc) {
- if (acc->object()) {
- uid = qHash(acc->object());
- for (int i = 0; i < indexOfNodes.count(); ++i)
- uid = qHash(uid + indexOfNodes.at(i));
-
- }
- if (acc != accessible)
- delete acc;
- }
- }
- return uid;
-}
-
-
#define IF_EQUAL_RETURN_IIDSTRING(id, iid) if (id == iid) return QByteArray(#iid)
QByteArray QWindowsIA2Accessible::IIDToString(REFIID id)
diff --git a/src/plugins/platforms/windows/accessible/iaccessible2.h b/src/plugins/platforms/windows/accessible/iaccessible2.h
index af9698b9b2..a391d495f9 100644
--- a/src/plugins/platforms/windows/accessible/iaccessible2.h
+++ b/src/plugins/platforms/windows/accessible/iaccessible2.h
@@ -132,7 +132,7 @@ public:
/* IAccessibleTable2 */
HRESULT STDMETHODCALLTYPE get_cellAt( long row, long column, IUnknown **cell);
- HRESULT STDMETHODCALLTYPE get_caption( IUnknown **accessible);
+ HRESULT STDMETHODCALLTYPE get_caption( IUnknown **accessibleInterface);
HRESULT STDMETHODCALLTYPE get_columnDescription( long column, BSTR *description);
HRESULT STDMETHODCALLTYPE get_nColumns( long *columnCount);
HRESULT STDMETHODCALLTYPE get_nRows( long *rowCount);
@@ -143,7 +143,7 @@ public:
HRESULT STDMETHODCALLTYPE get_selectedCells( IUnknown ***cells, long *nSelectedCells);
HRESULT STDMETHODCALLTYPE get_selectedColumns( long **selectedColumns, long *nColumns);
HRESULT STDMETHODCALLTYPE get_selectedRows( long **selectedRows, long *nRows);
- HRESULT STDMETHODCALLTYPE get_summary( IUnknown **accessible);
+ HRESULT STDMETHODCALLTYPE get_summary( IUnknown **accessibleInterface);
HRESULT STDMETHODCALLTYPE get_isColumnSelected( long column, boolean *isSelected);
HRESULT STDMETHODCALLTYPE get_isRowSelected( long row, boolean *isSelected);
HRESULT STDMETHODCALLTYPE selectRow( long row);
@@ -206,22 +206,27 @@ public:
/* private helper functions */
private:
inline QAccessibleTextInterface *textInterface() const {
- return accessible->isValid() ? accessible->textInterface() : static_cast<QAccessibleTextInterface *>(0);
+ QAccessibleInterface *accessible = accessibleInterface();
+ return accessible ? accessible->textInterface() : static_cast<QAccessibleTextInterface *>(0);
}
inline QAccessibleActionInterface *actionInterface() const {
+ QAccessibleInterface *accessible = accessibleInterface();
return accessible->actionInterface();
}
inline QAccessibleValueInterface *valueInterface() const {
+ QAccessibleInterface *accessible = accessibleInterface();
return accessible->valueInterface();
}
inline QAccessibleTableInterface *tableInterface() const {
+ QAccessibleInterface *accessible = accessibleInterface();
return accessible->tableInterface();
}
inline QAccessibleTableCellInterface *tableCellInterface() const {
+ QAccessibleInterface *accessible = accessibleInterface();
return accessible->tableCellInterface();
}
@@ -231,6 +236,7 @@ private:
\a x and \y (out) is in parent relative position if coordType == IA2_COORDTYPE_PARENT_RELATIVE
*/
void mapFromScreenPos(enum IA2CoordinateType coordType, const QPoint &screenPos, long *x, long *y) const {
+ QAccessibleInterface *accessible = accessibleInterface();
if (coordType == IA2_COORDTYPE_PARENT_RELATIVE) {
// caller wants relative to parent
if (QAccessibleInterface *parent = accessible->parent()) {
@@ -250,6 +256,7 @@ private:
\return a screen relative position
*/
QPoint mapToScreenPos(enum IA2CoordinateType coordType, long x, long y) const {
+ QAccessibleInterface *accessible = accessibleInterface();
if (coordType == IA2_COORDTYPE_PARENT_RELATIVE) {
if (QAccessibleInterface *parent = accessible->parent()) {
const QRect parentScreenRect = parent->rect();
@@ -261,7 +268,6 @@ private:
HRESULT getRelationsHelper(IAccessibleRelation **relations, int startIndex, long maxRelations, long *nRelations = 0);
HRESULT wrapListOfCells(const QList<QAccessibleInterface*> &inputCells, IUnknown ***outputAccessibles, long *nCellCount);
- uint uniqueID() const;
QByteArray IIDToString(REFIID id);
QString textForRange(int startOffset, int endOffset) const;
void replaceTextFallback(long startOffset, long endOffset, const QString &txt);
diff --git a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp
index 3ccc6212a9..f222deeeac 100644
--- a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp
+++ b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp
@@ -51,7 +51,7 @@
#include <QtCore/qpointer.h>
#include <QtCore/qsettings.h>
#include <QtGui/qaccessible.h>
-#include <QtGui/qaccessible2.h>
+#include <QtGui/private/qaccessible2_p.h>
#include <qpa/qplatformnativeinterface.h>
#include <QtGui/qwindow.h>
#include <QtGui/qguiapplication.h>
@@ -86,14 +86,8 @@
#include "../qtwindows_additional.h"
-
-// This stuff is used for widgets/items with no window handle:
-typedef QMap<int, QPair<QPointer<QObject>,int> > NotifyMap;
-Q_GLOBAL_STATIC(NotifyMap, qAccessibleRecentSentEvents)
-
QT_BEGIN_NAMESPACE
-
/*!
\!internal
\class QWindowsAccessibility
@@ -162,26 +156,16 @@ void QWindowsAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
}
}
- typedef void (WINAPI *PtrNotifyWinEvent)(DWORD, HWND, LONG, LONG);
-
#if defined(Q_OS_WINCE) // ### TODO: check for NotifyWinEvent in CE 6.0
// There is no user32.lib nor NotifyWinEvent for CE
return;
#else
- static PtrNotifyWinEvent ptrNotifyWinEvent = 0;
- static bool resolvedNWE = false;
- if (!resolvedNWE) {
- resolvedNWE = true;
- ptrNotifyWinEvent = (PtrNotifyWinEvent)QSystemLibrary::resolve(QLatin1String("user32"), "NotifyWinEvent");
- }
- if (!ptrNotifyWinEvent)
- return;
-
// An event has to be associated with a window,
// so find the first parent that is a widget and that has a WId
QAccessibleInterface *iface = event->accessibleInterface();
- QWindow *window = iface ? QWindowsAccessibility::windowHelper(iface) : 0;
- delete iface;
+ if (!iface) // ### This should not happen, maybe make it an assert.
+ return;
+ QWindow *window = QWindowsAccessibility::windowHelper(iface);
if (!window) {
window = QGuiApplication::focusWindow();
@@ -194,27 +178,9 @@ void QWindowsAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
return;
HWND hWnd = (HWND)platform->nativeResourceForWindow("handle", window);
- static int eventNum = 0;
if (event->type() != QAccessible::MenuCommand && // MenuCommand is faked
event->type() != QAccessible::ObjectDestroyed) {
- /* In some rare occasions, the server (Qt) might get a ::get_accChild call with a
- childId that references an entry in the cache where there was a dangling
- QObject-pointer. Previously we crashed on this.
-
- There is no point in actually notifying the AT client that the object got destroyed,
- because the AT client won't query for get_accChild if the event is ObjectDestroyed
- anyway, and we have no other way of mapping the eventId argument to the actual
- child/descendant object. (Firefox seems to simply completely ignore
- EVENT_OBJECT_DESTROY).
-
- We therefore guard each QObject in the cache with a QPointer, and only notify the AT
- client if the type is not ObjectDestroyed.
- */
- eventNum %= 50; //[0..49]
- int eventId = - (eventNum - 1);
- qAccessibleRecentSentEvents()->insert(eventId, qMakePair(QPointer<QObject>(event->object()), event->child()));
- ptrNotifyWinEvent(event->type(), hWnd, OBJID_CLIENT, eventId);
- ++eventNum;
+ ::NotifyWinEvent(event->type(), hWnd, OBJID_CLIENT, QAccessible::uniqueId(iface));
}
#endif // Q_OS_WINCE
}
@@ -224,10 +190,9 @@ QWindow *QWindowsAccessibility::windowHelper(const QAccessibleInterface *iface)
QWindow *window = iface->window();
if (!window) {
QAccessibleInterface *acc = iface->parent();
- while (acc && !window) {
+ while (acc && acc->isValid() && !window) {
window = acc->window();
QAccessibleInterface *par = acc->parent();
- delete acc;
acc = par;
}
}
@@ -242,6 +207,11 @@ IAccessible *QWindowsAccessibility::wrap(QAccessibleInterface *acc)
{
if (!acc)
return 0;
+
+ // ### FIXME: maybe we should accept double insertions into the cache
+ if (!QAccessible::uniqueId(acc))
+ QAccessible::registerAccessibleInterface(acc);
+
#ifdef Q_CC_MINGW
QWindowsMsaaAccessible *wacc = new QWindowsMsaaAccessible(acc);
#else
@@ -252,15 +222,6 @@ IAccessible *QWindowsAccessibility::wrap(QAccessibleInterface *acc)
return iacc;
}
-/*!
- \internal
-*/
-QPair<QObject*, int> QWindowsAccessibility::getCachedObject(int entryId)
-{
- QPair<QPointer<QObject>, int> pair = qAccessibleRecentSentEvents()->value(entryId);
- return qMakePair(pair.first.data(), pair.second);
-}
-
/*
void QWindowsAccessibility::setRootObject(QObject *o)
{
@@ -283,7 +244,7 @@ bool QWindowsAccessibility::handleAccessibleObjectFromWindowRequest(HWND hwnd, W
{
if (static_cast<long>(lParam) == static_cast<long>(UiaRootObjectId)) {
/* For UI Automation */
- } else if ((DWORD)lParam == OBJID_CLIENT) {
+ } else if ((DWORD)lParam == DWORD(OBJID_CLIENT)) {
#if 1
// Ignoring all requests while starting up
// ### Maybe QPA takes care of this???
@@ -313,8 +274,6 @@ bool QWindowsAccessibility::handleAccessibleObjectFromWindowRequest(HWND hwnd, W
iface->Release(); // the client will release the object again, and then it will destroy itself
}
return true;
- } else {
- delete acc;
}
}
}
diff --git a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h
index af0bd65c80..f25e2281a0 100644
--- a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h
+++ b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h
@@ -48,7 +48,6 @@
#include <oleacc.h>
-QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
class QWindowsAccessibility : public QPlatformAccessibility
@@ -64,11 +63,8 @@ public:
*/
static IAccessible *wrap(QAccessibleInterface *acc);
static QWindow *windowHelper(const QAccessibleInterface *iface);
-
- static QPair<QObject*, int> getCachedObject(int entryId);
};
QT_END_NAMESPACE
-QT_END_HEADER
#endif // QWINDOWSACCESSIBILITY_H
diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp
index c23902014c..7eb1bd30c0 100644
--- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp
+++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp
@@ -54,7 +54,7 @@
#include <QtCore/qpair.h>
#include <QtCore/qsettings.h>
#include <QtGui/qaccessible.h>
-#include <QtGui/qaccessible2.h>
+#include <QtGui/private/qaccessible2_p.h>
#include <QtGui/qguiapplication.h>
#include <qpa/qplatformnativeinterface.h>
#include <QtGui/qwindow.h>
@@ -186,21 +186,6 @@ HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Skip(unsigned long celt)
return S_OK;
}
-static bool compareAccessible(QAccessibleInterface *one, QAccessibleInterface *other)
-{
- if (one == other) return true;
- if (!one || !other) return false;
-
- if (one->object() && other->object() && (one->object() == other->object()))
- return true;
- QAIPointer onePar(one->parent());
- QAIPointer otherPar(other->parent());
-
- if (compareAccessible(onePar.data(), otherPar.data()))
- return onePar->indexOfChild(one) == otherPar->indexOfChild(other);
- return false;
-}
-
#ifndef QT_NO_DEBUG
bool debug_accessibility()
{
@@ -232,7 +217,9 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::QueryInterface(REFIID id, LPVO
QByteArray strIID = IIDToString(id);
if (!strIID.isEmpty()) {
- QString ss; QDebug dbg(&ss); dbg << accessible;
+ QString ss;
+ QDebug dbg(&ss);
+ dbg << accessibleInterface();
accessibleDebug("QWindowsIA2Accessible::QI() - IID:%s, iface:%s ", strIID.constData(), qPrintable(ss));
}
if (id == IID_IUnknown) {
@@ -533,8 +520,9 @@ IAccessible::accHitTest documents the value returned in pvarID like this:
*/
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accHitTest(long xLeft, long yTop, VARIANT *pvarID)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
QAccessibleInterface *child = accessible->childAt(xLeft, yTop);
@@ -571,14 +559,15 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accHitTest(long xLeft, long yT
// moz: [important]
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varID)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
QRect rect;
if (varID.lVal) {
- QAIPointer child(childPointer(varID));
- if (!child)
+ QAccessibleInterface *child = accessible->child(varID.lVal - 1);
+ if (!child || !child->isValid())
return E_FAIL;
rect = child->rect();
} else {
@@ -596,8 +585,9 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accLocation(long *pxLeft, long
// moz: [important, but no need to implement up/down/left/right]
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEnd)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
QAccessibleInterface *acc = 0;
@@ -612,12 +602,11 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accNavigate(long navDir, VARIA
case NAVDIR_PREVIOUS:
if (!varStart.lVal){
QAccessibleInterface *parent = accessible->parent();
- if (parent) {
+ if (parent && parent->isValid()) {
int index = parent->indexOfChild(accessible);
index += (navDir == NAVDIR_NEXT) ? 1 : -1;
if (index >= 0 && index < parent->childCount())
acc = parent->child(index);
- delete parent;
}
} else {
int index = varStart.lVal;
@@ -631,8 +620,9 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accNavigate(long navDir, VARIA
case NAVDIR_UP:
case NAVDIR_DOWN:
case NAVDIR_LEFT:
- case NAVDIR_RIGHT:
- if (QAccessibleInterface *pIface = accessible->parent()) {
+ case NAVDIR_RIGHT: {
+ QAccessibleInterface *pIface = accessible->parent();
+ if (pIface && pIface->isValid()) {
const int indexOfOurself = pIface->indexOfChild(accessible);
QRect startg = accessible->rect();
QPoint startc = startg.center();
@@ -645,7 +635,6 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accNavigate(long navDir, VARIA
Q_ASSERT(sibling);
if (i == indexOfOurself || sibling->state().invisible) {
//ignore ourself and invisible siblings
- delete sibling;
continue;
}
@@ -659,7 +648,6 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accNavigate(long navDir, VARIA
startp = QPoint(startg.left(), startg.top() + startg.height() / 2);
sibp = QPoint(sibg.right(), sibg.top() + sibg.height() / 2);
if (QPoint(sibc - startc).x() >= 0) {
- delete sibling;
continue;
}
distp = sibp - startp;
@@ -668,7 +656,6 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accNavigate(long navDir, VARIA
startp = QPoint(startg.right(), startg.top() + startg.height() / 2);
sibp = QPoint(sibg.left(), sibg.top() + sibg.height() / 2);
if (QPoint(sibc - startc).x() <= 0) {
- delete sibling;
continue;
}
distp = sibp - startp;
@@ -677,7 +664,6 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accNavigate(long navDir, VARIA
startp = QPoint(startg.left() + startg.width() / 2, startg.top());
sibp = QPoint(sibg.left() + sibg.width() / 2, sibg.bottom());
if (QPoint(sibc - startc).y() >= 0) {
- delete sibling;
continue;
}
distp = sibp - startp;
@@ -686,7 +672,6 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accNavigate(long navDir, VARIA
startp = QPoint(startg.left() + startg.width() / 2, startg.bottom());
sibp = QPoint(sibg.left() + sibg.width() / 2, sibg.top());
if (QPoint(sibc - startc).y() <= 0) {
- delete sibling;
continue;
}
distp = sibp - startp;
@@ -699,16 +684,13 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accNavigate(long navDir, VARIA
// squared distance, (thus, no need to take the sqrt()).
unsigned dist = distp.x() * distp.x() + distp.y() * distp.y();
if (dist < mindist) {
- delete candidate;
candidate = sibling;
mindist = dist;
- } else {
- delete sibling;
}
}
- delete pIface;
acc = candidate;
}
+ }
break;
default:
break;
@@ -722,9 +704,6 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accNavigate(long navDir, VARIA
(*pvarEnd).vt = VT_DISPATCH;
(*pvarEnd).pdispVal = iface;
return S_OK;
- } else {
- if (acc != accessible)
- delete acc;
}
(*pvarEnd).vt = VT_EMPTY;
@@ -734,8 +713,9 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accNavigate(long navDir, VARIA
// moz: [important]
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accChild(VARIANT varChildID, IDispatch** ppdispChild)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
if (varChildID.vt != VT_I4)
@@ -743,38 +723,18 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accChild(VARIANT varChildI
int childIndex = varChildID.lVal;
+
QAccessibleInterface *acc = 0;
- if (childIndex < 0) {
- const int entry = childIndex;
- QPair<QObject*, int> ref = QWindowsAccessibility::getCachedObject(entry);
- if (ref.first) {
- acc = QAccessible::queryAccessibleInterface(ref.first);
- if (acc && ref.second >= 0) {
- QAccessibleInterface *res = acc->child(ref.second);
- delete acc;
- if (!res)
- return E_INVALIDARG;
- acc = res;
- }
- } else {
- qWarning("get_accChild got a negative varChildID (%d), but did not find it in cache", childIndex);
- }
+
+ if (childIndex == 0) {
+ // Yes, some AT clients (Active Accessibility Object Inspector)
+ // actually ask for the same object. As a consequence, we need to clone ourselves:
+ acc = accessible;
+ } else if (childIndex < 0) {
+ acc = QAccessible::accessibleInterface((QAccessible::Id)childIndex);
} else {
- if (childIndex) {
- acc = accessible->child(childIndex - 1);
- } else {
- // Yes, some AT clients (Active Accessibility Object Inspector)
- // actually ask for the same object. As a consequence, we need to clone ourselves:
- if (QAccessibleInterface *par = accessible->parent()) {
- const int indexOf = par->indexOfChild(accessible);
- if (indexOf == -1)
- qWarning() << "inconsistent hierarchy, parent:" << par << "child:" << accessible;
- else
- acc = par->child(indexOf);
- delete par;
- }
- }
+ acc = accessible->child(childIndex - 1);
}
if (acc) {
@@ -788,8 +748,9 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accChild(VARIANT varChildI
// moz: [important]
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accChildCount(long* pcountChildren)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
*pcountChildren = accessible->childCount();
@@ -799,8 +760,9 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accChildCount(long* pcount
// moz: [important]
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accParent(IDispatch** ppdispParent)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
QAccessibleInterface *acc = accessible->parent();
@@ -808,8 +770,6 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accParent(IDispatch** ppdi
if (IAccessible *iface = QWindowsAccessibility::wrap(acc)) {
*ppdispParent = iface;
return S_OK;
- } else {
- delete acc;
}
}
@@ -823,8 +783,9 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accParent(IDispatch** ppdi
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accDoDefaultAction(VARIANT varID)
{
Q_UNUSED(varID);
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
if (QAccessibleActionInterface *actionIface = accessible->actionInterface()) {
@@ -840,8 +801,9 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accDoDefaultAction(VARIANT var
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accDefaultAction(VARIANT varID, BSTR* pszDefaultAction)
{
Q_UNUSED(varID);
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
*pszDefaultAction = 0;
@@ -855,14 +817,15 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accDefaultAction(VARIANT v
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accDescription(VARIANT varID, BSTR* pszDescription)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
QString descr;
if (varID.lVal) {
- QAIPointer child = childPointer(varID);
+ QAccessibleInterface *child = childPointer(varID);
if (!child)
return E_FAIL;
descr = child->text(QAccessible::Description);
@@ -880,13 +843,14 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accDescription(VARIANT var
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accHelp(VARIANT varID, BSTR *pszHelp)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
QString help;
if (varID.lVal) {
- QAIPointer child = childPointer(varID);
+ QAccessibleInterface *child = childPointer(varID);
if (!child)
return E_FAIL;
help = child->text(QAccessible::Help);
@@ -910,8 +874,9 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accHelpTopic(BSTR *, VARIA
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accKeyboardShortcut(VARIANT varID, BSTR *pszKeyboardShortcut)
{
Q_UNUSED(varID);
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
*pszKeyboardShortcut = 0;
@@ -931,29 +896,26 @@ static QAccessibleInterface *relatedInterface(QAccessibleInterface *iface, QAcce
typedef QPair<QAccessibleInterface *, QAccessible::Relation> RelationPair;
QVector<RelationPair> rels = iface->relations(flag);
- for (int i = 1; i < rels.count(); ++i)
- delete rels.at(i).first;
-
return rels.value(0).first;
}
// moz: [important]
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accName(VARIANT varID, BSTR* pszName)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
QString name;
if (varID.lVal) {
- QAIPointer child = childPointer(varID);
+ QAccessibleInterface *child = childPointer(varID);
if (!child)
return E_FAIL;
name = child->text(QAccessible::Name);
if (name.isEmpty()) {
- if (QAccessibleInterface *labelInterface = relatedInterface(child.data(), QAccessible::Label)) {
+ if (QAccessibleInterface *labelInterface = relatedInterface(child, QAccessible::Label)) {
name = labelInterface->text(QAccessible::Name);
- delete labelInterface;
}
}
} else {
@@ -961,7 +923,6 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accName(VARIANT varID, BST
if (name.isEmpty()) {
if (QAccessibleInterface *labelInterface = relatedInterface(accessible, QAccessible::Label)) {
name = labelInterface->text(QAccessible::Name);
- delete labelInterface;
}
}
}
@@ -976,6 +937,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accName(VARIANT varID, BST
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::put_accName(VARIANT, BSTR)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
return DISP_E_MEMBERNOTFOUND;
}
@@ -983,13 +945,14 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::put_accName(VARIANT, BSTR)
// moz: [important]
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accRole(VARIANT varID, VARIANT *pvarRole)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
QAccessible::Role role;
if (varID.lVal) {
- QAIPointer child = childPointer(varID);
+ QAccessibleInterface *child = childPointer(varID);
if (!child)
return E_FAIL;
role = child->role();
@@ -1017,14 +980,15 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accRole(VARIANT varID, VAR
// moz: [important]
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accState(VARIANT varID, VARIANT *pvarState)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
QAccessible::State state;
if (varID.lVal) {
- QAIPointer child = childPointer(varID);
- if (!child.data())
+ QAccessibleInterface *child = childPointer(varID);
+ if (!child)
return E_FAIL;
state = child->state();
} else {
@@ -1093,11 +1057,12 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accState(VARIANT varID, VA
// moz: [important]
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accValue(VARIANT varID, BSTR* pszValue)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
if (varID.vt != VT_I4)
return E_INVALIDARG;
- if (!accessible->isValid() || varID.lVal) {
+ if (!accessible || !accessible->isValid() || varID.lVal) {
return E_FAIL;
}
@@ -1119,6 +1084,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accValue(VARIANT varID, BS
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::put_accValue(VARIANT, BSTR)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
return DISP_E_MEMBERNOTFOUND;
}
@@ -1128,8 +1094,9 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accSelect(long flagsSelect, VA
{
Q_UNUSED(flagsSelect);
Q_UNUSED(varID);
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
bool res = false;
@@ -1139,17 +1106,17 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accSelect(long flagsSelect, VA
### and if there are no ia2 interfaces we should do nothing??
if (flagsSelect & SELFLAG_TAKEFOCUS)
- res = accessible->doAction(SetFocus, varID.lVal, QVariantList());
+ res = accessible()->doAction(SetFocus, varID.lVal, QVariantList());
if (flagsSelect & SELFLAG_TAKESELECTION) {
- accessible->doAction(ClearSelection, 0, QVariantList());
- res = accessible->doAction(AddToSelection, varID.lVal, QVariantList());
+ accessible()->doAction(ClearSelection, 0, QVariantList());
+ res = accessible()->doAction(AddToSelection, varID.lVal, QVariantList());
}
if (flagsSelect & SELFLAG_EXTENDSELECTION)
- res = accessible->doAction(ExtendSelection, varID.lVal, QVariantList());
+ res = accessible()->doAction(ExtendSelection, varID.lVal, QVariantList());
if (flagsSelect & SELFLAG_ADDSELECTION)
- res = accessible->doAction(AddToSelection, varID.lVal, QVariantList());
+ res = accessible()->doAction(AddToSelection, varID.lVal, QVariantList());
if (flagsSelect & SELFLAG_REMOVESELECTION)
- res = accessible->doAction(RemoveSelection, varID.lVal, QVariantList());
+ res = accessible()->doAction(RemoveSelection, varID.lVal, QVariantList());
*/
return res ? S_OK : S_FALSE;
}
@@ -1172,15 +1139,15 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accSelect(long flagsSelect, VA
*/
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accFocus(VARIANT *pvarID)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
if (QAccessibleInterface *acc = accessible->focusChild()) {
- if (compareAccessible(acc, accessible)) {
+ if (acc == accessible) {
(*pvarID).vt = VT_I4;
(*pvarID).lVal = CHILDID_SELF;
- delete acc;
return S_OK;
} else {
if (IAccessible *iface = QWindowsAccessibility::wrap(acc)) {
@@ -1189,7 +1156,6 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accFocus(VARIANT *pvarID)
return S_OK;
}
}
- delete acc;
}
(*pvarID).vt = VT_EMPTY;
return S_FALSE;
@@ -1197,8 +1163,9 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accFocus(VARIANT *pvarID)
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accSelection(VARIANT *pvarChildren)
{
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
int cc = accessible->childCount();
@@ -1209,7 +1176,6 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accSelection(VARIANT *pvar
QAccessibleInterface *child = accessible->child(i);
if (child) {
isSelected = child->state().selected;
- delete child;
}
if (isSelected)
sel[selIndex++] = i+1;
@@ -1239,11 +1205,10 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accSelection(VARIANT *pvar
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::GetWindow(HWND *phwnd)
{
*phwnd = 0;
+ QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- if (!accessible->isValid())
+ if (!accessible)
return E_FAIL;
- if (!accessible->isValid())
- return E_UNEXPECTED;
QWindow *window = QWindowsAccessibility::windowHelper(accessible);
if (!window)
diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h
index ecb2e2bc18..ef17acf3e9 100644
--- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h
+++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h
@@ -76,8 +76,6 @@ void accessibleDebugClientCalls_helper(const char* funcName, const QAccessibleIn
# define accessibleDebugClientCalls(iface)
#endif
-typedef QSharedPointer<QAccessibleInterface> QAIPointer;
-
QWindow *window_helper(const QAccessibleInterface *iface);
/**************************************************************\
@@ -93,14 +91,13 @@ class QWindowsMsaaAccessible : public
{
public:
QWindowsMsaaAccessible(QAccessibleInterface *a)
- : accessible(a)
- , ref(0)
+ : ref(0)
{
+ id = QAccessible::uniqueId(a);
}
virtual ~QWindowsMsaaAccessible()
{
- delete accessible;
}
/* IUnknown */
@@ -146,11 +143,23 @@ public:
protected:
virtual QByteArray IIDToString(REFIID id);
- QAccessibleInterface *accessible;
+ QAccessible::Id id;
+
+ QAccessibleInterface *accessibleInterface() const
+ {
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(id);
+ if (iface && iface->isValid())
+ return iface;
+ return 0;
+ }
- QAIPointer childPointer(VARIANT varID)
+ QAccessibleInterface *childPointer(VARIANT varID)
{
- return QAIPointer(accessible->child(varID.lVal - 1));
+ // -1 since windows API always uses 1 for the first child
+ QAccessibleInterface *iface = accessibleInterface();
+ if (iface)
+ return accessibleInterface()->child(varID.lVal - 1);
+ return 0;
}
private:
diff --git a/src/plugins/platforms/windows/qtwindows_additional.h b/src/plugins/platforms/windows/qtwindows_additional.h
index 8d59fbd7c6..3b2e9787a2 100644
--- a/src/plugins/platforms/windows/qtwindows_additional.h
+++ b/src/plugins/platforms/windows/qtwindows_additional.h
@@ -126,6 +126,10 @@ typedef struct tagUPDATELAYEREDWINDOWINFO {
// IME.
#define IMR_CONFIRMRECONVERTSTRING 0x0005
+#ifndef MAPVK_VK_TO_CHAR
+# define MAPVK_VK_TO_CHAR 2
+#endif
+
#endif // if defined(Q_CC_MINGW)
/* Touch is supported from Windows 7 onwards and data structures
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index 88c9bf448d..545484de8d 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -372,56 +372,53 @@ void QWindowsContext::setKeyGrabber(QWindow *w)
}
// Window class registering code (from qapplication_win.cpp)
-// If 0 is passed as the widget pointer, register a window class
-// for QWidget as default. This is used in QGLTemporaryContext
-// during GL initialization, where we don't want to use temporary
-// QWidgets or QGLWidgets, neither do we want to have separate code
-// to register window classes.
QString QWindowsContext::registerWindowClass(const QWindow *w, bool isGL)
{
- const Qt::WindowFlags flags = w ? w->flags() : (Qt::WindowFlags)0;
+ Q_ASSERT(w);
+ const Qt::WindowFlags flags = w->flags();
const Qt::WindowFlags type = flags & Qt::WindowType_Mask;
-
- uint style = 0;
- bool icon = false;
- QString cname = QStringLiteral("Qt5");
- if (w && isGL) {
- cname += QStringLiteral("QGLWindow");
- style = CS_DBLCLKS|CS_OWNDC;
- icon = true;
- } else if (w && (flags & Qt::MSWindowsOwnDC)) {
- cname += QStringLiteral("QWindowOwnDC");
- style = CS_DBLCLKS|CS_OWNDC;
- icon = true;
- } else if (w && (type == Qt::Tool || type == Qt::ToolTip)) {
- style = CS_DBLCLKS;
- if (w->inherits("QTipLabel") || w->inherits("QAlphaWidget")) {
- if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP
- && (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based))) {
- style |= CS_DROPSHADOW;
- }
- cname += QStringLiteral("QToolTip");
- } else {
- cname += QStringLiteral("QTool");
- }
- style |= CS_SAVEBITS;
- icon = false;
- } else if (w && (type == Qt::Popup)) {
- cname += QStringLiteral("QPopup");
- style = CS_DBLCLKS|CS_SAVEBITS;
- if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP
- && (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based)))
- style |= CS_DROPSHADOW;
+ // Determine style and icon.
+ uint style = CS_DBLCLKS;
+ bool icon = true;
+ if (isGL || (flags & Qt::MSWindowsOwnDC))
+ style |= CS_OWNDC;
+ if ((QSysInfo::WindowsVersion & QSysInfo::WV_NT_based)
+ && (type == Qt::Popup || w->property("_q_windowsDropShadow").toBool())) {
+ style |= CS_DROPSHADOW;
+ }
+ if (type == Qt::Tool || type == Qt::ToolTip || type == Qt::Popup) {
+ style |= CS_SAVEBITS; // Save/restore background
icon = false;
- } else {
- cname += QStringLiteral("QWindow");
- style = CS_DBLCLKS;
- icon = true;
}
+ // Create a unique name for the flag combination
+ QString cname = QStringLiteral("Qt5QWindow");
+ switch (type) {
+ case Qt::Tool:
+ cname += QStringLiteral("Tool");
+ break;
+ case Qt::ToolTip:
+ cname += QStringLiteral("ToolTip");
+ break;
+ case Qt::Popup:
+ cname += QStringLiteral("Popup");
+ break;
+ default:
+ break;
+ }
+ if (isGL)
+ cname += QStringLiteral("GL");
+ if (style & CS_DROPSHADOW)
+ cname += QStringLiteral("DropShadow");
+ if (style & CS_SAVEBITS)
+ cname += QStringLiteral("SaveBits");
+ if (style & CS_OWNDC)
+ cname += QStringLiteral("OwnDC");
+ if (icon)
+ cname += QStringLiteral("Icon");
HBRUSH brush = 0;
- if (w && !isGL)
+ if (!isGL)
brush = GetSysColorBrush(COLOR_WINDOW);
return registerWindowClass(cname, qWindowsWndProc, style, brush, icon);
}
@@ -787,7 +784,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
d->m_creationContext->obtainedGeometry.moveTo(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
return true;
case QtWindows::CalculateSize:
- return false;
+ return QWindowsGeometryHint::handleCalculateSize(d->m_creationContext->customMargins, msg, result);
default:
break;
}
@@ -822,12 +819,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
platformWindow->getSizeHints(reinterpret_cast<MINMAXINFO *>(lParam));
return true;// maybe available on some SDKs revisit WM_NCCALCSIZE
case QtWindows::CalculateSize:
- // NCCALCSIZE_PARAMS structure if wParam==TRUE
- if (wParam && QWindowsContext::verboseWindows) {
- const NCCALCSIZE_PARAMS *ncp = reinterpret_cast<NCCALCSIZE_PARAMS *>(lParam);
- qDebug() << platformWindow->window() << *ncp;
- }
- break;
+ return QWindowsGeometryHint::handleCalculateSize(platformWindow->customMargins(), msg, result);
#endif
case QtWindows::ExposeEvent:
return platformWindow->handleWmPaint(hwnd, message, wParam, lParam);
@@ -858,10 +850,10 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
return true;
case QtWindows::ShowEvent:
platformWindow->handleShown();
- return true;
+ return false; // Indicate transient children should be shown by windows (SW_PARENTOPENING)
case QtWindows::HideEvent:
platformWindow->handleHidden();
- return true;
+ return false;// Indicate transient children should be hidden by windows (SW_PARENTCLOSING)
case QtWindows::CloseEvent:
QWindowSystemInterface::handleCloseEvent(platformWindow->window());
return true;
diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp
index 4dc9af61d8..5b2a3acbae 100644
--- a/src/plugins/platforms/windows/qwindowscursor.cpp
+++ b/src/plugins/platforms/windows/qwindowscursor.cpp
@@ -395,6 +395,19 @@ QWindowsWindowCursor QWindowsCursor::standardWindowCursor(Qt::CursorShape shape)
}
/*!
+ \brief Return cached pixmap cursor or create new one.
+*/
+
+QWindowsWindowCursor QWindowsCursor::pixmapWindowCursor(const QCursor &c)
+{
+ const qint64 cacheKey = c.pixmap().cacheKey();
+ PixmapCursorCache::iterator it = m_pixmapCursorCache.find(cacheKey);
+ if (it == m_pixmapCursorCache.end())
+ it = m_pixmapCursorCache.insert(cacheKey, QWindowsWindowCursor(c));
+ return it.value();
+}
+
+/*!
\brief Set a cursor on a window.
This is called frequently as the mouse moves over widgets in the window
@@ -406,11 +419,15 @@ void QWindowsCursor::changeCursor(QCursor *cursorIn, QWindow *window)
if (QWindowsContext::verboseWindows > 1)
qDebug() << __FUNCTION__ << cursorIn << window;
- if (!cursorIn || !window)
+ if (!window)
+ return;
+ if (!cursorIn) {
+ QWindowsWindow::baseWindowOf(window)->setCursor(QWindowsWindowCursor());
return;
+ }
const QWindowsWindowCursor wcursor =
cursorIn->shape() == Qt::BitmapCursor ?
- QWindowsWindowCursor(*cursorIn) : standardWindowCursor(cursorIn->shape());
+ pixmapWindowCursor(*cursorIn) : standardWindowCursor(cursorIn->shape());
if (wcursor.handle()) {
QWindowsWindow::baseWindowOf(window)->setCursor(wcursor);
} else {
@@ -449,6 +466,7 @@ void QWindowsCursor::setPos(const QPoint &pos)
class QWindowsWindowCursorData : public QSharedData
{
public:
+ QWindowsWindowCursorData() : m_cursor(Qt::ArrowCursor), m_handle(0) {}
explicit QWindowsWindowCursorData(const QCursor &c);
~QWindowsWindowCursorData();
@@ -464,7 +482,13 @@ QWindowsWindowCursorData::QWindowsWindowCursorData(const QCursor &c) :
QWindowsWindowCursorData::~QWindowsWindowCursorData()
{
- DestroyCursor(m_handle);
+ if (m_handle)
+ DestroyCursor(m_handle);
+}
+
+QWindowsWindowCursor::QWindowsWindowCursor() :
+ m_data(new QWindowsWindowCursorData)
+{
}
QWindowsWindowCursor::QWindowsWindowCursor(const QCursor &c) :
@@ -488,6 +512,11 @@ QWindowsWindowCursor & QWindowsWindowCursor::operator =(const QWindowsWindowCurs
return *this;
}
+bool QWindowsWindowCursor::isNull() const
+{
+ return m_data->m_handle == 0;
+}
+
QCursor QWindowsWindowCursor::cursor() const
{
return m_data->m_cursor;
diff --git a/src/plugins/platforms/windows/qwindowscursor.h b/src/plugins/platforms/windows/qwindowscursor.h
index b0256d4203..1e818bc9b8 100644
--- a/src/plugins/platforms/windows/qwindowscursor.h
+++ b/src/plugins/platforms/windows/qwindowscursor.h
@@ -55,11 +55,13 @@ class QWindowsWindowCursorData;
class QWindowsWindowCursor
{
public:
+ QWindowsWindowCursor();
explicit QWindowsWindowCursor(const QCursor &c);
~QWindowsWindowCursor();
QWindowsWindowCursor(const QWindowsWindowCursor &c);
QWindowsWindowCursor &operator=(const QWindowsWindowCursor &c);
+ bool isNull() const;
QCursor cursor() const;
HCURSOR handle() const;
@@ -81,11 +83,14 @@ public:
static QPoint mousePosition();
QWindowsWindowCursor standardWindowCursor(Qt::CursorShape s = Qt::ArrowCursor);
+ QWindowsWindowCursor pixmapWindowCursor(const QCursor &c);
private:
typedef QHash<Qt::CursorShape, QWindowsWindowCursor> StandardCursorCache;
+ typedef QHash<qint64, QWindowsWindowCursor> PixmapCursorCache;
StandardCursorCache m_standardCursorCache;
+ PixmapCursorCache m_pixmapCursorCache;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
index daa4369d88..8565bf0204 100644
--- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
+++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
@@ -58,6 +58,10 @@
#include <QtCore/QObject>
#include <QtCore/QThread>
#include <QtCore/QSysInfo>
+#include <QtCore/QSharedData>
+#include <QtCore/QExplicitlySharedDataPointer>
+#include <QtCore/QMutex>
+#include <QtCore/QMutexLocker>
#include <QtCore/private/qsystemlibrary_p.h>
#include "qtwindows_additional.h"
@@ -82,6 +86,8 @@ static const IID q_IID_IShellItem = {0x43826d1e, 0xe718, 0x42ee, {0xbc, 0
#define IID_IShellItem q_IID_IShellItem
#else
static const IID IID_IShellItem = {0x43826d1e, 0xe718, 0x42ee, {0xbc, 0x55, 0xa1, 0xe2, 0x61, 0xc3, 0x7b, 0xfe}};
+static const IID IID_IShellItemArray = {0xb63ea76d, 0x1f85, 0x456f, {0xa1, 0x9c, 0x48, 0x15, 0x9e, 0xfa, 0x85, 0x8b}};
+# define LFF_FORCEFILESYSTEM 1
#endif
static const IID IID_IFileDialogEvents = {0x973510db, 0x7d7f, 0x452b,{0x89, 0x75, 0x74, 0xa8, 0x58, 0x28, 0xd3, 0x54}};
static const CLSID CLSID_FileOpenDialog = {0xdc1c5a9c, 0xe88a, 0x4dde, {0xa5, 0xa1, 0x60, 0xf8, 0x2a, 0x20, 0xae, 0xf7}};
@@ -249,6 +255,34 @@ DECLARE_INTERFACE_(IShellItemArray, IUnknown)
};
#endif
+#ifndef __IShellLibrary_INTERFACE_DEFINED__
+
+enum LIBRARYOPTIONFLAGS {};
+enum DEFAULTSAVEFOLDERTYPE { DSFT_DETECT = 1 };
+enum LIBRARYSAVEFLAGS {};
+
+DECLARE_INTERFACE_(IShellLibrary, IUnknown)
+{
+ STDMETHOD(LoadLibraryFromItem)(THIS_ IShellItem *psiLibrary, DWORD grfMode) PURE;
+ STDMETHOD(LoadLibraryFromKnownFolder)(THIS_ const GUID &kfidLibrary, DWORD grfMode) PURE;
+ STDMETHOD(AddFolder)(THIS_ IShellItem *psiLocation) PURE;
+ STDMETHOD(RemoveFolder)(THIS_ IShellItem *psiLocation) PURE;
+ STDMETHOD(GetFolders)(THIS_ int lff, REFIID riid, void **ppv) PURE;
+ STDMETHOD(ResolveFolder)(THIS_ IShellItem *psiFolderToResolve, DWORD dwTimeout, REFIID riid, void **ppv) PURE;
+ STDMETHOD(GetDefaultSaveFolder)(THIS_ DEFAULTSAVEFOLDERTYPE dsft, REFIID riid, void **ppv) PURE;
+ STDMETHOD(SetDefaultSaveFolder)(THIS_ DEFAULTSAVEFOLDERTYPE dsft, IShellItem *psi) PURE;
+ STDMETHOD(GetOptions)(THIS_ LIBRARYOPTIONFLAGS *plofOptions) PURE;
+ STDMETHOD(SetOptions)(THIS_ LIBRARYOPTIONFLAGS lofMask, LIBRARYOPTIONFLAGS lofOptions) PURE;
+ STDMETHOD(GetFolderType)(THIS_ GUID *pftid) PURE;
+ STDMETHOD(SetFolderType)(THIS_ const GUID &ftid) PURE;
+ STDMETHOD(GetIcon)(THIS_ LPWSTR *ppszIcon) PURE;
+ STDMETHOD(SetIcon)(THIS_ LPCWSTR pszIcon) PURE;
+ STDMETHOD(Commit)(THIS_) PURE;
+ STDMETHOD(Save)(THIS_ IShellItem *psiFolderToSaveIn, LPCWSTR pszLibraryName, LIBRARYSAVEFLAGS lsf, IShellItem **ppsiSavedTo) PURE;
+ STDMETHOD(SaveInKnownFolder)(THIS_ const GUID &kfidToSaveIn, LPCWSTR pszLibraryName, LIBRARYSAVEFLAGS lsf,IShellItem **ppsiSavedTo) PURE;
+};
+#endif
+
#ifndef __IModalWindow_INTERFACE_DEFINED__
DECLARE_INTERFACE_(IModalWindow, IUnknown)
{
@@ -387,6 +421,9 @@ void eatMouseMove()
Vista on) that mimick the behaviour of their QDialog
counterparts as close as possible.
+ Instances of derived classes are controlled by
+ QWindowsDialogHelperBase-derived classes.
+
A major difference is that there is only an exec(), which
is a modal, blocking call; there is no non-blocking show().
There 2 types of native dialogs:
@@ -401,6 +438,7 @@ void eatMouseMove()
like close() can be called on them from event handlers.
\endlist
+ \sa QWindowsDialogHelperBase
\internal
\ingroup qt-lighthouse-win
*/
@@ -411,7 +449,6 @@ class QWindowsNativeDialogBase : public QObject
public:
virtual void setWindowTitle(const QString &title) = 0;
virtual void exec(HWND owner = 0) = 0;
- virtual QPlatformDialogHelper::DialogCode result() const = 0;
signals:
void accepted();
@@ -432,12 +469,10 @@ protected:
The native dialog is created in setVisible_sys() since
then modality and the state of DontUseNativeDialog is known.
- Modal dialogs are then started via the platformNativeDialogModalHelp(),
- platformNativeDialogModalHelp() slots.
- Non-modal dialogs are shown using a separate thread should
- they support it.
+ Modal dialogs are then run by exec(). Non-modal dialogs are shown using a
+ separate thread started in show() should they support it.
- \sa QWindowsDialogThread
+ \sa QWindowsDialogThread, QWindowsNativeDialogBase
\internal
\ingroup qt-lighthouse-win
*/
@@ -445,17 +480,12 @@ protected:
template <class BaseClass>
QWindowsDialogHelperBase<BaseClass>::QWindowsDialogHelperBase() :
m_nativeDialog(0),
- m_ownerWindow(0)
+ m_ownerWindow(0),
+ m_timerId(0)
{
}
template <class BaseClass>
-QWindowsDialogHelperBase<BaseClass>::~QWindowsDialogHelperBase()
-{
- delete m_nativeDialog;
-}
-
-template <class BaseClass>
QWindowsNativeDialogBase *QWindowsDialogHelperBase<BaseClass>::nativeDialog() const
{
if (!m_nativeDialog) {
@@ -466,6 +496,19 @@ QWindowsNativeDialogBase *QWindowsDialogHelperBase<BaseClass>::nativeDialog() co
}
template <class BaseClass>
+void QWindowsDialogHelperBase<BaseClass>::deleteNativeDialog()
+{
+ delete m_nativeDialog;
+ m_nativeDialog = 0;
+}
+
+template <class BaseClass>
+void QWindowsDialogHelperBase<BaseClass>::timerEvent(QTimerEvent *)
+{
+ startDialogThread();
+}
+
+template <class BaseClass>
QWindowsNativeDialogBase *QWindowsDialogHelperBase<BaseClass>::ensureNativeDialog()
{
// Create dialog and apply common settings.
@@ -486,22 +529,18 @@ QWindowsNativeDialogBase *QWindowsDialogHelperBase<BaseClass>::ensureNativeDialo
class QWindowsDialogThread : public QThread
{
public:
- QWindowsDialogThread(QWindowsNativeDialogBase *dialog,
- HWND owner = 0) :
- m_dialog(dialog), m_owner(owner) {}
-
+ QWindowsDialogThread(QPlatformDialogHelper *h) : m_helper(h) {}
void run();
private:
- QWindowsNativeDialogBase *m_dialog;
- const HWND m_owner;
+ QPlatformDialogHelper *m_helper;
};
void QWindowsDialogThread::run()
{
if (QWindowsContext::verboseDialogs)
qDebug(">%s" , __FUNCTION__);
- m_dialog->exec(m_owner);
+ m_helper->exec();
deleteLater();
if (QWindowsContext::verboseDialogs)
qDebug("<%s" , __FUNCTION__);
@@ -512,7 +551,7 @@ bool QWindowsDialogHelperBase<BaseClass>::show(Qt::WindowFlags,
Qt::WindowModality windowModality,
QWindow *parent)
{
- const bool modal = (windowModality == Qt::ApplicationModal);
+ const bool modal = (windowModality != Qt::NonModal);
if (parent) {
m_ownerWindow = QWindowsWindow::handleOf(parent);
} else {
@@ -521,18 +560,40 @@ bool QWindowsDialogHelperBase<BaseClass>::show(Qt::WindowFlags,
if (QWindowsContext::verboseDialogs)
qDebug("%s modal=%d native=%p parent=%p" ,
__FUNCTION__, modal, m_nativeDialog, m_ownerWindow);
- if (!modal && !supportsNonModalDialog())
+ if (!modal && !supportsNonModalDialog(parent))
return false; // Was it changed in-between?
if (!ensureNativeDialog())
return false;
- if (!modal) { // Modal dialogs are shown in separate slot.
- QWindowsDialogThread *thread = new QWindowsDialogThread(m_nativeDialog, m_ownerWindow);
- thread->start();
+ // Start a background thread to show the dialog. For modal dialogs,
+ // a subsequent call to exec() may follow. So, start an idle timer
+ // which will start the dialog thread. If exec() is then called, the
+ // timer is stopped and dialog->exec() is called directly.
+ if (modal) {
+ m_timerId = this->startTimer(0);
+ } else {
+ startDialogThread();
}
return true;
}
template <class BaseClass>
+void QWindowsDialogHelperBase<BaseClass>::startDialogThread()
+{
+ QWindowsDialogThread *thread = new QWindowsDialogThread(this);
+ thread->start();
+ stopTimer();
+}
+
+template <class BaseClass>
+void QWindowsDialogHelperBase<BaseClass>::stopTimer()
+{
+ if (m_timerId) {
+ this->killTimer(m_timerId);
+ m_timerId = 0;
+ }
+}
+
+template <class BaseClass>
void QWindowsDialogHelperBase<BaseClass>::hide()
{
if (m_nativeDialog)
@@ -545,8 +606,11 @@ void QWindowsDialogHelperBase<BaseClass>::exec()
{
if (QWindowsContext::verboseDialogs)
qDebug("%s" , __FUNCTION__);
- if (QWindowsNativeDialogBase *nd = nativeDialog())
+ stopTimer();
+ if (QWindowsNativeDialogBase *nd = nativeDialog()) {
nd->exec(m_ownerWindow);
+ deleteNativeDialog();
+ }
}
static inline bool snapToDefaultButtonHint()
@@ -568,6 +632,101 @@ QVariant QWindowsDialogHelperBase<BaseClass>::styleHint(QPlatformDialogHelper::S
}
/*!
+ \class QWindowsFileDialogSharedData
+ \brief Explicitly shared file dialog parameters that are not in QFileDialogOptions.
+
+ Contain Parameters that need to be cached while the native dialog does not
+ exist yet. In addition, the data are updated by the change notifications of the
+ IFileDialogEvent, as querying them after the dialog has closed
+ does not reliably work. Provides thread-safe setters (for the non-modal case).
+
+ \internal
+ \ingroup qt-lighthouse-win
+ \sa QFileDialogOptions
+*/
+
+class QWindowsFileDialogSharedData
+{
+public:
+ QWindowsFileDialogSharedData() : m_data(new Data) {}
+ void fromOptions(const QSharedPointer<QFileDialogOptions> &o);
+
+ QString directory() const;
+ void setDirectory(const QString &);
+ QString selectedNameFilter() const;
+ void setSelectedNameFilter(const QString &);
+ QStringList selectedFiles() const;
+ void setSelectedFiles(const QStringList &);
+ QString selectedFile() const;
+
+private:
+ class Data : public QSharedData {
+ public:
+ QString directory;
+ QString selectedNameFilter;
+ QStringList selectedFiles;
+ QMutex mutex;
+ };
+ QExplicitlySharedDataPointer<Data> m_data;
+};
+
+inline QString QWindowsFileDialogSharedData::directory() const
+{
+ m_data->mutex.lock();
+ const QString result = m_data->directory;
+ m_data->mutex.unlock();
+ return result;
+}
+
+inline void QWindowsFileDialogSharedData::setDirectory(const QString &d)
+{
+ QMutexLocker (&m_data->mutex);
+ m_data->directory = d;
+}
+
+inline QString QWindowsFileDialogSharedData::selectedNameFilter() const
+{
+ m_data->mutex.lock();
+ const QString result = m_data->selectedNameFilter;
+ m_data->mutex.unlock();
+ return result;
+}
+
+inline void QWindowsFileDialogSharedData::setSelectedNameFilter(const QString &f)
+{
+ QMutexLocker (&m_data->mutex);
+ m_data->selectedNameFilter = f;
+}
+
+inline QStringList QWindowsFileDialogSharedData::selectedFiles() const
+{
+ m_data->mutex.lock();
+ const QStringList result = m_data->selectedFiles;
+ m_data->mutex.unlock();
+ return result;
+}
+
+inline QString QWindowsFileDialogSharedData::selectedFile() const
+{
+ const QStringList files = selectedFiles();
+ return files.isEmpty() ? QString() : files.front();
+}
+
+inline void QWindowsFileDialogSharedData::setSelectedFiles(const QStringList &f)
+{
+ QMutexLocker (&m_data->mutex);
+ m_data->selectedFiles = f;
+}
+
+inline void QWindowsFileDialogSharedData::fromOptions(const QSharedPointer<QFileDialogOptions> &o)
+{
+ QMutexLocker (&m_data->mutex);
+ m_data->directory = o->initialDirectory();
+ m_data->selectedFiles = o->initiallySelectedFiles();
+ m_data->selectedNameFilter = o->initiallySelectedNameFilter();
+}
+
+/*!
\class QWindowsNativeFileDialogEventHandler
\brief Listens to IFileDialog events and forwards them to QWindowsNativeFileDialogBase
@@ -609,7 +768,7 @@ public:
}
// IFileDialogEvents methods
- IFACEMETHODIMP OnFileOk(IFileDialog *) { return S_OK; }
+ IFACEMETHODIMP OnFileOk(IFileDialog *);
IFACEMETHODIMP OnFolderChange(IFileDialog *) { return S_OK; }
IFACEMETHODIMP OnFolderChanging(IFileDialog *, IShellItem *);
IFACEMETHODIMP OnHelp(IFileDialog *) { return S_OK; }
@@ -658,15 +817,17 @@ class QWindowsNativeFileDialogBase : public QWindowsNativeDialogBase
public:
~QWindowsNativeFileDialogBase();
- inline static QWindowsNativeFileDialogBase *create(QFileDialogOptions::AcceptMode am);
+ inline static QWindowsNativeFileDialogBase *create(QFileDialogOptions::AcceptMode am, const QWindowsFileDialogSharedData &data);
virtual void setWindowTitle(const QString &title);
inline void setMode(QFileDialogOptions::FileMode mode, QFileDialogOptions::FileDialogOptions options);
inline void setDirectory(const QString &directory);
+ inline void updateDirectory() { setDirectory(m_data.directory()); }
inline QString directory() const;
virtual void exec(HWND owner = 0);
inline void setNameFilters(const QStringList &f);
inline void selectNameFilter(const QString &filter);
+ inline void updateSelectedNameFilter() { selectNameFilter(m_data.selectedNameFilter()); }
inline QString selectedNameFilter() const;
void selectFile(const QString &fileName) const;
bool hideFiltersDetails() const { return m_hideFiltersDetails; }
@@ -674,14 +835,16 @@ public:
void setDefaultSuffix(const QString &s);
inline void setLabelText(QFileDialogOptions::DialogLabel l, const QString &text);
- virtual QPlatformDialogHelper::DialogCode result() const
- { return fileResult(); }
- virtual QPlatformDialogHelper::DialogCode fileResult(QStringList *fileResult = 0) const = 0;
+ // Return the selected files for tracking in OnSelectionChanged().
virtual QStringList selectedFiles() const = 0;
+ // Return the result for tracking in OnFileOk(). Differs from selection for
+ // example by appended default suffixes, etc.
+ virtual QStringList dialogResult() const = 0;
inline void onFolderChange(IShellItem *);
inline void onSelectionChange();
inline void onTypeChange();
+ inline bool onFileOk();
signals:
void directoryEntered(const QString& directory);
@@ -692,23 +855,30 @@ public slots:
virtual void close() { m_fileDialog->Close(S_OK); }
protected:
- QWindowsNativeFileDialogBase();
+ explicit QWindowsNativeFileDialogBase(const QWindowsFileDialogSharedData &data);
bool init(const CLSID &clsId, const IID &iid);
inline IFileDialog * fileDialog() const { return m_fileDialog; }
static QString itemPath(IShellItem *item);
+ static QStringList libraryItemFolders(IShellItem *item);
+ static QString libraryItemDefaultSaveFolder(IShellItem *item);
static int itemPaths(IShellItemArray *items, QStringList *fileResult = 0);
static IShellItem *shellItem(const QString &path);
+ const QWindowsFileDialogSharedData &data() const { return m_data; }
+ QWindowsFileDialogSharedData &data() { return m_data; }
+
private:
IFileDialog *m_fileDialog;
IFileDialogEvents *m_dialogEvents;
DWORD m_cookie;
QStringList m_nameFilters;
bool m_hideFiltersDetails;
+ QWindowsFileDialogSharedData m_data;
};
-QWindowsNativeFileDialogBase::QWindowsNativeFileDialogBase() :
- m_fileDialog(0), m_dialogEvents(0), m_cookie(0), m_hideFiltersDetails(false)
+QWindowsNativeFileDialogBase::QWindowsNativeFileDialogBase(const QWindowsFileDialogSharedData &data) :
+ m_fileDialog(0), m_dialogEvents(0), m_cookie(0), m_hideFiltersDetails(false),
+ m_data(data)
{
}
@@ -764,15 +934,17 @@ IShellItem *QWindowsNativeFileDialogBase::shellItem(const QString &path)
return result;
}
#endif
- qErrnoWarning("%s: SHCreateItemFromParsingName()) failed", __FUNCTION__);
+ qErrnoWarning("%s: SHCreateItemFromParsingName(%s)) failed", __FUNCTION__, qPrintable(path));
return 0;
}
void QWindowsNativeFileDialogBase::setDirectory(const QString &directory)
{
- if (IShellItem *psi = QWindowsNativeFileDialogBase::shellItem(directory)) {
- m_fileDialog->SetFolder(psi);
- psi->Release();
+ if (!directory.isEmpty()) {
+ if (IShellItem *psi = QWindowsNativeFileDialogBase::shellItem(directory)) {
+ m_fileDialog->SetFolder(psi);
+ psi->Release();
+ }
}
}
@@ -832,17 +1004,94 @@ void QWindowsNativeFileDialogBase::setMode(QFileDialogOptions::FileMode mode, QF
qErrnoWarning("%s: SetOptions() failed", __FUNCTION__);
}
-QString QWindowsNativeFileDialogBase::itemPath(IShellItem *item)
+#if !defined(Q_OS_WINCE) && defined(__IShellLibrary_INTERFACE_DEFINED__) // Windows SDK 7
+
+// Helper for "Libraries": collections of folders appearing from Windows 7
+// on, visible in the file dialogs.
+
+// Load a library from a IShellItem (sanitized copy of the inline function
+// SHLoadLibraryFromItem from ShObjIdl.h, which does not exist for MinGW).
+static IShellLibrary *sHLoadLibraryFromItem(IShellItem *libraryItem, DWORD mode)
+{
+ // ID symbols present from Windows 7 on:
+ static const CLSID classId_ShellLibrary = {0xd9b3211d, 0xe57f, 0x4426, {0xaa, 0xef, 0x30, 0xa8, 0x6, 0xad, 0xd3, 0x97}};
+ static const IID iId_IShellLibrary = {0x11a66efa, 0x382e, 0x451a, {0x92, 0x34, 0x1e, 0xe, 0x12, 0xef, 0x30, 0x85}};
+
+ IShellLibrary *helper = 0;
+ IShellLibrary *result = 0;
+ if (SUCCEEDED(CoCreateInstance(classId_ShellLibrary, NULL, CLSCTX_INPROC_SERVER, iId_IShellLibrary, reinterpret_cast<void **>(&helper))))
+ if (SUCCEEDED(helper->LoadLibraryFromItem(libraryItem, mode)))
+ helper->QueryInterface(iId_IShellLibrary, reinterpret_cast<void **>(&result));
+ if (helper)
+ helper->Release();
+ return result;
+}
+
+// Return all folders of a library-type item.
+QStringList QWindowsNativeFileDialogBase::libraryItemFolders(IShellItem *item)
+{
+ QStringList result;
+ if (IShellLibrary *library = sHLoadLibraryFromItem(item, STGM_READ | STGM_SHARE_DENY_WRITE)) {
+ IShellItemArray *itemArray = 0;
+ if (SUCCEEDED(library->GetFolders(LFF_FORCEFILESYSTEM, IID_IShellItemArray, reinterpret_cast<void **>(&itemArray)))) {
+ QWindowsNativeFileDialogBase::itemPaths(itemArray, &result);
+ itemArray->Release();
+ }
+ library->Release();
+ }
+ return result;
+}
+
+// Return default save folders of a library-type item.
+QString QWindowsNativeFileDialogBase::libraryItemDefaultSaveFolder(IShellItem *item)
{
QString result;
- LPWSTR name = 0;
- if (SUCCEEDED(item->GetDisplayName(SIGDN_FILESYSPATH, &name))) {
- result = QDir::cleanPath(QString::fromWCharArray(name));
- CoTaskMemFree(name);
+ if (IShellLibrary *library = sHLoadLibraryFromItem(item, STGM_READ | STGM_SHARE_DENY_WRITE)) {
+ IShellItem *item = 0;
+ if (SUCCEEDED(library->GetDefaultSaveFolder(DSFT_DETECT, IID_IShellItem, reinterpret_cast<void **>(&item)))) {
+ result = QWindowsNativeFileDialogBase::itemPath(item);
+ item->Release();
+ }
+ library->Release();
}
return result;
}
+#else // !Q_OS_WINCE && __IShellLibrary_INTERFACE_DEFINED__
+
+QStringList QWindowsNativeFileDialogBase::libraryItemFolders(IShellItem *)
+{
+ return QStringList();
+}
+
+QString QWindowsNativeFileDialogBase::libraryItemDefaultSaveFolder(IShellItem *)
+{
+ return QString();
+}
+
+#endif // Q_OS_WINCE || !__IShellLibrary_INTERFACE_DEFINED__
+
+QString QWindowsNativeFileDialogBase::itemPath(IShellItem *item)
+{
+ SFGAOF attributes = 0;
+ // Check whether it has a file system representation?
+ if (FAILED(item->GetAttributes(SFGAO_FILESYSTEM, &attributes)))
+ return QString();
+ if (attributes & SFGAO_FILESYSTEM) {
+ LPWSTR name = 0;
+ QString result;
+ if (SUCCEEDED(item->GetDisplayName(SIGDN_FILESYSPATH, &name))) {
+ result = QDir::cleanPath(QString::fromWCharArray(name));
+ CoTaskMemFree(name);
+ }
+ return result;
+ }
+ // Check for a "Library" item
+ if ((QSysInfo::windowsVersion() & QSysInfo::WV_NT_based) && QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7)
+ return QWindowsNativeFileDialogBase::libraryItemDefaultSaveFolder(item);
+ return QString();
+}
+
int QWindowsNativeFileDialogBase::itemPaths(IShellItemArray *items,
QStringList *result /* = 0 */)
{
@@ -983,14 +1232,16 @@ static int indexOfNameFilter(const QStringList &filters, const QString &needle)
void QWindowsNativeFileDialogBase::selectNameFilter(const QString &filter)
{
+ if (filter.isEmpty())
+ return;
const int index = indexOfNameFilter(m_nameFilters, filter);
- if (index >= 0) {
- m_fileDialog->SetFileTypeIndex(index + 1); // one-based.
- } else {
+ if (index < 0) {
qWarning("%s: Invalid parameter '%s' not found in '%s'.",
__FUNCTION__, qPrintable(filter),
qPrintable(m_nameFilters.join(QStringLiteral(", "))));
+ return;
}
+ m_fileDialog->SetFileTypeIndex(index + 1); // one-based.
}
QString QWindowsNativeFileDialogBase::selectedNameFilter() const
@@ -1008,6 +1259,7 @@ void QWindowsNativeFileDialogBase::onFolderChange(IShellItem *item)
{
if (item) {
const QString directory = QWindowsNativeFileDialogBase::itemPath(item);
+ m_data.setDirectory(directory);
emit directoryEntered(directory);
}
}
@@ -1015,13 +1267,23 @@ void QWindowsNativeFileDialogBase::onFolderChange(IShellItem *item)
void QWindowsNativeFileDialogBase::onSelectionChange()
{
const QStringList current = selectedFiles();
+ m_data.setSelectedFiles(current);
if (current.size() == 1)
emit currentChanged(current.front());
}
void QWindowsNativeFileDialogBase::onTypeChange()
{
- emit filterSelected(selectedNameFilter());
+ const QString filter = selectedNameFilter();
+ m_data.setSelectedNameFilter(filter);
+ emit filterSelected(filter);
+}
+
+bool QWindowsNativeFileDialogBase::onFileOk()
+{
+ // Store selected files as GetResults() returns invalid data after the dialog closes.
+ m_data.setSelectedFiles(dialogResult());
+ return true;
}
HRESULT QWindowsNativeFileDialogEventHandler::OnFolderChanging(IFileDialog *, IShellItem *item)
@@ -1042,6 +1304,11 @@ HRESULT QWindowsNativeFileDialogEventHandler::OnTypeChange(IFileDialog *)
return S_OK;
}
+HRESULT QWindowsNativeFileDialogEventHandler::OnFileOk(IFileDialog *)
+{
+ return m_nativeFileDialog->onFileOk() ? S_OK : S_FALSE;
+}
+
/*!
\class QWindowsNativeSaveFileDialog
\brief Windows native file save dialog wrapper around IFileSaveDialog.
@@ -1055,8 +1322,10 @@ HRESULT QWindowsNativeFileDialogEventHandler::OnTypeChange(IFileDialog *)
class QWindowsNativeSaveFileDialog : public QWindowsNativeFileDialogBase
{
public:
- virtual QPlatformDialogHelper::DialogCode fileResult(QStringList *fileResult = 0) const;
+ explicit QWindowsNativeSaveFileDialog(const QWindowsFileDialogSharedData &data) :
+ QWindowsNativeFileDialogBase(data) {}
virtual QStringList selectedFiles() const;
+ virtual QStringList dialogResult() const;
};
// Append a suffix from the name filter "Foo files (*.foo;*.bar)"
@@ -1081,17 +1350,13 @@ static inline QString appendSuffix(const QString &fileName, const QString &filte
return fileName + QLatin1Char('.') + filter.mid(suffixPos, endPos - suffixPos);
}
-QPlatformDialogHelper::DialogCode QWindowsNativeSaveFileDialog::fileResult(QStringList *result /* = 0 */) const
+QStringList QWindowsNativeSaveFileDialog::dialogResult() const
{
- if (result)
- result->clear();
+ QStringList result;
IShellItem *item = 0;
- const HRESULT hr = fileDialog()->GetResult(&item);
- if (FAILED(hr) || !item)
- return QPlatformDialogHelper::Rejected;
- if (result)
- result->push_back(appendSuffix(QWindowsNativeFileDialogBase::itemPath(item), selectedNameFilter()));
- return QPlatformDialogHelper::Accepted;
+ if (SUCCEEDED(fileDialog()->GetResult(&item)) && item)
+ result.push_back(appendSuffix(QWindowsNativeFileDialogBase::itemPath(item), selectedNameFilter()));
+ return result;
}
QStringList QWindowsNativeSaveFileDialog::selectedFiles() const
@@ -1117,23 +1382,23 @@ QStringList QWindowsNativeSaveFileDialog::selectedFiles() const
class QWindowsNativeOpenFileDialog : public QWindowsNativeFileDialogBase
{
public:
- virtual QPlatformDialogHelper::DialogCode fileResult(QStringList *fileResult = 0) const;
+ explicit QWindowsNativeOpenFileDialog(const QWindowsFileDialogSharedData &data) :
+ QWindowsNativeFileDialogBase(data) {}
virtual QStringList selectedFiles() const;
+ virtual QStringList dialogResult() const;
private:
inline IFileOpenDialog *openFileDialog() const
{ return static_cast<IFileOpenDialog *>(fileDialog()); }
};
-QPlatformDialogHelper::DialogCode QWindowsNativeOpenFileDialog::fileResult(QStringList *result /* = 0 */) const
+QStringList QWindowsNativeOpenFileDialog::dialogResult() const
{
- if (result)
- result->clear();
+ QStringList result;
IShellItemArray *items = 0;
- const HRESULT hr = openFileDialog()->GetResults(&items);
- if (SUCCEEDED(hr) && items && QWindowsNativeFileDialogBase::itemPaths(items, result) > 0)
- return QPlatformDialogHelper::Accepted;
- return QPlatformDialogHelper::Rejected;
+ if (SUCCEEDED(openFileDialog()->GetResults(&items)) && items)
+ QWindowsNativeFileDialogBase::itemPaths(items, &result);
+ return result;
}
QStringList QWindowsNativeOpenFileDialog::selectedFiles() const
@@ -1152,17 +1417,18 @@ QStringList QWindowsNativeOpenFileDialog::selectedFiles() const
QFileDialog::AcceptMode.
*/
-QWindowsNativeFileDialogBase *QWindowsNativeFileDialogBase::create(QFileDialogOptions::AcceptMode am)
+QWindowsNativeFileDialogBase *QWindowsNativeFileDialogBase::create(QFileDialogOptions::AcceptMode am,
+ const QWindowsFileDialogSharedData &data)
{
QWindowsNativeFileDialogBase *result = 0;
if (am == QFileDialogOptions::AcceptOpen) {
- result = new QWindowsNativeOpenFileDialog;
+ result = new QWindowsNativeOpenFileDialog(data);
if (!result->init(CLSID_FileOpenDialog, IID_IFileOpenDialog)) {
delete result;
return 0;
}
} else {
- result = new QWindowsNativeSaveFileDialog;
+ result = new QWindowsNativeSaveFileDialog(data);
if (!result->init(CLSID_FileSaveDialog, IID_IFileSaveDialog)) {
delete result;
return 0;
@@ -1171,16 +1437,17 @@ QWindowsNativeFileDialogBase *QWindowsNativeFileDialogBase::create(QFileDialogOp
return result;
}
+static inline bool isQQuickWindow(const QWindow *w = 0)
+{
+ return w && w->inherits("QQuickWindow");
+}
+
/*!
\class QWindowsFileDialogHelper
\brief Helper for native Windows file dialogs
- Non-modal dialogs are disabled for now. The functionality is
- implemented in principle, however there are failures
- when querying the results from a dialog run in another thread.
- This could probably be fixed be calling CoInitializeEx() with
- the right parameters from each thread. The problem is though
- that calls to CoInitialize() occur in several places in Qt.
+ For Qt 4 compatibility, do not create native non-modal dialogs on widgets,
+ but only on QQuickWindows, which do not have a fallback.
\internal
\ingroup qt-lighthouse-win
@@ -1190,8 +1457,9 @@ class QWindowsFileDialogHelper : public QWindowsDialogHelperBase<QPlatformFileDi
{
public:
QWindowsFileDialogHelper() {}
- virtual bool supportsNonModalDialog() const { return false; }
-
+ // For Qt 4 compatibility, do not create native non-modal dialogs on widgets,
+ // but only on QQuickWindows, which do not have a fallback.
+ virtual bool supportsNonModalDialog(const QWindow *parent = 0) const { return isQQuickWindow(parent); }
virtual bool defaultNameFilterDisables() const
{ return true; }
virtual void setDirectory(const QString &directory);
@@ -1207,11 +1475,14 @@ private:
virtual QWindowsNativeDialogBase *createNativeDialog();
inline QWindowsNativeFileDialogBase *nativeFileDialog() const
{ return static_cast<QWindowsNativeFileDialogBase *>(nativeDialog()); }
+
+ // Cache for the case no native dialog is created.
+ QWindowsFileDialogSharedData m_data;
};
QWindowsNativeDialogBase *QWindowsFileDialogHelper::createNativeDialog()
{
- QWindowsNativeFileDialogBase *result = QWindowsNativeFileDialogBase::create(options()->acceptMode());
+ QWindowsNativeFileDialogBase *result = QWindowsNativeFileDialogBase::create(options()->acceptMode(), m_data);
if (!result)
return 0;
QObject::connect(result, SIGNAL(accepted()), this, SIGNAL(accept()));
@@ -1225,8 +1496,10 @@ QWindowsNativeDialogBase *QWindowsFileDialogHelper::createNativeDialog()
// Apply settings.
const QSharedPointer<QFileDialogOptions> &opts = options();
+ m_data.fromOptions(opts);
+ const QFileDialogOptions::FileMode mode = opts->fileMode();
result->setWindowTitle(opts->windowTitle());
- result->setMode(opts->fileMode(), opts->options());
+ result->setMode(mode, opts->options());
result->setHideFiltersDetails(opts->testOption(QFileDialogOptions::HideNameFilterDetails));
const QStringList nameFilters = opts->nameFilters();
if (!nameFilters.isEmpty())
@@ -1235,18 +1508,20 @@ QWindowsNativeDialogBase *QWindowsFileDialogHelper::createNativeDialog()
result->setLabelText(QFileDialogOptions::FileName, opts->labelText(QFileDialogOptions::FileName));
if (opts->isLabelExplicitlySet(QFileDialogOptions::Accept))
result->setLabelText(QFileDialogOptions::Accept, opts->labelText(QFileDialogOptions::Accept));
- const QString initialDirectory = opts->initialDirectory();
- if (!initialDirectory.isEmpty())
- result->setDirectory(initialDirectory);
+ result->updateDirectory();
+ result->updateSelectedNameFilter();
const QStringList initialSelection = opts->initiallySelectedFiles();
if (initialSelection.size() > 0) {
QFileInfo info(initialSelection.front());
if (!info.isDir())
result->selectFile(info.fileName());
}
- const QString initialNameFilter = opts->initiallySelectedNameFilter();
- if (!initialNameFilter.isEmpty())
- result->selectNameFilter(initialNameFilter);
+ // No need to select initialNameFilter if mode is Dir
+ if (mode != QFileDialogOptions::Directory && mode != QFileDialogOptions::DirectoryOnly) {
+ const QString initialNameFilter = opts->initiallySelectedNameFilter();
+ if (!initialNameFilter.isEmpty())
+ result->selectNameFilter(initialNameFilter);
+ }
const QString defaultSuffix = opts->defaultSuffix();
if (!defaultSuffix.isEmpty())
result->setDefaultSuffix(defaultSuffix);
@@ -1258,15 +1533,14 @@ void QWindowsFileDialogHelper::setDirectory(const QString &directory)
if (QWindowsContext::verboseDialogs)
qDebug("%s %s" , __FUNCTION__, qPrintable(directory));
- if (QWindowsNativeFileDialogBase *nfd = nativeFileDialog())
- nfd->setDirectory(directory);
+ m_data.setDirectory(directory);
+ if (hasNativeDialog())
+ nativeFileDialog()->updateDirectory();
}
QString QWindowsFileDialogHelper::directory() const
{
- if (const QWindowsNativeFileDialogBase *nfd = nativeFileDialog())
- return nfd->directory();
- return QString();
+ return m_data.directory();
}
void QWindowsFileDialogHelper::selectFile(const QString &fileName)
@@ -1280,13 +1554,7 @@ void QWindowsFileDialogHelper::selectFile(const QString &fileName)
QStringList QWindowsFileDialogHelper::selectedFiles() const
{
- QStringList files;
- if (const QWindowsNativeFileDialogBase *nfd = nativeFileDialog())
- nfd->fileResult(&files);
- if (QWindowsContext::verboseDialogs)
- qDebug("%s files='%s'" , __FUNCTION__,
- qPrintable(files.join(QStringLiteral(", "))));
- return files;
+ return m_data.selectedFiles();
}
void QWindowsFileDialogHelper::setFilter()
@@ -1305,15 +1573,14 @@ void QWindowsFileDialogHelper::setNameFilters(const QStringList &filters)
void QWindowsFileDialogHelper::selectNameFilter(const QString &filter)
{
- if (QWindowsNativeFileDialogBase *nfd = nativeFileDialog())
- nfd->selectNameFilter(filter);
+ m_data.setSelectedNameFilter(filter);
+ if (hasNativeDialog())
+ nativeFileDialog()->updateSelectedNameFilter();
}
QString QWindowsFileDialogHelper::selectedNameFilter() const
{
- if (const QWindowsNativeFileDialogBase *nfd = nativeFileDialog())
- return nfd->selectedNameFilter();
- return QString();
+ return m_data.selectedNameFilter();
}
#ifndef Q_OS_WINCE
@@ -1337,20 +1604,12 @@ class QWindowsXpNativeFileDialog : public QWindowsNativeDialogBase
public:
typedef QSharedPointer<QFileDialogOptions> OptionsPtr;
- static QWindowsXpNativeFileDialog *create(const OptionsPtr &options);
+ static QWindowsXpNativeFileDialog *create(const OptionsPtr &options, const QWindowsFileDialogSharedData &data);
virtual void setWindowTitle(const QString &t) { m_title = t; }
virtual void exec(HWND owner = 0);
virtual QPlatformDialogHelper::DialogCode result() const { return m_result; }
- void setDirectory(const QString &d) { m_directory = d; }
- QString directory() const { return m_directory; }
- void selectFile(const QString &f) { m_initialFile = f; }
- QStringList selectedFiles() const { return m_selectedFiles; }
- void setNameFilters(const QStringList &n) { m_nameFilters = n; }
- void selectNameFilter(const QString &f);
- QString selectedNameFilter() const { return m_selectedNameFilter; }
-
int existingDirCallback(HWND hwnd, UINT uMsg, LPARAM lParam);
public slots:
@@ -1360,19 +1619,15 @@ private:
typedef BOOL (APIENTRY *PtrGetOpenFileNameW)(LPOPENFILENAMEW);
typedef BOOL (APIENTRY *PtrGetSaveFileNameW)(LPOPENFILENAMEW);
- explicit QWindowsXpNativeFileDialog(const OptionsPtr &options);
+ explicit QWindowsXpNativeFileDialog(const OptionsPtr &options, const QWindowsFileDialogSharedData &data);
void populateOpenFileName(OPENFILENAME *ofn, HWND owner) const;
QStringList execExistingDir(HWND owner);
QStringList execFileNames(HWND owner, int *selectedFilterIndex) const;
const OptionsPtr m_options;
QString m_title;
- QString m_directory;
- QString m_initialFile;
- QStringList m_selectedFiles;
- QString m_selectedNameFilter;
- QStringList m_nameFilters;
QPlatformDialogHelper::DialogCode m_result;
+ QWindowsFileDialogSharedData m_data;
static PtrGetOpenFileNameW m_getOpenFileNameW;
static PtrGetSaveFileNameW m_getSaveFileNameW;
@@ -1381,7 +1636,7 @@ private:
QWindowsXpNativeFileDialog::PtrGetOpenFileNameW QWindowsXpNativeFileDialog::m_getOpenFileNameW = 0;
QWindowsXpNativeFileDialog::PtrGetSaveFileNameW QWindowsXpNativeFileDialog::m_getSaveFileNameW = 0;
-QWindowsXpNativeFileDialog *QWindowsXpNativeFileDialog::create(const OptionsPtr &options)
+QWindowsXpNativeFileDialog *QWindowsXpNativeFileDialog::create(const OptionsPtr &options, const QWindowsFileDialogSharedData &data)
{
// GetOpenFileNameW() GetSaveFileName() are resolved
// dynamically as not to create a dependency on Comdlg32, which
@@ -1392,51 +1647,33 @@ QWindowsXpNativeFileDialog *QWindowsXpNativeFileDialog::create(const OptionsPtr
m_getSaveFileNameW = (PtrGetSaveFileNameW)(library.resolve("GetSaveFileNameW"));
}
if (m_getOpenFileNameW && m_getSaveFileNameW)
- return new QWindowsXpNativeFileDialog(options);
+ return new QWindowsXpNativeFileDialog(options, data);
return 0;
}
-QWindowsXpNativeFileDialog::QWindowsXpNativeFileDialog(const OptionsPtr &options) :
- m_options(options), m_result(QPlatformDialogHelper::Rejected)
+QWindowsXpNativeFileDialog::QWindowsXpNativeFileDialog(const OptionsPtr &options,
+ const QWindowsFileDialogSharedData &data) :
+ m_options(options), m_result(QPlatformDialogHelper::Rejected), m_data(data)
{
- const QStringList nameFilters = m_options->nameFilters();
- if (!nameFilters.isEmpty())
- setNameFilters(nameFilters);
- const QString initialDirectory = m_options->initialDirectory();
- if (!initialDirectory.isEmpty())
- setDirectory(initialDirectory);
- const QString initialNameFilter = m_options->initiallySelectedNameFilter();
- if (!initialNameFilter.isEmpty())
- selectNameFilter(initialNameFilter);
- const QStringList selectedFiles = m_options->initiallySelectedFiles();
- if (!selectedFiles.isEmpty())
- selectFile(selectedFiles.front());
setWindowTitle(m_options->windowTitle());
}
-void QWindowsXpNativeFileDialog::selectNameFilter(const QString &f)
-{
- const int index = indexOfNameFilter(m_nameFilters, f);
- if (index >= 0)
- m_selectedNameFilter = m_nameFilters.at(index);
-}
-
void QWindowsXpNativeFileDialog::exec(HWND owner)
{
int selectedFilterIndex = -1;
- m_selectedFiles = m_options->fileMode() == QFileDialogOptions::DirectoryOnly ?
+ const QStringList selectedFiles =
+ m_options->fileMode() == QFileDialogOptions::DirectoryOnly ?
execExistingDir(owner) : execFileNames(owner, &selectedFilterIndex);
+ m_data.setSelectedFiles(selectedFiles);
QWindowsDialogs::eatMouseMove();
- if (m_selectedFiles.isEmpty()) {
+ if (selectedFiles.isEmpty()) {
m_result = QPlatformDialogHelper::Rejected;
emit rejected();
} else {
- if (selectedFilterIndex >= 0 && selectedFilterIndex < m_nameFilters.size()) {
- m_selectedNameFilter = m_nameFilters.at(selectedFilterIndex);
- } else {
- m_selectedNameFilter.clear();
- }
- m_directory = QFileInfo(m_selectedFiles.front()).absolutePath();
+ const QStringList nameFilters = m_options->nameFilters();
+ if (selectedFilterIndex >= 0 && selectedFilterIndex < nameFilters.size())
+ m_data.setSelectedNameFilter(nameFilters.at(selectedFilterIndex));
+ m_data.setDirectory(QFileInfo(selectedFiles.front()).absolutePath());
m_result = QPlatformDialogHelper::Accepted;
emit accepted();
}
@@ -1460,9 +1697,11 @@ typedef PIDLIST_ABSOLUTE qt_LpItemIdList;
int QWindowsXpNativeFileDialog::existingDirCallback(HWND hwnd, UINT uMsg, LPARAM lParam)
{
switch (uMsg) {
- case BFFM_INITIALIZED:
- if (!m_initialFile.isEmpty())
- SendMessage(hwnd, BFFM_SETSELECTION, TRUE, LPARAM(m_initialFile.utf16()));
+ case BFFM_INITIALIZED: {
+ const QString initialFile = m_data.selectedFile();
+ if (!initialFile.isEmpty())
+ SendMessage(hwnd, BFFM_SETSELECTION, TRUE, LPARAM(initialFile.utf16()));
+ }
break;
case BFFM_SELCHANGED: {
wchar_t path[MAX_PATH];
@@ -1534,7 +1773,7 @@ void QWindowsXpNativeFileDialog::populateOpenFileName(OPENFILENAME *ofn, HWND ow
*ptr++ = 0;
}
*ptr = 0;
- const int nameFilterIndex = indexOfNameFilter(m_nameFilters, m_selectedNameFilter);
+ const int nameFilterIndex = indexOfNameFilter(m_options->nameFilters(), m_data.selectedNameFilter());
if (nameFilterIndex >= 0)
ofn->nFilterIndex = nameFilterIndex + 1; // 1..n based.
// lpstrFile receives the initial selection and is the buffer
@@ -1542,10 +1781,10 @@ void QWindowsXpNativeFileDialog::populateOpenFileName(OPENFILENAME *ofn, HWND ow
// will not show.
ofn->nMaxFile = 65535;
const QString initiallySelectedFile =
- QDir::toNativeSeparators(m_initialFile).remove(QLatin1Char('<')).
+ QDir::toNativeSeparators(m_data.selectedFile()).remove(QLatin1Char('<')).
remove(QLatin1Char('>')).remove(QLatin1Char('"')).remove(QLatin1Char('|'));
ofn->lpstrFile = qStringToWCharArray(initiallySelectedFile, ofn->nMaxFile);
- ofn->lpstrInitialDir = qStringToWCharArray(QDir::toNativeSeparators(m_directory));
+ ofn->lpstrInitialDir = qStringToWCharArray(QDir::toNativeSeparators(m_data.directory()));
ofn->lpstrTitle = (wchar_t*)m_title.utf16();
// Determine lpstrDefExt. Note that the current MSDN docs document this
// member wrong. It should rather be documented as "the default extension
@@ -1614,8 +1853,7 @@ class QWindowsXpFileDialogHelper : public QWindowsDialogHelperBase<QPlatformFile
{
public:
QWindowsXpFileDialogHelper() {}
- virtual bool supportsNonModalDialog() const { return false; }
-
+ virtual bool supportsNonModalDialog(const QWindow *parent = 0) const { return isQQuickWindow(parent); }
virtual bool defaultNameFilterDisables() const
{ return true; }
virtual void setDirectory(const QString &directory);
@@ -1631,11 +1869,14 @@ private:
virtual QWindowsNativeDialogBase *createNativeDialog();
inline QWindowsXpNativeFileDialog *nativeFileDialog() const
{ return static_cast<QWindowsXpNativeFileDialog *>(nativeDialog()); }
+
+ QWindowsFileDialogSharedData m_data;
};
QWindowsNativeDialogBase *QWindowsXpFileDialogHelper::createNativeDialog()
{
- if (QWindowsNativeDialogBase *result = QWindowsXpNativeFileDialog::create(options())) {
+ m_data.fromOptions(options());
+ if (QWindowsXpNativeFileDialog *result = QWindowsXpNativeFileDialog::create(options(), m_data)) {
QObject::connect(result, SIGNAL(accepted()), this, SIGNAL(accept()));
QObject::connect(result, SIGNAL(rejected()), this, SIGNAL(reject()));
return result;
@@ -1645,47 +1886,37 @@ QWindowsNativeDialogBase *QWindowsXpFileDialogHelper::createNativeDialog()
void QWindowsXpFileDialogHelper::setDirectory(const QString &directory)
{
- if (QWindowsXpNativeFileDialog *nfd = nativeFileDialog())
- nfd->setDirectory(directory);
+ m_data.setDirectory(directory); // Dialog cannot be updated at run-time.
}
QString QWindowsXpFileDialogHelper::directory() const
{
- if (const QWindowsXpNativeFileDialog *nfd = nativeFileDialog())
- return nfd->directory();
- return QString();
+ return m_data.directory();
}
void QWindowsXpFileDialogHelper::selectFile(const QString &filename)
{
- if (QWindowsXpNativeFileDialog *nfd = nativeFileDialog())
- nfd->selectFile(filename);
+ m_data.setSelectedFiles(QStringList(filename)); // Dialog cannot be updated at run-time.
}
QStringList QWindowsXpFileDialogHelper::selectedFiles() const
{
- if (const QWindowsXpNativeFileDialog *nfd = nativeFileDialog())
- return nfd->selectedFiles();
- return QStringList();
+ return m_data.selectedFiles();
}
-void QWindowsXpFileDialogHelper::setNameFilters(const QStringList &n)
+void QWindowsXpFileDialogHelper::setNameFilters(const QStringList &)
{
- if (QWindowsXpNativeFileDialog *nfd = nativeFileDialog())
- nfd->setNameFilters(n);
+ // Dialog cannot be updated at run-time.
}
void QWindowsXpFileDialogHelper::selectNameFilter(const QString &f)
{
- if (QWindowsXpNativeFileDialog *nfd = nativeFileDialog())
- nfd->selectNameFilter(f);
+ m_data.setSelectedNameFilter(f); // Dialog cannot be updated at run-time.
}
QString QWindowsXpFileDialogHelper::selectedNameFilter() const
{
- if (const QWindowsXpNativeFileDialog *nfd = nativeFileDialog())
- return nfd->selectedNameFilter();
- return QString();
+ return m_data.selectedNameFilter();
}
#endif // Q_OS_WINCE
diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.h b/src/plugins/platforms/windows/qwindowsdialoghelpers.h
index 07f105cb35..7884f398f3 100644
--- a/src/plugins/platforms/windows/qwindowsdialoghelpers.h
+++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.h
@@ -65,6 +65,7 @@ template <class BaseClass>
class QWindowsDialogHelperBase : public BaseClass
{
public:
+ ~QWindowsDialogHelperBase() { deleteNativeDialog(); }
virtual void exec();
virtual bool show(Qt::WindowFlags windowFlags,
@@ -73,19 +74,24 @@ public:
virtual void hide();
virtual QVariant styleHint(QPlatformDialogHelper::StyleHint) const;
- virtual bool supportsNonModalDialog() const { return true; }
+ virtual bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const { return true; }
protected:
QWindowsDialogHelperBase();
- ~QWindowsDialogHelperBase();
QWindowsNativeDialogBase *nativeDialog() const;
+ inline bool hasNativeDialog() const { return m_nativeDialog; }
+ void deleteNativeDialog();
+ void timerEvent(QTimerEvent *);
private:
virtual QWindowsNativeDialogBase *createNativeDialog() = 0;
inline QWindowsNativeDialogBase *ensureNativeDialog();
+ inline void startDialogThread();
+ inline void stopTimer();
QWindowsNativeDialogBase *m_nativeDialog;
HWND m_ownerWindow;
+ int m_timerId;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp
index 1286f5c106..fedda750d9 100644
--- a/src/plugins/platforms/windows/qwindowsdrag.cpp
+++ b/src/plugins/platforms/windows/qwindowsdrag.cpp
@@ -304,10 +304,10 @@ private:
class DragCursorHandle {
Q_DISABLE_COPY(DragCursorHandle)
public:
- DragCursorHandle(HCURSOR c, quint64 k) : cursor(c), cacheKey(k) {}
+ DragCursorHandle(HCURSOR c, qint64 k) : cursor(c), cacheKey(k) {}
~DragCursorHandle() { DestroyCursor(cursor); }
HCURSOR cursor;
- quint64 cacheKey;
+ qint64 cacheKey;
};
typedef QMap <Qt::DropAction, QSharedPointer<DragCursorHandle> > ActionCursorMap;
@@ -490,7 +490,7 @@ QWindowsOleDropSource::GiveFeedback(DWORD dwEffect)
qDebug("%s dwEffect=%lu, action=%d", __FUNCTION__, dwEffect, action);
QSharedPointer<DragCursorHandle> cursorHandler = m_cursors.value(action);
- quint64 currentCacheKey = m_drag->currentDrag()->dragCursor(action).cacheKey();
+ qint64 currentCacheKey = m_drag->currentDrag()->dragCursor(action).cacheKey();
if (cursorHandler.isNull() || currentCacheKey != cursorHandler->cacheKey)
createCursors();
diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp
index b4fb19e8e8..5fa954cb12 100644
--- a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp
+++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp
@@ -606,130 +606,6 @@ QDebug operator<<(QDebug d, const QFontDef &def)
return d;
}
-/* From QFontDatabase.cpp, qt_determine_writing_systems_from_truetype_bits().
- * Fixme: Make public? */
-
-// see the Unicode subset bitfields in the MSDN docs
-static int requiredUnicodeBits[QFontDatabase::WritingSystemsCount][2] = {
- // Any,
- { 127, 127 },
- // Latin,
- { 0, 127 },
- // Greek,
- { 7, 127 },
- // Cyrillic,
- { 9, 127 },
- // Armenian,
- { 10, 127 },
- // Hebrew,
- { 11, 127 },
- // Arabic,
- { 13, 127 },
- // Syriac,
- { 71, 127 },
- //Thaana,
- { 72, 127 },
- //Devanagari,
- { 15, 127 },
- //Bengali,
- { 16, 127 },
- //Gurmukhi,
- { 17, 127 },
- //Gujarati,
- { 18, 127 },
- //Oriya,
- { 19, 127 },
- //Tamil,
- { 20, 127 },
- //Telugu,
- { 21, 127 },
- //Kannada,
- { 22, 127 },
- //Malayalam,
- { 23, 127 },
- //Sinhala,
- { 73, 127 },
- //Thai,
- { 24, 127 },
- //Lao,
- { 25, 127 },
- //Tibetan,
- { 70, 127 },
- //Myanmar,
- { 74, 127 },
- // Georgian,
- { 26, 127 },
- // Khmer,
- { 80, 127 },
- // SimplifiedChinese,
- { 126, 127 },
- // TraditionalChinese,
- { 126, 127 },
- // Japanese,
- { 126, 127 },
- // Korean,
- { 56, 127 },
- // Vietnamese,
- { 0, 127 }, // same as latin1
- // Other,
- { 126, 127 },
- // Ogham,
- { 78, 127 },
- // Runic,
- { 79, 127 },
- // Nko,
- { 14, 127 },
-};
-
-enum
-{
- SimplifiedChineseCsbBit = 18,
- TraditionalChineseCsbBit = 20,
- JapaneseCsbBit = 17,
- KoreanCsbBit = 21
-};
-
-static inline void writingSystemsFromTrueTypeBits(quint32 unicodeRange[4],
- quint32 codePageRange[2],
- QSupportedWritingSystems *ws)
-{
- bool hasScript = false;
- for(int i = 0; i < QFontDatabase::WritingSystemsCount; i++) {
- int bit = requiredUnicodeBits[i][0];
- int index = bit/32;
- int flag = 1 << (bit&31);
- if (bit != 126 && unicodeRange[index] & flag) {
- bit = requiredUnicodeBits[i][1];
- index = bit/32;
-
- flag = 1 << (bit&31);
- if (bit == 127 || unicodeRange[index] & flag) {
- ws->setSupported(QFontDatabase::WritingSystem(i), true);
- hasScript = true;
- }
- }
- }
- if(codePageRange[0] & (1 << SimplifiedChineseCsbBit)) {
- ws->setSupported(QFontDatabase::SimplifiedChinese, true);
- hasScript = true;
- }
- if(codePageRange[0] & (1 << TraditionalChineseCsbBit)) {
- ws->setSupported(QFontDatabase::TraditionalChinese, true);
- hasScript = true;
- }
- if(codePageRange[0] & (1 << JapaneseCsbBit)) {
- ws->setSupported(QFontDatabase::Japanese, true);
- hasScript = true;
- //qDebug("font %s supports Japanese", familyName.latin1());
- }
- if(codePageRange[0] & (1 << KoreanCsbBit)) {
- ws->setSupported(QFontDatabase::Korean, true);
- hasScript = true;
- }
- if (!hasScript)
- ws->setSupported(QFontDatabase::Symbol, true);
-}
-
// convert 0 ~ 1000 integer to QFont::Weight
static inline QFont::Weight weightFromInteger(long weight)
{
@@ -744,36 +620,43 @@ static inline QFont::Weight weightFromInteger(long weight)
return QFont::Black;
}
-static inline QFontDatabase::WritingSystem writingSystemFromScript(const QString &scriptName)
+static inline QFontDatabase::WritingSystem writingSystemFromCharSet(uchar charSet)
{
- if (scriptName == QStringLiteral("Western")
- || scriptName == QStringLiteral("Baltic")
- || scriptName == QStringLiteral("Central European")
- || scriptName == QStringLiteral("Turkish")
- || scriptName == QStringLiteral("Vietnamese")
- || scriptName == QStringLiteral("OEM/Dos"))
+ switch (charSet) {
+ case ANSI_CHARSET:
+ case EASTEUROPE_CHARSET:
+ case BALTIC_CHARSET:
+ case TURKISH_CHARSET:
+ case OEM_CHARSET:
return QFontDatabase::Latin;
- if (scriptName == QStringLiteral("Thai"))
+ case GREEK_CHARSET:
+ return QFontDatabase::Greek;
+ case RUSSIAN_CHARSET:
+ return QFontDatabase::Cyrillic;
+ case HEBREW_CHARSET:
+ return QFontDatabase::Hebrew;
+ case ARABIC_CHARSET:
+ return QFontDatabase::Arabic;
+ case THAI_CHARSET:
return QFontDatabase::Thai;
- if (scriptName == QStringLiteral("Symbol")
- || scriptName == QStringLiteral("Other"))
- return QFontDatabase::Symbol;
- if (scriptName == QStringLiteral("CHINESE_GB2312"))
+ case GB2312_CHARSET:
return QFontDatabase::SimplifiedChinese;
- if (scriptName == QStringLiteral("CHINESE_BIG5"))
+ case CHINESEBIG5_CHARSET:
return QFontDatabase::TraditionalChinese;
- if (scriptName == QStringLiteral("Cyrillic"))
- return QFontDatabase::Cyrillic;
- if (scriptName == QStringLiteral("Hangul"))
- return QFontDatabase::Korean;
- if (scriptName == QStringLiteral("Hebrew"))
- return QFontDatabase::Hebrew;
- if (scriptName == QStringLiteral("Greek"))
- return QFontDatabase::Greek;
- if (scriptName == QStringLiteral("Japanese"))
+ case SHIFTJIS_CHARSET:
return QFontDatabase::Japanese;
- if (scriptName == QStringLiteral("Arabic"))
- return QFontDatabase::Arabic;
+ case HANGUL_CHARSET:
+ case JOHAB_CHARSET:
+ return QFontDatabase::Korean;
+ case VIETNAMESE_CHARSET:
+ return QFontDatabase::Vietnamese;
+ case SYMBOL_CHARSET:
+ return QFontDatabase::Symbol;
+ // ### case MAC_CHARSET:
+ // ### case DEFAULT_CHARSET:
+ default:
+ break;
+ }
return QFontDatabase::Any;
}
@@ -957,7 +840,7 @@ error:
Q_GUI_EXPORT void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias);
-static bool addFontToDatabase(QString familyName, const QString &scriptName,
+static bool addFontToDatabase(const QString &familyName, uchar charSet,
const TEXTMETRIC *textmetric,
const FONTSIGNATURE *signature,
int type)
@@ -981,7 +864,7 @@ static bool addFontToDatabase(QString familyName, const QString &scriptName,
#ifndef QT_NO_DEBUG_OUTPUT
if (QWindowsContext::verboseFonts > 2) {
QDebug nospace = qDebug().nospace();
- nospace << __FUNCTION__ << familyName << scriptName
+ nospace << __FUNCTION__ << familyName << charSet
<< "TTF=" << ttf;
if (type & DEVICE_FONTTYPE)
nospace << " DEVICE";
@@ -1001,6 +884,7 @@ static bool addFontToDatabase(QString familyName, const QString &scriptName,
QSupportedWritingSystems writingSystems;
if (type & TRUETYPE_FONTTYPE) {
+ Q_ASSERT(signature);
quint32 unicodeRange[4] = {
signature->fsUsb[0], signature->fsUsb[1],
signature->fsUsb[2], signature->fsUsb[3]
@@ -1019,7 +903,7 @@ static bool addFontToDatabase(QString familyName, const QString &scriptName,
unicodeRange[3] = 0xffffffff;
}
#endif
- writingSystemsFromTrueTypeBits(unicodeRange, codePageRange, &writingSystems);
+ writingSystems = QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
// ### Hack to work around problem with Thai text on Windows 7. Segoe UI contains
// the symbol for Baht, and Windows thus reports that it supports the Thai script.
// Since it's the default UI font on this platform, most widgets will be unable to
@@ -1029,7 +913,7 @@ static bool addFontToDatabase(QString familyName, const QString &scriptName,
familyName == QStringLiteral("Segoe UI"))
writingSystems.setSupported(QFontDatabase::Thai, false);
} else {
- const QFontDatabase::WritingSystem ws = writingSystemFromScript(scriptName);
+ const QFontDatabase::WritingSystem ws = writingSystemFromCharSet(charSet);
if (ws != QFontDatabase::Any)
writingSystems.setSupported(ws);
}
@@ -1058,14 +942,14 @@ static int CALLBACK storeFont(ENUMLOGFONTEX* f, NEWTEXTMETRICEX *textmetric,
{
typedef QSet<QString> StringSet;
const QString familyName = QString::fromWCharArray(f->elfLogFont.lfFaceName);
- const QString script = QString::fromWCharArray(f->elfScript);
+ const uchar charSet = f->elfLogFont.lfCharSet;
const FONTSIGNATURE signature = textmetric->ntmFontSig;
// NEWTEXTMETRICEX is a NEWTEXTMETRIC, which according to the documentation is
// identical to a TEXTMETRIC except for the last four members, which we don't use
// anyway
- if (addFontToDatabase(familyName, script, (TEXTMETRIC *)textmetric, &signature, type))
+ if (addFontToDatabase(familyName, charSet, (TEXTMETRIC *)textmetric, &signature, type))
reinterpret_cast<StringSet *>(namesSetIn)->insert(familyName);
// keep on enumerating
@@ -1160,9 +1044,7 @@ QWindowsFontDatabase::~QWindowsFontDatabase()
removeApplicationFonts();
}
-QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef,
- QUnicodeTables::Script script,
- void *handle)
+QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle)
{
QFontEngine *fe = QWindowsFontDatabase::createEngine(script, fontDef,
0, QWindowsContext::instance()->defaultDPI(), false,
@@ -1215,7 +1097,7 @@ QFontEngine *QWindowsFontDatabase::fontEngine(const QByteArray &fontData, qreal
request.styleStrategy = QFont::NoFontMerging | QFont::PreferMatch;
request.hintingPreference = hintingPreference;
- fontEngine = QWindowsFontDatabase::createEngine(QUnicodeTables::Common, request, 0,
+ fontEngine = QWindowsFontDatabase::createEngine(QChar::Script_Common, request, 0,
QWindowsContext::instance()->defaultDPI(), false, QStringList(),
sharedFontData());
@@ -1223,11 +1105,11 @@ QFontEngine *QWindowsFontDatabase::fontEngine(const QByteArray &fontData, qreal
if (request.family != fontEngine->fontDef.family) {
qWarning("%s: Failed to load font. Got fallback instead: %s",
__FUNCTION__, qPrintable(fontEngine->fontDef.family));
- if (fontEngine->cache_count == 0 && fontEngine->ref.load() == 0)
+ if (fontEngine->ref.load() == 0)
delete fontEngine;
fontEngine = 0;
} else {
- Q_ASSERT(fontEngine->cache_count == 0 && fontEngine->ref.load() == 0);
+ Q_ASSERT(fontEngine->ref.load() == 0);
// Override the generated font name
static_cast<QWindowsFontEngine *>(fontEngine)->setUniqueFamilyName(uniqueFamilyName);
@@ -1439,7 +1321,7 @@ QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData,
TEXTMETRIC textMetrics;
GetTextMetrics(hdc, &textMetrics);
- addFontToDatabase(familyName, QString(), &textMetrics, &signatures.at(j),
+ addFontToDatabase(familyName, lf.lfCharSet, &textMetrics, &signatures.at(j),
TRUETYPE_FONTTYPE);
SelectObject(hdc, oldobj);
@@ -1529,8 +1411,8 @@ HFONT QWindowsFontDatabase::systemFont()
static inline bool scriptRequiresOpenType(int script)
{
- return ((script >= QUnicodeTables::Syriac && script <= QUnicodeTables::Sinhala)
- || script == QUnicodeTables::Khmer || script == QUnicodeTables::Nko);
+ return ((script >= QChar::Script_Syriac && script <= QChar::Script_Sinhala)
+ || script == QChar::Script_Khmer || script == QChar::Script_Nko);
}
static const char *other_tryFonts[] = {
@@ -1715,7 +1597,7 @@ static QStringList extraTryFontsForFamily(const QString& family)
return result;
}
-QStringList QWindowsFontDatabase::fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const
+QStringList QWindowsFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const
{
QStringList result = QPlatformFontDatabase::fallbacksForFamily(family, style, styleHint, script);
if (!result.isEmpty())
@@ -1885,8 +1767,7 @@ QFontEngine *QWindowsFontDatabase::createEngine(int script, const QFontDef &requ
// for scripts that do not require OpenType we should just look at the list of
// supported writing systems in the font's OS/2 table.
if (scriptRequiresOpenType(script)) {
- HB_Face hbFace = few->harfbuzzFace();
- if (!hbFace || !hbFace->supported_scripts[script]) {
+ if (!few->supportsScript(QChar::Script(script))) {
qWarning(" OpenType support missing for script\n");
delete few;
return 0;
@@ -1917,7 +1798,7 @@ QFontEngine *QWindowsFontDatabase::createEngine(int script, const QFontDef &requ
directWriteFont->Release();
#endif
- if (script == QUnicodeTables::Common
+ if ((script == QChar::Script_Common || script == QChar::Script_Han)
&& !(request.styleStrategy & QFont::NoFontMerging)) {
QStringList extraFonts = extraTryFontsForFamily(request.family);
if (extraFonts.size()) {
diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.h b/src/plugins/platforms/windows/qwindowsfontdatabase.h
index c14d6027c2..b9e6c38eaa 100644
--- a/src/plugins/platforms/windows/qwindowsfontdatabase.h
+++ b/src/plugins/platforms/windows/qwindowsfontdatabase.h
@@ -78,9 +78,9 @@ public:
~QWindowsFontDatabase();
virtual void populateFontDatabase();
- virtual QFontEngine *fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *handle);
+ virtual QFontEngine *fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle);
virtual QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference);
- virtual QStringList fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const;
+ virtual QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const;
virtual QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName);
virtual void releaseHandle(void *handle);
virtual QString fontDir() const;
diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp
index 406dc636b8..98b4e7af62 100644
--- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp
+++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp
@@ -57,39 +57,6 @@
QT_BEGIN_NAMESPACE
-static inline QFontDatabase::WritingSystem writingSystemFromScript(const QString &scriptName)
-{
- if (scriptName == QStringLiteral("Western")
- || scriptName == QStringLiteral("Baltic")
- || scriptName == QStringLiteral("Central European")
- || scriptName == QStringLiteral("Turkish")
- || scriptName == QStringLiteral("Vietnamese")
- || scriptName == QStringLiteral("OEM/Dos"))
- return QFontDatabase::Latin;
- if (scriptName == QStringLiteral("Thai"))
- return QFontDatabase::Thai;
- if (scriptName == QStringLiteral("Symbol")
- || scriptName == QStringLiteral("Other"))
- return QFontDatabase::Symbol;
- if (scriptName == QStringLiteral("CHINESE_GB2312"))
- return QFontDatabase::SimplifiedChinese;
- if (scriptName == QStringLiteral("CHINESE_BIG5"))
- return QFontDatabase::TraditionalChinese;
- if (scriptName == QStringLiteral("Cyrillic"))
- return QFontDatabase::Cyrillic;
- if (scriptName == QStringLiteral("Hangul"))
- return QFontDatabase::Korean;
- if (scriptName == QStringLiteral("Hebrew"))
- return QFontDatabase::Hebrew;
- if (scriptName == QStringLiteral("Greek"))
- return QFontDatabase::Greek;
- if (scriptName == QStringLiteral("Japanese"))
- return QFontDatabase::Japanese;
- if (scriptName == QStringLiteral("Arabic"))
- return QFontDatabase::Arabic;
- return QFontDatabase::Any;
-}
-
// convert 0 ~ 1000 integer to QFont::Weight
static inline QFont::Weight weightFromInteger(long weight)
{
@@ -104,6 +71,46 @@ static inline QFont::Weight weightFromInteger(long weight)
return QFont::Black;
}
+static inline QFontDatabase::WritingSystem writingSystemFromCharSet(uchar charSet)
+{
+ switch (charSet) {
+ case ANSI_CHARSET:
+ case EASTEUROPE_CHARSET:
+ case BALTIC_CHARSET:
+ case TURKISH_CHARSET:
+ case OEM_CHARSET:
+ return QFontDatabase::Latin;
+ case GREEK_CHARSET:
+ return QFontDatabase::Greek;
+ case RUSSIAN_CHARSET:
+ return QFontDatabase::Cyrillic;
+ case HEBREW_CHARSET:
+ return QFontDatabase::Hebrew;
+ case ARABIC_CHARSET:
+ return QFontDatabase::Arabic;
+ case THAI_CHARSET:
+ return QFontDatabase::Thai;
+ case GB2312_CHARSET:
+ return QFontDatabase::SimplifiedChinese;
+ case CHINESEBIG5_CHARSET:
+ return QFontDatabase::TraditionalChinese;
+ case SHIFTJIS_CHARSET:
+ return QFontDatabase::Japanese;
+ case HANGUL_CHARSET:
+ case JOHAB_CHARSET:
+ return QFontDatabase::Korean;
+ case VIETNAMESE_CHARSET:
+ return QFontDatabase::Vietnamese;
+ case SYMBOL_CHARSET:
+ return QFontDatabase::Symbol;
+ // ### case MAC_CHARSET:
+ // ### case DEFAULT_CHARSET:
+ default:
+ break;
+ }
+ return QFontDatabase::Any;
+}
+
static FontFile * createFontFile(const QString &fileName, int index)
{
FontFile *fontFile = new FontFile;
@@ -117,7 +124,7 @@ extern QString getEnglishName(const QString &familyName);
Q_GUI_EXPORT void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias);
-static bool addFontToDatabase(QString familyName, const QString &scriptName,
+static bool addFontToDatabase(const QString &familyName, uchar charSet,
const TEXTMETRIC *textmetric,
const FONTSIGNATURE *signature,
int type)
@@ -148,7 +155,7 @@ static bool addFontToDatabase(QString familyName, const QString &scriptName,
#ifndef QT_NO_DEBUG_OUTPUT
if (QWindowsContext::verboseFonts > 2) {
QDebug nospace = qDebug().nospace();
- nospace << __FUNCTION__ << faceName << fullName << scriptName
+ nospace << __FUNCTION__ << familyName << faceName << fullName << charSet
<< "TTF=" << ttf;
if (type & DEVICE_FONTTYPE)
nospace << " DEVICE";
@@ -168,6 +175,7 @@ static bool addFontToDatabase(QString familyName, const QString &scriptName,
QSupportedWritingSystems writingSystems;
if (type & TRUETYPE_FONTTYPE) {
+ Q_ASSERT(signature);
quint32 unicodeRange[4] = {
signature->fsUsb[0], signature->fsUsb[1],
signature->fsUsb[2], signature->fsUsb[3]
@@ -175,7 +183,7 @@ static bool addFontToDatabase(QString familyName, const QString &scriptName,
quint32 codePageRange[2] = {
signature->fsCsb[0], signature->fsCsb[1]
};
- writingSystems = QBasicFontDatabase::determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
+ writingSystems = QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
// ### Hack to work around problem with Thai text on Windows 7. Segoe UI contains
// the symbol for Baht, and Windows thus reports that it supports the Thai script.
// Since it's the default UI font on this platform, most widgets will be unable to
@@ -185,7 +193,7 @@ static bool addFontToDatabase(QString familyName, const QString &scriptName,
faceName == QStringLiteral("Segoe UI"))
writingSystems.setSupported(QFontDatabase::Thai, false);
} else {
- const QFontDatabase::WritingSystem ws = writingSystemFromScript(scriptName);
+ const QFontDatabase::WritingSystem ws = writingSystemFromCharSet(charSet);
if (ws != QFontDatabase::Any)
writingSystems.setSupported(ws);
}
@@ -308,14 +316,14 @@ static int CALLBACK storeFont(ENUMLOGFONTEX* f, NEWTEXTMETRICEX *textmetric,
const QString familyName = QString::fromWCharArray(f->elfLogFont.lfFaceName)
+ QStringLiteral("::")
+ QString::fromWCharArray(f->elfFullName);
- const QString script = QString::fromWCharArray(f->elfScript);
+ const uchar charSet = f->elfLogFont.lfCharSet;
const FONTSIGNATURE signature = textmetric->ntmFontSig;
// NEWTEXTMETRICEX is a NEWTEXTMETRIC, which according to the documentation is
// identical to a TEXTMETRIC except for the last four members, which we don't use
// anyway
- if (addFontToDatabase(familyName, script, (TEXTMETRIC *)textmetric, &signature, type))
+ if (addFontToDatabase(familyName, charSet, (TEXTMETRIC *)textmetric, &signature, type))
reinterpret_cast<StringSet *>(namesSetIn)->insert(familyName);
// keep on enumerating
@@ -362,7 +370,7 @@ void QWindowsFontDatabaseFT::populate(const QString &family)
ReleaseDC(0, dummy);
}
-QFontEngine * QWindowsFontDatabaseFT::fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *handle)
+QFontEngine * QWindowsFontDatabaseFT::fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle)
{
QFontEngine *fe = QBasicFontDatabase::fontEngine(fontDef, script, handle);
if (QWindowsContext::verboseFonts)
@@ -430,9 +438,9 @@ static const char *kr_tryFonts[] = {
static const char **tryFonts = 0;
-QStringList QWindowsFontDatabaseFT::fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const
+QStringList QWindowsFontDatabaseFT::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const
{
- if(script == QUnicodeTables::Common) {
+ if (script == QChar::Script_Common || script == QChar::Script_Han) {
// && !(request.styleStrategy & QFont::NoFontMerging)) {
QFontDatabase db;
if (!db.writingSystems(family).contains(QFontDatabase::Symbol)) {
@@ -518,8 +526,8 @@ HFONT QWindowsFontDatabaseFT::systemFont()
static inline bool scriptRequiresOpenType(int script)
{
- return ((script >= QUnicodeTables::Syriac && script <= QUnicodeTables::Sinhala)
- || script == QUnicodeTables::Khmer || script == QUnicodeTables::Nko);
+ return ((script >= QChar::Script_Syriac && script <= QChar::Script_Sinhala)
+ || script == QChar::Script_Khmer || script == QChar::Script_Nko);
}
static inline int verticalDPI()
diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h
index 2ce429d012..d3cbc0210a 100644
--- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h
+++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h
@@ -52,10 +52,10 @@ class QWindowsFontDatabaseFT : public QBasicFontDatabase
{
public:
void populateFontDatabase();
- QFontEngine *fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *handle);
+ QFontEngine *fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle);
QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference);
- QStringList fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const;
+ QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const;
virtual QString fontDir() const;
virtual QFont defaultFont() const;
diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp
index 7fcd9814bd..c402f00453 100644
--- a/src/plugins/platforms/windows/qwindowsfontengine.cpp
+++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp
@@ -66,7 +66,6 @@
#include <QtCore/QThreadStorage>
#include <QtCore/private/qsystemlibrary_p.h>
-#include <QtCore/private/qunicodetables_p.h>
#include <QtCore/QDebug>
#include <limits.h>
@@ -155,9 +154,20 @@ static OUTLINETEXTMETRIC *getOutlineTextMetric(HDC hdc)
return otm;
}
+bool QWindowsFontEngine::hasCFFTable() const
+{
+ HDC hdc = m_fontEngineData->hdc;
+ SelectObject(hdc, hfont);
+ return GetFontData(hdc, MAKE_TAG('C', 'F', 'F', ' '), 0, 0, 0) != GDI_ERROR;
+}
+
void QWindowsFontEngine::getCMap()
{
ttf = (bool)(tm.tmPitchAndFamily & TMPF_TRUETYPE);
+
+ // TMPF_TRUETYPE is not set for fonts with CFF tables
+ cffTable = !ttf && hasCFFTable();
+
HDC hdc = m_fontEngineData->hdc;
SelectObject(hdc, hfont);
bool symb = false;
@@ -1041,7 +1051,7 @@ void QWindowsFontEngine::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, gly
bool QWindowsFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const
{
- if (!ttf)
+ if (!ttf && !cffTable)
return false;
HDC hdc = m_fontEngineData->hdc;
SelectObject(hdc, hfont);
@@ -1216,13 +1226,13 @@ QImage QWindowsFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed, const QTra
{
HFONT font = hfont;
- int contrast;
+ UINT contrast;
SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &contrast, 0);
SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, (void *) 1000, 0);
int margin = glyphMargin(QFontEngineGlyphCache::Raster_RGBMask);
QWindowsNativeImage *mask = drawGDIGlyph(font, glyph, margin, t, QImage::Format_RGB32);
- SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, (void *) contrast, 0);
+ SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, (void *) quintptr(contrast), 0);
if (mask == 0)
return QImage();
@@ -1258,7 +1268,7 @@ QFontEngine *QWindowsFontEngine::cloneWithSize(qreal pixelSize) const
request.styleStrategy |= QFont::NoFontMerging;
QFontEngine *fontEngine =
- QWindowsFontDatabase::createEngine(QUnicodeTables::Common, request, 0,
+ QWindowsFontDatabase::createEngine(QChar::Script_Common, request, 0,
QWindowsContext::instance()->defaultDPI(),
false,
QStringList(), m_fontEngineData);
diff --git a/src/plugins/platforms/windows/qwindowsfontengine.h b/src/plugins/platforms/windows/qwindowsfontengine.h
index a23db2f235..2bf6ead503 100644
--- a/src/plugins/platforms/windows/qwindowsfontengine.h
+++ b/src/plugins/platforms/windows/qwindowsfontengine.h
@@ -145,6 +145,7 @@ public:
private:
QWindowsNativeImage *drawGDIGlyph(HFONT font, glyph_t, int margin, const QTransform &xform,
QImage::Format mask_format);
+ bool hasCFFTable() const;
const QSharedPointer<QWindowsFontEngineData> m_fontEngineData;
@@ -155,6 +156,7 @@ private:
uint stockFont : 1;
uint ttf : 1;
uint hasOutline : 1;
+ uint cffTable : 1;
TEXTMETRIC tm;
int lw;
const unsigned char *cmap;
diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp
index 183acedfc8..5b6ce695d8 100644
--- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp
+++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp
@@ -376,10 +376,12 @@ void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEn
if (SUCCEEDED(hr)) {
for (int i=0; i<glyphs->numGlyphs; ++i) {
glyphs->advances_x[i] = DESIGN_TO_LOGICAL(glyphMetrics[i].advanceWidth);
- if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
- glyphs->advances_x[i] = glyphs->advances_x[i].round();
glyphs->advances_y[i] = 0;
}
+ if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
+ for (int i = 0; i < glyphs->numGlyphs; ++i)
+ glyphs->advances_x[i] = glyphs->advances_x[i].round();
+ }
} else {
qErrnoWarning("%s: GetDesignGlyphMetrics failed", __FUNCTION__);
}
diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h
index 35ed6f3891..106087f757 100644
--- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h
+++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h
@@ -42,6 +42,8 @@
#ifndef QWINDOWSFONTENGINEDIRECTWRITE_H
#define QWINDOWSFONTENGINEDIRECTWRITE_H
+#include <QtCore/qglobal.h>
+
#ifndef QT_NO_DIRECTWRITE
#include <QtGui/private/qfontengine_p.h>
diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp
index 081b42ce65..6f59b33e62 100644
--- a/src/plugins/platforms/windows/qwindowsglcontext.cpp
+++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp
@@ -232,6 +232,7 @@ static QSurfaceFormat
QWindowsOpenGLAdditionalFormat *additionalIn = 0)
{
QSurfaceFormat format;
+ format.setRenderableType(QSurfaceFormat::OpenGL);
if (pfd.dwFlags & PFD_DOUBLEBUFFER)
format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
format.setDepthBufferSize(pfd.cDepthBits);
@@ -500,6 +501,7 @@ static QSurfaceFormat
enum { attribSize =40 };
QSurfaceFormat result;
+ result.setRenderableType(QSurfaceFormat::OpenGL);
if (!staticContext.hasExtensions())
return result;
int iAttributes[attribSize];
@@ -875,6 +877,12 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex
m_renderingContext(0),
m_pixelFormat(0), m_extensionsUsed(false)
{
+ QSurfaceFormat format = context->format();
+ if (format.renderableType() == QSurfaceFormat::DefaultRenderableType)
+ format.setRenderableType(QSurfaceFormat::OpenGL);
+ if (format.renderableType() != QSurfaceFormat::OpenGL)
+ return;
+
// workaround for matrox driver:
// make a cheap call to opengl to force loading of DLL
static bool opengl32dll = false;
@@ -912,7 +920,7 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex
QWindowsOpenGLAdditionalFormat obtainedAdditional;
if (tryExtensions) {
m_pixelFormat =
- ARB::choosePixelFormat(hdc, *m_staticContext, context->format(),
+ ARB::choosePixelFormat(hdc, *m_staticContext, format,
requestedAdditional, &m_obtainedPixelFormatDescriptor);
if (m_pixelFormat > 0) {
m_obtainedFormat =
@@ -922,7 +930,7 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex
}
} // tryExtensions
if (!m_pixelFormat) { // Failed, try GDI
- m_pixelFormat = GDI::choosePixelFormat(hdc, context->format(), requestedAdditional,
+ m_pixelFormat = GDI::choosePixelFormat(hdc, format, requestedAdditional,
&m_obtainedPixelFormatDescriptor);
if (m_pixelFormat)
m_obtainedFormat =
@@ -945,7 +953,7 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex
if (m_extensionsUsed)
m_renderingContext =
ARB::createContext(*m_staticContext, hdc,
- context->format(),
+ format,
requestedAdditional,
sharingRenderingContext);
if (!m_renderingContext)
diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp
index da4519199f..30e0478e64 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.cpp
+++ b/src/plugins/platforms/windows/qwindowsintegration.cpp
@@ -77,6 +77,7 @@
#include <QtCore/private/qeventdispatcher_win_p.h>
#include <QtCore/QDebug>
+#include <QtCore/QVariant>
QT_BEGIN_NAMESPACE
@@ -114,6 +115,11 @@ public:
bool asyncExpose() const;
void setAsyncExpose(bool value);
+
+ QVariantMap windowProperties(QPlatformWindow *window) const;
+ QVariant windowProperty(QPlatformWindow *window, const QString &name) const;
+ QVariant windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const;
+ void setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value);
};
void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resource, QWindow *window)
@@ -150,6 +156,37 @@ void *QWindowsNativeInterface::nativeResourceForBackingStore(const QByteArray &r
return 0;
}
+static const char customMarginPropertyC[] = "WindowsCustomMargins";
+
+QVariant QWindowsNativeInterface::windowProperty(QPlatformWindow *window, const QString &name) const
+{
+ QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window);
+ if (name == QLatin1String(customMarginPropertyC))
+ return qVariantFromValue(platformWindow->customMargins());
+ return QVariant();
+}
+
+QVariant QWindowsNativeInterface::windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const
+{
+ const QVariant result = windowProperty(window, name);
+ return result.isValid() ? result : defaultValue;
+}
+
+void QWindowsNativeInterface::setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value)
+{
+ QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window);
+ if (name == QLatin1String(customMarginPropertyC))
+ platformWindow->setCustomMargins(qvariant_cast<QMargins>(value));
+}
+
+QVariantMap QWindowsNativeInterface::windowProperties(QPlatformWindow *window) const
+{
+ QVariantMap result;
+ const QString customMarginProperty = QLatin1String(customMarginPropertyC);
+ result.insert(customMarginProperty, windowProperty(window, customMarginProperty));
+ return result;
+}
+
#ifndef QT_NO_OPENGL
void *QWindowsNativeInterface::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context)
{
@@ -372,6 +409,11 @@ QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) cons
QWindowsWindow::WindowData requested;
requested.flags = window->flags();
requested.geometry = window->geometry();
+ // Apply custom margins (see QWindowsWindow::setCustomMargins())).
+ const QVariant customMarginsV = window->property("_q_windowsCustomMargins");
+ if (customMarginsV.isValid())
+ requested.customMargins = qvariant_cast<QMargins>(customMarginsV);
+
const QWindowsWindow::WindowData obtained
= QWindowsWindow::WindowData::create(window, requested, window->title());
if (QWindowsContext::verboseIntegration || QWindowsContext::verboseWindows)
diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h
index 24dc01f0bd..ca484415be 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.h
+++ b/src/plugins/platforms/windows/qwindowsintegration.h
@@ -78,7 +78,7 @@ public:
# ifndef QT_NO_DRAGANDDROP
virtual QPlatformDrag *drag() const;
# endif
-#endif !QT_NO_CLIPBOARD
+#endif // !QT_NO_CLIPBOARD
virtual QPlatformInputContext *inputContext() const;
#ifndef QT_NO_ACCESSIBILITY
virtual QPlatformAccessibility *accessibility() const;
diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp
index 56deb27442..924d604641 100644
--- a/src/plugins/platforms/windows/qwindowskeymapper.cpp
+++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp
@@ -856,9 +856,15 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &ms
if (isNumpad && (nModifiers & AltAny)) {
code = winceKeyBend(msg.wParam);
} else if (!isDeadKey) {
- unsigned char kbdBuffer[256]; // Will hold the complete keyboard state
- GetKeyboardState(kbdBuffer);
- code = toKeyOrUnicode(msg.wParam, scancode, kbdBuffer);
+ // QTBUG-8764, QTBUG-10032
+ // Can't call toKeyOrUnicode because that would call ToUnicode, and, if a dead key
+ // is pressed at the moment, Windows would NOT use it to compose a character for the next
+ // WM_CHAR event.
+
+ // Instead, use MapVirtualKey, which will provide adequate values.
+ code = MapVirtualKey(msg.wParam, MAPVK_VK_TO_CHAR);
+ if (code < 0x20 || code == 0x7f) // The same logic as in toKeyOrUnicode()
+ code = winceKeyBend(msg.wParam);
}
// Invert state logic:
@@ -1120,7 +1126,7 @@ QList<int> QWindowsKeyMapper::possibleKeys(const QKeyEvent *e) const
}
result << int(baseKey + keyMods); // The base key is _always_ valid, of course
- for (int i = 1; i < NumMods; ++i) {
+ for (size_t i = 1; i < NumMods; ++i) {
Qt::KeyboardModifiers neededMods = ModsTbl[i];
quint32 key = kbItem.qtKey[i];
if (key && key != baseKey && ((keyMods & neededMods) == neededMods))
diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmime.cpp
index 7fb32d3513..a8bacd631d 100644
--- a/src/plugins/platforms/windows/qwindowsmime.cpp
+++ b/src/plugins/platforms/windows/qwindowsmime.cpp
@@ -703,14 +703,14 @@ QWindowsMimeURI::QWindowsMimeURI()
bool QWindowsMimeURI::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
{
- if (getCf(formatetc) == CF_HDROP) {
+ if (mimeData->hasUrls() && getCf(formatetc) == CF_HDROP) {
QList<QUrl> urls = mimeData->urls();
for (int i=0; i<urls.size(); i++) {
if (!urls.at(i).toLocalFile().isEmpty())
return true;
}
}
- return (getCf(formatetc) == CF_INETURL_W || getCf(formatetc) == CF_INETURL) && mimeData->hasFormat(QStringLiteral("text/uri-list"));
+ return (getCf(formatetc) == CF_INETURL_W || getCf(formatetc) == CF_INETURL) && mimeData->hasUrls();
}
bool QWindowsMimeURI::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const
diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp
index e1f4f4b143..dd16ea1c6f 100644
--- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp
+++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp
@@ -49,6 +49,7 @@
#include <qpa/qwindowsysteminterface.h>
#include <QtGui/QGuiApplication>
#include <QtGui/QScreen>
+#include <QtGui/QWindow>
#include <QtCore/QDebug>
#include <QtCore/QScopedArrayPointer>
@@ -236,6 +237,9 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
platformWindow->setFlag(QWindowsWindow::AutoMouseCapture);
if (QWindowsContext::verboseEvents)
qDebug() << "Automatic mouse capture " << window;
+ // Implement "Click to focus" for native child windows.
+ if (!window->isTopLevel() && QGuiApplication::focusWindow() != window)
+ window->requestActivate();
} else if (platformWindow->hasMouseCapture()
&& platformWindow->testFlag(QWindowsWindow::AutoMouseCapture)
&& (msg.message == WM_LBUTTONUP || msg.message == WM_MBUTTONUP
diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.h b/src/plugins/platforms/windows/qwindowsmousehandler.h
index b3bfa03380..caf30e6b1a 100644
--- a/src/plugins/platforms/windows/qwindowsmousehandler.h
+++ b/src/plugins/platforms/windows/qwindowsmousehandler.h
@@ -109,6 +109,8 @@ Qt::KeyboardModifiers QWindowsMouseHandler::keyStateToModifiers(int wParam)
mods |= Qt::ControlModifier;
if (wParam & MK_SHIFT)
mods |= Qt::ShiftModifier;
+ if (GetKeyState(VK_MENU) < 0)
+ mods |= Qt::AltModifier;
return mods;
}
diff --git a/src/plugins/platforms/windows/qwindowsservices.cpp b/src/plugins/platforms/windows/qwindowsservices.cpp
index bcae2e0816..250fea56b1 100644
--- a/src/plugins/platforms/windows/qwindowsservices.cpp
+++ b/src/plugins/platforms/windows/qwindowsservices.cpp
@@ -44,6 +44,7 @@
#include <QtCore/QUrl>
#include <QtCore/QDebug>
+#include <QtCore/QDir>
#include <shlobj.h>
#ifndef Q_OS_WINCE
@@ -57,7 +58,8 @@ enum { debug = 0 };
static inline bool shellExecute(const QString &file)
{
#ifndef Q_OS_WINCE
- const quintptr result = (quintptr)ShellExecute(0, 0, (wchar_t*)file.utf16(), 0, 0, SW_SHOWNORMAL);
+ const QString nativeFilePath = QDir::toNativeSeparators(file);
+ const quintptr result = (quintptr)ShellExecute(0, 0, (wchar_t*)nativeFilePath.utf16(), 0, 0, SW_SHOWNORMAL);
// ShellExecute returns a value greater than 32 if successful
if (result <= 32) {
qWarning("ShellExecute '%s' failed (error %s).", qPrintable(file), qPrintable(QString::number(result)));
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index 07dc668b3f..9b2b67619d 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -64,6 +64,11 @@
QT_BEGIN_NAMESPACE
+enum {
+ defaultWindowWidth = 160,
+ defaultWindowHeight = 160
+};
+
Q_GUI_EXPORT HICON qt_pixmapToWinHICON(const QPixmap &);
static QByteArray debugWinStyle(DWORD style)
@@ -198,17 +203,16 @@ static inline QSize clientSize(HWND hwnd)
return qSizeOfRect(rect);
}
-// from qwidget_win.cpp/maximum layout size check removed.
-static bool shouldShowMaximizeButton(Qt::WindowFlags flags)
+// from qwidget_win.cpp
+static bool shouldShowMaximizeButton(const QWindow *w)
{
- if (flags & Qt::MSWindowsFixedSizeDialogHint)
+ const Qt::WindowFlags flags = w->flags();
+ if ((flags & Qt::MSWindowsFixedSizeDialogHint) || !(flags & Qt::WindowMaximizeButtonHint))
return false;
// if the user explicitly asked for the maximize button, we try to add
// it even if the window has fixed size.
- if (flags & Qt::CustomizeWindowHint &&
- flags & Qt::WindowMaximizeButtonHint)
- return true;
- return flags & Qt::WindowMaximizeButtonHint;
+ return (flags & Qt::CustomizeWindowHint) ||
+ w->maximumSize() == QSize(QWINDOWSIZE_MAX, QWINDOWSIZE_MAX);
}
// Set the WS_EX_LAYERED flag on a HWND if required. This is required for
@@ -253,6 +257,8 @@ static void setWindowOpacity(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, qr
} else {
QWindowsContext::user32dll.setLayeredWindowAttributes(hwnd, 0, (int)(level * 255), LWA_ALPHA);
}
+ } else if (IsWindowVisible(hwnd)) { // Repaint when switching from layered.
+ InvalidateRect(hwnd, NULL, TRUE);
}
#endif // !Q_OS_WINCE
}
@@ -296,7 +302,7 @@ struct WindowCreationData
tool(false), embedded(false), hasAlpha(false) {}
void fromWindow(const QWindow *w, const Qt::WindowFlags flags, unsigned creationFlags = 0);
- inline WindowData create(const QWindow *w, const QRect &geometry, QString title) const;
+ inline WindowData create(const QWindow *w, const WindowData &data, QString title) const;
inline void applyWindowFlags(HWND hwnd) const;
void initialize(HWND h, bool frameChange, qreal opacityLevel) const;
@@ -427,7 +433,7 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag
style |= WS_SYSMENU;
if (flags & Qt::WindowMinimizeButtonHint)
style |= WS_MINIMIZEBOX;
- if (shouldShowMaximizeButton(flags))
+ if (shouldShowMaximizeButton(w))
style |= WS_MAXIMIZEBOX;
if (tool)
exStyle |= WS_EX_TOOLWINDOW;
@@ -448,7 +454,7 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag
}
QWindowsWindow::WindowData
- WindowCreationData::create(const QWindow *w, const QRect &geometry, QString title) const
+ WindowCreationData::create(const QWindow *w, const WindowData &data, QString title) const
{
typedef QSharedPointer<QWindowCreationContext> QWindowCreationContextPtr;
@@ -468,30 +474,38 @@ QWindowsWindow::WindowData
const QString windowClassName = QWindowsContext::instance()->registerWindowClass(w, isGL);
+ QRect rect = QPlatformWindow::initialGeometry(w, data.geometry, defaultWindowWidth, defaultWindowHeight);
+
if (title.isEmpty() && (result.flags & Qt::WindowTitleHint))
title = topLevel ? qAppName() : w->objectName();
const wchar_t *titleUtf16 = reinterpret_cast<const wchar_t *>(title.utf16());
const wchar_t *classNameUtf16 = reinterpret_cast<const wchar_t *>(windowClassName.utf16());
- // Capture events before CreateWindowEx() returns.
- const QWindowCreationContextPtr context(new QWindowCreationContext(w, geometry, style, exStyle));
+ // Capture events before CreateWindowEx() returns. The context is cleared in
+ // the QWindowsWindow constructor.
+ const QWindowCreationContextPtr context(new QWindowCreationContext(w, rect, data.customMargins, style, exStyle));
QWindowsContext::instance()->setWindowCreationContext(context);
+ if (context->frameX < 0)
+ context->frameX = 0;
+ if (context->frameY < 0)
+ context->frameY = 0;
+
if (QWindowsContext::verboseWindows)
qDebug().nospace()
<< "CreateWindowEx: " << w << *this
<< " class=" <<windowClassName << " title=" << title
- << "\nrequested: " << geometry << ": "
+ << "\nrequested: " << rect << ": "
<< context->frameWidth << 'x' << context->frameHeight
- << '+' << context->frameX << '+' << context->frameY;
+ << '+' << context->frameX << '+' << context->frameY
+ << " custom margins: " << context->customMargins;
result.hwnd = CreateWindowEx(exStyle, classNameUtf16, titleUtf16,
style,
context->frameX, context->frameY,
context->frameWidth, context->frameHeight,
parentHandle, NULL, appinst, NULL);
- QWindowsContext::instance()->setWindowCreationContext(QWindowCreationContextPtr());
if (QWindowsContext::verboseWindows)
qDebug().nospace()
<< "CreateWindowEx: returns " << w << ' ' << result.hwnd << " obtained geometry: "
@@ -505,6 +519,7 @@ QWindowsWindow::WindowData
result.geometry = context->obtainedGeometry;
result.frame = context->margins;
result.embedded = embedded;
+ result.customMargins = context->customMargins;
return result;
}
@@ -543,6 +558,8 @@ void WindowCreationData::initialize(HWND hwnd, bool frameChange, qreal opacityLe
qWarning() << "QWidget: Incompatible window flags: the window can't be on top and on bottom at the same time";
} else if (flags & Qt::WindowStaysOnBottomHint) {
SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, swpFlags);
+ } else if (frameChange) { // Force WM_NCCALCSIZE with wParam=1 in case of custom margins.
+ SetWindowPos(hwnd, 0, 0, 0, 0, 0, swpFlags);
}
if (flags & (Qt::CustomizeWindowHint|Qt::WindowTitleHint)) {
HMENU systemMenu = GetSystemMenu(hwnd, FALSE);
@@ -571,9 +588,10 @@ void WindowCreationData::initialize(HWND hwnd, bool frameChange, qreal opacityLe
#define QWINDOWSIZE_MAX ((1<<24)-1)
-QWindowsGeometryHint::QWindowsGeometryHint(const QWindow *w) :
+QWindowsGeometryHint::QWindowsGeometryHint(const QWindow *w, const QMargins &cm) :
minimumSize(w->minimumSize()),
- maximumSize(w->maximumSize())
+ maximumSize(w->maximumSize()),
+ customMargins(cm)
{
}
@@ -603,6 +621,33 @@ QMargins QWindowsGeometryHint::frame(DWORD style, DWORD exStyle)
return result;
}
+bool QWindowsGeometryHint::handleCalculateSize(const QMargins &customMargins, const MSG &msg, LRESULT *result)
+{
+#ifndef Q_OS_WINCE
+ // NCCALCSIZE_PARAMS structure if wParam==TRUE
+ if (!msg.wParam || customMargins.isNull())
+ return false;
+ *result = DefWindowProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
+ NCCALCSIZE_PARAMS *ncp = reinterpret_cast<NCCALCSIZE_PARAMS *>(msg.lParam);
+ const RECT oldClientArea = ncp->rgrc[0];
+ ncp->rgrc[0].left += customMargins.left();
+ ncp->rgrc[0].top += customMargins.top();
+ ncp->rgrc[0].right -= customMargins.right();
+ ncp->rgrc[0].bottom -= customMargins.bottom();
+ result = 0;
+ if (QWindowsContext::verboseWindows)
+ qDebug() << __FUNCTION__ << oldClientArea << '+' << customMargins << "-->"
+ << ncp->rgrc[0] << ' ' << ncp->rgrc[1] << ' ' << ncp->rgrc[2]
+ << ' ' << ncp->lppos->cx << ',' << ncp->lppos->cy;
+ return true;
+#else
+ Q_UNUSED(customMargins)
+ Q_UNUSED(msg)
+ Q_UNUSED(result)
+ return false;
+#endif
+}
+
#ifndef Q_OS_WINCE
void QWindowsGeometryHint::applyToMinMaxInfo(HWND hwnd, MINMAXINFO *mmi) const
{
@@ -619,8 +664,8 @@ void QWindowsGeometryHint::applyToMinMaxInfo(DWORD style, DWORD exStyle, MINMAXI
<< " in " << *mmi;
const QMargins margins = QWindowsGeometryHint::frame(style, exStyle);
- const int frameWidth = margins.left() + margins.right();
- const int frameHeight = margins.top() + margins.bottom();
+ const int frameWidth = margins.left() + margins.right() + customMargins.left() + customMargins.right();
+ const int frameHeight = margins.top() + margins.bottom() + customMargins.top() + customMargins.bottom();
if (minimumSize.width() > 0)
mmi->ptMinTrackSize.x = minimumSize.width() + frameWidth;
if (minimumSize.height() > 0)
@@ -669,10 +714,11 @@ bool QWindowsGeometryHint::positionIncludesFrame(const QWindow *w)
QWindowCreationContext::QWindowCreationContext(const QWindow *w,
const QRect &geometry,
+ const QMargins &cm,
DWORD style_, DWORD exStyle_) :
- geometryHint(w), style(style_), exStyle(exStyle_),
+ geometryHint(w, cm), style(style_), exStyle(exStyle_),
requestedGeometry(geometry), obtainedGeometry(geometry),
- margins(QWindowsGeometryHint::frame(style, exStyle)),
+ margins(QWindowsGeometryHint::frame(style, exStyle)), customMargins(cm),
frameX(CW_USEDEFAULT), frameY(CW_USEDEFAULT),
frameWidth(CW_USEDEFAULT), frameHeight(CW_USEDEFAULT)
{
@@ -683,14 +729,16 @@ QWindowCreationContext::QWindowCreationContext(const QWindow *w,
if (geometry.isValid()) {
frameX = geometry.x();
frameY = geometry.y();
- frameWidth = margins.left() + geometry.width() + margins.right();
- frameHeight = margins.top() + geometry.height() + margins.bottom();
+ const QMargins effectiveMargins = margins + customMargins;
+ frameWidth = effectiveMargins.left() + geometry.width() + effectiveMargins.right();
+ frameHeight = effectiveMargins.top() + geometry.height() + effectiveMargins.bottom();
const bool isDefaultPosition = !frameX && !frameY && w->isTopLevel();
if (!QWindowsGeometryHint::positionIncludesFrame(w) && !isDefaultPosition) {
- frameX -= margins.left();
- frameY -= margins.top();
+ frameX -= effectiveMargins.left();
+ frameY -= effectiveMargins.top();
}
}
+
if (QWindowsContext::verboseWindows)
qDebug().nospace()
<< __FUNCTION__ << ' ' << w << geometry
@@ -698,7 +746,8 @@ QWindowCreationContext::QWindowCreationContext(const QWindow *w,
<< " frame: " << frameWidth << 'x' << frameHeight << '+'
<< frameX << '+' << frameY
<< " min" << geometryHint.minimumSize
- << " max" << geometryHint.maximumSize;
+ << " max" << geometryHint.maximumSize
+ << " custom margins " << customMargins;
}
/*!
@@ -730,9 +779,6 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const WindowData &data) :
m_hdc(0),
m_windowState(Qt::WindowNoState),
m_opacity(1.0),
-#ifndef QT_NO_CURSOR
- m_cursor(QWindowsScreen::screenOf(aWindow)->windowsCursor()->standardWindowCursor()),
-#endif
m_dropTarget(0),
m_savedStyle(0),
m_format(aWindow->format()),
@@ -745,11 +791,16 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const WindowData &data) :
m_iconSmall(0),
m_iconBig(0)
{
+ // Clear the creation context as the window can be found in QWindowsContext's map.
+ QWindowsContext::instance()->setWindowCreationContext(QSharedPointer<QWindowCreationContext>());
+ QWindowsContext::instance()->addWindow(m_data.hwnd, this);
+ const Qt::WindowType type = aWindow->type();
+ if (type == Qt::Desktop)
+ return; // No further handling for Qt::Desktop
if (aWindow->surfaceType() == QWindow::OpenGLSurface)
setFlag(OpenGLSurface);
- QWindowsContext::instance()->addWindow(m_data.hwnd, this);
if (aWindow->isTopLevel()) {
- switch (aWindow->type()) {
+ switch (type) {
case Qt::Window:
case Qt::Dialog:
case Qt::Sheet:
@@ -763,8 +814,13 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const WindowData &data) :
}
}
#ifndef Q_OS_WINCE
- if (QWindowsContext::instance()->systemInfo() & QWindowsContext::SI_SupportsTouch)
- QWindowsContext::user32dll.registerTouchWindow(m_data.hwnd, 0);
+ if (QWindowsContext::instance()->systemInfo() & QWindowsContext::SI_SupportsTouch) {
+ if (QWindowsContext::user32dll.registerTouchWindow(m_data.hwnd, 0)) {
+ setFlag(TouchRegistered);
+ } else {
+ qErrnoWarning("RegisterTouchWindow() failed for window '%s'.", qPrintable(aWindow->objectName()));
+ }
+ }
#endif // !Q_OS_WINCE
setWindowState(aWindow->windowState());
const qreal opacity = qt_window_private(aWindow)->opacity;
@@ -775,7 +831,8 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const WindowData &data) :
QWindowsWindow::~QWindowsWindow()
{
#ifndef Q_OS_WINCE
- if (QWindowsContext::instance()->systemInfo() & QWindowsContext::SI_SupportsTouch)
+ QWindowSystemInterface::flushWindowSystemEvents();
+ if (testFlag(TouchRegistered))
QWindowsContext::user32dll.unregisterTouchWindow(m_data.hwnd);
#endif // !Q_OS_WINCE
destroyWindow();
@@ -872,8 +929,9 @@ QWindowsWindow::WindowData
{
WindowCreationData creationData;
creationData.fromWindow(w, parameters.flags);
- WindowData result = creationData.create(w, parameters.geometry, title);
- creationData.initialize(result.hwnd, false, 1);
+ WindowData result = creationData.create(w, parameters, title);
+ // Force WM_NCCALCSIZE (with wParam=1) via SWP_FRAMECHANGED for custom margin.
+ creationData.initialize(result.hwnd, !parameters.customMargins.isNull(), 1);
return result;
}
@@ -1060,7 +1118,7 @@ void QWindowsWindow::setGeometry(const QRect &rectIn)
const QSize newSize = rect.size();
// Check on hint.
if (newSize != oldSize) {
- const QWindowsGeometryHint hint(window());
+ const QWindowsGeometryHint hint(window(), m_data.customMargins);
if (!hint.validSize(newSize)) {
qWarning("%s: Attempt to set a size (%dx%d) violating the constraints"
"(%dx%d - %dx%d) on window '%s'.", __FUNCTION__,
@@ -1078,14 +1136,19 @@ void QWindowsWindow::setGeometry(const QRect &rectIn)
if (m_data.geometry != rect) {
qWarning("%s: Unable to set geometry %dx%d+%d+%d on '%s'."
" Resulting geometry: %dx%d+%d+%d "
- "(frame: %d, %d, %d, %d).",
+ "(frame: %d, %d, %d, %d, custom margin: %d, %d, %d, %d"
+ ", minimum size: %dx%d, maximum size: %dx%d).",
__FUNCTION__,
rect.width(), rect.height(), rect.x(), rect.y(),
qPrintable(window()->objectName()),
m_data.geometry.width(), m_data.geometry.height(),
m_data.geometry.x(), m_data.geometry.y(),
m_data.frame.left(), m_data.frame.top(),
- m_data.frame.right(), m_data.frame.bottom());
+ m_data.frame.right(), m_data.frame.bottom(),
+ m_data.customMargins.left(), m_data.customMargins.top(),
+ m_data.customMargins.right(), m_data.customMargins.bottom(),
+ window()->minimumWidth(), window()->minimumHeight(),
+ window()->maximumWidth(), window()->maximumHeight());
}
} else {
QPlatformWindow::setGeometry(rect);
@@ -1163,7 +1226,7 @@ QRect QWindowsWindow::frameGeometry_sys() const
QRect QWindowsWindow::geometry_sys() const
{
- return frameGeometry_sys() - frameMargins();
+ return frameGeometry_sys().marginsRemoved(frameMargins());
}
/*!
@@ -1490,7 +1553,7 @@ QMargins QWindowsWindow::frameMargins() const
m_data.frame = QWindowsGeometryHint::frame(style(), exStyle());
clearFlag(FrameDirty);
}
- return m_data.frame;
+ return m_data.frame + m_data.customMargins;
}
void QWindowsWindow::setOpacity(qreal level)
@@ -1648,13 +1711,23 @@ void QWindowsWindow::setFrameStrutEventsEnabled(bool enabled)
#ifndef Q_OS_WINCE // maybe available on some SDKs revisit WM_GETMINMAXINFO
void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const
{
- const QWindowsGeometryHint hint(window());
+ const QWindowsGeometryHint hint(window(), m_data.customMargins);
hint.applyToMinMaxInfo(m_data.hwnd, mmi);
if (QWindowsContext::verboseWindows)
qDebug() << __FUNCTION__ << window() << *mmi;
}
#endif // !Q_OS_WINCE
+// Return the default cursor (Arrow) from QWindowsCursor's cache.
+static inline QWindowsWindowCursor defaultCursor(const QWindow *w)
+{
+ if (QScreen *screen = w->screen())
+ if (const QPlatformScreen *platformScreen = screen->handle())
+ if (QPlatformCursor *cursor = platformScreen->cursor())
+ return static_cast<QWindowsCursor *>(cursor)->standardWindowCursor(Qt::ArrowCursor);
+ return QWindowsWindowCursor(Qt::ArrowCursor);
+}
+
/*!
\brief Applies to cursor property set on the window to the global cursor.
@@ -1664,20 +1737,45 @@ void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const
void QWindowsWindow::applyCursor()
{
#ifndef QT_NO_CURSOR
- SetCursor(m_cursor.handle());
+ if (m_cursor.isNull()) { // Recurse up to parent with non-null cursor. Set default for toplevel.
+ if (const QWindow *p = window()->parent()) {
+ QWindowsWindow::baseWindowOf(p)->applyCursor();
+ } else {
+ SetCursor(defaultCursor(window()).handle());
+ }
+ } else {
+ SetCursor(m_cursor.handle());
+ }
#endif
}
+// Check whether to apply a new cursor. Either the window in question is
+// currently under mouse, or it is the parent of the window under mouse and
+// there is no other window with an explicitly set cursor in-between.
+static inline bool applyNewCursor(const QWindow *w)
+{
+ const QWindow *underMouse = QWindowsContext::instance()->windowUnderMouse();
+ if (underMouse == w)
+ return true;
+ for (const QWindow *p = underMouse; p ; p = p->parent()) {
+ if (p == w)
+ return true;
+ if (!QWindowsWindow::baseWindowOf(p)->cursor().isNull())
+ return false;
+ }
+ return false;
+}
+
void QWindowsWindow::setCursor(const QWindowsWindowCursor &c)
{
#ifndef QT_NO_CURSOR
if (c.handle() != m_cursor.handle()) {
- const bool underMouse = QWindowsContext::instance()->windowUnderMouse() == window();
+ const bool apply = applyNewCursor(window());
if (QWindowsContext::verboseWindows)
qDebug() << window() << __FUNCTION__ << "Shape=" << c.cursor().shape()
- << " isWUM=" << underMouse;
+ << " doApply=" << apply;
m_cursor = c;
- if (underMouse)
+ if (apply)
applyCursor();
}
#endif
@@ -1850,4 +1948,32 @@ void QWindowsWindow::setWindowIcon(const QIcon &icon)
}
}
+/*!
+ \brief Sets custom margins to be added to the default margins determined by
+ the windows style in the handling of the WM_NCCALCSIZE message.
+
+ This is currently used to give the Aero-style QWizard a smaller top margin.
+ The property can be set using QPlatformNativeInterface::setWindowProperty() or,
+ before platform window creation, by setting a dynamic property
+ on the QWindow (see QWindowsIntegration::createPlatformWindow()).
+*/
+
+void QWindowsWindow::setCustomMargins(const QMargins &newCustomMargins)
+{
+ if (newCustomMargins != m_data.customMargins) {
+ const QMargins oldCustomMargins = m_data.customMargins;
+ m_data.customMargins = newCustomMargins;
+ // Re-trigger WM_NCALCSIZE with wParam=1 by passing SWP_FRAMECHANGED
+ const QRect currentFrameGeometry = frameGeometry_sys();
+ const QPoint topLeft = currentFrameGeometry.topLeft();
+ QRect newFrame = currentFrameGeometry.marginsRemoved(oldCustomMargins) + m_data.customMargins;
+ newFrame.moveTo(topLeft);
+ setFlag(FrameDirty);
+ if (QWindowsContext::verboseWindows)
+ qDebug() << __FUNCTION__ << oldCustomMargins << "->" << newCustomMargins
+ << currentFrameGeometry << "->" << newFrame;
+ SetWindowPos(m_data.hwnd, 0, newFrame.x(), newFrame.y(), newFrame.width(), newFrame.height(), SWP_NOZORDER | SWP_FRAMECHANGED);
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h
index f3b480b0af..1148440f05 100644
--- a/src/plugins/platforms/windows/qwindowswindow.h
+++ b/src/plugins/platforms/windows/qwindowswindow.h
@@ -67,8 +67,9 @@ class QWindowsEGLStaticContext;
struct QWindowsGeometryHint
{
QWindowsGeometryHint() {}
- explicit QWindowsGeometryHint(const QWindow *w);
+ explicit QWindowsGeometryHint(const QWindow *w, const QMargins &customMargins);
static QMargins frame(DWORD style, DWORD exStyle);
+ static bool handleCalculateSize(const QMargins &customMargins, const MSG &msg, LRESULT *result);
#ifndef Q_OS_WINCE //MinMax maybe define struct if not available
void applyToMinMaxInfo(DWORD style, DWORD exStyle, MINMAXINFO *mmi) const;
void applyToMinMaxInfo(HWND hwnd, MINMAXINFO *mmi) const;
@@ -84,11 +85,13 @@ struct QWindowsGeometryHint
QSize minimumSize;
QSize maximumSize;
+ QMargins customMargins;
};
struct QWindowCreationContext
{
QWindowCreationContext(const QWindow *w, const QRect &r,
+ const QMargins &customMargins,
DWORD style, DWORD exStyle);
#ifndef Q_OS_WINCE //MinMax maybe define struct if not available
void applyToMinMaxInfo(MINMAXINFO *mmi) const
@@ -101,6 +104,7 @@ struct QWindowCreationContext
QRect requestedGeometry;
QRect obtainedGeometry;
QMargins margins;
+ QMargins customMargins; // User-defined, additional frame for WM_NCCALCSIZE
int frameX; // Passed on to CreateWindowEx(), including frame.
int frameY;
int frameWidth;
@@ -127,7 +131,8 @@ public:
FrameStrutEventsEnabled = 0x200,
SynchronousGeometryChangeEvent = 0x400,
WithinSetStyle = 0x800,
- WithinDestroy = 0x1000
+ WithinDestroy = 0x1000,
+ TouchRegistered = 0x2000
};
struct WindowData
@@ -137,6 +142,7 @@ public:
Qt::WindowFlags flags;
QRect geometry;
QMargins frame; // Do not use directly for windows, see FrameDirty.
+ QMargins customMargins; // User-defined, additional frame for NCCALCSIZE
HWND hwnd;
bool embedded;
@@ -191,6 +197,9 @@ public:
void setFrameStrutEventsEnabled(bool enabled);
bool frameStrutEventsEnabled() const { return testFlag(FrameStrutEventsEnabled); }
+ QMargins customMargins() const { return m_data.customMargins; }
+ void setCustomMargins(const QMargins &m);
+
#ifdef QT_OPENGL_ES_2
EGLSurface eglSurfaceHandle() const { return m_eglSurface;}
EGLSurface ensureEglSurfaceHandle(const QWindowsEGLStaticContextPtr &staticContext, EGLConfig config);
@@ -290,17 +299,6 @@ private:
HICON m_iconBig;
};
-// Conveniences for window frames.
-inline QRect operator+(const QRect &r, const QMargins &m)
-{
- return r.adjusted(-m.left(), -m.top(), m.right(), m.bottom());
-}
-
-inline QRect operator-(const QRect &r, const QMargins &m)
-{
- return r.adjusted(m.left(), m.top(), -m.right(), -m.bottom());
-}
-
// Debug
QDebug operator<<(QDebug d, const RECT &r);
#ifndef Q_OS_WINCE // maybe available on some SDKs revisit WM_GETMINMAXINFO/WM_NCCALCSIZE
@@ -371,4 +369,6 @@ inline void QWindowsWindow::destroyIcon()
QT_END_NAMESPACE
+Q_DECLARE_METATYPE(QMargins)
+
#endif // QWINDOWSWINDOW_H
diff --git a/src/plugins/platforms/windows/windows.pro b/src/plugins/platforms/windows/windows.pro
index ff162e2d41..3aa9caaa0f 100644
--- a/src/plugins/platforms/windows/windows.pro
+++ b/src/plugins/platforms/windows/windows.pro
@@ -102,12 +102,8 @@ contains(QT_CONFIG, opengles2) {
}
}
-# Enable access to HB_Face in harfbuzz includes included by qfontengine_p.h.
-DEFINES *= QT_COMPILES_IN_HARFBUZZ
-
contains(QT_CONFIG, freetype) {
DEFINES *= QT_NO_FONTCONFIG
- DEFINES *= QT_COMPILES_IN_HARFBUZZ
QT_FREETYPE_DIR = $$QT_SOURCE_TREE/src/3rdparty/freetype
HEADERS += \
diff --git a/src/plugins/platforms/xcb/qglxintegration.cpp b/src/plugins/platforms/xcb/qglxintegration.cpp
index 11c74edc45..516b35dac8 100644
--- a/src/plugins/platforms/xcb/qglxintegration.cpp
+++ b/src/plugins/platforms/xcb/qglxintegration.cpp
@@ -50,6 +50,7 @@
#include <GL/glx.h>
#include <QtGui/QOpenGLContext>
+#include <QtGui/QOffscreenSurface>
#include "qglxintegration.h"
#include <QtPlatformSupport/private/qglxconvenience_p.h>
@@ -70,6 +71,10 @@ typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXC
#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
#endif
+#ifndef GLX_CONTEXT_ES2_PROFILE_BIT_EXT
+#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004
+#endif
+
#ifndef GLX_CONTEXT_PROFILE_MASK_ARB
#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126
#endif
@@ -104,57 +109,6 @@ static Window createDummyWindow(QXcbScreen *screen, GLXFBConfig config)
return window;
}
-// Per-window data for active OpenGL contexts.
-struct QOpenGLContextData
-{
- QOpenGLContextData(Display *display, Window window, GLXContext context)
- : m_display(display),
- m_window(window),
- m_context(context)
- {}
-
- QOpenGLContextData()
- : m_display(0),
- m_window(0),
- m_context(0)
- {}
-
- Display *m_display;
- Window m_window;
- GLXContext m_context;
-};
-
-static inline QOpenGLContextData currentOpenGLContextData()
-{
- QOpenGLContextData result;
- result.m_display = glXGetCurrentDisplay();
- result.m_window = glXGetCurrentDrawable();
- result.m_context = glXGetCurrentContext();
- return result;
-}
-
-static inline QOpenGLContextData createDummyWindowOpenGLContextData(QXcbScreen *screen)
-{
- QOpenGLContextData result;
- result.m_display = DISPLAY_FROM_XCB(screen);
-
- QSurfaceFormat format;
- GLXFBConfig config = qglx_findConfig(DISPLAY_FROM_XCB(screen), screen->screenNumber(), format);
- if (config) {
- result.m_context = glXCreateNewContext(DISPLAY_FROM_XCB(screen), config, GLX_RGBA_TYPE, 0, true);
- result.m_window = createDummyWindow(screen, config);
- } else {
- XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(screen), screen->screenNumber(), &format);
- if (!visualInfo)
- qFatal("Could not initialize GLX");
- result.m_context = glXCreateContext(DISPLAY_FROM_XCB(screen), visualInfo, 0, true);
- result.m_window = createDummyWindow(screen, visualInfo);
- XFree(visualInfo);
- }
-
- return result;
-}
-
static inline QByteArray getGlString(GLenum param)
{
if (const GLubyte *s = glGetString(param))
@@ -173,109 +127,53 @@ static void updateFormatFromContext(QSurfaceFormat &format)
}
format.setProfile(QSurfaceFormat::NoProfile);
+ format.setOption(QSurfaceFormat::FormatOptions());
- const int version = (major << 8) + minor;
- if (version < 0x0300) {
- format.setProfile(QSurfaceFormat::NoProfile);
- format.setOption(QSurfaceFormat::DeprecatedFunctions);
- return;
- }
-
- // Version 3.0 onwards - check if it includes deprecated functionality or is
- // a debug context
- GLint value = 0;
- glGetIntegerv(GL_CONTEXT_FLAGS, &value);
- if (!(value & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT))
- format.setOption(QSurfaceFormat::DeprecatedFunctions);
- if (value & GL_CONTEXT_FLAG_DEBUG_BIT)
- format.setOption(QSurfaceFormat::DebugContext);
- if (version < 0x0302)
- return;
-
- // Version 3.2 and newer have a profile
- value = 0;
- glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &value);
-
- if (value & GL_CONTEXT_CORE_PROFILE_BIT)
- format.setProfile(QSurfaceFormat::CoreProfile);
- else if (value & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
- format.setProfile(QSurfaceFormat::CompatibilityProfile);
-}
-
-/*!
- \class QOpenGLTemporaryContext
- \brief A temporary context that can be instantiated on the stack.
-
- Functions like glGetString() only work if there is a current GL context.
-
- \internal
- \ingroup qt-lighthouse-xcb
-*/
-class QOpenGLTemporaryContext
-{
- Q_DISABLE_COPY(QOpenGLTemporaryContext)
-public:
- QOpenGLTemporaryContext(QXcbScreen *screen);
- ~QOpenGLTemporaryContext();
-
-private:
- const QOpenGLContextData m_previous;
- const QOpenGLContextData m_current;
-};
-
-QOpenGLTemporaryContext::QOpenGLTemporaryContext(QXcbScreen *screen)
- : m_previous(currentOpenGLContextData()),
- m_current(createDummyWindowOpenGLContextData(screen))
-{
- // Make our temporary context current on our temporary window
- glXMakeCurrent(m_current.m_display, m_current.m_window, m_current.m_context);
-}
-
-QOpenGLTemporaryContext::~QOpenGLTemporaryContext()
-{
- // Restore the previous context if possible, otherwise just release our temporary context
- if (m_previous.m_display)
- glXMakeCurrent(m_previous.m_display, m_previous.m_window, m_previous.m_context);
- else
- glXMakeCurrent(m_current.m_display, 0, 0);
-
- // Destroy our temporary window
- XDestroyWindow(m_current.m_display, m_current.m_window);
-
- // Finally destroy our temporary context itself
- glXDestroyContext(m_current.m_display, m_current.m_context);
-}
-
-QOpenGLDefaultContextInfo::QOpenGLDefaultContextInfo()
- : vendor(getGlString(GL_VENDOR)),
- renderer(getGlString(GL_RENDERER))
-{
- updateFormatFromContext(format);
-}
+ if (format.renderableType() == QSurfaceFormat::OpenGL) {
+ if (format.version() < qMakePair(3, 0)) {
+ format.setOption(QSurfaceFormat::DeprecatedFunctions);
+ return;
+ }
-QOpenGLDefaultContextInfo *QOpenGLDefaultContextInfo::create(QXcbScreen *screen)
-{
- // We need a current context for getGLString() to work. To have
- // the QOpenGLDefaultContextInfo contain the latest supported
- // context version, we rely upon the QOpenGLTemporaryContext to
- // correctly obtain a context with the latest version
- QScopedPointer<QOpenGLTemporaryContext> temporaryContext(new QOpenGLTemporaryContext(screen));
- QOpenGLDefaultContextInfo *result = new QOpenGLDefaultContextInfo;
- return result;
+ // Version 3.0 onwards - check if it includes deprecated functionality or is
+ // a debug context
+ GLint value = 0;
+ glGetIntegerv(GL_CONTEXT_FLAGS, &value);
+ if (!(value & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT))
+ format.setOption(QSurfaceFormat::DeprecatedFunctions);
+ if (value & GL_CONTEXT_FLAG_DEBUG_BIT)
+ format.setOption(QSurfaceFormat::DebugContext);
+ if (format.version() < qMakePair(3, 2))
+ return;
+
+ // Version 3.2 and newer have a profile
+ value = 0;
+ glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &value);
+
+ if (value & GL_CONTEXT_CORE_PROFILE_BIT)
+ format.setProfile(QSurfaceFormat::CoreProfile);
+ else if (value & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
+ format.setProfile(QSurfaceFormat::CompatibilityProfile);
+ }
}
-
-QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlatformOpenGLContext *share, QOpenGLDefaultContextInfo *defaultContextInfo)
+QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlatformOpenGLContext *share)
: QPlatformOpenGLContext()
, m_screen(screen)
, m_context(0)
+ , m_shareContext(0)
, m_format(format)
+ , m_isPBufferCurrent(false)
{
- m_shareContext = 0;
+ if (m_format.renderableType() == QSurfaceFormat::DefaultRenderableType)
+ m_format.setRenderableType(QSurfaceFormat::OpenGL);
+ if (m_format.renderableType() != QSurfaceFormat::OpenGL && m_format.renderableType() != QSurfaceFormat::OpenGLES)
+ return;
+
if (share)
m_shareContext = static_cast<const QGLXContext*>(share)->glxContext();
- GLXFBConfig config = qglx_findConfig(DISPLAY_FROM_XCB(screen),screen->screenNumber(),format);
+ GLXFBConfig config = qglx_findConfig(DISPLAY_FROM_XCB(screen),screen->screenNumber(),m_format);
XVisualInfo *visualInfo = 0;
Window window = 0; // Temporary window used to query OpenGL context
@@ -287,56 +185,88 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat
QList<QByteArray> glxExt = QByteArray(glXQueryExtensionsString(DISPLAY_FROM_XCB(m_screen), m_screen->screenNumber())).split(' ');
bool supportsProfiles = glxExt.contains("GLX_ARB_create_context_profile");
- // Use glXCreateContextAttribsARB if is available
- if (glxExt.contains("GLX_ARB_create_context") && glXCreateContextAttribsARB != 0) {
- // We limit the requested version by the version of the static context as
- // glXCreateContextAttribsARB fails and returns NULL if the requested context
- // version is not supported. This means that we will get the closest supported
- // context format that that which was requested and is supported by the driver
- const int maxSupportedVersion = (defaultContextInfo->format.majorVersion() << 8)
- + defaultContextInfo->format.minorVersion();
- const int requestedVersion = qMin((format.majorVersion() << 8) + format.minorVersion(),
- maxSupportedVersion);
- const int majorVersion = requestedVersion >> 8;
- const int minorVersion = requestedVersion & 0xFF;
-
- QVector<int> contextAttributes;
- contextAttributes << GLX_CONTEXT_MAJOR_VERSION_ARB << majorVersion
- << GLX_CONTEXT_MINOR_VERSION_ARB << minorVersion;
-
- // If asking for OpenGL 3.2 or newer we should also specify a profile
- if (supportsProfiles && (m_format.majorVersion() > 3 || (m_format.majorVersion() == 3 && m_format.minorVersion() > 1))) {
- if (m_format.profile() == QSurfaceFormat::CoreProfile)
- contextAttributes << GLX_CONTEXT_PROFILE_MASK_ARB << GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
- else
- contextAttributes << GLX_CONTEXT_PROFILE_MASK_ARB << GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
+ // Use glXCreateContextAttribsARB if available
+ // Also, GL ES context creation requires GLX_EXT_create_context_es2_profile
+ if (glxExt.contains("GLX_ARB_create_context") && glXCreateContextAttribsARB != 0
+ && (m_format.renderableType() != QSurfaceFormat::OpenGLES || (supportsProfiles && glxExt.contains("GLX_EXT_create_context_es2_profile")))) {
+ // Try to create an OpenGL context for each known OpenGL version in descending
+ // order from the requested version.
+ const int requestedVersion = format.majorVersion() * 10 + qMin(format.minorVersion(), 9);
+
+ QVector<int> glVersions;
+ if (m_format.renderableType() == QSurfaceFormat::OpenGL) {
+ if (requestedVersion > 43)
+ glVersions << requestedVersion;
+
+ // Don't bother with versions below 2.0
+ glVersions << 43 << 42 << 41 << 40 << 33 << 32 << 31 << 30 << 21 << 20;
+ } else if (m_format.renderableType() == QSurfaceFormat::OpenGLES) {
+ if (requestedVersion > 30)
+ glVersions << requestedVersion;
+
+ // Don't bother with versions below ES 2.0
+ glVersions << 30 << 20;
+ // ES does not support any format option
+ m_format.setOption(QSurfaceFormat::FormatOptions());
}
- int flags = 0;
+ Q_ASSERT(glVersions.count() > 0);
- if (m_format.testOption(QSurfaceFormat::DebugContext))
- flags |= GLX_CONTEXT_DEBUG_BIT_ARB;
+ for (int i = 0; !m_context && i < glVersions.count(); i++) {
+ const int version = glVersions[i];
+ if (version > requestedVersion)
+ continue;
- // A forward-compatible context may be requested for 3.0 and later
- if (m_format.majorVersion() >= 3 && !m_format.testOption(QSurfaceFormat::DeprecatedFunctions))
- flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
+ const int majorVersion = version / 10;
+ const int minorVersion = version % 10;
- if (flags != 0)
- contextAttributes << GLX_CONTEXT_FLAGS_ARB << flags;
+ QVector<int> contextAttributes;
+ contextAttributes << GLX_CONTEXT_MAJOR_VERSION_ARB << majorVersion
+ << GLX_CONTEXT_MINOR_VERSION_ARB << minorVersion;
- contextAttributes << None;
- m_context = glXCreateContextAttribsARB(DISPLAY_FROM_XCB(screen), config, m_shareContext, true, contextAttributes.data());
- if (!m_context && m_shareContext) {
- // re-try without a shared glx context
- m_context = glXCreateContextAttribsARB(DISPLAY_FROM_XCB(screen), config, 0, true, contextAttributes.data());
- if (m_context)
- m_shareContext = 0;
+ if (m_format.renderableType() == QSurfaceFormat::OpenGL) {
+ // If asking for OpenGL 3.2 or newer we should also specify a profile
+ if (version >= 32 && supportsProfiles) {
+ if (m_format.profile() == QSurfaceFormat::CoreProfile)
+ contextAttributes << GLX_CONTEXT_PROFILE_MASK_ARB << GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
+ else
+ contextAttributes << GLX_CONTEXT_PROFILE_MASK_ARB << GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
+ }
+
+ int flags = 0;
+
+ if (m_format.testOption(QSurfaceFormat::DebugContext))
+ flags |= GLX_CONTEXT_DEBUG_BIT_ARB;
+
+ // A forward-compatible context may be requested for 3.0 and later
+ if (version >= 30 && !m_format.testOption(QSurfaceFormat::DeprecatedFunctions))
+ flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
+
+ if (flags != 0)
+ contextAttributes << GLX_CONTEXT_FLAGS_ARB << flags;
+ } else if (m_format.renderableType() == QSurfaceFormat::OpenGLES) {
+ contextAttributes << GLX_CONTEXT_PROFILE_MASK_ARB << GLX_CONTEXT_ES2_PROFILE_BIT_EXT;
+ }
+
+ contextAttributes << None;
+
+ m_context = glXCreateContextAttribsARB(DISPLAY_FROM_XCB(screen), config, m_shareContext, true, contextAttributes.data());
+ if (!m_context && m_shareContext) {
+ // re-try without a shared glx context
+ m_context = glXCreateContextAttribsARB(DISPLAY_FROM_XCB(screen), config, 0, true, contextAttributes.data());
+ if (m_context)
+ m_shareContext = 0;
+ }
}
}
// Could not create a context using glXCreateContextAttribsARB, falling back to glXCreateNewContext.
if (!m_context) {
+ // requesting an OpenGL ES context requires glXCreateContextAttribsARB, so bail out
+ if (m_format.renderableType() == QSurfaceFormat::OpenGLES)
+ return;
+
m_context = glXCreateNewContext(DISPLAY_FROM_XCB(screen), config, GLX_RGBA_TYPE, m_shareContext, true);
if (!m_context && m_shareContext) {
// re-try without a shared glx context
@@ -348,11 +278,15 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat
// Get the basic surface format details
if (m_context)
- m_format = qglx_surfaceFormatFromGLXFBConfig(DISPLAY_FROM_XCB(screen), config, m_context);
+ qglx_surfaceFormatFromGLXFBConfig(&m_format, DISPLAY_FROM_XCB(screen), config, m_context);
// Create a temporary window so that we can make the new context current
window = createDummyWindow(screen, config);
} else {
+ // requesting an OpenGL ES context requires glXCreateContextAttribsARB, so bail out
+ if (m_format.renderableType() == QSurfaceFormat::OpenGLES)
+ return;
+
// Note that m_format gets updated with the used surface format
visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(screen), screen->screenNumber(), &m_format);
if (!visualInfo)
@@ -391,19 +325,35 @@ bool QGLXContext::makeCurrent(QPlatformSurface *surface)
{
Q_ASSERT(surface->surface()->surfaceType() == QSurface::OpenGLSurface);
- GLXDrawable glxDrawable = static_cast<QXcbWindow *>(surface)->xcb_window();
-
- return glXMakeCurrent(DISPLAY_FROM_XCB(m_screen), glxDrawable, m_context);
+ QSurface::SurfaceClass surfaceClass = surface->surface()->surfaceClass();
+ if (surfaceClass == QSurface::Window) {
+ m_isPBufferCurrent = false;
+ QXcbWindow *window = static_cast<QXcbWindow *>(surface);
+ return glXMakeCurrent(DISPLAY_FROM_XCB(m_screen), window->xcb_window(), m_context);
+ } else if (surfaceClass == QSurface::Offscreen) {
+ m_isPBufferCurrent = true;
+ QGLXPbuffer *pbuffer = static_cast<QGLXPbuffer *>(surface);
+ return glXMakeContextCurrent(DISPLAY_FROM_XCB(m_screen), pbuffer->pbuffer(), pbuffer->pbuffer(), m_context);
+ }
+ return false;
}
void QGLXContext::doneCurrent()
{
- glXMakeCurrent(DISPLAY_FROM_XCB(m_screen), 0, 0);
+ if (m_isPBufferCurrent)
+ glXMakeContextCurrent(DISPLAY_FROM_XCB(m_screen), 0, 0, 0);
+ else
+ glXMakeCurrent(DISPLAY_FROM_XCB(m_screen), 0, 0);
+ m_isPBufferCurrent = false;
}
void QGLXContext::swapBuffers(QPlatformSurface *surface)
{
- GLXDrawable glxDrawable = static_cast<QXcbWindow *>(surface)->xcb_window();
+ GLXDrawable glxDrawable = 0;
+ if (surface->surface()->surfaceClass() == QSurface::Offscreen)
+ glxDrawable = static_cast<QGLXPbuffer *>(surface)->pbuffer();
+ else
+ glxDrawable = static_cast<QXcbWindow *>(surface)->xcb_window();
glXSwapBuffers(DISPLAY_FROM_XCB(m_screen), glxDrawable);
}
@@ -455,4 +405,36 @@ bool QGLXContext::isValid() const
return m_context != 0;
}
+
+QGLXPbuffer::QGLXPbuffer(QOffscreenSurface *offscreenSurface)
+ : QPlatformOffscreenSurface(offscreenSurface)
+ , m_format(offscreenSurface->requestedFormat())
+ , m_screen(static_cast<QXcbScreen *>(offscreenSurface->screen()->handle()))
+ , m_pbuffer(0)
+{
+ GLXFBConfig config = qglx_findConfig(DISPLAY_FROM_XCB(m_screen), m_screen->screenNumber(), m_format);
+
+ if (config) {
+ const int attributes[] = {
+ GLX_PBUFFER_WIDTH, offscreenSurface->size().width(),
+ GLX_PBUFFER_HEIGHT, offscreenSurface->size().height(),
+ GLX_LARGEST_PBUFFER, False,
+ GLX_PRESERVED_CONTENTS, False,
+ GLX_NONE
+ };
+
+ m_pbuffer = glXCreatePbuffer(DISPLAY_FROM_XCB(m_screen), config, attributes);
+
+ if (m_pbuffer)
+ qglx_surfaceFormatFromGLXFBConfig(&m_format, DISPLAY_FROM_XCB(m_screen), config);
+ }
+}
+
+QGLXPbuffer::~QGLXPbuffer()
+{
+ if (m_pbuffer)
+ glXDestroyPbuffer(DISPLAY_FROM_XCB(m_screen), m_pbuffer);
+}
+
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qglxintegration.h b/src/plugins/platforms/xcb/qglxintegration.h
index 78e9985334..7116b2389d 100644
--- a/src/plugins/platforms/xcb/qglxintegration.h
+++ b/src/plugins/platforms/xcb/qglxintegration.h
@@ -46,6 +46,7 @@
#include "qxcbscreen.h"
#include <qpa/qplatformopenglcontext.h>
+#include <qpa/qplatformoffscreensurface.h>
#include <QtGui/QSurfaceFormat>
#include <QtCore/QMutex>
@@ -54,23 +55,10 @@
QT_BEGIN_NAMESPACE
-class QOpenGLDefaultContextInfo
-{
- Q_DISABLE_COPY(QOpenGLDefaultContextInfo)
- QOpenGLDefaultContextInfo();
-public:
- static QOpenGLDefaultContextInfo *create(QXcbScreen *screen);
-
- const QByteArray vendor;
- const QByteArray renderer;
- QSurfaceFormat format;
-};
-
-
class QGLXContext : public QPlatformOpenGLContext
{
public:
- QGLXContext(QXcbScreen *xd, const QSurfaceFormat &format, QPlatformOpenGLContext *share, QOpenGLDefaultContextInfo *defaultContextInfo);
+ QGLXContext(QXcbScreen *xd, const QSurfaceFormat &format, QPlatformOpenGLContext *share);
~QGLXContext();
bool makeCurrent(QPlatformSurface *surface);
@@ -89,6 +77,25 @@ private:
GLXContext m_context;
GLXContext m_shareContext;
QSurfaceFormat m_format;
+ bool m_isPBufferCurrent;
+};
+
+
+class QGLXPbuffer : public QPlatformOffscreenSurface
+{
+public:
+ explicit QGLXPbuffer(QOffscreenSurface *offscreenSurface);
+ ~QGLXPbuffer();
+
+ QSurfaceFormat format() const { return m_format; }
+ bool isValid() const { return m_pbuffer != 0; }
+
+ GLXPbuffer pbuffer() const { return m_pbuffer; }
+
+private:
+ QSurfaceFormat m_format;
+ QXcbScreen *m_screen;
+ GLXPbuffer m_pbuffer;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 32de54562a..1504bd99d2 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -184,7 +184,7 @@ void QXcbConnection::updateScreens()
activeScreens << screen;
++screenNumber;
if (!primaryScreen && primary) {
- if (primary->output == XCB_NONE || outputs[i] == primary->output) {
+ if (m_primaryScreen == xcbScreenNumber && (primary->output == XCB_NONE || outputs[i] == primary->output)) {
primaryScreen = screen;
siblings.prepend(siblings.takeLast());
#ifdef Q_XCB_DEBUG
@@ -222,7 +222,6 @@ void QXcbConnection::updateScreens()
// Delete any existing screens which are not in activeScreens
for (int i = m_screens.count() - 1; i >= 0; --i) {
if (!activeScreens.contains(m_screens[i])) {
- ((QXcbIntegration*)QGuiApplicationPrivate::platformIntegration())->removeDefaultOpenGLContextInfo(m_screens[i]);
delete m_screens[i];
m_screens.removeAt(i);
}
@@ -1067,7 +1066,7 @@ void QXcbConnection::processXcbEvents()
while (it != m_peekFuncs.end()) {
// These callbacks return true if the event is what they were
// waiting for, remove them from the list in that case.
- if ((*it)(event))
+ if ((*it)(this, event))
it = m_peekFuncs.erase(it);
else
++it;
@@ -1087,7 +1086,7 @@ void QXcbConnection::processXcbEvents()
// Indicate with a null event that the event the callbacks are waiting for
// is not in the queue currently.
Q_FOREACH (PeekFunc f, m_peekFuncs)
- f(0);
+ f(this, 0);
m_peekFuncs.clear();
xcb_flush(xcb_connection());
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index b499f75b78..f69a8a9f35 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -364,7 +364,7 @@ public:
template<typename T>
inline xcb_generic_event_t *checkEvent(T &checker);
- typedef bool (*PeekFunc)(xcb_generic_event_t *);
+ typedef bool (*PeekFunc)(QXcbConnection *, xcb_generic_event_t *);
void addPeekFunc(PeekFunc f);
inline xcb_timestamp_t time() const { return m_time; }
diff --git a/src/plugins/platforms/xcb/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp
index b40fdb0e92..3fd2ca70e3 100644
--- a/src/plugins/platforms/xcb/qxcbcursor.cpp
+++ b/src/plugins/platforms/xcb/qxcbcursor.cpp
@@ -287,8 +287,14 @@ QXcbCursor::QXcbCursor(QXcbConnection *conn, QXcbScreen *screen)
QXcbCursor::~QXcbCursor()
{
+ xcb_connection_t *conn = xcb_connection();
if (!--cursorCount)
- xcb_close_font(xcb_connection(), cursorFont);
+ xcb_close_font(conn, cursorFont);
+
+ foreach (xcb_cursor_t cursor, m_bitmapCursorMap)
+ xcb_free_cursor(conn, cursor);
+ foreach (xcb_cursor_t cursor, m_shapeCursorMap)
+ xcb_free_cursor(conn, cursor);
}
#ifndef QT_NO_CURSOR
@@ -300,18 +306,20 @@ void QXcbCursor::changeCursor(QCursor *cursor, QWindow *widget)
else
// No X11 cursor control when there is no widget under the cursor
return;
-
- xcb_cursor_t c;
- if (cursor->shape() == Qt::BitmapCursor) {
- qint64 id = cursor->pixmap().cacheKey();
- if (!m_bitmapCursorMap.contains(id))
- m_bitmapCursorMap.insert(id, createBitmapCursor(cursor));
- c = m_bitmapCursorMap.value(id);
- } else {
- int id = cursor->shape();
- if (!m_shapeCursorMap.contains(id))
- m_shapeCursorMap.insert(id, createFontCursor(cursor->shape()));
- c = m_shapeCursorMap.value(id);
+
+ xcb_cursor_t c = XCB_CURSOR_NONE;
+ if (cursor) {
+ if (cursor->shape() == Qt::BitmapCursor) {
+ qint64 id = cursor->pixmap().cacheKey();
+ if (!m_bitmapCursorMap.contains(id))
+ m_bitmapCursorMap.insert(id, createBitmapCursor(cursor));
+ c = m_bitmapCursorMap.value(id);
+ } else {
+ int id = cursor->shape();
+ if (!m_shapeCursorMap.contains(id))
+ m_shapeCursorMap.insert(id, createFontCursor(cursor->shape()));
+ c = m_shapeCursorMap.value(id);
+ }
}
w->setCursor(c);
diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp
index 1840dd1ce5..f0cabea43d 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.cpp
+++ b/src/plugins/platforms/xcb/qxcbintegration.cpp
@@ -78,10 +78,12 @@
#elif defined(XCB_USE_EGL)
#include "qxcbeglsurface.h"
#include <QtPlatformSupport/private/qeglplatformcontext_p.h>
+#include <QtPlatformSupport/private/qeglpbuffer_p.h>
#endif
#include <QtGui/QOpenGLContext>
#include <QtGui/QScreen>
+#include <QtGui/QOffscreenSurface>
#ifndef QT_NO_ACCESSIBILITY
#include <qpa/qplatformaccessibility.h>
#ifndef QT_NO_ACCESSIBILITY_ATSPI_BRIDGE
@@ -121,9 +123,6 @@ QXcbIntegration::QXcbIntegration(const QStringList &parameters)
QXcbIntegration::~QXcbIntegration()
{
-#if !defined(QT_NO_OPENGL) && defined(XCB_USE_GLX)
- qDeleteAll(m_defaultContextInfos);
-#endif
qDeleteAll(m_connections);
}
@@ -168,7 +167,10 @@ public:
EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface)
{
- return static_cast<QXcbWindow *>(surface)->eglSurface()->surface();
+ if (surface->surface()->surfaceClass() == QSurface::Window)
+ return static_cast<QXcbWindow *>(surface)->eglSurface()->surface();
+ else
+ return static_cast<QEGLPbuffer *>(surface)->pbuffer();
}
private:
@@ -181,14 +183,7 @@ QPlatformOpenGLContext *QXcbIntegration::createPlatformOpenGLContext(QOpenGLCont
{
QXcbScreen *screen = static_cast<QXcbScreen *>(context->screen()->handle());
#if defined(XCB_USE_GLX)
- QOpenGLDefaultContextInfo *defaultContextInfo;
- if (m_defaultContextInfos.contains(screen)) {
- defaultContextInfo = m_defaultContextInfos.value(screen);
- } else {
- defaultContextInfo = QOpenGLDefaultContextInfo::create(screen);
- m_defaultContextInfos.insert(screen, defaultContextInfo);
- }
- return new QGLXContext(screen, context->format(), context->shareHandle(), defaultContextInfo);
+ return new QGLXContext(screen, context->format(), context->shareHandle());
#elif defined(XCB_USE_EGL)
return new QEGLXcbPlatformContext(context->format(), context->shareHandle(),
screen->connection()->egl_display(), screen->connection());
@@ -205,6 +200,20 @@ QPlatformBackingStore *QXcbIntegration::createPlatformBackingStore(QWindow *wind
return new QXcbBackingStore(window);
}
+QPlatformOffscreenSurface *QXcbIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const
+{
+#if defined(XCB_USE_GLX)
+ return new QGLXPbuffer(surface);
+#elif defined(XCB_USE_EGL)
+ QXcbScreen *screen = static_cast<QXcbScreen *>(surface->screen()->handle());
+ return new QEGLPbuffer(screen->connection()->egl_display(), surface->requestedFormat(), surface);
+#else
+ Q_UNUSED(surface);
+ qWarning("QXcbIntegration: Cannot create platform offscreen surface, neither GLX nor EGL are enabled");
+ return 0;
+#endif
+}
+
bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const
{
switch (cap) {
@@ -219,6 +228,7 @@ bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const
case ThreadedOpenGL: return m_connections.at(0)->supportsThreadedRendering();
case WindowMasks: return true;
case MultipleWindows: return true;
+ case ForeignWindows: return true;
default: return QPlatformIntegration::hasCapability(cap);
}
}
@@ -293,21 +303,4 @@ QPlatformTheme *QXcbIntegration::createPlatformTheme(const QString &name) const
return QGenericUnixTheme::createUnixTheme(name);
}
-/*!
- Called by QXcbConnection prior to a QQnxScreen being deleted.
-
- Destroys and cleans up any default OpenGL context info for this screen.
-*/
-void QXcbIntegration::removeDefaultOpenGLContextInfo(QXcbScreen *screen)
-{
-#if !defined(QT_NO_OPENGL) && defined(XCB_USE_GLX)
- if (!m_defaultContextInfos.contains(screen))
- return;
- QOpenGLDefaultContextInfo* info = m_defaultContextInfos.take(screen);
- delete info;
-#else
- Q_UNUSED(screen);
-#endif
-}
-
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h
index cd6c2fd73c..6db9d82cca 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.h
+++ b/src/plugins/platforms/xcb/qxcbintegration.h
@@ -52,10 +52,6 @@ class QAbstractEventDispatcher;
class QXcbNativeInterface;
class QXcbScreen;
-#if !defined(QT_NO_OPENGL) && defined(XCB_USE_GLX)
-class QOpenGLDefaultContextInfo;
-#endif
-
class QXcbIntegration : public QPlatformIntegration
{
public:
@@ -68,6 +64,8 @@ public:
#endif
QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const;
+ QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const;
+
bool hasCapability(Capability cap) const;
QAbstractEventDispatcher *guiThreadEventDispatcher() const;
@@ -97,8 +95,6 @@ public:
QStringList themeNames() const;
QPlatformTheme *createPlatformTheme(const QString &name) const;
- void removeDefaultOpenGLContextInfo(QXcbScreen *screen);
-
private:
QList<QXcbConnection *> m_connections;
@@ -108,10 +104,6 @@ private:
QScopedPointer<QPlatformInputContext> m_inputContext;
QAbstractEventDispatcher *m_eventDispatcher;
-#if !defined(QT_NO_OPENGL) && defined(XCB_USE_GLX)
- mutable QHash<QXcbScreen *, QOpenGLDefaultContextInfo *> m_defaultContextInfos;
-#endif
-
#ifndef QT_NO_ACCESSIBILITY
QScopedPointer<QPlatformAccessibility> m_accessibility;
#endif
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
index bda54b4682..4ac60f6077 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
@@ -1081,6 +1081,7 @@ void QXcbKeyboard::handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycod
int qtcode = 0;
int count = chars.count();
QString string = translateKeySym(sym, state, qtcode, modifiers, chars, count);
+ string.truncate(count);
bool isAutoRepeat = false;
@@ -1102,7 +1103,7 @@ void QXcbKeyboard::handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycod
bool filtered = false;
if (inputContext) {
- QKeyEvent event(type, qtcode, modifiers, code, sym, state, string.left(count), isAutoRepeat, count);
+ QKeyEvent event(type, qtcode, modifiers, code, sym, state, string, isAutoRepeat, count);
event.setTimestamp(time);
filtered = inputContext->filterEvent(&event);
}
@@ -1114,7 +1115,7 @@ void QXcbKeyboard::handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycod
QWindowSystemInterface::handleContextMenuEvent(window, false, pos, globalPos, modifiers);
}
QWindowSystemInterface::handleExtendedKeyEvent(window, time, type, qtcode, modifiers,
- code, sym, state, string.left(count), isAutoRepeat);
+ code, sym, state, string, isAutoRepeat);
}
if (isAutoRepeat && type == QEvent::KeyRelease) {
@@ -1130,13 +1131,13 @@ void QXcbKeyboard::handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycod
}
if (!filtered && inputContext) {
- QKeyEvent event(QEvent::KeyPress, qtcode, modifiers, code, sym, state, string.left(count), isAutoRepeat, count);
+ QKeyEvent event(QEvent::KeyPress, qtcode, modifiers, code, sym, state, string, isAutoRepeat, count);
event.setTimestamp(time);
filtered = inputContext->filterEvent(&event);
}
if (!filtered)
QWindowSystemInterface::handleExtendedKeyEvent(window, time, QEvent::KeyPress, qtcode, modifiers,
- code, sym, state, string.left(count), isAutoRepeat);
+ code, sym, state, string, isAutoRepeat);
}
}
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index c0ddf5c0ae..5af6a9ec9d 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -113,11 +113,45 @@
#endif
#define XCOORD_MAX 16383
+enum {
+ defaultWindowWidth = 160,
+ defaultWindowHeight = 160
+};
//#ifdef NET_WM_STATE_DEBUG
QT_BEGIN_NAMESPACE
+#undef FocusIn
+
+enum QX11EmbedFocusInDetail {
+ XEMBED_FOCUS_CURRENT = 0,
+ XEMBED_FOCUS_FIRST = 1,
+ XEMBED_FOCUS_LAST = 2
+};
+
+enum QX11EmbedInfoFlags {
+ XEMBED_MAPPED = (1 << 0),
+};
+
+enum QX11EmbedMessageType {
+ XEMBED_EMBEDDED_NOTIFY = 0,
+ XEMBED_WINDOW_ACTIVATE = 1,
+ XEMBED_WINDOW_DEACTIVATE = 2,
+ XEMBED_REQUEST_FOCUS = 3,
+ XEMBED_FOCUS_IN = 4,
+ XEMBED_FOCUS_OUT = 5,
+ XEMBED_FOCUS_NEXT = 6,
+ XEMBED_FOCUS_PREV = 7,
+ XEMBED_MODALITY_ON = 10,
+ XEMBED_MODALITY_OFF = 11,
+ XEMBED_REGISTER_ACCELERATOR = 12,
+ XEMBED_UNREGISTER_ACCELERATOR = 13,
+ XEMBED_ACTIVATE_ACCELERATOR = 14
+};
+
+static unsigned int XEMBED_VERSION = 0;
+
// Returns true if we should set WM_TRANSIENT_FOR on \a w
static inline bool isTransient(const QWindow *w)
{
@@ -152,7 +186,9 @@ QXcbWindow::QXcbWindow(QWindow *window)
, m_gravity(XCB_GRAVITY_STATIC)
, m_mapped(false)
, m_transparent(false)
+ , m_usingSyncProtocol(false)
, m_deferredActivation(false)
+ , m_embedded(false)
, m_netWmUserTimeWindow(XCB_NONE)
, m_dirtyFrameMargins(false)
#if defined(XCB_USE_EGL)
@@ -164,7 +200,10 @@ QXcbWindow::QXcbWindow(QWindow *window)
setConnection(m_screen->connection());
- create();
+ if (window->type() != Qt::ForeignWindow)
+ create();
+ else
+ m_window = window->winId();
}
void QXcbWindow::create()
@@ -219,12 +258,22 @@ void QXcbWindow::create()
QRect rect = window()->geometry();
QPlatformWindow::setGeometry(rect);
- rect.setWidth(qBound(1, rect.width(), XCOORD_MAX));
- rect.setHeight(qBound(1, rect.height(), XCOORD_MAX));
+ QSize minimumSize = window()->minimumSize();
+ if (rect.width() > 0 || rect.height() > 0) {
+ rect.setWidth(qBound(1, rect.width(), XCOORD_MAX));
+ rect.setHeight(qBound(1, rect.height(), XCOORD_MAX));
+ } else if (minimumSize.width() > 0 || minimumSize.height() > 0) {
+ rect.setSize(minimumSize);
+ } else {
+ rect.setWidth(defaultWindowWidth);
+ rect.setHeight(defaultWindowHeight);
+ }
xcb_window_t xcb_parent_id = m_screen->root();
- if (parent())
+ if (parent()) {
xcb_parent_id = static_cast<QXcbWindow *>(parent())->xcb_window();
+ m_embedded = parent()->window()->type() == Qt::ForeignWindow;
+ }
m_format = window()->requestedFormat();
@@ -306,7 +355,9 @@ void QXcbWindow::create()
properties[propertyCount++] = atom(QXcbAtom::WM_TAKE_FOCUS);
properties[propertyCount++] = atom(QXcbAtom::_NET_WM_PING);
- if (m_screen->syncRequestSupported())
+ m_usingSyncProtocol = m_screen->syncRequestSupported() && window()->surfaceType() != QSurface::OpenGLSurface;
+
+ if (m_usingSyncProtocol)
properties[propertyCount++] = atom(QXcbAtom::_NET_WM_SYNC_REQUEST);
if (window()->flags() & Qt::WindowContextHelpButtonHint)
@@ -323,7 +374,7 @@ void QXcbWindow::create()
m_syncValue.hi = 0;
m_syncValue.lo = 0;
- if (m_screen->syncRequestSupported()) {
+ if (m_usingSyncProtocol) {
m_syncCounter = xcb_generate_id(xcb_connection());
Q_XCB_CALL(xcb_sync_create_counter(xcb_connection(), m_syncCounter, m_syncValue));
@@ -356,6 +407,14 @@ void QXcbWindow::create()
atom(QXcbAtom::WM_CLIENT_LEADER), XCB_ATOM_WINDOW, 32,
1, &leader));
+ /* Add XEMBED info; this operation doesn't initiate the embedding. */
+ long data[] = { XEMBED_VERSION, XEMBED_MAPPED };
+ Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
+ atom(QXcbAtom::_XEMBED_INFO),
+ atom(QXcbAtom::_XEMBED_INFO),
+ 32, 2, (void *)data));
+
+
#ifdef XCB_USE_XINPUT2_MAEMO
if (connection()->isUsingXInput2Maemo()) {
XIEventMask xieventmask;
@@ -398,7 +457,8 @@ void QXcbWindow::create()
QXcbWindow::~QXcbWindow()
{
- destroy();
+ if (window()->type() != Qt::ForeignWindow)
+ destroy();
}
void QXcbWindow::destroy()
@@ -406,7 +466,7 @@ void QXcbWindow::destroy()
if (connection()->focusWindow() == this)
connection()->setFocusWindow(0);
- if (m_syncCounter && m_screen->syncRequestSupported())
+ if (m_syncCounter && m_usingSyncProtocol)
Q_XCB_CALL(xcb_sync_destroy_counter(xcb_connection(), m_syncCounter));
if (m_window) {
if (m_netWmUserTimeWindow) {
@@ -436,15 +496,23 @@ void QXcbWindow::setGeometry(const QRect &rect)
propagateSizeHints();
const QRect wmGeometry = windowToWmGeometry(rect);
- const quint32 mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
- const qint32 values[] = {
- qBound<qint32>(-XCOORD_MAX, wmGeometry.x(), XCOORD_MAX),
- qBound<qint32>(-XCOORD_MAX, wmGeometry.y(), XCOORD_MAX),
- qBound<qint32>(1, wmGeometry.width(), XCOORD_MAX),
- qBound<qint32>(1, wmGeometry.height(), XCOORD_MAX),
- };
-
- Q_XCB_CALL(xcb_configure_window(xcb_connection(), m_window, mask, reinterpret_cast<const quint32*>(values)));
+ if (qt_window_private(window())->positionAutomatic) {
+ const quint32 mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
+ const qint32 values[] = {
+ qBound<qint32>(1, wmGeometry.width(), XCOORD_MAX),
+ qBound<qint32>(1, wmGeometry.height(), XCOORD_MAX),
+ };
+ Q_XCB_CALL(xcb_configure_window(xcb_connection(), m_window, mask, reinterpret_cast<const quint32*>(values)));
+ } else {
+ const quint32 mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
+ const qint32 values[] = {
+ qBound<qint32>(-XCOORD_MAX, wmGeometry.x(), XCOORD_MAX),
+ qBound<qint32>(-XCOORD_MAX, wmGeometry.y(), XCOORD_MAX),
+ qBound<qint32>(1, wmGeometry.width(), XCOORD_MAX),
+ qBound<qint32>(1, wmGeometry.height(), XCOORD_MAX),
+ };
+ Q_XCB_CALL(xcb_configure_window(xcb_connection(), m_window, mask, reinterpret_cast<const quint32*>(values)));
+ }
xcb_flush(xcb_connection());
}
@@ -554,15 +622,17 @@ void QXcbWindow::show()
propagateSizeHints();
// update WM_TRANSIENT_FOR
- if (isTransient(window())) {
+ const QWindow *tp = window()->transientParent();
+ if (isTransient(window()) || tp != 0) {
xcb_window_t transientXcbParent = 0;
- if (const QWindow *tp = window()->transientParent())
+ if (tp)
transientXcbParent = static_cast<const QXcbWindow *>(tp->handle())->winId();
// Default to client leader if there is no transient parent, else modal dialogs can
// be hidden by their parents.
if (!transientXcbParent)
transientXcbParent = static_cast<QXcbScreen *>(screen())->clientLeader();
if (transientXcbParent) { // ICCCM 4.1.2.6
+ m_gravity = XCB_GRAVITY_CENTER;
Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32,
1, &transientXcbParent));
@@ -1119,7 +1189,15 @@ void QXcbWindow::setParent(const QPlatformWindow *parent)
{
QPoint topLeft = geometry().topLeft();
- xcb_window_t xcb_parent_id = parent ? static_cast<const QXcbWindow *>(parent)->xcb_window() : m_screen->root();
+ xcb_window_t xcb_parent_id;
+ if (parent) {
+ const QXcbWindow *qXcbParent = static_cast<const QXcbWindow *>(parent);
+ xcb_parent_id = qXcbParent->xcb_window();
+ m_embedded = qXcbParent->window()->type() == Qt::ForeignWindow;
+ } else {
+ xcb_parent_id = m_screen->root();
+ m_embedded = false;
+ }
Q_XCB_CALL(xcb_reparent_window(xcb_connection(), xcb_window(), xcb_parent_id, topLeft.x(), topLeft.y()));
}
@@ -1221,8 +1299,10 @@ void QXcbWindow::propagateSizeHints()
QWindow *win = window();
- xcb_size_hints_set_position(&hints, true, rect.x(), rect.y());
- xcb_size_hints_set_size(&hints, true, rect.width(), rect.height());
+ if (!qt_window_private(win)->positionAutomatic)
+ xcb_size_hints_set_position(&hints, true, rect.x(), rect.y());
+ if (rect.width() < QWINDOWSIZE_MAX || rect.height() < QWINDOWSIZE_MAX)
+ xcb_size_hints_set_size(&hints, true, rect.width(), rect.height());
xcb_size_hints_set_win_gravity(&hints, m_gravity);
QSize minimumSize = win->minimumSize();
@@ -1248,6 +1328,13 @@ void QXcbWindow::propagateSizeHints()
void QXcbWindow::requestActivateWindow()
{
+ /* Never activate embedded windows; doing that would prevent the container
+ * to re-gain the keyboard focus later. */
+ if (m_embedded) {
+ QPlatformWindow::requestActivateWindow();
+ return;
+ }
+
if (!m_mapped) {
m_deferredActivation = true;
return;
@@ -1411,7 +1498,8 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even
} else if (event->type == atom(QXcbAtom::XdndDrop)) {
connection()->drag()->handleDrop(window(), event);
#endif
- } else if (event->type == atom(QXcbAtom::_XEMBED)) { // QSystemTrayIcon
+ } else if (event->type == atom(QXcbAtom::_XEMBED)) {
+ handleXEmbedMessage(event);
} else {
qWarning() << "QXcbWindow: Unhandled client message:" << connection()->atomName(event->type);
}
@@ -1453,6 +1541,53 @@ bool QXcbWindow::isExposed() const
return m_mapped;
}
+bool QXcbWindow::isEmbedded(const QPlatformWindow *parentWindow) const
+{
+ if (!m_embedded)
+ return false;
+
+ return parentWindow ? (parentWindow == parent()) : true;
+}
+
+QPoint QXcbWindow::mapToGlobal(const QPoint &pos) const
+{
+ if (!m_embedded)
+ return pos;
+
+ QPoint ret;
+ xcb_translate_coordinates_cookie_t cookie =
+ xcb_translate_coordinates(xcb_connection(), xcb_window(), m_screen->root(),
+ pos.x(), pos.y());
+ xcb_translate_coordinates_reply_t *reply =
+ xcb_translate_coordinates_reply(xcb_connection(), cookie, NULL);
+ if (reply) {
+ ret.setX(reply->dst_x);
+ ret.setY(reply->dst_y);
+ free(reply);
+ }
+
+ return ret;
+}
+
+QPoint QXcbWindow::mapFromGlobal(const QPoint &pos) const
+{
+ if (!m_embedded)
+ return pos;
+ QPoint ret;
+ xcb_translate_coordinates_cookie_t cookie =
+ xcb_translate_coordinates(xcb_connection(), m_screen->root(), xcb_window(),
+ pos.x(), pos.y());
+ xcb_translate_coordinates_reply_t *reply =
+ xcb_translate_coordinates_reply(xcb_connection(), cookie, NULL);
+ if (reply) {
+ ret.setX(reply->dst_x);
+ ret.setY(reply->dst_y);
+ free(reply);
+ }
+
+ return ret;
+}
+
void QXcbWindow::handleMapNotifyEvent(const xcb_map_notify_event_t *event)
{
if (event->window == m_window) {
@@ -1483,6 +1618,15 @@ void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event)
updateNetWmUserTime(event->time);
+ if (m_embedded) {
+ if (window() != QGuiApplication::focusWindow()) {
+ const QXcbWindow *container = static_cast<const QXcbWindow *>(parent());
+ Q_ASSERT(container != 0);
+
+ sendXEmbedMessage(container->xcb_window(), XEMBED_REQUEST_FOCUS);
+ }
+ }
+
QPoint local(event->event_x, event->event_y);
QPoint global(event->root_x, event->root_y);
@@ -1638,6 +1782,7 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev
QWindowSystemInterface::handleWindowStateChanged(window(), newState);
m_lastWindowStateEvent = newState;
}
+ return;
}
}
@@ -1649,7 +1794,7 @@ void QXcbWindow::handleFocusInEvent(const xcb_focus_in_event_t *)
QWindowSystemInterface::handleWindowActivated(w);
}
-static bool focusInPeeker(xcb_generic_event_t *event)
+static bool focusInPeeker(QXcbConnection *connection, xcb_generic_event_t *event)
{
if (!event) {
// FocusIn event is not in the queue, proceed with FocusOut normally.
@@ -1657,7 +1802,18 @@ static bool focusInPeeker(xcb_generic_event_t *event)
return true;
}
uint response_type = event->response_type & ~0x80;
- return response_type == XCB_FOCUS_IN;
+ if (response_type == XCB_FOCUS_IN)
+ return true;
+
+ /* We are also interested in XEMBED_FOCUS_IN events */
+ if (response_type == XCB_CLIENT_MESSAGE) {
+ xcb_client_message_event_t *cme = (xcb_client_message_event_t *)event;
+ if (cme->type == connection->atom(QXcbAtom::_XEMBED)
+ && cme->data.data32[1] == XEMBED_FOCUS_IN)
+ return true;
+ }
+
+ return false;
}
void QXcbWindow::handleFocusOutEvent(const xcb_focus_out_event_t *)
@@ -1671,7 +1827,7 @@ void QXcbWindow::handleFocusOutEvent(const xcb_focus_out_event_t *)
void QXcbWindow::updateSyncRequestCounter()
{
- if (m_screen->syncRequestSupported() && (m_syncValue.lo != 0 || m_syncValue.hi != 0)) {
+ if (m_usingSyncProtocol && (m_syncValue.lo != 0 || m_syncValue.hi != 0)) {
Q_XCB_CALL(xcb_sync_set_counter(xcb_connection(), m_syncCounter, m_syncValue));
xcb_flush(xcb_connection());
connection()->sync();
@@ -1721,6 +1877,35 @@ void QXcbWindow::setCursor(xcb_cursor_t cursor)
xcb_flush(xcb_connection());
}
+void QXcbWindow::windowEvent(QEvent *event)
+{
+ switch (event->type()) {
+ case QEvent::FocusIn:
+ if (m_embedded && !event->spontaneous()) {
+ QFocusEvent *focusEvent = static_cast<QFocusEvent *>(event);
+ switch (focusEvent->reason()) {
+ case Qt::TabFocusReason:
+ case Qt::BacktabFocusReason:
+ {
+ const QXcbWindow *container =
+ static_cast<const QXcbWindow *>(parent());
+ sendXEmbedMessage(container->xcb_window(),
+ focusEvent->reason() == Qt::TabFocusReason ?
+ XEMBED_FOCUS_NEXT : XEMBED_FOCUS_PREV);
+ event->accept();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ QPlatformWindow::windowEvent(event);
+}
+
bool QXcbWindow::startSystemResize(const QPoint &pos, Qt::Corner corner)
{
const xcb_atom_t moveResize = connection()->atom(QXcbAtom::_NET_WM_MOVERESIZE);
@@ -1749,6 +1934,71 @@ bool QXcbWindow::startSystemResize(const QPoint &pos, Qt::Corner corner)
return true;
}
+// Sends an XEmbed message.
+void QXcbWindow::sendXEmbedMessage(xcb_window_t window, long message,
+ long detail, long data1, long data2)
+{
+ xcb_client_message_event_t event;
+
+ event.response_type = XCB_CLIENT_MESSAGE;
+ event.format = 32;
+ event.window = window;
+ event.type = atom(QXcbAtom::_XEMBED);
+ event.data.data32[0] = connection()->time();
+ event.data.data32[1] = message;
+ event.data.data32[2] = detail;
+ event.data.data32[3] = data1;
+ event.data.data32[4] = data2;
+ Q_XCB_CALL(xcb_send_event(xcb_connection(), false, window,
+ XCB_EVENT_MASK_NO_EVENT, (const char *)&event));
+}
+
+static bool activeWindowChangeQueued(const QWindow *window)
+{
+ /* Check from window system event queue if the next queued activation
+ * targets a window other than @window.
+ */
+ QWindowSystemInterfacePrivate::ActivatedWindowEvent *systemEvent =
+ static_cast<QWindowSystemInterfacePrivate::ActivatedWindowEvent *>
+ (QWindowSystemInterfacePrivate::peekWindowSystemEvent(QWindowSystemInterfacePrivate::ActivatedWindow));
+ return systemEvent && systemEvent->activated != window;
+}
+
+void QXcbWindow::handleXEmbedMessage(const xcb_client_message_event_t *event)
+{
+ connection()->setTime(event->data.data32[0]);
+ switch (event->data.data32[1]) {
+ case XEMBED_WINDOW_ACTIVATE:
+ case XEMBED_WINDOW_DEACTIVATE:
+ case XEMBED_EMBEDDED_NOTIFY:
+ break;
+ case XEMBED_FOCUS_IN:
+ Qt::FocusReason reason;
+ switch (event->data.data32[2]) {
+ case XEMBED_FOCUS_FIRST:
+ reason = Qt::TabFocusReason;
+ break;
+ case XEMBED_FOCUS_LAST:
+ reason = Qt::BacktabFocusReason;
+ break;
+ case XEMBED_FOCUS_CURRENT:
+ default:
+ reason = Qt::OtherFocusReason;
+ break;
+ }
+ connection()->setFocusWindow(static_cast<QXcbWindow*>(window()->handle()));
+ QWindowSystemInterface::handleWindowActivated(window(), reason);
+ break;
+ case XEMBED_FOCUS_OUT:
+ if (window() == QGuiApplication::focusWindow()
+ && !activeWindowChangeQueued(window())) {
+ connection()->setFocusWindow(0);
+ QWindowSystemInterface::handleWindowActivated(0);
+ }
+ break;
+ }
+}
+
#if !defined(QT_NO_SHAPE)
static inline xcb_rectangle_t qRectToXCBRectangle(const QRect &r)
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
index 3b5404684f..f4bd2d96ff 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.h
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
@@ -87,6 +87,9 @@ public:
void setParent(const QPlatformWindow *window);
bool isExposed() const;
+ bool isEmbedded(const QPlatformWindow *parentWindow) const;
+ QPoint mapToGlobal(const QPoint &pos) const;
+ QPoint mapFromGlobal(const QPoint &pos) const;
void setWindowTitle(const QString &title);
void setWindowIcon(const QIcon &icon);
@@ -107,6 +110,8 @@ public:
QSurfaceFormat format() const;
+ void windowEvent(QEvent *event);
+
bool startSystemResize(const QPoint &pos, Qt::Corner corner);
void setOpacity(qreal level);
@@ -158,6 +163,9 @@ private:
void updateDoesNotAcceptFocus(bool doesNotAcceptFocus);
QRect windowToWmGeometry(QRect r) const;
+ void sendXEmbedMessage(xcb_window_t window, long message,
+ long detail = 0, long data1 = 0, long data2 = 0);
+ void handleXEmbedMessage(const xcb_client_message_event_t *event);
void create();
void destroy();
@@ -181,9 +189,11 @@ private:
bool m_mapped;
bool m_transparent;
+ bool m_usingSyncProtocol;
bool m_deferredActivation;
bool m_deferredExpose;
bool m_configureNotifyPending;
+ bool m_embedded;
xcb_window_t m_netWmUserTimeWindow;
QSurfaceFormat m_format;