diff options
Diffstat (limited to 'src/plugins')
199 files changed, 10504 insertions, 4432 deletions
diff --git a/src/plugins/accessible/widgets/itemviews.cpp b/src/plugins/accessible/widgets/itemviews.cpp index b477a6acb7..7cd47f3fec 100644 --- a/src/plugins/accessible/widgets/itemviews.cpp +++ b/src/plugins/accessible/widgets/itemviews.cpp @@ -1057,9 +1057,10 @@ QRect QAccessibleTableCell::rect() const QRect r; r = view->visualRect(m_index); - if (!r.isNull()) + if (!r.isNull()) { r.translate(view->viewport()->mapTo(view, QPoint(0,0))); r.translate(view->mapToGlobal(QPoint(0, 0))); + } return r; } diff --git a/src/plugins/bearer/connman/qconnmanservice_linux_p.h b/src/plugins/bearer/connman/qconnmanservice_linux_p.h index dd3f847cfd..6996fef5a7 100644 --- a/src/plugins/bearer/connman/qconnmanservice_linux_p.h +++ b/src/plugins/bearer/connman/qconnmanservice_linux_p.h @@ -71,22 +71,22 @@ #ifndef __CONNMAN_DBUS_H -#define CONNMAN_SERVICE "net.connman" -#define CONNMAN_PATH "/net/connman" - -#define CONNMAN_DEBUG_INTERFACE CONNMAN_SERVICE ".Debug" -#define CONNMAN_ERROR_INTERFACE CONNMAN_SERVICE ".Error" -#define CONNMAN_AGENT_INTERFACE CONNMAN_SERVICE ".Agent" -#define CONNMAN_COUNTER_INTERFACE CONNMAN_SERVICE ".Counter" - -#define CONNMAN_MANAGER_INTERFACE CONNMAN_SERVICE ".Manager" -#define CONNMAN_MANAGER_PATH "/" - -#define CONNMAN_TASK_INTERFACE CONNMAN_SERVICE ".Task" -#define CONNMAN_PROFILE_INTERFACE CONNMAN_SERVICE ".Profile" -#define CONNMAN_SERVICE_INTERFACE CONNMAN_SERVICE ".Service" -#define CONNMAN_PROVIDER_INTERFACE CONNMAN_SERVICE ".Provider" -#define CONNMAN_TECHNOLOGY_INTERFACE CONNMAN_SERVICE ".Technology" +#define CONNMAN_SERVICE "net.connman" +#define CONNMAN_PATH "/net/connman" + +#define CONNMAN_DEBUG_INTERFACE CONNMAN_SERVICE ".Debug" +#define CONNMAN_ERROR_INTERFACE CONNMAN_SERVICE ".Error" +#define CONNMAN_AGENT_INTERFACE CONNMAN_SERVICE ".Agent" +#define CONNMAN_COUNTER_INTERFACE CONNMAN_SERVICE ".Counter" + +#define CONNMAN_MANAGER_INTERFACE CONNMAN_SERVICE ".Manager" +#define CONNMAN_MANAGER_PATH "/" + +#define CONNMAN_TASK_INTERFACE CONNMAN_SERVICE ".Task" +#define CONNMAN_PROFILE_INTERFACE CONNMAN_SERVICE ".Profile" +#define CONNMAN_SERVICE_INTERFACE CONNMAN_SERVICE ".Service" +#define CONNMAN_PROVIDER_INTERFACE CONNMAN_SERVICE ".Provider" +#define CONNMAN_TECHNOLOGY_INTERFACE CONNMAN_SERVICE ".Technology" #endif QT_BEGIN_NAMESPACE diff --git a/src/plugins/bearer/connman/qofonoservice_linux_p.h b/src/plugins/bearer/connman/qofonoservice_linux_p.h index 25bffacceb..4802e0dc70 100644 --- a/src/plugins/bearer/connman/qofonoservice_linux_p.h +++ b/src/plugins/bearer/connman/qofonoservice_linux_p.h @@ -68,7 +68,7 @@ #ifndef QT_NO_BEARERMANAGEMENT #ifndef QT_NO_DBUS -#define OFONO_SERVICE "org.ofono" +#define OFONO_SERVICE "org.ofono" #define OFONO_MANAGER_INTERFACE "org.ofono.Manager" #define OFONO_MANAGER_PATH "/" #define OFONO_MODEM_INTERFACE "org.ofono.Modem" diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h index 7febe27ad2..74a25c1370 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h @@ -99,28 +99,28 @@ typedef enum NM_ACTIVE_CONNECTION_STATE_ACTIVATED } NMActiveConnectionState; -#define NM_DBUS_SERVICE "org.freedesktop.NetworkManager" +#define NM_DBUS_SERVICE "org.freedesktop.NetworkManager" -#define NM_DBUS_PATH "/org/freedesktop/NetworkManager" -#define NM_DBUS_INTERFACE "org.freedesktop.NetworkManager" -#define NM_DBUS_INTERFACE_DEVICE NM_DBUS_INTERFACE ".Device" +#define NM_DBUS_PATH "/org/freedesktop/NetworkManager" +#define NM_DBUS_INTERFACE "org.freedesktop.NetworkManager" +#define NM_DBUS_INTERFACE_DEVICE NM_DBUS_INTERFACE ".Device" #define NM_DBUS_INTERFACE_DEVICE_WIRED NM_DBUS_INTERFACE_DEVICE ".Wired" #define NM_DBUS_INTERFACE_DEVICE_WIRELESS NM_DBUS_INTERFACE_DEVICE ".Wireless" #define NM_DBUS_PATH_ACCESS_POINT NM_DBUS_PATH "/AccessPoint" #define NM_DBUS_INTERFACE_ACCESS_POINT NM_DBUS_INTERFACE ".AccessPoint" -#define NM_DBUS_PATH_SETTINGS "/org/freedesktop/NetworkManagerSettings" +#define NM_DBUS_PATH_SETTINGS "/org/freedesktop/NetworkManagerSettings" -#define NM_DBUS_IFACE_SETTINGS_CONNECTION "org.freedesktop.NetworkManagerSettings.Connection" -#define NM_DBUS_IFACE_SETTINGS "org.freedesktop.NetworkManagerSettings" +#define NM_DBUS_IFACE_SETTINGS_CONNECTION "org.freedesktop.NetworkManagerSettings.Connection" +#define NM_DBUS_IFACE_SETTINGS "org.freedesktop.NetworkManagerSettings" #define NM_DBUS_INTERFACE_ACTIVE_CONNECTION NM_DBUS_INTERFACE ".Connection.Active" #define NM_DBUS_INTERFACE_IP4_CONFIG NM_DBUS_INTERFACE ".IP4Config" -#define NM_DBUS_SERVICE_USER_SETTINGS "org.freedesktop.NetworkManagerUserSettings" -#define NM_DBUS_SERVICE_SYSTEM_SETTINGS "org.freedesktop.NetworkManagerSystemSettings" +#define NM_DBUS_SERVICE_USER_SETTINGS "org.freedesktop.NetworkManagerUserSettings" +#define NM_DBUS_SERVICE_SYSTEM_SETTINGS "org.freedesktop.NetworkManagerSystemSettings" -#define NM_802_11_AP_FLAGS_NONE 0x00000000 -#define NM_802_11_AP_FLAGS_PRIVACY 0x00000001 +#define NM_802_11_AP_FLAGS_NONE 0x00000000 +#define NM_802_11_AP_FLAGS_PRIVACY 0x00000001 #endif QT_BEGIN_NAMESPACE @@ -433,7 +433,7 @@ class QNetworkManagerIp4Config : public QObject public: explicit QNetworkManagerIp4Config(const QString &dbusPathName, QObject *parent = 0); - ~QNetworkManagerIp4Config(); + ~QNetworkManagerIp4Config(); QStringList domains() const; bool isValid(); diff --git a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp index 11545b16c3..692372c3a9 100644 --- a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp +++ b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp @@ -58,6 +58,7 @@ #include <locale.h> // LC_CTYPE #include <string.h> // strchr, strncmp, etc. #include <strings.h> // strncasecmp +#include <clocale> // LC_CTYPE TableGenerator::TableGenerator() : m_state(NoErrors), m_systemComposeDir(QString()) diff --git a/src/plugins/platforms/android/src/android.json b/src/plugins/platforms/android/android.json index 6843bd3301..6843bd3301 100644 --- a/src/plugins/platforms/android/src/android.json +++ b/src/plugins/platforms/android/android.json diff --git a/src/plugins/platforms/android/android.pro b/src/plugins/platforms/android/android.pro index aa5ab4ddbd..4d873dd986 100644 --- a/src/plugins/platforms/android/android.pro +++ b/src/plugins/platforms/android/android.pro @@ -1,3 +1,80 @@ -TEMPLATE = subdirs +TARGET = qtforandroid -SUBDIRS += raster opengl +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 +} + +QT += core-private gui-private platformsupport-private + +CONFIG += qpa/genericunixfontdatabase + +OTHER_FILES += $$PWD/android.json + +INCLUDEPATH += $$PWD + +SOURCES += $$PWD/androidplatformplugin.cpp \ + $$PWD/androidjnimain.cpp \ + $$PWD/androidjniaccessibility.cpp \ + $$PWD/androidjniinput.cpp \ + $$PWD/androidjnimenu.cpp \ + $$PWD/androidjniclipboard.cpp \ + $$PWD/qandroidplatformintegration.cpp \ + $$PWD/qandroidplatformservices.cpp \ + $$PWD/qandroidassetsfileenginehandler.cpp \ + $$PWD/qandroidinputcontext.cpp \ + $$PWD/qandroidplatformaccessibility.cpp \ + $$PWD/qandroidplatformfontdatabase.cpp \ + $$PWD/qandroidplatformdialoghelpers.cpp \ + $$PWD/qandroidplatformclipboard.cpp \ + $$PWD/qandroidplatformtheme.cpp \ + $$PWD/qandroidplatformmenubar.cpp \ + $$PWD/qandroidplatformmenu.cpp \ + $$PWD/qandroidplatformmenuitem.cpp \ + $$PWD/qandroidsystemlocale.cpp \ + $$PWD/qandroidplatformscreen.cpp \ + $$PWD/qandroidplatformwindow.cpp \ + $$PWD/qandroidplatformopenglwindow.cpp \ + $$PWD/qandroidplatformrasterwindow.cpp \ + $$PWD/qandroidplatformbackingstore.cpp \ + $$PWD/qandroidplatformopenglcontext.cpp + +HEADERS += $$PWD/qandroidplatformintegration.h \ + $$PWD/androidjnimain.h \ + $$PWD/androidjniaccessibility.h \ + $$PWD/androidjniinput.h \ + $$PWD/androidjnimenu.h \ + $$PWD/androidjniclipboard.h \ + $$PWD/qandroidplatformservices.h \ + $$PWD/qandroidassetsfileenginehandler.h \ + $$PWD/qandroidinputcontext.h \ + $$PWD/qandroidplatformaccessibility.h \ + $$PWD/qandroidplatformfontdatabase.h \ + $$PWD/qandroidplatformclipboard.h \ + $$PWD/qandroidplatformdialoghelpers.h \ + $$PWD/qandroidplatformtheme.h \ + $$PWD/qandroidplatformmenubar.h \ + $$PWD/qandroidplatformmenu.h \ + $$PWD/qandroidplatformmenuitem.h \ + $$PWD/qandroidsystemlocale.h \ + $$PWD/androidsurfaceclient.h \ + $$PWD/qandroidplatformscreen.h \ + $$PWD/qandroidplatformwindow.h \ + $$PWD/qandroidplatformopenglwindow.h \ + $$PWD/qandroidplatformrasterwindow.h \ + $$PWD/qandroidplatformbackingstore.h \ + $$PWD/qandroidplatformopenglcontext.h + +#Non-standard install directory, QTBUG-29859 +DESTDIR = $$DESTDIR/android +target.path = $${target.path}/android diff --git a/src/plugins/platforms/android/src/androidjniaccessibility.cpp b/src/plugins/platforms/android/androidjniaccessibility.cpp index b987c49c9c..b987c49c9c 100644 --- a/src/plugins/platforms/android/src/androidjniaccessibility.cpp +++ b/src/plugins/platforms/android/androidjniaccessibility.cpp diff --git a/src/plugins/platforms/android/src/androidjniaccessibility.h b/src/plugins/platforms/android/androidjniaccessibility.h index e708138c33..e708138c33 100644 --- a/src/plugins/platforms/android/src/androidjniaccessibility.h +++ b/src/plugins/platforms/android/androidjniaccessibility.h diff --git a/src/plugins/platforms/android/src/androidjniclipboard.cpp b/src/plugins/platforms/android/androidjniclipboard.cpp index 05270ac374..05270ac374 100644 --- a/src/plugins/platforms/android/src/androidjniclipboard.cpp +++ b/src/plugins/platforms/android/androidjniclipboard.cpp diff --git a/src/plugins/platforms/android/src/androidjniclipboard.h b/src/plugins/platforms/android/androidjniclipboard.h index 15cd93202e..15cd93202e 100644 --- a/src/plugins/platforms/android/src/androidjniclipboard.h +++ b/src/plugins/platforms/android/androidjniclipboard.h diff --git a/src/plugins/platforms/android/src/androidjniinput.cpp b/src/plugins/platforms/android/androidjniinput.cpp index 8ce95532d3..55d44b7377 100644 --- a/src/plugins/platforms/android/src/androidjniinput.cpp +++ b/src/plugins/platforms/android/androidjniinput.cpp @@ -471,6 +471,9 @@ namespace QtAndroidInput case 0x000000ba: // KEYCODE_PROG_BLUE return Qt::Key_Blue; + case 0x000000a5: // KEYCODE_INFO + return Qt::Key_Info; + case 0x000000a6: // KEYCODE_CHANNEL_UP return Qt::Key_ChannelUp; @@ -483,9 +486,15 @@ namespace QtAndroidInput case 0x000000a9: // KEYCODE_ZOOM_OUT return Qt::Key_ZoomOut; + case 0x000000ac: // KEYCODE_GUIDE + return Qt::Key_Guide; + case 0x000000af: // KEYCODE_CAPTIONS return Qt::Key_Subtitle; + case 0x000000b0: // KEYCODE_SETTINGS + return Qt::Key_Settings; + case 0x000000d0: // KEYCODE_CALENDAR return Qt::Key_Calendar; diff --git a/src/plugins/platforms/android/src/androidjniinput.h b/src/plugins/platforms/android/androidjniinput.h index a78c7519db..a78c7519db 100644 --- a/src/plugins/platforms/android/src/androidjniinput.h +++ b/src/plugins/platforms/android/androidjniinput.h diff --git a/src/plugins/platforms/android/src/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index 3064e5d4e2..ee62c002d8 100644 --- a/src/plugins/platforms/android/src/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** +** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org> ** 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. @@ -53,6 +53,7 @@ #include <qdebug.h> #include <qglobal.h> #include <qobjectdefs.h> +#include <QtCore/private/qjni_p.h> #include <stdlib.h> #include "androidjnimain.h" @@ -73,14 +74,6 @@ #include <qpa/qwindowsysteminterface.h> -#ifdef ANDROID_PLUGIN_OPENGL -# include "qandroidopenglplatformwindow.h" -#endif - -#include <android/native_window_jni.h> - -static jmethodID m_redrawSurfaceMethodID = 0; - Q_IMPORT_PLUGIN(QAndroidPlatformIntegrationPlugin) static JavaVM *m_javaVM = NULL; @@ -90,6 +83,9 @@ static jmethodID m_loadClassMethodID = NULL; static AAssetManager *m_assetManager = NULL; static jobject m_resourcesObj; static jobject m_activityObject = NULL; +static jmethodID m_createSurfaceMethodID = 0; +static jmethodID m_setSurfaceGeometryMethodID = 0; +static jmethodID m_destroySurfaceMethodID = 0; static bool m_activityActive = true; // defaults to true because when the platform plugin is // initialized, QtActivity::onResume() has already been called @@ -110,17 +106,19 @@ 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; -#endif +struct SurfaceData +{ + ~SurfaceData() { delete surface; } + QJNIObjectPrivate *surface = 0; + AndroidSurfaceClient *client = 0; +}; + +QHash<int, AndroidSurfaceClient *> m_surfaces; +static QMutex m_surfacesMutex; +static int m_surfaceId = 1; static QSemaphore m_quitAppSemaphore; -static QMutex m_surfaceMutex(QMutex::Recursive); static QSemaphore m_pauseApplicationSemaphore; static QMutex m_pauseApplicationMutex; @@ -140,128 +138,18 @@ 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; - } -#endif - void setAndroidPlatformIntegration(QAndroidPlatformIntegration *androidPlatformIntegration) { - m_surfaceMutex.lock(); + m_surfacesMutex.lock(); m_androidPlatformIntegration = androidPlatformIntegration; - m_surfaceMutex.unlock(); + m_surfacesMutex.unlock(); } QAndroidPlatformIntegration *androidPlatformIntegration() { - QMutexLocker locker(&m_surfaceMutex); + QMutexLocker locker(&m_surfacesMutex); return m_androidPlatformIntegration; } @@ -353,14 +241,14 @@ namespace QtAndroid jobject createBitmap(QImage img, JNIEnv *env) { - if (img.format() != QImage::Format_ARGB32 && img.format() != QImage::Format_RGB16) - img = img.convertToFormat(QImage::Format_ARGB32); + if (img.format() != QImage::Format_RGBA8888 && img.format() != QImage::Format_RGB16) + img = img.convertToFormat(QImage::Format_RGBA8888); jobject bitmap = env->CallStaticObjectMethod(m_bitmapClass, m_createBitmapMethodID, img.width(), img.height(), - img.format() == QImage::Format_ARGB32 + img.format() == QImage::Format_RGBA8888 ? m_ARGB_8888_BitmapConfigValue : m_RGB_565_BitmapConfigValue); if (!bitmap) @@ -393,6 +281,21 @@ namespace QtAndroid return bitmap; } + jobject createBitmap(int width, int height, QImage::Format format, JNIEnv *env) + { + if (format != QImage::Format_RGBA8888 + && format != QImage::Format_RGB16) + return 0; + + return env->CallStaticObjectMethod(m_bitmapClass, + m_createBitmapMethodID, + width, + height, + format == QImage::Format_RGB16 + ? m_RGB_565_BitmapConfigValue + : m_ARGB_8888_BitmapConfigValue); + } + jobject createBitmapDrawable(jobject bitmap, JNIEnv *env) { if (!bitmap) @@ -418,25 +321,74 @@ namespace QtAndroid { return m_qtTag; } + + int createSurface(AndroidSurfaceClient *client, const QRect &geometry, bool onTop) + { + QJNIEnvironmentPrivate env; + if (!env) + return 0; + + m_surfacesMutex.lock(); + int surfaceId = m_surfaceId++; + m_surfaces[surfaceId] = client; + m_surfacesMutex.unlock(); + + jint x = 0, y = 0, w = -1, h = -1; + if (!geometry.isNull()) { + x = geometry.x(); + y = geometry.y(); + w = std::max(geometry.width(), 1); + h = std::max(geometry.height(), 1); + } + env->CallStaticVoidMethod(m_applicationClass, + m_createSurfaceMethodID, + surfaceId, + jboolean(onTop), + x, y, w, h); + return surfaceId; + } + + void setSurfaceGeometry(int surfaceId, const QRect &geometry) + { + QJNIEnvironmentPrivate env; + if (!env) + return; + jint x = 0, y = 0, w = -1, h = -1; + if (!geometry.isNull()) { + x = geometry.x(); + y = geometry.y(); + w = geometry.width(); + h = geometry.height(); + } + env->CallStaticVoidMethod(m_applicationClass, + m_setSurfaceGeometryMethodID, + surfaceId, + x, y, w, h); + } + + void destroySurface(int surfaceId) + { + QMutexLocker lock(&m_surfacesMutex); + const auto &it = m_surfaces.find(surfaceId); + if (it == m_surfaces.end()) + return; + + m_surfaces.remove(surfaceId); + QJNIEnvironmentPrivate env; + if (!env) + return; + + env->CallStaticVoidMethod(m_applicationClass, + m_destroySurfaceMethodID, + surfaceId); + } } 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*/) @@ -512,54 +464,16 @@ static jboolean startQtApplication(JNIEnv *env, jobject /*object*/, jstring para 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); @@ -568,76 +482,19 @@ static void terminateQt(JNIEnv *env, jclass /*clazz*/) env->DeleteGlobalRef(m_ARGB_8888_BitmapConfigValue); env->DeleteGlobalRef(m_RGB_565_BitmapConfigValue); env->DeleteGlobalRef(m_bitmapDrawableClass); + m_androidPlatformIntegration = 0; + delete m_androidAssetsFileEngineHandler; } -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) { - // Use the desktop size. - // On some devices, the getters for the native window size gives wrong values - QSize size = QAndroidPlatformIntegration::defaultDesktopSize(); - - QPlatformScreen *screen = m_androidPlatformIntegration->screen(); - QRect geometry(QPoint(0, 0), size); - if (screen) { - QWindowSystemInterface::handleScreenAvailableGeometryChange(screen->screen(), geometry); - QWindowSystemInterface::handleScreenGeometryChange(screen->screen(), geometry); - } - - if (!sameNativeWindow) { - m_surfaceMutex.unlock(); - m_androidPlatformIntegration->surfaceChanged(); - } else { - // Resize all top level windows, since they share the same surface - foreach (QWindow *w, QGuiApplication::topLevelWindows()) { - QAndroidOpenGLPlatformWindow *window = - static_cast<QAndroidOpenGLPlatformWindow *>(w->handle()); - - 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*/) +static void setSurface(JNIEnv *env, jobject /*thiz*/, jint id, jobject jSurface, jint w, jint h) { -#ifndef ANDROID_PLUGIN_OPENGL - if (m_surface) { - env->DeleteGlobalRef(m_surface); - m_surface = 0; + QMutexLocker lock(&m_surfacesMutex); + const auto &it = m_surfaces.find(id); + if (it == m_surfaces.end()) { + qWarning()<<"Can't find surface" << id; + return; } -#else - Q_UNUSED(env); - m_nativeWindow = 0; - if (m_androidPlatformIntegration != 0) - m_androidPlatformIntegration->invalidateNativeSurface(); -#endif + it.value()->surfaceChanged(env, jSurface, w, h); } static void setDisplayMetrics(JNIEnv */*env*/, jclass /*clazz*/, @@ -660,16 +517,6 @@ static void setDisplayMetrics(JNIEnv */*env*/, jclass /*clazz*/, } } -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) @@ -680,12 +527,8 @@ static void updateWindow(JNIEnv */*env*/, jobject /*thiz*/) 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 updateApplicationState(JNIEnv */*env*/, jobject /*thiz*/, jint state) @@ -734,15 +577,10 @@ static void handleOrientationChanged(JNIEnv */*env*/, jobject /*thiz*/, jint new 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", "(IIIIDDD)V", (void *)setDisplayMetrics}, - {"setSurface", "(Ljava/lang/Object;)V", (void *)setSurface}, - {"destroySurface", "()V", (void *)destroySurface}, - {"lockSurface", "()V", (void *)lockSurface}, - {"unlockSurface", "()V", (void *)unlockSurface}, + {"setSurface", "(ILjava/lang/Object;II)V", (void *)setSurface}, {"updateWindow", "()V", (void *)updateWindow}, {"updateApplicationState", "(I)V", (void *)updateApplicationState}, {"handleOrientationChanged", "(II)V", (void *)handleOrientationChanged} @@ -795,7 +633,9 @@ static int registerNatives(JNIEnv *env) return JNI_FALSE; } - GET_AND_CHECK_STATIC_METHOD(m_redrawSurfaceMethodID, m_applicationClass, "redrawSurface", "(IIII)V"); + GET_AND_CHECK_STATIC_METHOD(m_createSurfaceMethodID, m_applicationClass, "createSurface", "(IZIIII)V"); + GET_AND_CHECK_STATIC_METHOD(m_setSurfaceGeometryMethodID, m_applicationClass, "setSurfaceGeometry", "(IIIII)V"); + GET_AND_CHECK_STATIC_METHOD(m_destroySurfaceMethodID, m_applicationClass, "destroySurface", "(I)V"); jmethodID methodID; GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "activity", "()Landroid/app/Activity;"); diff --git a/src/plugins/platforms/android/src/androidjnimain.h b/src/plugins/platforms/android/androidjnimain.h index 11d3573404..24287df474 100644 --- a/src/plugins/platforms/android/src/androidjnimain.h +++ b/src/plugins/platforms/android/androidjnimain.h @@ -1,7 +1,7 @@ /**************************************************************************** ** +** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org> ** 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. @@ -45,16 +45,11 @@ #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; +#include <QImage> + class QRect; class QPoint; class QThread; @@ -62,6 +57,7 @@ class QAndroidPlatformIntegration; class QWidget; class QString; class QWindow; +class AndroidSurfaceClient; namespace QtAndroid { @@ -69,11 +65,10 @@ namespace QtAndroid void setAndroidPlatformIntegration(QAndroidPlatformIntegration *androidPlatformIntegration); void setQtThread(QThread *thread); -#ifndef ANDROID_PLUGIN_OPENGL - void flushImage(const QPoint &pos, const QImage &image, const QRect &rect); -#else - EGLNativeWindowType nativeWindow(bool waitToCreate = true); -#endif + + int createSurface(AndroidSurfaceClient * client, const QRect &geometry, bool onTop); + void setSurfaceGeometry(int surfaceId, const QRect &geometry); + void destroySurface(int surfaceId); QWindow *topLevelWindowAt(const QPoint &globalPos); int desktopWidthPixels(); @@ -91,6 +86,7 @@ namespace QtAndroid void hideStatusBar(); jobject createBitmap(QImage img, JNIEnv *env = 0); + jobject createBitmap(int width, int height, QImage::Format format, JNIEnv *env); jobject createBitmapDrawable(jobject bitmap, JNIEnv *env = 0); struct AttachedJNIEnv diff --git a/src/plugins/platforms/android/src/androidjnimenu.cpp b/src/plugins/platforms/android/androidjnimenu.cpp index dbdd7c9b8e..dc2afe2b03 100644 --- a/src/plugins/platforms/android/src/androidjnimenu.cpp +++ b/src/plugins/platforms/android/androidjnimenu.cpp @@ -143,6 +143,9 @@ namespace QtAndroidMenu void setActiveTopLevelWindow(QWindow *window) { Qt::WindowFlags flags = window ? window->flags() : Qt::WindowFlags(); + if (!window) + return; + bool isNonRegularWindow = flags & (Qt::Desktop | Qt::Popup | Qt::Dialog | Qt::Sheet) & ~Qt::Window; if (isNonRegularWindow) return; @@ -195,9 +198,9 @@ namespace QtAndroidMenu 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); + env->DeleteLocalRef(env->CallObjectMethod(menuItem, setCheckableMenuItemMethodID, checkable)); + env->DeleteLocalRef(env->CallObjectMethod(menuItem, setCheckedMenuItemMethodID, checked)); + env->DeleteLocalRef(env->CallObjectMethod(menuItem, setEnabledMenuItemMethodID, enabled)); if (!icon.isNull()) { // isNull() only checks the d pointer, not the actual image data. int sz = qMax(36, qgetenv("QT_ANDROID_APP_ICON_SIZE").toInt()); @@ -207,13 +210,13 @@ namespace QtAndroidMenu : QIcon::Disabled, QIcon::On).toImage(); if (!img.isNull()) { // Make sure we have a valid image. - env->CallObjectMethod(menuItem, - setIconMenuItemMethodID, - createBitmapDrawable(createBitmap(img, env), env)); + env->DeleteLocalRef(env->CallObjectMethod(menuItem, + setIconMenuItemMethodID, + createBitmapDrawable(createBitmap(img, env), env))); } } - env->CallObjectMethod(menuItem, setVisibleMenuItemMethodID, visible); + env->DeleteLocalRef(env->CallObjectMethod(menuItem, setVisibleMenuItemMethodID, visible)); } static int addAllMenuItemsToMenu(JNIEnv *env, jobject menu, QAndroidPlatformMenu *platformMenu) { @@ -239,6 +242,7 @@ namespace QtAndroidMenu item->isEnabled(), item->isVisible(), item->icon()); + env->DeleteLocalRef(menuItem); } return order; diff --git a/src/plugins/platforms/android/src/androidjnimenu.h b/src/plugins/platforms/android/androidjnimenu.h index 7c5422f67b..7c5422f67b 100644 --- a/src/plugins/platforms/android/src/androidjnimenu.h +++ b/src/plugins/platforms/android/androidjnimenu.h diff --git a/src/plugins/platforms/android/src/androidplatformplugin.cpp b/src/plugins/platforms/android/androidplatformplugin.cpp index 2cf5aa1e01..2cf5aa1e01 100644 --- a/src/plugins/platforms/android/src/androidplatformplugin.cpp +++ b/src/plugins/platforms/android/androidplatformplugin.cpp diff --git a/src/plugins/platforms/android/src/raster/qandroidplatformscreen.h b/src/plugins/platforms/android/androidsurfaceclient.h index 9f8807b995..254e47123b 100644 --- a/src/plugins/platforms/android/src/raster/qandroidplatformscreen.h +++ b/src/plugins/platforms/android/androidsurfaceclient.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org> +** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org> ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -39,24 +39,20 @@ ** ****************************************************************************/ -#ifndef QANDROIDPLATFORMSCREEN_H -#define QANDROIDPLATFORMSCREEN_H +#ifndef ANDROIDSURFACECLIENT_H +#define ANDROIDSURFACECLIENT_H +#include <QMutex> +#include <jni.h> -#include <QtPlatformSupport/private/qfbscreen_p.h> - -class QAndroidPlatformScreen: public QFbScreen +class AndroidSurfaceClient { - Q_OBJECT public: - QAndroidPlatformScreen(); - void topWindowChanged(QWindow *w); - QDpi logicalDpi() const; - Qt::ScreenOrientation orientation() const; - Qt::ScreenOrientation nativeOrientation() const; - -public slots: - QRegion doRedraw(); + virtual void surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h) = 0; + void lockSurface() { m_surfaceMutex.lock(); } + void unlockSurface() { m_surfaceMutex.unlock(); } +protected: + QMutex m_surfaceMutex; }; -#endif +#endif // ANDROIDSURFACECLIENT_H diff --git a/src/plugins/platforms/android/opengl/opengl.pro b/src/plugins/platforms/android/opengl/opengl.pro deleted file mode 100644 index ea050ca3a0..0000000000 --- a/src/plugins/platforms/android/opengl/opengl.pro +++ /dev/null @@ -1,32 +0,0 @@ -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 \ - $$PWD/../src/opengl/qandroidopenglplatformscreen.h - -SOURCES += \ - $$PWD/../src/opengl/qandroidopenglcontext.cpp \ - $$PWD/../src/opengl/qandroidopenglplatformwindow.cpp \ - $$PWD/../src/opengl/qandroidopenglplatformscreen.cpp - -include($$PWD/../../eglfs/eglfs.pri) -include($$PWD/../src/src.pri) diff --git a/src/plugins/platforms/android/src/qandroidassetsfileenginehandler.cpp b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp index 95844fc649..95844fc649 100644 --- a/src/plugins/platforms/android/src/qandroidassetsfileenginehandler.cpp +++ b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp diff --git a/src/plugins/platforms/android/src/qandroidassetsfileenginehandler.h b/src/plugins/platforms/android/qandroidassetsfileenginehandler.h index 7bd560886c..7bd560886c 100644 --- a/src/plugins/platforms/android/src/qandroidassetsfileenginehandler.h +++ b/src/plugins/platforms/android/qandroidassetsfileenginehandler.h diff --git a/src/plugins/platforms/android/src/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp index 326972e71e..326972e71e 100644 --- a/src/plugins/platforms/android/src/qandroidinputcontext.cpp +++ b/src/plugins/platforms/android/qandroidinputcontext.cpp diff --git a/src/plugins/platforms/android/src/qandroidinputcontext.h b/src/plugins/platforms/android/qandroidinputcontext.h index 041bd0dc49..041bd0dc49 100644 --- a/src/plugins/platforms/android/src/qandroidinputcontext.h +++ b/src/plugins/platforms/android/qandroidinputcontext.h diff --git a/src/plugins/platforms/android/src/qandroidplatformaccessibility.cpp b/src/plugins/platforms/android/qandroidplatformaccessibility.cpp index 229368345b..229368345b 100644 --- a/src/plugins/platforms/android/src/qandroidplatformaccessibility.cpp +++ b/src/plugins/platforms/android/qandroidplatformaccessibility.cpp diff --git a/src/plugins/platforms/android/src/qandroidplatformaccessibility.h b/src/plugins/platforms/android/qandroidplatformaccessibility.h index 1b87f11919..1b87f11919 100644 --- a/src/plugins/platforms/android/src/qandroidplatformaccessibility.h +++ b/src/plugins/platforms/android/qandroidplatformaccessibility.h diff --git a/src/plugins/platforms/android/qandroidplatformbackingstore.cpp b/src/plugins/platforms/android/qandroidplatformbackingstore.cpp new file mode 100644 index 0000000000..1df7ce3179 --- /dev/null +++ b/src/plugins/platforms/android/qandroidplatformbackingstore.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org> +** 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 "qandroidplatformbackingstore.h" +#include "qandroidplatformscreen.h" +#include "qandroidplatformrasterwindow.h" +#include <qpa/qplatformscreen.h> + +QT_BEGIN_NAMESPACE + +QAndroidPlatformBackingStore::QAndroidPlatformBackingStore(QWindow *window) + : QPlatformBackingStore(window) +{ + Q_ASSERT(window->handle()); + (static_cast<QAndroidPlatformRasterWindow *>(window->handle()))->setBackingStore(this); +} + +QPaintDevice *QAndroidPlatformBackingStore::paintDevice() +{ + return &m_image; +} + +void QAndroidPlatformBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) +{ + Q_UNUSED(window); + Q_UNUSED(offset); + + (static_cast<QAndroidPlatformRasterWindow *>(window->handle()))->repaint(region); +} + +void QAndroidPlatformBackingStore::resize(const QSize &size, const QRegion &staticContents) +{ + Q_UNUSED(staticContents); + + if (m_image.size() != size) + m_image = QImage(size, window()->screen()->handle()->format()); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidplatformbackingstore.h b/src/plugins/platforms/android/qandroidplatformbackingstore.h new file mode 100644 index 0000000000..e6ea3dcce0 --- /dev/null +++ b/src/plugins/platforms/android/qandroidplatformbackingstore.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org> +** 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 QANDROIDPLATFORMBACKINGSTORE_H +#define QANDROIDPLATFORMBACKINGSTORE_H + +#include <qpa/qplatformbackingstore.h> +#include <qpa/qwindowsysteminterface.h> + +QT_BEGIN_NAMESPACE + +class QAndroidPlatformBackingStore : public QPlatformBackingStore +{ +public: + explicit QAndroidPlatformBackingStore(QWindow *window); + virtual QPaintDevice *paintDevice(); + virtual void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); + virtual void resize(const QSize &size, const QRegion &staticContents); + const QImage image() { return m_image; } + +protected: + QImage m_image; +}; + +QT_END_NAMESPACE + +#endif // QANDROIDPLATFORMBACKINGSTORE_H diff --git a/src/plugins/platforms/android/src/qandroidplatformclipboard.cpp b/src/plugins/platforms/android/qandroidplatformclipboard.cpp index bc48b4935b..bc48b4935b 100644 --- a/src/plugins/platforms/android/src/qandroidplatformclipboard.cpp +++ b/src/plugins/platforms/android/qandroidplatformclipboard.cpp diff --git a/src/plugins/platforms/android/src/qandroidplatformclipboard.h b/src/plugins/platforms/android/qandroidplatformclipboard.h index 644f326934..644f326934 100644 --- a/src/plugins/platforms/android/src/qandroidplatformclipboard.h +++ b/src/plugins/platforms/android/qandroidplatformclipboard.h diff --git a/src/plugins/platforms/android/src/qandroidplatformdialoghelpers.cpp b/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp index 4c91e76e0f..4b99f2ce73 100644 --- a/src/plugins/platforms/android/src/qandroidplatformdialoghelpers.cpp +++ b/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp @@ -43,6 +43,8 @@ #include <QtWidgets/QStyle> #include "qandroidplatformdialoghelpers.h" #include "androidjnimain.h" +#include <private/qguiapplication_p.h> +#include <qpa/qplatformtheme.h> namespace QtAndroidDialogHelpers { static jclass g_messageDialogHelperClass = 0; @@ -61,49 +63,6 @@ void QAndroidPlatformMessageDialogHelper::exec() m_loop.exec(); } -static QString standardButtonText(int sbutton) -{ - switch (sbutton) { - case QMessageDialogOptions::Ok: - return QAndroidPlatformMessageDialogHelper::tr("OK"); - case QMessageDialogOptions::Save: - return QAndroidPlatformMessageDialogHelper::tr("Save"); - case QMessageDialogOptions::Open: - return QAndroidPlatformMessageDialogHelper::tr("Open"); - case QMessageDialogOptions::Cancel: - return QAndroidPlatformMessageDialogHelper::tr("Cancel"); - case QMessageDialogOptions::Close: - return QAndroidPlatformMessageDialogHelper::tr("Close"); - case QMessageDialogOptions::Apply: - return QAndroidPlatformMessageDialogHelper::tr("Apply"); - case QMessageDialogOptions::Reset: - return QAndroidPlatformMessageDialogHelper::tr("Reset"); - case QMessageDialogOptions::Help: - return QAndroidPlatformMessageDialogHelper::tr("Help"); - case QMessageDialogOptions::Discard: - return QAndroidPlatformMessageDialogHelper::tr("Discard"); - case QMessageDialogOptions::Yes: - return QAndroidPlatformMessageDialogHelper::tr("Yes"); - case QMessageDialogOptions::YesToAll: - return QAndroidPlatformMessageDialogHelper::tr("Yes to All"); - case QMessageDialogOptions::No: - return QAndroidPlatformMessageDialogHelper::tr("No"); - case QMessageDialogOptions::NoToAll: - return QAndroidPlatformMessageDialogHelper::tr("No to All"); - case QMessageDialogOptions::SaveAll: - return QAndroidPlatformMessageDialogHelper::tr("Save All"); - case QMessageDialogOptions::Abort: - return QAndroidPlatformMessageDialogHelper::tr("Abort"); - case QMessageDialogOptions::Retry: - return QAndroidPlatformMessageDialogHelper::tr("Retry"); - case QMessageDialogOptions::Ignore: - return QAndroidPlatformMessageDialogHelper::tr("Ignore"); - case QMessageDialogOptions::RestoreDefaults: - return QAndroidPlatformMessageDialogHelper::tr("Restore Defaults"); - } // switch - return QString(); -} - bool QAndroidPlatformMessageDialogHelper::show(Qt::WindowFlags windowFlags , Qt::WindowModality windowModality , QWindow *parent) @@ -134,8 +93,10 @@ bool QAndroidPlatformMessageDialogHelper::show(Qt::WindowFlags windowFlags m_javaMessageDialog.callMethod<void>("setDetailedText", "(Ljava/lang/String;)V", QJNIObjectPrivate::fromString(str).object()); for (int i = QMessageDialogOptions::FirstButton; i < QMessageDialogOptions::LastButton; i<<=1) { - if ( opt->standardButtons() & i ) - m_javaMessageDialog.callMethod<void>("addButton", "(ILjava/lang/String;)V", i, QJNIObjectPrivate::fromString(standardButtonText(i)).object()); + if ( opt->standardButtons() & i ) { + const QString text = QGuiApplicationPrivate::platformTheme()->standardButtonText(i); + m_javaMessageDialog.callMethod<void>("addButton", "(ILjava/lang/String;)V", i, QJNIObjectPrivate::fromString(text).object()); + } } m_javaMessageDialog.callMethod<void>("show", "(J)V", jlong(static_cast<QObject*>(this))); diff --git a/src/plugins/platforms/android/src/qandroidplatformdialoghelpers.h b/src/plugins/platforms/android/qandroidplatformdialoghelpers.h index 88ec91d936..88ec91d936 100644 --- a/src/plugins/platforms/android/src/qandroidplatformdialoghelpers.h +++ b/src/plugins/platforms/android/qandroidplatformdialoghelpers.h diff --git a/src/plugins/platforms/android/src/qandroidplatformfontdatabase.cpp b/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp index 7f68b44ed8..7f68b44ed8 100644 --- a/src/plugins/platforms/android/src/qandroidplatformfontdatabase.cpp +++ b/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp diff --git a/src/plugins/platforms/android/src/qandroidplatformfontdatabase.h b/src/plugins/platforms/android/qandroidplatformfontdatabase.h index 3cbfe95d36..3cbfe95d36 100644 --- a/src/plugins/platforms/android/src/qandroidplatformfontdatabase.h +++ b/src/plugins/platforms/android/qandroidplatformfontdatabase.h diff --git a/src/plugins/platforms/android/src/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp index ae3e257d3c..2fc6b987ab 100644 --- a/src/plugins/platforms/android/src/qandroidplatformintegration.cpp +++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp @@ -40,35 +40,32 @@ ****************************************************************************/ #include "qandroidplatformintegration.h" -#include "qabstracteventdispatcher.h" -#include "androidjnimain.h" -#include <QtGui/qguiapplication.h> -#include <qpa/qwindowsysteminterface.h> + +#include <QGuiApplication> +#include <QOpenGLContext> #include <QThread> + +#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h> + +#include <qpa/qwindowsysteminterface.h> #include <qpa/qplatformwindow.h> + +#warning sort the headers +#include "androidjnimain.h" +#include "qabstracteventdispatcher.h" +#include "qandroidplatformrasterwindow.h" +#include "qandroidplatformopenglwindow.h" +#include "qandroidplatformbackingstore.h" #include "qandroidplatformservices.h" #include "qandroidplatformfontdatabase.h" #include "qandroidplatformclipboard.h" #include "qandroidplatformaccessibility.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 "qandroidopenglplatformscreen.h" -# include "qeglfshooks.h" -# include <QtGui/qopenglcontext.h> -#endif - +#include "qandroidplatformopenglcontext.h" +#include "qandroidplatformscreen.h" #include "qandroidplatformtheme.h" #include "qandroidsystemlocale.h" + QT_BEGIN_NAMESPACE int QAndroidPlatformIntegration::m_defaultGeometryWidth = 320; @@ -102,12 +99,21 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList ¶ m_androidPlatformNativeInterface = new QAndroidPlatformNativeInterface(); -#ifndef ANDROID_PLUGIN_OPENGL + if (!eglBindAPI(EGL_OPENGL_ES_API)) + qFatal("Could not bind GL_ES API"); + + m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (m_eglDisplay == EGL_NO_DISPLAY) + qFatal("Could not open egl display"); + + EGLint major, minor; + if (!eglInitialize(m_eglDisplay, &major, &minor)) + qFatal("Could not initialize egl display"); + 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); @@ -124,83 +130,53 @@ bool QAndroidPlatformIntegration::hasCapability(Capability cap) const switch (cap) { case ThreadedPixmaps: return true; case ApplicationState: return true; - case NativeWidgets: return false; + case NativeWidgets: return true; + case OpenGL: return true; + case ThreadedOpenGL: return true; default: -#ifndef ANDROID_PLUGIN_OPENGL - return QPlatformIntegration::hasCapability(cap); -#else - return QEglFSIntegration::hasCapability(cap); -#endif + return QPlatformIntegration::hasCapability(cap); } } -#ifndef ANDROID_PLUGIN_OPENGL QPlatformBackingStore *QAndroidPlatformIntegration::createPlatformBackingStore(QWindow *window) const { - return new QFbBackingStore(window); + return new QAndroidPlatformBackingStore(window); } -QPlatformWindow *QAndroidPlatformIntegration::createPlatformWindow(QWindow *window) const +QPlatformOpenGLContext *QAndroidPlatformIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { - QAndroidPlatformWindow *platformWindow = new QAndroidPlatformWindow(window); - platformWindow->setWindowState(window->windowState()); - - return platformWindow; + QSurfaceFormat format(context->format()); + format.setAlphaBufferSize(8); + format.setRedBufferSize(8); + format.setGreenBufferSize(8); + format.setBlueBufferSize(8); + return new QAndroidPlatformOpenGLContext(format, context->shareHandle(), m_eglDisplay); } -QAbstractEventDispatcher *QAndroidPlatformIntegration::createEventDispatcher() const -{ - return createUnixEventDispatcher(); -} -#else // !ANDROID_PLUGIN_OPENGL QPlatformWindow *QAndroidPlatformIntegration::createPlatformWindow(QWindow *window) const { - QAndroidOpenGLPlatformWindow *platformWindow = new QAndroidOpenGLPlatformWindow(window); - platformWindow->create(); - platformWindow->requestActivateWindow(); - platformWindow->setWindowState(window->windowState()); - QtAndroidMenu::setActiveTopLevelWindow(window); - - return platformWindow; + if (window->surfaceType() == QSurface::RasterSurface) + return new QAndroidPlatformRasterWindow(window); + else + return new QAndroidPlatformOpenGLWindow(window, m_eglDisplay); } -void QAndroidPlatformIntegration::invalidateNativeSurface() -{ - foreach (QWindow *w, QGuiApplication::topLevelWindows()) { - QAndroidOpenGLPlatformWindow *window = - static_cast<QAndroidOpenGLPlatformWindow *>(w->handle()); - if (window != 0) - window->invalidateSurface(); - } -} - -void QAndroidPlatformIntegration::surfaceChanged() -{ - QAndroidOpenGLPlatformWindow::updateStaticNativeWindow(); - foreach (QWindow *w, QGuiApplication::topLevelWindows()) { - QAndroidOpenGLPlatformWindow *window = - static_cast<QAndroidOpenGLPlatformWindow *>(w->handle()); - if (window != 0) - window->resetSurface(); - } -} - -QPlatformOpenGLContext *QAndroidPlatformIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const +QAbstractEventDispatcher *QAndroidPlatformIntegration::createEventDispatcher() const { - return new QAndroidOpenGLContext(this, - QEglFSHooks::hooks()->surfaceFormatFor(context->format()), - context->shareHandle(), - display()); + return createUnixEventDispatcher(); } -#endif // ANDROID_PLUGIN_OPENGL QAndroidPlatformIntegration::~QAndroidPlatformIntegration() { + if (m_eglDisplay != EGL_NO_DISPLAY) + eglTerminate(m_eglDisplay); + delete m_androidPlatformNativeInterface; delete m_androidFDB; delete m_androidSystemLocale; QtAndroid::setAndroidPlatformIntegration(NULL); } + QPlatformFontDatabase *QAndroidPlatformIntegration::fontDatabase() const { return m_androidFDB; @@ -295,8 +271,6 @@ QPlatformAccessibility *QAndroidPlatformIntegration::accessibility() const } #endif - -#ifndef ANDROID_PLUGIN_OPENGL void QAndroidPlatformIntegration::setDesktopSize(int width, int height) { if (m_primaryScreen) @@ -308,36 +282,5 @@ 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; -} - -QEglFSScreen *QAndroidPlatformIntegration::createScreen() const -{ - return new QAndroidOpenGLPlatformScreen(display()); -} - -#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/qandroidplatformintegration.h index bd08ad694c..a6cba7ac16 100644 --- a/src/plugins/platforms/android/src/qandroidplatformintegration.h +++ b/src/plugins/platforms/android/qandroidplatformintegration.h @@ -47,14 +47,11 @@ #include <qpa/qplatformnativeinterface.h> #include <QtWidgets/QAction> +#include <EGL/egl.h> #include <jni.h> #include "qandroidinputcontext.h" -#ifndef ANDROID_PLUGIN_OPENGL -# include "qandroidplatformscreen.h" -#else -# include "qeglfsintegration.h" -#endif +#include "qandroidplatformscreen.h" QT_BEGIN_NAMESPACE @@ -63,10 +60,6 @@ class QAndroidPlatformServices; class QAndroidSystemLocale; class QPlatformAccessibility; -#ifdef ANDROID_PLUGIN_OPENGL -class QAndroidOpenGLPlatformWindow; -#endif - class QAndroidPlatformNativeInterface: public QPlatformNativeInterface { public: @@ -75,12 +68,7 @@ public: QHash<int, QFont> m_fonts; }; -class QAndroidPlatformIntegration -#ifndef ANDROID_PLUGIN_OPENGL - : public QPlatformIntegration -#else - : public QEglFSIntegration -#endif +class QAndroidPlatformIntegration : public QPlatformIntegration { friend class QAndroidPlatformScreen; @@ -90,17 +78,11 @@ public: bool hasCapability(QPlatformIntegration::Capability cap) const; -#ifndef ANDROID_PLUGIN_OPENGL - QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; QPlatformWindow *createPlatformWindow(QWindow *window) const; + QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; + QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; QAbstractEventDispatcher *createEventDispatcher() const; QAndroidPlatformScreen *screen() { return m_primaryScreen; } -#else - QPlatformWindow *createPlatformWindow(QWindow *window) const; - void invalidateNativeSurface(); - void surfaceChanged(); - QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; -#endif virtual void setDesktopSize(int width, int height); virtual void setDisplayMetrics(int width, int height); @@ -121,13 +103,11 @@ public: #endif QVariant styleHint(StyleHint hint) const; - Qt::WindowState defaultWindowState(Qt::WindowFlags flags) const Q_DECL_OVERRIDE; + Qt::WindowState defaultWindowState(Qt::WindowFlags flags) 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 void setScreenOrientation(Qt::ScreenOrientation currentOrientation, @@ -141,19 +121,12 @@ public: QTouchDevice *touchDevice() const { return m_touchDevice; } void setTouchDevice(QTouchDevice *touchDevice) { m_touchDevice = touchDevice; } -#ifdef ANDROID_PLUGIN_OPENGL - QEglFSScreen *createScreen() const; -#endif - private: - - friend class QEglFSAndroidHooks; + EGLDisplay m_eglDisplay; QTouchDevice *m_touchDevice; -#ifndef ANDROID_PLUGIN_OPENGL QAndroidPlatformScreen *m_primaryScreen; -#endif QThread *m_mainThread; diff --git a/src/plugins/platforms/android/src/qandroidplatformmenu.cpp b/src/plugins/platforms/android/qandroidplatformmenu.cpp index 1ecabb25e2..1ecabb25e2 100644 --- a/src/plugins/platforms/android/src/qandroidplatformmenu.cpp +++ b/src/plugins/platforms/android/qandroidplatformmenu.cpp diff --git a/src/plugins/platforms/android/src/qandroidplatformmenu.h b/src/plugins/platforms/android/qandroidplatformmenu.h index 305b64168a..305b64168a 100644 --- a/src/plugins/platforms/android/src/qandroidplatformmenu.h +++ b/src/plugins/platforms/android/qandroidplatformmenu.h diff --git a/src/plugins/platforms/android/src/qandroidplatformmenubar.cpp b/src/plugins/platforms/android/qandroidplatformmenubar.cpp index 134062fb32..134062fb32 100644 --- a/src/plugins/platforms/android/src/qandroidplatformmenubar.cpp +++ b/src/plugins/platforms/android/qandroidplatformmenubar.cpp diff --git a/src/plugins/platforms/android/src/qandroidplatformmenubar.h b/src/plugins/platforms/android/qandroidplatformmenubar.h index 56915335c2..56915335c2 100644 --- a/src/plugins/platforms/android/src/qandroidplatformmenubar.h +++ b/src/plugins/platforms/android/qandroidplatformmenubar.h diff --git a/src/plugins/platforms/android/src/qandroidplatformmenuitem.cpp b/src/plugins/platforms/android/qandroidplatformmenuitem.cpp index bd37834d2a..bd37834d2a 100644 --- a/src/plugins/platforms/android/src/qandroidplatformmenuitem.cpp +++ b/src/plugins/platforms/android/qandroidplatformmenuitem.cpp diff --git a/src/plugins/platforms/android/src/qandroidplatformmenuitem.h b/src/plugins/platforms/android/qandroidplatformmenuitem.h index 5861e8e195..5861e8e195 100644 --- a/src/plugins/platforms/android/src/qandroidplatformmenuitem.h +++ b/src/plugins/platforms/android/qandroidplatformmenuitem.h diff --git a/src/plugins/platforms/android/src/opengl/qandroidopenglcontext.cpp b/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp index 6431914812..d99cafe6b7 100644 --- a/src/plugins/platforms/android/src/opengl/qandroidopenglcontext.cpp +++ b/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org> ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** @@ -39,49 +40,30 @@ ** ****************************************************************************/ -#include "qandroidopenglcontext.h" -#include "qandroidopenglplatformwindow.h" -#include "qandroidplatformintegration.h" - -#include <QtCore/qdebug.h> -#include <qpa/qwindowsysteminterface.h> +#include "qandroidplatformopenglcontext.h" +#include "qandroidplatformopenglwindow.h" +#include <QSurface> #include <QtGui/private/qopenglcontext_p.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) +QAndroidPlatformOpenGLContext::QAndroidPlatformOpenGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display) + :QEGLPlatformContext(format, share, display, EGL_OPENGL_ES_API) { } -void QAndroidOpenGLContext::swapBuffers(QPlatformSurface *surface) +void QAndroidPlatformOpenGLContext::swapBuffers(QPlatformSurface *surface) { - QEglFSContext::swapBuffers(surface); + QEGLPlatformContext::swapBuffers(surface); - if (surface->surface()->surfaceClass() == QSurface::Window) { - QAndroidOpenGLPlatformWindow *window = static_cast<QAndroidOpenGLPlatformWindow *>(surface); - window->lock(); - QSize size = window->scheduledResize(); - if (size.isValid()) { - QRect geometry(QPoint(0, 0), size); - window->setGeometry(geometry); - QWindowSystemInterface::handleGeometryChange(window->window(), geometry); - QWindowSystemInterface::handleExposeEvent(window->window(), QRegion(geometry)); - window->scheduleResize(QSize()); - } - window->unlock(); - } + if (surface->surface()->surfaceClass() == QSurface::Window) + static_cast<QAndroidPlatformOpenGLWindow *>(surface)->checkNativeSurface(eglConfig()); } -bool QAndroidOpenGLContext::makeCurrent(QPlatformSurface *surface) +bool QAndroidPlatformOpenGLContext::makeCurrent(QPlatformSurface *surface) { - bool ret = QEglFSContext::makeCurrent(surface); + bool ret = QEGLPlatformContext::makeCurrent(surface); const char *rendererString = reinterpret_cast<const char *>(glGetString(GL_RENDERER)); if (rendererString != 0 && qstrncmp(rendererString, "Android Emulator", 16) == 0) { @@ -92,4 +74,11 @@ bool QAndroidOpenGLContext::makeCurrent(QPlatformSurface *surface) return ret; } +EGLSurface QAndroidPlatformOpenGLContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface) +{ + if (surface->surface()->surfaceClass() == QSurface::Window) + return static_cast<QAndroidPlatformOpenGLWindow *>(surface)->eglSurface(eglConfig()); + return EGL_NO_SURFACE; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/src/opengl/qandroidopenglcontext.h b/src/plugins/platforms/android/qandroidplatformopenglcontext.h index c419ae8392..29e5f596d5 100644 --- a/src/plugins/platforms/android/src/opengl/qandroidopenglcontext.h +++ b/src/plugins/platforms/android/qandroidplatformopenglcontext.h @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org> ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** @@ -39,31 +40,24 @@ ** ****************************************************************************/ -#ifndef QANDROIDOPENGLCONTEXT_H -#define QANDROIDOPENGLCONTEXT_H +#ifndef QANDROIDPLATFORMOPENGLCONTEXT_H +#define QANDROIDPLATFORMOPENGLCONTEXT_H -#include <QtCore/qreadwritelock.h> -#include "qeglfscontext.h" +#include <QtPlatformSupport/private/qeglplatformcontext_p.h> QT_BEGIN_NAMESPACE -class QAndroidPlatformIntegration; -class QAndroidOpenGLContext : public QEglFSContext +class QAndroidPlatformOpenGLContext : public QEGLPlatformContext { public: - QAndroidOpenGLContext(const QAndroidPlatformIntegration *integration, - const QSurfaceFormat &format, - QPlatformOpenGLContext *share, - EGLDisplay display, - EGLenum eglApi = EGL_OPENGL_ES_API); - + QAndroidPlatformOpenGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display); void swapBuffers(QPlatformSurface *surface); bool makeCurrent(QPlatformSurface *surface); private: - const QAndroidPlatformIntegration *m_platformIntegration; + virtual EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface); }; QT_END_NAMESPACE -#endif // QANDROIDOPENGLCONTEXT_H +#endif // QANDROIDPLATFORMOPENGLCONTEXT_H diff --git a/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp new file mode 100644 index 0000000000..498f59be88 --- /dev/null +++ b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org> +** 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 "qandroidplatformopenglwindow.h" + +#include "androidjnimain.h" + +#include <QSurfaceFormat> + +#include <qpa/qwindowsysteminterface.h> + +#include <android/native_window.h> +#include <android/native_window_jni.h> + +#warning remove me +#include <QDebug> + +QT_BEGIN_NAMESPACE + +QAndroidPlatformOpenGLWindow::QAndroidPlatformOpenGLWindow(QWindow *window, EGLDisplay display) + :QAndroidPlatformWindow(window), m_eglDisplay(display) +{ + lockSurface(); + m_nativeSurfaceId = QtAndroid::createSurface(this, geometry(), bool(window->flags() & Qt::WindowStaysOnTopHint)); + m_surfaceWaitCondition.wait(&m_surfaceMutex); + unlockSurface(); +} + +QAndroidPlatformOpenGLWindow::~QAndroidPlatformOpenGLWindow() +{ + m_surfaceWaitCondition.wakeOne(); + lockSurface(); + if (m_nativeSurfaceId != -1) + QtAndroid::destroySurface(m_nativeSurfaceId); + clearEgl(); + unlockSurface(); +} + +void QAndroidPlatformOpenGLWindow::setGeometry(const QRect &rect) +{ + if (rect == geometry()) + return; + + qDebug() << rect; + QAndroidPlatformWindow::setGeometry(rect); + QtAndroid::setSurfaceGeometry(m_nativeSurfaceId, rect); +} + +EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config) +{ + QMutexLocker lock(&m_surfaceMutex); + if (m_eglSurface == EGL_NO_SURFACE) { + m_surfaceMutex.unlock(); + checkNativeSurface(config); + m_surfaceMutex.lock(); + } + return m_eglSurface; +} + +void QAndroidPlatformOpenGLWindow::checkNativeSurface(EGLConfig config) +{ + QMutexLocker lock(&m_surfaceMutex); + qDebug() << geometry() << m_changedAndroidSurface.isValid(); + if (m_nativeSurfaceId == -1 || !m_changedAndroidSurface.isValid()) + return; + + createEgl(config); + + // we've create another surface, the window should be repainted + QWindowSystemInterface::handleExposeEvent(window(), QRegion(geometry())); +} + +void QAndroidPlatformOpenGLWindow::createEgl(EGLConfig config) +{ + clearEgl(); + m_androidSurface = QJNIObjectPrivate(); + m_androidSurface = m_changedAndroidSurface; + m_changedAndroidSurface = QJNIObjectPrivate(); + QJNIEnvironmentPrivate env; + m_nativeWindow = ANativeWindow_fromSurface(env, m_androidSurface.object()); + if (m_nativeWindow) + ANativeWindow_acquire(m_nativeWindow); + + m_eglSurface = eglCreateWindowSurface(m_eglDisplay, config, m_nativeWindow, NULL); + if (m_eglSurface == EGL_NO_SURFACE) { + EGLint error = eglGetError(); + eglTerminate(m_eglDisplay); + qFatal("EGL Error : Could not create the egl surface: error = 0x%x\n", error); + } +} + +void QAndroidPlatformOpenGLWindow::clearEgl() +{ + eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (m_eglSurface != EGL_NO_SURFACE) { + eglDestroySurface(m_eglDisplay, m_eglSurface); + m_eglSurface = EGL_NO_SURFACE; + } + + if (m_nativeWindow) { + ANativeWindow_release(m_nativeWindow); + m_nativeWindow = 0; + } +} + +void QAndroidPlatformOpenGLWindow::surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h) +{ + Q_UNUSED(jniEnv); + Q_UNUSED(w); + Q_UNUSED(h); + qDebug() << w << h; + lockSurface(); + m_changedAndroidSurface = surface; + m_surfaceWaitCondition.wakeOne(); + unlockSurface(); + + // repaint the window + QWindowSystemInterface::handleExposeEvent(window(), QRegion(geometry())); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidplatformopenglwindow.h b/src/plugins/platforms/android/qandroidplatformopenglwindow.h new file mode 100644 index 0000000000..820453ab01 --- /dev/null +++ b/src/plugins/platforms/android/qandroidplatformopenglwindow.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org> +** 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 QANDROIDPLATFORMOPENGLWINDOW_H +#define QANDROIDPLATFORMOPENGLWINDOW_H + +#include <EGL/egl.h> +#include <QWaitCondition> +#include <QtCore/private/qjni_p.h> + +#include "androidsurfaceclient.h" +#include "qandroidplatformwindow.h" + +QT_BEGIN_NAMESPACE + +class QAndroidPlatformOpenGLWindow : public QAndroidPlatformWindow, public AndroidSurfaceClient +{ +public: + explicit QAndroidPlatformOpenGLWindow(QWindow *window, EGLDisplay display); + ~QAndroidPlatformOpenGLWindow(); + + void setGeometry(const QRect &rect); + EGLSurface eglSurface(EGLConfig config); + + void checkNativeSurface(EGLConfig config); + +protected: + virtual void surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h); + void createEgl(EGLConfig config); + void clearEgl(); + +private: + EGLDisplay m_eglDisplay; + EGLSurface m_eglSurface = EGL_NO_SURFACE; + EGLNativeWindowType m_nativeWindow = nullptr; + + int m_nativeSurfaceId = -1; + QJNIObjectPrivate m_androidSurface; + QJNIObjectPrivate m_changedAndroidSurface; + QWaitCondition m_surfaceWaitCondition; +}; + +QT_END_NAMESPACE +#endif // QANDROIDPLATFORMOPENGLWINDOW_H diff --git a/src/plugins/platforms/android/qandroidplatformrasterwindow.cpp b/src/plugins/platforms/android/qandroidplatformrasterwindow.cpp new file mode 100644 index 0000000000..113a69427d --- /dev/null +++ b/src/plugins/platforms/android/qandroidplatformrasterwindow.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org> +** 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 "qandroidplatformrasterwindow.h" + +#include "qandroidplatformscreen.h" + +QT_BEGIN_NAMESPACE + +QAndroidPlatformRasterWindow::QAndroidPlatformRasterWindow(QWindow *window) + :QAndroidPlatformWindow(window) +{ + +} + +void QAndroidPlatformRasterWindow::repaint(const QRegion ®ion) +{ + QRect currentGeometry = geometry(); + + QRect dirtyClient = region.boundingRect(); + QRect dirtyRegion(currentGeometry.left() + dirtyClient.left(), + currentGeometry.top() + dirtyClient.top(), + dirtyClient.width(), + dirtyClient.height()); + QRect mOldGeometryLocal = m_oldGeometry; + m_oldGeometry = currentGeometry; + // If this is a move, redraw the previous location + if (mOldGeometryLocal != currentGeometry) + platformScreen()->setDirty(mOldGeometryLocal); + platformScreen()->setDirty(dirtyRegion); +} + +void QAndroidPlatformRasterWindow::setGeometry(const QRect &rect) +{ + m_oldGeometry = geometry(); + QAndroidPlatformWindow::setGeometry(rect); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidplatformrasterwindow.h b/src/plugins/platforms/android/qandroidplatformrasterwindow.h new file mode 100644 index 0000000000..50c0d497af --- /dev/null +++ b/src/plugins/platforms/android/qandroidplatformrasterwindow.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org> +** 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 QANDROIDPLATFORMRASTERWINDOW_H +#define QANDROIDPLATFORMRASTERWINDOW_H + +#include "qandroidplatformwindow.h" +QT_BEGIN_NAMESPACE + +class QAndroidPlatformBackingStore; +class QAndroidPlatformRasterWindow : public QObject, public QAndroidPlatformWindow +{ + Q_OBJECT +public: + QAndroidPlatformRasterWindow(QWindow *window); + + void setBackingStore(QAndroidPlatformBackingStore *store) { m_backingStore = store; } + QAndroidPlatformBackingStore *backingStore() const { return m_backingStore; } + void repaint(const QRegion®ion); + +public slots: + void setGeometry(const QRect &rect); + +private: + QAndroidPlatformBackingStore *m_backingStore = nullptr; + QRect m_oldGeometry; + +}; + +QT_END_NAMESPACE +#endif // QANDROIDPLATFORMRASTERWINDOW_H diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp new file mode 100644 index 0000000000..4f956f7a4f --- /dev/null +++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp @@ -0,0 +1,352 @@ +/**************************************************************************** +** +** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org> +** 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 <QDebug> +#include <QTime> + +#include <qpa/qwindowsysteminterface.h> + +#include "qandroidplatformscreen.h" +#include "qandroidplatformbackingstore.h" +#include "qandroidplatformintegration.h" +#include "androidjnimain.h" +#include "androidjnimenu.h" +#include "qandroidplatformrasterwindow.h" + +#include <android/bitmap.h> + +QT_BEGIN_NAMESPACE + +#warning REMOVE ME +class ScopedProfiler +{ +public: + ScopedProfiler(const QString &msg) + { + m_msg = msg; + } + ~ScopedProfiler() + { + qDebug() << m_msg << m_timer.elapsed(); + } + +private: + QTime m_timer; + QString m_msg; +}; + +#define PROFILE_SCOPE ScopedProfiler ___sp___(__func__) + +QAndroidPlatformScreen::QAndroidPlatformScreen():QObject(),QPlatformScreen() +{ + m_geometry = QRect(0, 0, QAndroidPlatformIntegration::m_defaultGeometryWidth, QAndroidPlatformIntegration::m_defaultGeometryHeight); + // Raster only apps should set QT_ANDROID_RASTER_IMAGE_DEPTH to 16 + // is way much faster than 32 + if (qgetenv("QT_ANDROID_RASTER_IMAGE_DEPTH").toInt() == 16) { + m_format = QImage::Format_RGB16; + m_depth = 16; + } else { + m_format = QImage::Format_RGBA8888; + m_depth = 32; + } + m_physicalSize.setHeight(QAndroidPlatformIntegration::m_defaultPhysicalSizeHeight); + m_physicalSize.setWidth(QAndroidPlatformIntegration::m_defaultPhysicalSizeWidth); + m_redrawTimer.setSingleShot(true); + m_redrawTimer.setInterval(0); + connect(&m_redrawTimer, SIGNAL(timeout()), this, SLOT(doRedraw())); +} + +QAndroidPlatformScreen::~QAndroidPlatformScreen() +{ + if (m_id != -1) { + QtAndroid::destroySurface(m_id); + m_surfaceWaitCondition.wakeOne(); + if (m_bitmap) + QtAndroid::AttachedJNIEnv().jniEnv->DeleteGlobalRef(m_bitmap); + } +} + +QWindow *QAndroidPlatformScreen::topWindow() const +{ + foreach (QAndroidPlatformWindow *w, m_windowStack) + if (w->window()->type() == Qt::Window || w->window()->type() == Qt::Dialog) + return w->window(); + return 0; +} + +QWindow *QAndroidPlatformScreen::topLevelAt(const QPoint &p) const +{ + foreach (QAndroidPlatformWindow *w, m_windowStack) { + if (w->geometry().contains(p, false) && w->window()->isVisible()) + return w->window(); + } + return 0; +} + +void QAndroidPlatformScreen::addWindow(QAndroidPlatformWindow *window) +{ + m_windowStack.prepend(window); + if (window->isRaster()) + setDirty(window->geometry()); + + QWindow *w = topWindow(); + QWindowSystemInterface::handleWindowActivated(w); + topWindowChanged(w); +} + +void QAndroidPlatformScreen::removeWindow(QAndroidPlatformWindow *window) +{ + m_windowStack.removeOne(window); + if (window->isRaster()) { + setDirty(window->geometry()); + } + QWindow *w = topWindow(); + QWindowSystemInterface::handleWindowActivated(w); + topWindowChanged(w); +} + +void QAndroidPlatformScreen::raise(QAndroidPlatformWindow *window) +{ + int index = m_windowStack.indexOf(window); + if (index <= 0) + return; + m_windowStack.move(index, 0); + if (window->isRaster()) { + setDirty(window->geometry()); + } + QWindow *w = topWindow(); + QWindowSystemInterface::handleWindowActivated(w); + topWindowChanged(w); +} + +void QAndroidPlatformScreen::lower(QAndroidPlatformWindow *window) +{ + int index = m_windowStack.indexOf(window); + if (index == -1 || index == (m_windowStack.size() - 1)) + return; + m_windowStack.move(index, m_windowStack.size() - 1); + if (window->isRaster()) { + setDirty(window->geometry()); + } + QWindow *w = topWindow(); + QWindowSystemInterface::handleWindowActivated(w); + topWindowChanged(w); +} + +void QAndroidPlatformScreen::scheduleUpdate() +{ + if (!m_redrawTimer.isActive()) + m_redrawTimer.start(); +} + +void QAndroidPlatformScreen::setDirty(const QRect &rect) +{ + QRect intersection = rect.intersected(m_geometry); + QPoint screenOffset = m_geometry.topLeft(); + m_repaintRegion += intersection.translated(-screenOffset); // global to local translation + scheduleUpdate(); +} + +void QAndroidPlatformScreen::setPhysicalSize(const QSize &size) +{ + m_physicalSize = size; +} + +void QAndroidPlatformScreen::setGeometry(const QRect &rect) +{ + QMutexLocker lock(&m_surfaceMutex); + if (m_geometry == rect) + return; + + m_geometry = rect; + QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), geometry()); + QWindowSystemInterface::handleScreenAvailableGeometryChange(QPlatformScreen::screen(), availableGeometry()); + resizeMaximizedWindows(); + + if (m_id != -1) { + if (m_bitmap) { + QtAndroid::AttachedJNIEnv().jniEnv->DeleteGlobalRef(m_bitmap); + m_bitmap = 0; + } + QtAndroid::setSurfaceGeometry(m_id, rect); + } +} + +void QAndroidPlatformScreen::topWindowChanged(QWindow *w) +{ + QtAndroidMenu::setActiveTopLevelWindow(w); + + if (w != 0) { + QAndroidPlatformWindow *platformWindow = static_cast<QAndroidPlatformWindow *>(w->handle()); + if (platformWindow != 0) + platformWindow->updateStatusBarVisibility(); + } +} + +void QAndroidPlatformScreen::doRedraw() +{ + PROFILE_SCOPE; + + if (m_repaintRegion.isEmpty()) + return; + + QVector<QRect> rects = m_repaintRegion.rects(); + + QMutexLocker lock(&m_surfaceMutex); + if (m_id == -1) { + m_id = QtAndroid::createSurface(this, m_geometry, true); + m_surfaceWaitCondition.wait(&m_surfaceMutex); + } + + if (!m_bitmap || !m_surface.isValid()) + return; + + QJNIEnvironmentPrivate env; + if (!env) + return; + + int ret; + void *pixels; + + if ((ret = AndroidBitmap_lockPixels(env, m_bitmap, &pixels)) < 0) { + qWarning() << "AndroidBitmap_lockPixels() failed! error=" << ret; + return; + } + + QImage mScreenImage(reinterpret_cast<uchar *>(pixels), m_bitmapWidth, m_bitmapHeight, m_bitmapStride, m_format); + QPainter mCompositePainter(&mScreenImage); + + for (int rectIndex = 0; rectIndex < rects.size(); rectIndex++) { + QRegion visibleRegion = rects[rectIndex]; + foreach (QAndroidPlatformWindow *window, m_windowStack) { + if (!window->window()->isVisible() + || !window->isRaster()) + continue; + + foreach (const QRect &rect, visibleRegion.rects()) { + QRect targetRect = window->geometry(); + targetRect &= rect; + + if (targetRect.isNull()) + continue; + + visibleRegion -= targetRect; + QRect windowRect = targetRect.translated(-window->geometry().topLeft()); + QAndroidPlatformBackingStore *backingStore = static_cast<QAndroidPlatformRasterWindow *>(window)->backingStore(); + if (backingStore) + mCompositePainter.drawImage(targetRect, backingStore->image(), windowRect); + } + } + + foreach (const QRect &rect, visibleRegion.rects()) + mCompositePainter.fillRect(rect, Qt::transparent); + } + + + QRect br = m_repaintRegion.boundingRect(); + m_repaintRegion = QRegion(); + AndroidBitmap_unlockPixels(env, m_bitmap); + + QJNIObjectPrivate jrect("android.graphics.Rect", "(IIII)V", + jint(br.left()), + jint(br.top()), + jint(br.right() + 1), + jint(br.bottom() + 1)); + + QJNIObjectPrivate canvas = m_surface.callObjectMethod("lockCanvas", + "(Landroid/graphics/Rect;)Landroid/graphics/Canvas;", + jrect.object()); + if (!canvas.isValid()) { + qWarning() << "Can't lockCanvas"; + return; + } + canvas.callMethod<void>("drawBitmap", + "(Landroid/graphics/Bitmap;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Paint;)V", + m_bitmap, jrect.object(), jrect.object(), jobject(0)); + + m_surface.callMethod<void>("unlockCanvasAndPost", "(Landroid/graphics/Canvas;)V", canvas.object()); +} + +QDpi QAndroidPlatformScreen::logicalDpi() const +{ + qreal lDpi = QtAndroid::scaledDensity() * 72; + return QDpi(lDpi, lDpi); +} + +Qt::ScreenOrientation QAndroidPlatformScreen::orientation() const +{ + return QAndroidPlatformIntegration::m_orientation; +} + +Qt::ScreenOrientation QAndroidPlatformScreen::nativeOrientation() const +{ + return QAndroidPlatformIntegration::m_nativeOrientation; +} + +void QAndroidPlatformScreen::surfaceChanged(JNIEnv *env, jobject surface, int w, int h) +{ + lockSurface(); + m_surface = surface; + + if (surface && w && h) { + if (w != m_bitmapWidth || h != m_bitmapHeight) { + if (m_bitmap) + env->DeleteGlobalRef(m_bitmap); + m_bitmap = env->NewGlobalRef(QtAndroid::createBitmap(w, h, m_format, env)); + AndroidBitmapInfo info; + int res = AndroidBitmap_getInfo(env, m_bitmap, &info); + Q_ASSERT(res > -1); + m_bitmapStride = info.stride; + m_bitmapWidth = info.width; + m_bitmapHeight = info.height; + } + } else { + if (m_bitmap) { + env->DeleteGlobalRef(m_bitmap); + m_bitmap = 0; + } + } + unlockSurface(); + m_surfaceWaitCondition.wakeOne(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidplatformscreen.h b/src/plugins/platforms/android/qandroidplatformscreen.h new file mode 100644 index 0000000000..2310b31a51 --- /dev/null +++ b/src/plugins/platforms/android/qandroidplatformscreen.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org> +** 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 QANDROIDPLATFORMSCREEN_H +#define QANDROIDPLATFORMSCREEN_H + +#include <qpa/qplatformscreen.h> +#include <QList> +#include <QPainter> +#include <QTimer> +#include <QWaitCondition> +#include <QtCore/private/qjni_p.h> + +#include "androidsurfaceclient.h" + +QT_BEGIN_NAMESPACE + +class QAndroidPlatformWindow; +class QAndroidPlatformBackingStore; + +class QAndroidPlatformScreen: public QObject, public QPlatformScreen, public AndroidSurfaceClient +{ + Q_OBJECT +public: + QAndroidPlatformScreen(); + ~QAndroidPlatformScreen(); + + QRect geometry() const { return m_geometry; } + int depth() const { return m_depth; } + QImage::Format format() const { return m_format; } + QSizeF physicalSize() const { return m_physicalSize; } + + inline QWindow *topWindow() const; + QWindow *topLevelAt(const QPoint & p) const; + + // compositor api + void addWindow(QAndroidPlatformWindow *window); + void removeWindow(QAndroidPlatformWindow *window); + void raise(QAndroidPlatformWindow *window); + void lower(QAndroidPlatformWindow *window); + + void scheduleUpdate(); + void topWindowChanged(QWindow *w); + +public slots: + void setDirty(const QRect &rect); + void setPhysicalSize(const QSize &size); + void setGeometry(const QRect &rect); + +protected: + typedef QList<QAndroidPlatformWindow *> WindowStackType; + WindowStackType m_windowStack; + QRegion m_repaintRegion; + QTimer m_redrawTimer; + + QRect m_geometry; + int m_depth; + QImage::Format m_format; + QSizeF m_physicalSize; + +private: + QDpi logicalDpi() const; + Qt::ScreenOrientation orientation() const; + Qt::ScreenOrientation nativeOrientation() const; + void surfaceChanged(JNIEnv *env, jobject surface, int w, int h); + +private slots: + void doRedraw(); + +private: + int m_id = -1; + QJNIObjectPrivate m_surface; + jobject m_bitmap = nullptr; + QWaitCondition m_surfaceWaitCondition; + int m_bitmapStride = -1; + int m_bitmapWidth = -1; + int m_bitmapHeight = -1; +}; + +QT_END_NAMESPACE +#endif diff --git a/src/plugins/platforms/android/src/qandroidplatformservices.cpp b/src/plugins/platforms/android/qandroidplatformservices.cpp index 0df882f1f0..0df882f1f0 100644 --- a/src/plugins/platforms/android/src/qandroidplatformservices.cpp +++ b/src/plugins/platforms/android/qandroidplatformservices.cpp diff --git a/src/plugins/platforms/android/src/qandroidplatformservices.h b/src/plugins/platforms/android/qandroidplatformservices.h index 8368b19043..8368b19043 100644 --- a/src/plugins/platforms/android/src/qandroidplatformservices.h +++ b/src/plugins/platforms/android/qandroidplatformservices.h diff --git a/src/plugins/platforms/android/src/qandroidplatformtheme.cpp b/src/plugins/platforms/android/qandroidplatformtheme.cpp index 308bb70faf..ab29541f15 100644 --- a/src/plugins/platforms/android/src/qandroidplatformtheme.cpp +++ b/src/plugins/platforms/android/qandroidplatformtheme.cpp @@ -46,6 +46,7 @@ #include "qandroidplatformdialoghelpers.h" #include <QVariant> #include <QFileInfo> +#include <QCoreApplication> #include <qandroidplatformintegration.h> QAndroidPlatformTheme::QAndroidPlatformTheme(QAndroidPlatformNativeInterface *androidPlatformNativeInterface) @@ -152,6 +153,21 @@ QVariant QAndroidPlatformTheme::themeHint(ThemeHint hint) const } } +QString QAndroidPlatformTheme::standardButtonText(int button) const +{ + switch (button) { + case QMessageDialogOptions::Yes: + return QCoreApplication::translate("QAndroidPlatformTheme", "Yes"); + case QMessageDialogOptions::YesToAll: + return QCoreApplication::translate("QAndroidPlatformTheme", "Yes to All"); + case QMessageDialogOptions::No: + return QCoreApplication::translate("QAndroidPlatformTheme", "No"); + case QMessageDialogOptions::NoToAll: + return QCoreApplication::translate("QAndroidPlatformTheme", "No to All"); + } + return QPlatformTheme::standardButtonText(button); +} + bool QAndroidPlatformTheme::usePlatformNativeDialog(QPlatformTheme::DialogType type) const { if (type == MessageDialog) diff --git a/src/plugins/platforms/android/src/qandroidplatformtheme.h b/src/plugins/platforms/android/qandroidplatformtheme.h index ec259a9b0a..544061a7a2 100644 --- a/src/plugins/platforms/android/src/qandroidplatformtheme.h +++ b/src/plugins/platforms/android/qandroidplatformtheme.h @@ -54,6 +54,7 @@ public: virtual const QPalette *palette(Palette type = SystemPalette) const; virtual const QFont *font(Font type = SystemFont) const; virtual QVariant themeHint(ThemeHint hint) const; + QString standardButtonText(int button) const Q_DECL_OVERRIDE; virtual bool usePlatformNativeDialog(DialogType type) const; virtual QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const; diff --git a/src/plugins/platforms/android/src/raster/qandroidplatformwindow.cpp b/src/plugins/platforms/android/qandroidplatformwindow.cpp index 7ff18526d9..7c2dfd6bac 100644 --- a/src/plugins/platforms/android/src/raster/qandroidplatformwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformwindow.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org> +** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org> +** 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. @@ -40,63 +41,117 @@ ****************************************************************************/ #include "qandroidplatformwindow.h" +#include "qandroidplatformopenglcontext.h" +#include "qandroidplatformscreen.h" #include "androidjnimain.h" #include <qpa/qwindowsysteminterface.h> +QT_BEGIN_NAMESPACE + QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window) - : QFbWindow(window) + : QPlatformWindow(window) { + m_windowFlags = Qt::Widget; + m_windowState = Qt::WindowNoState; + static QAtomicInt winIdGenerator(1); + m_windowId = winIdGenerator.fetchAndAddRelaxed(1); + setWindowState(window->windowState()); } -void QAndroidPlatformWindow::setGeometry(const QRect &rect) +void QAndroidPlatformWindow::lower() { - QFbWindow::setGeometry(rect); + platformScreen()->lower(this); } -void QAndroidPlatformWindow::propagateSizeHints() +void QAndroidPlatformWindow::raise() { - //shut up warning from default implementation + updateStatusBarVisibility(); + platformScreen()->raise(this); } -void QAndroidPlatformWindow::updateStatusBarVisibility() +void QAndroidPlatformWindow::setGeometry(const QRect &rect) { - Qt::WindowFlags flags = window()->flags(); - bool isNonRegularWindow = flags & (Qt::Popup | Qt::Dialog | Qt::Sheet) & ~Qt::Window; - if (!isNonRegularWindow) { - if (mWindowState & Qt::WindowFullScreen) - QtAndroid::hideStatusBar(); - else if (mWindowState & Qt::WindowMaximized) - QtAndroid::showStatusBar(); - } + QWindowSystemInterface::handleGeometryChange(window(), rect); + QPlatformWindow::setGeometry(rect); } -void QAndroidPlatformWindow::raise() +void QAndroidPlatformWindow::setVisible(bool visible) { - updateStatusBarVisibility(); - QFbWindow::raise(); + if (visible) + updateStatusBarVisibility(); + + if (visible) { + if (m_windowState & Qt::WindowFullScreen) + setGeometry(platformScreen()->geometry()); + else if (m_windowState & Qt::WindowMaximized) + setGeometry(platformScreen()->availableGeometry()); + } + + QPlatformWindow::setVisible(visible); + + if (visible) + platformScreen()->addWindow(this); + else + platformScreen()->removeWindow(this); + + // The Android Activity is activated before Qt is initialized, causing the application state to + // never be set to 'active'. We explicitly set this state when the first window becomes visible. + if (visible) + QtAndroid::setApplicationActive(); } void QAndroidPlatformWindow::setWindowState(Qt::WindowState state) { - if (mWindowState == state) + if (m_windowState == state) return; + QPlatformWindow::setWindowState(state); + m_windowState = state; + if (window()->isVisible()) updateStatusBarVisibility(); +} - QFbWindow::setWindowState(state); +void QAndroidPlatformWindow::setWindowFlags(Qt::WindowFlags flags) +{ + if (m_windowFlags == flags) + return; + + m_windowFlags = flags; } -void QAndroidPlatformWindow::setVisible(bool visible) +Qt::WindowFlags QAndroidPlatformWindow::windowFlags() const { - if (visible) - updateStatusBarVisibility(); + return m_windowFlags; +} - QFbWindow::setVisible(visible); +QAndroidPlatformScreen *QAndroidPlatformWindow::platformScreen() const +{ + return static_cast<QAndroidPlatformScreen *>(window()->screen()->handle()); +} - // The Android Activity is activated before Qt is initialized, causing the application state to - // never be set to 'active'. We explicitly set this state when the first window becomes visible. - if (visible) - QtAndroid::setApplicationActive(); +void QAndroidPlatformWindow::propagateSizeHints() +{ + //shut up warning from default implementation } + +void QAndroidPlatformWindow::requestActivateWindow() +{ + platformScreen()->topWindowChanged(window()); +} + +void QAndroidPlatformWindow::updateStatusBarVisibility() +{ + Qt::WindowFlags flags = window()->flags(); + bool isNonRegularWindow = flags & (Qt::Popup | Qt::Dialog | Qt::Sheet) & ~Qt::Window; + if (!isNonRegularWindow) { + if (m_windowState & Qt::WindowFullScreen) + QtAndroid::hideStatusBar(); + else if (m_windowState & Qt::WindowMaximized) + QtAndroid::showStatusBar(); + } +} + + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.h b/src/plugins/platforms/android/qandroidplatformwindow.h index e4ff0444d4..db3cb35368 100644 --- a/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.h +++ b/src/plugins/platforms/android/qandroidplatformwindow.h @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org> ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** @@ -39,53 +40,48 @@ ** ****************************************************************************/ -#ifndef QANDROIDOPENGLPLATFORMWINDOW_H -#define QANDROIDOPENGLPLATFORMWINDOW_H - -#include "qeglfswindow.h" -#include <QtCore/qmutex.h> -#include <QtCore/qreadwritelock.h> +#ifndef ANDROIDPLATFORMWINDOW_H +#define ANDROIDPLATFORMWINDOW_H +#include <qobject.h> +#include <qrect.h> +#include <qpa/qplatformwindow.h> QT_BEGIN_NAMESPACE -class QAndroidOpenGLPlatformWindow : public QEglFSWindow +class QAndroidPlatformScreen; + +class QAndroidPlatformWindow: public QPlatformWindow { public: - QAndroidOpenGLPlatformWindow(QWindow *window); - ~QAndroidOpenGLPlatformWindow(); - - 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; + explicit QAndroidPlatformWindow(QWindow *window); + void lower(); void raise(); - void invalidateSurface(); - void resetSurface(); + void setVisible(bool visible); + void setWindowState(Qt::WindowState state); + void setWindowFlags(Qt::WindowFlags flags); + Qt::WindowFlags windowFlags() const; - void setVisible(bool visible); + WId winId() const { return m_windowId; } - void destroy(); + QAndroidPlatformScreen *platformScreen() const; - static void updateStaticNativeWindow(); + void propagateSizeHints(); + void requestActivateWindow(); void updateStatusBarVisibility(); + inline bool isRaster() const { return window()->surfaceType() == QSurface::RasterSurface; } -private: - QSize m_scheduledResize; - QMutex m_lock; - Qt::WindowState m_state; +protected: + void setGeometry(const QRect &rect); - static QReadWriteLock m_staticSurfaceLock; - static EGLSurface m_staticSurface; - static EGLNativeWindowType m_staticNativeWindow; - static QBasicAtomicInt m_referenceCount; +protected: + Qt::WindowFlags m_windowFlags; + Qt::WindowState m_windowState; + + WId m_windowId; }; QT_END_NAMESPACE - -#endif // QANDROIDOPENGLPLATFORMWINDOW_H +#endif // ANDROIDPLATFORMWINDOW_H diff --git a/src/plugins/platforms/android/src/qandroidsystemlocale.cpp b/src/plugins/platforms/android/qandroidsystemlocale.cpp index a20f970a44..a20f970a44 100644 --- a/src/plugins/platforms/android/src/qandroidsystemlocale.cpp +++ b/src/plugins/platforms/android/qandroidsystemlocale.cpp diff --git a/src/plugins/platforms/android/src/qandroidsystemlocale.h b/src/plugins/platforms/android/qandroidsystemlocale.h index fc2f6fad98..fc2f6fad98 100644 --- a/src/plugins/platforms/android/src/qandroidsystemlocale.h +++ b/src/plugins/platforms/android/qandroidsystemlocale.h diff --git a/src/plugins/platforms/android/raster/raster.pro b/src/plugins/platforms/android/raster/raster.pro deleted file mode 100644 index 53d8ee7a2b..0000000000 --- a/src/plugins/platforms/android/raster/raster.pro +++ /dev/null @@ -1,19 +0,0 @@ -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/opengl/qandroidopenglplatformwindow.cpp b/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.cpp deleted file mode 100644 index 6ed805174b..0000000000 --- a/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/**************************************************************************** -** -** 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 "qandroidplatformintegration.h" -#include <qpa/qwindowsysteminterface.h> - -QT_BEGIN_NAMESPACE - -EGLSurface QAndroidOpenGLPlatformWindow::m_staticSurface = 0; -EGLNativeWindowType QAndroidOpenGLPlatformWindow::m_staticNativeWindow = 0; -QReadWriteLock QAndroidOpenGLPlatformWindow::m_staticSurfaceLock; -QBasicAtomicInt QAndroidOpenGLPlatformWindow::m_referenceCount = Q_BASIC_ATOMIC_INITIALIZER(0); - -QAndroidOpenGLPlatformWindow::QAndroidOpenGLPlatformWindow(QWindow *window) - : QEglFSWindow(window) - , m_state(Qt::WindowNoState) -{ -} - -QAndroidOpenGLPlatformWindow::~QAndroidOpenGLPlatformWindow() -{ - destroy(); -} - -bool QAndroidOpenGLPlatformWindow::isExposed() const -{ - return QtAndroid::nativeWindow(false) != 0 && QEglFSWindow::isExposed(); -} - -void QAndroidOpenGLPlatformWindow::invalidateSurface() -{ - QWindowSystemInterface::handleExposeEvent(window(), QRegion()); // Obscure event - QWindowSystemInterface::flushWindowSystemEvents(); - - m_window = 0; - m_surface = 0; - - if (!m_referenceCount.deref()){ - QWriteLocker locker(&m_staticSurfaceLock); - - EGLDisplay display = (static_cast<QEglFSScreen *>(window()->screen()->handle()))->display(); - eglDestroySurface(display, m_staticSurface); - - m_staticSurface = 0; - m_staticNativeWindow = 0; - } -} - -void QAndroidOpenGLPlatformWindow::updateStaticNativeWindow() -{ - QWriteLocker locker(&m_staticSurfaceLock); - m_staticNativeWindow = QtAndroid::nativeWindow(false); -} - -void QAndroidOpenGLPlatformWindow::resetSurface() -{ - // Only add a reference if we're not already holding one, otherwise we're just updating - // the native window pointer - if (m_window == 0) - m_referenceCount.ref(); - - if (m_staticSurface == 0) { - QWriteLocker locker(&m_staticSurfaceLock); - QEglFSWindow::resetSurface(); - m_staticSurface = m_surface; - m_staticNativeWindow = m_window; - } else { - QReadLocker locker(&m_staticSurfaceLock); - m_window = m_staticNativeWindow; - m_surface = m_staticSurface; - } - - { - lock(); - // Use the desktop size. - // On some devices, the getters for the native window size gives wrong values - scheduleResize(QAndroidPlatformIntegration::defaultDesktopSize()); - QWindowSystemInterface::handleExposeEvent(window(), QRegion(geometry())); // Expose event - unlock(); - } - - QWindowSystemInterface::flushWindowSystemEvents(); -} - -void QAndroidOpenGLPlatformWindow::destroy() -{ - if (!m_referenceCount.deref()) { - QEglFSWindow::destroy(); - } else { - m_window = 0; - m_surface = 0; - } -} - -void QAndroidOpenGLPlatformWindow::updateStatusBarVisibility() -{ - Qt::WindowFlags flags = window()->flags(); - bool isNonRegularWindow = flags & (Qt::Popup | Qt::Dialog | Qt::Sheet) & ~Qt::Window; - if (!isNonRegularWindow) { - if (m_state & Qt::WindowFullScreen) - QtAndroid::hideStatusBar(); - else if (m_state & Qt::WindowMaximized) - QtAndroid::showStatusBar(); - } -} - -void QAndroidOpenGLPlatformWindow::raise() -{ - updateStatusBarVisibility(); -} - -void QAndroidOpenGLPlatformWindow::setWindowState(Qt::WindowState state) -{ - if (m_state == state) - return; - - m_state = state; - if (window()->isVisible()) - updateStatusBarVisibility(); -} - -void QAndroidOpenGLPlatformWindow::setVisible(bool visible) -{ - if (visible) - updateStatusBarVisibility(); - - QEglFSWindow::setVisible(visible); - - // The Android Activity is activated before Qt is initialized, causing the application state to - // never be set to 'active'. We explicitly set this state when the first window becomes visible. - if (visible) - QtAndroid::setApplicationActive(); - - QWindowSystemInterface::handleExposeEvent(window(), QRegion(geometry())); // Expose event - QWindowSystemInterface::flushWindowSystemEvents(); -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/src/opengl/qeglfshooks_android.cpp b/src/plugins/platforms/android/src/opengl/qeglfshooks_android.cpp deleted file mode 100644 index 278cd553f4..0000000000 --- a/src/plugins/platforms/android/src/opengl/qeglfshooks_android.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/**************************************************************************** -** -** 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; - QDpi logicalDpi() const; - Qt::ScreenOrientation orientation() const; - Qt::ScreenOrientation nativeOrientation() const; - int screenDepth() const; - QSurfaceFormat surfaceFormatFor(const QSurfaceFormat &inputFormat) const; - EGLNativeWindowType createNativeWindow(QPlatformWindow *platformWindow, const QSize &size, const QSurfaceFormat &format); - void destroyNativeWindow(EGLNativeWindowType window); - bool hasCapability(QPlatformIntegration::Capability cap) const; - QEglFSCursor *createCursor(QEglFSScreen *screen) const; -}; - -void QEglFSAndroidHooks::platformInit() -{ -} - -void QEglFSAndroidHooks::platformDestroy() -{ -} - -EGLNativeDisplayType QEglFSAndroidHooks::platformDisplay() const -{ - return EGL_DEFAULT_DISPLAY; -} - -QSize QEglFSAndroidHooks::screenSize() const -{ - return QAndroidPlatformIntegration::defaultDesktopSize(); -} - -QSizeF QEglFSAndroidHooks::physicalScreenSize() const -{ - return QSizeF(QAndroidPlatformIntegration::m_defaultPhysicalSizeWidth, QAndroidPlatformIntegration::m_defaultPhysicalSizeHeight); -} - -QDpi QEglFSAndroidHooks::logicalDpi() const -{ - qreal lDpi = QtAndroid::scaledDensity() * 72; - return QDpi(lDpi, lDpi); -} - -Qt::ScreenOrientation QEglFSAndroidHooks::orientation() const -{ - return QAndroidPlatformIntegration::m_orientation; -} - -Qt::ScreenOrientation QEglFSAndroidHooks::nativeOrientation() const -{ - return QAndroidPlatformIntegration::m_nativeOrientation; -} - -EGLNativeWindowType QEglFSAndroidHooks::createNativeWindow(QPlatformWindow *platformWindow, const QSize &size, const QSurfaceFormat &format) -{ - Q_UNUSED(platformWindow); - Q_UNUSED(size); - Q_UNUSED(format); - ANativeWindow *window = QtAndroid::nativeWindow(); - if (window != 0) - ANativeWindow_acquire(window); - - return window; -} - -void QEglFSAndroidHooks::destroyNativeWindow(EGLNativeWindowType window) -{ - if (window != 0) - 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; -} - -QEglFSCursor *QEglFSAndroidHooks::createCursor(QEglFSScreen *screen) const -{ - Q_UNUSED(screen); - return 0; -} - -static QEglFSAndroidHooks eglFSAndroidHooks; -QEglFSHooks *platformHooks = &eglFSAndroidHooks; - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/src/raster/qandroidplatformscreen.cpp b/src/plugins/platforms/android/src/raster/qandroidplatformscreen.cpp deleted file mode 100644 index 2e59c307c3..0000000000 --- a/src/plugins/platforms/android/src/raster/qandroidplatformscreen.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/**************************************************************************** -** -** 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" -#include "qandroidplatformwindow.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); - - if (w != 0) { - QAndroidPlatformWindow *platformWindow = static_cast<QAndroidPlatformWindow *>(w->handle()); - if (platformWindow != 0) - platformWindow->updateStatusBarVisibility(); - } -} - -QRegion QAndroidPlatformScreen::doRedraw() -{ - QRegion touched; - touched = QFbScreen::doRedraw(); - if (touched.isEmpty()) - return touched; - - QtAndroid::flushImage(mGeometry.topLeft(), *mScreenImage, touched.boundingRect()); - return touched; -} - -QDpi QAndroidPlatformScreen::logicalDpi() const -{ - qreal lDpi = QtAndroid::scaledDensity() * 72; - return QDpi(lDpi, lDpi); -} - -Qt::ScreenOrientation QAndroidPlatformScreen::orientation() const -{ - return QAndroidPlatformIntegration::m_orientation; -} - -Qt::ScreenOrientation QAndroidPlatformScreen::nativeOrientation() const -{ - return QAndroidPlatformIntegration::m_nativeOrientation; -} diff --git a/src/plugins/platforms/android/src/raster/raster.pri b/src/plugins/platforms/android/src/raster/raster.pri deleted file mode 100644 index 86e5aa235f..0000000000 --- a/src/plugins/platforms/android/src/raster/raster.pri +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index 9b64e846f7..0000000000 --- a/src/plugins/platforms/android/src/src.pri +++ /dev/null @@ -1,55 +0,0 @@ -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/androidjniaccessibility.cpp \ - $$PWD/androidjniinput.cpp \ - $$PWD/androidjnimenu.cpp \ - $$PWD/androidjniclipboard.cpp \ - $$PWD/qandroidplatformintegration.cpp \ - $$PWD/qandroidplatformservices.cpp \ - $$PWD/qandroidassetsfileenginehandler.cpp \ - $$PWD/qandroidinputcontext.cpp \ - $$PWD/qandroidplatformaccessibility.cpp \ - $$PWD/qandroidplatformfontdatabase.cpp \ - $$PWD/qandroidplatformdialoghelpers.cpp \ - $$PWD/qandroidplatformclipboard.cpp \ - $$PWD/qandroidplatformtheme.cpp \ - $$PWD/qandroidplatformmenubar.cpp \ - $$PWD/qandroidplatformmenu.cpp \ - $$PWD/qandroidplatformmenuitem.cpp \ - $$PWD/qandroidsystemlocale.cpp - - -HEADERS += $$PWD/qandroidplatformintegration.h \ - $$PWD/androidjnimain.h \ - $$PWD/androidjniaccessibility.h \ - $$PWD/androidjniinput.h \ - $$PWD/androidjnimenu.h \ - $$PWD/androidjniclipboard.h \ - $$PWD/qandroidplatformservices.h \ - $$PWD/qandroidassetsfileenginehandler.h \ - $$PWD/qandroidinputcontext.h \ - $$PWD/qandroidplatformaccessibility.h \ - $$PWD/qandroidplatformfontdatabase.h \ - $$PWD/qandroidplatformclipboard.h \ - $$PWD/qandroidplatformdialoghelpers.h \ - $$PWD/qandroidplatformtheme.h \ - $$PWD/qandroidplatformmenubar.h \ - $$PWD/qandroidplatformmenu.h \ - $$PWD/qandroidplatformmenuitem.h \ - $$PWD/qandroidsystemlocale.h - - -#Non-standard install directory, QTBUG-29859 -DESTDIR = $$DESTDIR/android -target.path = $${target.path}/android diff --git a/src/plugins/platforms/cocoa/messages.cpp b/src/plugins/platforms/cocoa/messages.cpp index 3db1618a50..1fe80b28b1 100644 --- a/src/plugins/platforms/cocoa/messages.cpp +++ b/src/plugins/platforms/cocoa/messages.cpp @@ -93,4 +93,9 @@ QPlatformMenuItem::MenuRole detectMenuRole(const QString &caption) return QPlatformMenuItem::NoRole; } +QString msgDialogButtonDiscard() +{ + return QCoreApplication::translate("QCocoaTheme", "Don't Save"); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/messages.h b/src/plugins/platforms/cocoa/messages.h index 09705c1e21..97f3ea7009 100644 --- a/src/plugins/platforms/cocoa/messages.h +++ b/src/plugins/platforms/cocoa/messages.h @@ -53,6 +53,8 @@ QString qt_mac_applicationmenu_string(int type); QPlatformMenuItem::MenuRole detectMenuRole(const QString &caption); +QString msgDialogButtonDiscard(); + QT_END_NAMESPACE #endif // MESSAGES_H diff --git a/src/plugins/platforms/cocoa/qcocoaapplication.h b/src/plugins/platforms/cocoa/qcocoaapplication.h index ffb12ea846..bb218bcabe 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplication.h +++ b/src/plugins/platforms/cocoa/qcocoaapplication.h @@ -86,7 +86,7 @@ // /* - Cocoa Application Categories + Cocoa Application Categories */ #include "qglobal.h" #include "private/qcore_mac_p.h" diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm index 8f74a71b1e..4b637a707d 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -143,7 +143,7 @@ QCocoaGLContext::QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLCo [pixelFormat release]; - const GLint interval = 1; + const GLint interval = format.swapInterval() >= 0 ? format.swapInterval() : 1; [m_context setValues:&interval forParameter:NSOpenGLCPSwapInterval]; if (format.alphaBufferSize() > 0) { diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h index 3e402673f3..64e1640a69 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.h +++ b/src/plugins/platforms/cocoa/qcocoahelpers.h @@ -116,6 +116,7 @@ inline NSPoint qt_mac_flipPoint(const QPoint &p) inline NSPoint qt_mac_flipPoint(const QPointF &p) { return NSMakePoint(p.x(), qt_mac_flipYCoordinate(p.y())); } +NSRect qt_mac_flipRect(const QRect &rect); NSRect qt_mac_flipRect(const QRect &rect, QWindow *window); Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum); diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm index 4a5696b35e..d27c134fa3 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.mm +++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm @@ -585,6 +585,12 @@ QString qt_mac_applicationName() return appName; } +NSRect qt_mac_flipRect(const QRect &rect) +{ + int flippedY = qt_mac_flipYCoordinate(rect.y() + rect.height()); + return NSMakeRect(rect.x(), flippedY, rect.width(), rect.height()); +} + /* 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 diff --git a/src/plugins/platforms/cocoa/qcocoatheme.h b/src/plugins/platforms/cocoa/qcocoatheme.h index e4237c9b3e..d60cdf10d1 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.h +++ b/src/plugins/platforms/cocoa/qcocoatheme.h @@ -73,6 +73,7 @@ public: QPlatformTheme::IconOptions options = 0) const; QVariant themeHint(ThemeHint hint) const; + QString standardButtonText(int button) const Q_DECL_OVERRIDE; static const char *name; diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm index d863861288..109649f24e 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.mm +++ b/src/plugins/platforms/cocoa/qcocoatheme.mm @@ -42,6 +42,7 @@ #import <Cocoa/Cocoa.h> #include "qcocoatheme.h" +#include "messages.h" #include <QtCore/QVariant> @@ -300,6 +301,11 @@ QVariant QCocoaTheme::themeHint(ThemeHint hint) const return QPlatformTheme::themeHint(hint); } +QString QCocoaTheme::standardButtonText(int button) const +{ + return button == QMessageDialogOptions::Discard ? msgDialogButtonDiscard() : QPlatformTheme::standardButtonText(button); +} + QPlatformMenuItem *QCocoaTheme::createPlatformMenuItem() const { return new QCocoaMenuItem(); diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index 66c3241b3d..c20773601d 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -220,6 +220,11 @@ public: // for QNSView bool m_drawContentBorderGradient; int m_topContentBorderThickness; int m_bottomContentBorderThickness; + + // used by showFullScreen in fake mode + QRect m_normalGeometry; + Qt::WindowFlags m_oldWindowFlags; + NSApplicationPresentationOptions m_presentationOptions; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 8e977236fa..f62a6d29ce 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -223,6 +223,7 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw) , m_drawContentBorderGradient(false) , m_topContentBorderThickness(0) , m_bottomContentBorderThickness(0) + , m_normalGeometry(QRect(0,0,-1,-1)) { #ifdef QT_COCOA_ENABLE_WINDOW_DEBUG qDebug() << "QCocoaWindow::QCocoaWindow" << this; @@ -274,8 +275,16 @@ QSurfaceFormat QCocoaWindow::format() const return window()->requestedFormat(); } -void QCocoaWindow::setGeometry(const QRect &rect) +void QCocoaWindow::setGeometry(const QRect &rectIn) { + QRect rect = rectIn; + // This means it is a call from QWindow::setFramePosition() and + // the coordinates include the frame (size is still the contents rectangle). + if (qt_window_private(const_cast<QWindow *>(window()))->positionPolicy + == QWindowPrivate::WindowFrameInclusive) { + const QMargins margins = frameMargins(); + rect.moveTopLeft(rect.topLeft() + QPoint(margins.left(), margins.top())); + } if (geometry() == rect) return; #ifdef QT_COCOA_ENABLE_WINDOW_DEBUG @@ -1021,13 +1030,35 @@ void QCocoaWindow::syncWindowState(Qt::WindowState newState) } if ((m_synchedWindowState & Qt::WindowFullScreen) != (newState & Qt::WindowFullScreen)) { + bool fakeFullScreen = true; #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { - [m_nsWindow toggleFullScreen : m_nsWindow]; - } else { - // TODO: "normal" fullscreen + if (window()->flags() & Qt::WindowFullscreenButtonHint) { + fakeFullScreen = false; + [m_nsWindow toggleFullScreen : m_nsWindow]; + } } #endif + if (fakeFullScreen) { + if (newState & Qt::WindowFullScreen) { + QScreen *screen = window()->screen(); + if (screen) { + if (m_normalGeometry.width() < 0) { + m_oldWindowFlags = m_windowFlags; + window()->setFlags(window()->flags() | Qt::FramelessWindowHint); + m_normalGeometry = windowGeometry(); + setGeometry(screen->geometry()); + m_presentationOptions = [NSApp presentationOptions]; + [NSApp setPresentationOptions : m_presentationOptions | NSApplicationPresentationAutoHideMenuBar | NSApplicationPresentationAutoHideDock]; + } + } + } else { + window()->setFlags(m_oldWindowFlags); + setGeometry(m_normalGeometry); + m_normalGeometry.setRect(0, 0, -1, -1); + [NSApp setPresentationOptions : m_presentationOptions]; + } + } } // New state is now the current synched state diff --git a/src/plugins/platforms/direct2d/direct2d.json b/src/plugins/platforms/direct2d/direct2d.json new file mode 100644 index 0000000000..aaea92f0ef --- /dev/null +++ b/src/plugins/platforms/direct2d/direct2d.json @@ -0,0 +1,3 @@ +{ + "Keys": [ "direct2d" ] +} diff --git a/src/plugins/platforms/direct2d/direct2d.pro b/src/plugins/platforms/direct2d/direct2d.pro new file mode 100644 index 0000000000..5a1e71b962 --- /dev/null +++ b/src/plugins/platforms/direct2d/direct2d.pro @@ -0,0 +1,39 @@ +TARGET = qdirect2d + +PLUGIN_TYPE = platforms +PLUGIN_CLASS_NAME = QWindowsDirect2DIntegrationPlugin +load(qt_plugin) + +QT *= core-private +QT *= gui-private +QT *= platformsupport-private + +LIBS *= -ld2d1 -ld3d11 -ldwrite + +include(../windows/windows.pri) + +SOURCES += \ + qwindowsdirect2dpaintengine.cpp \ + qwindowsdirect2dpaintdevice.cpp \ + qwindowsdirect2dplatformpixmap.cpp \ + qwindowsdirect2dcontext.cpp \ + qwindowsdirect2dbitmap.cpp \ + qwindowsdirect2dbackingstore.cpp \ + qwindowsdirect2dintegration.cpp \ + qwindowsdirect2dplatformplugin.cpp \ + qwindowsdirect2ddevicecontext.cpp \ + qwindowsdirect2dnativeinterface.cpp + +HEADERS += \ + qwindowsdirect2dpaintengine.h \ + qwindowsdirect2dpaintdevice.h \ + qwindowsdirect2dplatformpixmap.h \ + qwindowsdirect2dcontext.h \ + qwindowsdirect2dhelpers.h \ + qwindowsdirect2dbitmap.h \ + qwindowsdirect2dbackingstore.h \ + qwindowsdirect2dintegration.h \ + qwindowsdirect2ddevicecontext.h \ + qwindowsdirect2dnativeinterface.h + +OTHER_FILES += direct2d.json diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp new file mode 100644 index 0000000000..379e75c26e --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp @@ -0,0 +1,239 @@ +/**************************************************************************** +** +** 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 "qwindowsdirect2dbackingstore.h" +#include "qwindowsdirect2dintegration.h" +#include "qwindowsdirect2dcontext.h" +#include "qwindowsdirect2dpaintdevice.h" +#include "qwindowsdirect2dbitmap.h" +#include "qwindowsdirect2ddevicecontext.h" + +#include "qwindowswindow.h" +#include "qwindowscontext.h" + +#include <QtGui/QWindow> +#include <QtCore/QDebug> + +#include <dxgi1_2.h> +#include <d3d11.h> +#include <wrl.h> + +using Microsoft::WRL::ComPtr; + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DBackingStorePrivate +{ +public: + QWindowsDirect2DBackingStorePrivate() {} + + ComPtr<IDXGISwapChain1> swapChain; + QSharedPointer<QWindowsDirect2DBitmap> backingStore; + QScopedPointer<QWindowsDirect2DPaintDevice> nativePaintDevice; + + bool init(HWND hwnd) + { + DXGI_SWAP_CHAIN_DESC1 desc = {}; + + desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + desc.SampleDesc.Count = 1; + desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + desc.BufferCount = 1; + desc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL; + + HRESULT hr = QWindowsDirect2DContext::instance()->dxgiFactory()->CreateSwapChainForHwnd( + QWindowsDirect2DContext::instance()->d3dDevice(), // [in] IUnknown *pDevice + hwnd, // [in] HWND hWnd + &desc, // [in] const DXGI_SWAP_CHAIN_DESC1 *pDesc + NULL, // [in] const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *pFullscreenDesc + NULL, // [in] IDXGIOutput *pRestrictToOutput + swapChain.ReleaseAndGetAddressOf()); // [out] IDXGISwapChain1 **ppSwapChain + + if (FAILED(hr)) + qWarning("%s: Could not create swap chain: %#x", __FUNCTION__, hr); + + return SUCCEEDED(hr); + } + + bool setupPaintDevice() + { + if (!backingStore) { + ComPtr<ID2D1DeviceContext> deviceContext; + ComPtr<IDXGISurface1> backBufferSurface; + ComPtr<ID2D1Bitmap1> backBufferBitmap; + + HRESULT hr = QWindowsDirect2DContext::instance()->d2dDevice()->CreateDeviceContext( + D2D1_DEVICE_CONTEXT_OPTIONS_NONE, + deviceContext.ReleaseAndGetAddressOf()); + if (FAILED(hr)) { + qWarning("%s: Couldn't create Direct2D Device context: %#x", __FUNCTION__, hr); + return false; + } + + hr = swapChain->GetBuffer(0, IID_PPV_ARGS(&backBufferSurface)); + if (FAILED(hr)) { + qWarning("%s: Could not query backbuffer for DXGI Surface: %#x", __FUNCTION__, hr); + return false; + } + + hr = deviceContext->CreateBitmapFromDxgiSurface(backBufferSurface.Get(), NULL, backBufferBitmap.ReleaseAndGetAddressOf()); + if (FAILED(hr)) { + qWarning("%s: Could not create Direct2D Bitmap from DXGI Surface: %#x", __FUNCTION__, hr); + return false; + } + + backingStore.reset(new QWindowsDirect2DBitmap(backBufferBitmap.Get(), deviceContext.Get())); + } + + if (!nativePaintDevice) + nativePaintDevice.reset(new QWindowsDirect2DPaintDevice(backingStore.data(), QInternal::Widget)); + + return true; + } + + void releaseBackingStore() + { + nativePaintDevice.reset(); + backingStore.reset(); + } + + QPaintDevice *paintDevice() + { + setupPaintDevice(); + return nativePaintDevice.data(); + } + + void flush() + { + swapChain->Present(1, 0); + } +}; + +/*! + \class QWindowsDirect2DBackingStore + \brief Backing store for windows. + \internal + \ingroup qt-lighthouse-win +*/ + +QWindowsDirect2DBackingStore::QWindowsDirect2DBackingStore(QWindow *window) + : QPlatformBackingStore(window) + , d_ptr(new QWindowsDirect2DBackingStorePrivate) +{ +} + +bool QWindowsDirect2DBackingStore::init() +{ + if (window()->surfaceType() == QSurface::RasterSurface) { + Q_D(QWindowsDirect2DBackingStore); + return d->init(windowsWindow()->handle()); + } + + return true; +} + +QWindowsDirect2DBackingStore *QWindowsDirect2DBackingStore::create(QWindow *window) +{ + QWindowsDirect2DBackingStore *result = new QWindowsDirect2DBackingStore(window); + + if (!result->init()) { + delete result; + result = 0; + } + + return result; +} + +QWindowsDirect2DBackingStore::~QWindowsDirect2DBackingStore() +{ + Q_D(QWindowsDirect2DBackingStore); + d->releaseBackingStore(); + d->swapChain.Reset(); +} + +QPaintDevice *QWindowsDirect2DBackingStore::paintDevice() +{ + QPaintDevice *result = 0; + + if (window()->surfaceType() == QSurface::RasterSurface) { + Q_D(QWindowsDirect2DBackingStore); + result = d->paintDevice(); + } + + return result; +} + +void QWindowsDirect2DBackingStore::flush(QWindow *, const QRegion &, const QPoint &) +{ + if (window()->surfaceType() == QSurface::RasterSurface) { + Q_D(QWindowsDirect2DBackingStore); + d->flush(); + } +} + +void QWindowsDirect2DBackingStore::resize(const QSize &size, const QRegion ®ion) +{ + Q_UNUSED(region); + + if (window()->surfaceType() != QSurface::RasterSurface) + return; + + Q_D(QWindowsDirect2DBackingStore); + d->releaseBackingStore(); + QWindowsDirect2DContext::instance()->d3dDeviceContext()->ClearState(); + + HRESULT hr = d->swapChain->ResizeBuffers(0, + size.width(), size.height(), + DXGI_FORMAT_UNKNOWN, + 0); + if (FAILED(hr)) + qWarning("%s: Could not resize buffers: %#x", __FUNCTION__, hr); +} + +QWindowsWindow *QWindowsDirect2DBackingStore::windowsWindow() const +{ + if (const QWindow *w = window()) + if (QPlatformWindow *pw = w->handle()) + return static_cast<QWindowsWindow *>(pw); + return 0; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h new file mode 100644 index 0000000000..89ecee67dd --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** 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 QWINDOWSDIRECT2DBACKINGSTORE_H +#define QWINDOWSDIRECT2DBACKINGSTORE_H + +#include <QtCore/QScopedPointer> +#include <QtGui/qpa/qplatformbackingstore.h> + +QT_BEGIN_NAMESPACE + +class QWindowsWindow; +class QWindowsDirect2DBackingStorePrivate; + +class QWindowsDirect2DBackingStore : public QPlatformBackingStore +{ + Q_DECLARE_PRIVATE(QWindowsDirect2DBackingStore) + Q_DISABLE_COPY(QWindowsDirect2DBackingStore) + +public: + static QWindowsDirect2DBackingStore *create(QWindow *window); + ~QWindowsDirect2DBackingStore(); + + QPaintDevice *paintDevice() Q_DECL_OVERRIDE; + void flush(QWindow *, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE; + void resize(const QSize &size, const QRegion &staticContents) Q_DECL_OVERRIDE; + +private: + QWindowsDirect2DBackingStore(QWindow *window); + bool init(); + + QWindowsWindow *windowsWindow() const; + QScopedPointer<QWindowsDirect2DBackingStorePrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSDIRECT2DBACKINGSTORE_H diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp new file mode 100644 index 0000000000..85c56bc73e --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp @@ -0,0 +1,205 @@ +/**************************************************************************** +** +** 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 "qwindowsdirect2dbitmap.h" +#include "qwindowsdirect2dcontext.h" +#include "qwindowsdirect2dhelpers.h" +#include "qwindowsdirect2ddevicecontext.h" + +#include <QtGui/QImage> +#include <QtGui/QColor> + +#include <wrl.h> + +using Microsoft::WRL::ComPtr; + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DBitmapPrivate +{ +public: + QWindowsDirect2DBitmapPrivate(ID2D1DeviceContext *dc = 0, ID2D1Bitmap1 *bm = 0) + : bitmap(bm) + , deviceContext(new QWindowsDirect2DDeviceContext(dc)) + { + deviceContext->get()->SetTarget(bm); + } + + D2D1_BITMAP_PROPERTIES1 bitmapProperties() const + { + FLOAT dpiX, dpiY; + QWindowsDirect2DContext::instance()->d2dFactory()->GetDesktopDpi(&dpiX, &dpiY); + + return D2D1::BitmapProperties1( + D2D1_BITMAP_OPTIONS_TARGET, + D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, + D2D1_ALPHA_MODE_PREMULTIPLIED), + dpiX, dpiY); + + } + + bool resize(int width, int height, const void *data = 0, int pitch = 0) + { + deviceContext->get()->SetTarget(0); + bitmap.Reset(); + + D2D1_SIZE_U size = { + width, height + }; + + HRESULT hr = deviceContext->get()->CreateBitmap(size, data, pitch, + bitmapProperties(), + bitmap.ReleaseAndGetAddressOf()); + if (SUCCEEDED(hr)) + deviceContext->get()->SetTarget(bitmap.Get()); + else + qWarning("%s: Could not create bitmap: %#x", __FUNCTION__, hr); + + return SUCCEEDED(hr); + } + + QImage toImage(const QRect &rect) + { + if (!bitmap) + return QImage(); + + ComPtr<ID2D1Bitmap1> mappingCopy; + + HRESULT hr = S_OK; + D2D1_SIZE_U size = bitmap->GetPixelSize(); + + D2D1_BITMAP_PROPERTIES1 properties = bitmapProperties(); + properties.bitmapOptions = D2D1_BITMAP_OPTIONS_CANNOT_DRAW | D2D1_BITMAP_OPTIONS_CPU_READ; + + hr = deviceContext->get()->CreateBitmap(size, NULL, NULL, + properties, &mappingCopy); + if (FAILED(hr)) { + qWarning("%s: Could not create bitmap: %#x", __FUNCTION__, hr); + return QImage(); + } + + hr = mappingCopy->CopyFromBitmap(NULL, bitmap.Get(), NULL); + if (FAILED(hr)) { + qWarning("%s: Could not copy from bitmap: %#x", __FUNCTION__, hr); + return QImage(); + } + + D2D1_MAPPED_RECT mappedRect; + hr = mappingCopy->Map(D2D1_MAP_OPTIONS_READ, &mappedRect); + if (FAILED(hr)) { + qWarning("%s: Could not map: %#x", __FUNCTION__, hr); + return QImage(); + } + + return QImage(static_cast<const uchar *>(mappedRect.bits), + size.width, size.height, mappedRect.pitch, + QImage::Format_ARGB32_Premultiplied).copy(rect); + } + + QScopedPointer<QWindowsDirect2DDeviceContext> deviceContext; + ComPtr<ID2D1Bitmap1> bitmap; +}; + +QWindowsDirect2DBitmap::QWindowsDirect2DBitmap() + : d_ptr(new QWindowsDirect2DBitmapPrivate) +{ +} + +QWindowsDirect2DBitmap::QWindowsDirect2DBitmap(ID2D1Bitmap1 *bitmap, ID2D1DeviceContext *dc) + : d_ptr(new QWindowsDirect2DBitmapPrivate(dc, bitmap)) +{ +} + +QWindowsDirect2DBitmap::~QWindowsDirect2DBitmap() +{ +} + +bool QWindowsDirect2DBitmap::resize(int width, int height) +{ + Q_D(QWindowsDirect2DBitmap); + return d->resize(width, height); +} + +bool QWindowsDirect2DBitmap::fromImage(const QImage &image, Qt::ImageConversionFlags flags) +{ + Q_D(QWindowsDirect2DBitmap); + + QImage converted = image.convertToFormat(QImage::Format_ARGB32_Premultiplied, flags); + return d->resize(converted.width(), converted.height(), + converted.constBits(), converted.bytesPerLine()); +} + +ID2D1Bitmap1* QWindowsDirect2DBitmap::bitmap() const +{ + Q_D(const QWindowsDirect2DBitmap); + return d->bitmap.Get(); +} + +QWindowsDirect2DDeviceContext *QWindowsDirect2DBitmap::deviceContext() const +{ + Q_D(const QWindowsDirect2DBitmap); + return d->deviceContext.data(); +} + +void QWindowsDirect2DBitmap::fill(const QColor &color) +{ + Q_D(QWindowsDirect2DBitmap); + + d->deviceContext->begin(); + d->deviceContext->get()->Clear(to_d2d_color_f(color)); + d->deviceContext->end(); +} + +QImage QWindowsDirect2DBitmap::toImage(const QRect &rect) +{ + Q_D(QWindowsDirect2DBitmap); + return d->toImage(rect); +} + +QSize QWindowsDirect2DBitmap::size() const +{ + Q_D(const QWindowsDirect2DBitmap); + + D2D1_SIZE_U size = d->bitmap->GetPixelSize(); + return QSize(size.width, size.height); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.h b/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.h new file mode 100644 index 0000000000..d7015ef342 --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** 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 QWINDOWSDIRECT2DBITMAP_H +#define QWINDOWSDIRECT2DBITMAP_H + +#include <QtCore/QScopedPointer> +#include <QtGui/QImage> + +struct ID2D1DeviceContext; +struct ID2D1Bitmap1; + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DDeviceContext; +class QWindowsDirect2DBitmapPrivate; +class QWindowsDirect2DBitmap +{ + Q_DECLARE_PRIVATE(QWindowsDirect2DBitmap) + Q_DISABLE_COPY(QWindowsDirect2DBitmap) +public: + QWindowsDirect2DBitmap(); + QWindowsDirect2DBitmap(ID2D1Bitmap1 *bitmap, ID2D1DeviceContext *dc); + ~QWindowsDirect2DBitmap(); + + bool resize(int width, int height); + bool fromImage(const QImage &image, Qt::ImageConversionFlags flags); + + ID2D1Bitmap1* bitmap() const; + QWindowsDirect2DDeviceContext* deviceContext() const; + + void fill(const QColor &color); + QImage toImage(const QRect &rect = QRect()); + + QSize size() const; + +private: + QScopedPointer<QWindowsDirect2DBitmapPrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSDIRECT2DBITMAP_H diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.cpp new file mode 100644 index 0000000000..58002fb0dd --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.cpp @@ -0,0 +1,218 @@ +/**************************************************************************** +** +** 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 "qwindowsdirect2dcontext.h" +#include "qwindowsdirect2dhelpers.h" +#include "qwindowsdirect2dintegration.h" + +#include <d3d11_1.h> +#include <d2d1_1.h> +#include <d2d1_1helper.h> +#include <dxgi1_2.h> +#include <wrl.h> +#include <dwrite.h> + +using Microsoft::WRL::ComPtr; + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DContextPrivate +{ +public: + bool init() + { + HRESULT hr; + + D3D_FEATURE_LEVEL level; + + D3D_DRIVER_TYPE typeAttempts[] = { + D3D_DRIVER_TYPE_HARDWARE, + D3D_DRIVER_TYPE_WARP + }; + const int ntypes = int(sizeof(typeAttempts) / sizeof(typeAttempts[0])); + + for (int i = 0; i < ntypes; i++) { + hr = D3D11CreateDevice(NULL, + typeAttempts[i], + NULL, + D3D11_CREATE_DEVICE_SINGLETHREADED | D3D11_CREATE_DEVICE_BGRA_SUPPORT, + NULL, + 0, + D3D11_SDK_VERSION, + &d3dDevice, + &level, + &d3dDeviceContext); + + if (SUCCEEDED(hr)) + break; + } + + if (FAILED(hr)) { + qWarning("%s: Could not create Direct3D Device: %#x", __FUNCTION__, hr); + return false; + } + + ComPtr<IDXGIDevice> dxgiDevice; + ComPtr<IDXGIAdapter> dxgiAdapter; + + hr = d3dDevice.As(&dxgiDevice); + if (FAILED(hr)) { + qWarning("%s: DXGI Device interface query failed on D3D Device: %#x", __FUNCTION__, hr); + return false; + } + + hr = dxgiDevice->GetParent(IID_PPV_ARGS(&dxgiAdapter)); + if (FAILED(hr)) { + qWarning("%s: Failed to probe DXGI Device for parent DXGI Adapter: %#x", __FUNCTION__, hr); + return false; + } + + hr = dxgiAdapter->GetParent(IID_PPV_ARGS(&dxgiFactory)); + if (FAILED(hr)) { + qWarning("%s: Failed to probe DXGI Adapter for parent DXGI Factory: %#x", __FUNCTION__, hr); + return false; + } + + D2D1_FACTORY_OPTIONS options = {}; + +#ifdef QT_D2D_DEBUG_OUTPUT + qDebug("Turning on Direct2D debugging messages"); + options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION; +#endif // QT_D2D_DEBUG_OUTPUT + + hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, options, d2dFactory.GetAddressOf()); + if (FAILED(hr)) { + qWarning("%s: Could not create Direct2D Factory: %#x", __FUNCTION__, hr); + return false; + } + + hr = d2dFactory->CreateDevice(dxgiDevice.Get(), &d2dDevice); + if (FAILED(hr)) { + qWarning("%s: Could not create D2D Device: %#x", __FUNCTION__, hr); + return false; + } + + hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), + static_cast<IUnknown **>(&directWriteFactory)); + if (FAILED(hr)) { + qWarning("%s: Could not create DirectWrite factory: %#x", __FUNCTION__, hr); + return false; + } + + hr = directWriteFactory->GetGdiInterop(&directWriteGdiInterop); + if (FAILED(hr)) { + qWarning("%s: Could not create DirectWrite GDI Interop: %#x", __FUNCTION__, hr); + return false; + } + + return true; + } + + ComPtr<ID3D11Device> d3dDevice; + ComPtr<ID2D1Factory1> d2dFactory; + ComPtr<ID2D1Device> d2dDevice; + ComPtr<IDXGIFactory2> dxgiFactory; + ComPtr<ID3D11DeviceContext> d3dDeviceContext; + ComPtr<IDWriteFactory> directWriteFactory; + ComPtr<IDWriteGdiInterop> directWriteGdiInterop; +}; + +QWindowsDirect2DContext::QWindowsDirect2DContext() + : d_ptr(new QWindowsDirect2DContextPrivate) +{ +} + +QWindowsDirect2DContext::~QWindowsDirect2DContext() {} + +bool QWindowsDirect2DContext::init() +{ + Q_D(QWindowsDirect2DContext); + return d->init(); +} + +QWindowsDirect2DContext *QWindowsDirect2DContext::instance() +{ + return QWindowsDirect2DIntegration::instance()->direct2DContext(); +} + +ID3D11Device *QWindowsDirect2DContext::d3dDevice() const +{ + Q_D(const QWindowsDirect2DContext); + return d->d3dDevice.Get(); +} + +ID2D1Device *QWindowsDirect2DContext::d2dDevice() const +{ + Q_D(const QWindowsDirect2DContext); + return d->d2dDevice.Get(); +} + +ID2D1Factory1 *QWindowsDirect2DContext::d2dFactory() const +{ + Q_D(const QWindowsDirect2DContext); + return d->d2dFactory.Get(); +} + +IDXGIFactory2 *QWindowsDirect2DContext::dxgiFactory() const +{ + Q_D(const QWindowsDirect2DContext); + return d->dxgiFactory.Get(); +} + +ID3D11DeviceContext *QWindowsDirect2DContext::d3dDeviceContext() const +{ + Q_D(const QWindowsDirect2DContext); + return d->d3dDeviceContext.Get(); +} + +IDWriteFactory *QWindowsDirect2DContext::dwriteFactory() const +{ + Q_D(const QWindowsDirect2DContext); + return d->directWriteFactory.Get(); +} + +IDWriteGdiInterop *QWindowsDirect2DContext::dwriteGdiInterop() const +{ + Q_D(const QWindowsDirect2DContext); + return d->directWriteGdiInterop.Get(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.h b/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.h new file mode 100644 index 0000000000..0025463dd5 --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** 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 QWINDOWSDIRECT2DCONTEXT_H +#define QWINDOWSDIRECT2DCONTEXT_H + +#include <QtCore/QScopedPointer> + +struct ID3D11Device; +struct ID2D1Device; +struct ID2D1Factory1; +struct IDXGIFactory2; +struct ID3D11DeviceContext; +struct IDWriteFactory; +struct IDWriteGdiInterop; + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DContextPrivate; +class QWindowsDirect2DContext +{ + Q_DECLARE_PRIVATE( QWindowsDirect2DContext ) + +public: + QWindowsDirect2DContext(); + virtual ~QWindowsDirect2DContext(); + + bool init(); + + static QWindowsDirect2DContext *instance(); + + ID3D11Device *d3dDevice() const; + ID2D1Device *d2dDevice() const; + ID2D1Factory1 *d2dFactory() const; + IDXGIFactory2 *dxgiFactory() const; + ID3D11DeviceContext *d3dDeviceContext() const; + IDWriteFactory *dwriteFactory() const; + IDWriteGdiInterop *dwriteGdiInterop() const; + +private: + QScopedPointer<QWindowsDirect2DContextPrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSDIRECT2DCONTEXT_H diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.cpp new file mode 100644 index 0000000000..3ff4c9e636 --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.cpp @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** 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 "qwindowsdirect2dcontext.h" +#include "qwindowsdirect2dhelpers.h" +#include "qwindowsdirect2ddevicecontext.h" + +#include <wrl.h> + +using Microsoft::WRL::ComPtr; + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DDeviceContextPrivate { +public: + QWindowsDirect2DDeviceContextPrivate(ID2D1DeviceContext *dc) + : deviceContext(dc) + , refCount(0) + { + if (!dc) { + HRESULT hr = QWindowsDirect2DContext::instance()->d2dDevice()->CreateDeviceContext( + D2D1_DEVICE_CONTEXT_OPTIONS_NONE, + &deviceContext); + if (FAILED(hr)) + qFatal("%s: Couldn't create Direct2D Device Context: %#x", __FUNCTION__, hr); + } + + Q_ASSERT(deviceContext); + } + + void begin() + { + Q_ASSERT(deviceContext); + Q_ASSERT(refCount >= 0); + + if (refCount == 0) + deviceContext->BeginDraw(); + + refCount++; + } + + bool end() + { + Q_ASSERT(deviceContext); + Q_ASSERT(refCount >= 0); + + bool success = true; + refCount--; + + if (refCount == 0) { + D2D1_TAG tag1, tag2; + HRESULT hr = deviceContext->EndDraw(&tag1, &tag2); + + if (FAILED(hr)) { + success = false; + qWarning("%s: EndDraw failed: %#x, tag1: %lld, tag2: %lld", __FUNCTION__, hr, tag1, tag2); + } + } + + return success; + } + + ComPtr<ID2D1DeviceContext> deviceContext; + int refCount; +}; + +QWindowsDirect2DDeviceContext::QWindowsDirect2DDeviceContext(ID2D1DeviceContext *dc) + : d_ptr(new QWindowsDirect2DDeviceContextPrivate(dc)) +{ +} + +QWindowsDirect2DDeviceContext::~QWindowsDirect2DDeviceContext() +{ + +} + +ID2D1DeviceContext *QWindowsDirect2DDeviceContext::get() const +{ + Q_D(const QWindowsDirect2DDeviceContext); + Q_ASSERT(d->deviceContext); + + return d->deviceContext.Get(); +} + +void QWindowsDirect2DDeviceContext::begin() +{ + Q_D(QWindowsDirect2DDeviceContext); + d->begin(); +} + +bool QWindowsDirect2DDeviceContext::end() +{ + Q_D(QWindowsDirect2DDeviceContext); + return d->end(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.h b/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.h new file mode 100644 index 0000000000..4986efb967 --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** 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 QWINDOWSDIRECT2DDEVICECONTEXT_H +#define QWINDOWSDIRECT2DDEVICECONTEXT_H + +#include "qwindowsdirect2dhelpers.h" + +#include <QtCore/QScopedPointer> + +QT_BEGIN_NAMESPACE + +/* + * Convenience class for handling device contexts. We have to call BeginDraw + * before anything can happen, and EndDraw once we're done, for every frame and + * pretty much any kind of operation. + * + * Unfortunately, these calls cannot be interleaved, and there is no way to check + * what state a device context is in. + * + * The end result is that the following throws an error if we don't track it: + * QPixmap pmap; + * QPainter painter(&pmap); + * pmap.clear(); + * + * Here BeginDraw would first be called through the paint device, then when we clear + * the pixmap we would have to call it again. There is no way to know what state + * the device context is in when performing the clear, and activating the dc is an + * error. Bummer. + * + * Hence we keep a reference count here and only activate/deactivate the device + * if the refcount is zero. + * + * In a nutshell: Do not call BeginDraw/EndDraw yourself on the device pointer, do + * so through the begin/end members below. + */ + +class QWindowsDirect2DDeviceContextPrivate; +class QWindowsDirect2DDeviceContext +{ + Q_DECLARE_PRIVATE(QWindowsDirect2DDeviceContext) +public: + QWindowsDirect2DDeviceContext(ID2D1DeviceContext *dc); + ~QWindowsDirect2DDeviceContext(); + + ID2D1DeviceContext *get() const; + + void begin(); + bool end(); + +private: + QScopedPointer<QWindowsDirect2DDeviceContextPrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSDIRECT2DDEVICECONTEXT_H diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h b/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h new file mode 100644 index 0000000000..0ca26ca4cb --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h @@ -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$ +** +****************************************************************************/ + +#ifndef QWINDOWSDIRECT2DHELPERS_H +#define QWINDOWSDIRECT2DHELPERS_H + +#include <QtCore/QRectF> +#include <QtCore/QSizeF> +#include <QtCore/QPointF> +#include <QtGui/QColor> +#include <QtGui/QTransform> + +#include <d2d1_1helper.h> + +QT_BEGIN_NAMESPACE + +Q_DECL_CONSTEXPR inline D2D1_RECT_U to_d2d_rect_u(const QRect &qrect) +{ + return D2D1::RectU(qrect.left(), qrect.top(), qrect.right(), qrect.bottom()); +} + +Q_DECL_CONSTEXPR inline D2D1_RECT_F to_d2d_rect_f(const QRectF &qrect) +{ + return D2D1::RectF(qrect.left(), qrect.top(), qrect.right(), qrect.bottom()); +} + +Q_DECL_CONSTEXPR inline D2D1_SIZE_U to_d2d_size_u(const QSizeF &qsize) +{ + return D2D1::SizeU(qsize.width(), qsize.height()); +} + +Q_DECL_CONSTEXPR inline D2D1_SIZE_U to_d2d_size_u(const QSize &qsize) +{ + return D2D1::SizeU(qsize.width(), qsize.height()); +} + +Q_DECL_CONSTEXPR inline D2D1_POINT_2F to_d2d_point_2f(const QPointF &qpoint) +{ + return D2D1::Point2F(qpoint.x(), qpoint.y()); +} + +Q_DECL_CONSTEXPR inline D2D1::ColorF to_d2d_color_f(const QColor &c) +{ + return D2D1::ColorF(c.redF(), c.greenF(), c.blueF(), c.alphaF()); +} + +Q_DECL_CONSTEXPR inline D2D1_MATRIX_3X2_F to_d2d_matrix_3x2_f(const QTransform &transform) +{ + Q_ASSERT(transform.isAffine()); + + return D2D1::Matrix3x2F(transform.m11(), transform.m12(), + transform.m21(), transform.m22(), + transform.m31(), transform.m32()); +} + +QT_END_NAMESPACE + +#endif // QWINDOWSDIRECT2DHELPERS_H diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp new file mode 100644 index 0000000000..c2f3c05bde --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** 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 "qwindowsdirect2dcontext.h" +#include "qwindowsdirect2dintegration.h" +#include "qwindowsdirect2dbackingstore.h" +#include "qwindowsdirect2dplatformpixmap.h" +#include "qwindowsdirect2dnativeinterface.h" + +#include "qwindowscontext.h" + +#include <QtCore/QDebug> +#include <QtGui/private/qpixmap_raster_p.h> + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DIntegrationPrivate +{ +public: + QWindowsDirect2DNativeInterface m_nativeInterface; + QWindowsDirect2DContext m_d2dContext; +}; + +QWindowsDirect2DIntegration *QWindowsDirect2DIntegration::create(const QStringList ¶mList) +{ + QWindowsDirect2DIntegration *integration = new QWindowsDirect2DIntegration(paramList); + + if (!integration->init()) { + delete integration; + integration = 0; + } + + return integration; +} + +QWindowsDirect2DIntegration::~QWindowsDirect2DIntegration() +{ + +} + + QWindowsDirect2DIntegration *QWindowsDirect2DIntegration::instance() + { + return static_cast<QWindowsDirect2DIntegration *>(QWindowsIntegration::instance()); + } + + QPlatformNativeInterface *QWindowsDirect2DIntegration::nativeInterface() const + { + return &d->m_nativeInterface; + } + +QPlatformPixmap *QWindowsDirect2DIntegration::createPlatformPixmap(QPlatformPixmap::PixelType type) const +{ + switch (type) { + case QPlatformPixmap::BitmapType: + return new QRasterPlatformPixmap(type); + break; + default: + return new QWindowsDirect2DPlatformPixmap(type); + break; + } +} + +QPlatformBackingStore *QWindowsDirect2DIntegration::createPlatformBackingStore(QWindow *window) const +{ + return QWindowsDirect2DBackingStore::create(window); +} + +QWindowsDirect2DContext *QWindowsDirect2DIntegration::direct2DContext() const +{ + return &d->m_d2dContext; +} + +QWindowsDirect2DIntegration::QWindowsDirect2DIntegration(const QStringList ¶mList) + : QWindowsIntegration(paramList) + , d(new QWindowsDirect2DIntegrationPrivate) +{ +} + +bool QWindowsDirect2DIntegration::init() +{ + return d->m_d2dContext.init(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.h b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.h new file mode 100644 index 0000000000..12412cbc0f --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.h @@ -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$ +** +****************************************************************************/ + +#ifndef QWINDOWSDIRECT2DINTEGRATION_H +#define QWINDOWSDIRECT2DINTEGRATION_H + +#include "qwindowsintegration.h" + +#include <QtCore/QScopedPointer> + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DContext; +class QWindowsDirect2DIntegrationPrivate; + +class QWindowsDirect2DIntegration : public QWindowsIntegration +{ +public: + static QWindowsDirect2DIntegration *create(const QStringList ¶mList); + + virtual ~QWindowsDirect2DIntegration(); + + static QWindowsDirect2DIntegration *instance(); + + QPlatformNativeInterface *nativeInterface() const Q_DECL_OVERRIDE; + QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const Q_DECL_OVERRIDE; + QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const Q_DECL_OVERRIDE; + + QWindowsDirect2DContext *direct2DContext() const; + +private: + explicit QWindowsDirect2DIntegration(const QStringList ¶mList); + bool init(); + + QScopedPointer<QWindowsDirect2DIntegrationPrivate> d; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSDIRECT2DINTEGRATION_H diff --git a/src/plugins/platforms/ios/qiossoftwareinputhandler.h b/src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.cpp index 5dad6b8d86..6792d92de5 100644 --- a/src/plugins/platforms/ios/qiossoftwareinputhandler.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.cpp @@ -39,33 +39,26 @@ ** ****************************************************************************/ -#ifndef QIOSSOFTWAREINPUTHANDLER_H -#define QIOSSOFTWAREINPUTHANDLER_H +#include "qwindowsdirect2dnativeinterface.h" -#include <QtCore/QObject> -#include <QtCore/QPointer> -#include <QtWidgets/QWidget> +#include <QtGui/QBackingStore> QT_BEGIN_NAMESPACE -class QIOSSoftwareInputHandler : public QObject +void *QWindowsDirect2DNativeInterface::nativeResourceForBackingStore(const QByteArray &resource, QBackingStore *bs) { - Q_OBJECT + if (!bs || !bs->handle()) { + qWarning("%s: '%s' requested for null backingstore or backingstore without handle.", __FUNCTION__, resource.constData()); + return 0; + } -public: - QIOSSoftwareInputHandler() : m_CurrentFocusWidget(0), m_CurrentFocusObject(0) {} - bool eventFilter(QObject *obj, QEvent *event); + // getDC is so common we don't want to print an "invalid key" line for it + if (resource == "getDC") + return 0; -private slots: - void activeFocusChanged(bool focus); + qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData()); + return 0; -private: - bool closeSoftwareInputPanel(QWidget *widget); - - QPointer<QWidget> m_currentFocusWidget; - QPointer<QObject> m_currentFocusObject; -}; +} QT_END_NAMESPACE - -#endif diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.h b/src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.h new file mode 100644 index 0000000000..ee3f7f6eed --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dnativeinterface.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** 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 QWINDOWSDIRECT2DNATIVEINTERFACE_H +#define QWINDOWSDIRECT2DNATIVEINTERFACE_H + +#include "qwindowsnativeinterface.h" + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DNativeInterface : public QWindowsNativeInterface +{ + Q_OBJECT +public: + void *nativeResourceForBackingStore(const QByteArray &resource, QBackingStore *bs) Q_DECL_OVERRIDE; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSDIRECT2DNATIVEINTERFACE_H diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp new file mode 100644 index 0000000000..85dbaab2ce --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** 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 "qwindowsdirect2dpaintdevice.h" +#include "qwindowsdirect2dpaintengine.h" +#include "qwindowsdirect2dcontext.h" +#include "qwindowsdirect2dhelpers.h" +#include "qwindowsdirect2dbitmap.h" +#include "qwindowsdirect2ddevicecontext.h" + +#include "qwindowswindow.h" + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DPaintDevicePrivate +{ +public: + QWindowsDirect2DPaintDevicePrivate(QWindowsDirect2DBitmap *bitmap, QInternal::PaintDeviceFlags f) + : engine(new QWindowsDirect2DPaintEngine(bitmap)) + , bitmap(bitmap) + , flags(f) + {} + + QScopedPointer<QWindowsDirect2DPaintEngine> engine; + QWindowsDirect2DBitmap *bitmap; + QInternal::PaintDeviceFlags flags; +}; + +QWindowsDirect2DPaintDevice::QWindowsDirect2DPaintDevice(QWindowsDirect2DBitmap *bitmap, QInternal::PaintDeviceFlags flags) + : d_ptr(new QWindowsDirect2DPaintDevicePrivate(bitmap, flags)) +{ +} + +QPaintEngine *QWindowsDirect2DPaintDevice::paintEngine() const +{ + Q_D(const QWindowsDirect2DPaintDevice); + + return d->engine.data(); +} + +int QWindowsDirect2DPaintDevice::devType() const +{ + Q_D(const QWindowsDirect2DPaintDevice); + + return d->flags; +} + +int QWindowsDirect2DPaintDevice::metric(QPaintDevice::PaintDeviceMetric metric) const +{ + Q_D(const QWindowsDirect2DPaintDevice); + + switch (metric) { + case QPaintDevice::PdmWidth: + return d->bitmap->bitmap()->GetPixelSize().width; + break; + case QPaintDevice::PdmHeight: + return d->bitmap->bitmap()->GetPixelSize().height; + break; + case QPaintDevice::PdmNumColors: + return INT_MAX; + break; + case QPaintDevice::PdmDepth: + return 32; + break; + case QPaintDevice::PdmDpiX: + case QPaintDevice::PdmPhysicalDpiX: + { + FLOAT x, y; + QWindowsDirect2DContext::instance()->d2dFactory()->GetDesktopDpi(&x, &y); + return x; + } + break; + case QPaintDevice::PdmDpiY: + case QPaintDevice::PdmPhysicalDpiY: + { + FLOAT x, y; + QWindowsDirect2DContext::instance()->d2dFactory()->GetDesktopDpi(&x, &y); + return y; + } + break; + case QPaintDevice::PdmDevicePixelRatio: + return 1; + break; + case QPaintDevice::PdmWidthMM: + case QPaintDevice::PdmHeightMM: + return -1; + break; + } + + return -1; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.h b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.h new file mode 100644 index 0000000000..c799083d84 --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.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 QWINDOWSDIRECT2DPAINTDEVICE_H +#define QWINDOWSDIRECT2DPAINTDEVICE_H + +#include <QtCore/QScopedPointer> +#include <QtGui/QPaintDevice> + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DBitmap; + +class QWindowsDirect2DPaintDevicePrivate; +class QWindowsDirect2DPaintDevice : public QPaintDevice +{ + Q_DECLARE_PRIVATE(QWindowsDirect2DPaintDevice) + +public: + QWindowsDirect2DPaintDevice(QWindowsDirect2DBitmap *bitmap, QInternal::PaintDeviceFlags flags); + QPaintEngine *paintEngine() const Q_DECL_OVERRIDE; + int devType() const Q_DECL_OVERRIDE; + +protected: + int metric(PaintDeviceMetric metric) const Q_DECL_OVERRIDE; + +private: + QScopedPointer<QWindowsDirect2DPaintDevicePrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSDIRECT2DPAINTDEVICE_H diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp new file mode 100644 index 0000000000..aad3d192e7 --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp @@ -0,0 +1,1116 @@ +/**************************************************************************** +** +** 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 "qwindowsdirect2dpaintengine.h" +#include "qwindowsdirect2dplatformpixmap.h" +#include "qwindowsdirect2dpaintdevice.h" +#include "qwindowsdirect2dcontext.h" +#include "qwindowsdirect2dhelpers.h" +#include "qwindowsdirect2dbitmap.h" +#include "qwindowsdirect2ddevicecontext.h" + +#include "qwindowsfontengine.h" +#include "qwindowsfontenginedirectwrite.h" +#include "qwindowsfontdatabase.h" +#include "qwindowsintegration.h" + +#include <QtCore/QStack> +#include <QtGui/private/qpaintengine_p.h> +#include <QtGui/private/qtextengine_p.h> +#include <QtGui/private/qfontengine_p.h> + +#include <dwrite_1.h> +#include <wrl.h> + +using Microsoft::WRL::ComPtr; + +QT_BEGIN_NAMESPACE + +enum { + D2DDebugDrawInitialStateTag = -1, + D2DDebugDrawEllipseTag = 1, + D2DDebugDrawImageTag, + D2DDebugDrawLinesTag, + D2DDebugDrawPathTag, + D2DDebugDrawPixmapTag, + D2DDebugDrawPointsTag, + D2DDebugDrawPolygonTag, + D2DDebugDrawRectsTag, + D2DDebugDrawTextItemTag, + D2DDebugDrawTiledPixmap +}; +#define D2D_TAG(tag) d->dc()->SetTags(tag, tag) + +Q_GUI_EXPORT QImage qt_imageForBrush(int brushStyle, bool invert); + +static inline ID2D1Factory1 *factory() +{ + return QWindowsDirect2DContext::instance()->d2dFactory(); +} + +static const qreal defaultOpacity = 1.0; +static const qreal defaultPenWidth = 1.0; + +static ComPtr<ID2D1PathGeometry> painterPathToPathGeometry(const QPainterPath &path) +{ + ComPtr<ID2D1PathGeometry> geometry; + ComPtr<ID2D1GeometrySink> sink; + + HRESULT hr = factory()->CreatePathGeometry(&geometry); + if (FAILED(hr)) { + qWarning("%s: Could not create path geometry: %#x", __FUNCTION__, hr); + return NULL; + } + + hr = geometry->Open(&sink); + if (FAILED(hr)) { + qWarning("%s: Could not create geometry sink: %#x", __FUNCTION__, hr); + return NULL; + } + + switch (path.fillRule()) { + case Qt::WindingFill: + sink->SetFillMode(D2D1_FILL_MODE_WINDING); + break; + case Qt::OddEvenFill: + sink->SetFillMode(D2D1_FILL_MODE_ALTERNATE); + break; + } + + bool inFigure = false; + + for (int i = 0; i < path.elementCount(); i++) { + const QPainterPath::Element element = path.elementAt(i); + + switch (element.type) { + case QPainterPath::MoveToElement: + if (inFigure) + sink->EndFigure(D2D1_FIGURE_END_OPEN); + + sink->BeginFigure(to_d2d_point_2f(element), D2D1_FIGURE_BEGIN_FILLED); + inFigure = true; + break; + + case QPainterPath::LineToElement: + sink->AddLine(to_d2d_point_2f(element)); + break; + + case QPainterPath::CurveToElement: + { + const QPainterPath::Element data1 = path.elementAt(++i); + const QPainterPath::Element data2 = path.elementAt(++i); + + Q_ASSERT(i < path.elementCount()); + + Q_ASSERT(data1.type == QPainterPath::CurveToDataElement); + Q_ASSERT(data2.type == QPainterPath::CurveToDataElement); + + D2D1_BEZIER_SEGMENT segment; + + segment.point1 = to_d2d_point_2f(element); + segment.point2 = to_d2d_point_2f(data1); + segment.point3 = to_d2d_point_2f(data2); + + sink->AddBezier(segment); + } + break; + + case QPainterPath::CurveToDataElement: + qWarning("%s: Unhandled Curve Data Element", __FUNCTION__); + break; + } + } + + if (inFigure) + sink->EndFigure(D2D1_FIGURE_END_OPEN); + + sink->Close(); + + return geometry; +} + +static ComPtr<ID2D1PathGeometry> regionToPathGeometry(const QRegion ®ion) +{ + QPainterPath ppath; + ppath.addRegion(region); + return painterPathToPathGeometry(ppath); +} + +class QWindowsDirect2DPaintEnginePrivate : public QPaintEnginePrivate +{ + Q_DECLARE_PUBLIC(QWindowsDirect2DPaintEngine) +public: + QWindowsDirect2DPaintEnginePrivate(QWindowsDirect2DBitmap *bm) + : bitmap(bm) + , clipPushed(false) + , hasPerspectiveTransform(false) + , opacity(1.0) + , renderHints(QPainter::TextAntialiasing) + { + pen.reset(); + + HRESULT hr = factory()->CreateStrokeStyle(D2D1::StrokeStyleProperties(D2D1_CAP_STYLE_ROUND, + D2D1_CAP_STYLE_ROUND, + D2D1_CAP_STYLE_ROUND), + NULL, 0, + pointStrokeStyle.ReleaseAndGetAddressOf()); + if (FAILED(hr)) + qWarning("%s: Could not create stroke style for points and zero length lines: %#x", __FUNCTION__, hr); + + dc()->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED); + } + + QWindowsDirect2DBitmap *bitmap; + + QPainterPath clipPath; + bool clipPushed; + + ComPtr<ID2D1StrokeStyle> pointStrokeStyle; + QPointF currentBrushOrigin; + + bool hasPerspectiveTransform; + + qreal opacity; + + struct { + qreal width; + QColor color; + bool isNull; + ComPtr<ID2D1Brush> brush; + ComPtr<ID2D1StrokeStyle1> strokeStyle; + + inline void reset() { + width = defaultPenWidth; + color = QColor(Qt::black); + isNull = true; + brush.Reset(); + strokeStyle.Reset(); + } + } pen; + + struct { + ComPtr<ID2D1Brush> brush; + } brush; + + QPainter::RenderHints renderHints; + + inline ID2D1DeviceContext *dc() const + { + Q_ASSERT(bitmap); + return bitmap->deviceContext()->get(); + } + + inline D2D1_INTERPOLATION_MODE interpolationMode() const + { + return (renderHints & QPainter::SmoothPixmapTransform) ? D2D1_INTERPOLATION_MODE_HIGH_QUALITY_CUBIC + : D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR; + } + + inline D2D1_ANTIALIAS_MODE antialiasMode() const + { + return (renderHints & QPainter::Antialiasing) ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE + : D2D1_ANTIALIAS_MODE_ALIASED; + } + + void updateState(const QPaintEngineState &state, QPaintEngine::DirtyFlags dirty) + { + if (dirty & QPaintEngine::DirtyPen) + updatePen(state.pen()); + + if (dirty & QPaintEngine::DirtyBrush) + updateBrush(state.brush()); + + if (dirty & QPaintEngine::DirtyBrushOrigin) + updateBrushOrigin(state.brushOrigin()); + + if (dirty & QPaintEngine::DirtyHints) + updateHints(state.renderHints()); + + if (dirty & QPaintEngine::DirtyTransform) + updateTransform(state.transform()); + + if (dirty & QPaintEngine::DirtyClipEnabled) + updateClipEnabled(state.isClipEnabled()); + + if (dirty & QPaintEngine::DirtyClipPath) + updateClipPath(state.clipPath(), state.clipOperation()); + + if (dirty & QPaintEngine::DirtyClipRegion) + updateClipRegion(state.clipRegion(), state.clipOperation()); + + if (dirty & QPaintEngine::DirtyOpacity) + updateOpacity(state.opacity()); + } + + void updateTransform(const QTransform &t) + { + dc()->SetTransform(to_d2d_matrix_3x2_f(t)); + hasPerspectiveTransform = !t.isAffine(); + } + + void updateOpacity(qreal o) + { + opacity = o; + if (brush.brush) + brush.brush.Get()->SetOpacity(o); + if (pen.brush) + pen.brush.Get()->SetOpacity(o); + } + + void pushClip() + { + ComPtr<ID2D1Geometry> geometricMask = painterPathToPathGeometry(clipPath); + if (!geometricMask) { + qWarning("%s: Could not convert painter path, not pushing clip path!", __FUNCTION__); + return; + } + + popClip(); + dc()->PushLayer(D2D1::LayerParameters1(D2D1::InfiniteRect(), + geometricMask.Get(), + antialiasMode(), + D2D1::IdentityMatrix(), + 1.0, + NULL, + D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND), + NULL); + clipPushed = true; + } + + void popClip() + { + if (clipPushed) { + dc()->PopLayer(); + clipPushed = false; + } + } + + void updateClipEnabled(bool enabled) + { + if (!enabled) + popClip(); + else if (!clipPushed) + pushClip(); + } + + void updateClipPath(const QPainterPath &path, Qt::ClipOperation operation) + { + switch (operation) { + case Qt::NoClip: + popClip(); + break; + case Qt::ReplaceClip: + clipPath = path; + pushClip(); + break; + case Qt::IntersectClip: + clipPath &= path; + pushClip(); + break; + } + } + + void updateClipRegion(const QRegion ®ion, Qt::ClipOperation operation) + { + QPainterPath p; + p.addRegion(region); + updateClipPath(p, operation); + } + + void updateBrush(const QBrush &newBrush) + { + brush.brush = to_d2d_brush(newBrush); + if (brush.brush) { + brush.brush->SetOpacity(opacity); + applyBrushOrigin(currentBrushOrigin); + } + } + + void updateBrushOrigin(const QPointF &origin) + { + negateCurrentBrushOrigin(); + applyBrushOrigin(origin); + } + + void negateCurrentBrushOrigin() + { + if (brush.brush && !currentBrushOrigin.isNull()) { + D2D1_MATRIX_3X2_F transform; + brush.brush->GetTransform(&transform); + + brush.brush->SetTransform(*(D2D1::Matrix3x2F::ReinterpretBaseType(&transform)) + * D2D1::Matrix3x2F::Translation(-currentBrushOrigin.x(), + -currentBrushOrigin.y())); + } + } + + void applyBrushOrigin(const QPointF &origin) + { + if (brush.brush && !origin.isNull()) { + D2D1_MATRIX_3X2_F transform; + brush.brush->GetTransform(&transform); + + brush.brush->SetTransform(*(D2D1::Matrix3x2F::ReinterpretBaseType(&transform)) + * D2D1::Matrix3x2F::Translation(origin.x(), origin.y())); + } + + currentBrushOrigin = origin; + } + + void updatePen(const QPen &newPen) + { + pen.reset(); + + if (newPen.style() == Qt::NoPen) + return; + + pen.isNull = false; + pen.brush = to_d2d_brush(newPen.brush()); + if (!pen.brush) + return; + + pen.width = newPen.widthF(); + pen.color = newPen.color(); + pen.brush->SetOpacity(opacity); + + D2D1_STROKE_STYLE_PROPERTIES1 props = {}; + + // Try and match Qt's raster engine in output as closely as possible + switch (newPen.style()) { + case Qt::DotLine: + case Qt::DashDotLine: + case Qt::DashDotDotLine: + if (pen.width <= 1.0) { + props.startCap = props.endCap = props.dashCap = D2D1_CAP_STYLE_FLAT; + break; + } + // fall through + default: + switch (newPen.capStyle()) { + case Qt::SquareCap: + props.startCap = props.endCap = props.dashCap = D2D1_CAP_STYLE_SQUARE; + break; + case Qt::RoundCap: + props.startCap = props.endCap = props.dashCap = D2D1_CAP_STYLE_ROUND; + case Qt::FlatCap: + default: + props.startCap = props.endCap = props.dashCap = D2D1_CAP_STYLE_FLAT; + break; + } + break; + } + + switch (newPen.joinStyle()) { + case Qt::BevelJoin: + props.lineJoin = D2D1_LINE_JOIN_BEVEL; + break; + case Qt::RoundJoin: + props.lineJoin = D2D1_LINE_JOIN_ROUND; + break; + case Qt::MiterJoin: + default: + props.lineJoin = D2D1_LINE_JOIN_MITER; + break; + } + + props.miterLimit = newPen.miterLimit() * qreal(2.0); // D2D and Qt miter specs differ + props.dashOffset = newPen.dashOffset(); + props.transformType = qIsNull(newPen.widthF()) ? D2D1_STROKE_TRANSFORM_TYPE_HAIRLINE + : newPen.isCosmetic() ? D2D1_STROKE_TRANSFORM_TYPE_FIXED + : D2D1_STROKE_TRANSFORM_TYPE_NORMAL; + + switch (newPen.style()) { + case Qt::SolidLine: + props.dashStyle = D2D1_DASH_STYLE_SOLID; + break; + default: + props.dashStyle = D2D1_DASH_STYLE_CUSTOM; + break; + } + + HRESULT hr; + + if (props.dashStyle == D2D1_DASH_STYLE_CUSTOM) { + QVector<qreal> dashes = newPen.dashPattern(); + QVector<FLOAT> converted(dashes.size()); + + for (int i = 0; i < dashes.size(); i++) { + converted[i] = dashes[i]; + } + + hr = factory()->CreateStrokeStyle(props, converted.constData(), converted.size(), &(pen.strokeStyle)); + } else { + hr = factory()->CreateStrokeStyle(props, NULL, 0, &(pen.strokeStyle)); + } + + if (FAILED(hr)) + qWarning("%s: Could not create stroke style: %#x", __FUNCTION__, hr); + } + + ComPtr<ID2D1Brush> to_d2d_brush(const QBrush &newBrush) + { + HRESULT hr; + ComPtr<ID2D1Brush> result; + + switch (newBrush.style()) { + case Qt::NoBrush: + break; + + case Qt::SolidPattern: + { + ComPtr<ID2D1SolidColorBrush> solid; + + hr = dc()->CreateSolidColorBrush(to_d2d_color_f(newBrush.color()), &solid); + if (FAILED(hr)) { + qWarning("%s: Could not create solid color brush: %#x", __FUNCTION__, hr); + break; + } + + hr = solid.As(&result); + if (FAILED(hr)) + qWarning("%s: Could not convert solid color brush: %#x", __FUNCTION__, hr); + } + break; + + case Qt::Dense1Pattern: + case Qt::Dense2Pattern: + case Qt::Dense3Pattern: + case Qt::Dense4Pattern: + case Qt::Dense5Pattern: + case Qt::Dense6Pattern: + case Qt::Dense7Pattern: + case Qt::HorPattern: + case Qt::VerPattern: + case Qt::CrossPattern: + case Qt::BDiagPattern: + case Qt::FDiagPattern: + case Qt::DiagCrossPattern: + { + ComPtr<ID2D1BitmapBrush1> bitmapBrush; + D2D1_BITMAP_BRUSH_PROPERTIES1 bitmapBrushProperties = { + D2D1_EXTEND_MODE_WRAP, + D2D1_EXTEND_MODE_WRAP, + interpolationMode() + }; + + QImage brushImg = qt_imageForBrush(newBrush.style(), false); + brushImg.setColor(0, newBrush.color().rgba()); + brushImg.setColor(1, qRgba(0, 0, 0, 0)); + + QWindowsDirect2DBitmap bitmap; + bool success = bitmap.fromImage(brushImg, Qt::AutoColor); + if (!success) { + qWarning("%s: Could not create Direct2D bitmap from Qt pattern brush image", __FUNCTION__); + break; + } + + hr = dc()->CreateBitmapBrush(bitmap.bitmap(), + bitmapBrushProperties, + &bitmapBrush); + if (FAILED(hr)) { + qWarning("%s: Could not create Direct2D bitmap brush for Qt pattern brush: %#x", __FUNCTION__, hr); + break; + } + + hr = bitmapBrush.As(&result); + if (FAILED(hr)) + qWarning("%s: Could not convert Direct2D bitmap brush for Qt pattern brush: %#x", __FUNCTION__, hr); + } + break; + + case Qt::LinearGradientPattern: + case Qt::RadialGradientPattern: + case Qt::ConicalGradientPattern: + break; + + case Qt::TexturePattern: + { + ComPtr<ID2D1BitmapBrush1> bitmapBrush; + D2D1_BITMAP_BRUSH_PROPERTIES1 bitmapBrushProperties = { + D2D1_EXTEND_MODE_WRAP, + D2D1_EXTEND_MODE_WRAP, + interpolationMode() + }; + + QWindowsDirect2DPlatformPixmap *pp = static_cast<QWindowsDirect2DPlatformPixmap *>(newBrush.texture().handle()); + QWindowsDirect2DBitmap *bitmap = pp->bitmap(); + hr = dc()->CreateBitmapBrush(bitmap->bitmap(), + bitmapBrushProperties, + &bitmapBrush); + + if (FAILED(hr)) { + qWarning("%s: Could not create texture brush: %#x", __FUNCTION__, hr); + break; + } + + hr = bitmapBrush.As(&result); + if (FAILED(hr)) + qWarning("%s: Could not convert texture brush: %#x", __FUNCTION__, hr); + } + break; + } + + if (result && !newBrush.transform().isIdentity()) + result->SetTransform(to_d2d_matrix_3x2_f(newBrush.transform())); + + return result; + } + + void updateHints(QPainter::RenderHints newHints) + { + renderHints = newHints; + dc()->SetAntialiasMode(antialiasMode()); + } + + template <typename T> + void drawLines(const T* lines, int lineCount) + { + if (!pen.brush) + return; + + for (int i = 0; i < lineCount; i++) { + const T &line = lines[i]; + + // Try to fit Qt's and Direct2D's idea of zero length line + // handling together nicely. + + if (line.p1() == line.p2() && pen.strokeStyle.Get()->GetDashCap() != D2D1_CAP_STYLE_SQUARE) { + if (pen.width <= 1.0) { + dc()->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED); + // Note that we use pointStrokeStyle here, not the pen's stroke style! + dc()->DrawLine(to_d2d_point_2f(line.p1()), to_d2d_point_2f(line.p2()), pen.brush.Get(), pen.width, pointStrokeStyle.Get()); + dc()->SetAntialiasMode(antialiasMode()); + } + } else + dc()->DrawLine(to_d2d_point_2f(line.p1()), to_d2d_point_2f(line.p2()), pen.brush.Get(), pen.width, pen.strokeStyle.Get()); + } + } + + template <typename T> + void drawRects(const T* rects, int rectCount) + { + if (!brush.brush && !pen.brush) + return; + + for (int i = 0; i < rectCount; i++) { + if (brush.brush) + dc()->FillRectangle(to_d2d_rect_f(rects[i]), brush.brush.Get()); + + // Direct2D for some reason uses different geometry in FillRectangle and DrawRectangle. + // We have to adjust the rect right and down here by one pixel to paint the rectangle properly. + if (pen.brush) + dc()->DrawRectangle(to_d2d_rect_f(rects[i].adjusted(1, 1, 1, 1)), pen.brush.Get(), pen.width, pen.strokeStyle.Get()); + } + } + + template <typename T> + void drawPolygon(const T* points, int pointCount, QPaintEngine::PolygonDrawMode mode) + { + if (pointCount < 3) + return; + + if (!brush.brush && !pen.brush) + return; + + QVector<D2D1_POINT_2F> converted(pointCount); + for (int i = 0; i < pointCount; i++) { + const T &p = points[i]; + converted[i].x = p.x(); + converted[i].y = p.y(); + } + + drawPolygon(converted.constData(), converted.size(), mode); + } + + void drawPolygon(const D2D1_POINT_2F *points, int pointCount, QPaintEngine::PolygonDrawMode mode) + { + ComPtr<ID2D1PathGeometry> geometry; + ComPtr<ID2D1GeometrySink> sink; + const bool is_polyline = mode == QPaintEngine::PolylineMode; + + HRESULT hr = factory()->CreatePathGeometry(&geometry); + if (FAILED(hr)) + return; + + hr = geometry->Open(&sink); + if (FAILED(hr)) + return; + + switch (mode) { + case QPaintEngine::OddEvenMode: + sink->SetFillMode(D2D1_FILL_MODE_ALTERNATE); + break; + case QPaintEngine::WindingMode: + sink->SetFillMode(D2D1_FILL_MODE_WINDING); + break; + case QPaintEngine::ConvexMode: + case QPaintEngine::PolylineMode: + // XXX + break; + } + + sink->BeginFigure(points[0], is_polyline ? D2D1_FIGURE_BEGIN_HOLLOW + : D2D1_FIGURE_BEGIN_FILLED); + sink->AddLines(points + 1, pointCount - 1); + sink->EndFigure(is_polyline ? D2D1_FIGURE_END_OPEN + : D2D1_FIGURE_END_CLOSED); + sink->Close(); + + if (brush.brush) + dc()->FillGeometry(geometry.Get(), brush.brush.Get()); + + if (pen.brush) + dc()->DrawGeometry(geometry.Get(), pen.brush.Get(), pen.width, pen.strokeStyle.Get()); + } +}; + +QWindowsDirect2DPaintEngine::QWindowsDirect2DPaintEngine(QWindowsDirect2DBitmap *bitmap) + : QPaintEngine(PrimitiveTransform + | PatternTransform + | PixmapTransform + | PatternBrush + | AlphaBlend + | PainterPaths + | Antialiasing + | BrushStroke + | ConstantOpacity + | MaskedBrush + | ObjectBoundingModeGradients + + // Although Direct2D 1.1 contains support for both linear and radial gradients, + // there unfortunately is no support for repeating or reflecting versions of them + //| LinearGradientFill + //| RadialGradientFill + + // Unsupported entirely by Direct2D 1.1 + //| ConicalGradientFill + + // We might be able to support this using Direct2D effects + //| PorterDuff + + // Direct2D currently only supports affine transforms directly + // We might be able to support this using Direct2D effects + //| PerspectiveTransform + + // We might be able to support this using Direct2D effects + //| BlendModes + + // We might be able to support this using Direct2D effects + //| RasterOpModes + + // We have to inform Direct2D when we start and end drawing + //| PaintOutsidePaintEvent + ) + , d_ptr(new QWindowsDirect2DPaintEnginePrivate(bitmap)) +{ + +} + +bool QWindowsDirect2DPaintEngine::begin(QPaintDevice * pdev) +{ + Q_D(QWindowsDirect2DPaintEngine); + + d->bitmap->deviceContext()->begin(); + d->dc()->SetTransform(D2D1::Matrix3x2F::Identity()); + + QRect clip(0, 0, pdev->width(), pdev->height()); + if (!systemClip().isEmpty()) { + clip &= systemClip().boundingRect(); + } + d->dc()->PushAxisAlignedClip(to_d2d_rect_f(clip), d->antialiasMode()); + updateState(*state); + + D2D_TAG(D2DDebugDrawInitialStateTag); + + return true; +} + +bool QWindowsDirect2DPaintEngine::end() +{ + Q_D(QWindowsDirect2DPaintEngine); + d->popClip(); + d->dc()->PopAxisAlignedClip(); + return d->bitmap->deviceContext()->end(); +} + +void QWindowsDirect2DPaintEngine::updateState(const QPaintEngineState &state) +{ + Q_D(QWindowsDirect2DPaintEngine); + d->updateState(state, state.state()); +} + +QPaintEngine::Type QWindowsDirect2DPaintEngine::type() const +{ + return QPaintEngine::Direct2D; +} + +void QWindowsDirect2DPaintEngine::drawEllipse(const QRectF &rect) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawEllipseTag); + + D2D1_ELLIPSE ellipse = { + to_d2d_point_2f(rect.center()), + rect.width() / 2, + rect.height() / 2 + }; + + if (d->brush.brush) + d->dc()->FillEllipse(ellipse, d->brush.brush.Get()); + + if (d->pen.brush) { + d->dc()->DrawEllipse(ellipse, d->pen.brush.Get(), d->pen.width, d->pen.strokeStyle.Get()); + } +} + +void QWindowsDirect2DPaintEngine::drawEllipse(const QRect &rect) +{ + drawEllipse(QRectF(rect)); +} + +void QWindowsDirect2DPaintEngine::drawImage(const QRectF &rectangle, const QImage &image, + const QRectF &sr, Qt::ImageConversionFlags flags) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawImageTag); + + QPixmap pixmap = QPixmap::fromImage(image, flags); + drawPixmap(rectangle, pixmap, sr); +} + +void QWindowsDirect2DPaintEngine::drawLines(const QLineF *lines, int lineCount) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawLinesTag); + d->drawLines(lines, lineCount); +} + +void QWindowsDirect2DPaintEngine::drawLines(const QLine *lines, int lineCount) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawLinesTag); + d->drawLines(lines, lineCount); +} + +void QWindowsDirect2DPaintEngine::drawPath(const QPainterPath &path) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawPathTag); + + if (path.elementCount() == 0) + return; + + if (!d->brush.brush && !d->pen.brush) + return; + + ComPtr<ID2D1PathGeometry> geometry = painterPathToPathGeometry(path); + if (!geometry) + return; + + if (d->brush.brush) + d->dc()->FillGeometry(geometry.Get(), d->brush.brush.Get()); + + if (d->pen.brush) + d->dc()->DrawGeometry(geometry.Get(), d->pen.brush.Get(), d->pen.width, d->pen.strokeStyle.Get()); +} + +void QWindowsDirect2DPaintEngine::drawPixmap(const QRectF &r, + const QPixmap &pm, + const QRectF &sr) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawPixmapTag); + + if (pm.isNull()) + return; + + if (pm.handle()->pixelType() == QPlatformPixmap::BitmapType) { + QImage i = pm.toImage(); + i.setColor(0, qRgba(0, 0, 0, 0)); + i.setColor(1, d->pen.color.rgba()); + drawImage(r, i, sr); + return; + } + + QWindowsDirect2DPlatformPixmap *pp = static_cast<QWindowsDirect2DPlatformPixmap *>(pm.handle()); + QWindowsDirect2DBitmap *bitmap = pp->bitmap(); + + if (bitmap->bitmap() != d->bitmap->bitmap()) { + // Good, src bitmap != dst bitmap + if (sr.isValid()) + d->dc()->DrawBitmap(bitmap->bitmap(), + to_d2d_rect_f(r), d->opacity, + d->interpolationMode(), + to_d2d_rect_f(sr)); + else + d->dc()->DrawBitmap(bitmap->bitmap(), + to_d2d_rect_f(r), d->opacity, + d->interpolationMode()); + } else { + // Ok, so the source pixmap and destination pixmap is the same. + // D2D is not fond of this scenario, deal with it through + // an intermediate bitmap + QWindowsDirect2DBitmap intermediate; + + if (sr.isValid()) { + bool r = intermediate.resize(sr.width(), sr.height()); + if (!r) { + qDebug("%s: Could not resize intermediate bitmap to source rect size", __FUNCTION__); + return; + } + + D2D1_RECT_U d2d_sr = to_d2d_rect_u(sr.toRect()); + HRESULT hr = intermediate.bitmap()->CopyFromBitmap(NULL, + bitmap->bitmap(), + &d2d_sr); + if (FAILED(hr)) { + qWarning("%s: Could not copy source rect area from source bitmap to intermediate bitmap: %#x", __FUNCTION__, hr); + return; + } + } else { + bool r = intermediate.resize(bitmap->size().width(), + bitmap->size().height()); + if (!r) { + qDebug("%s: Could not resize intermediate bitmap to source bitmap size", __FUNCTION__); + return; + } + + HRESULT hr = intermediate.bitmap()->CopyFromBitmap(NULL, + bitmap->bitmap(), + NULL); + if (FAILED(hr)) { + qWarning("%s: Could not copy source bitmap to intermediate bitmap: %#x", __FUNCTION__, hr); + return; + } + } + + d->dc()->DrawBitmap(intermediate.bitmap(), + to_d2d_rect_f(r), d->opacity, + d->interpolationMode()); + } +} + +void QWindowsDirect2DPaintEngine::drawPolygon(const QPointF *points, + int pointCount, + QPaintEngine::PolygonDrawMode mode) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawPolygonTag); + d->drawPolygon(points, pointCount, mode); +} + +void QWindowsDirect2DPaintEngine::drawPolygon(const QPoint *points, + int pointCount, + QPaintEngine::PolygonDrawMode mode) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawPolygonTag); + d->drawPolygon(points, pointCount, mode); +} + +void QWindowsDirect2DPaintEngine::drawRects(const QRectF *rects, int rectCount) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawRectsTag); + d->drawRects(rects, rectCount); +} + +void QWindowsDirect2DPaintEngine::drawRects(const QRect *rects, int rectCount) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawRectsTag); + d->drawRects(rects, rectCount); +} + +// Points (1/72 inches) to Microsoft's Device Independent Pixels (1/96 inches) +inline static Q_DECL_CONSTEXPR FLOAT pointSizeToDIP(qreal pointSize) +{ + return pointSize + (pointSize / qreal(3.0)); +} + +inline static FLOAT pixelSizeToDIP(int pixelSize) +{ + FLOAT dpiX, dpiY; + factory()->GetDesktopDpi(&dpiX, &dpiY); + + return FLOAT(pixelSize) / (dpiY / 96.0f); +} + +inline static FLOAT fontSizeInDIP(const QFont &font) +{ + // Microsoft wants the font size in DIPs (Device Independent Pixels), each of which is 1/96 inches. + if (font.pixelSize() == -1) { + // font size was set as points + return pointSizeToDIP(font.pointSizeF()); + } else { + // font size was set as pixels + return pixelSizeToDIP(font.pixelSize()); + } +} + +void QWindowsDirect2DPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawTextItemTag); + + if (d->pen.isNull) + return; + + // If we can't support the current configuration with Direct2D, fall back to slow path + // Most common cases are perspective transform and gradient brush as pen + if (d->hasPerspectiveTransform || !d->pen.brush) { + QPaintEngine::drawTextItem(p, textItem); + return; + } + + const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem); + ComPtr<IDWriteFontFace> fontFace; + + switch (ti.fontEngine->type()) { + case QFontEngine::Win: + { + QWindowsFontEngine *wfe = static_cast<QWindowsFontEngine *>(ti.fontEngine); + QSharedPointer<QWindowsFontEngineData> wfed = wfe->fontEngineData(); + + HGDIOBJ oldfont = wfe->selectDesignFont(); + HRESULT hr = QWindowsDirect2DContext::instance()->dwriteGdiInterop()->CreateFontFaceFromHdc(wfed->hdc, &fontFace); + DeleteObject(SelectObject(wfed->hdc, oldfont)); + if (FAILED(hr)) + qWarning("%s: Could not create DirectWrite fontface from HDC: %#x", __FUNCTION__, hr); + + } + break; + +#ifndef QT_NO_DIRECTWRITE + + case QFontEngine::DirectWrite: + { + QWindowsFontEngineDirectWrite *wfedw = static_cast<QWindowsFontEngineDirectWrite *>(ti.fontEngine); + fontFace = wfedw->directWriteFontFace(); + } + break; + +#endif // QT_NO_DIRECTWRITE + + default: + qDebug("%s: Unknown font engine!", __FUNCTION__); + break; + } + + if (!fontFace) { + qDebug("%s: Could not find font - falling back to slow text rendering path.", __FUNCTION__); + QPaintEngine::drawTextItem(p, textItem); + return; + } + + QVector<UINT16> glyphIndices(ti.glyphs.numGlyphs); + QVector<FLOAT> glyphAdvances(ti.glyphs.numGlyphs); + QVector<DWRITE_GLYPH_OFFSET> glyphOffsets(ti.glyphs.numGlyphs); + + // Imperfect conversion here + for (int i = 0; i < ti.glyphs.numGlyphs; i++) { + glyphIndices[i] = UINT16(ti.glyphs.glyphs[i]); + glyphAdvances[i] = ti.glyphs.effectiveAdvance(i).toReal(); + glyphOffsets[i].advanceOffset = ti.glyphs.offsets[i].x.toReal(); + glyphOffsets[i].ascenderOffset = ti.glyphs.offsets[i].y.toReal(); + } + + const bool rtl = (ti.flags & QTextItem::RightToLeft); + const UINT32 bidiLevel = rtl ? 1 : 0; + + DWRITE_GLYPH_RUN glyphRun = { + fontFace.Get(), // IDWriteFontFace *fontFace; + fontSizeInDIP(ti.font()), // FLOAT fontEmSize; + ti.glyphs.numGlyphs, // UINT32 glyphCount; + glyphIndices.constData(), // const UINT16 *glyphIndices; + glyphAdvances.constData(), // const FLOAT *glyphAdvances; + glyphOffsets.constData(), // const DWRITE_GLYPH_OFFSET *glyphOffsets; + FALSE, // BOOL isSideways; + bidiLevel // UINT32 bidiLevel; + }; + + const bool antiAlias = bool((d->renderHints & QPainter::TextAntialiasing) + && !(ti.font().styleStrategy() & QFont::NoAntialias)); + d->dc()->SetTextAntialiasMode(antiAlias ? D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE + : D2D1_TEXT_ANTIALIAS_MODE_ALIASED); + + const QPointF offset(rtl ? ti.width.toReal() : 0, 0); + d->dc()->DrawGlyphRun(to_d2d_point_2f(p + offset), + &glyphRun, + NULL, + d->pen.brush.Get(), + DWRITE_MEASURING_MODE_GDI_CLASSIC); +} + +static void qt_draw_tile(QPaintEngine *gc, qreal x, qreal y, qreal w, qreal h, + const QPixmap &pixmap, qreal xOffset, qreal yOffset) +{ + qreal yPos, xPos, drawH, drawW, yOff, xOff; + yPos = y; + yOff = yOffset; + while (yPos < y + h) { + drawH = pixmap.height() - yOff; // Cropping first row + if (yPos + drawH > y + h) // Cropping last row + drawH = y + h - yPos; + xPos = x; + xOff = xOffset; + while (xPos < x + w) { + drawW = pixmap.width() - xOff; // Cropping first column + if (xPos + drawW > x + w) // Cropping last column + drawW = x + w - xPos; + if (drawW > 0 && drawH > 0) + gc->drawPixmap(QRectF(xPos, yPos, drawW, drawH), pixmap, QRectF(xOff, yOff, drawW, drawH)); + xPos += drawW; + xOff = 0; + } + yPos += drawH; + yOff = 0; + } +} + +void QWindowsDirect2DPaintEngine::drawTiledPixmap(const QRectF &rect, const QPixmap &pixmap, const QPointF &p) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawTextItemTag); + qt_draw_tile(this, rect.x(), rect.y(), rect.width(), rect.height(), pixmap, p.x(), p.y()); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h new file mode 100644 index 0000000000..554380cb1f --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** 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 QWINDOWSDIRECT2DPAINTENGINE_H +#define QWINDOWSDIRECT2DPAINTENGINE_H + +#include <QtCore/QScopedPointer> +#include <QtGui/QPaintEngine> + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DPaintEnginePrivate; +class QWindowsDirect2DBitmap; + +class QWindowsDirect2DPaintEngine : public QPaintEngine +{ + Q_DECLARE_PRIVATE(QWindowsDirect2DPaintEngine) + +public: + QWindowsDirect2DPaintEngine(QWindowsDirect2DBitmap *bitmap); + + bool begin(QPaintDevice *pdev) Q_DECL_OVERRIDE; + bool end() Q_DECL_OVERRIDE; + + void updateState(const QPaintEngineState &state) Q_DECL_OVERRIDE; + + Type type() const Q_DECL_OVERRIDE; + + void drawEllipse(const QRectF &rect) Q_DECL_OVERRIDE; + void drawEllipse(const QRect &rect) Q_DECL_OVERRIDE; + void drawImage(const QRectF &rectangle, const QImage &image, const QRectF &sr, Qt::ImageConversionFlags flags = Qt::AutoColor) Q_DECL_OVERRIDE; + void drawLines(const QLineF *lines, int lineCount) Q_DECL_OVERRIDE; + void drawLines(const QLine *lines, int lineCount) Q_DECL_OVERRIDE; + void drawPath(const QPainterPath &path) Q_DECL_OVERRIDE; + void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) Q_DECL_OVERRIDE; + void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode) Q_DECL_OVERRIDE; + void drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode) Q_DECL_OVERRIDE; + void drawRects(const QRectF *rects, int rectCount) Q_DECL_OVERRIDE; + void drawRects(const QRect *rects, int rectCount) Q_DECL_OVERRIDE; + void drawTextItem(const QPointF &p, const QTextItem &textItem) Q_DECL_OVERRIDE; + void drawTiledPixmap(const QRectF &rect, const QPixmap &pixmap, const QPointF &p) Q_DECL_OVERRIDE; + +private: + QScopedPointer<QWindowsDirect2DPaintEnginePrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSDIRECT2DPAINTENGINE_H diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.cpp new file mode 100644 index 0000000000..072c4b3c0e --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.cpp @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** 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 "qwindowsdirect2dcontext.h" +#include "qwindowsdirect2dpaintdevice.h" +#include "qwindowsdirect2dplatformpixmap.h" +#include "qwindowsdirect2dbitmap.h" +#include "qwindowsdirect2dhelpers.h" + +#include <QtGui/QPainter> +#include <QtGui/QImage> +#include <QtGui/QPaintDevice> +#include <QtGui/QPaintEngine> + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DPlatformPixmapPrivate +{ +public: + QWindowsDirect2DPlatformPixmapPrivate() + : bitmap(new QWindowsDirect2DBitmap) + , device(new QWindowsDirect2DPaintDevice(bitmap.data(), QInternal::Pixmap)) + , devicePixelRatio(1.0) + {} + + QScopedPointer<QWindowsDirect2DBitmap> bitmap; + QScopedPointer<QWindowsDirect2DPaintDevice> device; + qreal devicePixelRatio; +}; + +static int qt_d2dpixmap_serno = 0; + +QWindowsDirect2DPlatformPixmap::QWindowsDirect2DPlatformPixmap(PixelType pixelType) + : QPlatformPixmap(pixelType, Direct2DClass) + , d_ptr(new QWindowsDirect2DPlatformPixmapPrivate) +{ + setSerialNumber(qt_d2dpixmap_serno++); +} + +QWindowsDirect2DPlatformPixmap::~QWindowsDirect2DPlatformPixmap() +{ + +} + +void QWindowsDirect2DPlatformPixmap::resize(int width, int height) +{ + Q_D(QWindowsDirect2DPlatformPixmap); + + if (!d->bitmap->resize(width, height)) { + qWarning("%s: Could not resize bitmap", __FUNCTION__); + return; + } + + is_null = false; + w = width; + h = height; + this->d = 32; +} + +void QWindowsDirect2DPlatformPixmap::fromImage(const QImage &image, + Qt::ImageConversionFlags flags) +{ + Q_D(QWindowsDirect2DPlatformPixmap); + + if (!d->bitmap->fromImage(image, flags)) { + qWarning("%s: Could not init from image", __FUNCTION__); + return; + } + + is_null = false; + w = image.width(); + h = image.height(); + this->d = 32; +} + +int QWindowsDirect2DPlatformPixmap::metric(QPaintDevice::PaintDeviceMetric metric) const +{ + Q_D(const QWindowsDirect2DPlatformPixmap); + + Q_GUI_EXPORT int qt_paint_device_metric(const QPaintDevice *device, QPaintDevice::PaintDeviceMetric metric); + return qt_paint_device_metric(d->device.data(), metric); +} + +void QWindowsDirect2DPlatformPixmap::fill(const QColor &color) +{ + Q_D(QWindowsDirect2DPlatformPixmap); + d->bitmap->fill(color); +} + +bool QWindowsDirect2DPlatformPixmap::hasAlphaChannel() const +{ + return true; +} + +QImage QWindowsDirect2DPlatformPixmap::toImage() const +{ + return toImage(QRect()); +} + +QImage QWindowsDirect2DPlatformPixmap::toImage(const QRect &rect) const +{ + Q_D(const QWindowsDirect2DPlatformPixmap); + + bool active = d->device->paintEngine()->isActive(); + + if (active) + d->device->paintEngine()->end(); + + QImage result = d->bitmap->toImage(rect); + + if (active) + d->device->paintEngine()->begin(d->device.data()); + + return result; +} + +QPaintEngine* QWindowsDirect2DPlatformPixmap::paintEngine() const +{ + Q_D(const QWindowsDirect2DPlatformPixmap); + return d->device->paintEngine(); +} + +qreal QWindowsDirect2DPlatformPixmap::devicePixelRatio() const +{ + Q_D(const QWindowsDirect2DPlatformPixmap); + return d->devicePixelRatio; +} + +void QWindowsDirect2DPlatformPixmap::setDevicePixelRatio(qreal scaleFactor) +{ + Q_D(QWindowsDirect2DPlatformPixmap); + d->devicePixelRatio = scaleFactor; +} + +QWindowsDirect2DBitmap *QWindowsDirect2DPlatformPixmap::bitmap() const +{ + Q_D(const QWindowsDirect2DPlatformPixmap); + return d->bitmap.data(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.h b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.h new file mode 100644 index 0000000000..e6684ea423 --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** 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 QWINDOWSDIRECT2DPLATFORMPIXMAP_H +#define QWINDOWSDIRECT2DPLATFORMPIXMAP_H + +#include <QtGui/qpa/qplatformpixmap.h> +#include <QtCore/QScopedPointer> + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DPlatformPixmapPrivate; +class QWindowsDirect2DBitmap; + +class QWindowsDirect2DPlatformPixmap : public QPlatformPixmap +{ + Q_DECLARE_PRIVATE(QWindowsDirect2DPlatformPixmap) +public: + QWindowsDirect2DPlatformPixmap(PixelType pixelType); + ~QWindowsDirect2DPlatformPixmap(); + + virtual void resize(int width, int height); + virtual void fromImage(const QImage &image, + Qt::ImageConversionFlags flags); + + virtual int metric(QPaintDevice::PaintDeviceMetric metric) const; + virtual void fill(const QColor &color); + + virtual bool hasAlphaChannel() const; + + virtual QImage toImage() const; + virtual QImage toImage(const QRect &rect) const; + + virtual QPaintEngine* paintEngine() const; + + virtual qreal devicePixelRatio() const; + virtual void setDevicePixelRatio(qreal scaleFactor); + + QWindowsDirect2DBitmap *bitmap() const; + +private: + QScopedPointer<QWindowsDirect2DPlatformPixmapPrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSDIRECT2DPLATFORMPIXMAP_H diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformplugin.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformplugin.cpp new file mode 100644 index 0000000000..f75bb49fd9 --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformplugin.cpp @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** 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 "qwindowsdirect2dintegration.h" + +#include <QtGui/qpa/qplatformintegrationplugin.h> +#include <QtCore/QStringList> + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DIntegrationPlugin : public QPlatformIntegrationPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "direct2d.json") +public: + QPlatformIntegration *create(const QString&, const QStringList&); +}; + +QPlatformIntegration *QWindowsDirect2DIntegrationPlugin::create(const QString& system, const QStringList& paramList) +{ + if (system.compare(system, QStringLiteral("direct2d"), Qt::CaseInsensitive) == 0) + return QWindowsDirect2DIntegration::create(paramList); + return 0; +} + +QT_END_NAMESPACE + +#include "qwindowsdirect2dplatformplugin.moc" diff --git a/src/plugins/platforms/directfb/qdirectfbconvenience.cpp b/src/plugins/platforms/directfb/qdirectfbconvenience.cpp index b56d75a16e..16510095db 100644 --- a/src/plugins/platforms/directfb/qdirectfbconvenience.cpp +++ b/src/plugins/platforms/directfb/qdirectfbconvenience.cpp @@ -281,12 +281,16 @@ QDirectFbKeyMap::QDirectFbKeyMap() insert(DIKS_CLEAR , Qt::Key_Clear); insert(DIKS_MENU , Qt::Key_Menu); insert(DIKS_HELP , Qt::Key_Help); + insert(DIKS_INFO , Qt::Key_Info); + insert(DIKS_EXIT , Qt::Key_Exit); + insert(DIKS_SETUP , Qt::Key_Settings); insert(DIKS_CD , Qt::Key_CD); insert(DIKS_INTERNET , Qt::Key_HomePage); insert(DIKS_MAIL , Qt::Key_LaunchMail); insert(DIKS_FAVORITES , Qt::Key_Favorites); insert(DIKS_PHONE , Qt::Key_Phone); + insert(DIKS_PROGRAM , Qt::Key_Guide); insert(DIKS_TIME , Qt::Key_Time); insert(DIKS_RED , Qt::Key_Red); diff --git a/src/plugins/platforms/eglfs/eglfs.pri b/src/plugins/platforms/eglfs/eglfs.pri index 390061c168..7afa9c9e11 100644 --- a/src/plugins/platforms/eglfs/eglfs.pri +++ b/src/plugins/platforms/eglfs/eglfs.pri @@ -12,21 +12,15 @@ DEFINES += MESA_EGL_NO_X11_HEADERS SOURCES += $$PWD/qeglfsintegration.cpp \ $$PWD/qeglfswindow.cpp \ - $$PWD/qeglfsbackingstore.cpp \ $$PWD/qeglfsscreen.cpp \ $$PWD/qeglfshooks_stub.cpp \ - $$PWD/qeglfscursor.cpp \ - $$PWD/qeglfscontext.cpp \ - $$PWD/qeglfscompositor.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 \ - $$PWD/qeglfscompositor.h + $$PWD/qeglfscontext.h QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF diff --git a/src/plugins/platforms/eglfs/qeglfsbackingstore.cpp b/src/plugins/platforms/eglfs/qeglfsbackingstore.cpp deleted file mode 100644 index 03531916cf..0000000000 --- a/src/plugins/platforms/eglfs/qeglfsbackingstore.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/**************************************************************************** -** -** 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 "qeglfsbackingstore.h" -#include "qeglfscompositor.h" -#include "qeglfscursor.h" -#include "qeglfswindow.h" -#include "qeglfscontext.h" - -#include <QtGui/QOpenGLPaintDevice> -#include <QtGui/QOpenGLShaderProgram> - -QT_BEGIN_NAMESPACE - -QEglFSBackingStore::QEglFSBackingStore(QWindow *window) - : QPlatformBackingStore(window), - m_window(static_cast<QEglFSWindow *>(window->handle())), - m_texture(0) -{ - m_window->setBackingStore(this); -} - -QPaintDevice *QEglFSBackingStore::paintDevice() -{ - return &m_image; -} - -void QEglFSBackingStore::updateTexture() -{ - glBindTexture(GL_TEXTURE_2D, m_texture); - - if (!m_dirty.isNull()) { - QRegion fixed; - QRect imageRect = m_image.rect(); - m_dirty |= imageRect; - - foreach (const QRect &rect, m_dirty.rects()) { - // intersect with image rect to be sure - QRect r = imageRect & rect; - - // if the rect is wide enough it's cheaper to just - // extend it instead of doing an image copy - if (r.width() >= imageRect.width() / 2) { - r.setX(0); - r.setWidth(imageRect.width()); - } - - fixed |= r; - } - - foreach (const QRect &rect, fixed.rects()) { - // if the sub-rect is full-width we can pass the image data directly to - // OpenGL instead of copying, since there's no gap between scanlines - if (rect.width() == imageRect.width()) { - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, - m_image.constScanLine(rect.y())); - } else { - glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, - m_image.copy(rect).constBits()); - } - } - - m_dirty = QRegion(); - } -} - -void QEglFSBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) -{ - Q_UNUSED(window); - Q_UNUSED(region); - Q_UNUSED(offset); - -#ifdef QEGL_EXTRA_DEBUG - qWarning("QEglBackingStore::flush %p", window); -#endif - - QEglFSWindow *rootWin = m_window->screen()->rootWindow(); - if (!rootWin || !rootWin->isRaster()) - return; - - m_window->create(); - rootWin->screen()->rootContext()->makeCurrent(rootWin->window()); - updateTexture(); - QEglFSCompositor::instance()->schedule(rootWin->screen()); -} - -void QEglFSBackingStore::beginPaint(const QRegion &rgn) -{ - m_dirty |= rgn; -} - -void QEglFSBackingStore::resize(const QSize &size, const QRegion &staticContents) -{ - Q_UNUSED(staticContents); - - QEglFSWindow *rootWin = m_window->screen()->rootWindow(); - if (!rootWin || !rootWin->isRaster()) - return; - - m_image = QImage(size, QImage::Format_RGB32); - m_window->create(); - - rootWin->screen()->rootContext()->makeCurrent(rootWin->window()); - initializeOpenGLFunctions(); - - if (m_texture) - glDeleteTextures(1, &m_texture); - - glGenTextures(1, &m_texture); - glBindTexture(GL_TEXTURE_2D, m_texture); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/qeglfscompositor.cpp b/src/plugins/platforms/eglfs/qeglfscompositor.cpp deleted file mode 100644 index 845bb5b3b5..0000000000 --- a/src/plugins/platforms/eglfs/qeglfscompositor.cpp +++ /dev/null @@ -1,203 +0,0 @@ -/**************************************************************************** -** -** 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 "qeglfscompositor.h" -#include "qeglfswindow.h" -#include "qeglfscontext.h" - -#include <QtGui/QOpenGLContext> -#include <QtGui/QOpenGLShaderProgram> -#include <QtGui/QOpenGLFramebufferObject> - -QT_BEGIN_NAMESPACE - -static QEglFSCompositor *compositor = 0; - -QEglFSCompositor::QEglFSCompositor() - : m_screen(0), - m_program(0), - m_initialized(false) -{ - Q_ASSERT(!compositor); - m_updateTimer.setSingleShot(true); - m_updateTimer.setInterval(0); - connect(&m_updateTimer, SIGNAL(timeout()), SLOT(renderAll())); -} - -QEglFSCompositor::~QEglFSCompositor() -{ - Q_ASSERT(compositor == this); - delete m_program; - compositor = 0; -} - -void QEglFSCompositor::schedule(QEglFSScreen *screen) -{ - m_screen = screen; - if (!m_updateTimer.isActive()) - m_updateTimer.start(); -} - -void QEglFSCompositor::renderAll() -{ - QEglFSWindow *rootWin = m_screen->rootWindow(); - if (!rootWin) - return; - - Q_ASSERT(rootWin->hasNativeWindow()); - QOpenGLContext *context = m_screen->rootContext(); - Q_ASSERT(context); - - context->makeCurrent(rootWin->window()); - if (!m_initialized) { - initializeOpenGLFunctions(); - m_initialized = true; - } - ensureProgram(); - m_program->bind(); - - QList<QEglFSWindow *> windows = m_screen->windows(); - for (int i = 0; i < windows.size(); ++i) { - QEglFSWindow *window = windows.at(i); - uint texture = window->texture(); - if (texture) - render(window, texture, window->isRaster()); - } - - m_program->release(); - context->swapBuffers(rootWin->window()); -} - -void QEglFSCompositor::ensureProgram() -{ - if (!m_program) { - static const char *textureVertexProgram = - "attribute highp vec2 vertexCoordEntry;\n" - "attribute highp vec2 textureCoordEntry;\n" - "varying highp vec2 textureCoord;\n" - "void main() {\n" - " textureCoord = textureCoordEntry;\n" - " gl_Position = vec4(vertexCoordEntry, 0.0, 1.0);\n" - "}\n"; - - static const char *textureFragmentProgram = - "uniform sampler2D texture;\n" - "varying highp vec2 textureCoord;\n" - "uniform bool isRaster;\n" - "void main() {\n" - " lowp vec4 c = texture2D(texture, textureCoord);\n" - " gl_FragColor = isRaster ? c.bgra : c.rgba;\n" - "}\n"; - - m_program = new QOpenGLShaderProgram; - - m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, textureVertexProgram); - m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, textureFragmentProgram); - m_program->link(); - - m_vertexCoordEntry = m_program->attributeLocation("vertexCoordEntry"); - m_textureCoordEntry = m_program->attributeLocation("textureCoordEntry"); - m_isRasterEntry = m_program->uniformLocation("isRaster"); - } -} - -void QEglFSCompositor::render(QEglFSWindow *window, uint texture, bool raster) -{ - const GLfloat textureCoordinates[] = { - 0, 0, - 1, 0, - 1, 1, - 0, 1 - }; - - QRectF sr = window->screen()->geometry(); - QRect r = window->window()->geometry(); - QPoint tl = r.topLeft(); - QPoint br = r.bottomRight(); - - GLfloat x1 = (tl.x() / sr.width()) * 2 - 1; - GLfloat x2 = (br.x() / sr.width()) * 2 - 1; - GLfloat y1 = ((sr.height() - tl.y()) / sr.height()) * 2 - 1; - GLfloat y2 = ((sr.height() - br.y()) / sr.height()) * 2 - 1; - - if (!raster) - qSwap(y1, y2); - - const GLfloat vertexCoordinates[] = { - x1, y1, - x2, y1, - x2, y2, - x1, y2 - }; - - glViewport(0, 0, sr.width(), sr.height()); - - glEnableVertexAttribArray(m_vertexCoordEntry); - glEnableVertexAttribArray(m_textureCoordEntry); - - glVertexAttribPointer(m_vertexCoordEntry, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinates); - glVertexAttribPointer(m_textureCoordEntry, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinates); - - glBindTexture(GL_TEXTURE_2D, texture); - - m_program->setUniformValue(m_isRasterEntry, raster); - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - glBindTexture(GL_TEXTURE_2D, 0); - glDisableVertexAttribArray(m_vertexCoordEntry); - glDisableVertexAttribArray(m_textureCoordEntry); -} - -QEglFSCompositor *QEglFSCompositor::instance() -{ - if (!compositor) - compositor = new QEglFSCompositor; - return compositor; -} - -void QEglFSCompositor::destroy() -{ - delete compositor; - compositor = 0; -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/qeglfscontext.cpp b/src/plugins/platforms/eglfs/qeglfscontext.cpp index 2c6846132d..86ceb0721b 100644 --- a/src/plugins/platforms/eglfs/qeglfscontext.cpp +++ b/src/plugins/platforms/eglfs/qeglfscontext.cpp @@ -41,11 +41,12 @@ #include "qeglfscontext.h" #include "qeglfswindow.h" -#include "qeglfscursor.h" #include "qeglfshooks.h" #include "qeglfsintegration.h" +#include <QtPlatformSupport/private/qeglconvenience_p.h> #include <QtPlatformSupport/private/qeglpbuffer_p.h> +#include <QtPlatformSupport/private/qeglplatformcursor_p.h> #include <QtGui/QSurface> #include <QtDebug> @@ -54,31 +55,10 @@ QT_BEGIN_NAMESPACE QEglFSContext::QEglFSContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, EGLenum eglApi) : QEGLPlatformContext(QEglFSHooks::hooks()->surfaceFormatFor(format), share, display, - QEglFSIntegration::chooseConfig(display, QEglFSHooks::hooks()->surfaceFormatFor(format)), eglApi), - m_swapIntervalSet(false) + QEglFSIntegration::chooseConfig(display, QEglFSHooks::hooks()->surfaceFormatFor(format)), eglApi) { } -bool QEglFSContext::makeCurrent(QPlatformSurface *surface) -{ - bool success = QEGLPlatformContext::makeCurrent(surface); - - if (success && !m_swapIntervalSet) { - m_swapIntervalSet = true; - int swapInterval = 1; - QByteArray swapIntervalString = qgetenv("QT_QPA_EGLFS_SWAPINTERVAL"); - if (!swapIntervalString.isEmpty()) { - bool ok; - swapInterval = swapIntervalString.toInt(&ok); - if (!ok) - swapInterval = 1; - } - eglSwapInterval(eglDisplay(), swapInterval); - } - - return success; -} - EGLSurface QEglFSContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface) { if (surface->surface()->surfaceClass() == QSurface::Window) @@ -89,10 +69,10 @@ EGLSurface QEglFSContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface void QEglFSContext::swapBuffers(QPlatformSurface *surface) { + // draw the cursor if (surface->surface()->surfaceClass() == QSurface::Window) { - QEglFSWindow *window = static_cast<QEglFSWindow *>(surface); - // draw the cursor - if (QEglFSCursor *cursor = static_cast<QEglFSCursor *>(window->screen()->cursor())) + QPlatformWindow *window = static_cast<QPlatformWindow *>(surface); + if (QEGLPlatformCursor *cursor = static_cast<QEGLPlatformCursor *>(window->screen()->cursor())) cursor->paintOnScreen(); } @@ -101,4 +81,3 @@ void QEglFSContext::swapBuffers(QPlatformSurface *surface) } QT_END_NAMESPACE - diff --git a/src/plugins/platforms/eglfs/qeglfscontext.h b/src/plugins/platforms/eglfs/qeglfscontext.h index 8db340252c..22a7c67e46 100644 --- a/src/plugins/platforms/eglfs/qeglfscontext.h +++ b/src/plugins/platforms/eglfs/qeglfscontext.h @@ -42,7 +42,6 @@ #ifndef QEGLFSCONTEXT_H #define QEGLFSCONTEXT_H -#include <QtPlatformSupport/private/qeglconvenience_p.h> #include <QtPlatformSupport/private/qeglplatformcontext_p.h> QT_BEGIN_NAMESPACE @@ -52,12 +51,8 @@ class QEglFSContext : public QEGLPlatformContext public: QEglFSContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, EGLenum eglApi = EGL_OPENGL_ES_API); - bool makeCurrent(QPlatformSurface *surface); - EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface); - void swapBuffers(QPlatformSurface *surface); - -private: - bool m_swapIntervalSet; + EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface) Q_DECL_OVERRIDE; + void swapBuffers(QPlatformSurface *surface) Q_DECL_OVERRIDE; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/qeglfscursor.cpp b/src/plugins/platforms/eglfs/qeglfscursor.cpp deleted file mode 100644 index 0066426769..0000000000 --- a/src/plugins/platforms/eglfs/qeglfscursor.cpp +++ /dev/null @@ -1,356 +0,0 @@ -/**************************************************************************** -** -** 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 "qeglfscursor.h" -#include <qpa/qwindowsysteminterface.h> -#include <QtGui/QOpenGLContext> -#include <QtCore/QJsonDocument> -#include <QtCore/QJsonArray> -#include <QtCore/QJsonObject> -#include <QtDebug> - -QT_BEGIN_NAMESPACE - -QEglFSCursor::QEglFSCursor(QEglFSScreen *screen) - : m_screen(screen), m_program(0), m_vertexCoordEntry(0), m_textureCoordEntry(0), m_textureEntry(0) -{ - initCursorAtlas(); - - // initialize the cursor -#ifndef QT_NO_CURSOR - QCursor cursor(Qt::ArrowCursor); - setCurrentCursor(&cursor); -#endif -} - -QEglFSCursor::~QEglFSCursor() -{ - resetResources(); -} - -void QEglFSCursor::resetResources() -{ - if (QOpenGLContext::currentContext()) { - glDeleteProgram(m_program); - glDeleteTextures(1, &m_cursor.customCursorTexture); - glDeleteTextures(1, &m_cursorAtlas.texture); - } - m_program = 0; - m_cursor.customCursorTexture = 0; - m_cursor.customCursorPending = !m_cursor.customCursorImage.isNull(); - m_cursorAtlas.texture = 0; -} - -GLuint QEglFSCursor::createShader(GLenum shaderType, const char *program) -{ - GLuint shader = glCreateShader(shaderType); - glShaderSource(shader, 1 /* count */, &program, NULL /* lengths */); - glCompileShader(shader); - GLint status; - glGetShaderiv(shader, GL_COMPILE_STATUS, &status); - if (status == GL_TRUE) - return shader; - - GLint length; - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); - char *infoLog = new char[length]; - glGetShaderInfoLog(shader, length, NULL, infoLog); - qDebug("%s shader compilation error: %s", shaderType == GL_VERTEX_SHADER ? "vertex" : "fragment", infoLog); - delete [] infoLog; - return 0; -} - -GLuint QEglFSCursor::createProgram(GLuint vshader, GLuint fshader) -{ - GLuint program = glCreateProgram(); - glAttachShader(program, vshader); - glAttachShader(program, fshader); - glLinkProgram(program); - GLint status; - glGetProgramiv(program, GL_LINK_STATUS, &status); - if (status == GL_TRUE) - return program; - - GLint length; - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length); - char *infoLog = new char[length]; - glGetProgramInfoLog(program, length, NULL, infoLog); - qDebug("program link error: %s", infoLog); - delete [] infoLog; - return 0; -} - -void QEglFSCursor::createShaderPrograms() -{ - static const char *textureVertexProgram = - "attribute highp vec2 vertexCoordEntry;\n" - "attribute highp vec2 textureCoordEntry;\n" - "varying highp vec2 textureCoord;\n" - "void main() {\n" - " textureCoord = textureCoordEntry;\n" - " gl_Position = vec4(vertexCoordEntry, 1.0, 1.0);\n" - "}\n"; - - static const char *textureFragmentProgram = - "uniform sampler2D texture;\n" - "varying highp vec2 textureCoord;\n" - "void main() {\n" - " gl_FragColor = texture2D(texture, textureCoord).bgra;\n" - "}\n"; - - GLuint vertexShader = createShader(GL_VERTEX_SHADER, textureVertexProgram); - GLuint fragmentShader = createShader(GL_FRAGMENT_SHADER, textureFragmentProgram); - m_program = createProgram(vertexShader, fragmentShader); - glDeleteShader(vertexShader); - glDeleteShader(fragmentShader); - - m_vertexCoordEntry = glGetAttribLocation(m_program, "vertexCoordEntry"); - m_textureCoordEntry = glGetAttribLocation(m_program, "textureCoordEntry"); - m_textureEntry = glGetUniformLocation(m_program, "texture"); -} - -void QEglFSCursor::createCursorTexture(uint *texture, const QImage &image) -{ - if (!*texture) - glGenTextures(1, texture); - glBindTexture(GL_TEXTURE_2D, *texture); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glTexImage2D(GL_TEXTURE_2D, 0 /* level */, GL_RGBA, image.width(), image.height(), 0 /* border */, - GL_RGBA, GL_UNSIGNED_BYTE, image.constBits()); -} - -void QEglFSCursor::initCursorAtlas() -{ - static QByteArray json = qgetenv("QT_QPA_EGLFS_CURSOR"); - if (json.isEmpty()) - json = ":/cursor.json"; - - QFile file(json); - file.open(QFile::ReadOnly); - QJsonDocument doc = QJsonDocument::fromJson(file.readAll()); - QJsonObject object = doc.object(); - - QString atlas = object.value("image").toString(); - Q_ASSERT(!atlas.isEmpty()); - - const int cursorsPerRow = object.value("cursorsPerRow").toDouble(); - Q_ASSERT(cursorsPerRow); - m_cursorAtlas.cursorsPerRow = cursorsPerRow; - - const QJsonArray hotSpots = object.value("hotSpots").toArray(); - Q_ASSERT(hotSpots.count() == Qt::LastCursor); - for (int i = 0; i < hotSpots.count(); i++) { - QPoint hotSpot(hotSpots[i].toArray()[0].toDouble(), hotSpots[i].toArray()[1].toDouble()); - m_cursorAtlas.hotSpots << hotSpot; - } - - QImage image = QImage(atlas).convertToFormat(QImage::Format_ARGB32_Premultiplied); - m_cursorAtlas.cursorWidth = image.width() / m_cursorAtlas.cursorsPerRow; - m_cursorAtlas.cursorHeight = image.height() / ((Qt::LastCursor + cursorsPerRow - 1) / cursorsPerRow); - m_cursorAtlas.width = image.width(); - m_cursorAtlas.height = image.height(); - m_cursorAtlas.image = image; -} - -#ifndef QT_NO_CURSOR -void QEglFSCursor::changeCursor(QCursor *cursor, QWindow *window) -{ - Q_UNUSED(window); - const QRect oldCursorRect = cursorRect(); - if (setCurrentCursor(cursor)) - update(oldCursorRect | cursorRect()); -} - -bool QEglFSCursor::setCurrentCursor(QCursor *cursor) -{ - 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(); - m_cursor.customCursorPending = false; - } - 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), - hs * (m_cursor.shape / m_cursorAtlas.cursorsPerRow), - ws, hs); - m_cursor.hotSpot = m_cursorAtlas.hotSpots[m_cursor.shape]; - m_cursor.texture = m_cursorAtlas.texture; - m_cursor.size = QSize(m_cursorAtlas.cursorWidth, m_cursorAtlas.cursorHeight); - } else { - QImage image = cursor->pixmap().toImage(); - m_cursor.textureRect = QRectF(0, 0, 1, 1); - m_cursor.hotSpot = cursor->hotSpot(); - m_cursor.texture = 0; // will get updated in the next render() - m_cursor.size = image.size(); - m_cursor.customCursorImage = image; - m_cursor.customCursorPending = true; - } - - return true; -} -#endif - -void QEglFSCursor::update(const QRegion &rgn) -{ - QWindowSystemInterface::handleExposeEvent(m_screen->topLevelAt(m_cursor.pos), rgn); - QWindowSystemInterface::flushWindowSystemEvents(); -} - -QRect QEglFSCursor::cursorRect() const -{ - return QRect(m_cursor.pos - m_cursor.hotSpot, m_cursor.size); -} - -QPoint QEglFSCursor::pos() const -{ - return m_cursor.pos; -} - -void QEglFSCursor::setPos(const QPoint &pos) -{ - const QRect oldCursorRect = cursorRect(); - m_cursor.pos = pos; - update(oldCursorRect | cursorRect()); -} - -void QEglFSCursor::pointerEvent(const QMouseEvent &event) -{ - if (event.type() != QEvent::MouseMove) - return; - const QRect oldCursorRect = cursorRect(); - m_cursor.pos = event.screenPos().toPoint(); - update(oldCursorRect | cursorRect()); -} - -void QEglFSCursor::paintOnScreen() -{ - const QRectF cr = cursorRect(); - const QRect screenRect(m_screen->geometry()); - const GLfloat x1 = 2 * (cr.left() / screenRect.width()) - 1; - const GLfloat x2 = 2 * (cr.right() / screenRect.width()) - 1; - const GLfloat y1 = 1 - (cr.top() / screenRect.height()) * 2; - const GLfloat y2 = 1 - (cr.bottom() / screenRect.height()) * 2; - QRectF r(QPointF(x1, y1), QPointF(x2, y2)); - - draw(r); -} - -void QEglFSCursor::draw(const QRectF &r) -{ - if (!m_program) { - // one time initialization - initializeOpenGLFunctions(); - createShaderPrograms(); - - if (!m_cursorAtlas.texture) { - createCursorTexture(&m_cursorAtlas.texture, m_cursorAtlas.image); - - if (m_cursor.shape != Qt::BitmapCursor) - m_cursor.texture = m_cursorAtlas.texture; - } - } - - if (m_cursor.shape == Qt::BitmapCursor && m_cursor.customCursorPending) { - // upload the custom cursor - createCursorTexture(&m_cursor.customCursorTexture, m_cursor.customCursorImage); - m_cursor.texture = m_cursor.customCursorTexture; - m_cursor.customCursorPending = false; - } - - Q_ASSERT(m_cursor.texture); - - glUseProgram(m_program); - - const GLfloat x1 = r.left(); - const GLfloat x2 = r.right(); - const GLfloat y1 = r.top(); - const GLfloat y2 = r.bottom(); - const GLfloat cursorCoordinates[] = { - x1, y2, - x2, y2, - x1, y1, - x2, y1 - }; - - const GLfloat s1 = m_cursor.textureRect.left(); - const GLfloat s2 = m_cursor.textureRect.right(); - const GLfloat t1 = m_cursor.textureRect.top(); - const GLfloat t2 = m_cursor.textureRect.bottom(); - const GLfloat textureCoordinates[] = { - s1, t2, - s2, t2, - s1, t1, - s2, t1 - }; - - glBindTexture(GL_TEXTURE_2D, m_cursor.texture); - - glEnableVertexAttribArray(m_vertexCoordEntry); - glEnableVertexAttribArray(m_textureCoordEntry); - - glVertexAttribPointer(m_vertexCoordEntry, 2, GL_FLOAT, GL_FALSE, 0, cursorCoordinates); - glVertexAttribPointer(m_textureCoordEntry, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinates); - - glUniform1i(m_textureEntry, 0); - - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_DEPTH_TEST); // disable depth testing to make sure cursor is always on top - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - glDisable(GL_BLEND); - - glBindTexture(GL_TEXTURE_2D, 0); - glDisableVertexAttribArray(m_vertexCoordEntry); - glDisableVertexAttribArray(m_textureCoordEntry); - - glUseProgram(0); -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/qeglfscursor.h b/src/plugins/platforms/eglfs/qeglfscursor.h deleted file mode 100644 index 71ff73b8f3..0000000000 --- a/src/plugins/platforms/eglfs/qeglfscursor.h +++ /dev/null @@ -1,125 +0,0 @@ -/**************************************************************************** -** -** 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 QEGLFSCURSOR_H -#define QEGLFSCURSOR_H - -#include <qpa/qplatformcursor.h> -#include <QtGui/QOpenGLFunctions> -#include "qeglfsscreen.h" - -QT_BEGIN_NAMESPACE - -class QOpenGLShaderProgram; -class QEglFSScreen; - -class QEglFSCursor : public QPlatformCursor, public QOpenGLFunctions -{ -public: - QEglFSCursor(QEglFSScreen *screen); - ~QEglFSCursor(); - -#ifndef QT_NO_CURSOR - void changeCursor(QCursor *cursor, QWindow *widget) Q_DECL_OVERRIDE; -#endif - void pointerEvent(const QMouseEvent &event) Q_DECL_OVERRIDE; - - QPoint pos() const Q_DECL_OVERRIDE; - void setPos(const QPoint &pos) Q_DECL_OVERRIDE; - - QRect cursorRect() const; - - virtual void paintOnScreen(); - - void resetResources(); - -protected: -#ifndef QT_NO_CURSOR - bool setCurrentCursor(QCursor *cursor); -#endif - void draw(const QRectF &rect); - void update(const QRegion ®ion); - - GLuint createShader(GLenum shaderType, const char *program); - GLuint createProgram(GLuint vshader, GLuint fshader); - - QEglFSScreen *m_screen; - - // current cursor information - struct Cursor { - Cursor() : texture(0), shape(Qt::BlankCursor), customCursorTexture(0), customCursorPending(false) { } - uint texture; // a texture from 'image' or the atlas - Qt::CursorShape shape; - QRectF textureRect; // normalized rect inside texture - QSize size; // size of the cursor - QPoint hotSpot; - QImage customCursorImage; - QPoint pos; // current cursor position - uint customCursorTexture; - bool customCursorPending; - } m_cursor; - -private: - void createShaderPrograms(); - static void createCursorTexture(uint *texture, const QImage &image); - void initCursorAtlas(); - - // cursor atlas information - struct CursorAtlas { - CursorAtlas() : cursorsPerRow(0), texture(0), cursorWidth(0), cursorHeight(0) { } - int cursorsPerRow; - uint texture; - int width, height; // width and height of the the atlas - int cursorWidth, cursorHeight; // width and height of cursors inside the atlas - QList<QPoint> hotSpots; - QImage image; // valid until it's uploaded - } m_cursorAtlas; - - GLuint m_program; - int m_vertexCoordEntry; - int m_textureCoordEntry; - int m_textureEntry; -}; - -QT_END_NAMESPACE - -#endif // QEGLFSCURSOR_H - diff --git a/src/plugins/platforms/eglfs/qeglfshooks.h b/src/plugins/platforms/eglfs/qeglfshooks.h index 0251e27f96..67f4d1803d 100644 --- a/src/plugins/platforms/eglfs/qeglfshooks.h +++ b/src/plugins/platforms/eglfs/qeglfshooks.h @@ -50,7 +50,7 @@ QT_BEGIN_NAMESPACE -class QEglFSCursor; +class QEGLPlatformCursor; class QEglFSScreen; class QEglFSHooks @@ -73,7 +73,7 @@ public: const QSurfaceFormat &format); virtual void destroyNativeWindow(EGLNativeWindowType window); virtual bool hasCapability(QPlatformIntegration::Capability cap) const; - virtual QEglFSCursor *createCursor(QEglFSScreen *screen) const; + virtual QEGLPlatformCursor *createCursor(QPlatformScreen *screen) const; virtual bool filterConfig(EGLDisplay display, EGLConfig config) const; virtual void waitForVSync() const; diff --git a/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp b/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp index 4368f37e50..b81d260ecb 100644 --- a/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp +++ b/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp @@ -40,7 +40,8 @@ ****************************************************************************/ #include "qeglfshooks.h" -#include "qeglfscursor.h" +#include <QtPlatformSupport/private/qeglplatformcursor_p.h> +#include <QtPlatformSupport/private/qeglconvenience_p.h> #include <QtCore/QRegularExpression> #include <fcntl.h> @@ -48,7 +49,6 @@ #include <linux/fb.h> #include <sys/ioctl.h> -#include <private/qmath_p.h> #include <private/qcore_unix_p.h> QT_BEGIN_NAMESPACE @@ -100,105 +100,12 @@ EGLNativeDisplayType QEglFSHooks::platformDisplay() const 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; - QSize screenResolution; - - 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; - screenResolution = QSize(vinfo.xres, vinfo.yres); - } - } else { - screenResolution = screenSize(); - } - - const int defaultPhysicalDpi = 100; - size.setWidth(w <= 0 ? screenResolution.width() * Q_MM_PER_INCH / defaultPhysicalDpi : qreal(w)); - size.setHeight(h <= 0 ? screenResolution.height() * 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; + return q_physicalScreenSizeFromFb(framebuffer); } QSize QEglFSHooks::screenSize() const { - static QSize size; - - if (size.isEmpty()) { - int width = qgetenv("QT_QPA_EGLFS_WIDTH").toInt(); - int height = qgetenv("QT_QPA_EGLFS_HEIGHT").toInt(); - - if (width && height) { - // no need to read fb0 - size.setWidth(width); - size.setHeight(height); - return size; - } - - struct fb_var_screeninfo vinfo; - - 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); - - 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 - if (width) - size.setWidth(width); - if (height) - size.setHeight(height); - } - - return size; + return q_screenSizeFromFb(framebuffer); } QDpi QEglFSHooks::logicalDpi() const @@ -222,29 +129,7 @@ Qt::ScreenOrientation QEglFSHooks::orientation() const int QEglFSHooks::screenDepth() const { - static int depth = qgetenv("QT_QPA_EGLFS_DEPTH").toInt(); - - if (depth == 0) { - struct fb_var_screeninfo vinfo; - - 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; - - qWarning("EGLFS: Unable to query screen depth, defaulting to %d.\n" - "EGLFS: To override, set QT_QPA_EGLFS_DEPTH.", defaultDepth); - } - } - - return depth; + return q_screenDepthFromFb(framebuffer); } QImage::Format QEglFSHooks::screenFormat() const @@ -283,9 +168,9 @@ bool QEglFSHooks::hasCapability(QPlatformIntegration::Capability cap) const return false; } -QEglFSCursor *QEglFSHooks::createCursor(QEglFSScreen *screen) const +QEGLPlatformCursor *QEglFSHooks::createCursor(QPlatformScreen *screen) const { - return new QEglFSCursor(screen); + return new QEGLPlatformCursor(screen); } void QEglFSHooks::waitForVSync() const diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/qeglfsintegration.cpp index d6832493f1..dfe240a888 100644 --- a/src/plugins/platforms/eglfs/qeglfsintegration.cpp +++ b/src/plugins/platforms/eglfs/qeglfsintegration.cpp @@ -42,15 +42,10 @@ #include "qeglfsintegration.h" #include "qeglfswindow.h" -#include "qeglfsbackingstore.h" -#include "qeglfscompositor.h" #include "qeglfshooks.h" #include <QtGui/private/qguiapplication_p.h> -#include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h> -#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h> -#include <QtPlatformSupport/private/qgenericunixservices_p.h> #include <QtPlatformSupport/private/qeglconvenience_p.h> #include <QtPlatformSupport/private/qeglplatformcontext_p.h> #include <QtPlatformSupport/private/qeglpbuffer_p.h> @@ -68,8 +63,6 @@ #include <QtGui/QOffscreenSurface> #include <qpa/qplatformcursor.h> -#include <qpa/qplatforminputcontextfactory_p.h> - #include "qeglfscontext.h" #include <EGL/egl.h> @@ -82,10 +75,6 @@ static void initResources() QT_BEGIN_NAMESPACE QEglFSIntegration::QEglFSIntegration() - : mFontDb(new QGenericUnixFontDatabase) - , mServices(new QGenericUnixServices) - , mScreen(0) - , mInputContext(0) { mDisableInputHandlers = qgetenv("QT_QPA_EGLFS_DISABLE_INPUT").toInt(); @@ -94,9 +83,6 @@ QEglFSIntegration::QEglFSIntegration() QEglFSIntegration::~QEglFSIntegration() { - QEglFSCompositor::destroy(); - delete mScreen; - eglTerminate(mDisplay); QEglFSHooks::hooks()->platformDestroy(); } @@ -106,33 +92,12 @@ bool QEglFSIntegration::hasCapability(QPlatformIntegration::Capability cap) cons if (QEglFSHooks::hooks() && QEglFSHooks::hooks()->hasCapability(cap)) return true; - switch (cap) { - case ThreadedPixmaps: return true; - case OpenGL: return true; - case ThreadedOpenGL: return true; - case WindowManagement: return false; - default: return QPlatformIntegration::hasCapability(cap); - } -} - -QPlatformWindow *QEglFSIntegration::createPlatformWindow(QWindow *window) const -{ - QWindowSystemInterface::flushWindowSystemEvents(); - QEglFSWindow *w = new QEglFSWindow(window); - w->create(); - if (window->type() != Qt::ToolTip) - w->requestActivateWindow(); - return w; -} - -QPlatformBackingStore *QEglFSIntegration::createPlatformBackingStore(QWindow *window) const -{ - return new QEglFSBackingStore(window); + return QEGLPlatformIntegration::hasCapability(cap); } QPlatformOpenGLContext *QEglFSIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { - return new QEglFSContext(QEglFSHooks::hooks()->surfaceFormatFor(context->format()), context->shareHandle(), mDisplay); + return new QEglFSContext(QEglFSHooks::hooks()->surfaceFormatFor(context->format()), context->shareHandle(), display()); } QPlatformOffscreenSurface *QEglFSIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const @@ -141,164 +106,40 @@ QPlatformOffscreenSurface *QEglFSIntegration::createPlatformOffscreenSurface(QOf return new QEGLPbuffer(screen->display(), QEglFSHooks::hooks()->surfaceFormatFor(surface->requestedFormat()), surface); } -QPlatformFontDatabase *QEglFSIntegration::fontDatabase() const -{ - return mFontDb.data(); -} - -QAbstractEventDispatcher *QEglFSIntegration::createEventDispatcher() const -{ - return createUnixEventDispatcher(); -} - void QEglFSIntegration::initialize() { QEglFSHooks::hooks()->platformInit(); - EGLint major, minor; - - if (!eglBindAPI(EGL_OPENGL_ES_API)) { - qWarning("Could not bind GL_ES API\n"); - qFatal("EGL error"); - } - - 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"); - } - - if (!eglInitialize(mDisplay, &major, &minor)) { - qWarning("Could not initialize egl display\n"); - qFatal("EGL error"); - } - - mScreen = createScreen(); - screenAdded(mScreen); - - mInputContext = QPlatformInputContextFactory::create(); + QEGLPlatformIntegration::initialize(); if (!mDisableInputHandlers) createInputHandlers(); } -QEglFSScreen *QEglFSIntegration::createScreen() const +EGLNativeDisplayType QEglFSIntegration::nativeDisplay() const { - return new QEglFSScreen(mDisplay); + return QEglFSHooks::hooks()->platformDisplay(); } -QVariant QEglFSIntegration::styleHint(QPlatformIntegration::StyleHint hint) const +QEGLPlatformScreen *QEglFSIntegration::createScreen() const { - switch (hint) - { - case QPlatformIntegration::ShowIsFullScreen: - return mScreen->rootWindow() == 0; - default: - return QPlatformIntegration::styleHint(hint); - } -} - -QPlatformServices *QEglFSIntegration::services() const -{ - return mServices.data(); + return new QEglFSScreen(display()); } -QPlatformNativeInterface *QEglFSIntegration::nativeInterface() const +QEGLPlatformWindow *QEglFSIntegration::createWindow(QWindow *window) const { - return const_cast<QEglFSIntegration *>(this); + return new QEglFSWindow(window); } -enum ResourceType { - EglDisplay, - EglWindow, - EglContext -}; - -static int resourceType(const QByteArray &key) -{ - static const QByteArray names[] = { // match ResourceType - QByteArrayLiteral("egldisplay"), - QByteArrayLiteral("eglwindow"), - QByteArrayLiteral("eglcontext") - }; - const QByteArray *end = names + sizeof(names) / sizeof(names[0]); - const QByteArray *result = std::find(names, end, key); - if (result == end) - result = std::find(names, end, key.toLower()); - return int(result - names); -} - -void *QEglFSIntegration::nativeResourceForIntegration(const QByteArray &resource) -{ - void *result = 0; - - switch (resourceType(resource)) { - case EglDisplay: - result = mScreen->display(); - break; - default: - break; - } - - return result; -} - -void *QEglFSIntegration::nativeResourceForWindow(const QByteArray &resource, QWindow *window) -{ - void *result = 0; - - switch (resourceType(resource)) { - case EglDisplay: - if (window && window->handle()) - result = static_cast<QEglFSScreen *>(window->handle()->screen())->display(); - else - result = mScreen->display(); - break; - case EglWindow: - if (window && window->handle()) - result = reinterpret_cast<void*>(static_cast<QEglFSWindow *>(window->handle())->eglWindow()); - break; - default: - break; - } - - return result; -} - -void *QEglFSIntegration::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) +QVariant QEglFSIntegration::styleHint(QPlatformIntegration::StyleHint hint) const { - void *result = 0; - - switch (resourceType(resource)) { - case EglContext: - if (context->handle()) - result = static_cast<QEGLPlatformContext *>(context->handle())->eglContext(); - break; + switch (hint) + { + case QPlatformIntegration::ShowIsFullScreen: + return screen()->compositingWindow() == 0; default: - break; + return QPlatformIntegration::styleHint(hint); } - - return result; -} - -static void *eglContextForContext(QOpenGLContext *context) -{ - Q_ASSERT(context); - - QEGLPlatformContext *handle = static_cast<QEGLPlatformContext *>(context->handle()); - if (!handle) - return 0; - - return handle->eglContext(); -} - -QPlatformNativeInterface::NativeResourceForContextFunction QEglFSIntegration::nativeResourceFunctionForContext(const QByteArray &resource) -{ - QByteArray lowerCaseResource = resource.toLower(); - if (lowerCaseResource == "get_egl_context") - return NativeResourceForContextFunction(eglContextForContext); - - return 0; } EGLConfig QEglFSIntegration::chooseConfig(EGLDisplay display, const QSurfaceFormat &format) diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.h b/src/plugins/platforms/eglfs/qeglfsintegration.h index 12c8158bd1..581b523c76 100644 --- a/src/plugins/platforms/eglfs/qeglfsintegration.h +++ b/src/plugins/platforms/eglfs/qeglfsintegration.h @@ -42,61 +42,36 @@ #ifndef QEGLFSINTEGRATION_H #define QEGLFSINTEGRATION_H -#include "qeglfsscreen.h" - -#include <qpa/qplatformintegration.h> -#include <qpa/qplatformnativeinterface.h> +#include <QtPlatformSupport/private/qeglplatformintegration_p.h> #include <qpa/qplatformscreen.h> +#include <EGL/egl.h> QT_BEGIN_NAMESPACE -class QEglFSIntegration : public QPlatformIntegration, public QPlatformNativeInterface +class QEglFSIntegration : public QEGLPlatformIntegration { public: QEglFSIntegration(); ~QEglFSIntegration(); - bool hasCapability(QPlatformIntegration::Capability cap) const; - - 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; - QPlatformServices *services() const; - - QAbstractEventDispatcher *createEventDispatcher() const; - void initialize(); + QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const Q_DECL_OVERRIDE; + QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const Q_DECL_OVERRIDE; - QVariant styleHint(QPlatformIntegration::StyleHint hint) const; + void initialize() Q_DECL_OVERRIDE; - // QPlatformNativeInterface - void *nativeResourceForIntegration(const QByteArray &resource); - void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) Q_DECL_OVERRIDE; - void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context); + bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE; + QVariant styleHint(QPlatformIntegration::StyleHint hint) const Q_DECL_OVERRIDE; - NativeResourceForContextFunction nativeResourceFunctionForContext(const QByteArray &resource) Q_DECL_OVERRIDE; - - QPlatformScreen *screen() const { return mScreen; } static EGLConfig chooseConfig(EGLDisplay display, const QSurfaceFormat &format); - EGLDisplay display() const { return mDisplay; } - - QPlatformInputContext *inputContext() const { return mInputContext; } - protected: - virtual QEglFSScreen *createScreen() const; + QEGLPlatformScreen *createScreen() const Q_DECL_OVERRIDE; + QEGLPlatformWindow *createWindow(QWindow *window) const Q_DECL_OVERRIDE; + EGLNativeDisplayType nativeDisplay() const Q_DECL_OVERRIDE; private: void createInputHandlers(); - EGLDisplay mDisplay; - QScopedPointer<QPlatformFontDatabase> mFontDb; - QScopedPointer<QPlatformServices> mServices; - QEglFSScreen *mScreen; - QPlatformInputContext *mInputContext; bool mDisableInputHandlers; }; diff --git a/src/plugins/platforms/eglfs/qeglfsscreen.cpp b/src/plugins/platforms/eglfs/qeglfsscreen.cpp index 758b461b3f..11c1160ce9 100644 --- a/src/plugins/platforms/eglfs/qeglfsscreen.cpp +++ b/src/plugins/platforms/eglfs/qeglfsscreen.cpp @@ -39,39 +39,25 @@ ** ****************************************************************************/ -#include "qeglfscursor.h" #include "qeglfsscreen.h" #include "qeglfswindow.h" #include "qeglfshooks.h" - -#if !defined(QT_NO_EVDEV) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_NO_SDK)) -#include <QtPlatformSupport/private/qdevicediscovery_p.h> -#endif +#include <QtPlatformSupport/private/qeglplatformcursor_p.h> QT_BEGIN_NAMESPACE QEglFSScreen::QEglFSScreen(EGLDisplay dpy) - : m_dpy(dpy), + : QEGLPlatformScreen(dpy), m_surface(EGL_NO_SURFACE), m_cursor(0), + m_rootWindow(0), m_rootContext(0) { #ifdef QEGL_EXTRA_DEBUG qWarning("QEglScreen %p\n", this); #endif - QByteArray hideCursorVal = qgetenv("QT_QPA_EGLFS_HIDECURSOR"); - bool hideCursor = false; - if (hideCursorVal.isEmpty()) { -#if !defined(QT_NO_EVDEV) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_NO_SDK)) - QScopedPointer<QDeviceDiscovery> dis(QDeviceDiscovery::create(QDeviceDiscovery::Device_Mouse)); - hideCursor = dis->scanConnectedDevices().isEmpty(); -#endif - } else { - hideCursor = hideCursorVal.toInt() != 0; - } - if (!hideCursor) - m_cursor = QEglFSHooks::hooks()->createCursor(this); + m_cursor = QEglFSHooks::hooks()->createCursor(this); } QEglFSScreen::~QEglFSScreen() @@ -124,50 +110,4 @@ void QEglFSScreen::setPrimarySurface(EGLSurface surface) m_surface = surface; } -void QEglFSScreen::addWindow(QEglFSWindow *window) -{ - if (!m_windows.contains(window)) { - m_windows.append(window); - topWindowChanged(window); - } -} - -void QEglFSScreen::removeWindow(QEglFSWindow *window) -{ - m_windows.removeOne(window); - if (!m_windows.isEmpty()) - topWindowChanged(m_windows.last()); -} - -void QEglFSScreen::moveToTop(QEglFSWindow *window) -{ - m_windows.removeOne(window); - m_windows.append(window); - topWindowChanged(window); -} - -void QEglFSScreen::changeWindowIndex(QEglFSWindow *window, int newIdx) -{ - int idx = m_windows.indexOf(window); - if (idx != -1 && idx != newIdx) { - m_windows.move(idx, newIdx); - if (newIdx == m_windows.size() - 1) - topWindowChanged(m_windows.last()); - } -} - -QEglFSWindow *QEglFSScreen::rootWindow() -{ - Q_FOREACH (QEglFSWindow *window, m_windows) { - if (window->hasNativeWindow()) - return window; - } - return 0; -} - -void QEglFSScreen::topWindowChanged(QPlatformWindow *window) -{ - Q_UNUSED(window); -} - QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/qeglfsscreen.h b/src/plugins/platforms/eglfs/qeglfsscreen.h index 11d66b7e0f..13f7cfddd8 100644 --- a/src/plugins/platforms/eglfs/qeglfsscreen.h +++ b/src/plugins/platforms/eglfs/qeglfsscreen.h @@ -42,7 +42,7 @@ #ifndef QEGLFSSCREEN_H #define QEGLFSSCREEN_H -#include <qpa/qplatformscreen.h> +#include <QtPlatformSupport/private/qeglplatformscreen_p.h> #include <QtCore/QTextStream> @@ -50,52 +50,48 @@ QT_BEGIN_NAMESPACE -class QEglFSCursor; +class QEGLPlatformCursor; class QEglFSWindow; class QOpenGLContext; -class QEglFSScreen : public QPlatformScreen +class QEglFSScreen : public QEGLPlatformScreen { public: QEglFSScreen(EGLDisplay display); ~QEglFSScreen(); - QRect geometry() const; - int depth() const; - QImage::Format format() const; + QRect geometry() const Q_DECL_OVERRIDE; + int depth() const Q_DECL_OVERRIDE; + QImage::Format format() const Q_DECL_OVERRIDE; - QSizeF physicalSize() const; - QDpi logicalDpi() const; - Qt::ScreenOrientation nativeOrientation() const; - Qt::ScreenOrientation orientation() const; + QSizeF physicalSize() const Q_DECL_OVERRIDE; + QDpi logicalDpi() const Q_DECL_OVERRIDE; + Qt::ScreenOrientation nativeOrientation() const Q_DECL_OVERRIDE; + Qt::ScreenOrientation orientation() const Q_DECL_OVERRIDE; - QPlatformCursor *cursor() const; + QPlatformCursor *cursor() const Q_DECL_OVERRIDE; - EGLDisplay display() const { return m_dpy; } EGLSurface primarySurface() const { return m_surface; } - QList<QEglFSWindow *> windows() const { return m_windows; } - void addWindow(QEglFSWindow *window); - void removeWindow(QEglFSWindow *window); - void moveToTop(QEglFSWindow *window); - void changeWindowIndex(QEglFSWindow *window, int newIdx); - QEglFSWindow *rootWindow(); - QOpenGLContext *rootContext() { return m_rootContext; } + QEGLPlatformWindow *compositingWindow() Q_DECL_OVERRIDE { return m_rootWindow; } + QOpenGLContext *compositingContext() Q_DECL_OVERRIDE { return m_rootContext; } + + void setRootWindow(QEGLPlatformWindow *window) { m_rootWindow = window; } void setRootContext(QOpenGLContext *context) { m_rootContext = context; } protected: void setPrimarySurface(EGLSurface surface); - virtual void topWindowChanged(QPlatformWindow *window); private: friend class QEglFSWindow; EGLDisplay m_dpy; EGLSurface m_surface; - QEglFSCursor *m_cursor; - QList<QEglFSWindow *> m_windows; + QEGLPlatformCursor *m_cursor; + QEGLPlatformWindow *m_rootWindow; QOpenGLContext *m_rootContext; }; QT_END_NAMESPACE + #endif // QEGLFSSCREEN_H diff --git a/src/plugins/platforms/eglfs/qeglfswindow.cpp b/src/plugins/platforms/eglfs/qeglfswindow.cpp index bba00da128..279e7bbc91 100644 --- a/src/plugins/platforms/eglfs/qeglfswindow.cpp +++ b/src/plugins/platforms/eglfs/qeglfswindow.cpp @@ -41,13 +41,11 @@ #include "qeglfswindow.h" #include "qeglfshooks.h" -#include "qeglfscursor.h" -#include "qeglfsbackingstore.h" #include <qpa/qwindowsysteminterface.h> #include <qpa/qplatformintegration.h> #include <private/qguiapplication_p.h> #include <QtGui/QOpenGLContext> - +#include <QtPlatformSupport/private/qeglplatformcursor_p.h> #include <QtPlatformSupport/private/qeglconvenience_p.h> #include <QtDebug> @@ -55,11 +53,9 @@ QT_BEGIN_NAMESPACE QEglFSWindow::QEglFSWindow(QWindow *w) - : QPlatformWindow(w) + : QEGLPlatformWindow(w) , m_surface(0) , m_window(0) - , m_wid(0) - , m_backingStore(0) , m_flags(0) { #ifdef QEGL_EXTRA_DEBUG @@ -72,41 +68,24 @@ QEglFSWindow::~QEglFSWindow() destroy(); } -static WId newWId() -{ - static WId id = 0; - - if (id == std::numeric_limits<WId>::max()) - qWarning("EGLFS: Out of window IDs"); - - return ++id; -} - void QEglFSWindow::create() { if (m_flags.testFlag(Created)) return; + QEGLPlatformWindow::create(); + m_flags = Created; - m_wid = newWId(); - if (window()->type() == Qt::Desktop) { - QRect rect(QPoint(), QEglFSHooks::hooks()->screenSize()); - QPlatformWindow::setGeometry(rect); - QWindowSystemInterface::handleGeometryChange(window(), rect); + if (window()->type() == Qt::Desktop) return; - } - - // Save the original surface type before changing to OpenGLSurface. - if (window()->surfaceType() == QSurface::RasterSurface) - m_flags |= IsRaster; // Stop if there is already a window backed by a native window and surface. Additional // raster windows will not have their own native window, surface and context. Instead, // they will be composited onto the root window's surface. QEglFSScreen *screen = this->screen(); if (screen->primarySurface() != EGL_NO_SURFACE) { - if (m_flags.testFlag(IsRaster) && screen->rootWindow()->m_flags.testFlag(IsRaster)) + if (isRaster() && screen->compositingWindow()) return; #if !defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_NO_SDK) @@ -118,7 +97,6 @@ void QEglFSWindow::create() return; } - window()->setSurfaceType(QSurface::OpenGLSurface); m_flags |= HasNativeWindow; setGeometry(QRect()); // will become fullscreen QWindowSystemInterface::handleExposeEvent(window(), geometry()); @@ -126,18 +104,19 @@ void QEglFSWindow::create() EGLDisplay display = static_cast<QEglFSScreen *>(screen)->display(); QSurfaceFormat platformFormat = QEglFSHooks::hooks()->surfaceFormatFor(window()->requestedFormat()); m_config = QEglFSIntegration::chooseConfig(display, platformFormat); - m_format = q_glFormatFromConfig(display, m_config); + m_format = q_glFormatFromConfig(display, m_config, platformFormat); resetSurface(); screen->setPrimarySurface(m_surface); - if (m_flags.testFlag(IsRaster)) { + if (isRaster()) { QOpenGLContext *context = new QOpenGLContext(QGuiApplication::instance()); context->setFormat(window()->requestedFormat()); context->setScreen(window()->screen()); context->create(); screen->setRootContext(context); + screen->setRootWindow(this); } } @@ -145,7 +124,7 @@ void QEglFSWindow::destroy() { QEglFSScreen *screen = this->screen(); if (m_flags.testFlag(HasNativeWindow)) { - QEglFSCursor *cursor = static_cast<QEglFSCursor *>(screen->cursor()); + QEGLPlatformCursor *cursor = static_cast<QEGLPlatformCursor *>(screen->cursor()); if (cursor) cursor->resetResources(); @@ -188,7 +167,7 @@ void QEglFSWindow::resetSurface() void QEglFSWindow::setVisible(bool visible) { - QList<QEglFSWindow *> windows = screen()->windows(); + QList<QEGLPlatformWindow *> windows = screen()->windows(); if (window()->type() != Qt::Desktop) { if (visible) { @@ -234,11 +213,6 @@ QRect QEglFSWindow::geometry() const return QPlatformWindow::geometry(); } -WId QEglFSWindow::winId() const -{ - return m_wid; -} - void QEglFSWindow::requestActivateWindow() { if (window()->type() != Qt::Desktop) @@ -258,7 +232,7 @@ void QEglFSWindow::raise() void QEglFSWindow::lower() { - QList<QEglFSWindow *> windows = screen()->windows(); + QList<QEGLPlatformWindow *> windows = screen()->windows(); if (window()->type() != Qt::Desktop && windows.count() > 1) { int idx = windows.indexOf(this); if (idx > 0) { @@ -288,12 +262,4 @@ QEglFSScreen *QEglFSWindow::screen() const return static_cast<QEglFSScreen *>(QPlatformWindow::screen()); } -uint QEglFSWindow::texture() const -{ - if (m_backingStore) - return m_backingStore->texture(); - - return 0; -} - QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/qeglfswindow.h b/src/plugins/platforms/eglfs/qeglfswindow.h index ee3c194a7c..f93a9d54bc 100644 --- a/src/plugins/platforms/eglfs/qeglfswindow.h +++ b/src/plugins/platforms/eglfs/qeglfswindow.h @@ -45,42 +45,32 @@ #include "qeglfsintegration.h" #include "qeglfsscreen.h" -#include <qpa/qplatformwindow.h> +#include <QtPlatformSupport/private/qeglplatformwindow_p.h> QT_BEGIN_NAMESPACE -class QEglFSBackingStore; - -class QEglFSWindow : public QPlatformWindow +class QEglFSWindow : public QEGLPlatformWindow { public: QEglFSWindow(QWindow *w); ~QEglFSWindow(); - void setGeometry(const QRect &); - QRect geometry() const; - WId winId() const; - void setVisible(bool visible); - void requestActivateWindow(); - void raise(); - void lower(); + void create() Q_DECL_OVERRIDE; + void destroy(); + + void setGeometry(const QRect &) Q_DECL_OVERRIDE; + QRect geometry() const Q_DECL_OVERRIDE; + void setVisible(bool visible) Q_DECL_OVERRIDE; + void requestActivateWindow() Q_DECL_OVERRIDE; + void raise() Q_DECL_OVERRIDE; + void lower() Q_DECL_OVERRIDE; + QSurfaceFormat format() const Q_DECL_OVERRIDE; + EGLNativeWindowType eglWindow() const Q_DECL_OVERRIDE; EGLSurface surface() const; - QSurfaceFormat format() const; - EGLNativeWindowType eglWindow() const; - QEglFSScreen *screen() const; - void create(); - void destroy(); - bool hasNativeWindow() const { return m_flags.testFlag(HasNativeWindow); } - bool isRaster() const { return m_flags.testFlag(IsRaster); } - - QEglFSBackingStore *backingStore() { return m_backingStore; } - void setBackingStore(QEglFSBackingStore *backingStore) { m_backingStore = backingStore; } - - uint texture() const; virtual void invalidateSurface(); virtual void resetSurface(); @@ -92,13 +82,10 @@ protected: private: EGLConfig m_config; QSurfaceFormat m_format; - WId m_wid; - QEglFSBackingStore *m_backingStore; enum Flag { Created = 0x01, - IsRaster = 0x02, - HasNativeWindow = 0x04 + HasNativeWindow = 0x02 }; Q_DECLARE_FLAGS(Flags, Flag); Flags m_flags; diff --git a/src/plugins/platforms/ios/ios.pro b/src/plugins/platforms/ios/ios.pro index 72716e6a4c..1dfb07ba08 100644 --- a/src/plugins/platforms/ios/ios.pro +++ b/src/plugins/platforms/ios/ios.pro @@ -38,4 +38,3 @@ HEADERS = \ qiosglobal.h \ qiosservices.h -#HEADERS = qiossoftwareinputhandler.h diff --git a/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp b/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp index 735a43daf7..c0691a38fc 100644 --- a/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp +++ b/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp @@ -41,6 +41,7 @@ #include "qlinuxfbscreen.h" #include <QtPlatformSupport/private/qfbcursor_p.h> +#include <QtCore/QRegularExpression> #include <QtGui/QPainter> #include <private/qcore_unix_p.h> // overrides QT_OPEN @@ -318,11 +319,11 @@ QLinuxFbScreen::~QLinuxFbScreen() bool QLinuxFbScreen::initialize() { - QRegExp ttyRx(QLatin1String("tty=(.*)")); - QRegExp fbRx(QLatin1String("fb=(.*)")); - QRegExp mmSizeRx(QLatin1String("mmsize=(\\d+)x(\\d+)")); - QRegExp sizeRx(QLatin1String("size=(\\d+)x(\\d+)")); - QRegExp offsetRx(QLatin1String("offset=(\\d+)x(\\d+)")); + QRegularExpression ttyRx(QLatin1String("tty=(.*)")); + QRegularExpression fbRx(QLatin1String("fb=(.*)")); + QRegularExpression mmSizeRx(QLatin1String("mmsize=(\\d+)x(\\d+)")); + QRegularExpression sizeRx(QLatin1String("size=(\\d+)x(\\d+)")); + QRegularExpression offsetRx(QLatin1String("offset=(\\d+)x(\\d+)")); QString fbDevice, ttyDevice; QSize userMmSize; @@ -331,18 +332,19 @@ bool QLinuxFbScreen::initialize() // Parse arguments foreach (const QString &arg, mArgs) { + QRegularExpressionMatch match; if (arg == QLatin1String("nographicsmodeswitch")) doSwitchToGraphicsMode = false; - else if (sizeRx.indexIn(arg) != -1) - userGeometry.setSize(QSize(sizeRx.cap(1).toInt(), sizeRx.cap(2).toInt())); - else if (offsetRx.indexIn(arg) != -1) - userGeometry.setTopLeft(QPoint(offsetRx.cap(1).toInt(), offsetRx.cap(2).toInt())); - else if (ttyRx.indexIn(arg) != -1) - ttyDevice = ttyRx.cap(1); - else if (fbRx.indexIn(arg) != -1) - fbDevice = fbRx.cap(1); - else if (mmSizeRx.indexIn(arg) != -1) - userMmSize = QSize(mmSizeRx.cap(1).toInt(), mmSizeRx.cap(2).toInt()); + else if (arg.contains(sizeRx, &match)) + userGeometry.setSize(QSize(match.captured(1).toInt(), match.captured(2).toInt())); + else if (arg.contains(offsetRx, &match)) + userGeometry.setTopLeft(QPoint(match.captured(1).toInt(), match.captured(2).toInt())); + else if (arg.contains(ttyRx, &match)) + ttyDevice = match.captured(1); + else if (arg.contains(fbRx, &match)) + fbDevice = match.captured(1); + else if (arg.contains(mmSizeRx, &match)) + userMmSize = QSize(match.captured(1).toInt(), match.captured(2).toInt()); } if (fbDevice.isEmpty()) { diff --git a/src/plugins/platforms/minimal/qminimalintegration.cpp b/src/plugins/platforms/minimal/qminimalintegration.cpp index 76b4b5b0eb..7f5c25f239 100644 --- a/src/plugins/platforms/minimal/qminimalintegration.cpp +++ b/src/plugins/platforms/minimal/qminimalintegration.cpp @@ -41,17 +41,20 @@ #include "qminimalintegration.h" #include "qminimalbackingstore.h" -#ifndef Q_OS_WIN -#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h> -#else -#include <QtCore/private/qeventdispatcher_win_p.h> -#endif #include <QtGui/private/qpixmap_raster_p.h> #include <QtGui/private/qguiapplication_p.h> #include <qpa/qplatformwindow.h> #include <qpa/qplatformfontdatabase.h> +#if !defined(Q_OS_WIN) +#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h> +#elif defined(Q_OS_WINRT) +#include <QtCore/private/qeventdispatcher_winrt_p.h> +#else +#include <QtCore/private/qeventdispatcher_win_p.h> +#endif + QT_BEGIN_NAMESPACE static const char debugBackingStoreEnvironmentVariable[] = "QT_DEBUG_BACKINGSTORE"; @@ -132,7 +135,11 @@ QPlatformBackingStore *QMinimalIntegration::createPlatformBackingStore(QWindow * QAbstractEventDispatcher *QMinimalIntegration::createEventDispatcher() const { #ifdef Q_OS_WIN +#ifndef Q_OS_WINRT return new QEventDispatcherWin32; +#else // !Q_OS_WINRT + return new QEventDispatcherWinRT; +#endif // Q_OS_WINRT #else return createUnixEventDispatcher(); #endif diff --git a/src/plugins/platforms/minimalegl/qminimaleglscreen.cpp b/src/plugins/platforms/minimalegl/qminimaleglscreen.cpp index ebc402550e..d26b20d364 100644 --- a/src/plugins/platforms/minimalegl/qminimaleglscreen.cpp +++ b/src/plugins/platforms/minimalegl/qminimaleglscreen.cpp @@ -101,16 +101,6 @@ QMinimalEglScreen::QMinimalEglScreen(EGLNativeDisplayType display) } qWarning("Initialized display %d %d\n", major, minor); - - int swapInterval = 1; - QByteArray swapIntervalString = qgetenv("QT_QPA_EGLFS_SWAPINTERVAL"); - if (!swapIntervalString.isEmpty()) { - bool ok; - swapInterval = swapIntervalString.toInt(&ok); - if (!ok) - swapInterval = 1; - } - eglSwapInterval(m_dpy, swapInterval); } QMinimalEglScreen::~QMinimalEglScreen() diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp index a1da8e3a16..76881db6fc 100644 --- a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp +++ b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp @@ -52,7 +52,11 @@ #endif #elif defined(Q_OS_WIN) #include <QtPlatformSupport/private/qbasicfontdatabase_p.h> +#ifndef Q_OS_WINRT #include <QtCore/private/qeventdispatcher_win_p.h> +#else +#include <QtCore/private/qeventdispatcher_winrt_p.h> +#endif #endif #include <QtGui/private/qpixmap_raster_p.h> @@ -143,7 +147,11 @@ QAbstractEventDispatcher *QOffscreenIntegration::createEventDispatcher() const #if defined(Q_OS_UNIX) return createUnixEventDispatcher(); #elif defined(Q_OS_WIN) +#ifndef Q_OS_WINRT return new QOffscreenEventDispatcher<QEventDispatcherWin32>(); +#else // !Q_OS_WINRT + return new QOffscreenEventDispatcher<QEventDispatcherWinRT>(); +#endif // Q_OS_WINRT #else return 0; #endif diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro index 377ca32e64..584efa1665 100644 --- a/src/plugins/platforms/platforms.pro +++ b/src/plugins/platforms/platforms.pro @@ -15,7 +15,12 @@ mac { else: SUBDIRS += cocoa } -win32: SUBDIRS += windows +win32:!winrt: SUBDIRS += windows +winrt: SUBDIRS += winrt + +contains(QT_CONFIG, direct2d) { + SUBDIRS += direct2d +} qnx { SUBDIRS += qnx diff --git a/src/plugins/platforms/qnx/qnx.pro b/src/plugins/platforms/qnx/qnx.pro index bc7219de5c..100db54a5c 100644 --- a/src/plugins/platforms/qnx/qnx.pro +++ b/src/plugins/platforms/qnx/qnx.pro @@ -62,7 +62,8 @@ HEADERS = main.h \ qqnxabstractcover.h \ qqnxservices.h \ qqnxcursor.h \ - qqnxrasterwindow.h + qqnxrasterwindow.h \ + qqnxscreeneventfilter.h CONFIG(qqnx_screeneventthread) { DEFINES += QQNX_SCREENEVENTTHREAD diff --git a/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.cpp b/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.cpp index a42f73415e..800cb96bdf 100644 --- a/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.cpp +++ b/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.cpp @@ -1,6 +1,6 @@ /*************************************************************************** ** -** Copyright (C) 2011 - 2012 Research In Motion +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -49,6 +49,7 @@ QQnxAbstractVirtualKeyboard::QQnxAbstractVirtualKeyboard(QObject *parent) , m_visible(false) , m_locale(QLocale::system()) , m_keyboardMode(Default) + , m_enterKeyType(DefaultReturn) { } @@ -59,26 +60,35 @@ void QQnxAbstractVirtualKeyboard::setKeyboardMode(KeyboardMode mode) m_keyboardMode = mode; - applyKeyboardMode(mode); + if (m_visible) + applyKeyboardOptions(); } -void QQnxAbstractVirtualKeyboard::setInputHintsFromObject(QObject *focusObject) +void QQnxAbstractVirtualKeyboard::setEnterKeyType(EnterKeyType type) { - if (focusObject) { - const Qt::InputMethodHints hints = static_cast<Qt::InputMethodHints>( - focusObject->property("inputMethodHints").toInt()); - if (hints & Qt::ImhEmailCharactersOnly) { - setKeyboardMode(QQnxAbstractVirtualKeyboard::Email); - } else if (hints & Qt::ImhDialableCharactersOnly) { - setKeyboardMode(QQnxAbstractVirtualKeyboard::Phone); - } else if (hints & Qt::ImhUrlCharactersOnly) { - setKeyboardMode(QQnxAbstractVirtualKeyboard::Web); - } else if (hints & Qt::ImhFormattedNumbersOnly || hints & Qt::ImhDigitsOnly || - hints & Qt::ImhDate || hints & Qt::ImhTime) { - setKeyboardMode(QQnxAbstractVirtualKeyboard::NumPunc); - } else { - setKeyboardMode(QQnxAbstractVirtualKeyboard::Default); - } + if (type == m_enterKeyType) + return; + + m_enterKeyType = type; + + if (m_visible) + applyKeyboardOptions(); +} + +void QQnxAbstractVirtualKeyboard::setInputHints(int inputHints) +{ + if (inputHints & Qt::ImhEmailCharactersOnly) { + setKeyboardMode(QQnxAbstractVirtualKeyboard::Email); + } else if (inputHints & Qt::ImhDialableCharactersOnly) { + setKeyboardMode(QQnxAbstractVirtualKeyboard::Phone); + } else if (inputHints & Qt::ImhUrlCharactersOnly) { + setKeyboardMode(QQnxAbstractVirtualKeyboard::Url); + } else if (inputHints & Qt::ImhFormattedNumbersOnly || inputHints & Qt::ImhDigitsOnly) { + setKeyboardMode(QQnxAbstractVirtualKeyboard::Number); + } else if (inputHints & Qt::ImhDate || inputHints & Qt::ImhTime) { + setKeyboardMode(QQnxAbstractVirtualKeyboard::NumPunc); // Use NumPunc so that : is available. + } else if (inputHints & Qt::ImhHiddenText) { + setKeyboardMode(QQnxAbstractVirtualKeyboard::Password); } else { setKeyboardMode(QQnxAbstractVirtualKeyboard::Default); } diff --git a/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.h b/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.h index 9b911e1dec..bff8c56835 100644 --- a/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.h +++ b/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.h @@ -1,6 +1,6 @@ /*************************************************************************** ** -** Copyright (C) 2011 - 2012 Research In Motion +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -51,18 +51,20 @@ class QQnxAbstractVirtualKeyboard : public QObject { Q_OBJECT public: - // NOTE: Not all the following keyboard modes are currently used. + // Keyboard Types currently supported. // Default - Regular Keyboard // Url/Email - Enhanced keys for each types. // Web - Regular keyboard with two blank keys, currently unused. // NumPunc - Numbers & Punctionation, alternate to Symbol + // Number - Number pad // Symbol - All symbols, alternate to NumPunc, currently unused. - // Phone - Phone enhanced keyboard - currently unused as no alternate keyboard available to access a-zA-Z - // Pin - Keyboard for entering Pins (Hex values) currently unused. + // Phone - Phone enhanced keyboard + // Pin - Keyboard for entering Pins (Hex values). + // Password - Keyboard with lots of extra characters for password input. + // Alphanumeric - Similar to password without any of the security implications. // - // SPECIAL NOTE: Usage of NumPunc may have to be removed, ABC button is non-functional. - // - enum KeyboardMode { Default, Url, Email, Web, NumPunc, Symbol, Phone, Pin }; + enum KeyboardMode { Default, Url, Email, Web, NumPunc, Number, Symbol, Phone, Pin, Password, Alphanumeric }; + enum EnterKeyType { DefaultReturn, Connect, Done, Go, Join, Next, Search, Send, Submit }; explicit QQnxAbstractVirtualKeyboard(QObject *parent = 0); @@ -74,8 +76,11 @@ public: QLocale locale() const { return m_locale; } void setKeyboardMode(KeyboardMode mode); - void setInputHintsFromObject(QObject *focusObject); + void setEnterKeyType(EnterKeyType type); + + void setInputHints(int inputHints); KeyboardMode keyboardMode() const { return m_keyboardMode; } + EnterKeyType enterKeyType() const { return m_enterKeyType; } Q_SIGNALS: void heightChanged(int height); @@ -83,7 +88,7 @@ Q_SIGNALS: void localeChanged(const QLocale &locale); protected: - virtual void applyKeyboardMode(KeyboardMode mode) = 0; + virtual void applyKeyboardOptions() = 0; void setHeight(int height); void setVisible(bool visible); @@ -94,6 +99,7 @@ private: bool m_visible; QLocale m_locale; KeyboardMode m_keyboardMode; + EnterKeyType m_enterKeyType; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxeglwindow.cpp b/src/plugins/platforms/qnx/qqnxeglwindow.cpp index b57227a60b..1aad25a418 100644 --- a/src/plugins/platforms/qnx/qqnxeglwindow.cpp +++ b/src/plugins/platforms/qnx/qqnxeglwindow.cpp @@ -97,8 +97,8 @@ void QQnxEglWindow::createEGLSurface() , platformOpenGLContext()->getEglConfig(), (EGLNativeWindowType) nativeHandle(), eglSurfaceAttrs); if (m_eglSurface == EGL_NO_SURFACE) { - QQnxGLContext::checkEGLError("eglCreateWindowSurface"); - qFatal("QQNX: failed to create EGL surface, err=%d", eglGetError()); + const EGLenum error = QQnxGLContext::checkEGLError("eglCreateWindowSurface"); + qFatal("QQNX: failed to create EGL surface, err=%d", error); } } diff --git a/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp b/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp index 580553f6e2..619883e843 100644 --- a/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp +++ b/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp @@ -1,6 +1,6 @@ /*************************************************************************** ** -** Copyright (C) 2011 - 2012 Research In Motion +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -40,10 +40,10 @@ ****************************************************************************/ #include "qqnxinputcontext_imf.h" -#include "qqnxeventthread.h" #include "qqnxabstractvirtualkeyboard.h" #include "qqnxintegration.h" #include "qqnxscreen.h" +#include "qqnxscreeneventhandler.h" #include <QtGui/QGuiApplication> #include <QtGui/QInputMethodEvent> @@ -54,6 +54,8 @@ #include <QtCore/QVariant> #include <QtCore/QVariantHash> #include <QtCore/QWaitCondition> +#include <QtCore/QQueue> +#include <QtCore/QGlobalStatic> #include <dlfcn.h> #include "imf/imf_client.h" @@ -62,9 +64,9 @@ #include <sys/keycodes.h> #if defined(QQNXINPUTCONTEXT_IMF_EVENT_DEBUG) -#define qInputContextIMFEventDebug qDebug +#define qInputContextIMFRequestDebug qDebug #else -#define qInputContextIMFEventDebug QT_NO_QDEBUG_MACRO +#define qInputContextIMFRequestDebug QT_NO_QDEBUG_MACRO #endif #if defined(QQNXINPUTCONTEXT_DEBUG) @@ -73,492 +75,426 @@ #define qInputContextDebug QT_NO_QDEBUG_MACRO #endif -/** TODO: - Support inputMethodHints to restrict input (needs additional features in IMF). -*/ +static QQnxInputContext *sInputContextInstance; +static QColor sSelectedColor(0,0xb8,0,85); -#define STRX(x) #x -#define STR(x) STRX(x) - -// Someone tell me why input_control methods are in this namespace, but the rest is not. -using namespace InputMethodSystem; - -#define qs(x) QString::fromLatin1(x) -#define iarg(name) event->mArgs[qs(#name)] = QVariant::fromValue(name) -#define parg(name) event->mArgs[qs(#name)] = QVariant::fromValue((void*)name) -namespace -{ - -spannable_string_t *toSpannableString(const QString &text); +static const input_session_t *sSpellCheckSession = 0; static const input_session_t *sInputSession = 0; -bool isSessionOkay(input_session_t *ic) +static bool isSessionOkay(input_session_t *ic) { return ic !=0 && sInputSession != 0 && ic->component_id == sInputSession->component_id; } enum ImfEventType { - ImfBeginBatchEdit, - ImfClearMetaKeyStates, ImfCommitText, ImfDeleteSurroundingText, - ImfEndBatchEdit, ImfFinishComposingText, - ImfGetCursorCapsMode, ImfGetCursorPosition, - ImfGetExtractedText, - ImfGetSelectedText, ImfGetTextAfterCursor, ImfGetTextBeforeCursor, - ImfPerformEditorAction, - ImfReportFullscreenMode, ImfSendEvent, - ImfSendAsyncEvent, ImfSetComposingRegion, ImfSetComposingText, - ImfSetSelection + ImfIsTextSelected, + ImfIsAllTextSelected, }; -// We use this class as a round about way to support a posting synchronous event into -// Qt's main thread from the IMF thread. -class ImfEventResult -{ -public: - ImfEventResult() - { - m_mutex.lock(); - } - - ~ImfEventResult() - { - m_mutex.unlock(); - } - - void wait() - { - m_wait.wait(&m_mutex); - } - - void signal() - { - m_wait.wakeAll(); - } - - void setResult(const QVariant& result) - { - m_mutex.lock(); - m_retVal = result; - signal(); - m_mutex.unlock(); - } - - QVariant result() - { - return m_retVal; - } - -private: - QVariant m_retVal; - QMutex m_mutex; - QWaitCondition m_wait; +struct SpellCheckInfo { + SpellCheckInfo(void *_context, void (*_spellCheckDone)(void *, const QString &, const QList<int> &)) + : context(_context), spellCheckDone(_spellCheckDone) {} + void *context; + void (*spellCheckDone)(void *, const QString &, const QList<int> &); }; +Q_GLOBAL_STATIC(QQueue<SpellCheckInfo>, sSpellCheckQueue) -class ImfEvent : public QEvent +// IMF requests all arrive on IMF's own thread and have to be posted to the main thread to be processed. +class QQnxImfRequest { - public: - ImfEvent(input_session_t *session, ImfEventType type, ImfEventResult *result) : - QEvent((QEvent::Type)sUserEventType), - m_session(session), - m_imfType(type), - m_result(result) - { - } - ~ImfEvent() { } - - input_session_t *m_session; - ImfEventType m_imfType; - QVariantHash m_args; - ImfEventResult *m_result; - - static int sUserEventType; +public: + QQnxImfRequest(input_session_t *_session, ImfEventType _type) + : session(_session), type(_type) + { } + ~QQnxImfRequest() { } + + input_session_t *session; + ImfEventType type; + union { + struct { + int32_t n; + int32_t flags; + bool before; + spannable_string_t *result; + } gtac; // ic_get_text_before_cursor/ic_get_text_after_cursor + struct { + int32_t result; + } gcp; // ic_get_cursor_position + struct { + int32_t start; + int32_t end; + int32_t result; + } scr; // ic_set_composing_region + struct { + spannable_string_t* text; + int32_t new_cursor_position; + int32_t result; + } sct; // ic_set_composing_text + struct { + spannable_string_t* text; + int32_t new_cursor_position; + int32_t result; + } ct; // ic_commit_text + struct { + int32_t result; + } fct; // ic_finish_composing_text + struct { + int32_t left_length; + int32_t right_length; + int32_t result; + } dst; // ic_delete_surrounding_text + struct { + event_t *event; + int32_t result; + } sae; // ic_send_async_event/ic_send_event + struct { + int32_t *pIsSelected; + int32_t result; + } its; // ic_is_text_selected/ic_is_all_text_selected + }; }; -int ImfEvent::sUserEventType = QEvent::registerEventType(); -static int32_t imfBeginBatchEdit(input_session_t *ic) +// Invoke an IMF initiated request synchronously on Qt's main thread. As describe below all +// IMF requests are made from another thread but need to be executed on the main thread. +static void executeIMFRequest(QQnxImfRequest *event) +{ + QMetaObject::invokeMethod(sInputContextInstance, + "processImfEvent", + Qt::BlockingQueuedConnection, + Q_ARG(QQnxImfRequest*, event)); +} + +// The following functions (ic_*) are callback functions called by the input system to query information +// about the text object that currently has focus or to make changes to it. All calls are made from the +// input system's own thread. The pattern for each callback function is to copy its parameters into +// a QQnxImfRequest structure and call executeIMFRequest to have it passed synchronously to Qt's main thread. +// Any return values should be pre-initialised with suitable default values as in some cases +// (e.g. a stale session) the call will return without having executed any request specific code. +// +// To make the correspondence more obvious, the names of these functions match those defined in the headers. +// They're in an anonymous namespace to avoid compiler conflicts with external functions defined with the +// same names. +namespace { - qInputContextIMFEventDebug() << Q_FUNC_INFO; - - if (!isSessionOkay(ic)) - return 0; - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfBeginBatchEdit, &result); - QCoreApplication::postEvent(QCoreApplication::instance(), event); - - result.wait(); - int32_t ret = result.result().value<int32_t>(); +// See comment at beginning of namespace declaration for general information +static int32_t ic_begin_batch_edit(input_session_t *ic) +{ + Q_UNUSED(ic); - return ret; + // Ignore silently. + return 0; } -static int32_t imfClearMetaKeyStates(input_session_t *ic, int32_t states) +// End composition, committing the supplied text. +// See comment at beginning of namespace declaration for general information +static int32_t ic_commit_text(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position) { - qInputContextIMFEventDebug() << Q_FUNC_INFO; + qInputContextIMFRequestDebug() << Q_FUNC_INFO; - if (!isSessionOkay(ic)) - return 0; - - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfClearMetaKeyStates, &result); - iarg(states); - - QCoreApplication::postEvent(QCoreApplication::instance(), event); - - result.wait(); - int32_t ret = result.result().value<int32_t>(); + QQnxImfRequest event(ic, ImfCommitText); + event.ct.text = text; + event.ct.new_cursor_position = new_cursor_position; + event.ct.result = -1; + executeIMFRequest(&event); - return ret; + return event.ct.result; } -static int32_t imfCommitText(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position) +// Delete left_length characters before and right_length characters after the cursor. +// See comment at beginning of namespace declaration for general information +static int32_t ic_delete_surrounding_text(input_session_t *ic, int32_t left_length, int32_t right_length) { - qInputContextIMFEventDebug() << Q_FUNC_INFO; - - if (!isSessionOkay(ic)) - return 0; - - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfCommitText, &result); - parg(text); - iarg(new_cursor_position); + qInputContextIMFRequestDebug() << Q_FUNC_INFO; - QCoreApplication::postEvent(QCoreApplication::instance(), event); + QQnxImfRequest event(ic, ImfDeleteSurroundingText); + event.dst.left_length = left_length; + event.dst.right_length = right_length; + event.dst.result = -1; + executeIMFRequest(&event); - result.wait(); - int32_t ret = result.result().value<int32_t>(); - - return ret; + return event.dst.result; } -static int32_t imfDeleteSurroundingText(input_session_t *ic, int32_t left_length, int32_t right_length) +// See comment at beginning of namespace declaration for general information +static int32_t ic_end_batch_edit(input_session_t *ic) { - qInputContextIMFEventDebug() << Q_FUNC_INFO; - - if (!isSessionOkay(ic)) - return 0; - - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfDeleteSurroundingText, &result); - iarg(left_length); - iarg(right_length); + Q_UNUSED(ic); - QCoreApplication::postEvent(QCoreApplication::instance(), event); - - result.wait(); - int32_t ret = result.result().value<int32_t>(); - - return ret; + // Ignore silently. + return 0; } -static int32_t imfEndBatchEdit(input_session_t *ic) +// End composition, committing what's there. +// See comment at beginning of namespace declaration for general information +static int32_t ic_finish_composing_text(input_session_t *ic) { - qInputContextIMFEventDebug() << Q_FUNC_INFO; + qInputContextIMFRequestDebug() << Q_FUNC_INFO; - if (!isSessionOkay(ic)) - return 0; - - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfEndBatchEdit, &result); - - QCoreApplication::postEvent(QCoreApplication::instance(), event); - - result.wait(); - int32_t ret = result.result().value<int32_t>(); + QQnxImfRequest event(ic, ImfFinishComposingText); + event.fct.result = -1; + executeIMFRequest(&event); - return ret; + return event.fct.result; } -static int32_t imfFinishComposingText(input_session_t *ic) +// Return the position of the cursor. +// See comment at beginning of namespace declaration for general information +static int32_t ic_get_cursor_position(input_session_t *ic) { - qInputContextIMFEventDebug() << Q_FUNC_INFO; - - if (!isSessionOkay(ic)) - return 0; - - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfFinishComposingText, &result); + qInputContextIMFRequestDebug() << Q_FUNC_INFO; - QCoreApplication::postEvent(QCoreApplication::instance(), event); + QQnxImfRequest event(ic, ImfGetCursorPosition); + event.gcp.result = -1; + executeIMFRequest(&event); - result.wait(); - int32_t ret = result.result().value<int32_t>(); - - return ret; + return event.gcp.result; } -static int32_t imfGetCursorCapsMode(input_session_t *ic, int32_t req_modes) +// Return the n characters after the cursor. +// See comment at beginning of namespace declaration for general information +static spannable_string_t *ic_get_text_after_cursor(input_session_t *ic, int32_t n, int32_t flags) { - qInputContextIMFEventDebug() << Q_FUNC_INFO; - - if (!isSessionOkay(ic)) - return 0; - - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfGetCursorCapsMode, &result); - iarg(req_modes); + qInputContextIMFRequestDebug() << Q_FUNC_INFO; - QCoreApplication::postEvent(QCoreApplication::instance(), event); + QQnxImfRequest event(ic, ImfGetTextAfterCursor); + event.gtac.n = n; + event.gtac.flags = flags; + event.gtac.result = 0; + executeIMFRequest(&event); - int32_t ret = result.result().value<int32_t>(); - return ret; + return event.gtac.result; } -static int32_t imfGetCursorPosition(input_session_t *ic) +// Return the n characters before the cursor. +// See comment at beginning of namespace declaration for general information +static spannable_string_t *ic_get_text_before_cursor(input_session_t *ic, int32_t n, int32_t flags) { - qInputContextIMFEventDebug() << Q_FUNC_INFO; - - if (!isSessionOkay(ic)) - return 0; - - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfGetCursorPosition, &result); + qInputContextIMFRequestDebug() << Q_FUNC_INFO; - QCoreApplication::postEvent(QCoreApplication::instance(), event); + QQnxImfRequest event(ic, ImfGetTextBeforeCursor); + event.gtac.n = n; + event.gtac.flags = flags; + event.gtac.result = 0; + executeIMFRequest(&event); - result.wait(); - int32_t ret = result.result().value<int32_t>(); - - return ret; + return event.gtac.result; } -static extracted_text_t *imfGetExtractedText(input_session_t *ic, extracted_text_request_t *request, int32_t flags) +// Process an event from IMF. Primarily used for reflecting back keyboard events. +// See comment at beginning of namespace declaration for general information +static int32_t ic_send_event(input_session_t *ic, event_t *event) { - qInputContextIMFEventDebug() << Q_FUNC_INFO; - - if (!isSessionOkay(ic)) { - extracted_text_t *et = (extracted_text_t *)calloc(sizeof(extracted_text_t),1); - et->text = (spannable_string_t *)calloc(sizeof(spannable_string_t),1); - return et; - } - - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfGetExtractedText, &result); - parg(request); - iarg(flags); + qInputContextIMFRequestDebug() << Q_FUNC_INFO; - QCoreApplication::postEvent(QCoreApplication::instance(), event); + QQnxImfRequest imfEvent(ic, ImfSendEvent); + imfEvent.sae.event = event; + imfEvent.sae.result = -1; + executeIMFRequest(&imfEvent); - result.wait(); - return result.result().value<extracted_text_t *>(); + return imfEvent.sae.result; } -static spannable_string_t *imfGetSelectedText(input_session_t *ic, int32_t flags) +// Same as ic_send_event. +// See comment at beginning of namespace declaration for general information +static int32_t ic_send_async_event(input_session_t *ic, event_t *event) { - qInputContextIMFEventDebug() << Q_FUNC_INFO; - - if (!isSessionOkay(ic)) - return toSpannableString(""); - - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfGetSelectedText, &result); - iarg(flags); + qInputContextIMFRequestDebug() << Q_FUNC_INFO; - QCoreApplication::postEvent(QCoreApplication::instance(), event); + // There's no difference from our point of view between ic_send_event & ic_send_async_event + QQnxImfRequest imfEvent(ic, ImfSendEvent); + imfEvent.sae.event = event; + imfEvent.sae.result = -1; + executeIMFRequest(&imfEvent); - result.wait(); - return result.result().value<extracted_text_t *>(); + return imfEvent.sae.result; } -static spannable_string_t *imfGetTextAfterCursor(input_session_t *ic, int32_t n, int32_t flags) +// Set the range of text between start and end as the composition range. +// See comment at beginning of namespace declaration for general information +static int32_t ic_set_composing_region(input_session_t *ic, int32_t start, int32_t end) { - qInputContextIMFEventDebug() << Q_FUNC_INFO; + qInputContextIMFRequestDebug() << Q_FUNC_INFO; - if (!isSessionOkay(ic)) - return toSpannableString(""); - - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfGetTextAfterCursor, &result); - iarg(n); - iarg(flags); + QQnxImfRequest event(ic, ImfSetComposingRegion); + event.scr.start = start; + event.scr.end = end; + event.scr.result = -1; + executeIMFRequest(&event); - QCoreApplication::postEvent(QCoreApplication::instance(), event); - - result.wait(); - return result.result().value<extracted_text_t *>(); + return event.scr.result; } -static spannable_string_t *imfGetTextBeforeCursor(input_session_t *ic, int32_t n, int32_t flags) +// Update the composition range with the supplied text. This can be called when no composition +// range is in effect in which case one is started at the current cursor position. +// See comment at beginning of namespace declaration for general information +static int32_t ic_set_composing_text(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position) { - qInputContextIMFEventDebug() << Q_FUNC_INFO; + qInputContextIMFRequestDebug() << Q_FUNC_INFO; - if (!isSessionOkay(ic)) - return toSpannableString(""); + QQnxImfRequest event(ic, ImfSetComposingText); + event.sct.text = text; + event.sct.new_cursor_position = new_cursor_position; + event.sct.result = -1; + executeIMFRequest(&event); - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfGetTextBeforeCursor, &result); - iarg(n); - iarg(flags); - - QCoreApplication::postEvent(QCoreApplication::instance(), event); - - result.wait(); - return result.result().value<extracted_text_t *>(); + return event.sct.result; } -static int32_t imfPerformEditorAction(input_session_t *ic, int32_t editor_action) +// Indicate if any text is selected +// See comment at beginning of namespace declaration for general information +static int32_t ic_is_text_selected(input_session_t* ic, int32_t* pIsSelected) { - qInputContextIMFEventDebug() << Q_FUNC_INFO; - - if (!isSessionOkay(ic)) - return 0; - - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfPerformEditorAction, &result); - iarg(editor_action); + qInputContextIMFRequestDebug() << Q_FUNC_INFO; - QCoreApplication::postEvent(QCoreApplication::instance(), event); + QQnxImfRequest event(ic, ImfIsTextSelected); + event.its.pIsSelected = pIsSelected; + event.its.result = -1; + executeIMFRequest(&event); - result.wait(); - int32_t ret = result.result().value<int32_t>(); - return ret; + return event.its.result; } -static int32_t imfReportFullscreenMode(input_session_t *ic, int32_t enabled) +// Indicate if all text is selected +// See comment at beginning of namespace declaration for general information +static int32_t ic_is_all_text_selected(input_session_t* ic, int32_t* pIsSelected) { - qInputContextIMFEventDebug() << Q_FUNC_INFO; - - if (!isSessionOkay(ic)) - return 0; + qInputContextIMFRequestDebug() << Q_FUNC_INFO; - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfReportFullscreenMode, &result); - iarg(enabled); + QQnxImfRequest event(ic, ImfIsAllTextSelected); + event.its.pIsSelected = pIsSelected; + event.its.result = -1; + executeIMFRequest(&event); - QCoreApplication::postEvent(QCoreApplication::instance(), event); - - result.wait(); - int32_t ret = result.result().value<int32_t>(); - return ret; + return event.its.result; } -static int32_t imfSendEvent(input_session_t *ic, event_t *event) -{ - qInputContextIMFEventDebug() << Q_FUNC_INFO; - - if (!isSessionOkay(ic)) - return 0; - - ImfEvent *imfEvent = new ImfEvent(ic, ImfSendEvent, 0); - imfEvent->m_args[qs("event")] = QVariant::fromValue(static_cast<void *>(event)); +// LCOV_EXCL_START - exclude from code coverage analysis +// The following functions are defined in the IMF headers but are not currently called. - QCoreApplication::postEvent(QCoreApplication::instance(), imfEvent); +// Not currently used +static int32_t ic_perform_editor_action(input_session_t *ic, int32_t editor_action) +{ + Q_UNUSED(ic); + Q_UNUSED(editor_action); + qCritical() << "ic_perform_editor_action not implemented"; return 0; } -static int32_t imfSendAsyncEvent(input_session_t *ic, event_t *event) +// Not currently used +static int32_t ic_report_fullscreen_mode(input_session_t *ic, int32_t enabled) { - qInputContextIMFEventDebug() << Q_FUNC_INFO; - - if (!isSessionOkay(ic)) - return 0; - - ImfEvent *imfEvent = new ImfEvent(ic, ImfSendAsyncEvent, 0); - imfEvent->m_args[qs("event")] = QVariant::fromValue(static_cast<void *>(event)); - - QCoreApplication::postEvent(QCoreApplication::instance(), imfEvent); + Q_UNUSED(ic); + Q_UNUSED(enabled); + qCritical() << "ic_report_fullscreen_mode not implemented"; return 0; } -static int32_t imfSetComposingRegion(input_session_t *ic, int32_t start, int32_t end) +// Not currently used +static extracted_text_t *ic_get_extracted_text(input_session_t *ic, extracted_text_request_t *request, int32_t flags) { - qInputContextIMFEventDebug() << Q_FUNC_INFO; - - if (!isSessionOkay(ic)) - return 0; + Q_UNUSED(ic); + Q_UNUSED(request); + Q_UNUSED(flags); - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfSetComposingRegion, &result); - iarg(start); - iarg(end); + qCritical() << "ic_get_extracted_text not implemented"; + return 0; +} - QCoreApplication::postEvent(QCoreApplication::instance(), event); +// Not currently used +static spannable_string_t *ic_get_selected_text(input_session_t *ic, int32_t flags) +{ + Q_UNUSED(ic); + Q_UNUSED(flags); - result.wait(); - int32_t ret = result.result().value<int32_t>(); - return ret; + qCritical() << "ic_get_selected_text not implemented"; + return 0; } -static int32_t imfSetComposingText(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position) +// Not currently used +static int32_t ic_get_cursor_caps_mode(input_session_t *ic, int32_t req_modes) { - qInputContextIMFEventDebug() << Q_FUNC_INFO; - - if (!isSessionOkay(ic)) - return 0; + Q_UNUSED(ic); + Q_UNUSED(req_modes); - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfSetComposingText, &result); - parg(text); - iarg(new_cursor_position); + qCritical() << "ic_get_cursor_caps_mode not implemented"; + return 0; +} - QCoreApplication::postEvent(QCoreApplication::instance(), event); +// Not currently used +static int32_t ic_clear_meta_key_states(input_session_t *ic, int32_t states) +{ + Q_UNUSED(ic); + Q_UNUSED(states); - result.wait(); - int32_t ret = result.result().value<int32_t>(); - return ret; + qCritical() << "ic_clear_meta_key_states not implemented"; + return 0; } -static int32_t imfSetSelection(input_session_t *ic, int32_t start, int32_t end) +// Not currently used +static int32_t ic_set_selection(input_session_t *ic, int32_t start, int32_t end) { - qInputContextIMFEventDebug() << Q_FUNC_INFO; - - if (!isSessionOkay(ic)) - return 0; + Q_UNUSED(ic); + Q_UNUSED(start); + Q_UNUSED(end); - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfSetSelection, &result); - iarg(start); - iarg(end); + qCritical() << "ic_set_selection not implemented"; + return 0; +} - QCoreApplication::postEvent(QCoreApplication::instance(), event); +// End of un-hittable code +// LCOV_EXCL_STOP - result.wait(); - int32_t ret = result.result().value<int32_t>(); - return ret; -} static connection_interface_t ic_funcs = { - imfBeginBatchEdit, - imfClearMetaKeyStates, - imfCommitText, - imfDeleteSurroundingText, - imfEndBatchEdit, - imfFinishComposingText, - imfGetCursorCapsMode, - imfGetCursorPosition, - imfGetExtractedText, - imfGetSelectedText, - imfGetTextAfterCursor, - imfGetTextBeforeCursor, - imfPerformEditorAction, - imfReportFullscreenMode, - NULL, //ic_send_key_event - imfSendEvent, - imfSendAsyncEvent, - imfSetComposingRegion, - imfSetComposingText, - imfSetSelection, - NULL, //ic_set_candidates, + ic_begin_batch_edit, + ic_clear_meta_key_states, + ic_commit_text, + ic_delete_surrounding_text, + ic_end_batch_edit, + ic_finish_composing_text, + ic_get_cursor_caps_mode, + ic_get_cursor_position, + ic_get_extracted_text, + ic_get_selected_text, + ic_get_text_after_cursor, + ic_get_text_before_cursor, + ic_perform_editor_action, + ic_report_fullscreen_mode, + 0, //ic_send_key_event + ic_send_event, + ic_send_async_event, + ic_set_composing_region, + ic_set_composing_text, + ic_set_selection, + 0, //ic_set_candidates, + 0, //ic_get_cursor_offset, + 0, //ic_get_selection, + ic_is_text_selected, + ic_is_all_text_selected, + 0, //ic_get_max_cursor_offset_t }; +} // namespace + static void -initEvent(event_t *pEvent, const input_session_t *pSession, EventType eventType, int eventId) +initEvent(event_t *pEvent, const input_session_t *pSession, EventType eventType, int eventId, int eventSize) { static int s_transactionId; // Make sure structure is squeaky clean since it's not clear just what is significant. - memset(pEvent, 0, sizeof(event_t)); + memset(pEvent, 0, eventSize); pEvent->event_type = eventType; pEvent->event_id = eventId; pEvent->pid = getpid(); @@ -566,31 +502,20 @@ initEvent(event_t *pEvent, const input_session_t *pSession, EventType eventType, pEvent->transaction_id = ++s_transactionId; } -spannable_string_t *toSpannableString(const QString &text) +static spannable_string_t *toSpannableString(const QString &text) { qInputContextDebug() << Q_FUNC_INFO << text; - spannable_string_t *pString = reinterpret_cast<spannable_string_t *>(malloc(sizeof(spannable_string_t))); - pString->str = (wchar_t *)malloc(sizeof(wchar_t) * text.length() + 1); - pString->length = text.length(); + spannable_string_t *pString = static_cast<spannable_string_t *>(malloc(sizeof(spannable_string_t))); + pString->str = static_cast<wchar_t *>(malloc(sizeof(wchar_t) * text.length() + 1)); + pString->length = text.toWCharArray(pString->str); pString->spans = 0; pString->spans_count = 0; - - const QChar *pData = text.constData(); - wchar_t *pDst = pString->str; - - while (!pData->isNull()) - { - *pDst = pData->unicode(); - pDst++; - pData++; - } - *pDst = 0; + pString->str[pString->length] = 0; return pString; } -} // namespace static const input_session_t *(*p_ictrl_open_session)(connection_interface_t *) = 0; static void (*p_ictrl_close_session)(input_session_t *) = 0; @@ -645,27 +570,30 @@ QT_BEGIN_NAMESPACE QQnxInputContext::QQnxInputContext(QQnxIntegration *integration, QQnxAbstractVirtualKeyboard &keyboard) : QPlatformInputContext(), - m_lastCaretPos(0), + m_caretPosition(0), m_isComposing(false), + m_isUpdatingText(false), m_inputPanelVisible(false), m_inputPanelLocale(QLocale::c()), + m_focusObject(0), m_integration(integration), - m_virtualKeyboad(keyboard) + m_virtualKeyboard(keyboard) { qInputContextDebug() << Q_FUNC_INFO; if (!imfAvailable()) return; - if ( p_imf_client_init() != 0 ) { + // Save a pointer to ourselves so we can execute calls from IMF through executeIMFRequest + // In practice there will only ever be a single instance. + Q_ASSERT(sInputContextInstance == 0); + sInputContextInstance = this; + + if (p_imf_client_init() != 0) { s_imfInitFailed = true; qCritical("imf_client_init failed - IMF services will be unavailable"); } - QCoreApplication::instance()->installEventFilter(this); - - // p_vkb_init_selection_service(); - connect(&keyboard, SIGNAL(visibilityChanged(bool)), this, SLOT(keyboardVisibilityChanged(bool))); connect(&keyboard, SIGNAL(localeChanged(QLocale)), this, SLOT(keyboardLocaleChanged(QLocale))); keyboardVisibilityChanged(keyboard.isVisible()); @@ -676,168 +604,75 @@ QQnxInputContext::~QQnxInputContext() { qInputContextDebug() << Q_FUNC_INFO; + Q_ASSERT(sInputContextInstance == this); + sInputContextInstance = 0; + if (!imfAvailable()) return; - QCoreApplication::instance()->removeEventFilter(this); p_imf_client_disconnect(); } -#define getarg(type, name) type name = imfEvent->mArgs[qs(#name)].value<type>() -#define getparg(type, name) type name = (type)(imfEvent->mArgs[qs(#name)].value<void*>()) - bool QQnxInputContext::isValid() const { return imfAvailable(); } -bool QQnxInputContext::eventFilter(QObject *obj, QEvent *event) +void QQnxInputContext::processImfEvent(QQnxImfRequest *imfEvent) { - if (event->type() == ImfEvent::sUserEventType) { - // Forward the event to our real handler. - ImfEvent *imfEvent = static_cast<ImfEvent *>(event); - switch (imfEvent->m_imfType) { - case ImfBeginBatchEdit: { - int32_t ret = onBeginBatchEdit(imfEvent->m_session); - imfEvent->m_result->setResult(QVariant::fromValue(ret)); - break; - } - - case ImfClearMetaKeyStates: { - getarg(int32_t, states); - int32_t ret = onClearMetaKeyStates(imfEvent->m_session, states); - imfEvent->m_result->setResult(QVariant::fromValue(ret)); - break; - } - - case ImfCommitText: { - getparg(spannable_string_t*, text); - getarg(int32_t, new_cursor_position); - int32_t ret = onCommitText(imfEvent->m_session, text, new_cursor_position); - imfEvent->m_result->setResult(QVariant::fromValue(ret)); - break; - } - - case ImfDeleteSurroundingText: { - getarg(int32_t, left_length); - getarg(int32_t, right_length); - int32_t ret = onDeleteSurroundingText(imfEvent->m_session, left_length, right_length); - imfEvent->m_result->setResult(QVariant::fromValue(ret)); - break; - } - - case ImfEndBatchEdit: { - int32_t ret = onEndBatchEdit(imfEvent->m_session); - imfEvent->m_result->setResult(QVariant::fromValue(ret)); - break; - } - - case ImfFinishComposingText: { - int32_t ret = onFinishComposingText(imfEvent->m_session); - imfEvent->m_result->setResult(QVariant::fromValue(ret)); - break; - } - - case ImfGetCursorCapsMode: { - getarg(int32_t, req_modes); - int32_t ret = onGetCursorCapsMode(imfEvent->m_session, req_modes); - imfEvent->m_result->setResult(QVariant::fromValue(ret)); - break; - } - - case ImfGetCursorPosition: { - int32_t ret = onGetCursorPosition(imfEvent->m_session); - imfEvent->m_result->setResult(QVariant::fromValue(ret)); - break; - } - - case ImfGetExtractedText: { - getparg(extracted_text_request_t*, request); - getarg(int32_t, flags); - extracted_text_t *ret = onGetExtractedText(imfEvent->m_session, request, flags); - imfEvent->m_result->setResult(QVariant::fromValue(static_cast<void *>(ret))); - break; - } + // If input session is no longer current, just bail, imfEvent should already be set with the appropriate + // return value. The only exception is spell check events since they're not associated with the + // object with focus. + if (imfEvent->type != ImfSendEvent || imfEvent->sae.event->event_type != EVENT_SPELL_CHECK) { + if (!isSessionOkay(imfEvent->session)) + return; + } - case ImfGetSelectedText: { - getarg(int32_t, flags); - spannable_string_t *ret = onGetSelectedText(imfEvent->m_session, flags); - imfEvent->m_result->setResult(QVariant::fromValue(static_cast<void *>(ret))); - break; - } + switch (imfEvent->type) { + case ImfCommitText: + imfEvent->ct.result = onCommitText(imfEvent->ct.text, imfEvent->ct.new_cursor_position); + break; - case ImfGetTextAfterCursor: { - getarg(int32_t, n); - getarg(int32_t, flags); - spannable_string_t *ret = onGetTextAfterCursor(imfEvent->m_session, n, flags); - imfEvent->m_result->setResult(QVariant::fromValue(static_cast<void *>(ret))); - break; - } + case ImfDeleteSurroundingText: + imfEvent->dst.result = onDeleteSurroundingText(imfEvent->dst.left_length, imfEvent->dst.right_length); + break; - case ImfGetTextBeforeCursor: { - getarg(int32_t, n); - getarg(int32_t, flags); - spannable_string_t *ret = onGetTextBeforeCursor(imfEvent->m_session, n, flags); - imfEvent->m_result->setResult(QVariant::fromValue((void*)ret)); - break; - } + case ImfFinishComposingText: + imfEvent->fct.result = onFinishComposingText(); + break; - case ImfPerformEditorAction: { - getarg(int32_t, editor_action); - int32_t ret = onPerformEditorAction(imfEvent->m_session, editor_action); - imfEvent->m_result->setResult(QVariant::fromValue(ret)); - break; - } + case ImfGetCursorPosition: + imfEvent->gcp.result = onGetCursorPosition(); + break; - case ImfReportFullscreenMode: { - getarg(int32_t, enabled); - int32_t ret = onReportFullscreenMode(imfEvent->m_session, enabled); - imfEvent->m_result->setResult(QVariant::fromValue(ret)); - break; - } + case ImfGetTextAfterCursor: + imfEvent->gtac.result = onGetTextAfterCursor(imfEvent->gtac.n, imfEvent->gtac.flags); + break; - case ImfSendEvent: { - getparg(event_t*, event); - onSendEvent(imfEvent->m_session, event); - break; - } + case ImfGetTextBeforeCursor: + imfEvent->gtac.result = onGetTextBeforeCursor(imfEvent->gtac.n, imfEvent->gtac.flags); + break; - case ImfSendAsyncEvent: { - getparg(event_t*, event); - onSendAsyncEvent(imfEvent->m_session, event); - break; - } + case ImfSendEvent: + imfEvent->sae.result = onSendEvent(imfEvent->sae.event); + break; - case ImfSetComposingRegion: { - getarg(int32_t, start); - getarg(int32_t, end); - int32_t ret = onSetComposingRegion(imfEvent->m_session, start, end); - imfEvent->m_result->setResult(QVariant::fromValue(ret)); - break; - } + case ImfSetComposingRegion: + imfEvent->scr.result = onSetComposingRegion(imfEvent->scr.start, imfEvent->scr.end); + break; - case ImfSetComposingText: { - getparg(spannable_string_t*, text); - getarg(int32_t, new_cursor_position); - int32_t ret = onSetComposingText(imfEvent->m_session, text, new_cursor_position); - imfEvent->m_result->setResult(QVariant::fromValue(ret)); - break; - } + case ImfSetComposingText: + imfEvent->sct.result = onSetComposingText(imfEvent->sct.text, imfEvent->sct.new_cursor_position); + break; - case ImfSetSelection: { - getarg(int32_t, start); - getarg(int32_t, end); - int32_t ret = onSetSelection(imfEvent->m_session, start, end); - imfEvent->m_result->setResult(QVariant::fromValue(ret)); - break; - } - }; //switch + case ImfIsTextSelected: + imfEvent->its.result = onIsTextSelected(imfEvent->its.pIsSelected); + break; - return true; - } else { - // standard event processing - return QObject::eventFilter(obj, event); - } + case ImfIsAllTextSelected: + imfEvent->its.result = onIsAllTextSelected(imfEvent->its.pIsSelected); + break; + }; //switch } bool QQnxInputContext::filterEvent( const QEvent *event ) @@ -845,12 +680,12 @@ bool QQnxInputContext::filterEvent( const QEvent *event ) qInputContextDebug() << Q_FUNC_INFO << event; switch (event->type()) { - case QEvent::CloseSoftwareInputPanel: { + case QEvent::CloseSoftwareInputPanel: return dispatchCloseSoftwareInputPanel(); - } - case QEvent::RequestSoftwareInputPanel: { + + case QEvent::RequestSoftwareInputPanel: return dispatchRequestSoftwareInputPanel(); - } + default: return false; } @@ -869,12 +704,30 @@ void QQnxInputContext::reset() endComposition(); } -void QQnxInputContext::update(Qt::InputMethodQueries queries) +void QQnxInputContext::commit() { qInputContextDebug() << Q_FUNC_INFO; - reset(); + endComposition(); +} - QPlatformInputContext::update(queries); +void QQnxInputContext::update(Qt::InputMethodQueries queries) +{ + qInputContextDebug() << Q_FUNC_INFO << queries; + + if (queries & Qt::ImCursorPosition) { + int lastCaret = m_caretPosition; + updateCursorPosition(); + // If caret position has changed we need to inform IMF unless this is just due to our own action + // such as committing text. + if (hasSession() && !m_isUpdatingText && lastCaret != m_caretPosition) { + caret_event_t caretEvent; + initEvent(&caretEvent.event, sInputSession, EVENT_CARET, CARET_POS_CHANGED, sizeof(caretEvent)); + caretEvent.old_pos = lastCaret; + caretEvent.new_pos = m_caretPosition; + qInputContextDebug() << Q_FUNC_INFO << "ictrl_dispatch_event caret changed" << lastCaret << m_caretPosition; + p_ictrl_dispatch_event(&caretEvent.event); + } + } } void QQnxInputContext::closeSession() @@ -887,16 +740,23 @@ void QQnxInputContext::closeSession() p_ictrl_close_session((input_session_t *)sInputSession); sInputSession = 0; } + // These are likely already in the right state but this depends on the text control + // having called reset or commit. So, just in case, set them to proper values. + m_isComposing = false; + m_composingText.clear(); } -void QQnxInputContext::openSession() +bool QQnxInputContext::openSession() { - qInputContextDebug() << Q_FUNC_INFO; if (!imfAvailable()) - return; + return false; closeSession(); sInputSession = p_ictrl_open_session(&ic_funcs); + + qInputContextDebug() << Q_FUNC_INFO; + + return sInputSession != 0; } bool QQnxInputContext::hasSession() @@ -918,79 +778,89 @@ bool QQnxInputContext::hasSelectedText() bool QQnxInputContext::dispatchRequestSoftwareInputPanel() { + qInputContextDebug() << Q_FUNC_INFO << "requesting keyboard" << m_inputPanelVisible; m_virtualKeyboard.showKeyboard(); - qInputContextDebug() << Q_FUNC_INFO << "requesting virtual keyboard"; - QObject *input = qGuiApp->focusObject(); - if (!imfAvailable() || !input || !inputMethodAccepted()) - return true; - - if (!hasSession()) - openSession(); - // This also means that the caret position has moved - QInputMethodQueryEvent query(Qt::ImCursorPosition); - QCoreApplication::sendEvent(input, &query); - int caretPos = query.value(Qt::ImCursorPosition).toInt(); - caret_event_t caretEvent; - memset(&caretEvent, 0, sizeof(caret_event_t)); - initEvent(&caretEvent.event, sInputSession, EVENT_CARET, CARET_POS_CHANGED); - caretEvent.old_pos = m_lastCaretPos; - m_lastCaretPos = caretEvent.new_pos = caretPos; - p_ictrl_dispatch_event((event_t *)&caretEvent); return true; } bool QQnxInputContext::dispatchCloseSoftwareInputPanel() { + qInputContextDebug() << Q_FUNC_INFO << "hiding keyboard" << m_inputPanelVisible; m_virtualKeyboard.hideKeyboard(); - qInputContextDebug() << Q_FUNC_INFO << "hiding virtual keyboard"; - // This also means we are stopping composition, but we should already have done that. return true; } /** * IMF Event Dispatchers. */ -bool QQnxInputContext::dispatchFocusEvent(FocusEventId id, int hints) +bool QQnxInputContext::dispatchFocusGainEvent(int inputHints) { - qInputContextDebug() << Q_FUNC_INFO; + if (hasSession()) + dispatchFocusLossEvent(); - if (!sInputSession) { - qWarning() << Q_FUNC_INFO << "Attempt to dispatch a focus event with no input session."; - return false; - } + QObject *input = qGuiApp->focusObject(); - if (!imfAvailable()) + if (!input || !openSession()) return false; // Set the last caret position to 0 since we don't really have one and we don't // want to have the old one. - m_lastCaretPos = 0; + m_caretPosition = 0; + + QInputMethodQueryEvent query(Qt::ImHints); + QCoreApplication::sendEvent(input, &query); focus_event_t focusEvent; - memset(&focusEvent, 0, sizeof(focusEvent)); - initEvent(&focusEvent.event, sInputSession, EVENT_FOCUS, id); + initEvent(&focusEvent.event, sInputSession, EVENT_FOCUS, FOCUS_GAINED, sizeof(focusEvent)); focusEvent.style = DEFAULT_STYLE; - if (hints && Qt::ImhNoPredictiveText) + if (inputHints & Qt::ImhNoPredictiveText) focusEvent.style |= NO_PREDICTION | NO_AUTO_CORRECTION; - if (hints && Qt::ImhNoAutoUppercase) + if (inputHints & Qt::ImhNoAutoUppercase) focusEvent.style |= NO_AUTO_TEXT; + // Following styles are mutually exclusive + if (inputHints & Qt::ImhHiddenText) { + focusEvent.style |= IMF_PASSWORD_TYPE; + } else if (inputHints & Qt::ImhDialableCharactersOnly) { + focusEvent.style |= IMF_PHONE_TYPE; + } else if (inputHints & Qt::ImhUrlCharactersOnly) { + focusEvent.style |= IMF_URL_TYPE; + } else if (inputHints & Qt::ImhEmailCharactersOnly) { + focusEvent.style |= IMF_EMAIL_TYPE; + } + + qInputContextDebug() << Q_FUNC_INFO << "ictrl_dispatch_event focus gain style:" << focusEvent.style; + p_ictrl_dispatch_event((event_t *)&focusEvent); return true; } -bool QQnxInputContext::handleKeyboardEvent(int flags, int sym, int mod, int scan, int cap) +void QQnxInputContext::dispatchFocusLossEvent() { - if (!imfAvailable()) + if (hasSession()) { + qInputContextDebug() << Q_FUNC_INFO << "ictrl_dispatch_event focus lost"; + + focus_event_t focusEvent; + initEvent(&focusEvent.event, sInputSession, EVENT_FOCUS, FOCUS_LOST, sizeof(focusEvent)); + p_ictrl_dispatch_event((event_t *)&focusEvent); + closeSession(); + } +} + +bool QQnxInputContext::handleKeyboardEvent(int flags, int sym, int mod, int scan, int cap, int sequenceId) +{ + Q_UNUSED(scan); + + if (!hasSession()) return false; int key = (flags & KEY_SYM_VALID) ? sym : cap; - bool navKey = false; - switch ( key ) { + bool navigationKey = false; + switch (key) { case KEYCODE_RETURN: /* In a single line edit we should end composition because enter might be used by something. endComposition(); @@ -1007,27 +877,22 @@ bool QQnxInputContext::handleKeyboardEvent(int flags, int sym, int mod, int scan break; case KEYCODE_LEFT: key = NAVIGATE_LEFT; - navKey = true; + navigationKey = true; break; case KEYCODE_RIGHT: key = NAVIGATE_RIGHT; - navKey = true; + navigationKey = true; break; case KEYCODE_UP: key = NAVIGATE_UP; - navKey = true; + navigationKey = true; break; case KEYCODE_DOWN: key = NAVIGATE_DOWN; - navKey = true; + navigationKey = true; break; - case KEYCODE_CAPS_LOCK: - case KEYCODE_LEFT_SHIFT: - case KEYCODE_RIGHT_SHIFT: case KEYCODE_LEFT_CTRL: case KEYCODE_RIGHT_CTRL: - case KEYCODE_LEFT_ALT: - case KEYCODE_RIGHT_ALT: case KEYCODE_MENU: case KEYCODE_LEFT_HYPER: case KEYCODE_RIGHT_HYPER: @@ -1041,85 +906,183 @@ bool QQnxInputContext::handleKeyboardEvent(int flags, int sym, int mod, int scan break; } - if ( mod & KEYMOD_CTRL ) { - // If CTRL is pressed, just let AIR handle it. But terminate any composition first - //endComposition(); - return false; - } - // Pass the keys we don't know about on through if ( key == 0 ) return false; - // IMF doesn't need key releases so just swallow them. - if (!(flags & KEY_DOWN)) - return true; - - if ( navKey ) { + if (navigationKey) { // Even if we're forwarding up events, we can't do this for // navigation keys. if ( flags & KEY_DOWN ) { navigation_event_t navEvent; - initEvent(&navEvent.event, sInputSession, EVENT_NAVIGATION, key); + initEvent(&navEvent.event, sInputSession, EVENT_NAVIGATION, key, sizeof(navEvent)); navEvent.magnitude = 1; - qInputContextDebug() << Q_FUNC_INFO << "dispatch navigation event " << key; + qInputContextDebug() << Q_FUNC_INFO << "ictrl_dispatch_even navigation" << key; p_ictrl_dispatch_event(&navEvent.event); } - } - else { + } else { key_event_t keyEvent; - initEvent(&keyEvent.event, sInputSession, EVENT_KEY, flags & KEY_DOWN ? IMF_KEY_DOWN : IMF_KEY_UP); - keyEvent.key_code = key; - keyEvent.character = 0; - keyEvent.meta_key_state = 0; + initEvent(&keyEvent.event, sInputSession, EVENT_KEY, flags & KEY_DOWN ? IMF_KEY_DOWN : IMF_KEY_UP, + sizeof(keyEvent)); + keyEvent.key_code = cap; + keyEvent.character = sym; + keyEvent.meta_key_state = mod; + keyEvent.sequence_id = sequenceId; p_ictrl_dispatch_event(&keyEvent.event); - qInputContextDebug() << Q_FUNC_INFO << "dispatch key event " << key; + qInputContextDebug() << Q_FUNC_INFO << "ictrl_dispatch_even key" << key; } - scan = 0; return true; } -void QQnxInputContext::endComposition() +void QQnxInputContext::updateCursorPosition() { - if (!m_isComposing) + QObject *input = qGuiApp->focusObject(); + if (!input) return; - QObject *input = qGuiApp->focusObject(); - if (!imfAvailable() || !input) + QInputMethodQueryEvent query(Qt::ImCursorPosition); + QCoreApplication::sendEvent(input, &query); + m_caretPosition = query.value(Qt::ImCursorPosition).toInt(); + + qInputContextDebug() << Q_FUNC_INFO << m_caretPosition; +} + +void QQnxInputContext::endComposition() +{ + if (!m_isComposing) return; - QList<QInputMethodEvent::Attribute> attributes; - QInputMethodEvent event(QLatin1String(""), attributes); - event.setCommitString(m_composingText); - m_composingText = QString(); - m_isComposing = false; - QCoreApplication::sendEvent(input, &event); + finishComposingText(); - action_event_t actionEvent; - memset(&actionEvent, 0, sizeof(actionEvent)); - initEvent(&actionEvent.event, sInputSession, EVENT_ACTION, ACTION_END_COMPOSITION); - p_ictrl_dispatch_event(&actionEvent.event); + if (hasSession()) { + action_event_t actionEvent; + initEvent(&actionEvent.event, sInputSession, EVENT_ACTION, ACTION_END_COMPOSITION, sizeof(actionEvent)); + qInputContextDebug() << Q_FUNC_INFO << "ictrl_dispatch_even end composition"; + p_ictrl_dispatch_event(&actionEvent.event); + } } -void QQnxInputContext::setComposingText(QString const& composingText) +void QQnxInputContext::updateComposition(spannable_string_t *text, int32_t new_cursor_position) { - m_composingText = composingText; + QObject *input = qGuiApp->focusObject(); + if (!input) + return; + + if (new_cursor_position > 0) + new_cursor_position += text->length - 1; + + m_composingText = QString::fromWCharArray(text->str, text->length); m_isComposing = true; - QObject *input = qGuiApp->focusObject(); - if (!imfAvailable() || !input) - return; + qInputContextDebug() << Q_FUNC_INFO << m_composingText << new_cursor_position; QList<QInputMethodEvent::Attribute> attributes; - QTextCharFormat format; - format.setFontUnderline(true); - attributes.push_back(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, composingText.length(), format)); + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, + new_cursor_position, + 1, + QVariant())); + + for (unsigned int i = 0; i < text->spans_count; ++i) { + QColor highlightColor; + bool underline = false; + + if ((text->spans[i].attributes_mask & COMPOSED_TEXT_ATTRIB) != 0) + underline = true; + + if ((text->spans[i].attributes_mask & ACTIVE_REGION_ATTRIB) != 0) { + underline = true; + highlightColor = m_highlightColor[ActiveRegion]; + } else if ((text->spans[i].attributes_mask & AUTO_CORRECTION_ATTRIB) != 0) { + highlightColor = m_highlightColor[AutoCorrected]; + } else if ((text->spans[i].attributes_mask & REVERT_CORRECTION_ATTRIB) != 0) { + highlightColor = m_highlightColor[Reverted]; + } - QInputMethodEvent event(composingText, attributes); + if (underline || highlightColor.isValid()) { + QTextCharFormat format; + if (underline) + format.setFontUnderline(true); + if (highlightColor.isValid()) + format.setBackground(QBrush(highlightColor)); + qInputContextDebug() << " attrib: " << underline << highlightColor << text->spans[i].start << text->spans[i].end; + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, text->spans[i].start, + text->spans[i].end - text->spans[i].start + 1, QVariant(format))); + } + } + QInputMethodEvent event(m_composingText, attributes); + m_isUpdatingText = true; QCoreApplication::sendEvent(input, &event); + m_isUpdatingText = false; + + updateCursorPosition(); +} + +void QQnxInputContext::finishComposingText() +{ + QObject *input = qGuiApp->focusObject(); + + if (input) { + qInputContextDebug() << Q_FUNC_INFO << m_composingText; + + QInputMethodEvent event; + event.setCommitString(m_composingText); + m_isUpdatingText = true; + QCoreApplication::sendEvent(input, &event); + m_isUpdatingText = false; + } + m_composingText = QString(); + m_isComposing = false; + + updateCursorPosition(); +} + +// Return the index relative to a UTF-16 sequence of characters for a index that is relative to the +// corresponding UTF-32 character string given a starting index in the UTF-16 string and a count +// of the number of lead surrogates prior to that index. Updates the highSurrogateCount to reflect the +// new surrogate characters encountered. +static int adjustIndex(const QChar *text, int utf32Index, int utf16StartIndex, int *highSurrogateCount) +{ + int utf16Index = utf32Index + *highSurrogateCount; + while (utf16StartIndex < utf16Index) { + if (text[utf16StartIndex].isHighSurrogate()) { + ++utf16Index; + ++*highSurrogateCount; + } + ++utf16StartIndex; + } + return utf16StartIndex; +} + +int QQnxInputContext::handleSpellCheck(spell_check_event_t *event) +{ + // These should never happen. + if (sSpellCheckQueue->isEmpty() || event->event.event_id != NOTIFY_SP_CHECK_MISSPELLINGS) + return -1; + + SpellCheckInfo callerInfo = sSpellCheckQueue->dequeue(); + spannable_string_t* spellCheckData = *event->data; + QString text = QString::fromWCharArray(spellCheckData->str, spellCheckData->length); + // Generate the list of indices indicating misspelled words in the text. We use end + 1 + // since it's more conventional to have the end index point just past the string. We also + // can't use the indices directly since they are relative to UTF-32 encoded data and the + // conversion to Qt's UTF-16 internal format might cause lengthening. + QList<int> indices; + int adjustment = 0; + int index = 0; + for (unsigned int i = 0; i < spellCheckData->spans_count; ++i) { + if (spellCheckData->spans[i].attributes_mask & MISSPELLED_WORD_ATTRIB) { + index = adjustIndex(text.data(), spellCheckData->spans[i].start, index, &adjustment); + indices.push_back(index); + index = adjustIndex(text.data(), spellCheckData->spans[i].end + 1, index, &adjustment); + indices.push_back(index); + } + } + callerInfo.spellCheckDone(callerInfo.context, text, indices); + + return 0; } int32_t QQnxInputContext::processEvent(event_t *event) @@ -1128,7 +1091,7 @@ int32_t QQnxInputContext::processEvent(event_t *event) switch (event->event_type) { case EVENT_SPELL_CHECK: { qInputContextDebug() << Q_FUNC_INFO << "EVENT_SPELL_CHECK"; - result = 0; + result = handleSpellCheck(reinterpret_cast<spell_check_event_t *>(event)); break; } @@ -1140,19 +1103,24 @@ int32_t QQnxInputContext::processEvent(event_t *event) event->event_id == NAVIGATE_LEFT ? KEYCODE_LEFT : event->event_id == NAVIGATE_RIGHT ? KEYCODE_RIGHT : 0; - QQnxEventThread::injectKeyboardEvent(KEY_DOWN | KEY_CAP_VALID, key, 0, 0, 0); - QQnxEventThread::injectKeyboardEvent(KEY_CAP_VALID, key, 0, 0, 0); + QQnxScreenEventHandler::injectKeyboardEvent(KEY_DOWN | KEY_CAP_VALID, key, 0, 0, 0); + QQnxScreenEventHandler::injectKeyboardEvent(KEY_CAP_VALID, key, 0, 0, 0); result = 0; break; } case EVENT_KEY: { - qInputContextDebug() << Q_FUNC_INFO << "EVENT_KEY"; - key_event_t *kevent = static_cast<key_event_t *>(event); - - QQnxEventThread::injectKeyboardEvent(KEY_DOWN | KEY_SYM_VALID | KEY_CAP_VALID, kevent->key_code, 0, 0, kevent->key_code); - QQnxEventThread::injectKeyboardEvent(KEY_SYM_VALID | KEY_CAP_VALID, kevent->key_code, 0, 0, kevent->key_code); - + key_event_t *kevent = reinterpret_cast<key_event_t *>(event); + int keySym = kevent->character != 0 ? kevent->character : kevent->key_code; + int keyCap = kevent->key_code; + int modifiers = 0; + if (kevent->meta_key_state & META_SHIFT_ON) + modifiers |= KEYMOD_SHIFT; + int flags = KEY_SYM_VALID | KEY_CAP_VALID; + if (event->event_id == IMF_KEY_DOWN) + flags |= KEY_DOWN; + qInputContextDebug() << Q_FUNC_INFO << "EVENT_KEY" << flags << keySym; + QQnxScreenEventHandler::injectKeyboardEvent(flags, keySym, modifiers, 0, keyCap); result = 0; break; } @@ -1179,339 +1147,175 @@ int32_t QQnxInputContext::processEvent(event_t *event) * IMF Event Handlers */ -int32_t QQnxInputContext::onBeginBatchEdit(input_session_t *ic) -{ - qInputContextDebug() << Q_FUNC_INFO; - - if (!isSessionOkay(ic)) - return 0; - - // We don't care. - return 0; -} - -int32_t QQnxInputContext::onClearMetaKeyStates(input_session_t *ic, int32_t states) -{ - Q_UNUSED(states); - qInputContextDebug() << Q_FUNC_INFO; - - if (!isSessionOkay(ic)) - return 0; - - // Should never get called. - qCritical() << Q_FUNC_INFO << "onClearMetaKeyStates is unsupported."; - return 0; -} - -int32_t QQnxInputContext::onCommitText(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position) +int32_t QQnxInputContext::onCommitText(spannable_string_t *text, int32_t new_cursor_position) { - Q_UNUSED(new_cursor_position); // TODO: How can we set the cursor position it's not part of the API. - if (!isSessionOkay(ic)) - return 0; - - QObject *input = qGuiApp->focusObject(); - if (!imfAvailable() || !input) - return 0; - - QString commitString = QString::fromWCharArray(text->str, text->length); - - qInputContextDebug() << Q_FUNC_INFO << "Committing [" << commitString << "]"; - - QList<QInputMethodEvent::Attribute> attributes; - QInputMethodEvent event(QLatin1String(""), attributes); - event.setCommitString(commitString, 0, 0); + Q_UNUSED(new_cursor_position); - QCoreApplication::sendEvent(input, &event); - m_composingText = QString(); + updateComposition(text, new_cursor_position); + finishComposingText(); return 0; } -int32_t QQnxInputContext::onDeleteSurroundingText(input_session_t *ic, int32_t left_length, int32_t right_length) +int32_t QQnxInputContext::onDeleteSurroundingText(int32_t left_length, int32_t right_length) { qInputContextDebug() << Q_FUNC_INFO << "L:" << left_length << " R:" << right_length; - if (!isSessionOkay(ic)) - return 0; - QObject *input = qGuiApp->focusObject(); - if (!imfAvailable() || !input) - return 0; - - if (hasSelectedText()) { - QQnxEventThread::injectKeyboardEvent(KEY_DOWN | KEY_CAP_VALID, KEYCODE_DELETE, 0, 0, 0); - QQnxEventThread::injectKeyboardEvent(KEY_CAP_VALID, KEYCODE_DELETE, 0, 0, 0); - reset(); + if (!input) return 0; - } int replacementLength = left_length + right_length; int replacementStart = -left_length; - QList<QInputMethodEvent::Attribute> attributes; - QInputMethodEvent event(QLatin1String(""), attributes); - event.setCommitString(QLatin1String(""), replacementStart, replacementLength); - QCoreApplication::sendEvent(input, &event); - - return 0; -} - -int32_t QQnxInputContext::onEndBatchEdit(input_session_t *ic) -{ - qInputContextDebug() << Q_FUNC_INFO; - - if (!isSessionOkay(ic)) - return 0; - - return 0; -} - -int32_t QQnxInputContext::onFinishComposingText(input_session_t *ic) -{ - qInputContextDebug() << Q_FUNC_INFO; - - if (!isSessionOkay(ic)) - return 0; - - QObject *input = qGuiApp->focusObject(); - if (!imfAvailable() || !input) - return 0; + finishComposingText(); - // Only update the control, no need to send a message back to imf (don't call - // end composition) - QList<QInputMethodEvent::Attribute> attributes; - QInputMethodEvent event(QLatin1String(""), attributes); - event.setCommitString(m_composingText); - m_composingText = QString(); - m_isComposing = false; + QInputMethodEvent event; + event.setCommitString(QString(), replacementStart, replacementLength); + m_isUpdatingText = true; QCoreApplication::sendEvent(input, &event); + m_isUpdatingText = false; - return 0; -} - -int32_t QQnxInputContext::onGetCursorCapsMode(input_session_t *ic, int32_t req_modes) -{ - Q_UNUSED(req_modes); - qInputContextDebug() << Q_FUNC_INFO; - - if (!isSessionOkay(ic)) - return 0; - - // Should never get called. - qCritical() << Q_FUNC_INFO << "onGetCursorCapsMode is unsupported."; + updateCursorPosition(); return 0; } -int32_t QQnxInputContext::onGetCursorPosition(input_session_t *ic) +int32_t QQnxInputContext::onFinishComposingText() { - qInputContextDebug() << Q_FUNC_INFO; - - if (!isSessionOkay(ic)) - return 0; + finishComposingText(); - QObject *input = qGuiApp->focusObject(); - if (!imfAvailable() || !input) - return 0; - - QInputMethodQueryEvent query(Qt::ImCursorPosition); - QCoreApplication::sendEvent(input, &query); - m_lastCaretPos = query.value(Qt::ImCursorPosition).toInt(); - - return m_lastCaretPos; -} - -extracted_text_t *QQnxInputContext::onGetExtractedText(input_session_t *ic, extracted_text_request_t *request, int32_t flags) -{ - Q_UNUSED(flags); - Q_UNUSED(request); - qInputContextDebug() << Q_FUNC_INFO; - - if (!isSessionOkay(ic)) { - extracted_text_t *et = (extracted_text_t *)calloc(sizeof(extracted_text_t),1); - et->text = reinterpret_cast<spannable_string_t *>(calloc(sizeof(spannable_string_t),1)); - return et; - } - - // Used to update dictionaries, but not supported right now. - extracted_text_t *et = (extracted_text_t *)calloc(sizeof(extracted_text_t),1); - et->text = reinterpret_cast<spannable_string_t *>(calloc(sizeof(spannable_string_t),1)); - - return et; + return 0; } -spannable_string_t *QQnxInputContext::onGetSelectedText(input_session_t *ic, int32_t flags) +int32_t QQnxInputContext::onGetCursorPosition() { - Q_UNUSED(flags); qInputContextDebug() << Q_FUNC_INFO; - if (!isSessionOkay(ic)) - return toSpannableString(""); - QObject *input = qGuiApp->focusObject(); - if (!imfAvailable() || !input) + if (!input) return 0; - QInputMethodQueryEvent query(Qt::ImCurrentSelection); - QCoreApplication::sendEvent(input, &query); - QString text = query.value(Qt::ImCurrentSelection).toString(); + updateCursorPosition(); - return toSpannableString(text); + return m_caretPosition; } -spannable_string_t *QQnxInputContext::onGetTextAfterCursor(input_session_t *ic, int32_t n, int32_t flags) +spannable_string_t *QQnxInputContext::onGetTextAfterCursor(int32_t n, int32_t flags) { Q_UNUSED(flags); qInputContextDebug() << Q_FUNC_INFO; - if (!isSessionOkay(ic)) - return toSpannableString(""); - QObject *input = qGuiApp->focusObject(); - if (!imfAvailable() || !input) + if (!input) return toSpannableString(""); QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImSurroundingText); QCoreApplication::sendEvent(input, &query); QString text = query.value(Qt::ImSurroundingText).toString(); - m_lastCaretPos = query.value(Qt::ImCursorPosition).toInt(); + m_caretPosition = query.value(Qt::ImCursorPosition).toInt(); - return toSpannableString(text.mid(m_lastCaretPos+1, n)); + return toSpannableString(text.mid(m_caretPosition, n)); } -spannable_string_t *QQnxInputContext::onGetTextBeforeCursor(input_session_t *ic, int32_t n, int32_t flags) +spannable_string_t *QQnxInputContext::onGetTextBeforeCursor(int32_t n, int32_t flags) { Q_UNUSED(flags); qInputContextDebug() << Q_FUNC_INFO; - if (!isSessionOkay(ic)) - return toSpannableString(""); - QObject *input = qGuiApp->focusObject(); - if (!imfAvailable() || !input) + if (!input) return toSpannableString(""); QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImSurroundingText); QCoreApplication::sendEvent(input, &query); QString text = query.value(Qt::ImSurroundingText).toString(); - m_lastCaretPos = query.value(Qt::ImCursorPosition).toInt(); + m_caretPosition = query.value(Qt::ImCursorPosition).toInt(); - if (n < m_lastCaretPos) - return toSpannableString(text.mid(m_lastCaretPos - n, n)); + if (n < m_caretPosition) + return toSpannableString(text.mid(m_caretPosition - n, n)); else - return toSpannableString(text.mid(0, m_lastCaretPos)); -} - -int32_t QQnxInputContext::onPerformEditorAction(input_session_t *ic, int32_t editor_action) -{ - Q_UNUSED(editor_action); - qInputContextDebug() << Q_FUNC_INFO; - - if (!isSessionOkay(ic)) - return 0; - - // Should never get called. - qCritical() << Q_FUNC_INFO << "onPerformEditorAction is unsupported."; - - return 0; -} - -int32_t QQnxInputContext::onReportFullscreenMode(input_session_t *ic, int32_t enabled) -{ - Q_UNUSED(enabled); - qInputContextDebug() << Q_FUNC_INFO; - - if (!isSessionOkay(ic)) - return 0; - - // Should never get called. - qCritical() << Q_FUNC_INFO << "onReportFullscreenMode is unsupported."; - - return 0; -} - -int32_t QQnxInputContext::onSendEvent(input_session_t *ic, event_t *event) -{ - qInputContextDebug() << Q_FUNC_INFO; - - if (!isSessionOkay(ic)) - return 0; - - return processEvent(event); + return toSpannableString(text.mid(0, m_caretPosition)); } -int32_t QQnxInputContext::onSendAsyncEvent(input_session_t *ic, event_t *event) +int32_t QQnxInputContext::onSendEvent(event_t *event) { qInputContextDebug() << Q_FUNC_INFO; - if (!isSessionOkay(ic)) - return 0; - return processEvent(event); } -int32_t QQnxInputContext::onSetComposingRegion(input_session_t *ic, int32_t start, int32_t end) +int32_t QQnxInputContext::onSetComposingRegion(int32_t start, int32_t end) { - qInputContextDebug() << Q_FUNC_INFO; - - if (!isSessionOkay(ic)) - return 0; - QObject *input = qGuiApp->focusObject(); - if (!imfAvailable() || !input) + if (!input) return 0; QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImSurroundingText); QCoreApplication::sendEvent(input, &query); QString text = query.value(Qt::ImSurroundingText).toString(); - m_lastCaretPos = query.value(Qt::ImCursorPosition).toInt(); + m_caretPosition = query.value(Qt::ImCursorPosition).toInt(); - QString empty = QString::fromLatin1(""); - text = text.mid(start, end - start); + qInputContextDebug() << Q_FUNC_INFO << text; + + m_isUpdatingText = true; // Delete the current text. + QInputMethodEvent deleteEvent; + deleteEvent.setCommitString(QString(), start - m_caretPosition, end - start); + QCoreApplication::sendEvent(input, &deleteEvent); + + m_composingText = text.mid(start, end - start); + m_isComposing = true; + QList<QInputMethodEvent::Attribute> attributes; - QInputMethodEvent event(empty, attributes); - event.setCommitString(empty, start - m_lastCaretPos, end - start); - QCoreApplication::sendEvent(input, &event); + QTextCharFormat format; + format.setFontUnderline(true); + attributes.push_back(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, m_composingText.length(), format)); + + QInputMethodEvent setTextEvent(m_composingText, attributes); + QCoreApplication::sendEvent(input, &setTextEvent); - // Move the specified text into a preedit string. - setComposingText(text); + m_isUpdatingText = false; return 0; } -int32_t QQnxInputContext::onSetComposingText(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position) +int32_t QQnxInputContext::onSetComposingText(spannable_string_t *text, int32_t new_cursor_position) { - Q_UNUSED(new_cursor_position); - qInputContextDebug() << Q_FUNC_INFO; - - if (!isSessionOkay(ic)) - return 0; - - QObject *input = qGuiApp->focusObject(); - if (!imfAvailable() || !input) - return 0; + if (text->length > 0) { + updateComposition(text, new_cursor_position); + } else { + // If the composing text is empty we can simply end composition, the visual effect is the same. + // However, sometimes one wants to display hint text in an empty text field and for this to work + // QQuickTextEdit.inputMethodComposing has to be false if the composition string is empty. + m_composingText.clear(); + finishComposingText(); + } + return 0; +} - m_isComposing = true; +int32_t QQnxInputContext::onIsTextSelected(int32_t* pIsSelected) +{ + *pIsSelected = hasSelectedText(); - QString preeditString = QString::fromWCharArray(text->str, text->length); - setComposingText(preeditString); + qInputContextDebug() << Q_FUNC_INFO << *pIsSelected; return 0; } -int32_t QQnxInputContext::onSetSelection(input_session_t *ic, int32_t start, int32_t end) +int32_t QQnxInputContext::onIsAllTextSelected(int32_t* pIsSelected) { - Q_UNUSED(start); - Q_UNUSED(end); - qInputContextDebug() << Q_FUNC_INFO; + QObject *input = qGuiApp->focusObject(); + if (!input) + return -1; - if (!isSessionOkay(ic)) - return 0; + QInputMethodQueryEvent query(Qt::ImCurrentSelection | Qt::ImSurroundingText); + QCoreApplication::sendEvent(input, &query); + + *pIsSelected = query.value(Qt::ImSurroundingText).toString().length() == query.value(Qt::ImCurrentSelection).toString().length(); - // Should never get called. - qCritical() << Q_FUNC_INFO << "onSetSelection is unsupported."; + qInputContextDebug() << Q_FUNC_INFO << *pIsSelected; return 0; } @@ -1556,19 +1360,74 @@ void QQnxInputContext::keyboardLocaleChanged(const QLocale &locale) } } +void QQnxInputContext::setHighlightColor(int index, const QColor &color) +{ + qInputContextDebug() << Q_FUNC_INFO << "setHighlightColor" << index << color << qGuiApp->focusObject(); + + if (!sInputContextInstance) + return; + + // If the focus has changed, revert all colors to the default. + if (sInputContextInstance->m_focusObject != qGuiApp->focusObject()) { + QColor invalidColor; + sInputContextInstance->m_highlightColor[ActiveRegion] = sSelectedColor; + sInputContextInstance->m_highlightColor[AutoCorrected] = invalidColor; + sInputContextInstance->m_highlightColor[Reverted] = invalidColor; + sInputContextInstance->m_focusObject = qGuiApp->focusObject(); + } + if (index >= 0 && index <= Reverted) + sInputContextInstance->m_highlightColor[index] = color; +} + void QQnxInputContext::setFocusObject(QObject *object) { qInputContextDebug() << Q_FUNC_INFO << "input item=" << object; + // Ensure the colors are reset if we've a change in focus object + setHighlightColor(-1, QColor()); + if (!inputMethodAccepted()) { if (m_inputPanelVisible) hideInputPanel(); + if (hasSession()) + dispatchFocusLossEvent(); } else { - m_virtualKeyboard.setInputHintsFromObject(object); + QInputMethodQueryEvent query(Qt::ImHints); + QCoreApplication::sendEvent(object, &query); + int inputHints = query.value(Qt::ImHints).toInt(); + + dispatchFocusGainEvent(inputHints); + + m_virtualKeyboard.setInputHints(inputHints); if (!m_inputPanelVisible) showInputPanel(); } } +bool QQnxInputContext::checkSpelling(const QString &text, void *context, void (*spellCheckDone)(void *context, const QString &text, const QList<int> &indices)) +{ + qInputContextDebug() << Q_FUNC_INFO << "text" << text; + + if (!imfAvailable()) + return false; + + if (!sSpellCheckSession) + sSpellCheckSession = p_ictrl_open_session(&ic_funcs); + + action_event_t spellEvent; + initEvent(&spellEvent.event, sSpellCheckSession, EVENT_ACTION, ACTION_CHECK_MISSPELLINGS, sizeof(spellEvent)); + int len = text.length(); + spellEvent.event_data = alloca(sizeof(wchar_t) * (len + 1)); + spellEvent.length_data = text.toWCharArray(static_cast<wchar_t*>(spellEvent.event_data)) * sizeof(wchar_t); + + int rc = p_ictrl_dispatch_event(reinterpret_cast<event_t*>(&spellEvent)); + + if (rc == 0) { + sSpellCheckQueue->enqueue(SpellCheckInfo(context, spellCheckDone)); + return true; + } + return false; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxinputcontext_imf.h b/src/plugins/platforms/qnx/qqnxinputcontext_imf.h index 1980a99ed9..5028215bbe 100644 --- a/src/plugins/platforms/qnx/qqnxinputcontext_imf.h +++ b/src/plugins/platforms/qnx/qqnxinputcontext_imf.h @@ -1,6 +1,6 @@ /*************************************************************************** ** -** Copyright (C) 2011 - 2012 Research In Motion +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -43,9 +43,11 @@ #define QQNXINPUTCONTEXT_H #include <qpa/qplatforminputcontext.h> +#include "qqnxscreeneventfilter.h" #include <QtCore/QLocale> #include <QtCore/QMetaType> +#include <QtCore/QList> #include <qpa/qplatformintegration.h> #include "imf/imf_client.h" @@ -55,21 +57,30 @@ QT_BEGIN_NAMESPACE class QQnxAbstractVirtualKeyboard; class QQnxIntegration; +class QQnxImfRequest; -class QQnxInputContext : public QPlatformInputContext +class QQnxInputContext : public QPlatformInputContext, public QQnxScreenEventFilter { Q_OBJECT public: explicit QQnxInputContext(QQnxIntegration *integration, QQnxAbstractVirtualKeyboard &keyboard); ~QQnxInputContext(); + // Indices for selecting and setting highlight colors. + enum HighlightIndex { + ActiveRegion, + AutoCorrected, + Reverted, + }; + bool isValid() const; bool filterEvent(const QEvent *event); QRectF keyboardRect() const; void reset(); + void commit(); void update(Qt::InputMethodQueries); - bool handleKeyboardEvent(int flags, int sym, int mod, int scan, int cap); + bool handleKeyboardEvent(int flags, int sym, int mod, int scan, int cap, int sequenceId); void showInputPanel(); @@ -79,61 +90,62 @@ public: QLocale locale() const; void setFocusObject(QObject *object); -protected: - // Filters only for IMF events. - bool eventFilter(QObject *obj, QEvent *event); + static void setHighlightColor(int index, const QColor &color); + + static bool checkSpelling(const QString &text, void *context, void (*spellCheckDone)(void *context, const QString &text, const QList<int> &indices)); private Q_SLOTS: void keyboardVisibilityChanged(bool visible); void keyboardLocaleChanged(const QLocale &locale); + void processImfEvent(QQnxImfRequest *event); private: // IMF Event dispatchers - bool dispatchFocusEvent(FocusEventId id, int hints = Qt::ImhNone); + bool dispatchFocusGainEvent(int inputHints); + void dispatchFocusLossEvent(); bool dispatchRequestSoftwareInputPanel(); bool dispatchCloseSoftwareInputPanel(); + int handleSpellCheck(spell_check_event_t *event); int32_t processEvent(event_t *event); void closeSession(); - void openSession(); + bool openSession(); bool hasSession(); + void updateCursorPosition(); void endComposition(); - void setComposingText(QString const &composingText); + void finishComposingText(); bool hasSelectedText(); + void updateComposition(spannable_string_t *text, int32_t new_cursor_position); // IMF Event handlers - these events will come in from QCoreApplication. - int32_t onBeginBatchEdit(input_session_t *ic); - int32_t onClearMetaKeyStates(input_session_t *ic, int32_t states); - int32_t onCommitText(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position); - int32_t onDeleteSurroundingText(input_session_t *ic, int32_t left_length, int32_t right_length); - int32_t onEndBatchEdit(input_session_t *ic); - int32_t onFinishComposingText(input_session_t *ic); - int32_t onGetCursorCapsMode(input_session_t *ic, int32_t req_modes); - int32_t onGetCursorPosition(input_session_t *ic); - extracted_text_t *onGetExtractedText(input_session_t *ic, extracted_text_request_t *request, int32_t flags); - spannable_string_t *onGetSelectedText(input_session_t *ic, int32_t flags); - spannable_string_t *onGetTextAfterCursor(input_session_t *ic, int32_t n, int32_t flags); - spannable_string_t *onGetTextBeforeCursor(input_session_t *ic, int32_t n, int32_t flags); - int32_t onPerformEditorAction(input_session_t *ic, int32_t editor_action); - int32_t onReportFullscreenMode(input_session_t *ic, int32_t enabled); - int32_t onSendEvent(input_session_t *ic, event_t *event); - int32_t onSendAsyncEvent(input_session_t *ic, event_t *event); - int32_t onSetComposingRegion(input_session_t *ic, int32_t start, int32_t end); - int32_t onSetComposingText(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position); - int32_t onSetSelection(input_session_t *ic, int32_t start, int32_t end); + int32_t onCommitText(spannable_string_t *text, int32_t new_cursor_position); + int32_t onDeleteSurroundingText(int32_t left_length, int32_t right_length); + int32_t onGetCursorCapsMode(int32_t req_modes); + int32_t onFinishComposingText(); + int32_t onGetCursorPosition(); + spannable_string_t *onGetTextAfterCursor(int32_t n, int32_t flags); + spannable_string_t *onGetTextBeforeCursor(int32_t n, int32_t flags); + int32_t onSendEvent(event_t *event); + int32_t onSetComposingRegion(int32_t start, int32_t end); + int32_t onSetComposingText(spannable_string_t *text, int32_t new_cursor_position); + int32_t onIsTextSelected(int32_t* pIsSelected); + int32_t onIsAllTextSelected(int32_t* pIsSelected); int32_t onForceUpdate(); - int m_lastCaretPos; + int m_caretPosition; bool m_isComposing; QString m_composingText; + bool m_isUpdatingText; bool m_inputPanelVisible; QLocale m_inputPanelLocale; + // The object that had focus when the last highlight color was set. + QObject *m_focusObject; + // Indexed by HighlightIndex + QColor m_highlightColor[3]; QQnxIntegration *m_integration; - QQnxAbstractVirtualKeyboard &m_virtualKeyboad; + QQnxAbstractVirtualKeyboard &m_virtualKeyboard; }; -Q_DECLARE_METATYPE(extracted_text_t*) - QT_END_NAMESPACE #endif // QQNXINPUTCONTEXT_H diff --git a/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp b/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp index f444d34b5e..9270f1ed6b 100644 --- a/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp +++ b/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp @@ -1,6 +1,6 @@ /*************************************************************************** ** -** Copyright (C) 2011 - 2012 Research In Motion +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -46,6 +46,7 @@ #include <QtCore/QDebug> #include <QtGui/QGuiApplication> +#include <QtGui/QInputMethodEvent> #if defined(QQNXINPUTCONTEXT_DEBUG) #define qInputContextDebug qDebug @@ -179,7 +180,11 @@ void QQnxInputContext::setFocusObject(QObject *object) if (m_inputPanelVisible) hideInputPanel(); } else { - m_virtualKeyboard.setInputHintsFromObject(object); + QInputMethodQueryEvent query(Qt::ImHints); + QCoreApplication::sendEvent(object, &query); + int inputHints = query.value(Qt::ImHints).toInt(); + + m_virtualKeyboard.setInputHints(inputHints); if (!m_inputPanelVisible) showInputPanel(); diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp index 52f836abbe..5695ef433a 100644 --- a/src/plugins/platforms/qnx/qqnxintegration.cpp +++ b/src/plugins/platforms/qnx/qqnxintegration.cpp @@ -1,6 +1,6 @@ /*************************************************************************** ** -** Copyright (C) 2011 - 2013 BlackBerry Limited. All rights reserved. +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -251,6 +251,9 @@ QQnxIntegration::QQnxIntegration(const QStringList ¶mList) #if defined(QQNX_PPS) // Set up the input context m_inputContext = new QQnxInputContext(this, *m_virtualKeyboard); +#if defined(QQNX_IMF) + m_screenEventHandler->addScreenEventFilter(m_inputContext); +#endif #endif } @@ -271,17 +274,6 @@ QQnxIntegration::~QQnxIntegration() delete m_drag; #endif -#if defined(QQNX_PPS) - // Destroy the hardware button notifier - delete m_buttonsNotifier; - - // Destroy input context - delete m_inputContext; -#endif - - // Destroy the keyboard class. - delete m_virtualKeyboard; - #if !defined(QT_NO_CLIPBOARD) // Delete the clipboard delete m_clipboard; @@ -321,6 +313,17 @@ QQnxIntegration::~QQnxIntegration() QQnxGLContext::shutdown(); #endif +#if defined(QQNX_PPS) + // Destroy the hardware button notifier + delete m_buttonsNotifier; + + // Destroy input context + delete m_inputContext; +#endif + + // Destroy the keyboard class. + delete m_virtualKeyboard; + // Destroy services class delete m_services; diff --git a/src/plugins/platforms/qnx/qqnxnativeinterface.cpp b/src/plugins/platforms/qnx/qqnxnativeinterface.cpp index e468b051cd..df9d96739a 100644 --- a/src/plugins/platforms/qnx/qqnxnativeinterface.cpp +++ b/src/plugins/platforms/qnx/qqnxnativeinterface.cpp @@ -44,6 +44,9 @@ #include "qqnxglcontext.h" #include "qqnxscreen.h" #include "qqnxwindow.h" +#if defined(QQNX_IMF) +#include "qqnxinputcontext_imf.h" +#endif #include <QtGui/QOpenGLContext> #include <QtGui/QScreen> @@ -85,10 +88,27 @@ void *QQnxNativeInterface::nativeResourceForContext(const QByteArray &resource, void QQnxNativeInterface::setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value) { + QQnxWindow *qnxWindow = static_cast<QQnxWindow*>(window); + if (name == QStringLiteral("mmRendererWindowName")) { - QQnxWindow *qnxWindow = static_cast<QQnxWindow*>(window); qnxWindow->setMMRendererWindowName(value.toString()); + } else if (name == QStringLiteral("windowGroup")) { + if (value.isNull()) + qnxWindow->joinWindowGroup(QByteArray()); + else if (value.canConvert<QByteArray>()) + qnxWindow->joinWindowGroup(value.toByteArray()); } } +QPlatformNativeInterface::NativeResourceForIntegrationFunction QQnxNativeInterface::nativeResourceFunctionForIntegration(const QByteArray &resource) +{ +#if defined(QQNX_IMF) + if (resource == "blackberryIMFSetHighlightColor") + return reinterpret_cast<NativeResourceForIntegrationFunction>(QQnxInputContext::setHighlightColor); + if (resource == "blackberryIMFCheckSpelling") + return reinterpret_cast<NativeResourceForIntegrationFunction>(QQnxInputContext::checkSpelling); +#endif + return 0; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxnativeinterface.h b/src/plugins/platforms/qnx/qqnxnativeinterface.h index dfd386214e..e2fdd32689 100644 --- a/src/plugins/platforms/qnx/qqnxnativeinterface.h +++ b/src/plugins/platforms/qnx/qqnxnativeinterface.h @@ -51,8 +51,10 @@ class QQnxNativeInterface : public QPlatformNativeInterface public: void *nativeResourceForWindow(const QByteArray &resource, QWindow *window); void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen); + void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context); void setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value); + NativeResourceForIntegrationFunction nativeResourceFunctionForIntegration(const QByteArray &resource); }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxscreen.cpp b/src/plugins/platforms/qnx/qqnxscreen.cpp index a09d6ce1f5..8461e37e4d 100644 --- a/src/plugins/platforms/qnx/qqnxscreen.cpp +++ b/src/plugins/platforms/qnx/qqnxscreen.cpp @@ -200,6 +200,9 @@ QQnxScreen::~QQnxScreen() Q_FOREACH (QQnxWindow *childWindow, m_childWindows) childWindow->setScreen(0); + if (m_coverWindow) + m_coverWindow->setScreen(0); + delete m_cursor; } @@ -505,7 +508,6 @@ void QQnxScreen::raiseWindow(QQnxWindow *window) if (window != m_coverWindow) { removeWindow(window); m_childWindows.push_back(window); - updateHierarchy(); } } @@ -516,7 +518,6 @@ void QQnxScreen::lowerWindow(QQnxWindow *window) if (window != m_coverWindow) { removeWindow(window); m_childWindows.push_front(window); - updateHierarchy(); } } @@ -728,8 +729,6 @@ void QQnxScreen::activateWindowGroup(const QByteArray &id) if (m_coverWindow) m_coverWindow->setExposed(false); - - QWindowSystemInterface::handleWindowActivated(window); } void QQnxScreen::deactivateWindowGroup(const QByteArray &id) @@ -744,8 +743,6 @@ void QQnxScreen::deactivateWindowGroup(const QByteArray &id) Q_FOREACH (QQnxWindow *childWindow, m_childWindows) childWindow->setExposed(false); - - QWindowSystemInterface::handleWindowActivated(rootWindow()->window()); } QQnxWindow *QQnxScreen::rootWindow() const diff --git a/src/plugins/platforms/qnx/qqnxscreen.h b/src/plugins/platforms/qnx/qqnxscreen.h index 61c47e6c72..d39a210d4b 100644 --- a/src/plugins/platforms/qnx/qqnxscreen.h +++ b/src/plugins/platforms/qnx/qqnxscreen.h @@ -80,7 +80,7 @@ public: int nativeFormat() const { return (depth() == 32) ? SCREEN_FORMAT_RGBA8888 : SCREEN_FORMAT_RGB565; } screen_display_t nativeDisplay() const { return m_display; } screen_context_t nativeContext() const { return m_screenContext; } - const char *windowGroupName() const { return rootWindow()->groupName().constData(); } + const char *windowGroupName() const { return m_rootWindow ? m_rootWindow->groupName().constData() : 0; } QQnxWindow *findWindow(screen_window_t windowHandle); diff --git a/src/plugins/platforms/qnx/qqnxscreeneventfilter.h b/src/plugins/platforms/qnx/qqnxscreeneventfilter.h new file mode 100644 index 0000000000..f9ecadd2a9 --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxscreeneventfilter.h @@ -0,0 +1,58 @@ +/*************************************************************************** +** +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. +** 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 QQNXSCREENEVENTFILTER_H +#define QQNXSCREENEVENTFILTER_H + +QT_BEGIN_NAMESPACE + +class QQnxScreenEventFilter +{ +protected: + ~QQnxScreenEventFilter() {} + +public: + virtual bool handleKeyboardEvent(int flags, int sym, int mod, int scan, int cap, int sequenceId) = 0; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp index 6f06797393..b50e590265 100644 --- a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp +++ b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp @@ -1,6 +1,6 @@ /*************************************************************************** ** -** Copyright (C) 2011 - 2012 Research In Motion +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -46,6 +46,7 @@ #include "qqnxintegration.h" #include "qqnxkeytranslator.h" #include "qqnxscreen.h" +#include "qqnxscreeneventfilter.h" #include <QDebug> #include <QGuiApplication> @@ -90,6 +91,16 @@ QQnxScreenEventHandler::QQnxScreenEventHandler(QQnxIntegration *integration) } } +void QQnxScreenEventHandler::addScreenEventFilter(QQnxScreenEventFilter *filter) +{ + m_eventFilters.append(filter); +} + +void QQnxScreenEventHandler::removeScreenEventFilter(QQnxScreenEventFilter *filter) +{ + m_eventFilters.removeOne(filter); +} + bool QQnxScreenEventHandler::handleEvent(screen_event_t event) { // get the event type @@ -256,7 +267,23 @@ void QQnxScreenEventHandler::handleKeyboardEvent(screen_event_t event) if (result) qFatal("QQNX: failed to query event cap, errno=%d", errno); - injectKeyboardEvent(flags, sym, modifiers, scan, cap); + int sequenceId = 0; +#if defined(Q_OS_BLACKBERRY) + result = screen_get_event_property_iv(event, SCREEN_PROPERTY_SEQUENCE_ID, &sequenceId); + if (result) + qFatal("QQNX: failed to query event seqId, errno=%d", errno); +#endif + + bool inject = true; + Q_FOREACH (QQnxScreenEventFilter *filter, m_eventFilters) { + if (filter->handleKeyboardEvent(flags, sym, modifiers, scan, cap, sequenceId)) { + inject = false; + break; + } + } + + if (inject) + injectKeyboardEvent(flags, sym, modifiers, scan, cap); } void QQnxScreenEventHandler::handlePointerEvent(screen_event_t event) @@ -314,10 +341,6 @@ void QQnxScreenEventHandler::handlePointerEvent(screen_event_t event) } } - // If we don't have a navigator, we don't get activation events. - if (buttonState && w && w != QGuiApplication::focusWindow() && !m_qnxIntegration->supportsNavigatorEvents()) - QWindowSystemInterface::handleWindowActivated(w); - m_lastMouseWindow = qnxWindow; // Apply scaling to wheel delta and invert value for Qt. We'll probably want to scale @@ -405,6 +428,19 @@ void QQnxScreenEventHandler::handleTouchEvent(screen_event_t event, int qnxType) if (result) qFatal("QQNX: failed to query event window, errno=%d", errno); + errno = 0; + int touchArea[2]; + result = screen_get_event_property_iv(event, SCREEN_PROPERTY_SIZE, touchArea); + if (result) + qFatal("QQNX: failed to query event touch area, errno=%d", errno); + + errno = 0; + int touchPressure; + result = screen_get_event_property_iv(event, SCREEN_PROPERTY_TOUCH_PRESSURE, &touchPressure); + if (result) + qFatal("QQNX: failed to query event touch pressure, errno=%d", errno); + + screen_window_t qnxWindow = static_cast<screen_window_t>(handle); // check if finger is valid @@ -439,14 +475,23 @@ void QQnxScreenEventHandler::handleTouchEvent(screen_event_t event, int qnxType) QPointF(static_cast<qreal>(pos[0]) / screenSize.width(), static_cast<qreal>(pos[1]) / screenSize.height()); - m_touchPoints[touchId].area = QRectF(w->geometry().left() + windowPos[0], - w->geometry().top() + windowPos[1], 0.0, 0.0); + m_touchPoints[touchId].area = QRectF(w->geometry().left() + windowPos[0] - (touchArea[0]>>1), + w->geometry().top() + windowPos[1] - (touchArea[1]>>1), + 0.0, 0.0); QWindow *parent = w->parent(); while (parent) { m_touchPoints[touchId].area.translate(parent->geometry().topLeft()); parent = parent->parent(); } + //Qt expects the pressure between 0 and 1. There is however no definit upper limit for + //the integer value of touch event pressure. The 200 was determined by experiment, it + //usually does not get higher than that. + m_touchPoints[touchId].pressure = static_cast<qreal>(touchPressure)/200.0; + // Can happen, because there is no upper limit for pressure + if (m_touchPoints[touchId].pressure > 1) + m_touchPoints[touchId].pressure = 1; + // determine event type and update state of current touch point QEvent::Type type = QEvent::None; switch (qnxType) { @@ -589,9 +634,15 @@ void QQnxScreenEventHandler::handleKeyboardFocusPropertyEvent(screen_window_t wi if (window && screen_get_window_property_iv(window, SCREEN_PROPERTY_KEYBOARD_FOCUS, &focus) != 0) qFatal("QQnx: failed to query keyboard focus property, errno=%d", errno); - QWindow *w = focus ? QQnxIntegration::window(window) : 0; - - QWindowSystemInterface::handleWindowActivated(w); + QWindow *focusWindow = QQnxIntegration::window(window); + if (focus) { + QWindowSystemInterface::handleWindowActivated(focusWindow); + } else if (focusWindow == QGuiApplication::focusWindow()) { + // Deactivate only if the window was the focus window. + // Screen might send a keyboard focus event for a newly created + // window on the secondary screen, with focus 0. + QWindowSystemInterface::handleWindowActivated(0); + } } #include "moc_qqnxscreeneventhandler.cpp" diff --git a/src/plugins/platforms/qnx/qqnxscreeneventhandler.h b/src/plugins/platforms/qnx/qqnxscreeneventhandler.h index 1fdb2c83cd..a7bcd449ee 100644 --- a/src/plugins/platforms/qnx/qqnxscreeneventhandler.h +++ b/src/plugins/platforms/qnx/qqnxscreeneventhandler.h @@ -1,6 +1,6 @@ /*************************************************************************** ** -** Copyright (C) 2011 - 2012 Research In Motion +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -49,6 +49,7 @@ QT_BEGIN_NAMESPACE class QQnxIntegration; +class QQnxScreenEventFilter; #if defined(QQNX_SCREENEVENTTHREAD) class QQnxScreenEventThread; #endif @@ -59,6 +60,9 @@ class QQnxScreenEventHandler : public QObject public: explicit QQnxScreenEventHandler(QQnxIntegration *integration); + void addScreenEventFilter(QQnxScreenEventFilter *filter); + void removeScreenEventFilter(QQnxScreenEventFilter *filter); + bool handleEvent(screen_event_t event); bool handleEvent(screen_event_t event, int qnxType); @@ -99,6 +103,7 @@ private: screen_window_t m_lastMouseWindow; QTouchDevice *m_touchDevice; QWindowSystemInterface::TouchPoint m_touchPoints[MaximumTouchPoints]; + QList<QQnxScreenEventFilter*> m_eventFilters; #if defined(QQNX_SCREENEVENTTHREAD) QQnxScreenEventThread *m_eventThread; #endif diff --git a/src/plugins/platforms/qnx/qqnxvirtualkeyboardbps.cpp b/src/plugins/platforms/qnx/qqnxvirtualkeyboardbps.cpp index 11eb4a5082..08de94a082 100644 --- a/src/plugins/platforms/qnx/qqnxvirtualkeyboardbps.cpp +++ b/src/plugins/platforms/qnx/qqnxvirtualkeyboardbps.cpp @@ -1,6 +1,6 @@ /*************************************************************************** ** -** Copyright (C) 2012 Research In Motion +** Copyright (C) 2013 BlackBerry Limited. All rights reserved. ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -46,6 +46,9 @@ #include <bps/event.h> #include <bps/locale.h> #include <bps/virtualkeyboard.h> +#if defined(Q_OS_BLACKBERRY) +#include <bbndk.h> +#endif #if defined(QQNXVIRTUALKEYBOARD_DEBUG) #define qVirtualKeyboardDebug qDebug @@ -89,7 +92,7 @@ bool QQnxVirtualKeyboardBps::showKeyboard() // They keyboard's mode is global between applications, we have to set it each time if ( !isVisible() ) - applyKeyboardMode(keyboardMode()); + applyKeyboardOptions(); virtualkeyboard_show(); return true; @@ -102,48 +105,76 @@ bool QQnxVirtualKeyboardBps::hideKeyboard() return true; } -void QQnxVirtualKeyboardBps::applyKeyboardMode(KeyboardMode mode) +void QQnxVirtualKeyboardBps::applyKeyboardOptions() { - virtualkeyboard_layout_t layout = VIRTUALKEYBOARD_LAYOUT_DEFAULT; + virtualkeyboard_layout_t layout = keyboardLayout(); + virtualkeyboard_enter_t enter = enterKey(); - switch (mode) { - case Url: - layout = VIRTUALKEYBOARD_LAYOUT_URL; - break; + qVirtualKeyboardDebug() << Q_FUNC_INFO << "mode=" << keyboardMode() << "enterKey=" << enterKeyType(); - case Email: - layout = VIRTUALKEYBOARD_LAYOUT_EMAIL; - break; + virtualkeyboard_change_options(layout, enter); +} +virtualkeyboard_layout_t QQnxVirtualKeyboardBps::keyboardLayout() const +{ + switch (keyboardMode()) { + case Url: + return VIRTUALKEYBOARD_LAYOUT_URL; + case Email: + return VIRTUALKEYBOARD_LAYOUT_EMAIL; case Web: - layout = VIRTUALKEYBOARD_LAYOUT_WEB; - break; - + return VIRTUALKEYBOARD_LAYOUT_WEB; case NumPunc: - layout = VIRTUALKEYBOARD_LAYOUT_NUM_PUNC; - break; - + return VIRTUALKEYBOARD_LAYOUT_NUM_PUNC; + case Number: + return VIRTUALKEYBOARD_LAYOUT_NUMBER; case Symbol: - layout = VIRTUALKEYBOARD_LAYOUT_SYMBOL; - break; - + return VIRTUALKEYBOARD_LAYOUT_SYMBOL; case Phone: - layout = VIRTUALKEYBOARD_LAYOUT_PHONE; - break; - + return VIRTUALKEYBOARD_LAYOUT_PHONE; case Pin: - layout = VIRTUALKEYBOARD_LAYOUT_PIN; - break; - + return VIRTUALKEYBOARD_LAYOUT_PIN; + case Password: + return VIRTUALKEYBOARD_LAYOUT_PASSWORD; +#if defined(Q_OS_BLACKBERRY) +#if BBNDK_VERSION_AT_LEAST(10, 2, 1) + case Alphanumeric: + return VIRTUALKEYBOARD_LAYOUT_ALPHANUMERIC; +#endif +#endif case Default: // fall through default: - layout = VIRTUALKEYBOARD_LAYOUT_DEFAULT; - break; + return VIRTUALKEYBOARD_LAYOUT_DEFAULT; } - qVirtualKeyboardDebug() << Q_FUNC_INFO << "mode=" << mode; + return VIRTUALKEYBOARD_LAYOUT_DEFAULT; +} + +virtualkeyboard_enter_t QQnxVirtualKeyboardBps::enterKey() const +{ + switch (enterKeyType()) { + case Connect: + return VIRTUALKEYBOARD_ENTER_CONNECT; + case Done: + return VIRTUALKEYBOARD_ENTER_DONE; + case Go: + return VIRTUALKEYBOARD_ENTER_GO; + case Join: + return VIRTUALKEYBOARD_ENTER_JOIN; + case Next: + return VIRTUALKEYBOARD_ENTER_NEXT; + case Search: + return VIRTUALKEYBOARD_ENTER_SEARCH; + case Send: + return VIRTUALKEYBOARD_ENTER_SEND; + case Submit: + return VIRTUALKEYBOARD_ENTER_SUBMIT; + case Default: // fall through + default: + return VIRTUALKEYBOARD_ENTER_DEFAULT; + } - virtualkeyboard_change_options(layout, VIRTUALKEYBOARD_ENTER_DEFAULT); + return VIRTUALKEYBOARD_ENTER_DEFAULT; } bool QQnxVirtualKeyboardBps::handleLocaleEvent(bps_event_t *event) diff --git a/src/plugins/platforms/qnx/qqnxvirtualkeyboardbps.h b/src/plugins/platforms/qnx/qqnxvirtualkeyboardbps.h index 43ecb4ecf8..5749deb4e0 100644 --- a/src/plugins/platforms/qnx/qqnxvirtualkeyboardbps.h +++ b/src/plugins/platforms/qnx/qqnxvirtualkeyboardbps.h @@ -43,6 +43,7 @@ #define QQNXVIRTUALKEYBOARDBPS_H #include "qqnxabstractvirtualkeyboard.h" +#include <bps/virtualkeyboard.h> struct bps_event_t; @@ -60,11 +61,14 @@ public: bool hideKeyboard(); protected: - void applyKeyboardMode(KeyboardMode mode); + void applyKeyboardOptions(); private: bool handleLocaleEvent(bps_event_t *event); bool handleVirtualKeyboardEvent(bps_event_t *event); + + virtualkeyboard_layout_t keyboardLayout() const; + virtualkeyboard_enter_t enterKey() const; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp index 20fce3da70..2b6ee3d1dc 100644 --- a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp +++ b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp @@ -67,9 +67,6 @@ QT_BEGIN_NAMESPACE const char *QQnxVirtualKeyboardPps::ms_PPSPath = "/pps/services/input/control"; const size_t QQnxVirtualKeyboardPps::ms_bufferSize = 2048; -// Huge hack for keyboard shadow (see QNX PR 88400). Should be removed ASAP. -#define KEYBOARD_SHADOW_HEIGHT 8 - QQnxVirtualKeyboardPps::QQnxVirtualKeyboardPps() : m_encoder(0), m_decoder(0), @@ -91,11 +88,6 @@ void QQnxVirtualKeyboardPps::start() return; } -void QQnxVirtualKeyboardPps::applyKeyboardMode(KeyboardMode mode) -{ - applyKeyboardModeOptions(mode); -} - void QQnxVirtualKeyboardPps::close() { delete m_readNotifier; @@ -159,18 +151,14 @@ bool QQnxVirtualKeyboardPps::connect() bool QQnxVirtualKeyboardPps::queryPPSInfo() { + if (!prepareToSend()) + return false; + // Request info, requires id to regenerate res message. pps_encoder_add_string(m_encoder, "msg", "info"); pps_encoder_add_string(m_encoder, "id", "libWebView"); - if (::write(m_fd, pps_encoder_buffer(m_encoder), pps_encoder_length(m_encoder)) == -1) { - close(); - return false; - } - - pps_encoder_reset(m_encoder); - - return true; + return writeCurrentPPSEncoder(); } void QQnxVirtualKeyboardPps::ppsDataReady() @@ -257,9 +245,6 @@ void QQnxVirtualKeyboardPps::handleKeyboardInfoMessage() } const QString countryId = QString::fromLatin1(value); - // HUGE hack, should be removed ASAP. - newHeight -= KEYBOARD_SHADOW_HEIGHT; // We want to ignore the 8 pixel shadow above the keyboard. (PR 88400) - setHeight(newHeight); const QLocale locale = QLocale(languageId + QLatin1Char('_') + countryId); @@ -272,13 +257,12 @@ bool QQnxVirtualKeyboardPps::showKeyboard() { qVirtualKeyboardDebug() << Q_FUNC_INFO; - // Try to connect. - if (m_fd == -1 && !connect()) + if (!prepareToSend()) return false; // NOTE: This must be done everytime the keyboard is shown even if there is no change because // hiding the keyboard wipes the setting. - applyKeyboardModeOptions(keyboardMode()); + applyKeyboardOptions(); if (isVisible()) return true; @@ -288,140 +272,110 @@ bool QQnxVirtualKeyboardPps::showKeyboard() // Send the show message. pps_encoder_add_string(m_encoder, "msg", "show"); - if (::write(m_fd, pps_encoder_buffer(m_encoder), pps_encoder_length(m_encoder)) == -1) { - close(); - return false; - } - - pps_encoder_reset(m_encoder); - - // Return true if no error occurs. Sizing response will be triggered when confirmation of - // the change arrives. - return true; + return writeCurrentPPSEncoder(); } bool QQnxVirtualKeyboardPps::hideKeyboard() { qVirtualKeyboardDebug() << Q_FUNC_INFO; - if (m_fd == -1 && !connect()) + if (!prepareToSend()) return false; pps_encoder_add_string(m_encoder, "msg", "hide"); - if (::write(m_fd, pps_encoder_buffer(m_encoder), pps_encoder_length(m_encoder)) == -1) { - close(); + return writeCurrentPPSEncoder(); +} - //Try again. - if (connect()) { - if (::write(m_fd, pps_encoder_buffer(m_encoder), pps_encoder_length(m_encoder)) == -1) { - close(); - return false; - } - } - else - return false; - } +bool QQnxVirtualKeyboardPps::prepareToSend() +{ + if (m_fd == -1 && !connect()) + return false; pps_encoder_reset(m_encoder); + return true; +} - // Return true if no error occurs. Sizing response will be triggered when confirmation of - // the change arrives. +bool QQnxVirtualKeyboardPps::writeCurrentPPSEncoder() +{ + if (::write(m_fd, pps_encoder_buffer(m_encoder), pps_encoder_length(m_encoder)) == -1) { + close(); + return false; + } return true; } -void QQnxVirtualKeyboardPps::applyKeyboardModeOptions(KeyboardMode mode) +void QQnxVirtualKeyboardPps::applyKeyboardOptions() { - // Try to connect. - if (m_fd == -1 && !connect()) + if (!prepareToSend()) return; // Send the options message. pps_encoder_add_string(m_encoder, "msg", "options"); - pps_encoder_start_object(m_encoder, "dat"); - switch (mode) { + + pps_encoder_add_string(m_encoder, "enter", enterKeyTypeStr()); + pps_encoder_add_string(m_encoder, "type", keyboardModeStr()); + + pps_encoder_end_object(m_encoder); + + writeCurrentPPSEncoder(); +} + +const char* QQnxVirtualKeyboardPps::keyboardModeStr() const +{ + switch (keyboardMode()) { case Url: - addUrlModeOptions(); - break; + return "url"; case Email: - addEmailModeOptions(); - break; + return "email"; case Web: - addWebModeOptions(); - break; + return "web"; case NumPunc: - addNumPuncModeOptions(); - break; + return "num_punc"; + case Number: + return "number"; case Symbol: - addSymbolModeOptions(); - break; + return "symbol"; case Phone: - addPhoneModeOptions(); - break; + return "phone"; case Pin: - addPinModeOptions(); - break; + return "pin"; + case Password: + return "password"; + case Alphanumeric: + return "alphanumeric"; case Default: - default: - addDefaultModeOptions(); - break; + return "default"; } - pps_encoder_end_object(m_encoder); - - if (::write(m_fd, pps_encoder_buffer(m_encoder), pps_encoder_length(m_encoder)) == -1) - close(); - - pps_encoder_reset(m_encoder); -} - -void QQnxVirtualKeyboardPps::addDefaultModeOptions() -{ - pps_encoder_add_string(m_encoder, "enter", "enter.default"); - pps_encoder_add_string(m_encoder, "type", "default"); + return ""; } -void QQnxVirtualKeyboardPps::addUrlModeOptions() +const char* QQnxVirtualKeyboardPps::enterKeyTypeStr() const { - pps_encoder_add_string(m_encoder, "enter", "enter.default"); - pps_encoder_add_string(m_encoder, "type", "url"); -} - -void QQnxVirtualKeyboardPps::addEmailModeOptions() -{ - pps_encoder_add_string(m_encoder, "enter", "enter.default"); - pps_encoder_add_string(m_encoder, "type", "email"); -} - -void QQnxVirtualKeyboardPps::addWebModeOptions() -{ - pps_encoder_add_string(m_encoder, "enter", "enter.default"); - pps_encoder_add_string(m_encoder, "type", "web"); -} - -void QQnxVirtualKeyboardPps::addNumPuncModeOptions() -{ - pps_encoder_add_string(m_encoder, "enter", "enter.default"); - pps_encoder_add_string(m_encoder, "type", "numPunc"); -} - -void QQnxVirtualKeyboardPps::addPhoneModeOptions() -{ - pps_encoder_add_string(m_encoder, "enter", "enter.default"); - pps_encoder_add_string(m_encoder, "type", "phone"); -} - -void QQnxVirtualKeyboardPps::addPinModeOptions() -{ - pps_encoder_add_string(m_encoder, "enter", "enter.default"); - pps_encoder_add_string(m_encoder, "type", "pin"); -} + switch (enterKeyType()) { + case DefaultReturn: + return "enter.default"; + case Connect: + return "enter.connect"; + case Done: + return "enter.done"; + case Go: + return "enter.go"; + case Join: + return "enter.join"; + case Next: + return "enter.next"; + case Search: + return "enter.search"; + case Send: + return "enter.send"; + case Submit: + return "enter.submit"; + } -void QQnxVirtualKeyboardPps::addSymbolModeOptions() -{ - pps_encoder_add_string(m_encoder, "enter", "enter.default"); - pps_encoder_add_string(m_encoder, "type", "symbol"); + return ""; } QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h index 6048868b08..2b56d5afbe 100644 --- a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h +++ b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h @@ -48,6 +48,7 @@ QT_BEGIN_NAMESPACE + class QSocketNotifier; class QQnxVirtualKeyboardPps : public QQnxAbstractVirtualKeyboard @@ -64,7 +65,7 @@ public Q_SLOTS: void start(); protected: - void applyKeyboardMode(KeyboardMode mode); + void applyKeyboardOptions(); private Q_SLOTS: void ppsDataReady(); @@ -76,15 +77,11 @@ private: bool queryPPSInfo(); void handleKeyboardInfoMessage(); - void applyKeyboardModeOptions(KeyboardMode mode); - void addDefaultModeOptions(); - void addUrlModeOptions(); - void addEmailModeOptions(); - void addWebModeOptions(); - void addNumPuncModeOptions(); - void addSymbolModeOptions(); - void addPhoneModeOptions(); - void addPinModeOptions(); + const char* keyboardModeStr() const; + const char* enterKeyTypeStr() const; + + bool prepareToSend(); + bool writeCurrentPPSEncoder(); pps_encoder_t *m_encoder; pps_decoder_t *m_decoder; diff --git a/src/plugins/platforms/qnx/qqnxwindow.cpp b/src/plugins/platforms/qnx/qqnxwindow.cpp index 99071cf4f2..e28e5f40e5 100644 --- a/src/plugins/platforms/qnx/qqnxwindow.cpp +++ b/src/plugins/platforms/qnx/qqnxwindow.cpp @@ -86,9 +86,18 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, bool needRootW QQnxScreen *platformScreen = static_cast<QQnxScreen *>(window->screen()->handle()); - m_isTopLevel = ( needRootWindow && !platformScreen->rootWindow()) - || (!needRootWindow && !parent()) - || window->type() == Qt::CoverWindow; + if (window->type() == Qt::CoverWindow) { + // Cover windows have to be top level to be accessible to window delegate (i.e. navigator) + m_isTopLevel = true; + } else if (parent() || (window->type() & Qt::Dialog) == Qt::Dialog) { + // If we have a parent we are a child window. Sometimes we have to be a child even if we + // don't have a parent e.g. our parent might be in a different process. + m_isTopLevel = false; + } else { + // We're parentless. If we're not using a root window, we'll always be a top-level window + // otherwise only the first window is. + m_isTopLevel = !needRootWindow || !platformScreen->rootWindow(); + } errno = 0; if (m_isTopLevel) { @@ -96,13 +105,14 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, bool needRootW if (window->type() != Qt::CoverWindow) { if (needRootWindow) platformScreen->setRootWindow(this); - createWindowGroup(); } } else { result = screen_create_window_type(&m_window, m_screenContext, SCREEN_CHILD_WINDOW); } if (result != 0) qFatal("QQnxWindow: failed to create window, errno=%d", errno); + + createWindowGroup(); } QQnxWindow::~QQnxWindow() @@ -130,7 +140,7 @@ void QQnxWindow::setGeometry(const QRect &rect) if (screen()->rootWindow() == this) //If this is the root window, it has to be shown fullscreen newGeometry = screen()->geometry(); - const QRect oldGeometry = setGeometryHelper(newGeometry); + setGeometryHelper(newGeometry); // Send a geometry change event to Qt (triggers resizeEvent() in QWindow/QWidget). @@ -140,23 +150,15 @@ void QQnxWindow::setGeometry(const QRect &rect) QWindowSystemInterface::handleGeometryChange(window(), newGeometry); QWindowSystemInterface::handleExposeEvent(window(), newGeometry); QWindowSystemInterface::setSynchronousWindowsSystemEvents(false); - - // Now move all children. - if (!oldGeometry.isEmpty()) { - const QPoint offset = newGeometry.topLeft() - oldGeometry.topLeft(); - Q_FOREACH (QQnxWindow *childWindow, m_childWindows) - childWindow->setOffset(offset); - } } -QRect QQnxWindow::setGeometryHelper(const QRect &rect) +void QQnxWindow::setGeometryHelper(const QRect &rect) { qWindowDebug() << Q_FUNC_INFO << "window =" << window() << ", (" << rect.x() << "," << rect.y() << "," << rect.width() << "," << rect.height() << ")"; // Call base class method - QRect oldGeometry = QPlatformWindow::geometry(); QPlatformWindow::setGeometry(rect); // Set window geometry equal to widget geometry @@ -181,30 +183,7 @@ QRect QQnxWindow::setGeometryHelper(const QRect &rect) if (result != 0) qFatal("QQnxWindow: failed to set window source size, errno=%d", errno); - return oldGeometry; -} - -void QQnxWindow::setOffset(const QPoint &offset) -{ - qWindowDebug() << Q_FUNC_INFO << "window =" << window(); - // Move self and then children. - QRect newGeometry = geometry(); - newGeometry.translate(offset); - - // Call the base class - QPlatformWindow::setGeometry(newGeometry); - - int val[2]; - - errno = 0; - val[0] = newGeometry.x(); - val[1] = newGeometry.y(); - int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_POSITION, val); - if (result != 0) - qFatal("QQnxWindow: failed to set window position, errno=%d", errno); - - Q_FOREACH (QQnxWindow *childWindow, m_childWindows) - childWindow->setOffset(offset); + screen_flush_context(m_screenContext, 0); } void QQnxWindow::setVisible(bool visible) @@ -214,6 +193,12 @@ void QQnxWindow::setVisible(bool visible) if (m_visible == visible) return; + // The first time through we join a window group if appropriate. + if (m_parentGroupName.isNull() && !m_isTopLevel) { + joinWindowGroup(parent() ? static_cast<QQnxWindow*>(parent())->groupName() + : QByteArray(m_screen->windowGroupName())); + } + m_visible = visible; QQnxWindow *root = this; @@ -386,16 +371,6 @@ void QQnxWindow::setScreen(QQnxScreen *platformScreen) qFatal("QQnxWindow: failed to set window display, errno=%d", errno); } else { errno = 0; - int result; - if (!parent()) { - result = screen_join_window_group(m_window, platformScreen->windowGroupName()); - if (result != 0) - qFatal("QQnxWindow: failed to join window group, errno=%d", errno); - } else { - result = screen_join_window_group(m_window, static_cast<QQnxWindow*>(parent())->groupName().constData()); - if (result != 0) - qFatal("QQnxWindow: failed to join window group, errno=%d", errno); - } Q_FOREACH (QQnxWindow *childWindow, m_childWindows) { // Only subwindows and tooltips need necessarily be moved to another display with the window. @@ -439,8 +414,10 @@ void QQnxWindow::setParent(const QPlatformWindow *window) setScreen(m_parentWindow->m_screen); m_parentWindow->m_childWindows.push_back(this); + joinWindowGroup(m_parentWindow->groupName()); } else { m_screen->addWindow(this); + joinWindowGroup(QByteArray()); } adjustBufferSize(); @@ -478,12 +455,7 @@ void QQnxWindow::lower() void QQnxWindow::requestActivateWindow() { - qWindowDebug() << Q_FUNC_INFO << "window =" << window(); - - // TODO: Tell screen to set keyboard focus to this window. - - // Notify that we gained focus. - gainedFocus(); + // Overwrite the default implementation where the window is activated } @@ -507,14 +479,6 @@ void QQnxWindow::propagateSizeHints() qWindowDebug() << Q_FUNC_INFO << ": ignored"; } -void QQnxWindow::gainedFocus() -{ - qWindowDebug() << Q_FUNC_INFO << "window =" << window(); - - // Got focus - QWindowSystemInterface::handleWindowActivated(window()); -} - void QQnxWindow::setMMRendererWindowName(const QString &name) { m_mmRendererWindowName = name; @@ -599,13 +563,18 @@ void QQnxWindow::initWindow() qFatal("QQnxWindow: failed to set window sensitivity, errno=%d", errno); } - setScreen(static_cast<QQnxScreen *>(window()->screen()->handle())); + QQnxScreen *platformScreen = static_cast<QQnxScreen *>(window()->screen()->handle()); + setScreen(platformScreen); if (window()->type() == Qt::CoverWindow) { #if defined(Q_OS_BLACKBERRY) && !defined(Q_OS_BLACKBERRY_TABLET) - screen_set_window_property_pv(m_screen->rootWindow()->nativeHandle(), - SCREEN_PROPERTY_ALTERNATE_WINDOW, (void**)&m_window); - m_cover.reset(new QQnxNavigatorCover); + if (platformScreen->rootWindow()) { + screen_set_window_property_pv(m_screen->rootWindow()->nativeHandle(), + SCREEN_PROPERTY_ALTERNATE_WINDOW, (void**)&m_window); + m_cover.reset(new QQnxNavigatorCover); + } else { + qWarning("No root window for cover window"); + } #endif m_exposed = false; } @@ -638,6 +607,34 @@ void QQnxWindow::createWindowGroup() qFatal("QQnxRootWindow: failed to create app window group, errno=%d", errno); } +void QQnxWindow::joinWindowGroup(const QByteArray &groupName) +{ + bool changed = false; + + qWindowDebug() << Q_FUNC_INFO << "group:" << groupName; + + if (!groupName.isEmpty()) { + if (groupName != m_parentGroupName) { + screen_join_window_group(m_window, groupName); + m_parentGroupName = groupName; + changed = true; + } + } else { + if (!m_parentGroupName.isEmpty()) { + screen_leave_window_group(m_window); + changed = true; + } + // By setting to an empty string we'll stop setVisible from trying to + // change our group, we want that to happen only if joinWindowGroup has + // never been called. This allows windows to be created that are not initially + // part of any group. + m_parentGroupName = ""; + } + + if (changed) + screen_flush_context(m_screenContext, 0); +} + void QQnxWindow::updateZorder(int &topZorder) { updateZorder(m_window, topZorder); diff --git a/src/plugins/platforms/qnx/qqnxwindow.h b/src/plugins/platforms/qnx/qqnxwindow.h index 3c8070b0be..5fa7b32dc8 100644 --- a/src/plugins/platforms/qnx/qqnxwindow.h +++ b/src/plugins/platforms/qnx/qqnxwindow.h @@ -93,7 +93,6 @@ public: void propagateSizeHints(); - void gainedFocus(); void setMMRendererWindowName(const QString &name); void setMMRendererWindow(screen_window_t handle); void clearMMRendererWindow(); @@ -112,6 +111,7 @@ public: void setRotation(int rotation); QByteArray groupName() const { return m_windowGroupName; } + void joinWindowGroup(const QByteArray &groupName); protected: virtual int pixelFormat() const = 0; @@ -126,9 +126,8 @@ protected: private: void createWindowGroup(); - QRect setGeometryHelper(const QRect &rect); + void setGeometryHelper(const QRect &rect); void removeFromParent(); - void setOffset(const QPoint &setOffset); void updateVisibility(bool parentVisible); void updateZorder(int &topZorder); void updateZorder(screen_window_t window, int &zOrder); @@ -146,7 +145,10 @@ private: QString m_mmRendererWindowName; screen_window_t m_mmRendererWindow; + // Group name of window group headed by this window QByteArray m_windowGroupName; + // Group name that we have joined or "" if we've not joined any group. + QByteArray m_parentGroupName; bool m_isTopLevel; }; diff --git a/src/plugins/platforms/windows/accessible/accessible.pri b/src/plugins/platforms/windows/accessible/accessible.pri index 08a37a4733..e26c6614e2 100644 --- a/src/plugins/platforms/windows/accessible/accessible.pri +++ b/src/plugins/platforms/windows/accessible/accessible.pri @@ -8,10 +8,10 @@ HEADERS += \ $$PWD/qwindowsaccessibility.h \ $$PWD/comutils.h -!win32-g++*: { +!mingw: { SOURCES += $$PWD/iaccessible2.cpp HEADERS += $$PWD/iaccessible2.h include(../../../../3rdparty/iaccessible2/iaccessible2.pri) } -win32-g++*: LIBS *= -luuid
\ No newline at end of file +mingw: LIBS *= -luuid
\ No newline at end of file diff --git a/src/plugins/platforms/windows/main.cpp b/src/plugins/platforms/windows/main.cpp index ffd87af193..a0057534b8 100644 --- a/src/plugins/platforms/windows/main.cpp +++ b/src/plugins/platforms/windows/main.cpp @@ -43,7 +43,7 @@ #include <qpa/qplatformintegrationplugin.h> #include <QtCore/QStringList> -#include "qwindowsintegration.h" +#include "qwindowsgdiintegration.h" QT_BEGIN_NAMESPACE @@ -113,7 +113,7 @@ public: QPlatformIntegration *QWindowsIntegrationPlugin::create(const QString& system, const QStringList& paramList, int &, char **) { if (system.compare(system, QStringLiteral("windows"), Qt::CaseInsensitive) == 0) - return new QWindowsIntegration(paramList); + return new QWindowsGdiIntegration(paramList); return 0; } diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h index 7b574b0a56..ee640224cf 100644 --- a/src/plugins/platforms/windows/qtwindowsglobal.h +++ b/src/plugins/platforms/windows/qtwindowsglobal.h @@ -73,6 +73,7 @@ enum WindowsEventType // Simplify event types ExposeEvent = WindowEventFlag + 1, ActivateWindowEvent = WindowEventFlag + 2, DeactivateWindowEvent = WindowEventFlag + 3, + MouseActivateWindowEvent = WindowEventFlag + 4, LeaveEvent = WindowEventFlag + 5, CloseEvent = WindowEventFlag + 6, ShowEvent = WindowEventFlag + 7, @@ -131,6 +132,8 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI case WM_ACTIVATEAPP: return (int)wParamIn ? QtWindows::ActivateApplicationEvent : QtWindows::DeactivateApplicationEvent; + case WM_MOUSEACTIVATE: + return QtWindows::MouseActivateWindowEvent; case WM_ACTIVATE: return LOWORD(wParamIn) == WA_INACTIVE ? QtWindows::DeactivateWindowEvent : QtWindows::ActivateWindowEvent; diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.cpp b/src/plugins/platforms/windows/qwindowsbackingstore.cpp index 55e7b85d96..0e0d10284b 100644 --- a/src/plugins/platforms/windows/qwindowsbackingstore.cpp +++ b/src/plugins/platforms/windows/qwindowsbackingstore.cpp @@ -117,8 +117,11 @@ void QWindowsBackingStore::flush(QWindow *window, const QRegion ®ion, } if (!BitBlt(dc, br.x(), br.y(), br.width(), br.height(), - m_image->hdc(), br.x() + offset.x(), br.y() + offset.y(), SRCCOPY)) - qErrnoWarning("%s: BitBlt failed", __FUNCTION__); + m_image->hdc(), br.x() + offset.x(), br.y() + offset.y(), SRCCOPY)) { + const DWORD lastError = GetLastError(); // QTBUG-35926, QTBUG-29716: may fail after lock screen. + if (lastError != ERROR_SUCCESS && lastError != ERROR_INVALID_HANDLE) + qErrnoWarning(lastError, "%s: BitBlt failed", __FUNCTION__); + } rw->releaseDC(); #ifndef Q_OS_WINCE } diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 77cac647ba..43ea317f83 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -80,7 +80,6 @@ QT_BEGIN_NAMESPACE // Verbosity of components -int QWindowsContext::verboseIntegration = 0; int QWindowsContext::verboseWindows = 0; int QWindowsContext::verboseEvents = 0; int QWindowsContext::verboseBackingStore = 0; @@ -89,7 +88,6 @@ int QWindowsContext::verboseGL = 0; int QWindowsContext::verboseOLE = 0; int QWindowsContext::verboseInputMethods = 0; int QWindowsContext::verboseDialogs = 0; -int QWindowsContext::verboseTheming = 0; int QWindowsContext::verboseTablet = 0; // Get verbosity of components from "foo:2,bar:3" @@ -321,7 +319,6 @@ QWindowsContext::QWindowsContext() : const QByteArray bv = qgetenv("QT_QPA_VERBOSE"); if (!bv.isEmpty()) { const char *v = bv.data(); - QWindowsContext::verboseIntegration = componentVerbose(v, "integration"); QWindowsContext::verboseWindows = componentVerbose(v, "windows"); QWindowsContext::verboseEvents = componentVerbose(v, "events"); QWindowsContext::verboseBackingStore = componentVerbose(v, "backingstore"); @@ -330,7 +327,6 @@ QWindowsContext::QWindowsContext() : QWindowsContext::verboseOLE = componentVerbose(v, "ole"); QWindowsContext::verboseInputMethods = componentVerbose(v, "im"); QWindowsContext::verboseDialogs = componentVerbose(v, "dialogs"); - QWindowsContext::verboseTheming = componentVerbose(v, "theming"); QWindowsContext::verboseTablet = componentVerbose(v, "tablet"); } #if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE) @@ -519,7 +515,7 @@ QString QWindowsContext::registerWindowClass(QString cname, qPrintable(cname)); d->m_registeredWindowClassNames.insert(cname); - if (QWindowsContext::verboseIntegration || QWindowsContext::verboseWindows) + if (QWindowsContext::verboseWindows) qDebug().nospace() << __FUNCTION__ << ' ' << cname << " style=0x" << QString::number(style, 16) << " brush=" << brush << " icon=" << icon << " atom=" << atom; @@ -530,11 +526,8 @@ void QWindowsContext::unregisterWindowClasses() { const HINSTANCE appInstance = (HINSTANCE)GetModuleHandle(0); - foreach (const QString &name, d->m_registeredWindowClassNames) { - if (QWindowsContext::verboseIntegration) - qDebug() << __FUNCTION__ << name; + foreach (const QString &name, d->m_registeredWindowClassNames) UnregisterClass((wchar_t*)name.utf16(), appInstance); - } d->m_registeredWindowClassNames.clear(); } @@ -928,6 +921,10 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, return true; #ifndef Q_OS_WINCE case QtWindows::ActivateWindowEvent: + if (platformWindow->window()->flags() & Qt::WindowDoesNotAcceptFocus) { + *result = LRESULT(MA_NOACTIVATE); + return true; + } #ifndef QT_NO_TABLETEVENT if (!d->m_tabletSupport.isNull()) d->m_tabletSupport->notifyActivate(); @@ -936,6 +933,12 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, if (const QWindow *modalWindow = QGuiApplication::modalWindow()) QWindowsWindow::baseWindowOf(modalWindow)->alertWindow(); break; + case QtWindows::MouseActivateWindowEvent: + if (platformWindow->window()->flags() & Qt::WindowDoesNotAcceptFocus) { + *result = LRESULT(MA_NOACTIVATE); + return true; + } + break; #endif #ifndef QT_NO_CONTEXTMENU case QtWindows::ContextMenu: diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h index 173df58570..c31d0fd41a 100644 --- a/src/plugins/platforms/windows/qwindowscontext.h +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -128,7 +128,6 @@ public: }; // Verbose flag set by environment variable QT_QPA_VERBOSE - static int verboseIntegration; static int verboseWindows; static int verboseBackingStore; static int verboseEvents; @@ -137,7 +136,6 @@ public: static int verboseOLE; static int verboseInputMethods; static int verboseDialogs; - static int verboseTheming; static int verboseTablet; explicit QWindowsContext(); diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp index 3a6f9f72e3..2b6a6255b8 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp @@ -1620,7 +1620,8 @@ QStringList QWindowsFontDatabase::fallbacksForFamily(const QString &family, QFon result << QString::fromLatin1("Arial"); } - result.append(extraTryFontsForFamily(family)); + if (script == QChar::Script_Common || script == QChar::Script_Han) + result.append(extraTryFontsForFamily(family)); if (QWindowsContext::verboseFonts) qDebug() << __FUNCTION__ << family << style << styleHint diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h index 57a6a3ba1d..399bb5f5ad 100644 --- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h +++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h @@ -105,6 +105,8 @@ public: static QString fontNameSubstitute(const QString &familyName); + IDWriteFontFace *directWriteFontFace() const { return m_directWriteFontFace; } + private: QImage imageForGlyph(glyph_t t, QFixed subPixelPosition, int margin, const QTransform &xform); void collectMetrics(); diff --git a/src/plugins/platforms/windows/qwindowsgdiintegration.cpp b/src/plugins/platforms/windows/qwindowsgdiintegration.cpp new file mode 100644 index 0000000000..9c8b5ed620 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsgdiintegration.cpp @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** 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 "qwindowsgdiintegration.h" +#include "qwindowscontext.h" +#include "qwindowsbackingstore.h" +#include "qwindowsgdinativeinterface.h" + +#include <QtCore/QDebug> +#include <QtGui/private/qpixmap_raster_p.h> + +QT_BEGIN_NAMESPACE + +class QWindowsGdiIntegrationPrivate +{ +public: + QWindowsGdiNativeInterface m_nativeInterface; +}; + +QWindowsGdiIntegration::QWindowsGdiIntegration(const QStringList ¶mList) + : QWindowsIntegration(paramList) + , d(new QWindowsGdiIntegrationPrivate) +{} + +QWindowsGdiIntegration::~QWindowsGdiIntegration() +{} + +QPlatformNativeInterface *QWindowsGdiIntegration::nativeInterface() const +{ + return &d->m_nativeInterface; +} + +QPlatformPixmap *QWindowsGdiIntegration::createPlatformPixmap(QPlatformPixmap::PixelType type) const +{ + return new QRasterPlatformPixmap(type); +} + +QPlatformBackingStore *QWindowsGdiIntegration::createPlatformBackingStore(QWindow *window) const +{ + return new QWindowsBackingStore(window); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsgdiintegration.h b/src/plugins/platforms/windows/qwindowsgdiintegration.h new file mode 100644 index 0000000000..0bf44d5439 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsgdiintegration.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** 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 QWINDOWSGDIINTEGRATION_H +#define QWINDOWSGDIINTEGRATION_H + +#include "qwindowsintegration.h" + +QT_BEGIN_NAMESPACE + +class QWindowsGdiIntegrationPrivate; +class QWindowsGdiIntegration : public QWindowsIntegration +{ +public: + explicit QWindowsGdiIntegration(const QStringList ¶mList); + virtual ~QWindowsGdiIntegration(); + + QPlatformNativeInterface *nativeInterface() const Q_DECL_OVERRIDE; + QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const Q_DECL_OVERRIDE; + QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const Q_DECL_OVERRIDE; + +private: + QScopedPointer<QWindowsGdiIntegrationPrivate> d; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSGDIINTEGRATION_H diff --git a/src/plugins/platforms/android/src/opengl/qandroidopenglplatformscreen.cpp b/src/plugins/platforms/windows/qwindowsgdinativeinterface.cpp index de4075feff..c1b0c139c9 100644 --- a/src/plugins/platforms/android/src/opengl/qandroidopenglplatformscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsgdinativeinterface.cpp @@ -39,23 +39,24 @@ ** ****************************************************************************/ -#include "qandroidopenglplatformscreen.h" -#include "qandroidopenglplatformwindow.h" -#include "androidjnimenu.h" +#include "qwindowsgdinativeinterface.h" +#include "qwindowsbackingstore.h" -QT_BEGIN_NAMESPACE +#include <QtGui/QBackingStore> -QAndroidOpenGLPlatformScreen::QAndroidOpenGLPlatformScreen(EGLDisplay display) - : QEglFSScreen(display) -{ -} +QT_BEGIN_NAMESPACE -void QAndroidOpenGLPlatformScreen::topWindowChanged(QPlatformWindow *window) +void *QWindowsGdiNativeInterface::nativeResourceForBackingStore(const QByteArray &resource, QBackingStore *bs) { - QtAndroidMenu::setActiveTopLevelWindow(window->window()); - QAndroidOpenGLPlatformWindow *platformWindow = static_cast<QAndroidOpenGLPlatformWindow *>(window); - if (platformWindow != 0) - platformWindow->updateStatusBarVisibility(); + if (!bs || !bs->handle()) { + qWarning("%s: '%s' requested for null backingstore or backingstore without handle.", __FUNCTION__, resource.constData()); + return 0; + } + QWindowsBackingStore *wbs = static_cast<QWindowsBackingStore *>(bs->handle()); + if (resource == "getDC") + return wbs->getDC(); + qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData()); + return 0; } QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsgdinativeinterface.h b/src/plugins/platforms/windows/qwindowsgdinativeinterface.h new file mode 100644 index 0000000000..3aa3a0b175 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsgdinativeinterface.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** 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 QWINDOWSGDINATIVEINTERFACE_H +#define QWINDOWSGDINATIVEINTERFACE_H + +#include "qwindowsnativeinterface.h" + +QT_BEGIN_NAMESPACE + +class QWindowsGdiNativeInterface : public QWindowsNativeInterface +{ + Q_OBJECT +public: + void *nativeResourceForBackingStore(const QByteArray &resource, QBackingStore *bs) Q_DECL_OVERRIDE; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSGDINATIVEINTERFACE_H diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp index 82deb0f473..281f54a9d9 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -882,7 +882,9 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex m_staticContext(staticContext), m_context(context), m_renderingContext(0), - m_pixelFormat(0), m_extensionsUsed(false) + m_pixelFormat(0), + m_extensionsUsed(false), + m_swapInterval(-1) { QSurfaceFormat format = context->format(); if (format.renderableType() == QSurfaceFormat::DefaultRenderableType) @@ -979,11 +981,9 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex QWindowsOpenGLContextFormat::current().apply(&m_obtainedFormat); - if (requestedAdditional.swapInterval != -1 && m_staticContext->wglSwapInternalExt) { - m_staticContext->wglSwapInternalExt(requestedAdditional.swapInterval); - if (m_staticContext->wglGetSwapInternalExt) - obtainedSwapInternal = m_staticContext->wglGetSwapInternalExt(); - } + if (m_staticContext->wglGetSwapInternalExt) + obtainedSwapInternal = m_staticContext->wglGetSwapInternalExt(); + wglMakeCurrent(0, 0); } while (false); if (hdc) @@ -1087,7 +1087,19 @@ bool QWindowsGLContext::makeCurrent(QPlatformSurface *surface) window->setFlag(QWindowsWindow::OpenGLDoubleBuffered); } m_windowContexts.append(newContext); - return wglMakeCurrent(newContext.hdc, newContext.renderingContext); + + bool success = wglMakeCurrent(newContext.hdc, newContext.renderingContext); + + // Set the swap interval + if (m_staticContext->wglSwapInternalExt) { + const int interval = surface->format().swapInterval(); + if (interval >= 0 && m_swapInterval != interval) { + m_swapInterval = interval; + m_staticContext->wglSwapInternalExt(interval); + } + } + + return success; } void QWindowsGLContext::doneCurrent() diff --git a/src/plugins/platforms/windows/qwindowsglcontext.h b/src/plugins/platforms/windows/qwindowsglcontext.h index 730e90bf70..c6b477128a 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.h +++ b/src/plugins/platforms/windows/qwindowsglcontext.h @@ -64,11 +64,10 @@ enum QWindowsGLFormatFlags // Additional format information for Windows. struct QWindowsOpenGLAdditionalFormat { - QWindowsOpenGLAdditionalFormat(unsigned formatFlagsIn = 0, unsigned pixmapDepthIn = 0, unsigned swapIntervalIn = -1) : - formatFlags(formatFlagsIn), pixmapDepth(pixmapDepthIn), swapInterval(swapIntervalIn) {} + QWindowsOpenGLAdditionalFormat(unsigned formatFlagsIn = 0, unsigned pixmapDepthIn = 0) : + formatFlags(formatFlagsIn), pixmapDepth(pixmapDepthIn) { } unsigned formatFlags; // QWindowsGLFormatFlags. unsigned pixmapDepth; // for QWindowsGLRenderToPixmap - int swapInterval; }; // Per-window data for active OpenGL contexts. @@ -178,6 +177,7 @@ private: PIXELFORMATDESCRIPTOR m_obtainedPixelFormatDescriptor; int m_pixelFormat; bool m_extensionsUsed; + int m_swapInterval; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index b6e75929f8..5ff1fbaa44 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -41,7 +41,6 @@ ****************************************************************************/ #include "qwindowsintegration.h" -#include "qwindowsbackingstore.h" #include "qwindowswindow.h" #include "qwindowscontext.h" #if defined(QT_OPENGL_ES_2) @@ -75,8 +74,6 @@ #if !defined(Q_OS_WINCE) && !defined(QT_NO_SESSIONMANAGER) # include "qwindowssessionmanager.h" #endif -#include <QtGui/QBackingStore> -#include <QtGui/private/qpixmap_raster_p.h> #include <QtGui/private/qguiapplication_p.h> #include <QtCore/private/qeventdispatcher_win_p.h> @@ -86,174 +83,6 @@ QT_BEGIN_NAMESPACE /*! - \class QWindowsNativeInterface - \brief Provides access to native handles. - - Currently implemented keys - \list - \li handle (HWND) - \li getDC (DC) - \li releaseDC Releases the previously acquired DC and returns 0. - \endlist - - \internal - \ingroup qt-lighthouse-win -*/ - -class QWindowsNativeInterface : public QPlatformNativeInterface -{ - Q_OBJECT - Q_PROPERTY(bool asyncExpose READ asyncExpose WRITE setAsyncExpose) -public: -#ifndef QT_NO_OPENGL - virtual void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context); -#endif - virtual void *nativeResourceForWindow(const QByteArray &resource, QWindow *window); - virtual void *nativeResourceForBackingStore(const QByteArray &resource, QBackingStore *bs); - - Q_INVOKABLE void *createMessageWindow(const QString &classNameTemplate, - const QString &windowName, - void *eventProc) const; - - Q_INVOKABLE QString registerWindowClass(const QString &classNameIn, void *eventProc) const; - - Q_INVOKABLE void beep() { MessageBeep(MB_OK); } // For QApplication - - 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) -{ - if (!window || !window->handle()) { - qWarning("%s: '%s' requested for null window or window without handle.", __FUNCTION__, resource.constData()); - return 0; - } - QWindowsWindow *bw = static_cast<QWindowsWindow *>(window->handle()); - if (resource == "handle") - return bw->handle(); - if (window->surfaceType() == QWindow::RasterSurface) { - if (resource == "getDC") - return bw->getDC(); - if (resource == "releaseDC") { - bw->releaseDC(); - return 0; - } - } - qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData()); - return 0; -} - -void *QWindowsNativeInterface::nativeResourceForBackingStore(const QByteArray &resource, QBackingStore *bs) -{ - if (!bs || !bs->handle()) { - qWarning("%s: '%s' requested for null backingstore or backingstore without handle.", __FUNCTION__, resource.constData()); - return 0; - } - QWindowsBackingStore *wbs = static_cast<QWindowsBackingStore *>(bs->handle()); - if (resource == "getDC") - return wbs->getDC(); - qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData()); - 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) -{ - if (!context || !context->handle()) { - qWarning("%s: '%s' requested for null context or context without handle.", __FUNCTION__, resource.constData()); - return 0; - } -#ifdef QT_OPENGL_ES_2 - QWindowsEGLContext *windowsEglContext = static_cast<QWindowsEGLContext *>(context->handle()); - if (resource == QByteArrayLiteral("eglDisplay")) - return windowsEglContext->eglDisplay(); - if (resource == QByteArrayLiteral("eglContext")) - return windowsEglContext->eglContext(); - if (resource == QByteArrayLiteral("eglConfig")) - return windowsEglContext->eglConfig(); -#else // QT_OPENGL_ES_2 - QWindowsGLContext *windowsContext = static_cast<QWindowsGLContext *>(context->handle()); - if (resource == QByteArrayLiteral("renderingContext")) - return windowsContext->renderingContext(); -#endif // !QT_OPENGL_ES_2 - - qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData()); - return 0; -} -#endif // !QT_NO_OPENGL - -/*! - \brief Creates a non-visible window handle for filtering messages. -*/ - -void *QWindowsNativeInterface::createMessageWindow(const QString &classNameTemplate, - const QString &windowName, - void *eventProc) const -{ - QWindowsContext *ctx = QWindowsContext::instance(); - const HWND hwnd = ctx->createDummyWindow(classNameTemplate, - (wchar_t*)windowName.utf16(), - (WNDPROC)eventProc); - return hwnd; -} - -/*! - \brief Registers a unique window class with a callback function based on \a classNameIn. -*/ - -QString QWindowsNativeInterface::registerWindowClass(const QString &classNameIn, void *eventProc) const -{ - return QWindowsContext::instance()->registerWindowClass(classNameIn, (WNDPROC)eventProc); -} - -bool QWindowsNativeInterface::asyncExpose() const -{ - return QWindowsContext::instance()->asyncExpose(); -} - -void QWindowsNativeInterface::setAsyncExpose(bool value) -{ - QWindowsContext::instance()->setAsyncExpose(value); -} - -/*! \class QWindowsIntegration \brief QPlatformIntegration implementation for Windows. \internal @@ -308,7 +137,6 @@ struct QWindowsIntegrationPrivate const unsigned m_options; QWindowsContext m_context; QPlatformFontDatabase *m_fontDatabase; - QWindowsNativeInterface m_nativeInterface; #ifndef QT_NO_CLIPBOARD QWindowsClipboard m_clipboard; # ifndef QT_NO_DRAGANDDROP @@ -345,8 +173,8 @@ static inline unsigned parseOptions(const QStringList ¶mList) } } else if (param == QLatin1String("gl=gdi")) { options |= QWindowsIntegration::DisableArb; - } else if (param == QLatin1String("mousefromtouch")) { - options |= QWindowsIntegration::PassOsMouseEventsSynthesizedFromTouch; + } else if (param == QLatin1String("nomousefromtouch")) { + options |= QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch; } } return options; @@ -375,8 +203,6 @@ QWindowsIntegration::QWindowsIntegration(const QStringList ¶mList) : QWindowsIntegration::~QWindowsIntegration() { - if (QWindowsContext::verboseIntegration) - qDebug("%s", __FUNCTION__); } bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) const @@ -406,11 +232,6 @@ bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) co return false; } -QPlatformPixmap *QWindowsIntegration::createPlatformPixmap(QPlatformPixmap::PixelType type) const -{ - return new QRasterPlatformPixmap(type); -} - QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) const { QWindowsWindow::WindowData requested; @@ -423,7 +244,7 @@ QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) cons const QWindowsWindow::WindowData obtained = QWindowsWindow::WindowData::create(window, requested, window->title()); - if (QWindowsContext::verboseIntegration || QWindowsContext::verboseWindows) + if (QWindowsContext::verboseWindows) qDebug().nospace() << __FUNCTION__ << '<' << window << '\n' << " Requested: " << requested.geometry << "frame incl.: " @@ -444,18 +265,11 @@ QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) cons return new QWindowsWindow(window, obtained); } -QPlatformBackingStore *QWindowsIntegration::createPlatformBackingStore(QWindow *window) const -{ - if (QWindowsContext::verboseIntegration) - qDebug() << __FUNCTION__ << window; - return new QWindowsBackingStore(window); -} - #ifndef QT_NO_OPENGL QPlatformOpenGLContext *QWindowsIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { - if (QWindowsContext::verboseIntegration) + if (QWindowsContext::verboseGL) qDebug() << __FUNCTION__ << context->format(); #ifdef QT_OPENGL_ES_2 if (d->m_staticEGLContext.isNull()) { @@ -510,7 +324,7 @@ QPlatformFontDatabase *QWindowsIntegration::fontDatabase() const d->m_fontDatabase = new QWindowsFontDatabase; #else if (isQMLApplication()) { - if (QWindowsContext::verboseIntegration) { + if (QWindowsContext::verboseFonts) { qDebug() << "QML application detected, using FreeType rendering"; } d->m_fontDatabase = new QWindowsFontDatabaseFT; @@ -563,11 +377,9 @@ QVariant QWindowsIntegration::styleHint(QPlatformIntegration::StyleHint hint) co case QPlatformIntegration::SynthesizeMouseFromTouchEvents: #ifdef Q_OS_WINCE // We do not want Qt to synthesize mouse events as Windows also does that. - // Alternatively, Windows-generated touch mouse events can be identified and - // ignored by checking GetMessageExtraInfo() for MI_WP_SIGNATURE (0xFF515700). return false; #else // Q_OS_WINCE - return QVariant(!(d->m_options & PassOsMouseEventsSynthesizedFromTouch)); + return QVariant(bool(d->m_options & DontPassOsMouseEventsSynthesizedFromTouch)); #endif // !Q_OS_WINCE default: break; @@ -585,11 +397,6 @@ QList<int> QWindowsIntegration::possibleKeys(const QKeyEvent *e) const return d->m_context.possibleKeys(e); } -QPlatformNativeInterface *QWindowsIntegration::nativeInterface() const -{ - return &d->m_nativeInterface; -} - #ifndef QT_NO_CLIPBOARD QPlatformClipboard * QWindowsIntegration::clipboard() const { @@ -655,5 +462,3 @@ QPlatformServices *QWindowsIntegration::services() const } QT_END_NAMESPACE - -#include "qwindowsintegration.moc" diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h index 97916a479b..30a39f67c4 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.h +++ b/src/plugins/platforms/windows/qwindowsintegration.h @@ -60,7 +60,7 @@ public: DisableArb = 0x4, NoNativeDialogs = 0x8, XpNativeDialogs = 0x10, - PassOsMouseEventsSynthesizedFromTouch = 0x20 // Pass OS-generated mouse events from touch. + DontPassOsMouseEventsSynthesizedFromTouch = 0x20 // Do not pass OS-generated mouse events from touch. }; explicit QWindowsIntegration(const QStringList ¶mList); @@ -68,9 +68,7 @@ public: bool hasCapability(QPlatformIntegration::Capability cap) const; - virtual QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const; QPlatformWindow *createPlatformWindow(QWindow *window) const; - QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; #ifndef QT_NO_OPENGL virtual QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; #endif @@ -85,7 +83,6 @@ public: #ifndef QT_NO_ACCESSIBILITY virtual QPlatformAccessibility *accessibility() const; #endif - virtual QPlatformNativeInterface *nativeInterface() const; virtual QPlatformFontDatabase *fontDatabase() const; virtual QStringList themeNames() const; virtual QPlatformTheme *createPlatformTheme(const QString &name) const; diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp index 3dd8c5a0cd..b43aafeba0 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp +++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp @@ -167,8 +167,12 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, if (et == QtWindows::MouseWheelEvent) return translateMouseWheelEvent(window, hwnd, msg, result); + Qt::MouseEventSource source = Qt::MouseEventNotSynthesized; + #ifndef Q_OS_WINCE - static const bool passSynthesizedMouseEvents = QWindowsIntegration::instance()->options() & QWindowsIntegration::PassOsMouseEventsSynthesizedFromTouch; + // Check for events synthesized from touch. Lower byte is touch index, 0 means pen. + static const bool passSynthesizedMouseEvents = + !(QWindowsIntegration::instance()->options() & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch); if (!passSynthesizedMouseEvents) { // Check for events synthesized from touch. Lower 7 bits are touch/pen index, bit 8 indicates touch. // However, when tablet support is active, extraInfo is a packet serial number. This is not a problem @@ -177,6 +181,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, const bool fromTouch = (extraInfo & signatureMask) == miWpSignature && (extraInfo & 0x80); if (fromTouch) return false; + source = Qt::MouseEventSynthesizedBySystem; } #endif // !Q_OS_WINCE @@ -187,7 +192,8 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, const Qt::MouseButtons buttons = QWindowsMouseHandler::queryMouseButtons(); QWindowSystemInterface::handleFrameStrutMouseEvent(window, clientPosition, globalPosition, buttons, - QWindowsKeyMapper::queryKeyboardModifiers()); + QWindowsKeyMapper::queryKeyboardModifiers(), + source); return false; // Allow further event processing (dragging of windows). } @@ -335,7 +341,8 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, } QWindowSystemInterface::handleMouseEvent(window, winEventPosition, globalPosition, buttons, - QWindowsKeyMapper::queryKeyboardModifiers()); + QWindowsKeyMapper::queryKeyboardModifiers(), + source); m_previousCaptureWindow = hasCapture ? window : 0; return true; } diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp new file mode 100644 index 0000000000..9bf4b3240c --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** 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 "qwindowsnativeinterface.h" +#include "qwindowswindow.h" +#include "qwindowscontext.h" + +#if defined(QT_OPENGL_ES_2) +# include "qwindowseglcontext.h" +# include <QtGui/QOpenGLContext> +#elif !defined(QT_NO_OPENGL) +# include "qwindowsglcontext.h" +#endif + +#include <QtGui/QWindow> + +QT_BEGIN_NAMESPACE + +void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resource, QWindow *window) +{ + if (!window || !window->handle()) { + qWarning("%s: '%s' requested for null window or window without handle.", __FUNCTION__, resource.constData()); + return 0; + } + QWindowsWindow *bw = static_cast<QWindowsWindow *>(window->handle()); + if (resource == "handle") + return bw->handle(); + if (window->surfaceType() == QWindow::RasterSurface) { + if (resource == "getDC") + return bw->getDC(); + if (resource == "releaseDC") { + bw->releaseDC(); + return 0; + } + } + qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData()); + 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) +{ + if (!context || !context->handle()) { + qWarning("%s: '%s' requested for null context or context without handle.", __FUNCTION__, resource.constData()); + return 0; + } +#ifdef QT_OPENGL_ES_2 + QWindowsEGLContext *windowsEglContext = static_cast<QWindowsEGLContext *>(context->handle()); + if (resource == QByteArrayLiteral("eglDisplay")) + return windowsEglContext->eglDisplay(); + if (resource == QByteArrayLiteral("eglContext")) + return windowsEglContext->eglContext(); + if (resource == QByteArrayLiteral("eglConfig")) + return windowsEglContext->eglConfig(); +#else // QT_OPENGL_ES_2 + QWindowsGLContext *windowsContext = static_cast<QWindowsGLContext *>(context->handle()); + if (resource == QByteArrayLiteral("renderingContext")) + return windowsContext->renderingContext(); +#endif // !QT_OPENGL_ES_2 + + qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData()); + return 0; +} +#endif // !QT_NO_OPENGL + +/*! + \brief Creates a non-visible window handle for filtering messages. +*/ + +void *QWindowsNativeInterface::createMessageWindow(const QString &classNameTemplate, + const QString &windowName, + void *eventProc) const +{ + QWindowsContext *ctx = QWindowsContext::instance(); + const HWND hwnd = ctx->createDummyWindow(classNameTemplate, + (wchar_t*)windowName.utf16(), + (WNDPROC)eventProc); + return hwnd; +} + +/*! + \brief Registers a unique window class with a callback function based on \a classNameIn. +*/ + +QString QWindowsNativeInterface::registerWindowClass(const QString &classNameIn, void *eventProc) const +{ + return QWindowsContext::instance()->registerWindowClass(classNameIn, (WNDPROC)eventProc); +} + +bool QWindowsNativeInterface::asyncExpose() const +{ + return QWindowsContext::instance()->asyncExpose(); +} + +void QWindowsNativeInterface::setAsyncExpose(bool value) +{ + QWindowsContext::instance()->setAsyncExpose(value); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.h b/src/plugins/platforms/windows/qwindowsnativeinterface.h new file mode 100644 index 0000000000..20100d0f49 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsnativeinterface.h @@ -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$ +** +****************************************************************************/ + +#ifndef QWINDOWSNATIVEINTERFACE_H +#define QWINDOWSNATIVEINTERFACE_H + +#include "qtwindows_additional.h" +#include <QtGui/qpa/qplatformnativeinterface.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QWindowsNativeInterface + \brief Provides access to native handles. + + Currently implemented keys + \list + \li handle (HWND) + \li getDC (DC) + \li releaseDC Releases the previously acquired DC and returns 0. + \endlist + + \internal + \ingroup qt-lighthouse-win +*/ + +class QWindowsNativeInterface : public QPlatformNativeInterface +{ + Q_OBJECT + Q_PROPERTY(bool asyncExpose READ asyncExpose WRITE setAsyncExpose) +public: +#ifndef QT_NO_OPENGL + virtual void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context); +#endif + virtual void *nativeResourceForWindow(const QByteArray &resource, QWindow *window); + + Q_INVOKABLE void *createMessageWindow(const QString &classNameTemplate, + const QString &windowName, + void *eventProc) const; + + Q_INVOKABLE QString registerWindowClass(const QString &classNameIn, void *eventProc) const; + + Q_INVOKABLE void beep() { MessageBeep(MB_OK); } // For QApplication + + 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); +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSNATIVEINTERFACE_H diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index 1fc1be53c7..60c8bee286 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -201,8 +201,6 @@ Q_GUI_EXPORT QPixmap qt_pixmapFromWinHBITMAP(HBITMAP bitmap, int hbitmapFormat = QPixmap QWindowsScreen::grabWindow(WId window, int x, int y, int width, int height) const { - if (QWindowsContext::verboseIntegration) - qDebug() << __FUNCTION__ << window << x << y << width << height; RECT r; HWND hwnd = window ? (HWND)window : GetDesktopWindow(); GetClientRect(hwnd, &r); diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index 00a5da8f44..988e34ea6d 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -406,10 +406,6 @@ void QWindowsTheme::refreshPalettes() m_palettes[ToolTipPalette] = new QPalette(toolTipPalette(*m_palettes[SystemPalette])); m_palettes[MenuPalette] = new QPalette(menuPalette(*m_palettes[SystemPalette])); m_palettes[MenuBarPalette] = menuBarPalette(*m_palettes[MenuPalette]); - if (QWindowsContext::verboseTheming) - qDebug() << __FUNCTION__ << '\n' - << " system=" << paletteToString(*m_palettes[SystemPalette]) - << " tooltip=" << paletteToString(*m_palettes[ToolTipPalette]); } void QWindowsTheme::clearFonts() @@ -449,11 +445,6 @@ void QWindowsTheme::refreshFonts() m_fonts[DockWidgetTitleFont] = new QFont(titleFont); m_fonts[ItemViewFont] = new QFont(iconTitleFont); m_fonts[FixedFont] = new QFont(fixedFont); - - if (QWindowsContext::verboseTheming) - qDebug() << __FUNCTION__ << '\n' - << " menuFont=" << menuFont - << " messageBox=" << MessageBoxFont; #endif // !Q_OS_WINCE } diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 51902385e1..b201f322ac 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -949,7 +949,7 @@ void QWindowsWindow::fireExpose(const QRegion ®ion, bool force) void QWindowsWindow::destroyWindow() { - if (QWindowsContext::verboseIntegration || QWindowsContext::verboseWindows) + if (QWindowsContext::verboseWindows) qDebug() << __FUNCTION__ << this << window() << m_data.hwnd; if (m_data.hwnd) { // Stop event dispatching before Window is destroyed. setFlag(WithinDestroy); @@ -1193,7 +1193,7 @@ void QWindowsWindow::hide_sys() const if (flags & Qt::Popup) ShowWindow(m_data.hwnd, SW_HIDE); else - SetWindowPos(m_data.hwnd,0, 0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER); + SetWindowPos(m_data.hwnd,0, 0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE); } } diff --git a/src/plugins/platforms/windows/windows.pri b/src/plugins/platforms/windows/windows.pri new file mode 100644 index 0000000000..c10d00c2ad --- /dev/null +++ b/src/plugins/platforms/windows/windows.pri @@ -0,0 +1,180 @@ +# Note: OpenGL32 must precede Gdi32 as it overwrites some functions. +LIBS *= -lole32 +!wince*:LIBS *= -luser32 -lwinspool -limm32 -lwinmm -loleaut32 + +contains(QT_CONFIG, opengl):!contains(QT_CONFIG, opengles2):LIBS *= -lopengl32 + +mingw: LIBS *= -luuid +# For the dialog helpers: +!wince*:LIBS *= -lshlwapi -lshell32 +!wince*:LIBS *= -ladvapi32 +wince*:DEFINES *= QT_LIBINFIX=L"\"\\\"$${QT_LIBINFIX}\\\"\"" + +DEFINES *= QT_NO_CAST_FROM_ASCII + +contains(QT_CONFIG, directwrite) { + LIBS *= -ldwrite + SOURCES += $$PWD/qwindowsfontenginedirectwrite.cpp + HEADERS += $$PWD/qwindowsfontenginedirectwrite.h +} else { + DEFINES *= QT_NO_DIRECTWRITE +} + +SOURCES += \ + $$PWD/qwindowswindow.cpp \ + $$PWD/qwindowsintegration.cpp \ + $$PWD/qwindowscontext.cpp \ + $$PWD/qwindowsscreen.cpp \ + $$PWD/qwindowskeymapper.cpp \ + $$PWD/qwindowsfontengine.cpp \ + $$PWD/qwindowsfontdatabase.cpp \ + $$PWD/qwindowsmousehandler.cpp \ + $$PWD/qwindowsguieventdispatcher.cpp \ + $$PWD/qwindowsole.cpp \ + $$PWD/qwindowsmime.cpp \ + $$PWD/qwindowsinternalmimedata.cpp \ + $$PWD/qwindowscursor.cpp \ + $$PWD/qwindowsinputcontext.cpp \ + $$PWD/qwindowstheme.cpp \ + $$PWD/qwindowsdialoghelpers.cpp \ + $$PWD/qwindowsservices.cpp \ + $$PWD/qwindowsnativeimage.cpp \ + $$PWD/qwindowsnativeinterface.cpp + +HEADERS += \ + $$PWD/qwindowswindow.h \ + $$PWD/qwindowsintegration.h \ + $$PWD/qwindowscontext.h \ + $$PWD/qwindowsscreen.h \ + $$PWD/qwindowskeymapper.h \ + $$PWD/qwindowsfontengine.h \ + $$PWD/qwindowsfontdatabase.h \ + $$PWD/qwindowsmousehandler.h \ + $$PWD/qwindowsguieventdispatcher.h \ + $$PWD/qtwindowsglobal.h \ + $$PWD/qtwindows_additional.h \ + $$PWD/qwindowsole.h \ + $$PWD/qwindowsmime.h \ + $$PWD/qwindowsinternalmimedata.h \ + $$PWD/qwindowscursor.h \ + $$PWD/array.h \ + $$PWD/qwindowsinputcontext.h \ + $$PWD/qwindowstheme.h \ + $$PWD/qwindowsdialoghelpers.h \ + $$PWD/qwindowsservices.h \ + $$PWD/qplatformfunctions_wince.h \ + $$PWD/qwindowsnativeimage.h \ + $$PWD/qwindowsnativeinterface.h + +INCLUDEPATH += $$PWD + +contains(QT_CONFIG, opengles2) { + SOURCES += $$PWD/qwindowseglcontext.cpp + HEADERS += $$PWD/qwindowseglcontext.h +} else { + contains(QT_CONFIG, opengl) { + SOURCES += $$PWD/qwindowsglcontext.cpp + HEADERS += $$PWD/qwindowsglcontext.h + } +} + +!contains( DEFINES, QT_NO_CLIPBOARD ) { + SOURCES += $$PWD/qwindowsclipboard.cpp + HEADERS += $$PWD/qwindowsclipboard.h +} + +# drag and drop on windows only works if a clipboard is available +!contains( DEFINES, QT_NO_DRAGANDDROP ) { + !win32:SOURCES += $$PWD/qwindowsdrag.cpp + !win32:HEADERS += $$PWD/qwindowsdrag.h + win32:!contains( DEFINES, QT_NO_CLIPBOARD ) { + HEADERS += $$PWD/qwindowsdrag.h + SOURCES += $$PWD/qwindowsdrag.cpp + } +} + +!wince*:!contains( DEFINES, QT_NO_TABLETEVENT ) { + INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/wintab + HEADERS += $$PWD/qwindowstabletsupport.h + SOURCES += $$PWD/qwindowstabletsupport.cpp +} + +!wince*:!contains( DEFINES, QT_NO_SESSIONMANAGER ) { + SOURCES += $$PWD/qwindowssessionmanager.cpp + HEADERS += $$PWD/qwindowssessionmanager.h +} + +contains(QT_CONFIG, freetype) { + DEFINES *= QT_NO_FONTCONFIG + QT_FREETYPE_DIR = $$QT_SOURCE_TREE/src/3rdparty/freetype + + HEADERS += \ + $$PWD/qwindowsfontdatabase_ft.h + SOURCES += \ + $$PWD/qwindowsfontdatabase_ft.cpp \ + $$QT_FREETYPE_DIR/src/base/ftbase.c \ + $$QT_FREETYPE_DIR/src/base/ftbbox.c \ + $$QT_FREETYPE_DIR/src/base/ftdebug.c \ + $$QT_FREETYPE_DIR/src/base/ftglyph.c \ + $$QT_FREETYPE_DIR/src/base/ftinit.c \ + $$QT_FREETYPE_DIR/src/base/ftmm.c \ + $$QT_FREETYPE_DIR/src/base/fttype1.c \ + $$QT_FREETYPE_DIR/src/base/ftsynth.c \ + $$QT_FREETYPE_DIR/src/base/ftbitmap.c \ + $$QT_FREETYPE_DIR/src/bdf/bdf.c \ + $$QT_FREETYPE_DIR/src/cache/ftcache.c \ + $$QT_FREETYPE_DIR/src/cff/cff.c \ + $$QT_FREETYPE_DIR/src/cid/type1cid.c \ + $$QT_FREETYPE_DIR/src/gzip/ftgzip.c \ + $$QT_FREETYPE_DIR/src/pcf/pcf.c \ + $$QT_FREETYPE_DIR/src/pfr/pfr.c \ + $$QT_FREETYPE_DIR/src/psaux/psaux.c \ + $$QT_FREETYPE_DIR/src/pshinter/pshinter.c \ + $$QT_FREETYPE_DIR/src/psnames/psmodule.c \ + $$QT_FREETYPE_DIR/src/raster/raster.c \ + $$QT_FREETYPE_DIR/src/sfnt/sfnt.c \ + $$QT_FREETYPE_DIR/src/smooth/smooth.c \ + $$QT_FREETYPE_DIR/src/truetype/truetype.c \ + $$QT_FREETYPE_DIR/src/type1/type1.c \ + $$QT_FREETYPE_DIR/src/type42/type42.c \ + $$QT_FREETYPE_DIR/src/winfonts/winfnt.c \ + $$QT_FREETYPE_DIR/src/lzw/ftlzw.c\ + $$QT_FREETYPE_DIR/src/otvalid/otvalid.c\ + $$QT_FREETYPE_DIR/src/otvalid/otvbase.c\ + $$QT_FREETYPE_DIR/src/otvalid/otvgdef.c\ + $$QT_FREETYPE_DIR/src/otvalid/otvjstf.c\ + $$QT_FREETYPE_DIR/src/otvalid/otvcommn.c\ + $$QT_FREETYPE_DIR/src/otvalid/otvgpos.c\ + $$QT_FREETYPE_DIR/src/otvalid/otvgsub.c\ + $$QT_FREETYPE_DIR/src/otvalid/otvmod.c\ + $$QT_FREETYPE_DIR/src/autofit/afangles.c\ + $$QT_FREETYPE_DIR/src/autofit/afglobal.c\ + $$QT_FREETYPE_DIR/src/autofit/aflatin.c\ + $$QT_FREETYPE_DIR/src/autofit/afmodule.c\ + $$QT_FREETYPE_DIR/src/autofit/afdummy.c\ + $$QT_FREETYPE_DIR/src/autofit/afhints.c\ + $$QT_FREETYPE_DIR/src/autofit/afloader.c\ + $$QT_FREETYPE_DIR/src/autofit/autofit.c + + SOURCES += $$QT_FREETYPE_DIR/src/base/ftsystem.c + + + INCLUDEPATH += \ + $$QT_FREETYPE_DIR/src \ + $$QT_FREETYPE_DIR/include + + TR_EXCLUDE += $$QT_FREETYPE_DIR/* + + DEFINES += FT2_BUILD_LIBRARY + contains(QT_CONFIG, system-zlib) { + DEFINES += FT_CONFIG_OPTION_SYSTEM_ZLIB + } +} else:contains(QT_CONFIG, system-freetype) { + include($$QT_SOURCE_TREE/src/platformsupport/fontdatabases/basic/basic.pri) + HEADERS += \ + $$PWD/qwindowsfontdatabase_ft.h + SOURCES += \ + $$PWD/qwindowsfontdatabase_ft.cpp +} + +contains(QT_CONFIG, accessibility):include($$PWD/accessible/accessible.pri) diff --git a/src/plugins/platforms/windows/windows.pro b/src/plugins/platforms/windows/windows.pro index 0249e156d9..188bd7917c 100644 --- a/src/plugins/platforms/windows/windows.pro +++ b/src/plugins/platforms/windows/windows.pro @@ -8,184 +8,19 @@ QT *= core-private QT *= gui-private QT *= platformsupport-private -# Note: OpenGL32 must precede Gdi32 as it overwrites some functions. -LIBS *= -lole32 -!wince*:LIBS *= -lgdi32 -luser32 -lwinspool -limm32 -lwinmm -loleaut32 +!wince:LIBS *= -lgdi32 -contains(QT_CONFIG, opengl):!contains(QT_CONFIG, opengles2):LIBS *= -lopengl32 +include(windows.pri) -win32-g++*: LIBS *= -luuid -# For the dialog helpers: -!wince*:LIBS *= -lshlwapi -lshell32 -!wince*:LIBS *= -ladvapi32 -wince*:DEFINES *= QT_LIBINFIX=L"\"\\\"$${QT_LIBINFIX}\\\"\"" - -DEFINES *= QT_NO_CAST_FROM_ASCII - -contains(QT_CONFIG, directwrite) { - LIBS *= -ldwrite - SOURCES += qwindowsfontenginedirectwrite.cpp - HEADERS += qwindowsfontenginedirectwrite.h -} else { - DEFINES *= QT_NO_DIRECTWRITE -} - -SOURCES += \ +SOURCES += \ main.cpp \ - qwindowsnativeimage.cpp \ - qwindowswindow.cpp \ - qwindowsintegration.cpp \ - qwindowscontext.cpp \ qwindowsbackingstore.cpp \ - qwindowsscreen.cpp \ - qwindowskeymapper.cpp \ - qwindowsfontengine.cpp \ - qwindowsfontdatabase.cpp \ - qwindowsmousehandler.cpp \ - qwindowsguieventdispatcher.cpp \ - qwindowsole.cpp \ - qwindowsmime.cpp \ - qwindowsinternalmimedata.cpp \ - qwindowscursor.cpp \ - qwindowsinputcontext.cpp \ - qwindowstheme.cpp \ - qwindowsdialoghelpers.cpp \ - qwindowsservices.cpp + qwindowsgdiintegration.cpp \ + qwindowsgdinativeinterface.cpp -HEADERS += \ - qwindowsnativeimage.h \ - qwindowswindow.h \ - qwindowsintegration.h \ - qwindowscontext.h \ +HEADERS += \ qwindowsbackingstore.h \ - qwindowsscreen.h \ - qwindowskeymapper.h \ - qwindowsfontengine.h \ - qwindowsfontdatabase.h \ - qwindowsmousehandler.h \ - qwindowsguieventdispatcher.h \ - qtwindowsglobal.h \ - qtwindows_additional.h \ - qwindowsole.h \ - qwindowsmime.h \ - qwindowsinternalmimedata.h \ - qwindowscursor.h \ - array.h \ - qwindowsinputcontext.h \ - qwindowstheme.h \ - qwindowsdialoghelpers.h \ - qwindowsservices.h \ - qplatformfunctions_wince.h - -contains(QT_CONFIG, opengles2) { - SOURCES += qwindowseglcontext.cpp - HEADERS += qwindowseglcontext.h -} else { - contains(QT_CONFIG, opengl) { - SOURCES += qwindowsglcontext.cpp - HEADERS += qwindowsglcontext.h - } -} - -!contains( DEFINES, QT_NO_CLIPBOARD ) { - SOURCES += qwindowsclipboard.cpp - HEADERS += qwindowsclipboard.h -} - -# drag and drop on windows only works if a clipboard is available -!contains( DEFINES, QT_NO_DRAGANDDROP ) { - !win32:SOURCES += qwindowsdrag.cpp - !win32:HEADERS += qwindowsdrag.h - win32:!contains( DEFINES, QT_NO_CLIPBOARD ) { - HEADERS += qwindowsdrag.h - SOURCES += qwindowsdrag.cpp - } -} - -!wince*:!contains( DEFINES, QT_NO_TABLETEVENT ) { - INCLUDEPATH += ../../../3rdparty/wintab - HEADERS += qwindowstabletsupport.h - SOURCES += qwindowstabletsupport.cpp -} - -!wince*:!contains( DEFINES, QT_NO_SESSIONMANAGER ) { - SOURCES += qwindowssessionmanager.cpp - HEADERS += qwindowssessionmanager.h -} - -contains(QT_CONFIG, freetype) { - DEFINES *= QT_NO_FONTCONFIG - QT_FREETYPE_DIR = $$QT_SOURCE_TREE/src/3rdparty/freetype - - HEADERS += \ - qwindowsfontdatabase_ft.h - SOURCES += \ - qwindowsfontdatabase_ft.cpp \ - $$QT_FREETYPE_DIR/src/base/ftbase.c \ - $$QT_FREETYPE_DIR/src/base/ftbbox.c \ - $$QT_FREETYPE_DIR/src/base/ftdebug.c \ - $$QT_FREETYPE_DIR/src/base/ftglyph.c \ - $$QT_FREETYPE_DIR/src/base/ftinit.c \ - $$QT_FREETYPE_DIR/src/base/ftmm.c \ - $$QT_FREETYPE_DIR/src/base/fttype1.c \ - $$QT_FREETYPE_DIR/src/base/ftsynth.c \ - $$QT_FREETYPE_DIR/src/base/ftbitmap.c \ - $$QT_FREETYPE_DIR/src/bdf/bdf.c \ - $$QT_FREETYPE_DIR/src/cache/ftcache.c \ - $$QT_FREETYPE_DIR/src/cff/cff.c \ - $$QT_FREETYPE_DIR/src/cid/type1cid.c \ - $$QT_FREETYPE_DIR/src/gzip/ftgzip.c \ - $$QT_FREETYPE_DIR/src/pcf/pcf.c \ - $$QT_FREETYPE_DIR/src/pfr/pfr.c \ - $$QT_FREETYPE_DIR/src/psaux/psaux.c \ - $$QT_FREETYPE_DIR/src/pshinter/pshinter.c \ - $$QT_FREETYPE_DIR/src/psnames/psmodule.c \ - $$QT_FREETYPE_DIR/src/raster/raster.c \ - $$QT_FREETYPE_DIR/src/sfnt/sfnt.c \ - $$QT_FREETYPE_DIR/src/smooth/smooth.c \ - $$QT_FREETYPE_DIR/src/truetype/truetype.c \ - $$QT_FREETYPE_DIR/src/type1/type1.c \ - $$QT_FREETYPE_DIR/src/type42/type42.c \ - $$QT_FREETYPE_DIR/src/winfonts/winfnt.c \ - $$QT_FREETYPE_DIR/src/lzw/ftlzw.c\ - $$QT_FREETYPE_DIR/src/otvalid/otvalid.c\ - $$QT_FREETYPE_DIR/src/otvalid/otvbase.c\ - $$QT_FREETYPE_DIR/src/otvalid/otvgdef.c\ - $$QT_FREETYPE_DIR/src/otvalid/otvjstf.c\ - $$QT_FREETYPE_DIR/src/otvalid/otvcommn.c\ - $$QT_FREETYPE_DIR/src/otvalid/otvgpos.c\ - $$QT_FREETYPE_DIR/src/otvalid/otvgsub.c\ - $$QT_FREETYPE_DIR/src/otvalid/otvmod.c\ - $$QT_FREETYPE_DIR/src/autofit/afangles.c\ - $$QT_FREETYPE_DIR/src/autofit/afglobal.c\ - $$QT_FREETYPE_DIR/src/autofit/aflatin.c\ - $$QT_FREETYPE_DIR/src/autofit/afmodule.c\ - $$QT_FREETYPE_DIR/src/autofit/afdummy.c\ - $$QT_FREETYPE_DIR/src/autofit/afhints.c\ - $$QT_FREETYPE_DIR/src/autofit/afloader.c\ - $$QT_FREETYPE_DIR/src/autofit/autofit.c - - SOURCES += $$QT_FREETYPE_DIR/src/base/ftsystem.c - - - INCLUDEPATH += \ - $$QT_FREETYPE_DIR/src \ - $$QT_FREETYPE_DIR/include - - TR_EXCLUDE += $$QT_FREETYPE_DIR/* - - DEFINES += FT2_BUILD_LIBRARY - contains(QT_CONFIG, system-zlib) { - DEFINES += FT_CONFIG_OPTION_SYSTEM_ZLIB - } -} else:contains(QT_CONFIG, system-freetype) { - include($$QT_SOURCE_TREE/src/platformsupport/fontdatabases/basic/basic.pri) - HEADERS += \ - qwindowsfontdatabase_ft.h - SOURCES += \ - qwindowsfontdatabase_ft.cpp -} + qwindowsgdiintegration.h \ + qwindowsgdinativeinterface.h OTHER_FILES += windows.json - -contains(QT_CONFIG, accessibility):include(accessible/accessible.pri) diff --git a/src/plugins/platforms/winrt/blit.hlsl b/src/plugins/platforms/winrt/blit.hlsl new file mode 100644 index 0000000000..170e7f40ca --- /dev/null +++ b/src/plugins/platforms/winrt/blit.hlsl @@ -0,0 +1,14 @@ +uniform SamplerState Sampler : register(s0); +uniform Texture2D Texture : register(t0); + +void blitvs(in float4 pos0 : TEXCOORD0, in float2 tex0 : TEXCOORD1, + out float4 gl_Position : SV_POSITION, out float2 coord : TEXCOORD0) +{ + coord = tex0; + gl_Position = pos0 * float4(1.0, -1.0, 1.0, 1.0); +} + +float4 blitps(in float4 gl_Position : SV_POSITION, in float2 coord : TEXCOORD0) : SV_TARGET0 +{ + return Texture.Sample(Sampler, coord); +} diff --git a/src/plugins/platforms/winrt/main.cpp b/src/plugins/platforms/winrt/main.cpp new file mode 100644 index 0000000000..89d560dbe3 --- /dev/null +++ b/src/plugins/platforms/winrt/main.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** 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 "qwinrtintegration.h" + +#include <qpa/qplatformintegrationplugin.h> + +QT_BEGIN_NAMESPACE + +class QWinRTIntegrationPlugin : public QPlatformIntegrationPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "winrt.json") + +public: + QStringList keys() const; + QPlatformIntegration *create(const QString&, const QStringList&); +}; + +QStringList QWinRTIntegrationPlugin::keys() const +{ + return QStringList(QStringLiteral("WinRT")); +} + +QPlatformIntegration *QWinRTIntegrationPlugin::create(const QString& system, const QStringList& paramList) +{ + Q_UNUSED(paramList); + if (!system.compare(QLatin1String("winrt"), Qt::CaseInsensitive)) + return QWinRTIntegration::create(); + + return 0; +} + +QT_END_NAMESPACE + +#include "main.moc" diff --git a/src/plugins/platforms/winrt/qwinrtbackingstore.cpp b/src/plugins/platforms/winrt/qwinrtbackingstore.cpp new file mode 100644 index 0000000000..b219548788 --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrtbackingstore.cpp @@ -0,0 +1,393 @@ +/**************************************************************************** +** +** 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 "qwinrtbackingstore.h" + +#include "qwinrtscreen.h" +#include "qwinrtwindow.h" +#include "qwinrteglcontext.h" +#include <QtGui/QOpenGLContext> + +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +#include <dxgi.h> + +// Generated shader headers +#include "blitps.h" +#include "blitvs.h" + +namespace { // Utility namespace for writing out an ANGLE-compatible binary blob + +// Must match packaged ANGLE +enum : quint32 { + AngleMajorVersion = 1, + AngleMinorVersion = 2, + AngleBuildRevision = 2446, + AngleVersion = ((AngleMajorVersion << 24) | (AngleMinorVersion << 16) | AngleBuildRevision), + AngleOptimizationLevel = (1 << 14) +}; + +struct ShaderString +{ + ShaderString(const char *data = 0) : data(data) { } + const char *data; +}; + +// ANGLE stream compatibility - when size_t is 32-bit, QDataStream::writeBytes() also works +QDataStream &operator<<(QDataStream &stream, const ShaderString &shaderString) +{ + if (!shaderString.data) + return stream << size_t(0); + + size_t len = strlen(shaderString.data); + stream << len; + stream.writeRawData(shaderString.data, int(len)); + return stream; +} + +struct Attribute +{ + Attribute(GLenum type = 0, const char *name = 0, quint32 index = 0) + : type(type), name(name), index(index) { } + GLenum type; + ShaderString name; + quint32 index; +}; + +struct Sampler +{ + enum TextureType { Texture2D, TextureCube }; + Sampler(bool active = false, GLint unit = 0, TextureType type = Texture2D) + : active(active), unit(unit), type(type) { } + bool active; + GLint unit; + TextureType type; +}; + +struct Uniform +{ + Uniform() { } + Uniform(GLenum type, quint32 precision, const char *name, quint32 arraySize, + quint32 psRegisterIndex, quint32 vsRegisterIndex, quint32 registerCount) + : type(type), precision(precision), name(name), arraySize(arraySize) + , psRegisterIndex(psRegisterIndex), vsRegisterIndex(vsRegisterIndex), registerCount(registerCount) { } + GLenum type; + quint32 precision; + ShaderString name; + quint32 arraySize; + quint32 psRegisterIndex; + quint32 vsRegisterIndex; + quint32 registerCount; +}; + +struct UniformIndex +{ + UniformIndex(const char *name = 0, quint32 element = 0, quint32 index = 0) + : name(name), element(element), index(index) { } + ShaderString name; + quint32 element; + quint32 index; +}; + +static const QByteArray createAngleBinary( + const QVector<Attribute> &attributes, + const QVector<Sampler> &textureSamplers, + const QVector<Sampler> &vertexSamplers, + const QVector<Uniform> &uniforms, + const QVector<UniformIndex> &uniformIndex, + const QByteArray &pixelShader, + const QByteArray &vertexShader, + const QByteArray &geometryShader = QByteArray(), + bool usesPointSize = false) +{ + QByteArray binary; + + QDataStream stream(&binary, QIODevice::WriteOnly); + stream.setByteOrder(QDataStream::LittleEndian); + + stream << quint32(GL_PROGRAM_BINARY_ANGLE) + << quint32(AngleVersion) + << quint32(AngleOptimizationLevel); + + // Vertex attributes + for (int i = 0; i < 16; ++i) { + if (i < attributes.size()) + stream << quint32(attributes[i].type) << attributes[i].name << attributes[i].index; + else + stream << quint32(GL_NONE) << ShaderString() << qint32(-1); + } + + // Texture units + for (int i = 0; i < 16; ++i) { + if (i < textureSamplers.size()) + stream << textureSamplers[i].active << textureSamplers[i].unit << qint32(textureSamplers[i].type); + else + stream << false << qint32(0) << qint32(Sampler::Texture2D); + } + + // Vertex texture units + for (int i = 0; i < 16; ++i) { + if (i < vertexSamplers.size()) + stream << vertexSamplers[i].active << vertexSamplers[i].unit << qint32(vertexSamplers[i].type); + else + stream << false << qint32(0) << qint32(Sampler::Texture2D); + } + + stream << vertexSamplers.size() + << textureSamplers.size() + << usesPointSize; + + stream << size_t(uniforms.size()); + foreach (const Uniform &uniform, uniforms) { + stream << uniform.type << uniform.precision << uniform.name << uniform.arraySize + << uniform.psRegisterIndex << uniform.vsRegisterIndex << uniform.registerCount; + } + + stream << size_t(uniformIndex.size()); + foreach (const UniformIndex &index, uniformIndex) + stream << index.name << index.element << index.index; + + stream << quint32(pixelShader.size()) + << quint32(vertexShader.size()) + << quint32(geometryShader.size()); + + // ANGLE requires that we query the adapter for its LUID. Later on, it may be useful + // for checking feature level support, picking the best adapter on the system, etc. + IDXGIFactory1 *dxgiFactory; + if (FAILED(CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory)))) { + qCritical("QWinRTBackingStore: failed to create DXGI factory."); + return QByteArray(); + } + IDXGIAdapter *dxgiAdapter; + if (FAILED(dxgiFactory->EnumAdapters(0, &dxgiAdapter))) { + qCritical("QWinRTBackingStore:: failed to enumerate adapter."); + dxgiFactory->Release(); + return QByteArray(); + } + DXGI_ADAPTER_DESC desc; + dxgiAdapter->GetDesc(&desc); + dxgiAdapter->Release(); + QByteArray guid(sizeof(GUID), '\0'); + memcpy(guid.data(), &desc.AdapterLuid, sizeof(LUID)); + stream.writeRawData(guid.constData(), guid.size()); + stream.writeRawData(pixelShader.constData(), pixelShader.size()); + stream.writeRawData(vertexShader.constData(), vertexShader.size()); + if (!geometryShader.isEmpty()) + stream.writeRawData(geometryShader.constData(), geometryShader.size()); + + return binary; +} + +} // namespace + +QT_BEGIN_NAMESPACE + +static const GLfloat normCoords[] = { -1, 1, 1, 1, 1, -1, -1, -1 }; +static const GLfloat quadCoords[] = { 0, 0, 1, 0, 1, 1, 0, 1 }; + +QWinRTBackingStore::QWinRTBackingStore(QWindow *window) + : QPlatformBackingStore(window) + , m_context(new QOpenGLContext) + , m_shaderProgram(0) + , m_fbo(0) + , m_texture(0) + , m_screen(static_cast<QWinRTScreen*>(window->screen()->handle())) +{ + window->setSurfaceType(QSurface::OpenGLSurface); // Required for flipping, but could be done in the swap + + m_context->setFormat(window->requestedFormat()); + m_context->setScreen(window->screen()); + m_context->create(); + + m_context->makeCurrent(window); + glGenFramebuffers(1, &m_fbo); + glGenRenderbuffers(1, &m_rbo); + glGenTextures(1, &m_texture); + m_shaderProgram = glCreateProgram(); + +#if 0 // Standard GLES passthrough shader program + static const char *vertexShaderSource = + "attribute vec4 pos0;\n" + "attribute vec2 tex0;\n" + "varying vec2 coord;\n" + "void main() {\n" + " coord = tex0;\n" + " gl_Position = pos0;\n" + "}\n"; + static const char *fragmentShaderSource = + "uniform sampler2D texture;\n" + "varying highp vec2 coord;\n" + "void main() {\n" + " gl_FragColor = texture2D(texture, coord);\n" + "}\n"; + GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); + glCompileShader(vertexShader); + GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); + glCompileShader(fragmentShader); + glAttachShader(m_shaderProgram, vertexShader); + glAttachShader(m_shaderProgram, fragmentShader); + glLinkProgram(m_shaderProgram); +#else // Precompiled passthrough shader + QVector<Attribute> attributes = QVector<Attribute>() << Attribute(GL_FLOAT_VEC4, "pos0", 0) + << Attribute(GL_FLOAT_VEC2, "tex0", 1); + QVector<Sampler> textureSamplers = QVector<Sampler>() << Sampler(true, 0, Sampler::Texture2D); + QVector<Sampler> vertexSamplers; + QVector<Uniform> uniforms = QVector<Uniform>() << Uniform(GL_SAMPLER_2D, 0, "texture", 0, 0, -1, 1); + QVector<UniformIndex> uniformsIndex = QVector<UniformIndex>() << UniformIndex("texture", 0, 0); + QByteArray pixelShader(reinterpret_cast<const char *>(q_blitps), sizeof(q_blitps)); + QByteArray vertexShader(reinterpret_cast<const char *>(q_blitvs), sizeof(q_blitvs)); + QByteArray binary = createAngleBinary(attributes, textureSamplers, vertexSamplers, + uniforms, uniformsIndex, pixelShader, vertexShader); + glProgramBinaryOES(m_shaderProgram, GL_PROGRAM_BINARY_ANGLE, binary.constData(), binary.size()); +#endif + m_context->doneCurrent(); + resize(window->size(), QRegion()); +} + +QWinRTBackingStore::~QWinRTBackingStore() +{ + glDeleteBuffers(1, &m_fbo); + glDeleteRenderbuffers(1, &m_rbo); + glDeleteTextures(1, &m_texture); + glDeleteProgram(m_shaderProgram); +} + +QPaintDevice *QWinRTBackingStore::paintDevice() +{ + return m_paintDevice.data(); +} + +void QWinRTBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) +{ + Q_UNUSED(offset) + + const QImage *image = static_cast<QImage *>(m_paintDevice.data()); + + m_context->makeCurrent(window); + + // Blitting the entire image width trades zero image copy/relayout for a larger texture upload. + // Since we're blitting the whole width anyway, the boundingRect() is used in the assumption that + // we don't repeat upload. This is of course dependent on the distance between update regions. + // Ideally, we would use the GL_EXT_unpack_subimage extension, which should be possible to implement + // since D3D11_MAPPED_SUBRESOURCE supports RowPitch (see below). + // Note that single-line blits in a loop are *very* slow, so reducing calls to glTexSubImage2D + // is probably a good idea anyway. + glBindTexture(GL_TEXTURE_2D, m_texture); + QRect bounds = region.boundingRect(); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, bounds.y(), m_size.width(), bounds.height(), + GL_BGRA_EXT, GL_UNSIGNED_BYTE, image->scanLine(bounds.y())); + // TODO: Implement GL_EXT_unpack_subimage in ANGLE for more minimal uploads + //glPixelStorei(GL_UNPACK_ROW_LENGTH, image->bytesPerLine()); + //glTexSubImage2D(GL_TEXTURE_2D, 0, bounds.x(), bounds.y(), bounds.width(), bounds.height(), + // GL_BGRA_EXT, GL_UNSIGNED_BYTE, image->scanLine(bounds.y()) + bounds.x() * 4); + + // Bind render buffer + glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_rbo); + + // Bind position + glUseProgram(m_shaderProgram); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, normCoords); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, quadCoords); + + // Render + glViewport(0, 0, m_size.width(), m_size.height()); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + // Unbind + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); + glUseProgram(0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindTexture(GL_TEXTURE_2D, 0); + + // fast blit - TODO: perform the blit inside swap buffers instead + glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, m_fbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, 0); + glBlitFramebufferANGLE(0, 0, m_size.width(), m_size.height(), // TODO: blit only the changed rectangle + 0, 0, m_size.width(), m_size.height(), + GL_COLOR_BUFFER_BIT, GL_NEAREST); + + m_context->swapBuffers(window); + m_context->doneCurrent(); +} + +void QWinRTBackingStore::resize(const QSize &size, const QRegion &staticContents) +{ + Q_UNUSED(staticContents) + if (m_size == size) + return; + + m_size = size; + m_paintDevice.reset(new QImage(m_size, QImage::Format_ARGB32_Premultiplied)); + + m_context->makeCurrent(window()); + // Input texture + glBindTexture(GL_TEXTURE_2D, m_texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, m_size.width(), m_size.height(), + 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, NULL); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glBindTexture(GL_TEXTURE_2D, 0); + // Render buffer + glBindRenderbuffer(GL_RENDERBUFFER, m_rbo); + glRenderbufferStorage(GL_RENDERBUFFER, GL_BGRA8_EXT, m_size.width(), m_size.height()); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + m_context->doneCurrent(); +} + +void QWinRTBackingStore::beginPaint(const QRegion ®ion) +{ + Q_UNUSED(region) +} + +void QWinRTBackingStore::endPaint() +{ +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/qeglfsbackingstore.h b/src/plugins/platforms/winrt/qwinrtbackingstore.h index 9af856e8e7..8be549b441 100644 --- a/src/plugins/platforms/eglfs/qeglfsbackingstore.h +++ b/src/plugins/platforms/winrt/qwinrtbackingstore.h @@ -39,43 +39,39 @@ ** ****************************************************************************/ -#ifndef QEGLFSBACKINGSTORE_H -#define QEGLFSBACKINGSTORE_H +#ifndef QWINRTBACKINGSTORE_H +#define QWINRTBACKINGSTORE_H #include <qpa/qplatformbackingstore.h> -#include <QtGui/QOpenGLFunctions> - -#include <QImage> -#include <QRegion> +#include <QtCore/QScopedPointer> QT_BEGIN_NAMESPACE -class QOpenGLPaintDevice; -class QEglFSWindow; +class QWinRTScreen; +class QOpenGLContext; -class QEglFSBackingStore : public QPlatformBackingStore, public QOpenGLFunctions +class QWinRTBackingStore : public QPlatformBackingStore { public: - QEglFSBackingStore(QWindow *window); - + explicit QWinRTBackingStore(QWindow *window); + ~QWinRTBackingStore(); QPaintDevice *paintDevice(); - void beginPaint(const QRegion &); - + void endPaint(); void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); void resize(const QSize &size, const QRegion &staticContents); - uint texture() const { return m_texture; } - private: - void updateTexture(); - - QEglFSWindow *m_window; - QImage m_image; - uint m_texture; - QRegion m_dirty; + QSize m_size; + QScopedPointer<QPaintDevice> m_paintDevice; + QScopedPointer<QOpenGLContext> m_context; + quint32 m_shaderProgram; + quint32 m_fbo; + quint32 m_rbo; + quint32 m_texture; + QWinRTScreen *m_screen; }; QT_END_NAMESPACE -#endif // QEGLFSBACKINGSTORE_H +#endif // QWINRTBACKINGSTORE_H diff --git a/src/plugins/platforms/winrt/qwinrtcursor.cpp b/src/plugins/platforms/winrt/qwinrtcursor.cpp new file mode 100644 index 0000000000..8241560cef --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrtcursor.cpp @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** 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 "qwinrtcursor.h" + +#include <wrl.h> +#include <windows.ui.core.h> +#include <windows.foundation.h> +using namespace Microsoft::WRL::Wrappers; +using namespace ABI::Windows::UI::Core; +using namespace ABI::Windows::Foundation; + +QT_BEGIN_NAMESPACE + +QWinRTCursor::QWinRTCursor(ICoreWindow *window) : m_window(window), m_cursorFactory(nullptr) +{ +#ifndef Q_OS_WINPHONE + GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Core_CoreCursor).Get(), &m_cursorFactory); +#endif +} + +QWinRTCursor::~QWinRTCursor() +{ + if (m_cursorFactory) + m_cursorFactory->Release(); +} + +#ifndef QT_NO_CURSOR +void QWinRTCursor::changeCursor(QCursor *windowCursor, QWindow *) +{ +#ifndef Q_OS_WINPHONE + if (!m_cursorFactory) + return; + + CoreCursorType type; + switch (windowCursor ? windowCursor->shape() : Qt::ArrowCursor) { + case Qt::BlankCursor: + m_window->put_PointerCursor(nullptr); + return; + default: + case Qt::OpenHandCursor: + case Qt::ClosedHandCursor: + case Qt::DragCopyCursor: + case Qt::DragMoveCursor: + case Qt::DragLinkCursor: + // (unavailable) + case Qt::ArrowCursor: + type = CoreCursorType_Arrow; + break; + case Qt::UpArrowCursor: + type = CoreCursorType_UpArrow; + break; + case Qt::CrossCursor: + type = CoreCursorType_Cross; + break; + case Qt::WaitCursor: + case Qt::BusyCursor: + type = CoreCursorType_Wait; + break; + case Qt::IBeamCursor: + type = CoreCursorType_IBeam; + break; + case Qt::SizeVerCursor: + case Qt::SplitVCursor: + type = CoreCursorType_SizeNorthSouth; + break; + case Qt::SizeHorCursor: + case Qt::SplitHCursor: + type = CoreCursorType_SizeWestEast; + break; + case Qt::SizeBDiagCursor: + type = CoreCursorType_SizeNortheastSouthwest; + break; + case Qt::SizeFDiagCursor: + type = CoreCursorType_SizeNorthwestSoutheast; + break; + case Qt::SizeAllCursor: + type = CoreCursorType_SizeAll; + break; + case Qt::PointingHandCursor: + type = CoreCursorType_Hand; + break; + case Qt::ForbiddenCursor: + type = CoreCursorType_UniversalNo; + break; + case Qt::WhatsThisCursor: + type = CoreCursorType_Help; + break; + case Qt::BitmapCursor: + case Qt::CustomCursor: + // TODO: figure out if arbitrary bitmaps can be made into resource IDs + // For now, we don't get enough info from QCursor to set a custom cursor + type = CoreCursorType_Custom; + break; + } + + ICoreCursor *cursor; + if (SUCCEEDED(m_cursorFactory->CreateCursor(type, 0, &cursor))) + m_window->put_PointerCursor(cursor); +#endif // Q_OS_WINPHONE +} +#endif // QT_NO_CURSOR + +QPoint QWinRTCursor::pos() const +{ +#ifdef Q_OS_WINPHONE + return QPlatformCursor::pos(); +#else + Point point; + m_window->get_PointerPosition(&point); + return QPoint(point.X, point.Y); +#endif +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtcursor.h b/src/plugins/platforms/winrt/qwinrtcursor.h new file mode 100644 index 0000000000..f7b301a98b --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrtcursor.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** 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 QWINRTCURSOR_H +#define QWINRTCURSOR_H + +#include <qpa/qplatformcursor.h> + +namespace ABI { + namespace Windows { + namespace UI { + namespace Core { + struct ICoreWindow; + struct ICoreCursorFactory; + } + } + } +} + +QT_BEGIN_NAMESPACE + +class QWinRTCursor : public QPlatformCursor +{ +public: + explicit QWinRTCursor(ABI::Windows::UI::Core::ICoreWindow *window); + ~QWinRTCursor(); +#ifndef QT_NO_CURSOR + void changeCursor(QCursor * windowCursor, QWindow *); +#endif + QPoint pos() const; + +private: + ABI::Windows::UI::Core::ICoreWindow *m_window; + ABI::Windows::UI::Core::ICoreCursorFactory *m_cursorFactory; +}; + +QT_END_NAMESPACE + +#endif // QWINRTCURSOR_H diff --git a/src/plugins/platforms/winrt/qwinrteglcontext.cpp b/src/plugins/platforms/winrt/qwinrteglcontext.cpp new file mode 100644 index 0000000000..014378f896 --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrteglcontext.cpp @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** 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 "qwinrteglcontext.h" + +QT_BEGIN_NAMESPACE + +QWinRTEGLContext::QWinRTEGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, EGLSurface surface) + : QEGLPlatformContext(format, share, display, EGL_OPENGL_ES_API), m_eglSurface(surface) +{ +} + +EGLSurface QWinRTEGLContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface) +{ + if (surface->surface()->surfaceClass() == QSurface::Window) { + // All windows use the same surface + return m_eglSurface; + } else { + // TODO: return EGL surfaces for offscreen surfaces + qWarning("This plugin does not support offscreen surfaces."); + return EGL_NO_SURFACE; + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrteglcontext.h b/src/plugins/platforms/winrt/qwinrteglcontext.h new file mode 100644 index 0000000000..c065847374 --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrteglcontext.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** 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 QWINDOWSEGLCONTEXT_H +#define QWINDOWSEGLCONTEXT_H + +#include <QtPlatformSupport/private/qeglplatformcontext_p.h> + +QT_BEGIN_NAMESPACE + +class QWinRTEGLContext : public QEGLPlatformContext +{ +public: + explicit QWinRTEGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, EGLSurface surface); + +protected: + EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface); + +private: + EGLSurface m_eglSurface; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSEGLCONTEXT_H diff --git a/src/plugins/platforms/winrt/qwinrteventdispatcher.cpp b/src/plugins/platforms/winrt/qwinrteventdispatcher.cpp new file mode 100644 index 0000000000..baa8b5c636 --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrteventdispatcher.cpp @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** 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 "qwinrteventdispatcher.h" +#include <qpa/qwindowsysteminterface.h> +#include <qpa/qplatformscreen.h> +#include <qpa/qplatformscreenpageflipper.h> +#include <QtCore/QThread> +#include <QtGui/QGuiApplication> + +#include <Windows.ui.core.h> +#include <Windows.ApplicationModel.core.h> + +using namespace ABI::Windows::ApplicationModel::Core; +using namespace ABI::Windows::UI::Core; +using namespace ABI::Windows::Foundation; +using namespace Microsoft::WRL; + +QT_BEGIN_NAMESPACE + +QWinRTEventDispatcher::QWinRTEventDispatcher(ICoreDispatcher *dispatcher, QObject *parent) + : QEventDispatcherWinRT(parent) + , m_dispatcher(dispatcher) + , m_interrupt(false) +{ +} + +bool QWinRTEventDispatcher::hasPendingEvents() +{ + return QEventDispatcherWinRT::hasPendingEvents() || QWindowSystemInterface::windowSystemEventsQueued(); +} + +void QWinRTEventDispatcher::interrupt() +{ + m_interrupt = true; +} + +bool QWinRTEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) +{ + bool canWait = flags & QEventLoop::WaitForMoreEvents; + bool didProcess; + m_interrupt = false; + do { + // Send Qt events + didProcess = QEventDispatcherWinRT::processEvents(flags); + + // Process system events + emit aboutToBlock(); + if (m_dispatcher) + m_dispatcher->ProcessEvents(CoreProcessEventsOption_ProcessAllIfPresent); + emit awake(); + + // Dispatch accumulated user events + didProcess |= QWindowSystemInterface::sendWindowSystemEvents(flags); + canWait = canWait && !didProcess && !m_interrupt; + + // Short sleep if there is nothing to do + if (canWait) { + emit aboutToBlock(); + WaitForSingleObjectEx(GetCurrentThread(), 1, true); + emit awake(); + } + } while (canWait); + return didProcess; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/qeglfscompositor.h b/src/plugins/platforms/winrt/qwinrteventdispatcher.h index 0d5daafa2c..741007c7fa 100644 --- a/src/plugins/platforms/eglfs/qeglfscompositor.h +++ b/src/plugins/platforms/winrt/qwinrteventdispatcher.h @@ -39,47 +39,43 @@ ** ****************************************************************************/ -#ifndef QEGLFSCOMPOSITOR_H -#define QEGLFSCOMPOSITOR_H +#ifndef QWINRTEVENTDISPATCHER_H +#define QWINRTEVENTDISPATCHER_H -#include <QtCore/QTimer> -#include <QtGui/QOpenGLFunctions> +#include <QtCore/private/qeventdispatcher_winrt_p.h> -QT_BEGIN_NAMESPACE +#include <wrl.h> + +namespace ABI { + namespace Windows { + namespace UI { + namespace Core { + struct ICoreDispatcher; + } + } + } +} -class QEglFSScreen; -class QEglFSWindow; -class QOpenGLShaderProgram; +QT_BEGIN_NAMESPACE -class QEglFSCompositor : public QObject, public QOpenGLFunctions +class QWinRTEventDispatcher : public QEventDispatcherWinRT { Q_OBJECT - public: - void schedule(QEglFSScreen *screen); - - static QEglFSCompositor *instance(); - static void destroy(); + explicit QWinRTEventDispatcher(ABI::Windows::UI::Core::ICoreDispatcher *dispatcher, QObject *parent = 0); -private slots: - void renderAll(); +protected: + void interrupt(); + bool hasPendingEvents(); + bool processEvents(QEventLoop::ProcessEventsFlags flags); private: - QEglFSCompositor(); - ~QEglFSCompositor(); - - void render(QEglFSWindow *window, uint texture, bool raster); - void ensureProgram(); + Microsoft::WRL::ComPtr<ABI::Windows::UI::Core::ICoreDispatcher> m_dispatcher; + bool m_interrupt; - QEglFSScreen *m_screen; - QTimer m_updateTimer; - QOpenGLShaderProgram *m_program; - int m_vertexCoordEntry; - int m_textureCoordEntry; - int m_isRasterEntry; - bool m_initialized; + friend class QWinRTIntegration; }; QT_END_NAMESPACE -#endif // QEGLFSCOMPOSITOR_H +#endif // QWINRTEVENTDISPATCHER_H diff --git a/src/plugins/platforms/winrt/qwinrtfontdatabase.cpp b/src/plugins/platforms/winrt/qwinrtfontdatabase.cpp new file mode 100644 index 0000000000..c7fa339fad --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrtfontdatabase.cpp @@ -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$ +** +****************************************************************************/ + +#include "qwinrtfontdatabase.h" + +#include <QtCore/QCoreApplication> +#include <QtCore/QFile> + +QT_BEGIN_NAMESPACE + +QString QWinRTFontDatabase::fontDir() const +{ + QString fontDirectory = QBasicFontDatabase::fontDir(); + if (!QFile::exists(fontDirectory)) { + // Fall back to app directory + fonts, and just app directory after that + const QString applicationDirPath = QCoreApplication::applicationDirPath(); + fontDirectory = applicationDirPath + QLatin1String("/fonts"); + if (!QFile::exists(fontDirectory)) { + qWarning("No fonts directory found in application package."); + fontDirectory = applicationDirPath; + } + } + return fontDirectory; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/src/opengl/qandroidopenglplatformscreen.h b/src/plugins/platforms/winrt/qwinrtfontdatabase.h index e9251592aa..49e32470c2 100644 --- a/src/plugins/platforms/android/src/opengl/qandroidopenglplatformscreen.h +++ b/src/plugins/platforms/winrt/qwinrtfontdatabase.h @@ -39,22 +39,19 @@ ** ****************************************************************************/ -#ifndef QANDROIDOPENGLPLATFORMSCREEN_H -#define QANDROIDOPENGLPLATFORMSCREEN_H +#ifndef QWINRTFONTDATABASE_H +#define QWINRTFONTDATABASE_H -#include "qeglfsscreen.h" +#include <QtPlatformSupport/private/qbasicfontdatabase_p.h> QT_BEGIN_NAMESPACE -class QAndroidOpenGLPlatformScreen : public QEglFSScreen +class QWinRTFontDatabase : public QBasicFontDatabase { public: - QAndroidOpenGLPlatformScreen(EGLDisplay display); - -protected: - void topWindowChanged(QPlatformWindow *window); + QString fontDir() const; }; QT_END_NAMESPACE -#endif // QANDROIDOPENGLPLATFORMSCREEN_H +#endif // QWINRTFONTDATABASE_H diff --git a/src/plugins/platforms/winrt/qwinrtinputcontext.cpp b/src/plugins/platforms/winrt/qwinrtinputcontext.cpp new file mode 100644 index 0000000000..bc15f1e448 --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrtinputcontext.cpp @@ -0,0 +1,300 @@ +/**************************************************************************** +** +** 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 "qwinrtinputcontext.h" +#include <QtGui/QWindow> + +#include <wrl.h> +#include <roapi.h> +#include <windows.ui.viewmanagement.h> +#include <windows.ui.core.h> +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::UI::ViewManagement; +using namespace ABI::Windows::UI::Core; + +#ifdef Q_OS_WINPHONE +#include <windows.phone.ui.core.h> +using namespace ABI::Windows::Phone::UI::Core; +#endif + +typedef ITypedEventHandler<InputPane*, InputPaneVisibilityEventArgs*> InputPaneVisibilityHandler; + +QT_BEGIN_NAMESPACE + +/*! + \class QWinRTInputContext + \brief Manages Input Method visibility + \internal + \ingroup qt-qpa-winrt + + Listens to the native virtual keyboard for hide/show events and provides + hints to the OS for showing/hiding. On WinRT, showInputPanel()/hideInputPanel() + have no effect because WinRT dictates that keyboard presence is user-driven: + (http://msdn.microsoft.com/en-us/library/windows/apps/hh465404.aspx) + Windows Phone, however, supports direct hiding/showing of the keyboard. +*/ + +QWinRTInputContext::QWinRTInputContext(ICoreWindow *window) + : m_window(window) +{ + IInputPaneStatics *statics; + if (FAILED(GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_InputPane).Get(), + &statics))) { + qWarning(Q_FUNC_INFO ": failed to retrieve input pane statics."); + return; + } + + IInputPane *inputPane; + statics->GetForCurrentView(&inputPane); + statics->Release(); + if (inputPane) { + EventRegistrationToken showToken, hideToken; + inputPane->add_Showing(Callback<InputPaneVisibilityHandler>( + this, &QWinRTInputContext::onShowing).Get(), &showToken); + inputPane->add_Hiding(Callback<InputPaneVisibilityHandler>( + this, &QWinRTInputContext::onHiding).Get(), &hideToken); + + Rect rect; + inputPane->get_OccludedRect(&rect); + m_keyboardRect = QRectF(rect.X, rect.Y, rect.Width, rect.Height); + m_isInputPanelVisible = !m_keyboardRect.isEmpty(); + } else { + qWarning(Q_FUNC_INFO ": failed to retrieve InputPane."); + } +} + +QRectF QWinRTInputContext::keyboardRect() const +{ + return m_keyboardRect; +} + +bool QWinRTInputContext::isInputPanelVisible() const +{ + return m_isInputPanelVisible; +} + +HRESULT QWinRTInputContext::onShowing(IInputPane *pane, IInputPaneVisibilityEventArgs *) +{ + m_isInputPanelVisible = true; + emitInputPanelVisibleChanged(); + + Rect rect; + pane->get_OccludedRect(&rect); + setKeyboardRect(QRectF(rect.X, rect.Y, rect.Width, rect.Height)); + + return S_OK; +} + +HRESULT QWinRTInputContext::onHiding(IInputPane *pane, IInputPaneVisibilityEventArgs *) +{ + m_isInputPanelVisible = false; + emitInputPanelVisibleChanged(); + + Rect rect; + pane->get_OccludedRect(&rect); + setKeyboardRect(QRectF(rect.X, rect.Y, rect.Width, rect.Height)); + + return S_OK; +} + +void QWinRTInputContext::setKeyboardRect(const QRectF rect) +{ + if (m_keyboardRect == rect) + return; + + m_keyboardRect = rect; + emitKeyboardRectChanged(); +} + +#ifdef Q_OS_WINPHONE + +void QWinRTInputContext::showInputPanel() +{ + ICoreWindowKeyboardInput *input; + if (SUCCEEDED(m_window->QueryInterface(IID_PPV_ARGS(&input)))) { + input->put_IsKeyboardInputEnabled(true); + input->Release(); + } +} + +void QWinRTInputContext::hideInputPanel() +{ + ICoreWindowKeyboardInput *input; + if (SUCCEEDED(m_window->QueryInterface(IID_PPV_ARGS(&input)))) { + input->put_IsKeyboardInputEnabled(false); + input->Release(); + } +} + +#else // Q_OS_WINPHONE + +// IRawElementProviderSimple +HRESULT QWinRTInputContext::get_ProviderOptions(ProviderOptions *retVal) +{ + *retVal = ProviderOptions_ServerSideProvider|ProviderOptions_UseComThreading; + return S_OK; +} + +HRESULT QWinRTInputContext::GetPatternProvider(PATTERNID id, IUnknown **retVal) +{ + switch (id) { + case 10002: //UIA_ValuePatternId + return QueryInterface(__uuidof(IValueProvider), (void**)retVal); + break; + case 10014: //UIA_TextPatternId: + return QueryInterface(__uuidof(ITextProvider), (void**)retVal); + case 10029: //UIA_TextChildPatternId: + *retVal = nullptr; + break; + default: + qWarning("Unhandled pattern ID: %d", id); + break; + } + return S_OK; +} + +HRESULT QWinRTInputContext::GetPropertyValue(PROPERTYID idProp, VARIANT *retVal) +{ + switch (idProp) { + case 30003: //UIA_ControlTypePropertyId + retVal->vt = VT_I4; + retVal->lVal = 50025; //UIA_CustomControlTypeId + break; + case 30008: //UIA_IsKeyboardFocusablePropertyId + case 30009: //UIA_HasKeyboardFocusPropertyId + // These are probably never actually called + case 30016: //UIA_IsControlElementPropertyId + case 30017: //UIA_IsContentElementPropertyId + retVal->vt = VT_BOOL; + retVal->boolVal = VARIANT_TRUE; + break; + case 30019: //UIA_IsPasswordPropertyId + retVal->vt = VT_BOOL; + retVal->boolVal = VARIANT_FALSE; + break; + case 30020: //UIA_NativeWindowHandlePropertyId + retVal->vt = VT_PTR; + retVal->punkVal = m_window; + break; + } + return S_OK; +} + +HRESULT QWinRTInputContext::get_HostRawElementProvider(IRawElementProviderSimple **retVal) +{ + // Return the window's element provider + IInspectable *hostProvider; + HRESULT hr = m_window->get_AutomationHostProvider(&hostProvider); + if (SUCCEEDED(hr)) { + hr = hostProvider->QueryInterface(IID_PPV_ARGS(retVal)); + hostProvider->Release(); + } + return hr; +} + +// ITextProvider +HRESULT QWinRTInputContext::GetSelection(SAFEARRAY **) +{ + // To be useful, requires listening to the focus object for a selection change and raising an event + return S_OK; +} + +HRESULT QWinRTInputContext::GetVisibleRanges(SAFEARRAY **) +{ + // To be useful, requires listening to the focus object for a selection change and raising an event + return S_OK; +} + +HRESULT QWinRTInputContext::RangeFromChild(IRawElementProviderSimple *,ITextRangeProvider **) +{ + // To be useful, requires listening to the focus object for a selection change and raising an event + return S_OK; +} + +HRESULT QWinRTInputContext::RangeFromPoint(UiaPoint, ITextRangeProvider **) +{ + // To be useful, requires listening to the focus object for a selection change and raising an event + return S_OK; +} + +HRESULT QWinRTInputContext::get_DocumentRange(ITextRangeProvider **) +{ + // To be useful, requires listening to the focus object for a selection change and raising an event + return S_OK; +} + +HRESULT QWinRTInputContext::get_SupportedTextSelection(SupportedTextSelection *) +{ + // To be useful, requires listening to the focus object for a selection change and raising an event + return S_OK; +} + +// IValueProvider +HRESULT QWinRTInputContext::SetValue(LPCWSTR) +{ + // To be useful, requires listening to the focus object for a value change and raising an event + // May be useful for inputPanel autocomplete, etc. + return S_OK; +} + +HRESULT QWinRTInputContext::get_Value(BSTR *) +{ + // To be useful, requires listening to the focus object for a value change and raising an event + // May be useful for inputPanel autocomplete, etc. + return S_OK; +} + +HRESULT QWinRTInputContext::get_IsReadOnly(BOOL *isReadOnly) +{ + // isReadOnly dictates keyboard opening behavior when view is tapped. + // We need to decide if the user tapped within a control which is about to receive focus... + // Since this isn't possible (this function gets called before we receive the touch event), + // the most platform-aligned option is to show the keyboard if an editable item has focus, + // and close the keyboard if it is already open. + *isReadOnly = m_isInputPanelVisible || !inputMethodAccepted(); + return S_OK; +} + +#endif // !Q_OS_WINPHONE + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtinputcontext.h b/src/plugins/platforms/winrt/qwinrtinputcontext.h new file mode 100644 index 0000000000..0a35f9b6e1 --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrtinputcontext.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** 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 QWINRTINPUTCONTEXT_H +#define QWINRTINPUTCONTEXT_H + +#include <qpa/qplatforminputcontext.h> +#include <QtCore/QRectF> + +#include <wrl.h> +#ifndef Q_OS_WINPHONE +# include <UIAutomationCore.h> +#endif + +namespace ABI { + namespace Windows { + namespace UI { + namespace Core { + struct ICoreWindow; + } + namespace ViewManagement { + struct IInputPane; + struct IInputPaneVisibilityEventArgs; + } + } + } +} + +QT_BEGIN_NAMESPACE + +class QWinRTInputContext : public QPlatformInputContext +#ifndef Q_OS_WINPHONE + , public Microsoft::WRL::RuntimeClass< + Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::WinRtClassicComMix>, + IRawElementProviderSimple, ITextProvider, IValueProvider> +#endif // !Q_OS_WINPHONE +{ +public: + explicit QWinRTInputContext(ABI::Windows::UI::Core::ICoreWindow *window); + + QRectF keyboardRect() const; + + bool isInputPanelVisible() const; + +#ifdef Q_OS_WINPHONE + void showInputPanel(); + void hideInputPanel(); +#else // Q_OS_WINPHONE + // IRawElementProviderSimple + HRESULT __stdcall get_ProviderOptions(ProviderOptions *retVal); + HRESULT __stdcall GetPatternProvider(PATTERNID, IUnknown **); + HRESULT __stdcall GetPropertyValue(PROPERTYID idProp, VARIANT *retVal); + HRESULT __stdcall get_HostRawElementProvider(IRawElementProviderSimple **retVal); + + // ITextProvider + HRESULT __stdcall GetSelection(SAFEARRAY **); + HRESULT __stdcall GetVisibleRanges(SAFEARRAY **); + HRESULT __stdcall RangeFromChild(IRawElementProviderSimple *,ITextRangeProvider **); + HRESULT __stdcall RangeFromPoint(UiaPoint, ITextRangeProvider **); + HRESULT __stdcall get_DocumentRange(ITextRangeProvider **); + HRESULT __stdcall get_SupportedTextSelection(SupportedTextSelection *); + + // IValueProvider + HRESULT __stdcall SetValue(LPCWSTR); + HRESULT __stdcall get_Value(BSTR *); + HRESULT __stdcall get_IsReadOnly(BOOL *); +#endif // !Q_OS_WINPHONE + +private: + HRESULT onShowing(ABI::Windows::UI::ViewManagement::IInputPane *, + ABI::Windows::UI::ViewManagement::IInputPaneVisibilityEventArgs *); + HRESULT onHiding(ABI::Windows::UI::ViewManagement::IInputPane *, + ABI::Windows::UI::ViewManagement::IInputPaneVisibilityEventArgs *); + void setKeyboardRect(const QRectF rect); + + ABI::Windows::UI::Core::ICoreWindow *m_window; + QRectF m_keyboardRect; + bool m_isInputPanelVisible; +}; + +QT_END_NAMESPACE + +#endif // QWINRTINPUTCONTEXT_H diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp new file mode 100644 index 0000000000..22c50e67f3 --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp @@ -0,0 +1,194 @@ +/**************************************************************************** +** +** 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 "qwinrtintegration.h" +#include "qwinrtwindow.h" +#include "qwinrteventdispatcher.h" +#include "qwinrtbackingstore.h" +#include "qwinrtscreen.h" +#include "qwinrtinputcontext.h" +#include "qwinrtservices.h" +#include "qwinrteglcontext.h" +#include "qwinrtfontdatabase.h" + +#include <QtGui/QOpenGLContext> + +#include <wrl.h> +#include <windows.ui.core.h> +#include <windows.ui.viewmanagement.h> +#include <Windows.ApplicationModel.core.h> + +using namespace Microsoft::WRL; +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::UI::Core; +using namespace ABI::Windows::UI::ViewManagement; +using namespace ABI::Windows::ApplicationModel::Core; + +static IUISettings *getSettings() +{ + static IUISettings *settings = 0; + if (!settings) { + if (FAILED(RoActivateInstance(Wrappers::HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_UISettings).Get(), + reinterpret_cast<IInspectable **>(&settings)))) { + qWarning("Could not activate UISettings."); + } + } + return settings; +} + +QT_BEGIN_NAMESPACE + +QWinRTIntegration::QWinRTIntegration() + : m_success(false) + , m_fontDatabase(new QWinRTFontDatabase) + , m_services(new QWinRTServices) +{ + // Obtain the WinRT Application, view, and window + ICoreApplication *application; + if (FAILED(RoGetActivationFactory(Wrappers::HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(), + IID_PPV_ARGS(&application)))) + qCritical("Could not attach to the application factory."); + + ICoreApplicationView *view; + if (FAILED(application->GetCurrentView(&view))) { + qCritical("Could not obtain the application view - have you started outside of WinRT?"); + return; + } + + // Get core window (will act as our screen) + ICoreWindow *window; + if (FAILED(view->get_CoreWindow(&window))) { + qCritical("Could not obtain the application window - have you started outside of WinRT?"); + return; + } + window->Activate(); + m_screen = new QWinRTScreen(window); + screenAdded(m_screen); + + m_success = true; +} + +QWinRTIntegration::~QWinRTIntegration() +{ + Windows::Foundation::Uninitialize(); +} + +QAbstractEventDispatcher *QWinRTIntegration::createEventDispatcher() const +{ + ICoreDispatcher *dispatcher; + if (FAILED(m_screen->coreWindow()->get_Dispatcher(&dispatcher))) + qCritical("Could not capture UI Dispatcher"); + return new QWinRTEventDispatcher(dispatcher); +} + +bool QWinRTIntegration::hasCapability(QPlatformIntegration::Capability cap) const +{ + switch (cap) { + case ThreadedPixmaps: + case OpenGL: + case ApplicationState: + return true; + default: + return QPlatformIntegration::hasCapability(cap); + } +} + +QVariant QWinRTIntegration::styleHint(StyleHint hint) const +{ + switch (hint) { + case CursorFlashTime: + if (IUISettings *settings = getSettings()) { + quint32 blinkRate; + settings->get_CaretBlinkRate(&blinkRate); + return blinkRate; + } + break; + case MouseDoubleClickInterval: + if (IUISettings *settings = getSettings()) { + quint32 doubleClickTime; + settings->get_DoubleClickTime(&doubleClickTime); + return doubleClickTime; + } + case ShowIsFullScreen: + return true; + default: + break; + } + return QPlatformIntegration::styleHint(hint); +} + +QPlatformWindow *QWinRTIntegration::createPlatformWindow(QWindow *window) const +{ + return new QWinRTWindow(window); +} + +QPlatformBackingStore *QWinRTIntegration::createPlatformBackingStore(QWindow *window) const +{ + return new QWinRTBackingStore(window); +} + +QPlatformOpenGLContext *QWinRTIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const +{ + QWinRTScreen *screen = static_cast<QWinRTScreen *>(context->screen()->handle()); + return new QWinRTEGLContext(context->format(), context->handle(), screen->eglDisplay(), screen->eglSurface()); +} + +QPlatformFontDatabase *QWinRTIntegration::fontDatabase() const +{ + return m_fontDatabase; +} + +QPlatformInputContext *QWinRTIntegration::inputContext() const +{ + return m_screen->inputContext(); +} + +QPlatformServices *QWinRTIntegration::services() const +{ + return m_services; +} + +Qt::KeyboardModifiers QWinRTIntegration::queryKeyboardModifiers() const +{ + return m_screen->keyboardModifiers(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtintegration.h b/src/plugins/platforms/winrt/qwinrtintegration.h new file mode 100644 index 0000000000..d9438bcb3a --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrtintegration.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** 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 QWINRTINTEGRATION_H +#define QWINRTINTEGRATION_H + +#include <qpa/qplatformintegration.h> + +QT_BEGIN_NAMESPACE + +class QAbstractEventDispatcher; +class QWinRTScreen; + +class QWinRTIntegration : public QPlatformIntegration +{ +private: + explicit QWinRTIntegration(); +public: + ~QWinRTIntegration(); + + static QWinRTIntegration *create() + { + QWinRTIntegration *integration = new QWinRTIntegration; + return integration->m_success ? integration : 0; + } + + bool hasCapability(QPlatformIntegration::Capability cap) const; + QVariant styleHint(StyleHint hint) const; + + QPlatformWindow *createPlatformWindow(QWindow *window) const; + QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; + QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; + QAbstractEventDispatcher *createEventDispatcher() const; + QPlatformFontDatabase *fontDatabase() const; + QPlatformInputContext *inputContext() const; + QPlatformServices *services() const; + Qt::KeyboardModifiers queryKeyboardModifiers() const; + +private: + bool m_success; + QWinRTScreen *m_screen; + QPlatformFontDatabase *m_fontDatabase; + QPlatformServices *m_services; +}; + +QT_END_NAMESPACE + +#endif // QWINRTINTEGRATION_H diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp new file mode 100644 index 0000000000..911d3619fe --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -0,0 +1,975 @@ +/**************************************************************************** +** +** 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 "qwinrtscreen.h" + +#include "qwinrtbackingstore.h" +#include "qwinrtinputcontext.h" +#include "qwinrtcursor.h" +#include "qwinrteglcontext.h" + +#include <QtGui/QSurfaceFormat> +#include <QtGui/QGuiApplication> +#include <QtPlatformSupport/private/qeglconvenience_p.h> +#include <qpa/qwindowsysteminterface.h> +#include <QtCore/qt_windows.h> + +#include <wrl.h> +#include <windows.system.h> +#include <windows.devices.input.h> +#include <windows.ui.h> +#include <windows.ui.core.h> +#include <windows.ui.input.h> +#include <windows.ui.viewmanagement.h> +#include <windows.graphics.display.h> +#include <windows.foundation.h> + +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::System; +using namespace ABI::Windows::UI::Core; +using namespace ABI::Windows::UI::Input; +using namespace ABI::Windows::UI::ViewManagement; +using namespace ABI::Windows::Devices::Input; +using namespace ABI::Windows::Graphics::Display; + +typedef ITypedEventHandler<CoreWindow*, WindowActivatedEventArgs*> ActivatedHandler; +typedef ITypedEventHandler<CoreWindow*, CoreWindowEventArgs*> ClosedHandler; +typedef ITypedEventHandler<CoreWindow*, CharacterReceivedEventArgs*> CharacterReceivedHandler; +typedef ITypedEventHandler<CoreWindow*, InputEnabledEventArgs*> InputEnabledHandler; +typedef ITypedEventHandler<CoreWindow*, KeyEventArgs*> KeyHandler; +typedef ITypedEventHandler<CoreWindow*, PointerEventArgs*> PointerHandler; +typedef ITypedEventHandler<CoreWindow*, WindowSizeChangedEventArgs*> SizeChangedHandler; +typedef ITypedEventHandler<CoreWindow*, VisibilityChangedEventArgs*> VisibilityChangedHandler; +typedef ITypedEventHandler<CoreWindow*, AutomationProviderRequestedEventArgs*> AutomationProviderRequestedHandler; + +QT_BEGIN_NAMESPACE + +static inline Qt::ScreenOrientations qtOrientationsFromNative(DisplayOrientations native) +{ + Qt::ScreenOrientations orientations = Qt::PrimaryOrientation; + if (native & DisplayOrientations_Portrait) + orientations |= Qt::PortraitOrientation; + if (native & DisplayOrientations_PortraitFlipped) + orientations |= Qt::InvertedPortraitOrientation; + if (native & DisplayOrientations_Landscape) + orientations |= Qt::LandscapeOrientation; + if (native & DisplayOrientations_LandscapeFlipped) + orientations |= Qt::InvertedLandscapeOrientation; + return orientations; +} + +static inline DisplayOrientations nativeOrientationsFromQt(Qt::ScreenOrientations orientation) +{ + DisplayOrientations native = DisplayOrientations_None; + if (orientation & Qt::PortraitOrientation) + native |= DisplayOrientations_Portrait; + if (orientation & Qt::InvertedPortraitOrientation) + native |= DisplayOrientations_PortraitFlipped; + if (orientation & Qt::LandscapeOrientation) + native |= DisplayOrientations_Landscape; + if (orientation & Qt::InvertedLandscapeOrientation) + native |= DisplayOrientations_LandscapeFlipped; + return native; +} + +static inline bool qIsNonPrintable(quint32 keyCode) +{ + switch (keyCode) { + case '\b': + case '\n': + case '\t': + case '\r': + case '\v': + case '\f': + return true; + default: + return false; + } +} + +// Return Qt meta key from VirtualKey +static inline Qt::Key qKeyFromVirtual(VirtualKey key) +{ + switch (key) { + + default: + return Qt::Key_unknown; + + // Non-printable characters + case VirtualKey_Enter: + return Qt::Key_Enter; + case VirtualKey_Tab: + return Qt::Key_Tab; + case VirtualKey_Back: + return Qt::Key_Backspace; + + // Modifiers + case VirtualKey_Shift: + case VirtualKey_LeftShift: + case VirtualKey_RightShift: + return Qt::Key_Shift; + case VirtualKey_Control: + case VirtualKey_LeftControl: + case VirtualKey_RightControl: + return Qt::Key_Control; + case VirtualKey_Menu: + case VirtualKey_LeftMenu: + case VirtualKey_RightMenu: + return Qt::Key_Alt; + case VirtualKey_LeftWindows: + case VirtualKey_RightWindows: + return Qt::Key_Meta; + + // Toggle keys + case VirtualKey_CapitalLock: + return Qt::Key_CapsLock; + case VirtualKey_NumberKeyLock: + return Qt::Key_NumLock; + case VirtualKey_Scroll: + return Qt::Key_ScrollLock; + + // East-Asian language keys + case VirtualKey_Kana: + //case VirtualKey_Hangul: // Same enum as Kana + return Qt::Key_Kana_Shift; + case VirtualKey_Junja: + return Qt::Key_Hangul_Jeonja; + case VirtualKey_Kanji: + //case VirtualKey_Hanja: // Same enum as Kanji + return Qt::Key_Kanji; + case VirtualKey_ModeChange: + return Qt::Key_Mode_switch; + case VirtualKey_Convert: + return Qt::Key_Henkan; + case VirtualKey_NonConvert: + return Qt::Key_Muhenkan; + + // Misc. keys + case VirtualKey_Cancel: + return Qt::Key_Cancel; + case VirtualKey_Clear: + return Qt::Key_Clear; + case VirtualKey_Application: + return Qt::Key_ApplicationLeft; + case VirtualKey_Sleep: + return Qt::Key_Sleep; + case VirtualKey_Pause: + return Qt::Key_Pause; + case VirtualKey_PageUp: + return Qt::Key_PageUp; + case VirtualKey_PageDown: + return Qt::Key_PageDown; + case VirtualKey_End: + return Qt::Key_End; + case VirtualKey_Home: + return Qt::Key_Home; + case VirtualKey_Left: + return Qt::Key_Left; + case VirtualKey_Up: + return Qt::Key_Up; + case VirtualKey_Right: + return Qt::Key_Right; + case VirtualKey_Down: + return Qt::Key_Down; + case VirtualKey_Select: + return Qt::Key_Select; + case VirtualKey_Print: + return Qt::Key_Print; + case VirtualKey_Execute: + return Qt::Key_Execute; + case VirtualKey_Insert: + return Qt::Key_Insert; + case VirtualKey_Delete: + return Qt::Key_Delete; + case VirtualKey_Help: + return Qt::Key_Help; + case VirtualKey_Snapshot: + return Qt::Key_Camera; + case VirtualKey_Escape: + return Qt::Key_Escape; + + // Function Keys + case VirtualKey_F1: + return Qt::Key_F1; + case VirtualKey_F2: + return Qt::Key_F2; + case VirtualKey_F3: + return Qt::Key_F3; + case VirtualKey_F4: + return Qt::Key_F4; + case VirtualKey_F5: + return Qt::Key_F5; + case VirtualKey_F6: + return Qt::Key_F6; + case VirtualKey_F7: + return Qt::Key_F7; + case VirtualKey_F8: + return Qt::Key_F8; + case VirtualKey_F9: + return Qt::Key_F9; + case VirtualKey_F10: + return Qt::Key_F10; + case VirtualKey_F11: + return Qt::Key_F11; + case VirtualKey_F12: + return Qt::Key_F12; + case VirtualKey_F13: + return Qt::Key_F13; + case VirtualKey_F14: + return Qt::Key_F14; + case VirtualKey_F15: + return Qt::Key_F15; + case VirtualKey_F16: + return Qt::Key_F16; + case VirtualKey_F17: + return Qt::Key_F17; + case VirtualKey_F18: + return Qt::Key_F18; + case VirtualKey_F19: + return Qt::Key_F19; + case VirtualKey_F20: + return Qt::Key_F20; + case VirtualKey_F21: + return Qt::Key_F21; + case VirtualKey_F22: + return Qt::Key_F22; + case VirtualKey_F23: + return Qt::Key_F23; + case VirtualKey_F24: + return Qt::Key_F24; + + // Character keys + case VirtualKey_Space: + return Qt::Key_Space; + case VirtualKey_Number0: + case VirtualKey_NumberPad0: + return Qt::Key_0; + case VirtualKey_Number1: + case VirtualKey_NumberPad1: + return Qt::Key_1; + case VirtualKey_Number2: + case VirtualKey_NumberPad2: + return Qt::Key_2; + case VirtualKey_Number3: + case VirtualKey_NumberPad3: + return Qt::Key_3; + case VirtualKey_Number4: + case VirtualKey_NumberPad4: + return Qt::Key_4; + case VirtualKey_Number5: + case VirtualKey_NumberPad5: + return Qt::Key_5; + case VirtualKey_Number6: + case VirtualKey_NumberPad6: + return Qt::Key_6; + case VirtualKey_Number7: + case VirtualKey_NumberPad7: + return Qt::Key_7; + case VirtualKey_Number8: + case VirtualKey_NumberPad8: + return Qt::Key_8; + case VirtualKey_Number9: + case VirtualKey_NumberPad9: + return Qt::Key_9; + case VirtualKey_A: + return Qt::Key_A; + case VirtualKey_B: + return Qt::Key_B; + case VirtualKey_C: + return Qt::Key_C; + case VirtualKey_D: + return Qt::Key_D; + case VirtualKey_E: + return Qt::Key_E; + case VirtualKey_F: + return Qt::Key_F; + case VirtualKey_G: + return Qt::Key_G; + case VirtualKey_H: + return Qt::Key_H; + case VirtualKey_I: + return Qt::Key_I; + case VirtualKey_J: + return Qt::Key_J; + case VirtualKey_K: + return Qt::Key_K; + case VirtualKey_L: + return Qt::Key_L; + case VirtualKey_M: + return Qt::Key_M; + case VirtualKey_N: + return Qt::Key_N; + case VirtualKey_O: + return Qt::Key_O; + case VirtualKey_P: + return Qt::Key_P; + case VirtualKey_Q: + return Qt::Key_Q; + case VirtualKey_R: + return Qt::Key_R; + case VirtualKey_S: + return Qt::Key_S; + case VirtualKey_T: + return Qt::Key_T; + case VirtualKey_U: + return Qt::Key_U; + case VirtualKey_V: + return Qt::Key_V; + case VirtualKey_W: + return Qt::Key_W; + case VirtualKey_X: + return Qt::Key_X; + case VirtualKey_Y: + return Qt::Key_Y; + case VirtualKey_Z: + return Qt::Key_Z; + case VirtualKey_Multiply: + return Qt::Key_9; + case VirtualKey_Add: + return Qt::Key_9; + case VirtualKey_Separator: + return Qt::Key_9; + case VirtualKey_Subtract: + return Qt::Key_9; + case VirtualKey_Decimal: + return Qt::Key_9; + case VirtualKey_Divide: + return Qt::Key_9; + + /* Keys with no matching Qt enum (?) + case VirtualKey_None: + case VirtualKey_LeftButton: + case VirtualKey_RightButton: + case VirtualKey_MiddleButton: + case VirtualKey_XButton1: + case VirtualKey_XButton2: + case VirtualKey_Final: + case VirtualKey_Accept:*/ + } +} + +static inline Qt::Key qKeyFromCode(quint32 code, int mods) +{ + if (code >= 'a' && code <= 'z') + code = toupper(code); + if ((mods & Qt::ControlModifier) != 0) { + if (code >= 0 && code <= 31) // Ctrl+@..Ctrl+A..CTRL+Z..Ctrl+_ + code += '@'; // to @..A..Z.._ + } + return static_cast<Qt::Key>(code & 0xff); +} + +QWinRTScreen::QWinRTScreen(ICoreWindow *window) + : m_coreWindow(window) + , m_depth(32) + , m_format(QImage::Format_ARGB32_Premultiplied) +#ifdef Q_OS_WINPHONE + , m_inputContext(new QWinRTInputContext(m_coreWindow)) +#else + , m_inputContext(Make<QWinRTInputContext>(m_coreWindow).Detach()) +#endif + , m_cursor(new QWinRTCursor(window)) + , m_orientation(Qt::PrimaryOrientation) +{ +#ifdef Q_OS_WINPHONE // On phone, there can be only one touch device + QTouchDevice *touchDevice = new QTouchDevice; + touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure); + touchDevice->setType(QTouchDevice::TouchScreen); + touchDevice->setName(QStringLiteral("WinPhoneTouchScreen")); + Pointer pointer = { Pointer::TouchScreen, touchDevice }; + m_pointers.insert(0, pointer); + QWindowSystemInterface::registerTouchDevice(touchDevice); +#endif + + Rect rect; + window->get_Bounds(&rect); + m_geometry = QRect(0, 0, rect.Width, rect.Height); + + m_surfaceFormat.setAlphaBufferSize(0); + m_surfaceFormat.setRedBufferSize(8); + m_surfaceFormat.setGreenBufferSize(8); + m_surfaceFormat.setBlueBufferSize(8); + + m_surfaceFormat.setRenderableType(QSurfaceFormat::OpenGLES); + m_surfaceFormat.setSamples(1); + m_surfaceFormat.setSwapBehavior(QSurfaceFormat::DoubleBuffer); + m_surfaceFormat.setDepthBufferSize(24); + m_surfaceFormat.setStencilBufferSize(8); + + m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (m_eglDisplay == EGL_NO_DISPLAY) + qFatal("Qt WinRT platform plugin: failed to initialize EGL display."); + + if (!eglInitialize(m_eglDisplay, NULL, NULL)) + qFatal("Qt WinRT platform plugin: failed to initialize EGL. This can happen if you haven't included the D3D compiler DLL in your application package."); + + // TODO: move this to Window + m_eglSurface = eglCreateWindowSurface(m_eglDisplay, q_configFromGLFormat(m_eglDisplay, m_surfaceFormat), window, NULL); + if (m_eglSurface == EGL_NO_SURFACE) + qFatal("Could not create EGL surface, error 0x%X", eglGetError()); + + // Event handlers mapped to QEvents + m_coreWindow->add_KeyDown(Callback<KeyHandler>(this, &QWinRTScreen::onKeyDown).Get(), &m_tokens[QEvent::KeyPress]); + m_coreWindow->add_KeyUp(Callback<KeyHandler>(this, &QWinRTScreen::onKeyUp).Get(), &m_tokens[QEvent::KeyRelease]); + m_coreWindow->add_CharacterReceived(Callback<CharacterReceivedHandler>(this, &QWinRTScreen::onCharacterReceived).Get(), &m_tokens[QEvent::User]); + m_coreWindow->add_PointerEntered(Callback<PointerHandler>(this, &QWinRTScreen::onPointerEntered).Get(), &m_tokens[QEvent::Enter]); + m_coreWindow->add_PointerExited(Callback<PointerHandler>(this, &QWinRTScreen::onPointerExited).Get(), &m_tokens[QEvent::Leave]); + m_coreWindow->add_PointerMoved(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &m_tokens[QEvent::MouseMove]); + m_coreWindow->add_PointerPressed(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &m_tokens[QEvent::MouseButtonPress]); + m_coreWindow->add_PointerReleased(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &m_tokens[QEvent::MouseButtonRelease]); + m_coreWindow->add_PointerWheelChanged(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &m_tokens[QEvent::Wheel]); + m_coreWindow->add_SizeChanged(Callback<SizeChangedHandler>(this, &QWinRTScreen::onSizeChanged).Get(), &m_tokens[QEvent::Resize]); + + // Window event handlers + m_coreWindow->add_Activated(Callback<ActivatedHandler>(this, &QWinRTScreen::onActivated).Get(), &m_tokens[QEvent::WindowActivate]); + m_coreWindow->add_Closed(Callback<ClosedHandler>(this, &QWinRTScreen::onClosed).Get(), &m_tokens[QEvent::WindowDeactivate]); + m_coreWindow->add_VisibilityChanged(Callback<VisibilityChangedHandler>(this, &QWinRTScreen::onVisibilityChanged).Get(), &m_tokens[QEvent::Show]); + m_coreWindow->add_AutomationProviderRequested(Callback<AutomationProviderRequestedHandler>(this, &QWinRTScreen::onAutomationProviderRequested).Get(), &m_tokens[QEvent::InputMethodQuery]); + + // Orientation handling + if (SUCCEEDED(GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Graphics_Display_DisplayProperties).Get(), + &m_displayProperties))) { + // Set native orientation + DisplayOrientations displayOrientation; + m_displayProperties->get_NativeOrientation(&displayOrientation); + m_nativeOrientation = static_cast<Qt::ScreenOrientation>(static_cast<int>(qtOrientationsFromNative(displayOrientation))); + + // Set initial orientation + onOrientationChanged(0); + + m_displayProperties->add_OrientationChanged(Callback<IDisplayPropertiesEventHandler>(this, &QWinRTScreen::onOrientationChanged).Get(), + &m_tokens[QEvent::OrientationChange]); + } + +#ifndef Q_OS_WINPHONE + GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_ApplicationView).Get(), + &m_applicationView); +#endif +} + +QRect QWinRTScreen::geometry() const +{ + return m_geometry; +} + +int QWinRTScreen::depth() const +{ + return m_depth; +} + +QImage::Format QWinRTScreen::format() const +{ + return m_format; +} + +QSurfaceFormat QWinRTScreen::surfaceFormat() const +{ + return m_surfaceFormat; +} + +QWinRTInputContext *QWinRTScreen::inputContext() const +{ + return m_inputContext; +} + +QPlatformCursor *QWinRTScreen::cursor() const +{ + return m_cursor; +} + +Qt::KeyboardModifiers QWinRTScreen::keyboardModifiers() const +{ + Qt::KeyboardModifiers mods; + CoreVirtualKeyStates mod; + m_coreWindow->GetAsyncKeyState(VirtualKey_Shift, &mod); + if (mod == CoreVirtualKeyStates_Down) + mods |= Qt::ShiftModifier; + m_coreWindow->GetAsyncKeyState(VirtualKey_Menu, &mod); + if (mod == CoreVirtualKeyStates_Down) + mods |= Qt::AltModifier; + m_coreWindow->GetAsyncKeyState(VirtualKey_Control, &mod); + if (mod == CoreVirtualKeyStates_Down) + mods |= Qt::ControlModifier; + m_coreWindow->GetAsyncKeyState(VirtualKey_LeftWindows, &mod); + if (mod == CoreVirtualKeyStates_Down) { + mods |= Qt::MetaModifier; + } else { + m_coreWindow->GetAsyncKeyState(VirtualKey_RightWindows, &mod); + if (mod == CoreVirtualKeyStates_Down) + mods |= Qt::MetaModifier; + } + return mods; +} + +Qt::ScreenOrientation QWinRTScreen::nativeOrientation() const +{ + return m_nativeOrientation; +} + +Qt::ScreenOrientation QWinRTScreen::orientation() const +{ + return m_orientation; +} + +void QWinRTScreen::setOrientationUpdateMask(Qt::ScreenOrientations mask) +{ + m_displayProperties->put_AutoRotationPreferences(nativeOrientationsFromQt(mask)); +} + +ICoreWindow *QWinRTScreen::coreWindow() const +{ + return m_coreWindow; +} + +EGLDisplay QWinRTScreen::eglDisplay() const +{ + return m_eglDisplay; +} + +EGLSurface QWinRTScreen::eglSurface() const +{ + return m_eglSurface; +} + +QWindow *QWinRTScreen::topWindow() const +{ + return m_visibleWindows.isEmpty() ? 0 : m_visibleWindows.first(); +} + +void QWinRTScreen::addWindow(QWindow *window) +{ + if (window == topWindow()) + return; + m_visibleWindows.prepend(window); + QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason); + handleExpose(); +} + +void QWinRTScreen::removeWindow(QWindow *window) +{ + const bool wasTopWindow = window == topWindow(); + if (!m_visibleWindows.removeAll(window)) + return; + if (wasTopWindow) + QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason); + handleExpose(); +} + +void QWinRTScreen::raise(QWindow *window) +{ + m_visibleWindows.removeAll(window); + addWindow(window); +} + +void QWinRTScreen::lower(QWindow *window) +{ + const bool wasTopWindow = window == topWindow(); + if (wasTopWindow && m_visibleWindows.size() == 1) + return; + m_visibleWindows.removeAll(window); + m_visibleWindows.append(window); + if (wasTopWindow) + QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason); + handleExpose(); +} + +void QWinRTScreen::handleExpose() +{ + if (m_visibleWindows.isEmpty()) + return; + QList<QWindow *>::const_iterator it = m_visibleWindows.constBegin(); + QWindowSystemInterface::handleExposeEvent(*it, m_geometry); + while (++it != m_visibleWindows.constEnd()) + QWindowSystemInterface::handleExposeEvent(*it, QRegion()); + QWindowSystemInterface::flushWindowSystemEvents(); +} + +HRESULT QWinRTScreen::onKeyDown(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IKeyEventArgs *args) +{ + Q_UNUSED(window); + VirtualKey virtualKey; + args->get_VirtualKey(&virtualKey); + Qt::Key key = qKeyFromVirtual(virtualKey); + // Defer character key presses to onCharacterReceived + if (key == Qt::Key_unknown || (key >= Qt::Key_Space && key <= Qt::Key_ydiaeresis)) + return S_OK; + QWindowSystemInterface::handleKeyEvent(topWindow(), QEvent::KeyPress, key, keyboardModifiers()); + return S_OK; +} + +HRESULT QWinRTScreen::onKeyUp(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IKeyEventArgs *args) +{ + Q_UNUSED(window); + Qt::KeyboardModifiers mods = keyboardModifiers(); +#ifndef Q_OS_WINPHONE + CorePhysicalKeyStatus status; // Look for a pressed character key + if (SUCCEEDED(args->get_KeyStatus(&status)) && m_activeKeys.contains(status.ScanCode)) { + QPair<Qt::Key, QString> keyStatus = m_activeKeys.take(status.ScanCode); + QWindowSystemInterface::handleKeyEvent(topWindow(), QEvent::KeyRelease, + keyStatus.first, mods, keyStatus.second); + return S_OK; + } +#endif // !Q_OS_WINPHONE + VirtualKey virtualKey; + args->get_VirtualKey(&virtualKey); + QWindowSystemInterface::handleKeyEvent(topWindow(), QEvent::KeyRelease, + qKeyFromVirtual(virtualKey), mods); + return S_OK; +} + +HRESULT QWinRTScreen::onCharacterReceived(ICoreWindow *window, ICharacterReceivedEventArgs *args) +{ + Q_UNUSED(window); + + quint32 keyCode; + args->get_KeyCode(&keyCode); + // Don't generate character events for non-printables; the meta key stage is enough + if (qIsNonPrintable(keyCode)) + return S_OK; + + Qt::KeyboardModifiers mods = keyboardModifiers(); + Qt::Key key = qKeyFromCode(keyCode, mods); + QString text = QChar(keyCode); + QWindowSystemInterface::handleKeyEvent(topWindow(), QEvent::KeyPress, key, mods, text); +#ifndef Q_OS_WINPHONE + CorePhysicalKeyStatus status; // Defer release to onKeyUp for physical keys + if (SUCCEEDED(args->get_KeyStatus(&status)) && !status.IsKeyReleased) { + m_activeKeys.insert(status.ScanCode, qMakePair(key, text)); + return S_OK; + } +#endif // !Q_OS_WINPHONE + QWindowSystemInterface::handleKeyEvent(topWindow(), QEvent::KeyRelease, key, mods, text); + return S_OK; +} + +HRESULT QWinRTScreen::onPointerEntered(ICoreWindow *window, IPointerEventArgs *args) +{ + Q_UNUSED(window); + IPointerPoint *pointerPoint; + if (SUCCEEDED(args->get_CurrentPoint(&pointerPoint))) { + // Assumes full-screen window + Point point; + pointerPoint->get_Position(&point); + QPoint pos(point.X, point.Y); + + QWindowSystemInterface::handleEnterEvent(topWindow(), pos, pos); + pointerPoint->Release(); + } + return S_OK; +} + +HRESULT QWinRTScreen::onPointerExited(ICoreWindow *window, IPointerEventArgs *args) +{ + Q_UNUSED(window); + Q_UNUSED(args); + QWindowSystemInterface::handleLeaveEvent(0); + return S_OK; +} + +HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *window, IPointerEventArgs *args) +{ + Q_UNUSED(window); + + IPointerPoint *pointerPoint; + if (FAILED(args->get_CurrentPoint(&pointerPoint))) + return E_INVALIDARG; + + // Common traits - point, modifiers, properties + Point point; + pointerPoint->get_Position(&point); + QPointF pos(point.X, point.Y); + + VirtualKeyModifiers modifiers; + args->get_KeyModifiers(&modifiers); + Qt::KeyboardModifiers mods; + if (modifiers & VirtualKeyModifiers_Control) + mods |= Qt::ControlModifier; + if (modifiers & VirtualKeyModifiers_Menu) + mods |= Qt::AltModifier; + if (modifiers & VirtualKeyModifiers_Shift) + mods |= Qt::ShiftModifier; + if (modifiers & VirtualKeyModifiers_Windows) + mods |= Qt::MetaModifier; + + IPointerPointProperties *properties; + if (FAILED(pointerPoint->get_Properties(&properties))) + return E_INVALIDARG; + +#ifdef Q_OS_WINPHONE + quint32 pointerId = 0; + Pointer pointer = m_pointers.value(pointerId); +#else + Pointer pointer = { Pointer::Unknown, 0 }; + quint32 pointerId; + pointerPoint->get_PointerId(&pointerId); + if (m_pointers.contains(pointerId)) { + pointer = m_pointers.value(pointerId); + } else { // We have not yet enumerated this device. Do so now... + IPointerDevice *device; + if (SUCCEEDED(pointerPoint->get_PointerDevice(&device))) { + PointerDeviceType type; + device->get_PointerDeviceType(&type); + switch (type) { + case PointerDeviceType_Touch: + pointer.type = Pointer::TouchScreen; + pointer.device = new QTouchDevice; + pointer.device->setName(QStringLiteral("WinRT TouchScreen ") + QString::number(pointerId)); + // TODO: We may want to probe the device usage flags for more accurate values for these next two + pointer.device->setType(QTouchDevice::TouchScreen); + pointer.device->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure); + QWindowSystemInterface::registerTouchDevice(pointer.device); + break; + + case PointerDeviceType_Pen: + pointer.type = Pointer::Tablet; + break; + + case PointerDeviceType_Mouse: + pointer.type = Pointer::Mouse; + break; + } + + m_pointers.insert(pointerId, pointer); + device->Release(); + } + } +#endif + switch (pointer.type) { + case Pointer::Mouse: { + qint32 delta; + properties->get_MouseWheelDelta(&delta); + if (delta) { + boolean isHorizontal; + properties->get_IsHorizontalMouseWheel(&isHorizontal); + QPoint angleDelta(isHorizontal ? delta : 0, isHorizontal ? 0 : delta); + QWindowSystemInterface::handleWheelEvent(topWindow(), pos, pos, QPoint(), angleDelta, mods); + break; + } + + boolean isPressed; + Qt::MouseButtons buttons = Qt::NoButton; + properties->get_IsLeftButtonPressed(&isPressed); + if (isPressed) + buttons |= Qt::LeftButton; + + properties->get_IsMiddleButtonPressed(&isPressed); + if (isPressed) + buttons |= Qt::MiddleButton; + + properties->get_IsRightButtonPressed(&isPressed); + if (isPressed) + buttons |= Qt::RightButton; + + properties->get_IsXButton1Pressed(&isPressed); + if (isPressed) + buttons |= Qt::XButton1; + + properties->get_IsXButton2Pressed(&isPressed); + if (isPressed) + buttons |= Qt::XButton2; + + QWindowSystemInterface::handleMouseEvent(topWindow(), pos, pos, buttons, mods); + + break; + } + case Pointer::TouchScreen: { + quint32 id; + pointerPoint->get_PointerId(&id); + + Rect area; + properties->get_ContactRect(&area); + + float pressure; + properties->get_Pressure(&pressure); + + QHash<quint32, QWindowSystemInterface::TouchPoint>::iterator it = m_touchPoints.find(id); + if (it != m_touchPoints.end()) { + boolean isPressed; +#ifndef Q_OS_WINPHONE + pointerPoint->get_IsInContact(&isPressed); +#else + properties->get_IsLeftButtonPressed(&isPressed); // IsInContact not reliable on phone +#endif + it.value().state = isPressed ? Qt::TouchPointMoved : Qt::TouchPointReleased; + } else { + it = m_touchPoints.insert(id, QWindowSystemInterface::TouchPoint()); + it.value().state = Qt::TouchPointPressed; + it.value().id = id; + } + it.value().area = QRectF(area.X, area.Y, area.Width, area.Height); + it.value().normalPosition = QPointF(pos.x()/m_geometry.width(), pos.y()/m_geometry.height()); + it.value().pressure = pressure; + + QWindowSystemInterface::handleTouchEvent(topWindow(), pointer.device, m_touchPoints.values(), mods); + + // Remove released points, station others + for (QHash<quint32, QWindowSystemInterface::TouchPoint>::iterator i = m_touchPoints.begin(); i != m_touchPoints.end();) { + if (i.value().state == Qt::TouchPointReleased) + i = m_touchPoints.erase(i); + else + (i++).value().state = Qt::TouchPointStationary; + } + + break; + } + case Pointer::Tablet: { + quint32 id; + pointerPoint->get_PointerId(&id); + + boolean isPressed; + pointerPoint->get_IsInContact(&isPressed); + + boolean isEraser; + properties->get_IsEraser(&isEraser); + int pointerType = isEraser ? 3 : 1; + + float pressure; + properties->get_Pressure(&pressure); + + float xTilt; + properties->get_XTilt(&xTilt); + + float yTilt; + properties->get_YTilt(&yTilt); + + float rotation; + properties->get_Twist(&rotation); + + QWindowSystemInterface::handleTabletEvent(topWindow(), isPressed, pos, pos, pointerId, + pointerType, pressure, xTilt, yTilt, + 0, rotation, 0, id, mods); + + break; + } + } + + properties->Release(); + pointerPoint->Release(); + + return S_OK; +} + +HRESULT QWinRTScreen::onAutomationProviderRequested(ICoreWindow *, IAutomationProviderRequestedEventArgs *args) +{ +#ifndef Q_OS_WINPHONE + args->put_AutomationProvider(m_inputContext); +#endif + return S_OK; +} + +HRESULT QWinRTScreen::onSizeChanged(ICoreWindow *window, IWindowSizeChangedEventArgs *args) +{ + Q_UNUSED(window); + + Size size; + if (FAILED(args->get_Size(&size))) { + qWarning(Q_FUNC_INFO ": failed to get size"); + return S_OK; + } + + // Regardless of state, all top-level windows are viewport-sized - this might change if + // a more advanced compositor is written. + m_geometry.setSize(QSize(size.Width, size.Height)); + QWindowSystemInterface::handleScreenGeometryChange(screen(), m_geometry); + QWindowSystemInterface::handleScreenAvailableGeometryChange(screen(), m_geometry); + QPlatformScreen::resizeMaximizedWindows(); + handleExpose(); + + return S_OK; +} + +HRESULT QWinRTScreen::onActivated(ICoreWindow *window, IWindowActivatedEventArgs *args) +{ + Q_UNUSED(window); + + CoreWindowActivationState activationState; + args->get_WindowActivationState(&activationState); + if (activationState == CoreWindowActivationState_Deactivated) { + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive); + return S_OK; + } + + // Activate topWindow + if (!m_visibleWindows.isEmpty()) { + Qt::FocusReason focusReason = activationState == CoreWindowActivationState_PointerActivated + ? Qt::MouseFocusReason : Qt::ActiveWindowFocusReason; + QWindowSystemInterface::handleWindowActivated(topWindow(), focusReason); + } + return S_OK; +} + +HRESULT QWinRTScreen::onClosed(ICoreWindow *window, ICoreWindowEventArgs *args) +{ + Q_UNUSED(window); + Q_UNUSED(args); + + foreach (QWindow *w, QGuiApplication::topLevelWindows()) + QWindowSystemInterface::handleCloseEvent(w); + return S_OK; +} + +HRESULT QWinRTScreen::onVisibilityChanged(ICoreWindow *window, IVisibilityChangedEventArgs *args) +{ + Q_UNUSED(window); + Q_UNUSED(args); + + boolean visible; + args->get_Visible(&visible); + QWindowSystemInterface::handleApplicationStateChanged(visible ? Qt::ApplicationActive : Qt::ApplicationHidden); + return S_OK; +} + +HRESULT QWinRTScreen::onOrientationChanged(IInspectable *) +{ + DisplayOrientations displayOrientation; + m_displayProperties->get_CurrentOrientation(&displayOrientation); + Qt::ScreenOrientation newOrientation = static_cast<Qt::ScreenOrientation>(static_cast<int>(qtOrientationsFromNative(displayOrientation))); + if (m_orientation != newOrientation) { + m_orientation = newOrientation; + QWindowSystemInterface::handleScreenOrientationChange(screen(), m_orientation); + } + + return S_OK; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtscreen.h b/src/plugins/platforms/winrt/qwinrtscreen.h new file mode 100644 index 0000000000..21e50fa10a --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrtscreen.h @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** 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 QWINRTSCREEN_H +#define QWINRTSCREEN_H + +#include <qpa/qplatformscreen.h> +#include <qpa/qwindowsysteminterface.h> + +#include <QtCore/QHash> +#include <QtGui/QSurfaceFormat> +#include <EGL/egl.h> + +#include <EventToken.h> + +namespace ABI { + namespace Windows { + namespace UI { + namespace Core { + struct IAutomationProviderRequestedEventArgs; + struct ICharacterReceivedEventArgs; + struct ICoreWindow; + struct ICoreWindowEventArgs; + struct IKeyEventArgs; + struct IPointerEventArgs; + struct IVisibilityChangedEventArgs; + struct IWindowActivatedEventArgs; + struct IWindowSizeChangedEventArgs; + } + namespace ViewManagement { + struct IApplicationViewStatics; + } + } + namespace Graphics { + namespace Display { + struct IDisplayPropertiesStatics; + } + } + } +} +struct IInspectable; + +QT_BEGIN_NAMESPACE + +class QTouchDevice; +class QWinRTEGLContext; +class QWinRTPageFlipper; +class QWinRTCursor; +class QWinRTInputContext; + +struct Pointer { + enum Type { Unknown, Mouse, TouchScreen, Tablet }; + Type type; + QTouchDevice *device; +}; + +class QWinRTScreen : public QPlatformScreen +{ +public: + explicit QWinRTScreen(ABI::Windows::UI::Core::ICoreWindow *window); + QRect geometry() const; + int depth() const; + QImage::Format format() const; + QSurfaceFormat surfaceFormat() const; + QWinRTInputContext *inputContext() const; + QPlatformCursor *cursor() const; + Qt::KeyboardModifiers keyboardModifiers() const; + + Qt::ScreenOrientation nativeOrientation() const; + Qt::ScreenOrientation orientation() const; + void setOrientationUpdateMask(Qt::ScreenOrientations mask); + + QWindow *topWindow() const; + void addWindow(QWindow *window); + void removeWindow(QWindow *window); + void raise(QWindow *window); + void lower(QWindow *window); + + ABI::Windows::UI::Core::ICoreWindow *coreWindow() const; + EGLDisplay eglDisplay() const; // To opengl context + EGLSurface eglSurface() const; // To window + +private: + void handleExpose(); + + // Event handlers + QHash<QEvent::Type, EventRegistrationToken> m_tokens; + + HRESULT onKeyDown(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IKeyEventArgs *args); + HRESULT onKeyUp(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IKeyEventArgs *args); + HRESULT onCharacterReceived(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::ICharacterReceivedEventArgs *args); + HRESULT onPointerEntered(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IPointerEventArgs *args); + HRESULT onPointerExited(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IPointerEventArgs *args); + HRESULT onPointerUpdated(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IPointerEventArgs *args); + HRESULT onSizeChanged(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *args); + + HRESULT onActivated(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowActivatedEventArgs *args); + HRESULT onClosed(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::ICoreWindowEventArgs *args); + HRESULT onVisibilityChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IVisibilityChangedEventArgs *args); + HRESULT onAutomationProviderRequested(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IAutomationProviderRequestedEventArgs *args); + + HRESULT onOrientationChanged(IInspectable *); + + ABI::Windows::UI::Core::ICoreWindow *m_coreWindow; + ABI::Windows::UI::ViewManagement::IApplicationViewStatics *m_applicationView; + QRect m_geometry; + QImage::Format m_format; + QSurfaceFormat m_surfaceFormat; + int m_depth; + QWinRTInputContext *m_inputContext; + QWinRTCursor *m_cursor; + QList<QWindow *> m_visibleWindows; + + EGLDisplay m_eglDisplay; + EGLSurface m_eglSurface; + + ABI::Windows::Graphics::Display::IDisplayPropertiesStatics *m_displayProperties; + Qt::ScreenOrientation m_nativeOrientation; + Qt::ScreenOrientation m_orientation; + +#ifndef Q_OS_WINPHONE + QHash<quint32, QPair<Qt::Key, QString> > m_activeKeys; +#endif + QHash<quint32, Pointer> m_pointers; + QHash<quint32, QWindowSystemInterface::TouchPoint> m_touchPoints; +}; + +QT_END_NAMESPACE + +#endif // QWINRTSCREEN_H diff --git a/src/plugins/platforms/winrt/qwinrtservices.cpp b/src/plugins/platforms/winrt/qwinrtservices.cpp new file mode 100644 index 0000000000..8f0a1d55bb --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrtservices.cpp @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** 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 "qwinrtservices.h" +#include <QtCore/QUrl> +#include <QtCore/QDir> +#include <QtCore/QCoreApplication> + +#include <wrl.h> +#include <windows.foundation.h> +#include <windows.storage.h> +#include <windows.system.h> +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Storage; +using namespace ABI::Windows::System; + +QT_BEGIN_NAMESPACE + +QWinRTServices::QWinRTServices() +{ + GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Foundation_Uri).Get(), &m_uriFactory); + GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_StorageFile).Get(), &m_fileFactory); + GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_System_Launcher).Get(), &m_launcher); +} + +QWinRTServices::~QWinRTServices() +{ + if (m_uriFactory) + m_uriFactory->Release(); + + if (m_fileFactory) + m_fileFactory->Release(); + + if (m_launcher) + m_launcher->Release(); +} + +bool QWinRTServices::openUrl(const QUrl &url) +{ + if (!(m_uriFactory && m_launcher)) + return QPlatformServices::openUrl(url); + + IUriRuntimeClass *uri; + QString urlString = url.toString(); HSTRING uriString; HSTRING_HEADER header; + WindowsCreateStringReference((const wchar_t*)urlString.utf16(), urlString.length(), &header, &uriString); + m_uriFactory->CreateUri(uriString, &uri); + if (!uri) + return false; + + IAsyncOperation<bool> *launchOp; + m_launcher->LaunchUriAsync(uri, &launchOp); + uri->Release(); + if (!launchOp) + return false; + + boolean result = false; + while (launchOp->GetResults(&result) == E_ILLEGAL_METHOD_CALL) + QCoreApplication::processEvents(); + launchOp->Release(); + + return result; +} + +bool QWinRTServices::openDocument(const QUrl &url) +{ + if (!(m_fileFactory && m_launcher)) + return QPlatformServices::openDocument(url); + + QString pathString = QDir::toNativeSeparators( + QDir::cleanPath(qApp->applicationDirPath().append(url.toString(QUrl::RemoveScheme)))); + HSTRING_HEADER header; HSTRING path; + WindowsCreateStringReference((const wchar_t*)pathString.utf16(), pathString.length(), &header, &path); + IAsyncOperation<StorageFile*> *fileOp; + m_fileFactory->GetFileFromPathAsync(path, &fileOp); + if (!fileOp) + return false; + + IStorageFile *file = nullptr; + while (fileOp->GetResults(&file) == E_ILLEGAL_METHOD_CALL) + QCoreApplication::processEvents(); + fileOp->Release(); + if (!file) + return false; + + IAsyncOperation<bool> *launchOp; + m_launcher->LaunchFileAsync(file, &launchOp); + if (!launchOp) + return false; + + boolean result = false; + while (launchOp->GetResults(&result) == E_ILLEGAL_METHOD_CALL) + QCoreApplication::processEvents(); + launchOp->Release(); + + return result; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtservices.h b/src/plugins/platforms/winrt/qwinrtservices.h new file mode 100644 index 0000000000..9cc917030a --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrtservices.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** 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 QWINRTSERVICES_H +#define QWINRTSERVICES_H + +#include <qpa/qplatformservices.h> + +namespace ABI { + namespace Windows { + namespace Foundation { + struct IUriRuntimeClassFactory; + } + namespace Storage { + struct IStorageFileStatics; + } + namespace System { + struct ILauncherStatics; + } + } +} + +QT_BEGIN_NAMESPACE + +class QWinRTServices : public QPlatformServices +{ +public: + explicit QWinRTServices(); + ~QWinRTServices(); + + bool openUrl(const QUrl &url); + bool openDocument(const QUrl &url); + +private: + ABI::Windows::Foundation::IUriRuntimeClassFactory *m_uriFactory; + ABI::Windows::Storage::IStorageFileStatics *m_fileFactory; + ABI::Windows::System::ILauncherStatics *m_launcher; +}; + +QT_END_NAMESPACE + +#endif // QWINRTSERVICES_H diff --git a/src/plugins/platforms/winrt/qwinrtwindow.cpp b/src/plugins/platforms/winrt/qwinrtwindow.cpp new file mode 100644 index 0000000000..88b753b463 --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrtwindow.cpp @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** 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 "qwinrtwindow.h" +#include "qwinrtscreen.h" + +#include <qpa/qwindowsysteminterface.h> +#include <qpa/qplatformscreen.h> +#include <QtGui/QGuiApplication> +#include <QtGui/QWindow> +#include <QtGui/QOpenGLContext> + +QT_BEGIN_NAMESPACE + +QWinRTWindow::QWinRTWindow(QWindow *window) + : QPlatformWindow(window) + , m_screen(static_cast<QWinRTScreen*>(screen())) +{ + setWindowFlags(window->flags()); + setWindowState(window->windowState()); + handleContentOrientationChange(window->contentOrientation()); + setGeometry(window->geometry()); +} + +QWinRTWindow::~QWinRTWindow() +{ + m_screen->removeWindow(window()); +} + +QSurfaceFormat QWinRTWindow::format() const +{ + return m_screen->surfaceFormat(); +} + +bool QWinRTWindow::isActive() const +{ + return m_screen->topWindow() == window(); +} + +bool QWinRTWindow::isExposed() const +{ + const bool exposed = isActive(); + return exposed; +} + +void QWinRTWindow::setGeometry(const QRect &rect) +{ + if (window()->isTopLevel()) { + QPlatformWindow::setGeometry(m_screen->geometry()); + QWindowSystemInterface::handleGeometryChange(window(), geometry()); + } else { + QPlatformWindow::setGeometry(rect); + QWindowSystemInterface::handleGeometryChange(window(), rect); + } +} + +void QWinRTWindow::setVisible(bool visible) +{ + if (!window()->isTopLevel()) + return; + if (visible) + m_screen->addWindow(window()); + else + m_screen->removeWindow(window()); +} + +void QWinRTWindow::raise() +{ + if (!window()->isTopLevel()) + return; + m_screen->raise(window()); +} + +void QWinRTWindow::lower() +{ + if (!window()->isTopLevel()) + return; + m_screen->lower(window()); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/src/raster/qandroidplatformwindow.h b/src/plugins/platforms/winrt/qwinrtwindow.h index 9e3f203201..1f19b4f2d5 100644 --- a/src/plugins/platforms/android/src/raster/qandroidplatformwindow.h +++ b/src/plugins/platforms/winrt/qwinrtwindow.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org> +** 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. @@ -39,26 +39,34 @@ ** ****************************************************************************/ -#ifndef ANDROIDPLATFORMWINDOW_H -#define ANDROIDPLATFORMWINDOW_H -#include <qobject.h> -#include <QtPlatformSupport/private/qfbwindow_p.h> +#ifndef QWINRTWINDOW_H +#define QWINRTWINDOW_H -class QAndroidPlatformWindow: public QObject, public QFbWindow +#include <qpa/qplatformwindow.h> +#include <qpa/qwindowsysteminterface.h> + +QT_BEGIN_NAMESPACE + +class QWinRTScreen; + +class QWinRTWindow : public QPlatformWindow { - Q_OBJECT public: - explicit QAndroidPlatformWindow(QWindow *window); + QWinRTWindow(QWindow *window); + ~QWinRTWindow(); - void propagateSizeHints(); - - void raise(); - void setWindowState(Qt::WindowState state); + QSurfaceFormat format() const; + bool isActive() const; + bool isExposed() const; + void setGeometry(const QRect &rect); void setVisible(bool visible); - void updateStatusBarVisibility(); + void raise(); + void lower(); -public slots: - void setGeometry(const QRect &rect); +private: + QWinRTScreen *m_screen; }; -#endif // ANDROIDPLATFORMWINDOW_H +QT_END_NAMESPACE + +#endif // QWINRTWINDOW_H diff --git a/src/plugins/platforms/winrt/winrt.json b/src/plugins/platforms/winrt/winrt.json new file mode 100644 index 0000000000..962747b697 --- /dev/null +++ b/src/plugins/platforms/winrt/winrt.json @@ -0,0 +1,3 @@ +{ + "Keys": [ "winrt" ] +} diff --git a/src/plugins/platforms/winrt/winrt.pro b/src/plugins/platforms/winrt/winrt.pro new file mode 100644 index 0000000000..ea5ff93d00 --- /dev/null +++ b/src/plugins/platforms/winrt/winrt.pro @@ -0,0 +1,55 @@ +TARGET = qwinrt +CONFIG -= precompile_header + +PLUGIN_TYPE = platforms +PLUGIN_CLASS_NAME = QWinRTIntegrationPlugin +load(qt_plugin) + +QT += core-private gui-private platformsupport-private + +DEFINES *= QT_NO_CAST_FROM_ASCII __WRL_NO_DEFAULT_LIB__ GL_GLEXT_PROTOTYPES + +LIBS += $$QMAKE_LIBS_CORE -ldxgi + +SOURCES = \ + main.cpp \ + qwinrtbackingstore.cpp \ + qwinrtcursor.cpp \ + qwinrteglcontext.cpp \ + qwinrteventdispatcher.cpp \ + qwinrtfontdatabase.cpp \ + qwinrtinputcontext.cpp \ + qwinrtintegration.cpp \ + qwinrtscreen.cpp \ + qwinrtservices.cpp \ + qwinrtwindow.cpp + +HEADERS = \ + qwinrtbackingstore.h \ + qwinrtcursor.h \ + qwinrteglcontext.h \ + qwinrteventdispatcher.h \ + qwinrtfontdatabase.h \ + qwinrtinputcontext.h \ + qwinrtintegration.h \ + qwinrtscreen.h \ + qwinrtservices.h \ + qwinrtwindow.h + +BLIT_INPUT = $$PWD/blit.hlsl +fxc_blitps.commands = fxc.exe /nologo /T ps_4_0_level_9_1 /E blitps /Vn q_blitps /Fh ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME} +fxc_blitps.output = $$OUT_PWD/blitps.h +fxc_blitps.input = BLIT_INPUT +fxc_blitps.dependency_type = TYPE_C +fxc_blitps.variable_out = HEADERS +fxc_blitps.CONFIG += target_predeps +fxc_blitvs.commands = fxc.exe /nologo /T vs_4_0_level_9_1 /E blitvs /Vn q_blitvs /Fh ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME} +fxc_blitvs.output = $$OUT_PWD/blitvs.h +fxc_blitvs.input = BLIT_INPUT +fxc_blitvs.dependency_type = TYPE_C +fxc_blitvs.variable_out = HEADERS +fxc_blitvs.CONFIG += target_predeps +QMAKE_EXTRA_COMPILERS += fxc_blitps fxc_blitvs + +OTHER_FILES += winrt.json \ + blit.hlsl diff --git a/src/plugins/platforms/xcb/qglxintegration.cpp b/src/plugins/platforms/xcb/qglxintegration.cpp index e504d93fba..3f1c53b122 100644 --- a/src/plugins/platforms/xcb/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/qglxintegration.cpp @@ -167,6 +167,7 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat , m_shareContext(0) , m_format(format) , m_isPBufferCurrent(false) + , m_swapInterval(-1) { if (m_format.renderableType() == QSurfaceFormat::DefaultRenderableType) m_format.setRenderableType(QSurfaceFormat::OpenGL); @@ -326,19 +327,50 @@ QGLXContext::~QGLXContext() bool QGLXContext::makeCurrent(QPlatformSurface *surface) { + bool success = false; Q_ASSERT(surface->surface()->surfaceType() == QSurface::OpenGLSurface); + Display *dpy = DISPLAY_FROM_XCB(m_screen); + GLXDrawable glxDrawable = 0; 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); + glxDrawable = window->xcb_window(); + success = glXMakeCurrent(dpy, glxDrawable, 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); + glxDrawable = pbuffer->pbuffer(); + success = glXMakeContextCurrent(dpy, glxDrawable, glxDrawable, m_context); + } + + if (success) { + int interval = surface->format().swapInterval(); + if (interval >= 0 && m_swapInterval != interval) { + m_swapInterval = interval; + typedef void (*qt_glXSwapIntervalEXT)(Display *, GLXDrawable, int); + typedef void (*qt_glXSwapIntervalMESA)(unsigned int); + static qt_glXSwapIntervalEXT glXSwapIntervalEXT = 0; + static qt_glXSwapIntervalMESA glXSwapIntervalMESA = 0; + static bool resolved = false; + if (!resolved) { + resolved = true; + QList<QByteArray> glxExt = QByteArray(glXQueryExtensionsString(dpy, + m_screen->screenNumber())).split(' '); + if (glxExt.contains("GLX_EXT_swap_control")) + glXSwapIntervalEXT = (qt_glXSwapIntervalEXT) getProcAddress("glXSwapIntervalEXT"); + if (glxExt.contains("GLX_MESA_swap_control")) + glXSwapIntervalMESA = (qt_glXSwapIntervalMESA) getProcAddress("glXSwapIntervalMESA"); + } + if (glXSwapIntervalEXT) + glXSwapIntervalEXT(dpy, glxDrawable, interval); + else if (glXSwapIntervalMESA) + glXSwapIntervalMESA(interval); + } } - return false; + + return success; } void QGLXContext::doneCurrent() diff --git a/src/plugins/platforms/xcb/qglxintegration.h b/src/plugins/platforms/xcb/qglxintegration.h index dcc7fe8855..00bba94ab3 100644 --- a/src/plugins/platforms/xcb/qglxintegration.h +++ b/src/plugins/platforms/xcb/qglxintegration.h @@ -81,7 +81,7 @@ private: GLXContext m_shareContext; QSurfaceFormat m_format; bool m_isPBufferCurrent; - + int m_swapInterval; static bool m_queriedDummyContext; static bool m_supportsThreading; }; diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index e93b36cb99..366e043e98 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -232,9 +232,6 @@ void QXcbShmImage::put(xcb_window_t window, const QPoint &target, const QRect &s Q_XCB_NOOP(connection()); m_dirty = m_dirty | source; - - xcb_flush(xcb_connection()); - Q_XCB_NOOP(connection()); } void QXcbShmImage::preparePaint(const QRegion ®ion) @@ -314,10 +311,11 @@ void QXcbBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoin Q_XCB_NOOP(connection()); if (m_syncingResize) { - xcb_flush(xcb_connection()); connection()->sync(); m_syncingResize = false; platformWindow->updateSyncRequestCounter(); + } else { + xcb_flush(xcb_connection()); } } diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 3c4ab8d3e2..0cff92dacc 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -326,23 +326,6 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra initializeXRandr(); updateScreens(); - m_connectionEventListener = xcb_generate_id(m_connection); - xcb_create_window(m_connection, XCB_COPY_FROM_PARENT, - m_connectionEventListener, m_screens.at(0)->root(), - 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY, - m_screens.at(0)->screen()->root_visual, 0, 0); -#ifndef QT_NO_DEBUG - QByteArray ba("Qt xcb connection listener window"); - Q_XCB_CALL(xcb_change_property(xcb_connection(), - XCB_PROP_MODE_REPLACE, - m_connectionEventListener, - atom(QXcbAtom::_NET_WM_NAME), - atom(QXcbAtom::UTF8_STRING), - 8, - ba.length(), - ba.constData())); -#endif - initializeGLX(); initializeXFixes(); initializeXRender(); @@ -379,9 +362,6 @@ QXcbConnection::~QXcbConnection() #ifndef QT_NO_DRAGANDDROP delete m_drag; #endif - // Delete screens in reverse order to avoid crash in case of multiple screens - while (!m_screens.isEmpty()) - delete m_screens.takeLast(); #ifdef XCB_USE_XINPUT2_MAEMO finalizeXInput2Maemo(); @@ -396,6 +376,10 @@ QXcbConnection::~QXcbConnection() delete m_reader; + // Delete screens in reverse order to avoid crash in case of multiple screens + while (!m_screens.isEmpty()) + delete m_screens.takeLast(); + #ifdef XCB_USE_EGL if (m_has_egl) eglTerminate(m_egl_display); @@ -1081,14 +1065,21 @@ void QXcbConnection::sendConnectionEvent(QXcbAtom::Atom a, uint id) xcb_client_message_event_t event; memset(&event, 0, sizeof(event)); + const xcb_window_t eventListener = xcb_generate_id(m_connection); + Q_XCB_CALL(xcb_create_window(m_connection, XCB_COPY_FROM_PARENT, + eventListener, m_screens.at(0)->root(), + 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY, + m_screens.at(0)->screen()->root_visual, 0, 0)); + event.response_type = XCB_CLIENT_MESSAGE; event.format = 32; event.sequence = 0; - event.window = m_connectionEventListener; + event.window = eventListener; event.type = atom(a); event.data.data32[0] = id; - Q_XCB_CALL(xcb_send_event(xcb_connection(), false, m_connectionEventListener, XCB_EVENT_MASK_NO_EVENT, (const char *)&event)); + Q_XCB_CALL(xcb_send_event(xcb_connection(), false, eventListener, XCB_EVENT_MASK_NO_EVENT, (const char *)&event)); + Q_XCB_CALL(xcb_destroy_window(m_connection, eventListener)); xcb_flush(xcb_connection()); } @@ -1450,6 +1441,10 @@ static const char * xcb_atomnames = { "Abs Distance\0" "Wacom Serial IDs\0" "INTEGER\0" + "Rel Horiz Wheel\0" + "Rel Vert Wheel\0" + "Rel Horiz Scroll\0" + "Rel Vert Scroll\0" #if XCB_USE_MAEMO_WINDOW_PROPERTIES "_MEEGOTOUCH_ORIENTATION_ANGLE\0" #endif @@ -1731,21 +1726,23 @@ bool QXcbConnection::hasEgl() const #endif // defined(XCB_USE_EGL) #if defined(XCB_USE_XINPUT2) || defined(XCB_USE_XINPUT2_MAEMO) -// Borrowed from libXi. -int QXcbConnection::xi2CountBits(unsigned char *ptr, int len) +static int xi2ValuatorOffset(unsigned char *maskPtr, int maskLen, int number) { - int bits = 0; - int i; - unsigned char x; - - for (i = 0; i < len; i++) { - x = ptr[i]; - while (x > 0) { - bits += (x & 0x1); - x >>= 1; + int offset = 0; + for (int i = 0; i < maskLen; i++) { + if (number < 8) { + if ((maskPtr[i] & (1 << number)) == 0) + return -1; } + for (int j = 0; j < 8; j++) { + if (j == number) + return offset; + if (maskPtr[i] & (1 << j)) + offset++; + } + number -= 8; } - return bits; + return -1; } bool QXcbConnection::xi2GetValuatorValueIfSet(void *event, int valuatorNum, double *value) @@ -1754,13 +1751,13 @@ bool QXcbConnection::xi2GetValuatorValueIfSet(void *event, int valuatorNum, doub unsigned char *buttonsMaskAddr = (unsigned char*)&xideviceevent[1]; unsigned char *valuatorsMaskAddr = buttonsMaskAddr + xideviceevent->buttons_len * 4; FP3232 *valuatorsValuesAddr = (FP3232*)(valuatorsMaskAddr + xideviceevent->valuators_len * 4); - int numValuatorValues = xi2CountBits(valuatorsMaskAddr, xideviceevent->valuators_len * 4); - // This relies on all bit being set until a certain number i.e. it doesn't support only bit 0 and 5 being set in the mask. - // Just like the original code, works for now. - if (valuatorNum >= numValuatorValues) + + int valuatorOffset = xi2ValuatorOffset(valuatorsMaskAddr, xideviceevent->valuators_len, valuatorNum); + if (valuatorOffset < 0) return false; - *value = valuatorsValuesAddr[valuatorNum].integral; - *value += ((double)valuatorsValuesAddr[valuatorNum].frac / (1 << 16) / (1 << 16)); + + *value = valuatorsValuesAddr[valuatorOffset].integral; + *value += ((double)valuatorsValuesAddr[valuatorOffset].frac / (1 << 16) / (1 << 16)); return true; } diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index ba056a8006..71f5ce13fb 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -69,9 +69,12 @@ struct XInput2MaemoData; #elif XCB_USE_XINPUT2 #include <X11/extensions/XI2.h> +#ifdef XIScrollClass +#define XCB_USE_XINPUT21 // XI 2.1 adds smooth scrolling support #ifdef XI_TouchBeginMask #define XCB_USE_XINPUT22 // XI 2.2 adds multi-point touch support #endif +#endif struct XInput2DeviceData; #endif struct xcb_randr_get_output_info_reply_t; @@ -271,6 +274,10 @@ namespace QXcbAtom { AbsDistance, WacomSerialIDs, INTEGER, + RelHorizWheel, + RelVertWheel, + RelHorizScroll, + RelVertScroll, #if XCB_USE_MAEMO_WINDOW_PROPERTIES MeegoTouchOrientationAngle, @@ -499,10 +506,19 @@ private: void xi2ReportTabletEvent(const TabletData &tabletData, void *event); QVector<TabletData> m_tabletData; #endif + struct ScrollingDevice { + ScrollingDevice() : deviceId(0), verticalIndex(0), horizontalIndex(0), orientations(0) { } + int deviceId; + int verticalIndex, horizontalIndex; + double verticalIncrement, horizontalIncrement; + Qt::Orientations orientations; + QPointF lastScrollPosition; + }; + void xi2HandleScrollEvent(void *event, ScrollingDevice &scrollingDevice); + QHash<int, ScrollingDevice> m_scrollingDevices; #endif // XCB_USE_XINPUT2 #if defined(XCB_USE_XINPUT2) || defined(XCB_USE_XINPUT2_MAEMO) - static int xi2CountBits(unsigned char *ptr, int len); static bool xi2GetValuatorValueIfSet(void *event, int valuatorNum, double *value); static bool xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event, int opCode); #endif @@ -521,8 +537,6 @@ private: QByteArray m_displayName; - xcb_window_t m_connectionEventListener; - QXcbKeyboard *m_keyboard; #ifndef QT_NO_CLIPBOARD QXcbClipboard *m_clipboard; diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index a571f16eb6..d80b49ccbb 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qxcbconnection.h" +#include "qxcbkeyboard.h" #include "qxcbscreen.h" #include "qxcbwindow.h" #include "qtouchdevice.h" @@ -75,16 +76,20 @@ void QXcbConnection::initializeXInput2() #ifndef QT_NO_TABLETEVENT m_tabletData.clear(); #endif + m_scrollingDevices.clear(); Display *xDisplay = static_cast<Display *>(m_xlib_display); if (XQueryExtension(xDisplay, "XInputExtension", &m_xiOpCode, &m_xiEventBase, &m_xiErrorBase)) { int xiMajor = 2; m_xi2Minor = 2; // try 2.2 first, needed for TouchBegin/Update/End if (XIQueryVersion(xDisplay, &xiMajor, &m_xi2Minor) == BadRequest) { - m_xi2Minor = 0; // for tablet support 2.0 is enough - m_xi2Enabled = XIQueryVersion(xDisplay, &xiMajor, &m_xi2Minor) != BadRequest; - } else { + m_xi2Minor = 1; // for smooth scrolling 2.1 is enough + if (XIQueryVersion(xDisplay, &xiMajor, &m_xi2Minor) == BadRequest) { + m_xi2Minor = 0; // for tablet support 2.0 is enough + m_xi2Enabled = XIQueryVersion(xDisplay, &xiMajor, &m_xi2Minor) != BadRequest; + } else + m_xi2Enabled = true; + } else m_xi2Enabled = true; - } if (m_xi2Enabled) { if (Q_UNLIKELY(debug_xinput_devices)) #ifdef XCB_USE_XINPUT22 @@ -103,6 +108,7 @@ void QXcbConnection::initializeXInput2() #ifndef QT_NO_TABLETEVENT TabletData tabletData; #endif + ScrollingDevice scrollingDevice; for (int c = 0; c < devices[i].num_classes; ++c) { switch (devices[i].classes[c]->type) { case XIValuatorClass: { @@ -119,7 +125,29 @@ void QXcbConnection::initializeXInput2() tabletData.valuatorInfo[valuatorAtom] = info; } #endif // QT_NO_TABLETEVENT - } break; + if (valuatorAtom == QXcbAtom::RelHorizScroll || valuatorAtom == QXcbAtom::RelHorizWheel) + scrollingDevice.lastScrollPosition.setX(vci->value); + else if (valuatorAtom == QXcbAtom::RelVertScroll || valuatorAtom == QXcbAtom::RelVertWheel) + scrollingDevice.lastScrollPosition.setY(vci->value); + break; + } +#ifdef XCB_USE_XINPUT21 + case XIScrollClass: { + XIScrollClassInfo *sci = reinterpret_cast<XIScrollClassInfo *>(devices[i].classes[c]); + scrollingDevice.deviceId = devices[i].deviceid; + if (sci->scroll_type == XIScrollTypeVertical) { + scrollingDevice.orientations |= Qt::Vertical; + scrollingDevice.verticalIndex = sci->number; + scrollingDevice.verticalIncrement = sci->increment; + } + else if (sci->scroll_type == XIScrollTypeHorizontal) { + scrollingDevice.orientations |= Qt::Horizontal; + scrollingDevice.horizontalIndex = sci->number; + scrollingDevice.horizontalIncrement = sci->increment; + } + break; + } +#endif default: break; } @@ -140,6 +168,15 @@ void QXcbConnection::initializeXInput2() qDebug() << " it's a tablet with pointer type" << tabletData.pointerType; } #endif // QT_NO_TABLETEVENT + +#ifdef XCB_USE_XINPUT21 + if (scrollingDevice.orientations) { + m_scrollingDevices.insert(scrollingDevice.deviceId, scrollingDevice); + if (Q_UNLIKELY(debug_xinput_devices)) + qDebug() << " it's a scrolling device"; + } +#endif + if (!isTablet) { XInput2DeviceData *dev = deviceForId(devices[i].deviceid); if (Q_UNLIKELY(debug_xinput_devices)) { @@ -181,7 +218,7 @@ void QXcbConnection::xi2Select(xcb_window_t window) mask.mask_len = sizeof(bitMask); mask.mask = xiBitMask; // Enable each touchscreen - foreach (XInput2DeviceData *dev, m_touchDevices.values()) { + foreach (XInput2DeviceData *dev, m_touchDevices) { mask.deviceid = dev->xiDeviceInfo->deviceid; Status result = XISelectEvents(xDisplay, window, &mask, 1); // If we have XInput >= 2.2 and successfully enable a touchscreen, then @@ -213,6 +250,22 @@ void QXcbConnection::xi2Select(xcb_window_t window) XISelectEvents(xDisplay, window, xiEventMask.data(), m_tabletData.count()); } #endif // QT_NO_TABLETEVENT + +#ifdef XCB_USE_XINPUT21 + // Enable each scroll device + if (!m_scrollingDevices.isEmpty()) { + QVector<XIEventMask> xiEventMask(m_scrollingDevices.size()); + bitMask = XI_MotionMask; + int i=0; + Q_FOREACH (const ScrollingDevice& scrollingDevice, m_scrollingDevices) { + xiEventMask[i].deviceid = scrollingDevice.deviceId; + xiEventMask[i].mask_len = sizeof(bitMask); + xiEventMask[i].mask = xiBitMask; + i++; + } + XISelectEvents(xDisplay, window, xiEventMask.data(), m_scrollingDevices.size()); + } +#endif } XInput2DeviceData *QXcbConnection::deviceForId(int id) @@ -243,7 +296,8 @@ XInput2DeviceData *QXcbConnection::deviceForId(int id) type = QTouchDevice::TouchScreen; break; } - } break; + break; + } #endif // XCB_USE_XINPUT22 case XIValuatorClass: { XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(classinfo); @@ -260,7 +314,8 @@ XInput2DeviceData *QXcbConnection::deviceForId(int id) hasRelativeCoords = true; dev->size.setHeight((vci->max - vci->min) * 1000.0 / vci->resolution); } - } break; + break; + } } } if (type < 0 && caps && hasRelativeCoords) { @@ -287,12 +342,14 @@ XInput2DeviceData *QXcbConnection::deviceForId(int id) return dev; } -#ifdef XCB_USE_XINPUT22 +#if defined(XCB_USE_XINPUT21) || !defined(QT_NO_TABLETEVENT) static qreal fixed1616ToReal(FP1616 val) { return (qreal(val >> 16)) + (val & 0xFF) / (qreal)0xFF; } +#endif // defined(XCB_USE_XINPUT21) || !defined(QT_NO_TABLETEVENT) +#if defined(XCB_USE_XINPUT21) static qreal valuatorNormalized(double value, XIValuatorClassInfo *vci) { if (value > vci->max) @@ -301,7 +358,7 @@ static qreal valuatorNormalized(double value, XIValuatorClassInfo *vci) value = vci->min; return (value - vci->min) / (vci->max - vci->min); } -#endif // XCB_USE_XINPUT22 +#endif // XCB_USE_XINPUT21 void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) { @@ -317,6 +374,12 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) } #endif // QT_NO_TABLETEVENT +#ifdef XCB_USE_XINPUT21 + QHash<int, ScrollingDevice>::iterator device = m_scrollingDevices.find(xiEvent->deviceid); + if (device != m_scrollingDevices.end()) + xi2HandleScrollEvent(xiEvent, device.value()); +#endif // XCB_USE_XINPUT21 + #ifdef XCB_USE_XINPUT22 if (xiEvent->evtype == XI_TouchBegin || xiEvent->evtype == XI_TouchUpdate || xiEvent->evtype == XI_TouchEnd) { xXIDeviceEvent* xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event); @@ -461,6 +524,55 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) } } +void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollingDevice) +{ +#ifdef XCB_USE_XINPUT21 + xXIGenericDeviceEvent *xiEvent = reinterpret_cast<xXIGenericDeviceEvent *>(event); + + if (xiEvent->evtype == XI_Motion) { + xXIDeviceEvent* xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event); + if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) { + QPoint rawDelta; + QPoint angleDelta; + double value; + if (scrollingDevice.orientations & Qt::Vertical) { + if (xi2GetValuatorValueIfSet(xiDeviceEvent, scrollingDevice.verticalIndex, &value)) { + double delta = scrollingDevice.lastScrollPosition.y() - value; + scrollingDevice.lastScrollPosition.setY(value); + angleDelta.setY((delta / scrollingDevice.verticalIncrement) * 120); + // We do not set "pixel" delta if it is only measured in ticks. + if (scrollingDevice.verticalIncrement > 1) + rawDelta.setY(delta); + } + } + if (scrollingDevice.orientations & Qt::Horizontal) { + if (xi2GetValuatorValueIfSet(xiDeviceEvent, scrollingDevice.horizontalIndex, &value)) { + double delta = scrollingDevice.lastScrollPosition.x() - value; + scrollingDevice.lastScrollPosition.setX(value); + angleDelta.setX((delta / scrollingDevice.horizontalIncrement) * 120); + // We do not set "pixel" delta if it is only measured in ticks. + if (scrollingDevice.horizontalIncrement > 1) + rawDelta.setX(delta); + } + } + if (!angleDelta.isNull()) { + QPoint local(fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y)); + QPoint global(fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y)); + Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective_mods); + if (modifiers & Qt::AltModifier) { + std::swap(angleDelta.rx(), angleDelta.ry()); + std::swap(rawDelta.rx(), rawDelta.ry()); + } + QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiEvent->time, local, global, rawDelta, angleDelta, modifiers); + } + } + } +#else + Q_UNUSED(event); + Q_UNUSED(scrollingDevice); +#endif // XCB_USE_XINPUT21 +} + #ifndef QT_NO_TABLETEVENT bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData) { diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp index d18693f6b8..61dfe8ac17 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.cpp +++ b/src/plugins/platforms/xcb/qxcbdrag.cpp @@ -593,9 +593,9 @@ static Window findXdndAwareParent(Window window) unsigned char *data = 0; if (XGetWindowProperty(X11->display, window, ATOM(XdndAware), 0, 0, False, AnyPropertyType, &type, &f,&n,&a,&data) == Success) { - if (data) + if (data) XFree(data); - if (type) { + if (type) { target = window; break; } diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index 2529fb8a83..966090dbd5 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -117,7 +117,7 @@ #define XF86XK_KbdBrightnessUp 0x1008FF05 #define XF86XK_KbdBrightnessDown 0x1008FF06 #define XF86XK_Standby 0x1008FF10 -#define XF86XK_AudioLowerVolume 0x1008FF11 +#define XF86XK_AudioLowerVolume 0x1008FF11 #define XF86XK_AudioMute 0x1008FF12 #define XF86XK_AudioRaiseVolume 0x1008FF13 #define XF86XK_AudioPlay 0x1008FF14 @@ -344,65 +344,65 @@ static const unsigned int KeyTbl[] = { // International & multi-key character composition XK_ISO_Level3_Shift, Qt::Key_AltGr, - XK_Multi_key, Qt::Key_Multi_key, - XK_Codeinput, Qt::Key_Codeinput, - XK_SingleCandidate, Qt::Key_SingleCandidate, - XK_MultipleCandidate, Qt::Key_MultipleCandidate, - XK_PreviousCandidate, Qt::Key_PreviousCandidate, + XK_Multi_key, Qt::Key_Multi_key, + XK_Codeinput, Qt::Key_Codeinput, + XK_SingleCandidate, Qt::Key_SingleCandidate, + XK_MultipleCandidate, Qt::Key_MultipleCandidate, + XK_PreviousCandidate, Qt::Key_PreviousCandidate, // Misc Functions - XK_Mode_switch, Qt::Key_Mode_switch, - XK_script_switch, Qt::Key_Mode_switch, + XK_Mode_switch, Qt::Key_Mode_switch, + XK_script_switch, Qt::Key_Mode_switch, // Japanese keyboard support - XK_Kanji, Qt::Key_Kanji, - XK_Muhenkan, Qt::Key_Muhenkan, - //XK_Henkan_Mode, Qt::Key_Henkan_Mode, - XK_Henkan_Mode, Qt::Key_Henkan, - XK_Henkan, Qt::Key_Henkan, - XK_Romaji, Qt::Key_Romaji, - XK_Hiragana, Qt::Key_Hiragana, - XK_Katakana, Qt::Key_Katakana, - XK_Hiragana_Katakana, Qt::Key_Hiragana_Katakana, - XK_Zenkaku, Qt::Key_Zenkaku, - XK_Hankaku, Qt::Key_Hankaku, - XK_Zenkaku_Hankaku, Qt::Key_Zenkaku_Hankaku, - XK_Touroku, Qt::Key_Touroku, - XK_Massyo, Qt::Key_Massyo, - XK_Kana_Lock, Qt::Key_Kana_Lock, - XK_Kana_Shift, Qt::Key_Kana_Shift, - XK_Eisu_Shift, Qt::Key_Eisu_Shift, - XK_Eisu_toggle, Qt::Key_Eisu_toggle, - //XK_Kanji_Bangou, Qt::Key_Kanji_Bangou, - //XK_Zen_Koho, Qt::Key_Zen_Koho, - //XK_Mae_Koho, Qt::Key_Mae_Koho, - XK_Kanji_Bangou, Qt::Key_Codeinput, - XK_Zen_Koho, Qt::Key_MultipleCandidate, - XK_Mae_Koho, Qt::Key_PreviousCandidate, + XK_Kanji, Qt::Key_Kanji, + XK_Muhenkan, Qt::Key_Muhenkan, + //XK_Henkan_Mode, Qt::Key_Henkan_Mode, + XK_Henkan_Mode, Qt::Key_Henkan, + XK_Henkan, Qt::Key_Henkan, + XK_Romaji, Qt::Key_Romaji, + XK_Hiragana, Qt::Key_Hiragana, + XK_Katakana, Qt::Key_Katakana, + XK_Hiragana_Katakana, Qt::Key_Hiragana_Katakana, + XK_Zenkaku, Qt::Key_Zenkaku, + XK_Hankaku, Qt::Key_Hankaku, + XK_Zenkaku_Hankaku, Qt::Key_Zenkaku_Hankaku, + XK_Touroku, Qt::Key_Touroku, + XK_Massyo, Qt::Key_Massyo, + XK_Kana_Lock, Qt::Key_Kana_Lock, + XK_Kana_Shift, Qt::Key_Kana_Shift, + XK_Eisu_Shift, Qt::Key_Eisu_Shift, + XK_Eisu_toggle, Qt::Key_Eisu_toggle, + //XK_Kanji_Bangou, Qt::Key_Kanji_Bangou, + //XK_Zen_Koho, Qt::Key_Zen_Koho, + //XK_Mae_Koho, Qt::Key_Mae_Koho, + XK_Kanji_Bangou, Qt::Key_Codeinput, + XK_Zen_Koho, Qt::Key_MultipleCandidate, + XK_Mae_Koho, Qt::Key_PreviousCandidate, #ifdef XK_KOREAN // Korean keyboard support - XK_Hangul, Qt::Key_Hangul, - XK_Hangul_Start, Qt::Key_Hangul_Start, - XK_Hangul_End, Qt::Key_Hangul_End, - XK_Hangul_Hanja, Qt::Key_Hangul_Hanja, - XK_Hangul_Jamo, Qt::Key_Hangul_Jamo, - XK_Hangul_Romaja, Qt::Key_Hangul_Romaja, - //XK_Hangul_Codeinput, Qt::Key_Hangul_Codeinput, - XK_Hangul_Codeinput, Qt::Key_Codeinput, - XK_Hangul_Jeonja, Qt::Key_Hangul_Jeonja, - XK_Hangul_Banja, Qt::Key_Hangul_Banja, - XK_Hangul_PreHanja, Qt::Key_Hangul_PreHanja, - XK_Hangul_PostHanja, Qt::Key_Hangul_PostHanja, + XK_Hangul, Qt::Key_Hangul, + XK_Hangul_Start, Qt::Key_Hangul_Start, + XK_Hangul_End, Qt::Key_Hangul_End, + XK_Hangul_Hanja, Qt::Key_Hangul_Hanja, + XK_Hangul_Jamo, Qt::Key_Hangul_Jamo, + XK_Hangul_Romaja, Qt::Key_Hangul_Romaja, + //XK_Hangul_Codeinput, Qt::Key_Hangul_Codeinput, + XK_Hangul_Codeinput, Qt::Key_Codeinput, + XK_Hangul_Jeonja, Qt::Key_Hangul_Jeonja, + XK_Hangul_Banja, Qt::Key_Hangul_Banja, + XK_Hangul_PreHanja, Qt::Key_Hangul_PreHanja, + XK_Hangul_PostHanja, Qt::Key_Hangul_PostHanja, //XK_Hangul_SingleCandidate,Qt::Key_Hangul_SingleCandidate, //XK_Hangul_MultipleCandidate,Qt::Key_Hangul_MultipleCandidate, //XK_Hangul_PreviousCandidate,Qt::Key_Hangul_PreviousCandidate, - XK_Hangul_SingleCandidate, Qt::Key_SingleCandidate, + XK_Hangul_SingleCandidate, Qt::Key_SingleCandidate, XK_Hangul_MultipleCandidate,Qt::Key_MultipleCandidate, XK_Hangul_PreviousCandidate,Qt::Key_PreviousCandidate, - XK_Hangul_Special, Qt::Key_Hangul_Special, - //XK_Hangul_switch, Qt::Key_Hangul_switch, - XK_Hangul_switch, Qt::Key_Mode_switch, + XK_Hangul_Special, Qt::Key_Hangul_Special, + //XK_Hangul_switch, Qt::Key_Hangul_switch, + XK_Hangul_switch, Qt::Key_Mode_switch, #endif // XK_KOREAN // dead keys diff --git a/src/plugins/platforms/xcb/qxcbsessionmanager.cpp b/src/plugins/platforms/xcb/qxcbsessionmanager.cpp index 9d81c8e224..8c10b134bd 100644 --- a/src/plugins/platforms/xcb/qxcbsessionmanager.cpp +++ b/src/plugins/platforms/xcb/qxcbsessionmanager.cpp @@ -50,6 +50,7 @@ #include <X11/SM/SMlib.h> #include <errno.h> // ERANGE +#include <cerrno> // ERANGE class QSmSocketReceiver : public QObject { diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index f46bed77d6..63894373b8 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -297,7 +297,7 @@ void QXcbWindow::create() #elif defined(XCB_USE_EGL) EGLDisplay eglDisplay = connection()->egl_display(); EGLConfig eglConfig = q_configFromGLFormat(eglDisplay, m_format, true); - m_format = q_glFormatFromConfig(eglDisplay, eglConfig); + m_format = q_glFormatFromConfig(eglDisplay, eglConfig, m_format); VisualID id = QXlibEglIntegration::getCompatibleVisualId(DISPLAY_FROM_XCB(this), eglDisplay, eglConfig); @@ -672,8 +672,6 @@ void QXcbWindow::show() m_screen->windowShown(this); - xcb_flush(xcb_connection()); - connection()->sync(); } @@ -1695,6 +1693,7 @@ void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event) Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state); if (isWheel) { +#ifndef XCB_USE_XINPUT21 // Logic borrowed from qapplication_x11.cpp int delta = 120 * ((event->detail == 4 || event->detail == 6) ? 1 : -1); bool hor = (((event->detail == 4 || event->detail == 5) @@ -1703,6 +1702,7 @@ void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event) QWindowSystemInterface::handleWheelEvent(window(), event->time, local, global, delta, hor ? Qt::Horizontal : Qt::Vertical, modifiers); +#endif return; } @@ -1893,7 +1893,6 @@ void QXcbWindow::updateSyncRequestCounter() { 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(); m_syncValue.lo = 0; diff --git a/src/plugins/platforms/xcb/xcb-plugin.pro b/src/plugins/platforms/xcb/xcb-plugin.pro index 8968d020c4..67f2d8a911 100644 --- a/src/plugins/platforms/xcb/xcb-plugin.pro +++ b/src/plugins/platforms/xcb/xcb-plugin.pro @@ -42,7 +42,7 @@ HEADERS = \ qxcbxsettings.h \ qxcbsystemtraytracker.h -LIBS += -ldl +LIBS += $$QMAKE_LIBS_DYNLOAD # needed by GLX, Xcursor ... contains(QT_CONFIG, xcb-xlib) { diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index 6f4bca63be..942db329ca 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -1,7 +1,7 @@ TEMPLATE = subdirs SUBDIRS *= sqldrivers -qtHaveModule(network): SUBDIRS += bearer +!winrt:qtHaveModule(network): SUBDIRS += bearer qtHaveModule(gui): SUBDIRS *= imageformats platforms platforminputcontexts platformthemes generic qtHaveModule(widgets): SUBDIRS += accessible |