diff options
Diffstat (limited to 'src/plugins')
258 files changed, 12361 insertions, 6010 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/compose.pro b/src/plugins/platforminputcontexts/compose/compose.pro index 2490a4ffbe..c206e99e57 100644 --- a/src/plugins/platforminputcontexts/compose/compose.pro +++ b/src/plugins/platforminputcontexts/compose/compose.pro @@ -8,6 +8,7 @@ QT += gui-private LIBS += $$QMAKE_LIBS_XKBCOMMON QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_XKBCOMMON +DEFINES += COMPOSE_X11_PREFIX='\\"$$QMAKE_X11_PREFIX\\"' SOURCES += $$PWD/main.cpp \ $$PWD/qcomposeplatforminputcontext.cpp \ diff --git a/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp b/src/plugins/platforminputcontexts/compose/generator/qtablegenerator.cpp index 11545b16c3..121e734ec1 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()) @@ -72,17 +73,13 @@ TableGenerator::TableGenerator() : m_state(NoErrors), void TableGenerator::initPossibleLocations() { - // AFAICT there is no way to know the exact location - // of the compose files. It depends on how Xlib was configured - // on a specific platform. During the "./configure" process - // xlib generates a config.h file which contains a bunch of defines, - // including XLOCALEDIR which points to the location of the compose file dir. // To add an extra system path use the QTCOMPOSE environment variable if (qEnvironmentVariableIsSet("QTCOMPOSE")) { m_possibleLocations.append(QString(qgetenv("QTCOMPOSE"))); } - m_possibleLocations.append(QStringLiteral("/usr/share/X11/locale")); - m_possibleLocations.append(QStringLiteral("/usr/lib/X11/locale")); + + m_possibleLocations.append(QStringLiteral(COMPOSE_X11_PREFIX "/share/X11/locale")); + m_possibleLocations.append(QStringLiteral(COMPOSE_X11_PREFIX "/lib/X11/locale")); } void TableGenerator::findComposeFile() 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 6461fa4733..e997a49a25 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,17 @@ 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 (!m_bitmapClass) + return 0; + + 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,9 +284,24 @@ 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) + if (!bitmap || !m_bitmapDrawableClass || !m_resourcesObj) return 0; return env->NewObject(m_bitmapDrawableClass, @@ -426,25 +332,76 @@ namespace QtAndroid return manufacturer + QStringLiteral(" ") + model; } + + 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); + } } // namespace QtAndroid + 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*/) @@ -520,132 +477,43 @@ 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); - env->DeleteGlobalRef(m_activityObject); - env->DeleteGlobalRef(m_bitmapClass); - env->DeleteGlobalRef(m_ARGB_8888_BitmapConfigValue); - env->DeleteGlobalRef(m_RGB_565_BitmapConfigValue); - env->DeleteGlobalRef(m_bitmapDrawableClass); -} - -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 + if (m_resourcesObj) + env->DeleteGlobalRef(m_resourcesObj); + if (m_activityObject) + env->DeleteGlobalRef(m_activityObject); + if (m_bitmapClass) + env->DeleteGlobalRef(m_bitmapClass); + if (m_ARGB_8888_BitmapConfigValue) + env->DeleteGlobalRef(m_ARGB_8888_BitmapConfigValue); + if (m_RGB_565_BitmapConfigValue) + env->DeleteGlobalRef(m_RGB_565_BitmapConfigValue); + if (m_bitmapDrawableClass) + env->DeleteGlobalRef(m_bitmapDrawableClass); + m_androidPlatformIntegration = 0; + delete m_androidAssetsFileEngineHandler; } -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*/, @@ -668,16 +536,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) @@ -688,12 +546,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) @@ -742,15 +596,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} @@ -803,43 +652,48 @@ 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;"); jobject activityObject = env->CallStaticObjectMethod(m_applicationClass, methodID); - m_activityObject = env->NewGlobalRef(activityObject); GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "classLoader", "()Ljava/lang/ClassLoader;"); m_classLoaderObject = env->NewGlobalRef(env->CallStaticObjectMethod(m_applicationClass, methodID)); - clazz = env->GetObjectClass(m_classLoaderObject); GET_AND_CHECK_METHOD(m_loadClassMethodID, clazz, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); - FIND_AND_CHECK_CLASS("android/content/ContextWrapper"); - GET_AND_CHECK_METHOD(methodID, clazz, "getAssets", "()Landroid/content/res/AssetManager;"); - m_assetManager = AAssetManager_fromJava(env, env->CallObjectMethod(activityObject, methodID)); + if (activityObject) { + m_activityObject = env->NewGlobalRef(activityObject); - GET_AND_CHECK_METHOD(methodID, clazz, "getResources", "()Landroid/content/res/Resources;"); - m_resourcesObj = env->NewGlobalRef(env->CallObjectMethod(activityObject, methodID)); + FIND_AND_CHECK_CLASS("android/content/ContextWrapper"); + GET_AND_CHECK_METHOD(methodID, clazz, "getAssets", "()Landroid/content/res/AssetManager;"); + m_assetManager = AAssetManager_fromJava(env, env->CallObjectMethod(activityObject, methodID)); + + GET_AND_CHECK_METHOD(methodID, clazz, "getResources", "()Landroid/content/res/Resources;"); + m_resourcesObj = env->NewGlobalRef(env->CallObjectMethod(activityObject, methodID)); + + FIND_AND_CHECK_CLASS("android/graphics/Bitmap"); + m_bitmapClass = static_cast<jclass>(env->NewGlobalRef(clazz)); + GET_AND_CHECK_STATIC_METHOD(m_createBitmapMethodID, m_bitmapClass + , "createBitmap", "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;"); + FIND_AND_CHECK_CLASS("android/graphics/Bitmap$Config"); + jfieldID fieldId; + GET_AND_CHECK_STATIC_FIELD(fieldId, clazz, "ARGB_8888", "Landroid/graphics/Bitmap$Config;"); + m_ARGB_8888_BitmapConfigValue = env->NewGlobalRef(env->GetStaticObjectField(clazz, fieldId)); + GET_AND_CHECK_STATIC_FIELD(fieldId, clazz, "RGB_565", "Landroid/graphics/Bitmap$Config;"); + m_RGB_565_BitmapConfigValue = env->NewGlobalRef(env->GetStaticObjectField(clazz, fieldId)); + + FIND_AND_CHECK_CLASS("android/graphics/drawable/BitmapDrawable"); + m_bitmapDrawableClass = static_cast<jclass>(env->NewGlobalRef(clazz)); + GET_AND_CHECK_METHOD(m_bitmapDrawableConstructorMethodID, + m_bitmapDrawableClass, + "<init>", + "(Landroid/content/res/Resources;Landroid/graphics/Bitmap;)V"); + } - FIND_AND_CHECK_CLASS("android/graphics/Bitmap"); - m_bitmapClass = static_cast<jclass>(env->NewGlobalRef(clazz)); - GET_AND_CHECK_STATIC_METHOD(m_createBitmapMethodID, m_bitmapClass - , "createBitmap", "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;"); - FIND_AND_CHECK_CLASS("android/graphics/Bitmap$Config"); - jfieldID fieldId; - GET_AND_CHECK_STATIC_FIELD(fieldId, clazz, "ARGB_8888", "Landroid/graphics/Bitmap$Config;"); - m_ARGB_8888_BitmapConfigValue = env->NewGlobalRef(env->GetStaticObjectField(clazz, fieldId)); - GET_AND_CHECK_STATIC_FIELD(fieldId, clazz, "RGB_565", "Landroid/graphics/Bitmap$Config;"); - m_RGB_565_BitmapConfigValue = env->NewGlobalRef(env->GetStaticObjectField(clazz, fieldId)); - - FIND_AND_CHECK_CLASS("android/graphics/drawable/BitmapDrawable"); - m_bitmapDrawableClass = static_cast<jclass>(env->NewGlobalRef(clazz)); - GET_AND_CHECK_METHOD(m_bitmapDrawableConstructorMethodID, - m_bitmapDrawableClass, - "<init>", - "(Landroid/content/res/Resources;Landroid/graphics/Bitmap;)V"); return JNI_TRUE; } diff --git a/src/plugins/platforms/android/src/androidjnimain.h b/src/plugins/platforms/android/androidjnimain.h index a7b7072ba3..eb8dd87ae0 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..5f77d1645a 100644 --- a/src/plugins/platforms/android/src/qandroidassetsfileenginehandler.cpp +++ b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp @@ -293,6 +293,7 @@ QAbstractFileEngine * AndroidAssetsFileEngineHandler::create(const QString &file AAssetDir *assetDir = AAssetManager_openDir(m_assetManager, path.constData() + prefixSize); if (assetDir) { if (AAssetDir_getNextFileName(assetDir)) { + AAssetDir_rewind(assetDir); aad = new QSharedPointer<AndroidAssetDir>(new AndroidAssetDir(assetDir)); m_assetsCacheMutext.lock(); m_assetsCache.insert(path, aad); 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 9bfb6e9a70..3dc8632374 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; @@ -106,12 +103,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); @@ -140,83 +146,50 @@ 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: if (needsWorkaround()) return false; // fall through 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; -} - -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(); - } + if (window->surfaceType() == QSurface::RasterSurface) + return new QAndroidPlatformRasterWindow(window); + else + return new QAndroidPlatformOpenGLWindow(window, m_eglDisplay); } -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; @@ -227,6 +200,7 @@ QAndroidPlatformIntegration::~QAndroidPlatformIntegration() QtAndroid::setAndroidPlatformIntegration(NULL); } + QPlatformFontDatabase *QAndroidPlatformIntegration::fontDatabase() const { return m_androidFDB; @@ -317,8 +291,6 @@ QPlatformAccessibility *QAndroidPlatformIntegration::accessibility() const } #endif - -#ifndef ANDROID_PLUGIN_OPENGL void QAndroidPlatformIntegration::setDesktopSize(int width, int height) { if (m_primaryScreen) @@ -330,36 +302,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 c5476128a5..0dc2415337 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,20 +121,13 @@ public: QTouchDevice *touchDevice() const { return m_touchDevice; } void setTouchDevice(QTouchDevice *touchDevice) { m_touchDevice = touchDevice; } -#ifdef ANDROID_PLUGIN_OPENGL - QEglFSScreen *createScreen() const; -#endif - static bool needsWorkaround(); - + EGLDisplay m_eglDisplay; private: - friend class QEglFSAndroidHooks; 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 d94bb241f7..59ca69c004 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,31 @@ ** ****************************************************************************/ -#include "qandroidopenglcontext.h" -#include "qandroidopenglplatformwindow.h" +#include "qandroidplatformopenglcontext.h" +#include "qandroidplatformopenglwindow.h" #include "qandroidplatformintegration.h" -#include <QtCore/qdebug.h> -#include <qpa/qwindowsysteminterface.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); QOpenGLContextPrivate *ctx_d = QOpenGLContextPrivate::get(context()); const char *rendererString = reinterpret_cast<const char *>(glGetString(GL_RENDERER)); @@ -94,4 +77,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..9df6610a99 --- /dev/null +++ b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** 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> + +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; + + 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); + if (m_nativeSurfaceId == -1 || !m_androidSurfaceObject.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(); + QJNIEnvironmentPrivate env; + m_nativeWindow = ANativeWindow_fromSurface(env, m_androidSurfaceObject.object()); + m_androidSurfaceObject = QJNIObjectPrivate(); + 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); + lockSurface(); + m_androidSurfaceObject = 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..7af8b722aa --- /dev/null +++ b/src/plugins/platforms/android/qandroidplatformopenglwindow.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** 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_androidSurfaceObject; + 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..68545c6562 --- /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().translated(mapToGlobal(QPoint(0,0))); + + 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..f59a80d74e --- /dev/null +++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp @@ -0,0 +1,351 @@ +/**************************************************************************** +** +** 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> +#include <android/native_window_jni.h> + +QT_BEGIN_NAMESPACE + +#ifdef QANDROIDPLATFORMSCREEN_DEBUG +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__) +#else +# define PROFILE_SCOPE +#endif + +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_ARGB32_Premultiplied; + 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_nativeSurface) + ANativeWindow_release(m_nativeSurface); + } +} + +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) +{ + if (window->parent()) + return; + + m_windowStack.prepend(window); + if (window->isRaster()) + setDirty(window->geometry()); + + QWindow *w = topWindow(); + QWindowSystemInterface::handleWindowActivated(w); + topWindowChanged(w); +} + +void QAndroidPlatformScreen::removeWindow(QAndroidPlatformWindow *window) +{ + if (window->parent()) + return; + + m_windowStack.removeOne(window); + if (window->isRaster()) { + setDirty(window->geometry()); + } + QWindow *w = topWindow(); + QWindowSystemInterface::handleWindowActivated(w); + topWindowChanged(w); +} + +void QAndroidPlatformScreen::raise(QAndroidPlatformWindow *window) +{ + if (window->parent()) + return; + + 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) +{ + if (window->parent()) + return; + + 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); + m_repaintRegion += intersection; + 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_nativeSurface) { + ANativeWindow_release(m_nativeSurface); + m_nativeSurface = 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_nativeSurface) + return; + + ANativeWindow_Buffer nativeWindowBuffer; + ARect nativeWindowRect; + QRect br = m_repaintRegion.boundingRect(); + nativeWindowRect.top = br.top(); + nativeWindowRect.left = br.left(); + nativeWindowRect.bottom = br.bottom() + 1; // for some reason that I don't understand the QRect bottom needs to +1 to be the same with ARect bottom + nativeWindowRect.right = br.right() + 1; // same for the right + + int ret; + if ((ret = ANativeWindow_lock(m_nativeSurface, &nativeWindowBuffer, &nativeWindowRect)) < 0) { + qWarning() << "ANativeWindow_lock() failed! error=" << ret; + return; + } + + int bpp = 4; + QImage::Format format = QImage::Format_RGBA8888_Premultiplied; + if (nativeWindowBuffer.format == WINDOW_FORMAT_RGB_565) { + bpp = 2; + format = QImage::Format_RGB16; + } + + QImage screenImage(reinterpret_cast<uchar *>(nativeWindowBuffer.bits) + , nativeWindowBuffer.width, nativeWindowBuffer.height + , nativeWindowBuffer.stride * bpp , format); + + QPainter compositePainter(&screenImage); + compositePainter.setCompositionMode(QPainter::CompositionMode_Source); + + 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) + compositePainter.drawImage(targetRect.topLeft(), backingStore->image(), windowRect); + } + } + + foreach (const QRect &rect, visibleRegion.rects()) { + compositePainter.fillRect(rect, QColor(Qt::transparent)); + } + } + + ret = ANativeWindow_unlockAndPost(m_nativeSurface); + if (ret >= 0) + m_repaintRegion = QRegion(); +} + +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(); + if (surface && w && h) { + if (m_nativeSurface) + ANativeWindow_release(m_nativeSurface); + m_nativeSurface = ANativeWindow_fromSurface(env, surface); + } else { + if (m_nativeSurface) { + ANativeWindow_release(m_nativeSurface); + m_nativeSurface = 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..d3de937548 --- /dev/null +++ b/src/plugins/platforms/android/qandroidplatformscreen.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** 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" + +#include <android/native_window.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; + ANativeWindow* m_nativeSurface = nullptr; + QWaitCondition m_surfaceWaitCondition; +}; + +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..b4231f0283 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,122 @@ ****************************************************************************/ #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); +void QAndroidPlatformWindow::setParent(const QPlatformWindow *window) +{ + Q_UNUSED(window); +} - // 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(); +QAndroidPlatformScreen *QAndroidPlatformWindow::platformScreen() const +{ + return static_cast<QAndroidPlatformScreen *>(window()->screen()->handle()); +} + +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..764dd3ab86 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 setWindowState(Qt::WindowState state); - void setVisible(bool visible); - void destroy(); + void setWindowState(Qt::WindowState state); + void setWindowFlags(Qt::WindowFlags flags); + Qt::WindowFlags windowFlags() const; + void setParent(const QPlatformWindow *window); + WId winId() const { return m_windowId; } + + 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/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm index f9767ce716..327ca00ad6 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm +++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm @@ -114,7 +114,7 @@ static void cleanupCocoaApplicationDelegate() - (void)updateScreens:(NSNotification *)notification { Q_UNUSED(notification); - if (QCocoaIntegration *ci = dynamic_cast<QCocoaIntegration *>(QGuiApplicationPrivate::platformIntegration())) + if (QCocoaIntegration *ci = QCocoaIntegration::instance()) ci->updateScreens(); } 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/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h index 111329aaee..8babfcf8ae 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.h +++ b/src/plugins/platforms/cocoa/qcocoaintegration.h @@ -46,6 +46,10 @@ #include "qcocoaautoreleasepool.h" #include "qcocoacursor.h" +#include "qcocoawindow.h" +#include "qcocoanativeinterface.h" +#include "qcocoainputcontext.h" +#include "qcocoaaccessibility.h" #include "qcocoaclipboard.h" #include "qcocoadrag.h" #include "qcocoaservices.h" @@ -53,6 +57,7 @@ #include <QtCore/QScopedPointer> #include <qpa/qplatformintegration.h> +#include <QtPlatformSupport/private/qcoretextfontdatabase_p.h> QT_BEGIN_NAMESPACE @@ -103,23 +108,25 @@ public: QCocoaIntegration(); ~QCocoaIntegration(); + static QCocoaIntegration *instance(); + bool hasCapability(QPlatformIntegration::Capability cap) const; QPlatformWindow *createPlatformWindow(QWindow *window) const; QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; QPlatformBackingStore *createPlatformBackingStore(QWindow *widget) const; QAbstractEventDispatcher *createEventDispatcher() const; - QPlatformFontDatabase *fontDatabase() const; - QPlatformNativeInterface *nativeInterface() const; - QPlatformInputContext *inputContext() const; - QPlatformAccessibility *accessibility() const; - QPlatformClipboard *clipboard() const; - QPlatformDrag *drag() const; + QCoreTextFontDatabase *fontDatabase() const; + QCocoaNativeInterface *nativeInterface() const; + QCocoaInputContext *inputContext() const; + QCocoaAccessibility *accessibility() const; + QCocoaClipboard *clipboard() const; + QCocoaDrag *drag() const; QStringList themeNames() const; QPlatformTheme *createPlatformTheme(const QString &name) const; - QPlatformServices *services() const; + QCocoaServices *services() const; QVariant styleHint(StyleHint hint) const; QList<int> possibleKeys(const QKeyEvent *event) const; @@ -128,18 +135,19 @@ public: QCocoaScreen *screenAtIndex(int index); private: + static QCocoaIntegration *mInstance; - QScopedPointer<QPlatformFontDatabase> mFontDb; + QScopedPointer<QCoreTextFontDatabase> mFontDb; - QScopedPointer<QPlatformInputContext> mInputContext; + QScopedPointer<QCocoaInputContext> mInputContext; #ifndef QT_NO_ACCESSIBILITY - QScopedPointer<QPlatformAccessibility> mAccessibility; + QScopedPointer<QCocoaAccessibility> mAccessibility; #endif QScopedPointer<QPlatformTheme> mPlatformTheme; QList<QCocoaScreen *> mScreens; QCocoaClipboard *mCocoaClipboard; QScopedPointer<QCocoaDrag> mCocoaDrag; - QScopedPointer<QPlatformNativeInterface> mNativeInterface; + QScopedPointer<QCocoaNativeInterface> mNativeInterface; QScopedPointer<QCocoaServices> mServices; QScopedPointer<QCocoaKeyMapper> mKeyboardMapper; }; diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 5f01274d98..e8cf5ca69b 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -58,7 +58,6 @@ #include <qpa/qplatformaccessibility.h> #include <QtCore/qcoreapplication.h> -#include <QtPlatformSupport/private/qcoretextfontdatabase_p.h> #include <IOKit/graphics/IOGraphicsLib.h> static void initResources() @@ -214,6 +213,8 @@ QPixmap QCocoaScreen::grabWindow(WId window, int x, int y, int width, int height return windowPixmap; } +QCocoaIntegration *QCocoaIntegration::mInstance = 0; + QCocoaIntegration::QCocoaIntegration() : mFontDb(new QCoreTextFontDatabase()) , mInputContext(new QCocoaInputContext) @@ -226,6 +227,10 @@ QCocoaIntegration::QCocoaIntegration() , mServices(new QCocoaServices) , mKeyboardMapper(new QCocoaKeyMapper) { + if (mInstance != 0) + qWarning("Creating multiple Cocoa platform integrations is not supported"); + mInstance = this; + initResources(); QCocoaAutoReleasePool pool; @@ -273,6 +278,8 @@ QCocoaIntegration::QCocoaIntegration() QCocoaIntegration::~QCocoaIntegration() { + mInstance = 0; + qt_resetNSApplicationSendEvent(); QCocoaAutoReleasePool pool; @@ -296,6 +303,11 @@ QCocoaIntegration::~QCocoaIntegration() } } +QCocoaIntegration *QCocoaIntegration::instance() +{ + return mInstance; +} + /*! \brief Synchronizes the screen list, adds new screens, removes deleted ones */ @@ -388,22 +400,22 @@ QAbstractEventDispatcher *QCocoaIntegration::createEventDispatcher() const return new QCocoaEventDispatcher; } -QPlatformFontDatabase *QCocoaIntegration::fontDatabase() const +QCoreTextFontDatabase *QCocoaIntegration::fontDatabase() const { return mFontDb.data(); } -QPlatformNativeInterface *QCocoaIntegration::nativeInterface() const +QCocoaNativeInterface *QCocoaIntegration::nativeInterface() const { return mNativeInterface.data(); } -QPlatformInputContext *QCocoaIntegration::inputContext() const +QCocoaInputContext *QCocoaIntegration::inputContext() const { return mInputContext.data(); } -QPlatformAccessibility *QCocoaIntegration::accessibility() const +QCocoaAccessibility *QCocoaIntegration::accessibility() const { #ifndef QT_NO_ACCESSIBILITY return mAccessibility.data(); @@ -412,12 +424,12 @@ QPlatformAccessibility *QCocoaIntegration::accessibility() const #endif } -QPlatformClipboard *QCocoaIntegration::clipboard() const +QCocoaClipboard *QCocoaIntegration::clipboard() const { return mCocoaClipboard; } -QPlatformDrag *QCocoaIntegration::drag() const +QCocoaDrag *QCocoaIntegration::drag() const { return mCocoaDrag.data(); } @@ -434,7 +446,7 @@ QPlatformTheme *QCocoaIntegration::createPlatformTheme(const QString &name) cons return QPlatformIntegration::createPlatformTheme(name); } -QPlatformServices *QCocoaIntegration::services() const +QCocoaServices *QCocoaIntegration::services() const { return mServices.data(); } diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.h b/src/plugins/platforms/cocoa/qcocoanativeinterface.h index 5c59c73847..4bcb348acb 100644 --- a/src/plugins/platforms/cocoa/qcocoanativeinterface.h +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.h @@ -137,6 +137,7 @@ private: static void setContentBorderThickness(QWindow *window, int topThickness, int bottomThickness); }; +QT_END_NAMESPACE + #endif // QCOCOANATIVEINTERFACE_H -QT_END_NAMESPACE 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 452be90108..7b9768fcd9 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -52,34 +52,32 @@ QT_FORWARD_DECLARE_CLASS(QCocoaWindow) -@interface QNSWindow : NSWindow { - @public QCocoaWindow *m_cocoaPlatformWindow; -} - -- (void)clearPlatformWindow; -- (BOOL)canBecomeKeyWindow; -@end +@class QNSWindowDelegate; -@interface QNSPanel : NSPanel { - @public QCocoaWindow *m_cocoaPlatformWindow; +@interface QNSWindow : NSPanel { +@public + QCocoaWindow *m_cocoaPlatformWindow; } + - (void)clearPlatformWindow; -- (BOOL)canBecomeKeyWindow; @end -@class QNSWindowDelegate; - QT_BEGIN_NAMESPACE + // QCocoaWindow // -// QCocoaWindow is an NSView (not an NSWindow!) in the sense -// that it relies on a NSView for all event handling and -// graphics output and does not require a NSWindow, except for -// for the window-related functions like setWindowTitle. +// A QCocoaWindow is backed by a NSView and optionally a NSWindow. +// +// The NSView is used for most event handling and graphics output. // -// As a consequence of this it is possible to embed the QCocoaWindow -// in an NSView hierarchy by getting a pointer to the "backing" -// NSView and not calling QCocoaWindow::show(): +// Top-level QWindows are always backed by a NSWindow in addition to +// the NSView. Child QWindows can also be backed by NSWindows, which +// enables proper stacking of GL Widgets and threaded GL rendering +// to multiple contexts. +// +// It is possible to embed the QCocoaWindow in an NSView hierarchy +// by getting a pointer to the backing NSView and not calling +// QCocoaWindow::show(): // // QWindow *qtWindow = new MyWindow(); // qtWindow->create(); @@ -100,6 +98,10 @@ public: void setGeometry(const QRect &rect); void setCocoaGeometry(const QRect &rect); + void clipChildWindows(); + void clipWindow(const NSRect &clipRect); + void show(bool becauseOfAncestor = false); + void hide(bool becauseOfAncestor = false); void setVisible(bool visible); void setWindowFlags(Qt::WindowFlags flags); void setWindowState(Qt::WindowState state); @@ -135,6 +137,7 @@ public: void windowDidResize(); bool windowShouldClose(); bool windowIsPopupType(Qt::WindowType type = Qt::Widget) const; + bool windowShouldBehaveAsPanel() const; void setSynchedWindowStateFromWindow(); @@ -167,16 +170,16 @@ public: void updateExposedGeometry(); QWindow *childWindowAt(QPoint windowPoint); protected: - // NSWindow handling. The QCocoaWindow/QNSView can either be displayed - // in an existing NSWindow or in one created by Qt. void recreateWindow(const QPlatformWindow *parentWindow); - NSWindow *createNSWindow(); - void setNSWindow(NSWindow *window); - void clearNSWindow(NSWindow *window); + QNSWindow *createNSWindow(); + void setNSWindow(QNSWindow *window); + void clearNSWindow(QNSWindow *window); QRect windowGeometry() const; QCocoaWindow *parentCocoaWindow() const; void syncWindowState(Qt::WindowState newState); + void reinsertChildWindow(QCocoaWindow *child); + void removeChildWindow(QCocoaWindow *child); // private: public: // for QNSView @@ -185,12 +188,17 @@ public: // for QNSView NSView *m_contentView; QNSView *m_qtView; - NSWindow *m_nsWindow; + QNSWindow *m_nsWindow; + QCocoaWindow *m_forwardWindow; // TODO merge to one variable if possible bool m_contentViewIsEmbedded; // true if the m_contentView is actually embedded in a "foreign" NSView hiearchy bool m_contentViewIsToBeEmbedded; // true if the m_contentView is intended to be embedded in a "foreign" NSView hiearchy + QCocoaWindow *m_parentCocoaWindow; + bool m_isNSWindowChild; // this window is a non-top level QWindow with a NSWindow. + QList<QCocoaWindow *> m_childWindows; + QNSWindowDelegate *m_nsWindowDelegate; Qt::WindowFlags m_windowFlags; Qt::WindowState m_synchedWindowState; @@ -211,6 +219,8 @@ public: // for QNSView QRect m_exposedGeometry; int m_registerTouchCount; bool m_resizableTransientParent; + bool m_hiddenByClipping; + bool m_hiddenByAncestor; static const int NoAlertRequest; NSInteger m_alertRequest; @@ -219,6 +229,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 211ecd60ab..70a08bbea5 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -80,15 +80,10 @@ static bool isMouseEvent(NSEvent *ev) } @interface NSWindow (CocoaWindowCategory) -- (void) clearPlatformWindow; - (NSRect) legacyConvertRectFromScreen:(NSRect) rect; @end @implementation NSWindow (CocoaWindowCategory) -- (void) clearPlatformWindow -{ -} - - (NSRect) legacyConvertRectFromScreen:(NSRect) rect { #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 @@ -104,11 +99,40 @@ static bool isMouseEvent(NSEvent *ev) @implementation QNSWindow +- (id)initWithContentRect:(NSRect)contentRect + styleMask:(NSUInteger)windowStyle + qPlatformWindow:(QCocoaWindow *)qpw +{ + self = [super initWithContentRect:contentRect + styleMask:windowStyle + backing:NSBackingStoreBuffered + defer:NO]; // Deferring window creation breaks OpenGL (the GL context is + // set up before the window is shown and needs a proper window) + + if (self) { + m_cocoaPlatformWindow = qpw; + } + return self; +} + - (BOOL)canBecomeKeyWindow { - // The default implementation returns NO for title-bar less windows, - // override and return yes here to make sure popup windows such as - // the combobox popup can become the key window. + // Prevent child NSWindows from becoming the key window in + // order keep the active apperance of the top-level window. + if (!m_cocoaPlatformWindow || m_cocoaPlatformWindow->m_isNSWindowChild) + return NO; + + // Only tool or dialog windows should become key: + if (m_cocoaPlatformWindow && m_cocoaPlatformWindow->windowShouldBehaveAsPanel()) { + Qt::WindowType type = m_cocoaPlatformWindow->window()->type(); + if (type == Qt::Tool || type == Qt::Dialog) + return YES; + return NO; + } + + // All other windows can become the key window. This includes + // popup windows such as the combobox popup, which is a title-bar + // less window that by default can't become key. return YES; } @@ -118,7 +142,11 @@ static bool isMouseEvent(NSEvent *ev) // Windows with a transient parent (such as combobox popup windows) // cannot become the main window: - if (!m_cocoaPlatformWindow || m_cocoaPlatformWindow->window()->transientParent()) + if (!m_cocoaPlatformWindow || m_cocoaPlatformWindow->m_isNSWindowChild + || m_cocoaPlatformWindow->window()->transientParent()) + canBecomeMain = NO; + + if (m_cocoaPlatformWindow && m_cocoaPlatformWindow->windowShouldBehaveAsPanel()) canBecomeMain = NO; return canBecomeMain; @@ -126,47 +154,24 @@ static bool isMouseEvent(NSEvent *ev) - (void) sendEvent: (NSEvent*) theEvent { - [super sendEvent: theEvent]; + if (m_cocoaPlatformWindow && m_cocoaPlatformWindow->m_forwardWindow) { + if (theEvent.type == NSLeftMouseUp || theEvent.type == NSLeftMouseDragged) { + QNSView *forwardView = m_cocoaPlatformWindow->m_qtView; + if (theEvent.type == NSLeftMouseUp) { + [forwardView mouseUp:theEvent]; + m_cocoaPlatformWindow->m_forwardWindow = 0; + } else { + [forwardView mouseDragged:theEvent]; + } - if (!m_cocoaPlatformWindow) - return; + return; + } - if (m_cocoaPlatformWindow->frameStrutEventsEnabled() && isMouseEvent(theEvent)) { - NSPoint loc = [theEvent locationInWindow]; - NSRect windowFrame = [self legacyConvertRectFromScreen:[self frame]]; - NSRect contentFrame = [[self contentView] frame]; - if (NSMouseInRect(loc, windowFrame, NO) && - !NSMouseInRect(loc, contentFrame, NO)) - { - QNSView *contentView = (QNSView *) m_cocoaPlatformWindow->contentView(); - [contentView handleFrameStrutMouseEvent: theEvent]; + if (theEvent.type == NSLeftMouseDown) { + m_cocoaPlatformWindow->m_forwardWindow = 0; } } -} - -- (void)clearPlatformWindow -{ - m_cocoaPlatformWindow = 0; -} - -@end - -@implementation QNSPanel - -- (BOOL)canBecomeKeyWindow -{ - if (!m_cocoaPlatformWindow) - return NO; - // Only tool or dialog windows should become key: - if (m_cocoaPlatformWindow - && (m_cocoaPlatformWindow->window()->type() == Qt::Tool || m_cocoaPlatformWindow->window()->type() == Qt::Dialog)) - return YES; - return NO; -} - -- (void) sendEvent: (NSEvent*) theEvent -{ [super sendEvent: theEvent]; if (!m_cocoaPlatformWindow) @@ -199,8 +204,11 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw) , m_contentView(nil) , m_qtView(nil) , m_nsWindow(0) + , m_forwardWindow(0) , m_contentViewIsEmbedded(false) , m_contentViewIsToBeEmbedded(false) + , m_parentCocoaWindow(0) + , m_isNSWindowChild(false) , m_nsWindowDelegate(0) , m_synchedWindowState(Qt::WindowActive) , m_windowModality(Qt::NonModal) @@ -215,11 +223,14 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw) , m_isExposed(false) , m_registerTouchCount(0) , m_resizableTransientParent(false) + , m_hiddenByClipping(false) + , m_hiddenByAncestor(false) , m_alertRequest(NoAlertRequest) , monitor(nil) , 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; @@ -259,8 +270,21 @@ QCocoaWindow::~QCocoaWindow() QCocoaAutoReleasePool pool; clearNSWindow(m_nsWindow); - if (parent()) + if (m_isNSWindowChild) { + if (m_parentCocoaWindow) + m_parentCocoaWindow->removeChildWindow(this); + } else if (parent()) { [m_contentView removeFromSuperview]; + } else if (m_qtView) { + [[NSNotificationCenter defaultCenter] removeObserver:m_qtView + name:nil object:m_nsWindow]; + } + + foreach (QCocoaWindow *child, m_childWindows) { + [m_nsWindow removeChildWindow:child->m_nsWindow]; + child->m_parentCocoaWindow = 0; + } + [m_contentView release]; [m_nsWindow release]; [m_nsWindowDelegate release]; @@ -272,8 +296,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 @@ -291,7 +323,16 @@ void QCocoaWindow::setCocoaGeometry(const QRect &rect) return; } - if (m_nsWindow) { + if (m_isNSWindowChild) { + QPlatformWindow::setGeometry(rect); + NSWindow *parentNSWindow = m_parentCocoaWindow->m_nsWindow; + NSRect parentWindowFrame = [parentNSWindow contentRectForFrameRect:parentNSWindow.frame]; + clipWindow(parentWindowFrame); + + // call this here: updateGeometry in qnsview.mm is a no-op for this case + QWindowSystemInterface::handleGeometryChange(window(), rect); + QWindowSystemInterface::handleExposeEvent(window(), rect); + } else if (m_nsWindow) { NSRect bounds = qt_mac_flipRect(rect, window()); [m_nsWindow setFrame:[m_nsWindow frameRectForContentRect:bounds] display:YES animate:NO]; } else { @@ -301,8 +342,99 @@ void QCocoaWindow::setCocoaGeometry(const QRect &rect) // will call QPlatformWindow::setGeometry(rect) during resize confirmation (see qnsview.mm) } +void QCocoaWindow::clipChildWindows() +{ + foreach (QCocoaWindow *childWindow, m_childWindows) { + childWindow->clipWindow(m_nsWindow.frame); + } +} + +void QCocoaWindow::clipWindow(const NSRect &clipRect) +{ + if (!m_isNSWindowChild) + return; + + NSRect clippedWindowRect = NSZeroRect; + if (!NSIsEmptyRect(clipRect)) { + NSRect windowFrame = qt_mac_flipRect(QRect(window()->mapToGlobal(QPoint(0, 0)), geometry().size()), window()); + clippedWindowRect = NSIntersectionRect(windowFrame, clipRect); + // Clipping top/left offsets the content. Move it back. + NSPoint contentViewOffset = NSMakePoint(qMax(CGFloat(0), NSMinX(clippedWindowRect) - NSMinX(windowFrame)), + qMax(CGFloat(0), NSMaxY(windowFrame) - NSMaxY(clippedWindowRect))); + [m_contentView setBoundsOrigin:contentViewOffset]; + } + + if (NSIsEmptyRect(clippedWindowRect)) { + if (!m_hiddenByClipping) { + // We dont call hide() here as we will recurse further down + [m_nsWindow orderOut:nil]; + m_hiddenByClipping = true; + } + } else { + [m_nsWindow setFrame:clippedWindowRect display:YES animate:NO]; + if (m_hiddenByClipping) { + m_hiddenByClipping = false; + if (!m_hiddenByAncestor) { + [m_nsWindow orderFront:nil]; + m_parentCocoaWindow->reinsertChildWindow(this); + } + } + } + + // recurse + foreach (QCocoaWindow *childWindow, m_childWindows) { + childWindow->clipWindow(clippedWindowRect); + } +} + +void QCocoaWindow::hide(bool becauseOfAncestor) +{ + bool visible = [m_nsWindow isVisible]; + + if (!m_hiddenByAncestor && !visible) // Already explicitly hidden + return; + if (m_hiddenByAncestor && becauseOfAncestor) // Trying to hide some child again + return; + + m_hiddenByAncestor = becauseOfAncestor; + + if (!visible) // Could have been clipped before + return; + + foreach (QCocoaWindow *childWindow, m_childWindows) + childWindow->hide(true); + + [m_nsWindow orderOut:nil]; +} + +void QCocoaWindow::show(bool becauseOfAncestor) +{ + if ([m_nsWindow isVisible]) + return; + + if (m_parentCocoaWindow && ![m_parentCocoaWindow->m_nsWindow isVisible]) { + m_hiddenByAncestor = true; // Parent still hidden, don't show now + } else if ((becauseOfAncestor == m_hiddenByAncestor) // Was NEITHER explicitly hidden + && !m_hiddenByClipping) { // ... NOR clipped + if (m_isNSWindowChild) { + m_hiddenByAncestor = false; + setCocoaGeometry(window()->geometry()); + } + if (!m_hiddenByClipping) { // setCocoaGeometry() can change the clipping status + [m_nsWindow orderFront:nil]; + if (m_isNSWindowChild) + m_parentCocoaWindow->reinsertChildWindow(this); + foreach (QCocoaWindow *childWindow, m_childWindows) + childWindow->show(true); + } + } +} + void QCocoaWindow::setVisible(bool visible) { + if (m_isNSWindowChild && m_hiddenByClipping) + return; + QCocoaAutoReleasePool pool; QCocoaWindow *parentCocoaWindow = 0; if (window()->transientParent()) @@ -367,8 +499,10 @@ void QCocoaWindow::setVisible(bool visible) m_hasModalSession = true; } else if ([m_nsWindow canBecomeKeyWindow]) { [m_nsWindow makeKeyAndOrderFront:nil]; + foreach (QCocoaWindow *childWindow, m_childWindows) + childWindow->show(true); } else { - [m_nsWindow orderFront: nil]; + show(); } // We want the events to properly reach the popup, dialog, and tool @@ -392,28 +526,27 @@ void QCocoaWindow::setVisible(bool visible) // qDebug() << "close" << this; if (m_glContext) m_glContext->windowWasHidden(); + QCocoaEventDispatcher *cocoaEventDispatcher = qobject_cast<QCocoaEventDispatcher *>(QGuiApplication::instance()->eventDispatcher()); + Q_ASSERT(cocoaEventDispatcher != 0); + QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = static_cast<QCocoaEventDispatcherPrivate *>(QObjectPrivate::get(cocoaEventDispatcher)); if (m_nsWindow) { if (m_hasModalSession) { - QCocoaEventDispatcher *cocoaEventDispatcher = qobject_cast<QCocoaEventDispatcher *>(QGuiApplication::instance()->eventDispatcher()); - Q_ASSERT(cocoaEventDispatcher != 0); - QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = static_cast<QCocoaEventDispatcherPrivate *>(QObjectPrivate::get(cocoaEventDispatcher)); cocoaEventDispatcherPrivate->endModalSession(window()); m_hasModalSession = false; - - [m_nsWindow orderOut:m_nsWindow]; - if (m_nsWindow == [NSApp keyWindow] && !cocoaEventDispatcherPrivate->currentModalSession()) { - // Probably because we call runModalSession: outside [NSApp run] in QCocoaEventDispatcher - // (e.g., when show()-ing a modal QDialog instead of exec()-ing it), it can happen that - // the current NSWindow is still key after being ordered out. Then, after checking we - // don't have any other modal session left, it's safe to make the main window key again. - NSWindow *mainWindow = [NSApp mainWindow]; - if (mainWindow && [mainWindow canBecomeKeyWindow]) - [mainWindow makeKeyWindow]; - } } else { if ([m_nsWindow isSheet]) [NSApp endSheet:m_nsWindow]; - [m_nsWindow orderOut:m_nsWindow]; + } + + hide(); + if (m_nsWindow == [NSApp keyWindow] && !cocoaEventDispatcherPrivate->currentModalSession()) { + // Probably because we call runModalSession: outside [NSApp run] in QCocoaEventDispatcher + // (e.g., when show()-ing a modal QDialog instead of exec()-ing it), it can happen that + // the current NSWindow is still key after being ordered out. Then, after checking we + // don't have any other modal session left, it's safe to make the main window key again. + NSWindow *mainWindow = [NSApp mainWindow]; + if (mainWindow && [mainWindow canBecomeKeyWindow]) + [mainWindow makeKeyWindow]; } } else { [m_contentView setHidden:YES]; @@ -520,7 +653,7 @@ void QCocoaWindow::setWindowShadow(Qt::WindowFlags flags) void QCocoaWindow::setWindowFlags(Qt::WindowFlags flags) { - if (m_nsWindow) { + if (m_nsWindow && !m_isNSWindowChild) { NSUInteger styleMask = windowStyleMask(flags); NSInteger level = this->windowLevel(flags); [m_nsWindow setStyleMask:styleMask]; @@ -532,15 +665,21 @@ void QCocoaWindow::setWindowFlags(Qt::WindowFlags flags) #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { - Qt::WindowType type = window()->type(); - if ((type & Qt::Popup) != Qt::Popup && (type & Qt::Dialog) != Qt::Dialog) { - NSWindowCollectionBehavior behavior = [m_nsWindow collectionBehavior]; + NSWindowCollectionBehavior behavior = [m_nsWindow collectionBehavior]; + if (windowShouldBehaveAsPanel()) { + behavior &= ~NSWindowCollectionBehaviorFullScreenPrimary; + behavior |= NSWindowCollectionBehaviorFullScreenAuxiliary; + } else { if (flags & Qt::WindowFullscreenButtonHint) behavior |= NSWindowCollectionBehaviorFullScreenPrimary; else behavior &= ~NSWindowCollectionBehaviorFullScreenPrimary; - [m_nsWindow setCollectionBehavior:behavior]; } + [m_nsWindow setCollectionBehavior:behavior]; + + [m_nsWindow setAnimationBehavior:(flags & Qt::Popup) == Qt::Popup + ? NSWindowAnimationBehaviorUtilityWindow + : NSWindowAnimationBehaviorDefault]; } #endif } @@ -618,16 +757,55 @@ void QCocoaWindow::raise() // ### handle spaces (see Qt 4 raise_sys in qwidget_mac.mm) if (!m_nsWindow) return; - if ([m_nsWindow isVisible]) - [m_nsWindow orderFront: m_nsWindow]; + if (m_isNSWindowChild) { + QList<QCocoaWindow *> &siblings = m_parentCocoaWindow->m_childWindows; + siblings.removeOne(this); + siblings.append(this); + if (m_hiddenByClipping) + return; + } + if ([m_nsWindow isVisible]) { + if (m_isNSWindowChild) { + // -[NSWindow orderFront:] doesn't work with attached windows. + // The only solution is to remove and add the child window. + // This will place it on top of all the other NSWindows. + NSWindow *parentNSWindow = m_parentCocoaWindow->m_nsWindow; + [parentNSWindow removeChildWindow:m_nsWindow]; + [parentNSWindow addChildWindow:m_nsWindow ordered:NSWindowAbove]; + } else { + [m_nsWindow orderFront: m_nsWindow]; + } + } } void QCocoaWindow::lower() { if (!m_nsWindow) return; - if ([m_nsWindow isVisible]) - [m_nsWindow orderBack: m_nsWindow]; + if (m_isNSWindowChild) { + QList<QCocoaWindow *> &siblings = m_parentCocoaWindow->m_childWindows; + siblings.removeOne(this); + siblings.prepend(this); + if (m_hiddenByClipping) + return; + } + if ([m_nsWindow isVisible]) { + if (m_isNSWindowChild) { + // -[NSWindow orderBack:] doesn't work with attached windows. + // The only solution is to remove and add all the child windows except this one. + // This will keep the current window at the bottom while adding the others on top of it, + // hopefully in the same order (this is not documented anywhere in the Cocoa documentation). + NSWindow *parentNSWindow = m_parentCocoaWindow->m_nsWindow; + NSArray *children = [parentNSWindow.childWindows copy]; + for (NSWindow *child in children) + if (m_nsWindow != child) { + [parentNSWindow removeChildWindow:child]; + [parentNSWindow addChildWindow:child ordered:NSWindowAbove]; + } + } else { + [m_nsWindow orderBack: m_nsWindow]; + } + } } bool QCocoaWindow::isExposed() const @@ -773,6 +951,9 @@ void QCocoaWindow::windowWillMove() void QCocoaWindow::windowDidMove() { + if (m_isNSWindowChild) + return; + [m_qtView updateGeometry]; } @@ -781,6 +962,10 @@ void QCocoaWindow::windowDidResize() if (!m_nsWindow) return; + if (m_isNSWindowChild) + return; + + clipChildWindows(); [m_qtView updateGeometry]; } @@ -808,6 +993,14 @@ bool QCocoaWindow::windowIsPopupType(Qt::WindowType type) const return ((type & Qt::Popup) == Qt::Popup); } +bool QCocoaWindow::windowShouldBehaveAsPanel() const +{ + // Before merging QNSPanel and QNSWindow, we used NSPanel for popup-type + // windows (Popup, Tool, ToolTip, SplashScreen) and dialogs + Qt::WindowType type = window()->type(); + return (type & Qt::Popup) == Qt::Popup || (type & Qt::Dialog) == Qt::Dialog; +} + void QCocoaWindow::setCurrentContext(QCocoaGLContext *context) { m_glContext = context; @@ -820,8 +1013,18 @@ QCocoaGLContext *QCocoaWindow::currentContext() const void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) { + bool wasNSWindowChild = m_isNSWindowChild; + bool needsNSWindow = m_isNSWindowChild || !parentWindow; + + QCocoaWindow *oldParentCocoaWindow = m_parentCocoaWindow; + m_parentCocoaWindow = const_cast<QCocoaWindow *>(static_cast<const QCocoaWindow *>(parentWindow)); + + // No child QNSWindow should notify its QNSView + if (m_nsWindow && m_qtView && m_parentCocoaWindow && !oldParentCocoaWindow) + [[NSNotificationCenter defaultCenter] removeObserver:m_qtView + name:nil object:m_nsWindow]; // Remove current window (if any) - if (m_nsWindow) { + if (m_nsWindow && !needsNSWindow) { clearNSWindow(m_nsWindow); [m_nsWindow close]; [m_nsWindow release]; @@ -830,22 +1033,64 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) m_nsWindowDelegate = 0; } + if (needsNSWindow) { + bool noPreviousWindow = m_nsWindow == 0; + if (noPreviousWindow) + m_nsWindow = createNSWindow(); + + // Only non-child QNSWindows should notify their QNSViews + // (but don't register more than once). + if (m_qtView && (noPreviousWindow || (wasNSWindowChild && !m_isNSWindowChild))) + [[NSNotificationCenter defaultCenter] addObserver:m_qtView + selector:@selector(windowNotification:) + name:nil // Get all notifications + object:m_nsWindow]; + + if (oldParentCocoaWindow) { + if (!m_isNSWindowChild || oldParentCocoaWindow != m_parentCocoaWindow) + oldParentCocoaWindow->removeChildWindow(this); + m_forwardWindow = oldParentCocoaWindow; + } + + setNSWindow(m_nsWindow); + } + + if (m_contentViewIsToBeEmbedded) { // An embedded window doesn't have its own NSWindow. } else if (!parentWindow) { - // Create a new NSWindow if this is a top-level window. - m_nsWindow = createNSWindow(); - setNSWindow(m_nsWindow); - // QPlatformWindow subclasses must sync up with QWindow on creation: propagateSizeHints(); setWindowFlags(window()->flags()); setWindowTitle(window()->title()); setWindowState(window()->windowState()); + } else if (m_isNSWindowChild) { + m_nsWindow.styleMask = NSBorderlessWindowMask; + m_nsWindow.hasShadow = NO; + m_nsWindow.level = NSNormalWindowLevel; + NSWindowCollectionBehavior collectionBehavior = + NSWindowCollectionBehaviorManaged | NSWindowCollectionBehaviorIgnoresCycle; +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 + if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { + collectionBehavior |= NSWindowCollectionBehaviorFullScreenAuxiliary; + m_nsWindow.animationBehavior = NSWindowAnimationBehaviorNone; + } +#endif + m_nsWindow.collectionBehavior = collectionBehavior; + setCocoaGeometry(window()->geometry()); + + QList<QCocoaWindow *> &siblings = m_parentCocoaWindow->m_childWindows; + if (siblings.contains(this)) { + if (!m_hiddenByClipping) + m_parentCocoaWindow->reinsertChildWindow(this); + } else { + if (!m_hiddenByClipping) + [m_parentCocoaWindow->m_nsWindow addChildWindow:m_nsWindow ordered:NSWindowAbove]; + siblings.append(this); + } } else { // Child windows have no NSWindow, link the NSViews instead. - const QCocoaWindow *parentCococaWindow = static_cast<const QCocoaWindow *>(parentWindow); - [parentCococaWindow->m_contentView addSubview : m_contentView]; + [m_parentCocoaWindow->m_contentView addSubview : m_contentView]; QRect rect = window()->geometry(); NSRect frame = NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height()); [m_contentView setFrame:frame]; @@ -857,6 +1102,19 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) setOpacity(opacity); } +void QCocoaWindow::reinsertChildWindow(QCocoaWindow *child) +{ + int childIndex = m_childWindows.indexOf(child); + Q_ASSERT(childIndex != -1); + + for (int i = childIndex; i < m_childWindows.size(); i++) { + NSWindow *nsChild = m_childWindows[i]->m_nsWindow; + if (i != childIndex) + [m_nsWindow removeChildWindow:nsChild]; + [m_nsWindow addChildWindow:nsChild ordered:NSWindowAbove]; + } +} + void QCocoaWindow::requestActivateWindow() { NSWindow *window = [m_contentView window]; @@ -864,63 +1122,33 @@ void QCocoaWindow::requestActivateWindow() [ window makeKeyWindow ]; } -NSWindow * QCocoaWindow::createNSWindow() +QNSWindow * QCocoaWindow::createNSWindow() { QCocoaAutoReleasePool pool; QRect rect = initialGeometry(window(), window()->geometry(), defaultWindowWidth, defaultWindowHeight); NSRect frame = qt_mac_flipRect(rect, window()); - Qt::WindowType type = window()->type(); Qt::WindowFlags flags = window()->flags(); - NSUInteger styleMask = windowStyleMask(flags); - NSWindow *createdWindow = 0; - - // Use NSPanel for popup-type windows. (Popup, Tool, ToolTip, SplashScreen) - // and dialogs - if ((type & Qt::Popup) == Qt::Popup || (type & Qt::Dialog) == Qt::Dialog) { - QNSPanel *window; - window = [[QNSPanel alloc] initWithContentRect:frame - styleMask: styleMask - backing:NSBackingStoreBuffered - defer:NO]; // Deferring window creation breaks OpenGL (the GL context is set up - // before the window is shown and needs a proper window.). - if ((type & Qt::Popup) == Qt::Popup) - [window setHasShadow:YES]; - [window setHidesOnDeactivate: NO]; - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { - // Make popup winows show on the same desktop as the parent full-screen window. - [window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary]; - - if ((type & Qt::Popup) == Qt::Popup) - [window setAnimationBehavior:NSWindowAnimationBehaviorUtilityWindow]; - } -#endif - window->m_cocoaPlatformWindow = this; - createdWindow = window; + NSUInteger styleMask; + if (m_isNSWindowChild) { + styleMask = NSBorderlessWindowMask; } else { - QNSWindow *window; - window = [[QNSWindow alloc] initWithContentRect:frame - styleMask: styleMask - backing:NSBackingStoreBuffered - defer:NO]; // Deferring window creation breaks OpenGL (the GL context is set up - // before the window is shown and needs a proper window.). - window->m_cocoaPlatformWindow = this; - - createdWindow = window; + styleMask = windowStyleMask(flags); } + QNSWindow *createdWindow = [[QNSWindow alloc] initWithContentRect:frame styleMask:styleMask qPlatformWindow:this]; + + Qt::WindowFlags type = window()->type(); + createdWindow.hidesOnDeactivate = type == Qt::Tool || type == Qt::ToolTip; + #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - if ([createdWindow respondsToSelector:@selector(setRestorable:)]) + if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { [createdWindow setRestorable: NO]; + } #endif - NSInteger level = windowLevel(flags); - [createdWindow setLevel:level]; - if (window()->format().alphaBufferSize() > 0) { [createdWindow setBackgroundColor:[NSColor clearColor]]; [createdWindow setOpaque:NO]; @@ -933,10 +1161,12 @@ NSWindow * QCocoaWindow::createNSWindow() return createdWindow; } -void QCocoaWindow::setNSWindow(NSWindow *window) +void QCocoaWindow::setNSWindow(QNSWindow *window) { - m_nsWindowDelegate = [[QNSWindowDelegate alloc] initWithQCocoaWindow:this]; - [window setDelegate:m_nsWindowDelegate]; + if (!m_nsWindowDelegate) { + m_nsWindowDelegate = [[QNSWindowDelegate alloc] initWithQCocoaWindow:this]; + [window setDelegate:m_nsWindowDelegate]; + } // Prevent Cocoa from releasing the window on close. Qt // handles the close event asynchronously and we want to @@ -944,31 +1174,33 @@ void QCocoaWindow::setNSWindow(NSWindow *window) // QCocoaWindow is deleted by Qt. [window setReleasedWhenClosed : NO]; - - if (m_qtView) - [[NSNotificationCenter defaultCenter] addObserver:m_qtView - selector:@selector(windowNotification:) - name:nil // Get all notifications - object:m_nsWindow]; - - [m_contentView setPostsFrameChangedNotifications: NO]; - [window setContentView:m_contentView]; - [m_contentView setPostsFrameChangedNotifications: YES]; + if (window.contentView != m_contentView) { + [m_contentView setPostsFrameChangedNotifications: NO]; + [window setContentView:m_contentView]; + [m_contentView setPostsFrameChangedNotifications: YES]; + } } -void QCocoaWindow::clearNSWindow(NSWindow *window) +void QCocoaWindow::clearNSWindow(QNSWindow *window) { [window setContentView:nil]; [window setDelegate:nil]; [window clearPlatformWindow]; - [[NSNotificationCenter defaultCenter] removeObserver:m_contentView - name:nil object:window]; + if (m_isNSWindowChild) { + m_parentCocoaWindow->removeChildWindow(this); + } +} + +void QCocoaWindow::removeChildWindow(QCocoaWindow *child) +{ + m_childWindows.removeOne(child); + [m_nsWindow removeChildWindow:child->m_nsWindow]; } // Returns the current global screen geometry for the nswindow associated with this window. QRect QCocoaWindow::windowGeometry() const { - if (!m_nsWindow) + if (!m_nsWindow || m_isNSWindowChild) return geometry(); NSRect rect = [m_nsWindow frame]; @@ -1015,13 +1247,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 @@ -1054,16 +1308,21 @@ void QCocoaWindow::setWindowCursor(NSCursor *cursor) // for a popup window.) Qt expects the set cursor to "stick": // it should be accociated with the window until a different // cursor is set. - - // Cocoa has different abstractions. We can set the cursor *now*: - if (m_windowUnderMouse) - [cursor set]; - // or we can set the cursor on mouse enter/leave using tracking - // areas. This is done in QNSView, save the cursor: if (m_windowCursor != cursor) { [m_windowCursor release]; m_windowCursor = [cursor retain]; } + + // Use the built in cursor rect API if the QCocoaWindow has a NSWindow. + // Othervise, set the cursor if this window is under the mouse. In + // this case QNSView::cursorUpdate will set the cursor as the pointer + // moves. + if (m_nsWindow && m_qtView) { + [m_nsWindow invalidateCursorRectsForView : m_qtView]; + } else { + if (m_windowUnderMouse) + [cursor set]; + } } void QCocoaWindow::registerTouch(bool enable) diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index ed9aad1654..58c732de98 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -229,7 +229,21 @@ static QTouchDevice *touchDevice = 0; - (void)updateGeometry { QRect geometry; - if (m_platformWindow->m_nsWindow) { + + if (m_platformWindow->m_isNSWindowChild) { + return; +#if 0 + //geometry = qt_mac_toQRect([self frame]); + qDebug() << "nsview updateGeometry" << m_platformWindow->window(); + QRect screenRect = qt_mac_toQRect([m_platformWindow->m_nsWindow convertRectToScreen:[self frame]]); + qDebug() << "screenRect" << screenRect; + + screenRect.moveTop(qt_mac_flipYCoordinate(screenRect.y() + screenRect.height())); + geometry = QRect(m_platformWindow->window()->parent()->mapFromGlobal(screenRect.topLeft()), screenRect.size()); + qDebug() << "geometry" << geometry; +#endif + //geometry = QRect(screenRect.origin.x, qt_mac_flipYCoordinate(screenRect.origin.y + screenRect.size.height), screenRect.size.width, screenRect.size.height); + } else if (m_platformWindow->m_nsWindow) { // top level window, get window rect and flip y. NSRect rect = [self frame]; NSRect windowRect = [[self window] frame]; @@ -310,10 +324,9 @@ static QTouchDevice *touchDevice = 0; m_platformWindow->exposeWindow(); } else if (notificationName == NSWindowDidChangeScreenNotification) { if (m_window) { - QCocoaIntegration *ci = static_cast<QCocoaIntegration *>(QGuiApplicationPrivate::platformIntegration()); NSUInteger screenIndex = [[NSScreen screens] indexOfObject:self.window.screen]; if (screenIndex != NSNotFound) { - QCocoaScreen *cocoaScreen = ci->screenAtIndex(screenIndex); + QCocoaScreen *cocoaScreen = QCocoaIntegration::instance()->screenAtIndex(screenIndex); QWindowSystemInterface::handleWindowScreenChanged(m_window, cocoaScreen->screen()); } } @@ -551,14 +564,20 @@ static QTouchDevice *touchDevice = 0; QPointF qtWindowPoint; QPointF qtScreenPoint; - [self convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint]; + QNSView *targetView = self; + if (m_platformWindow && m_platformWindow->m_forwardWindow + && (theEvent.type == NSLeftMouseDragged || theEvent.type == NSLeftMouseUp)) { + targetView = m_platformWindow->m_forwardWindow->m_qtView; + } + + [targetView convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint]; ulong timestamp = [theEvent timestamp] * 1000; - QCocoaDrag* nativeDrag = static_cast<QCocoaDrag *>(QGuiApplicationPrivate::platformIntegration()->drag()); + QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag(); nativeDrag->setLastMouseEvent(theEvent, self); Qt::KeyboardModifiers keyboardModifiers = [QNSView convertKeyModifiers:[theEvent modifierFlags]]; - QWindowSystemInterface::handleMouseEvent(m_window, timestamp, qtWindowPoint, qtScreenPoint, m_buttons, keyboardModifiers); + QWindowSystemInterface::handleMouseEvent(targetView->m_window, timestamp, qtWindowPoint, qtScreenPoint, m_buttons, keyboardModifiers); } - (void)handleFrameStrutMouseEvent:(NSEvent *)theEvent @@ -689,8 +708,18 @@ static QTouchDevice *touchDevice = 0; -(void)cursorUpdate:(NSEvent *)theEvent { Q_UNUSED(theEvent) - if (m_platformWindow->m_windowCursor) + // Set the cursor manually if there is no NSWindow. + if (!m_platformWindow->m_nsWindow && m_platformWindow->m_windowCursor) [m_platformWindow->m_windowCursor set]; + else + [super cursorUpdate:theEvent]; +} + +-(void)resetCursorRects +{ + // Use the cursor rect API if there is a NSWindow + if (m_platformWindow->m_nsWindow && m_platformWindow->m_windowCursor) + [self addCursorRect:[self visibleRect] cursor:m_platformWindow->m_windowCursor]; } - (void)mouseMoved:(NSEvent *)theEvent @@ -1619,7 +1648,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) - (NSDragOperation) draggingSourceOperationMaskForLocal:(BOOL)isLocal { Q_UNUSED(isLocal); - QCocoaDrag* nativeDrag = static_cast<QCocoaDrag *>(QGuiApplicationPrivate::platformIntegration()->drag()); + QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag(); return qt_mac_mapDropActions(nativeDrag->currentDrag()->supportedActions()); } @@ -1650,7 +1679,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) QPlatformDragQtResponse response(false, Qt::IgnoreAction, QRect()); if ([sender draggingSource] != nil) { - QCocoaDrag* nativeDrag = static_cast<QCocoaDrag *>(QGuiApplicationPrivate::platformIntegration()->drag()); + QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag(); response = QWindowSystemInterface::handleDrag(m_window, nativeDrag->platformDropData(), qt_windowPoint, qtAllowed); } else { QCocoaDropData mimeData([sender draggingPasteboard]); @@ -1678,14 +1707,14 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) QPlatformDropQtResponse response(false, Qt::IgnoreAction); if ([sender draggingSource] != nil) { - QCocoaDrag* nativeDrag = static_cast<QCocoaDrag *>(QGuiApplicationPrivate::platformIntegration()->drag()); + QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag(); response = QWindowSystemInterface::handleDrop(m_window, nativeDrag->platformDropData(), qt_windowPoint, qtAllowed); } else { QCocoaDropData mimeData([sender draggingPasteboard]); response = QWindowSystemInterface::handleDrop(m_window, &mimeData, qt_windowPoint, qtAllowed); } if (response.isAccepted()) { - QCocoaDrag* nativeDrag = static_cast<QCocoaDrag *>(QGuiApplicationPrivate::platformIntegration()->drag()); + QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag(); nativeDrag->setAcceptedAction(response.acceptedAction()); } return response.isAccepted(); diff --git a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm index e8f26aa8c4..a438950a55 100644 --- a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm +++ b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm @@ -45,7 +45,7 @@ #include "qcocoahelpers.h" #include "qcocoaaccessibility.h" #include "qcocoaaccessibilityelement.h" -#include <qpa/qplatformintegration.h> +#include "qcocoaintegration.h" #include <QtGui/qaccessible.h> #include <QtCore/QDebug> @@ -63,7 +63,7 @@ - (id)accessibilityAttributeValue:(NSString *)attribute { // activate accessibility updates - QGuiApplicationPrivate::platformIntegration()->accessibility()->setActive(true); + QCocoaIntegration::instance()->accessibility()->setActive(true); if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) { if (m_window->accessibleRoot()) diff --git a/src/plugins/platforms/cocoa/qprintengine_mac.mm b/src/plugins/platforms/cocoa/qprintengine_mac.mm index f363b1772f..3e92a45a62 100644 --- a/src/plugins/platforms/cocoa/qprintengine_mac.mm +++ b/src/plugins/platforms/cocoa/qprintengine_mac.mm @@ -591,20 +591,43 @@ void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va return; switch (key) { - case PPK_CollateCopies: + + // The following keys are properties or derived values and so cannot be set + case PPK_PageRect: + break; + case PPK_PaperRect: + break; + case PPK_PaperSources: + break; + case PPK_SupportsMultipleCopies: + break; + case PPK_SupportedResolutions: break; + + // The following keys are settings that are unsupported by the Mac PrintEngine case PPK_ColorMode: break; - case PPK_Creator: + case PPK_CustomBase: break; - case PPK_DocumentName: + case PPK_Duplex: + // TODO Add support using PMSetDuplex / PMGetDuplex + break; + case PPK_FontEmbedding: break; case PPK_PageOrder: + // TODO Check if can be supported via Cups Options break; case PPK_PaperSource: + // TODO Check if can be supported via Cups Options + break; + case PPK_PrinterProgram: break; case PPK_SelectionOption: break; + case PPK_WindowsPageSize: + break; + + // The following keys are properties and settings that are supported by the Mac PrintEngine case PPK_Resolution: { PMPrinter printer; UInt32 count; @@ -633,7 +656,15 @@ void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va PMSessionValidatePageFormat(d->session(), d->format(), kPMDontWantBoolean); break; } - + case PPK_CollateCopies: + PMSetCollate(d->settings(), value.toBool()); + break; + case PPK_Creator: + d->m_creator = value.toString(); + break; + case PPK_DocumentName: + PMPrintSettingsSetJobName(d->settings(), QCFString(value.toString())); + break; case PPK_FullPage: d->fullPage = value.toBool(); break; @@ -642,18 +673,15 @@ void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va PMSetCopies(d->settings(), value.toInt(), false); break; case PPK_Orientation: { - if (d->state == QPrinter::Active) { - qWarning("QMacPrintEngine::setOrientation: Orientation cannot be changed during a print job, ignoring change"); - } else { - QPrinter::Orientation newOrientation = QPrinter::Orientation(value.toInt()); - if (d->hasCustomPaperSize && (d->orient != newOrientation)) - d->customSize = QSizeF(d->customSize.height(), d->customSize.width()); - d->orient = newOrientation; - PMOrientation o = d->orient == QPrinter::Portrait ? kPMPortrait : kPMLandscape; - PMSetOrientation(d->format(), o, false); - PMSessionValidatePageFormat(d->session(), d->format(), kPMDontWantBoolean); - } - break; } + QPrinter::Orientation newOrientation = QPrinter::Orientation(value.toInt()); + if (d->hasCustomPaperSize && (d->orient != newOrientation)) + d->customSize = QSizeF(d->customSize.height(), d->customSize.width()); + d->orient = newOrientation; + PMOrientation o = d->orient == QPrinter::Portrait ? kPMPortrait : kPMLandscape; + PMSetOrientation(d->format(), o, false); + PMSessionValidatePageFormat(d->session(), d->format(), kPMDontWantBoolean); + break; + } case PPK_OutputFileName: d->outputFilename = value.toString(); break; @@ -709,9 +737,7 @@ void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va d->hasCustomPageMargins = true; break; } - - default: - break; + // No default so that compiler will complain if new keys added and not handled in this engine } } @@ -724,16 +750,63 @@ QVariant QMacPrintEngine::property(PrintEnginePropertyKey key) const return *d->valueCache.find(key); switch (key) { - case PPK_CollateCopies: - ret = false; - break; + + // The following keys are settings that are unsupported by the Mac PrintEngine + // Return sensible default values to ensure consistent behavior across platforms case PPK_ColorMode: ret = QPrinter::Color; break; + case PPK_CustomBase: + // Special case, leave null + break; + case PPK_Duplex: + // TODO Add support using PMSetDuplex / PMGetDuplex + ret = QPrinter::DuplexNone; + break; + case PPK_FontEmbedding: + ret = false; + break; + case PPK_PageOrder: + // TODO Check if can be supported via Cups Options + ret = QPrinter::FirstPageFirst; + break; + case PPK_PaperSource: + // TODO Check if can be supported via Cups Options + ret = QPrinter::Auto; + break; + case PPK_PaperSources: { + // TODO Check if can be supported via Cups Options + QList<QVariant> out; + out << int(QPrinter::Auto); + ret = out; + break; + } + case PPK_PrinterProgram: + ret = QString(); + break; + case PPK_SelectionOption: + ret = QString(); + break; + case PPK_WindowsPageSize: + // Special case, leave null + break; + + // The following keys are properties and settings that are supported by the Mac PrintEngine + case PPK_CollateCopies: { + Boolean status; + PMGetCollate(d->settings(), &status); + ret = bool(status); + break; + } case PPK_Creator: + ret = d->m_creator; break; - case PPK_DocumentName: + case PPK_DocumentName: { + CFStringRef name; + PMPrintSettingsGetJobName(d->settings(), &name); + ret = QCFString::toQString(name); break; + } case PPK_FullPage: ret = d->fullPage; break; @@ -757,10 +830,6 @@ QVariant QMacPrintEngine::property(PrintEnginePropertyKey key) const case PPK_OutputFileName: ret = d->outputFilename; break; - case PPK_PageOrder: - break; - case PPK_PaperSource: - break; case PPK_PageRect: { // PageRect is returned in device pixels QRect r; @@ -855,8 +924,7 @@ QVariant QMacPrintEngine::property(PrintEnginePropertyKey key) const ret = margins; break; } - default: - break; + // No default so that compiler will complain if new keys added and not handled in this engine } return ret; } diff --git a/src/plugins/platforms/cocoa/qprintengine_mac_p.h b/src/plugins/platforms/cocoa/qprintengine_mac_p.h index 644a07184f..e3a8520811 100644 --- a/src/plugins/platforms/cocoa/qprintengine_mac_p.h +++ b/src/plugins/platforms/cocoa/qprintengine_mac_p.h @@ -125,6 +125,7 @@ public: NSPrintInfo *printInfo; PMResolution resolution; QString outputFilename; + QString m_creator; bool fullPage; QPaintEngine *paintEngine; bool hasCustomPaperSize; 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..4f986b57d7 --- /dev/null +++ b/src/plugins/platforms/direct2d/direct2d.pro @@ -0,0 +1,41 @@ +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 \ + qwindowsdirect2dwindow.cpp + +HEADERS += \ + qwindowsdirect2dpaintengine.h \ + qwindowsdirect2dpaintdevice.h \ + qwindowsdirect2dplatformpixmap.h \ + qwindowsdirect2dcontext.h \ + qwindowsdirect2dhelpers.h \ + qwindowsdirect2dbitmap.h \ + qwindowsdirect2dbackingstore.h \ + qwindowsdirect2dintegration.h \ + qwindowsdirect2ddevicecontext.h \ + qwindowsdirect2dnativeinterface.h \ + qwindowsdirect2dwindow.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..079ad6f127 --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.cpp @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowsdirect2dbackingstore.h" +#include "qwindowsdirect2dintegration.h" +#include "qwindowsdirect2dcontext.h" +#include "qwindowsdirect2dpaintdevice.h" +#include "qwindowsdirect2dbitmap.h" +#include "qwindowsdirect2ddevicecontext.h" +#include "qwindowsdirect2dwindow.h" + +#include "qwindowscontext.h" + +#include <QtGui/QWindow> +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +/*! + \class QWindowsDirect2DBackingStore + \brief Backing store for windows. + \internal + \ingroup qt-lighthouse-win +*/ + +static inline QWindowsDirect2DPlatformPixmap *platformPixmap(QPixmap *p) +{ + return static_cast<QWindowsDirect2DPlatformPixmap *>(p->handle()); +} + +QWindowsDirect2DBackingStore::QWindowsDirect2DBackingStore(QWindow *window) + : QPlatformBackingStore(window) +{ +} + +QWindowsDirect2DBackingStore::~QWindowsDirect2DBackingStore() +{ +} + +QPaintDevice *QWindowsDirect2DBackingStore::paintDevice() +{ + return m_pixmap.data(); +} + +void QWindowsDirect2DBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) +{ + QPlatformWindow *pw = window->handle(); + if (pw && m_pixmap) + static_cast<QWindowsDirect2DWindow *>(pw)->flush(platformPixmap(m_pixmap.data())->bitmap(), region, offset); +} + +void QWindowsDirect2DBackingStore::resize(const QSize &size, const QRegion ®ion) +{ + Q_UNUSED(region); + + QScopedPointer<QPixmap> oldPixmap(m_pixmap.take()); + m_pixmap.reset(new QPixmap(size.width(), size.height())); + + if (oldPixmap) { + foreach (const QRect &rect, region.rects()) + platformPixmap(m_pixmap.data())->copy(oldPixmap->handle(), rect); + } +} + +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..9776d234e8 --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.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 QWINDOWSDIRECT2DBACKINGSTORE_H +#define QWINDOWSDIRECT2DBACKINGSTORE_H + +#include "qwindowsdirect2dplatformpixmap.h" + +#include <QtCore/QScopedPointer> +#include <QtGui/qpa/qplatformbackingstore.h> +#include <QtGui/QPixmap> + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DBackingStore : public QPlatformBackingStore +{ + Q_DISABLE_COPY(QWindowsDirect2DBackingStore) + +public: + QWindowsDirect2DBackingStore(QWindow *window); + ~QWindowsDirect2DBackingStore(); + + QPaintDevice *paintDevice() Q_DECL_OVERRIDE; + void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE; + void resize(const QSize &size, const QRegion &staticContents) Q_DECL_OVERRIDE; + +private: + QScopedPointer<QPixmap> m_pixmap; +}; + +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..27e94e4be4 --- /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/kms/qkmsvthandler.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h index 5e5afd3161..98248515e6 100644 --- a/src/plugins/platforms/kms/qkmsvthandler.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h @@ -39,62 +39,58 @@ ** ****************************************************************************/ -#include <qkmsvthandler.h> -#include <QtCore/private/qcrashhandler_p.h> -#include <QtGui/private/qguiapplication_p.h> -#include <sys/ioctl.h> -#include <linux/vt.h> -#include <linux/kd.h> +#ifndef QWINDOWSDIRECT2DHELPERS_H +#define QWINDOWSDIRECT2DHELPERS_H -#ifdef K_OFF -#define KBD_OFF_MODE K_OFF -#else -#define KBD_OFF_MODE K_RAW -#endif +#include <QtCore/QRectF> +#include <QtCore/QSizeF> +#include <QtCore/QPointF> +#include <QtGui/QColor> +#include <QtGui/QTransform> -QT_BEGIN_NAMESPACE +#include <d2d1_1helper.h> -QKmsVTHandler *QKmsVTHandler::self = 0; +QT_BEGIN_NAMESPACE -QKmsVTHandler::QKmsVTHandler(QObject *parent) - : QObject(parent), m_tty(-1) +Q_DECL_CONSTEXPR inline D2D1_RECT_U to_d2d_rect_u(const QRect &qrect) { - Q_ASSERT(!self); - self = this; - - if (!isatty(0)) - return; + return D2D1::RectU(qrect.x(), qrect.y(), qrect.x() + qrect.width(), qrect.y() + qrect.height()); +} - m_tty = 0; +Q_DECL_CONSTEXPR inline D2D1_RECT_F to_d2d_rect_f(const QRectF &qrect) +{ + return D2D1::RectF(qrect.x(), qrect.y(), qrect.x() + qrect.width(), qrect.y() + qrect.height()); +} - ioctl(m_tty, KDGKBMODE, &m_oldKbdMode); - if (!qgetenv("QT_KMS_TTYKBD").toInt()) { - ioctl(m_tty, KDSKBMODE, KBD_OFF_MODE); - QGuiApplicationPrivate *appd = QGuiApplicationPrivate::instance(); - Q_ASSERT(appd); - QSegfaultHandler::initialize(appd->argv, appd->argc); - QSegfaultHandler::installCrashHandler(crashHandler); - } +Q_DECL_CONSTEXPR inline D2D1_SIZE_U to_d2d_size_u(const QSizeF &qsize) +{ + return D2D1::SizeU(qsize.width(), qsize.height()); } -QKmsVTHandler::~QKmsVTHandler() +Q_DECL_CONSTEXPR inline D2D1_SIZE_U to_d2d_size_u(const QSize &qsize) { - self->cleanup(); - self = 0; + return D2D1::SizeU(qsize.width(), qsize.height()); } -void QKmsVTHandler::cleanup() +Q_DECL_CONSTEXPR inline D2D1_POINT_2F to_d2d_point_2f(const QPointF &qpoint) { - if (m_tty == -1) - return; + return D2D1::Point2F(qpoint.x(), qpoint.y()); +} - ioctl(m_tty, KDSKBMODE, m_oldKbdMode); +Q_DECL_CONSTEXPR inline D2D1::ColorF to_d2d_color_f(const QColor &c) +{ + return D2D1::ColorF(c.redF(), c.greenF(), c.blueF(), c.alphaF()); } -void QKmsVTHandler::crashHandler() +Q_DECL_CONSTEXPR inline D2D1_MATRIX_3X2_F to_d2d_matrix_3x2_f(const QTransform &transform) { - Q_ASSERT(self); - self->cleanup(); + 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..1a26d7029e --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.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 "qwindowsdirect2dcontext.h" +#include "qwindowsdirect2dintegration.h" +#include "qwindowsdirect2dbackingstore.h" +#include "qwindowsdirect2dplatformpixmap.h" +#include "qwindowsdirect2dnativeinterface.h" +#include "qwindowsdirect2dwindow.h" + +#include "qwindowscontext.h" + +#include <QtCore/QDebug> +#include <QtGui/private/qpixmap_raster_p.h> +#include <QtGui/qpa/qwindowsysteminterface.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()); + } + + QPlatformWindow *QWindowsDirect2DIntegration::createPlatformWindow(QWindow *window) const + { + QWindowsWindowData data = createWindowData(window); + return data.hwnd ? new QWindowsDirect2DWindow(window, data) + : Q_NULLPTR; + } + + 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 new QWindowsDirect2DBackingStore(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..a46d5c0126 --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** 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(); + + QPlatformWindow *createPlatformWindow(QWindow *window) const Q_DECL_OVERRIDE; + 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..e19a6be47b --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp @@ -0,0 +1,1168 @@ +/**************************************************************************** +** +** 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 <QtGui/private/qpaintengine_p.h> +#include <QtGui/private/qtextengine_p.h> +#include <QtGui/private/qfontengine_p.h> +#include <QtGui/private/qstatictext_p.h> + +#include <wrl.h> +using Microsoft::WRL::ComPtr; + +QT_BEGIN_NAMESPACE + +// The enum values below are set as tags on the device context +// in the various draw methods. When EndDraw is called the device context +// will report the last set tag number in case of errors +// along with an error code + +// Microsoft keeps a list of d2d error codes here: +// http://msdn.microsoft.com/en-us/library/windows/desktop/dd370979(v=vs.85).aspx +enum { + D2DDebugDrawInitialStateTag = -1, + D2DDebugDrawImageTag = 1, + D2DDebugFillTag, + D2DDebugDrawPixmapTag, + D2DDebugDrawStaticTextItemTag, + D2DDebugDrawTextItemTag +}; +#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(); +} + +// XXX reduce code duplication between painterPathToPathGeometry and +// vectorPathToID2D1PathGeometry, the two are quite similar + +static ComPtr<ID2D1PathGeometry1> painterPathToPathGeometry(const QPainterPath &path) +{ + ComPtr<ID2D1PathGeometry1> 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<ID2D1PathGeometry1> vectorPathToID2D1PathGeometry(const QVectorPath &path, bool alias) +{ + ComPtr<ID2D1PathGeometry1> pathGeometry; + HRESULT hr = factory()->CreatePathGeometry(pathGeometry.GetAddressOf()); + if (FAILED(hr)) { + qWarning("%s: Could not create path geometry: %#x", __FUNCTION__, hr); + return NULL; + } + + if (path.isEmpty()) + return pathGeometry; + + ComPtr<ID2D1GeometrySink> sink; + hr = pathGeometry->Open(sink.GetAddressOf()); + if (FAILED(hr)) { + qWarning("%s: Could not create geometry sink: %#x", __FUNCTION__, hr); + return NULL; + } + + sink->SetFillMode(path.hasWindingFill() ? D2D1_FILL_MODE_WINDING + : D2D1_FILL_MODE_ALTERNATE); + + bool inFigure = false; + + const QPainterPath::ElementType *types = path.elements(); + const int count = path.elementCount(); + const qreal *points = 0; + + QScopedArrayPointer<qreal> rounded_points; + + if (alias) { + // Aliased painting, round to whole numbers + rounded_points.reset(new qreal[count * 2]); + points = rounded_points.data(); + + for (int i = 0; i < (count * 2); i++) + rounded_points[i] = qRound(path.points()[i]); + } else { + // Antialiased painting, keep original numbers + points = path.points(); + } + + Q_ASSERT(points); + + if (types) { + qreal x, y; + + for (int i = 0; i < count; i++) { + x = points[i * 2]; + y = points[i * 2 + 1]; + + switch (types[i]) { + case QPainterPath::MoveToElement: + if (inFigure) + sink->EndFigure(D2D1_FIGURE_END_OPEN); + + sink->BeginFigure(D2D1::Point2F(x, y), D2D1_FIGURE_BEGIN_FILLED); + inFigure = true; + break; + + case QPainterPath::LineToElement: + sink->AddLine(D2D1::Point2F(x, y)); + break; + + case QPainterPath::CurveToElement: + { + Q_ASSERT((i + 2) < count); + Q_ASSERT(types[i+1] == QPainterPath::CurveToDataElement); + Q_ASSERT(types[i+2] == QPainterPath::CurveToDataElement); + + i++; + const qreal x2 = points[i * 2]; + const qreal y2 = points[i * 2 + 1]; + + i++; + const qreal x3 = points[i * 2]; + const qreal y3 = points[i * 2 + 1]; + + D2D1_BEZIER_SEGMENT segment = { + D2D1::Point2F(x, y), + D2D1::Point2F(x2, y2), + D2D1::Point2F(x3, y3) + }; + + sink->AddBezier(segment); + } + break; + + case QPainterPath::CurveToDataElement: + qWarning("%s: Unhandled Curve Data Element", __FUNCTION__); + break; + } + } + } else { + sink->BeginFigure(D2D1::Point2F(points[0], points[1]), D2D1_FIGURE_BEGIN_FILLED); + inFigure = true; + + for (int i = 1; i < count; i++) + sink->AddLine(D2D1::Point2F(points[i * 2], points[i * 2 + 1])); + } + + if (inFigure) { + if (path.hasImplicitClose()) + sink->AddLine(D2D1::Point2F(points[0], points[1])); + + sink->EndFigure(D2D1_FIGURE_END_OPEN); + } + + sink->Close(); + + return pathGeometry; +} + +class QWindowsDirect2DPaintEnginePrivate : public QPaintEngineExPrivate +{ + Q_DECLARE_PUBLIC(QWindowsDirect2DPaintEngine) +public: + QWindowsDirect2DPaintEnginePrivate(QWindowsDirect2DBitmap *bm) + : bitmap(bm) + , clipPushed(false) + { + pen.reset(); + brush.reset(); + + dc()->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED); + } + + QWindowsDirect2DBitmap *bitmap; + + QPainterPath clipPath; + bool clipPushed; + + QPointF currentBrushOrigin; + + struct { + bool emulate; + QPen qpen; + ComPtr<ID2D1Brush> brush; + ComPtr<ID2D1StrokeStyle1> strokeStyle; + + inline void reset() { + emulate = false; + qpen = QPen(); + brush.Reset(); + strokeStyle.Reset(); + } + } pen; + + struct { + bool emulate; + QBrush qbrush; + ComPtr<ID2D1Brush> brush; + + inline void reset() { + emulate = false; + brush.Reset(); + qbrush = QBrush(); + } + } brush; + + inline ID2D1DeviceContext *dc() const + { + Q_ASSERT(bitmap); + return bitmap->deviceContext()->get(); + } + + inline D2D1_INTERPOLATION_MODE interpolationMode() const + { + Q_Q(const QWindowsDirect2DPaintEngine); + // XXX are we choosing the right d2d interpolation modes? + return (q->state()->renderHints & QPainter::SmoothPixmapTransform) ? D2D1_INTERPOLATION_MODE_HIGH_QUALITY_CUBIC + : D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR; + } + + inline D2D1_ANTIALIAS_MODE antialiasMode() const + { + Q_Q(const QWindowsDirect2DPaintEngine); + return (q->state()->renderHints & QPainter::Antialiasing) ? D2D1_ANTIALIAS_MODE_PER_PRIMITIVE + : D2D1_ANTIALIAS_MODE_ALIASED; + } + + void updateTransform() + { + Q_Q(const QWindowsDirect2DPaintEngine); + // Note the loss of info going from 3x3 to 3x2 matrix here + dc()->SetTransform(to_d2d_matrix_3x2_f(q->state()->transform())); + } + + void updateOpacity() + { + Q_Q(const QWindowsDirect2DPaintEngine); + qreal opacity = q->state()->opacity; + if (brush.brush) + brush.brush->SetOpacity(opacity); + if (pen.brush) + pen.brush->SetOpacity(opacity); + } + + void pushClip() + { + popClip(); + + ComPtr<ID2D1PathGeometry1> geometry = painterPathToPathGeometry(clipPath); + if (!geometry) + return; + + dc()->PushLayer(D2D1::LayerParameters1(D2D1::InfiniteRect(), + geometry.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() + { + Q_Q(const QWindowsDirect2DPaintEngine); + if (!q->state()->clipEnabled) + 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 updateCompositionMode() + { + Q_Q(const QWindowsDirect2DPaintEngine); + QPainter::CompositionMode mode = q->state()->compositionMode(); + + switch (mode) { + case QPainter::CompositionMode_Source: + dc()->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND_COPY); + break; + case QPainter::CompositionMode_SourceOver: + dc()->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND_SOURCE_OVER); + break; + + default: + qWarning("Unsupported composition mode: %d", mode); + break; + } + } + + void updateBrush(const QBrush &newBrush) + { + Q_Q(const QWindowsDirect2DPaintEngine); + + if (qbrush_fast_equals(brush.qbrush, newBrush)) + return; + + brush.brush = to_d2d_brush(newBrush, &brush.emulate); + brush.qbrush = newBrush; + + if (brush.brush) { + brush.brush->SetOpacity(q->state()->opacity); + applyBrushOrigin(currentBrushOrigin); + } + } + + void updateBrushOrigin() + { + Q_Q(const QWindowsDirect2DPaintEngine); + + negateCurrentBrushOrigin(); + applyBrushOrigin(q->state()->brushOrigin); + } + + 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() + { + Q_Q(const QWindowsDirect2DPaintEngine); + const QPen &newPen = q->state()->pen; + + if (qpen_fast_equals(newPen, pen.qpen)) + return; + + pen.reset(); + pen.qpen = newPen; + + if (newPen.style() == Qt::NoPen) + return; + + pen.brush = to_d2d_brush(newPen.brush(), &pen.emulate); + if (!pen.brush) + return; + + pen.brush->SetOpacity(q->state()->opacity); + + D2D1_STROKE_STYLE_PROPERTIES1 props = {}; + + 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; + } + + 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; + + case Qt::DotLine: + case Qt::DashDotLine: + case Qt::DashDotDotLine: + // Try and match Qt's raster engine in output as closely as possible + if (newPen.widthF() <= 1.0) + props.startCap = props.endCap = props.dashCap = D2D1_CAP_STYLE_FLAT; + + // fall through + 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, bool *needsEmulation) + { + HRESULT hr; + ComPtr<ID2D1Brush> result; + + Q_ASSERT(needsEmulation); + + *needsEmulation = false; + + 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: + *needsEmulation = true; + 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() + { + dc()->SetAntialiasMode(antialiasMode()); + } +}; + +QWindowsDirect2DPaintEngine::QWindowsDirect2DPaintEngine(QWindowsDirect2DBitmap *bitmap) + : QPaintEngineEx(*(new QWindowsDirect2DPaintEnginePrivate(bitmap))) +{ + QPaintEngine::PaintEngineFeatures unsupported = + // As of 1.1 Direct2D gradient support is deficient for linear and radial gradients + QPaintEngine::LinearGradientFill + | QPaintEngine::RadialGradientFill + + // As of 1.1 Direct2D does not support conical gradients at all + | QPaintEngine::ConicalGradientFill + + // As of 1.1 Direct2D does not natively support complex composition modes + // However, using Direct2D effects that implement them should be possible + | QPaintEngine::PorterDuff + | QPaintEngine::BlendModes + | QPaintEngine::RasterOpModes + + // As of 1.1 Direct2D does not natively support perspective transforms + // However, writing a custom effect that implements them should be possible + // The built-in 3D transform effect unfortunately changes output image size, making + // it unusable for us. + | QPaintEngine::PerspectiveTransform; + + gccaps &= ~unsupported; +} + +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), D2D1_ANTIALIAS_MODE_ALIASED); + + D2D_TAG(D2DDebugDrawInitialStateTag); + + return true; +} + +bool QWindowsDirect2DPaintEngine::end() +{ + Q_D(QWindowsDirect2DPaintEngine); + // First pop any user-applied clipping + d->popClip(); + // Now the system clip from begin() above + d->dc()->PopAxisAlignedClip(); + return d->bitmap->deviceContext()->end(); +} + +QPaintEngine::Type QWindowsDirect2DPaintEngine::type() const +{ + return QPaintEngine::Direct2D; +} + +void QWindowsDirect2DPaintEngine::fill(const QVectorPath &path, const QBrush &brush) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugFillTag); + + if (path.isEmpty()) + return; + + d->updateBrush(brush); + + if (d->brush.emulate) { + // We mostly (only?) get here when gradients are required. + // We could probably natively support linear and radial gradients that have pad reflect + + QImage img(d->bitmap->size(), QImage::Format_ARGB32); + img.fill(Qt::transparent); + + QPainter p; + QPaintEngine *engine = img.paintEngine(); + if (engine->isExtended() && p.begin(&img)) { + QPaintEngineEx *extended = static_cast<QPaintEngineEx *>(engine); + extended->fill(path, brush); + if (!p.end()) + qWarning("%s: Paint Engine end returned false", __FUNCTION__); + + drawImage(img.rect(), img, img.rect()); + } else { + qWarning("%s: Could not fall back to QImage", __FUNCTION__); + } + + return; + } + + if (!d->brush.brush) + return; + + ComPtr<ID2D1Geometry> geometry = vectorPathToID2D1PathGeometry(path, d->antialiasMode() == D2D1_ANTIALIAS_MODE_ALIASED); + if (!geometry) { + qWarning("%s: Could not convert path to d2d geometry", __FUNCTION__); + return; + } + + d->dc()->FillGeometry(geometry.Get(), d->brush.brush.Get()); +} + +// For clipping we convert everything to painter paths since it allows +// calculating intersections easily. It might be faster to convert to +// ID2D1Geometry and use its operations, although that needs to measured. +// The implementation would be more complex in any case. + +void QWindowsDirect2DPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op) +{ + clip(path.convertToPainterPath(), op); +} + +void QWindowsDirect2DPaintEngine::clip(const QRect &rect, Qt::ClipOperation op) +{ + QPainterPath p; + p.addRect(rect); + clip(p, op); +} + +void QWindowsDirect2DPaintEngine::clip(const QRegion ®ion, Qt::ClipOperation op) +{ + QPainterPath p; + p.addRegion(region); + clip(p, op); +} + +void QWindowsDirect2DPaintEngine::clip(const QPainterPath &path, Qt::ClipOperation op) +{ + Q_D(QWindowsDirect2DPaintEngine); + d->updateClipPath(path, op); +} + +void QWindowsDirect2DPaintEngine::clipEnabledChanged() +{ + Q_D(QWindowsDirect2DPaintEngine); + d->updateClipEnabled(); +} + +void QWindowsDirect2DPaintEngine::penChanged() +{ + Q_D(QWindowsDirect2DPaintEngine); + d->updatePen(); +} + +void QWindowsDirect2DPaintEngine::brushChanged() +{ + Q_D(QWindowsDirect2DPaintEngine); + d->updateBrush(state()->brush); +} + +void QWindowsDirect2DPaintEngine::brushOriginChanged() +{ + Q_D(QWindowsDirect2DPaintEngine); + d->updateBrushOrigin(); +} + +void QWindowsDirect2DPaintEngine::opacityChanged() +{ + Q_D(QWindowsDirect2DPaintEngine); + d->updateOpacity(); +} + +void QWindowsDirect2DPaintEngine::compositionModeChanged() +{ + Q_D(QWindowsDirect2DPaintEngine); + d->updateCompositionMode(); +} + +void QWindowsDirect2DPaintEngine::renderHintsChanged() +{ + Q_D(QWindowsDirect2DPaintEngine); + d->updateHints(); +} + +void QWindowsDirect2DPaintEngine::transformChanged() +{ + Q_D(QWindowsDirect2DPaintEngine); + d->updateTransform(); +} + +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::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.qpen.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), state()->opacity, + d->interpolationMode(), + to_d2d_rect_f(sr)); + else + d->dc()->DrawBitmap(bitmap->bitmap(), + to_d2d_rect_f(r), state()->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) { + qWarning("%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) { + qWarning("%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), state()->opacity, + d->interpolationMode()); + } +} + +static ComPtr<IDWriteFontFace> fontFaceFromFontEngine(QFontEngine *fe) +{ + ComPtr<IDWriteFontFace> fontFace; + + switch (fe->type()) { + case QFontEngine::Win: + { + QWindowsFontEngine *wfe = static_cast<QWindowsFontEngine *>(fe); + 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 *>(fe); + fontFace = wfedw->directWriteFontFace(); + } + break; + +#endif // QT_NO_DIRECTWRITE + + default: + qWarning("%s: Unknown font engine!", __FUNCTION__); + break; + } + + return fontFace; +} + +void QWindowsDirect2DPaintEngine::drawStaticTextItem(QStaticTextItem *staticTextItem) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawStaticTextItemTag); + + if (qpen_style(d->pen.qpen) == Qt::NoPen) + return; + + if (staticTextItem->numGlyphs == 0) + 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 ((state()->transform().isAffine() == false) || d->pen.emulate) { + QPaintEngineEx::drawStaticTextItem(staticTextItem); + return; + } + + ComPtr<IDWriteFontFace> fontFace = fontFaceFromFontEngine(staticTextItem->fontEngine()); + if (!fontFace) { + qWarning("%s: Could not find font - falling back to slow text rendering path.", __FUNCTION__); + QPaintEngineEx::drawStaticTextItem(staticTextItem); + return; + } + + QVector<UINT16> glyphIndices(staticTextItem->numGlyphs); + QVector<FLOAT> glyphAdvances(staticTextItem->numGlyphs); + QVector<DWRITE_GLYPH_OFFSET> glyphOffsets(staticTextItem->numGlyphs); + + // XXX Are we generating a lot of cache misses here? + for (int i = 0; i < staticTextItem->numGlyphs; i++) { + glyphIndices[i] = UINT16(staticTextItem->glyphs[i]); // Imperfect conversion here + + // This looks a little funky because the positions are precalculated + glyphAdvances[i] = 0; + glyphOffsets[i].advanceOffset = staticTextItem->glyphPositions[i].x.toReal(); + // Qt and Direct2D seem to disagree on the direction of the ascender offset... + glyphOffsets[i].ascenderOffset = staticTextItem->glyphPositions[i].y.toReal() * -1; + } + + drawGlyphRun(D2D1::Point2F(0, 0), + fontFace.Get(), + staticTextItem->font, + staticTextItem->numGlyphs, + glyphIndices.constData(), + glyphAdvances.constData(), + glyphOffsets.constData(), + false); +} + +void QWindowsDirect2DPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawTextItemTag); + + if (qpen_style(d->pen.qpen) == Qt::NoPen) + return; + + const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem); + if (ti.glyphs.numGlyphs == 0) + 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 ((state()->transform().isAffine() == false) || d->pen.emulate) { + QPaintEngine::drawTextItem(p, textItem); + return; + } + + ComPtr<IDWriteFontFace> fontFace = fontFaceFromFontEngine(ti.fontEngine); + if (!fontFace) { + qWarning("%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); + + // XXX Are we generating a lot of cache misses here? + for (int i = 0; i < ti.glyphs.numGlyphs; i++) { + glyphIndices[i] = UINT16(ti.glyphs.glyphs[i]); // Imperfect conversion here + glyphAdvances[i] = ti.glyphs.effectiveAdvance(i).toReal(); + glyphOffsets[i].advanceOffset = ti.glyphs.offsets[i].x.toReal(); + + // XXX Should we negate the y value like for static text items? + glyphOffsets[i].ascenderOffset = ti.glyphs.offsets[i].y.toReal(); + } + + const bool rtl = (ti.flags & QTextItem::RightToLeft); + const QPointF offset(rtl ? ti.width.toReal() : 0, 0); + + drawGlyphRun(to_d2d_point_2f(p + offset), + fontFace.Get(), + ti.font(), + ti.glyphs.numGlyphs, + glyphIndices.constData(), + glyphAdvances.constData(), + glyphOffsets.constData(), + rtl); +} + +// 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) +{ + // Direct2d 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::drawGlyphRun(const D2D1_POINT_2F &pos, + IDWriteFontFace *fontFace, + const QFont &font, + int numGlyphs, + const UINT16 *glyphIndices, + const FLOAT *glyphAdvances, + const DWRITE_GLYPH_OFFSET *glyphOffsets, + bool rtl) +{ + Q_D(QWindowsDirect2DPaintEngine); + + DWRITE_GLYPH_RUN glyphRun = { + fontFace, // IDWriteFontFace *fontFace; + fontSizeInDIP(font), // FLOAT fontEmSize; + numGlyphs, // UINT32 glyphCount; + glyphIndices, // const UINT16 *glyphIndices; + glyphAdvances, // const FLOAT *glyphAdvances; + glyphOffsets, // const DWRITE_GLYPH_OFFSET *glyphOffsets; + FALSE, // BOOL isSideways; + rtl ? 1 : 0 // UINT32 bidiLevel; + }; + + const bool antiAlias = bool((state()->renderHints & QPainter::TextAntialiasing) + && !(font.styleStrategy() & QFont::NoAntialias)); + d->dc()->SetTextAntialiasMode(antiAlias ? D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE + : D2D1_TEXT_ANTIALIAS_MODE_ALIASED); + + d->dc()->DrawGlyphRun(pos, + &glyphRun, + NULL, + d->pen.brush.Get(), + DWRITE_MEASURING_MODE_GDI_CLASSIC); +} + +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..6c74a07e88 --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** 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/private/qpaintengineex_p.h> + +#include <d2d1_1.h> +#include <dwrite_1.h> + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DPaintEnginePrivate; +class QWindowsDirect2DBitmap; + +class QWindowsDirect2DPaintEngine : public QPaintEngineEx +{ + Q_DECLARE_PRIVATE(QWindowsDirect2DPaintEngine) + +public: + QWindowsDirect2DPaintEngine(QWindowsDirect2DBitmap *bitmap); + + bool begin(QPaintDevice *pdev) Q_DECL_OVERRIDE; + bool end() Q_DECL_OVERRIDE; + + Type type() const Q_DECL_OVERRIDE; + + void fill(const QVectorPath &path, const QBrush &brush) Q_DECL_OVERRIDE; + + void clip(const QVectorPath &path, Qt::ClipOperation op) Q_DECL_OVERRIDE; + void clip(const QRect &rect, Qt::ClipOperation op) Q_DECL_OVERRIDE; + void clip(const QRegion ®ion, Qt::ClipOperation op) Q_DECL_OVERRIDE; + void clip(const QPainterPath &path, Qt::ClipOperation op) Q_DECL_OVERRIDE; + + void clipEnabledChanged() Q_DECL_OVERRIDE; + void penChanged() Q_DECL_OVERRIDE; + void brushChanged() Q_DECL_OVERRIDE; + void brushOriginChanged() Q_DECL_OVERRIDE; + void opacityChanged() Q_DECL_OVERRIDE; + void compositionModeChanged() Q_DECL_OVERRIDE; + void renderHintsChanged() Q_DECL_OVERRIDE; + void transformChanged() Q_DECL_OVERRIDE; + + void drawImage(const QRectF &rectangle, const QImage &image, const QRectF &sr, Qt::ImageConversionFlags flags = Qt::AutoColor) Q_DECL_OVERRIDE; + void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) Q_DECL_OVERRIDE; + + void drawStaticTextItem(QStaticTextItem *staticTextItem) Q_DECL_OVERRIDE; + void drawTextItem(const QPointF &p, const QTextItem &textItem) Q_DECL_OVERRIDE; + +private: + void drawGlyphRun(const D2D1_POINT_2F &pos, IDWriteFontFace *fontFace, const QFont &font, + int numGlyphs, const UINT16 *glyphIndices, const FLOAT *glyphAdvances, + const DWRITE_GLYPH_OFFSET *glyphOffsets, bool rtl); +}; + +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/direct2d/qwindowsdirect2dwindow.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp new file mode 100644 index 0000000000..bf860f982e --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp @@ -0,0 +1,177 @@ +/**************************************************************************** +** +** Copyright (C) 2014 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 "qwindowsdirect2dwindow.h" +#include "qwindowsdirect2ddevicecontext.h" +#include "qwindowsdirect2dhelpers.h" + +#include <d3d11.h> +#include <d2d1_1.h> +using Microsoft::WRL::ComPtr; + +QT_BEGIN_NAMESPACE + +QWindowsDirect2DWindow::QWindowsDirect2DWindow(QWindow *window, const QWindowsWindowData &data) + : QWindowsWindow(window, data) + , m_needsFullFlush(true) +{ + 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 + handle(), // [in] HWND hWnd + &desc, // [in] const DXGI_SWAP_CHAIN_DESC1 *pDesc + NULL, // [in] const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *pFullscreenDesc + NULL, // [in] IDXGIOutput *pRestrictToOutput + m_swapChain.ReleaseAndGetAddressOf()); // [out] IDXGISwapChain1 **ppSwapChain + + if (FAILED(hr)) + qWarning("%s: Could not create swap chain: %#x", __FUNCTION__, hr); + + hr = QWindowsDirect2DContext::instance()->d2dDevice()->CreateDeviceContext( + D2D1_DEVICE_CONTEXT_OPTIONS_NONE, + m_deviceContext.GetAddressOf()); + if (FAILED(hr)) + qWarning("%s: Couldn't create Direct2D Device context: %#x", __FUNCTION__, hr); +} + +QWindowsDirect2DWindow::~QWindowsDirect2DWindow() +{ +} + +void QWindowsDirect2DWindow::flush(QWindowsDirect2DBitmap *bitmap, const QRegion ®ion, const QPoint &offset) +{ + DXGI_SWAP_CHAIN_DESC1 desc; + HRESULT hr = m_swapChain->GetDesc1(&desc); + QRect geom = geometry(); + + if (FAILED(hr) || (desc.Width != geom.width()) || (desc.Height != geom.height())) { + resizeSwapChain(geom.size()); + m_swapChain->GetDesc1(&desc); + } + + setupBitmap(); + if (!m_bitmap) + return; + + m_bitmap->deviceContext()->begin(); + + ID2D1DeviceContext *dc = m_bitmap->deviceContext()->get(); + if (!m_needsFullFlush) { + QRegion clipped = region; + clipped &= QRect(0, 0, desc.Width, desc.Height); + + foreach (const QRect &rect, clipped.rects()) { + QRectF rectF(rect); + dc->DrawBitmap(bitmap->bitmap(), + to_d2d_rect_f(rectF), + 1.0, + D2D1_INTERPOLATION_MODE_LINEAR, + to_d2d_rect_f(rectF.translated(offset.x(), offset.y()))); + } + } else { + QRectF rectF(0, 0, desc.Width, desc.Height); + dc->DrawBitmap(bitmap->bitmap(), + to_d2d_rect_f(rectF), + 1.0, + D2D1_INTERPOLATION_MODE_LINEAR, + to_d2d_rect_f(rectF.translated(offset.x(), offset.y()))); + m_needsFullFlush = false; + } + + m_bitmap->deviceContext()->end(); + m_swapChain->Present(1, 0); +} + +void QWindowsDirect2DWindow::resizeSwapChain(const QSize &size) +{ + if (!m_swapChain) + return; + + m_bitmap.reset(); + m_deviceContext->SetTarget(Q_NULLPTR); + + HRESULT hr = m_swapChain->ResizeBuffers(0, + size.width(), size.height(), + DXGI_FORMAT_UNKNOWN, + 0); + if (FAILED(hr)) + qWarning("%s: Could not resize swap chain: %#x", __FUNCTION__, hr); + + m_needsFullFlush = true; +} + +void QWindowsDirect2DWindow::setupBitmap() +{ + if (m_bitmap) + return; + + if (!m_deviceContext) + return; + + if (!m_swapChain) + return; + + ComPtr<IDXGISurface1> backBufferSurface; + HRESULT hr = m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBufferSurface)); + if (FAILED(hr)) { + qWarning("%s: Could not query backbuffer for DXGI Surface: %#x", __FUNCTION__, hr); + return; + } + + ComPtr<ID2D1Bitmap1> backBufferBitmap; + hr = m_deviceContext->CreateBitmapFromDxgiSurface(backBufferSurface.Get(), NULL, backBufferBitmap.GetAddressOf()); + if (FAILED(hr)) { + qWarning("%s: Could not create Direct2D Bitmap from DXGI Surface: %#x", __FUNCTION__, hr); + return; + } + + m_bitmap.reset(new QWindowsDirect2DBitmap(backBufferBitmap.Get(), m_deviceContext.Get())); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.h b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.h new file mode 100644 index 0000000000..7996904639 --- /dev/null +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2014 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 QWINDOWSDIRECT2DWINDOW_H +#define QWINDOWSDIRECT2DWINDOW_H + +#include "qwindowswindow.h" +#include "qwindowsdirect2dbitmap.h" + +#include <dxgi1_2.h> +#include <wrl.h> + +QT_BEGIN_NAMESPACE + +class QWindowsDirect2DWindow : public QWindowsWindow +{ +public: + QWindowsDirect2DWindow(QWindow *window, const QWindowsWindowData &data); + ~QWindowsDirect2DWindow(); + + void flush(QWindowsDirect2DBitmap *bitmap, const QRegion ®ion, const QPoint &offset); + +private: + void resizeSwapChain(const QSize &size); + void setupBitmap(); + +private: + Microsoft::WRL::ComPtr<IDXGISwapChain1> m_swapChain; + Microsoft::WRL::ComPtr<ID2D1DeviceContext> m_deviceContext; + QScopedPointer<QWindowsDirect2DBitmap> m_bitmap; + bool m_needsFullFlush; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSDIRECT2DWINDOW_H 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..dbfd8d99dc 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, screenSize()); } 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..472e58cc72 100644 --- a/src/plugins/platforms/eglfs/qeglfsintegration.cpp +++ b/src/plugins/platforms/eglfs/qeglfsintegration.cpp @@ -42,25 +42,15 @@ #include "qeglfsintegration.h" #include "qeglfswindow.h" -#include "qeglfsbackingstore.h" -#include "qeglfscompositor.h" #include "qeglfshooks.h" +#include "qeglfscontext.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> -#if !defined(QT_NO_EVDEV) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_NO_SDK)) -#include <QtPlatformSupport/private/qevdevmousemanager_p.h> -#include <QtPlatformSupport/private/qevdevkeyboardmanager_p.h> -#include <QtPlatformSupport/private/qevdevtouch_p.h> -#endif - #include <qpa/qplatformwindow.h> #include <QtGui/QSurfaceFormat> #include <QtGui/QOpenGLContext> @@ -68,10 +58,6 @@ #include <QtGui/QOffscreenSurface> #include <qpa/qplatformcursor.h> -#include <qpa/qplatforminputcontextfactory_p.h> - -#include "qeglfscontext.h" - #include <EGL/egl.h> static void initResources() @@ -82,10 +68,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 +76,6 @@ QEglFSIntegration::QEglFSIntegration() QEglFSIntegration::~QEglFSIntegration() { - QEglFSCompositor::destroy(); - delete mScreen; - eglTerminate(mDisplay); QEglFSHooks::hooks()->platformDestroy(); } @@ -106,33 +85,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 +99,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 -{ - return new QEglFSScreen(mDisplay); -} - -QVariant QEglFSIntegration::styleHint(QPlatformIntegration::StyleHint hint) const -{ - switch (hint) - { - case QPlatformIntegration::ShowIsFullScreen: - return mScreen->rootWindow() == 0; - default: - return QPlatformIntegration::styleHint(hint); - } -} - -QPlatformServices *QEglFSIntegration::services() const +EGLNativeDisplayType QEglFSIntegration::nativeDisplay() const { - return mServices.data(); + return QEglFSHooks::hooks()->platformDisplay(); } -QPlatformNativeInterface *QEglFSIntegration::nativeInterface() const +QEGLPlatformScreen *QEglFSIntegration::createScreen() const { - return const_cast<QEglFSIntegration *>(this); + return new QEglFSScreen(display()); } -enum ResourceType { - EglDisplay, - EglWindow, - EglContext -}; - -static int resourceType(const QByteArray &key) +QEGLPlatformWindow *QEglFSIntegration::createWindow(QWindow *window) const { - 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); + return new QEglFSWindow(window); } -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) @@ -326,13 +160,4 @@ EGLConfig QEglFSIntegration::chooseConfig(EGLDisplay display, const QSurfaceForm return chooser.chooseConfig(); } -void QEglFSIntegration::createInputHandlers() -{ -#if !defined(QT_NO_EVDEV) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_NO_SDK)) - new QEvdevKeyboardManager(QLatin1String("EvdevKeyboard"), QString() /* spec */, this); - new QEvdevMouseManager(QLatin1String("EvdevMouse"), QString() /* spec */, this); - new QEvdevTouchScreenHandlerThread(QString() /* spec */, this); -#endif -} - QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.h b/src/plugins/platforms/eglfs/qeglfsintegration.h index 12c8158bd1..9ff5bd6f3b 100644 --- a/src/plugins/platforms/eglfs/qeglfsintegration.h +++ b/src/plugins/platforms/eglfs/qeglfsintegration.h @@ -42,61 +42,34 @@ #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/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm index 0a6a00b753..2fe679fc20 100644 --- a/src/plugins/platforms/ios/qiosviewcontroller.mm +++ b/src/plugins/platforms/ios/qiosviewcontroller.mm @@ -44,6 +44,9 @@ #include <QtGui/QGuiApplication> #include <QtGui/QWindow> #include <QtGui/QScreen> + +#include <QtGui/private/qwindow_p.h> + #include "qiosscreen.h" #include "qiosglobal.h" #include "qioswindow.h" @@ -105,11 +108,10 @@ if (hiddenFromPlist) return YES; QWindow *focusWindow = QGuiApplication::focusWindow(); - if (!focusWindow || !focusWindow->handle()) + if (!focusWindow) return [UIApplication sharedApplication].statusBarHidden; - QWindow *topLevel = static_cast<QIOSWindow *>(focusWindow->handle())->topLevelWindow(); - return topLevel->windowState() == Qt::WindowFullScreen; + return qt_window_private(focusWindow)->topLevelWindow()->windowState() == Qt::WindowFullScreen; } @end diff --git a/src/plugins/platforms/ios/qioswindow.h b/src/plugins/platforms/ios/qioswindow.h index 8a5eb589d2..fc99543aa6 100644 --- a/src/plugins/platforms/ios/qioswindow.h +++ b/src/plugins/platforms/ios/qioswindow.h @@ -87,8 +87,6 @@ public: WId winId() const { return WId(m_view); }; - QWindow *topLevelWindow() const; - private: void applyGeometry(const QRect &rect); diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm index 7a0ff055ec..15a52e89ec 100644 --- a/src/plugins/platforms/ios/qioswindow.mm +++ b/src/plugins/platforms/ios/qioswindow.mm @@ -636,23 +636,6 @@ void QIOSWindow::setParent(const QPlatformWindow *parentWindow) } } -QWindow *QIOSWindow::topLevelWindow() const -{ - QWindow *window = this->window(); - while (window) { - QWindow *parent = window->parent(); - if (!parent) - parent = window->transientParent(); - - if (!parent) - break; - - window = parent; - } - - return window; -} - void QIOSWindow::requestActivateWindow() { // Note that several windows can be active at the same time if they exist in the same diff --git a/src/plugins/platforms/kms/kms.pro b/src/plugins/platforms/kms/kms.pro index 612a878736..1b3678f13a 100644 --- a/src/plugins/platforms/kms/kms.pro +++ b/src/plugins/platforms/kms/kms.pro @@ -21,8 +21,8 @@ SOURCES = main.cpp \ qkmscursor.cpp \ qkmsdevice.cpp \ qkmsbackingstore.cpp \ - qkmsnativeinterface.cpp \ - qkmsvthandler.cpp + qkmsnativeinterface.cpp + HEADERS = qkmsintegration.h \ qkmsscreen.h \ qkmscontext.h \ @@ -30,8 +30,7 @@ HEADERS = qkmsintegration.h \ qkmscursor.h \ qkmsdevice.h \ qkmsbackingstore.h \ - qkmsnativeinterface.h \ - qkmsvthandler.h + qkmsnativeinterface.h OTHER_FILES += \ kms.json diff --git a/src/plugins/platforms/kms/qkmsintegration.cpp b/src/plugins/platforms/kms/qkmsintegration.cpp index 80c5887a28..63c6d08bdc 100644 --- a/src/plugins/platforms/kms/qkmsintegration.cpp +++ b/src/plugins/platforms/kms/qkmsintegration.cpp @@ -46,7 +46,6 @@ #include "qkmsbackingstore.h" #include "qkmscontext.h" #include "qkmsnativeinterface.h" -#include "qkmsvthandler.h" #if !defined(QT_NO_EVDEV) #include <QtPlatformSupport/private/qevdevmousemanager_p.h> @@ -56,6 +55,8 @@ #include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h> #include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h> +#include <QtPlatformSupport/private/qfbvthandler_p.h> + #include <QtGui/private/qguiapplication_p.h> #include <QtGui/QOpenGLContext> #include <QtGui/QScreen> @@ -68,7 +69,7 @@ QKmsIntegration::QKmsIntegration() m_nativeInterface(new QKmsNativeInterface) { setenv("EGL_PLATFORM", "drm",1); - m_vtHandler = new QKmsVTHandler; + m_vtHandler = new QFbVtHandler; m_deviceDiscovery = QDeviceDiscovery::create(QDeviceDiscovery::Device_DRM | QDeviceDiscovery::Device_DRM_PrimaryGPU, 0); if (m_deviceDiscovery) { diff --git a/src/plugins/platforms/kms/qkmsintegration.h b/src/plugins/platforms/kms/qkmsintegration.h index 0a626e6bd2..bba4f53d7c 100644 --- a/src/plugins/platforms/kms/qkmsintegration.h +++ b/src/plugins/platforms/kms/qkmsintegration.h @@ -50,7 +50,7 @@ QT_BEGIN_NAMESPACE class QKmsScreen; class QKmsDevice; -class QKmsVTHandler; +class QFbVtHandler; class QKmsIntegration : public QObject, public QPlatformIntegration { @@ -85,7 +85,7 @@ private: QList<QKmsDevice *> m_devices; QPlatformFontDatabase *m_fontDatabase; QPlatformNativeInterface *m_nativeInterface; - QKmsVTHandler *m_vtHandler; + QFbVtHandler *m_vtHandler; QDeviceDiscovery *m_deviceDiscovery; }; diff --git a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp index 53f48d5480..b1b13e862f 100644 --- a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp +++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp @@ -43,18 +43,22 @@ #include "qlinuxfbscreen.h" #include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h> +#include <QtPlatformSupport/private/qgenericunixservices_p.h> #include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h> + +#include <QtPlatformSupport/private/qfbvthandler_p.h> #include <QtPlatformSupport/private/qfbbackingstore_p.h> #include <QtPlatformSupport/private/qfbwindow_p.h> #include <QtPlatformSupport/private/qfbcursor_p.h> #include <QtGui/private/qguiapplication_p.h> -#include <QtGui/private/qpixmap_raster_p.h> +#include <qpa/qplatforminputcontextfactory_p.h> QT_BEGIN_NAMESPACE QLinuxFbIntegration::QLinuxFbIntegration(const QStringList ¶mList) - : m_fontDb(new QGenericUnixFontDatabase()) + : m_fontDb(new QGenericUnixFontDatabase), + m_services(new QGenericUnixServices) { m_primaryScreen = new QLinuxFbScreen(paramList); } @@ -70,21 +74,21 @@ void QLinuxFbIntegration::initialize() screenAdded(m_primaryScreen); else qWarning("linuxfb: Failed to initialize screen"); + + m_inputContext = QPlatformInputContextFactory::create(); + + m_vtHandler.reset(new QFbVtHandler); } bool QLinuxFbIntegration::hasCapability(QPlatformIntegration::Capability cap) const { switch (cap) { case ThreadedPixmaps: return true; + case WindowManagement: return false; default: return QPlatformIntegration::hasCapability(cap); } } -QPlatformPixmap *QLinuxFbIntegration::createPlatformPixmap(QPlatformPixmap::PixelType type) const -{ - return new QRasterPlatformPixmap(type); -} - QPlatformBackingStore *QLinuxFbIntegration::createPlatformBackingStore(QWindow *window) const { return new QFbBackingStore(window); @@ -109,7 +113,12 @@ QList<QPlatformScreen *> QLinuxFbIntegration::screens() const QPlatformFontDatabase *QLinuxFbIntegration::fontDatabase() const { - return m_fontDb; + return m_fontDb.data(); +} + +QPlatformServices *QLinuxFbIntegration::services() const +{ + return m_services.data(); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/linuxfb/qlinuxfbintegration.h b/src/plugins/platforms/linuxfb/qlinuxfbintegration.h index 965a6e4642..67742ecab9 100644 --- a/src/plugins/platforms/linuxfb/qlinuxfbintegration.h +++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.h @@ -46,9 +46,9 @@ QT_BEGIN_NAMESPACE -class QLinuxFbIntegrationPrivate; class QAbstractEventDispatcher; class QLinuxFbScreen; +class QFbVtHandler; class QLinuxFbIntegration : public QPlatformIntegration { @@ -59,21 +59,25 @@ public: void initialize() Q_DECL_OVERRIDE; bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE; - QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const Q_DECL_OVERRIDE; QPlatformWindow *createPlatformWindow(QWindow *window) const Q_DECL_OVERRIDE; QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const Q_DECL_OVERRIDE; + QAbstractEventDispatcher *createEventDispatcher() const Q_DECL_OVERRIDE; + QPlatformFontDatabase *fontDatabase() const Q_DECL_OVERRIDE; + QPlatformServices *services() const Q_DECL_OVERRIDE; + QPlatformInputContext *inputContext() const Q_DECL_OVERRIDE { return m_inputContext; } QList<QPlatformScreen *> screens() const; private: QLinuxFbScreen *m_primaryScreen; - QPlatformFontDatabase *m_fontDb; - + QPlatformInputContext *m_inputContext; + QScopedPointer<QPlatformFontDatabase> m_fontDb; + QScopedPointer<QPlatformServices> m_services; + QScopedPointer<QFbVtHandler> m_vtHandler; }; QT_END_NAMESPACE #endif // QLINUXFBINTEGRATION_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..c605126091 100644 --- a/src/plugins/platforms/qnx/qnx.pro +++ b/src/plugins/platforms/qnx/qnx.pro @@ -45,7 +45,8 @@ SOURCES = main.cpp \ qqnxabstractvirtualkeyboard.cpp \ qqnxservices.cpp \ qqnxcursor.cpp \ - qqnxrasterwindow.cpp + qqnxrasterwindow.cpp \ + qqnxglobal.cpp HEADERS = main.h \ qqnxbuffer.h \ @@ -62,7 +63,9 @@ HEADERS = main.h \ qqnxabstractcover.h \ qqnxservices.h \ qqnxcursor.h \ - qqnxrasterwindow.h + qqnxrasterwindow.h \ + qqnxscreeneventfilter.h \ + qqnxglobal.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/qqnxbuffer.cpp b/src/plugins/platforms/qnx/qqnxbuffer.cpp index abb8a07026..e9afd5232b 100644 --- a/src/plugins/platforms/qnx/qqnxbuffer.cpp +++ b/src/plugins/platforms/qnx/qqnxbuffer.cpp @@ -39,6 +39,8 @@ ** ****************************************************************************/ +#include "qqnxglobal.h" + #include "qqnxbuffer.h" #include <QtCore/QDebug> @@ -66,34 +68,30 @@ QQnxBuffer::QQnxBuffer(screen_buffer_t buffer) qBufferDebug() << Q_FUNC_INFO << "normal"; // Get size of buffer - errno = 0; int size[2]; - int result = screen_get_buffer_property_iv(buffer, SCREEN_PROPERTY_BUFFER_SIZE, size); - if (result != 0) - qFatal("QQNX: failed to query buffer size, errno=%d", errno); + Q_SCREEN_CRITICALERROR(screen_get_buffer_property_iv(buffer, SCREEN_PROPERTY_BUFFER_SIZE, size), + "Failed to query buffer size"); // Get stride of buffer - errno = 0; int stride; - result = screen_get_buffer_property_iv(buffer, SCREEN_PROPERTY_STRIDE, &stride); - if (result != 0) - qFatal("QQNX: failed to query buffer stride, errno=%d", errno); + Q_SCREEN_CHECKERROR(screen_get_buffer_property_iv(buffer, SCREEN_PROPERTY_STRIDE, &stride), + "Failed to query buffer stride"); // Get access to buffer's data errno = 0; uchar *dataPtr = 0; - result = screen_get_buffer_property_pv(buffer, SCREEN_PROPERTY_POINTER, (void **)&dataPtr); - if (result != 0) - qFatal("QQNX: failed to query buffer pointer, errno=%d", errno); + Q_SCREEN_CRITICALERROR( + screen_get_buffer_property_pv(buffer, SCREEN_PROPERTY_POINTER, (void **)&dataPtr), + "Failed to query buffer pointer"); + if (dataPtr == 0) qFatal("QQNX: buffer pointer is NULL, errno=%d", errno); // Get format of buffer - errno = 0; int screenFormat; - result = screen_get_buffer_property_iv(buffer, SCREEN_PROPERTY_FORMAT, &screenFormat); - if (result != 0) - qFatal("QQNX: failed to query buffer format, errno=%d", errno); + Q_SCREEN_CHECKERROR( + screen_get_buffer_property_iv(buffer, SCREEN_PROPERTY_FORMAT, &screenFormat), + "Failed to query buffer format"); // Convert screen format to QImage format QImage::Format imageFormat = QImage::Format_Invalid; diff --git a/src/plugins/platforms/qnx/qqnxeglwindow.cpp b/src/plugins/platforms/qnx/qqnxeglwindow.cpp index 984de67d7d..45a7bab871 100644 --- a/src/plugins/platforms/qnx/qqnxeglwindow.cpp +++ b/src/plugins/platforms/qnx/qqnxeglwindow.cpp @@ -86,8 +86,9 @@ void QQnxEglWindow::createEGLSurface() // the window's buffers before we create the EGL surface const QSize surfaceSize = requestedBufferSize(); if (!surfaceSize.isValid()) { - qFatal("QQNX: Trying to create 0 size EGL surface. " + qWarning("QQNX: Trying to create 0 size EGL surface. " "Please set a valid window size before calling QOpenGLContext::makeCurrent()"); + return; } setBufferSize(surfaceSize); @@ -104,8 +105,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"); + qWarning("QQNX: failed to create EGL surface, err=%d", error); } } @@ -141,6 +142,8 @@ void QQnxEglWindow::swapEGLBuffers() EGLSurface QQnxEglWindow::getSurface() { if (m_newSurfaceRequested.testAndSetOrdered(true, false)) { + const QMutexLocker locker(&m_mutex); //Set geomety must not reset the requestedBufferSize till + //the surface is created if (m_eglSurface != EGL_NO_SURFACE) { platformOpenGLContext()->doneCurrent(); destroyEGLSurface(); @@ -172,17 +175,9 @@ void QQnxEglWindow::setGeometry(const QRect &rect) QSize QQnxEglWindow::requestedBufferSize() const { - const QMutexLocker locker(&m_mutex); return m_requestedBufferSize; } -void QQnxEglWindow::adjustBufferSize() -{ - const QSize windowSize = window()->size(); - if (windowSize != bufferSize()) - setBufferSize(windowSize); -} - void QQnxEglWindow::setPlatformOpenGLContext(QQnxGLContext *platformOpenGLContext) { // This function does not take ownership of the platform gl context. @@ -220,7 +215,6 @@ int QQnxEglWindow::pixelFormat() const void QQnxEglWindow::resetBuffers() { - const QMutexLocker locker(&m_mutex); m_requestedBufferSize = QSize(); } diff --git a/src/plugins/platforms/qnx/qqnxeglwindow.h b/src/plugins/platforms/qnx/qqnxeglwindow.h index fc53afcd7a..a6a223c58e 100644 --- a/src/plugins/platforms/qnx/qqnxeglwindow.h +++ b/src/plugins/platforms/qnx/qqnxeglwindow.h @@ -68,8 +68,6 @@ public: // Called by QQnxGLContext::createSurface() QSize requestedBufferSize() const; - void adjustBufferSize(); - protected: int pixelFormat() const; void resetBuffers(); diff --git a/src/plugins/platforms/qnx/qqnxglcontext.cpp b/src/plugins/platforms/qnx/qqnxglcontext.cpp index 34e8150928..3a365be408 100644 --- a/src/plugins/platforms/qnx/qqnxglcontext.cpp +++ b/src/plugins/platforms/qnx/qqnxglcontext.cpp @@ -132,7 +132,7 @@ QQnxGLContext::QQnxGLContext(QOpenGLContext *glContext) } } - m_eglContext = eglCreateContext(ms_eglDisplay, m_eglConfig, shareContext, contextAttrs()); + m_eglContext = eglCreateContext(ms_eglDisplay, m_eglConfig, shareContext, contextAttrs(format)); if (m_eglContext == EGL_NO_CONTEXT) { checkEGLError("eglCreateContext"); qFatal("QQnxGLContext: failed to create EGL context, err=%d", eglGetError()); @@ -227,7 +227,8 @@ bool QQnxGLContext::makeCurrent(QPlatformSurface *surface) eglResult = eglMakeCurrent(ms_eglDisplay, m_currentEglSurface, m_currentEglSurface, m_eglContext); if (eglResult != EGL_TRUE) { checkEGLError("eglMakeCurrent"); - qFatal("QQNX: failed to set current EGL context, err=%d", eglGetError()); + qWarning("QQNX: failed to set current EGL context, err=%d", eglGetError()); + return false; } return (eglResult == EGL_TRUE); } @@ -274,13 +275,13 @@ EGLDisplay QQnxGLContext::getEglDisplay() { return ms_eglDisplay; } -EGLint *QQnxGLContext::contextAttrs() +EGLint *QQnxGLContext::contextAttrs(const QSurfaceFormat &format) { qGLContextDebug() << Q_FUNC_INFO; // Choose EGL settings based on OpenGL version #if defined(QT_OPENGL_ES_2) - static EGLint attrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; + static EGLint attrs[] = { EGL_CONTEXT_CLIENT_VERSION, format.version().first, EGL_NONE }; return attrs; #else return 0; diff --git a/src/plugins/platforms/qnx/qqnxglcontext.h b/src/plugins/platforms/qnx/qqnxglcontext.h index 2b12657da9..af89586bd5 100644 --- a/src/plugins/platforms/qnx/qqnxglcontext.h +++ b/src/plugins/platforms/qnx/qqnxglcontext.h @@ -88,7 +88,7 @@ private: EGLContext m_eglContext; EGLSurface m_currentEglSurface; - static EGLint *contextAttrs(); + static EGLint *contextAttrs(const QSurfaceFormat &format); }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxglobal.cpp b/src/plugins/platforms/qnx/qqnxglobal.cpp new file mode 100644 index 0000000000..cef37af84e --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxglobal.cpp @@ -0,0 +1,63 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2014 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$ +** +****************************************************************************/ +#include <errno.h> + +#include <QDebug> +#include "qqnxintegration.h" + +QT_BEGIN_NAMESPACE + +void qScreenCheckError(int rc, const char *funcInfo, const char *message, bool critical) +{ + if (!rc && (QQnxIntegration::options() & QQnxIntegration::AlwaysFlushScreenContext) + && QQnxIntegration::screenContext() != 0) { + rc = screen_flush_context(QQnxIntegration::screenContext(), 0); + } + + if (rc) { + if (critical) + qCritical("%s - Screen: %s - Error: %s (%i)", funcInfo, message, strerror(errno), errno); + else + qWarning("%s - Screen: %s - Error: %s (%i)", funcInfo, message, strerror(errno), errno); + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxglobal.h b/src/plugins/platforms/qnx/qqnxglobal.h new file mode 100644 index 0000000000..8cfbfb084a --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxglobal.h @@ -0,0 +1,59 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2014 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 QQNXGLOBAL_H +#define QQNXGLOBAL_H + +#include <qglobal.h> + +QT_BEGIN_NAMESPACE + +void qScreenCheckError(int rc, const char *funcInfo, const char *message, bool critical); + +#define Q_SCREEN_CHECKERROR(x, message) \ +qScreenCheckError(x, Q_FUNC_INFO, message, false) + +#define Q_SCREEN_CRITICALERROR(x, message) \ +qScreenCheckError(x, Q_FUNC_INFO, message, true) + +QT_END_NAMESPACE + +#endif // QQNXGLOBAL_H 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..b39311353c 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. @@ -39,6 +39,8 @@ ** ****************************************************************************/ +#include "qqnxglobal.h" + #include "qqnxintegration.h" #if defined(QQNX_SCREENEVENTTHREAD) #include "qqnxscreeneventthread.h" @@ -123,6 +125,10 @@ static inline QQnxIntegration::Options parseOptions(const QStringList ¶mList options |= QQnxIntegration::FullScreenApplication; } + if (!paramList.contains(QLatin1String("flush-screen-context"))) { + options |= QQnxIntegration::AlwaysFlushScreenContext; + } + // On Blackberry the first window is treated as a root window #ifdef Q_OS_BLACKBERRY if (!paramList.contains(QLatin1String("no-rootwindow"))) { @@ -165,14 +171,12 @@ QQnxIntegration::QQnxIntegration(const QStringList ¶mList) #if !defined(QT_NO_DRAGANDDROP) , m_drag(new QSimpleDrag()) #endif - , m_options(parseOptions(paramList)) { + ms_options = parseOptions(paramList); qIntegrationDebug() << Q_FUNC_INFO; // Open connection to QNX composition manager - errno = 0; - int result = screen_create_context(&m_screenContext, SCREEN_APPLICATION_CONTEXT); - if (result != 0) - qFatal("QQnx: failed to connect to composition manager, errno=%d", errno); + Q_SCREEN_CRITICALERROR(screen_create_context(&ms_screenContext, SCREEN_APPLICATION_CONTEXT), + "Failed to create screen context"); // Not on BlackBerry, it has specialized event dispatcher which also handles navigator events #if !defined(Q_OS_BLACKBERRY) && defined(QQNX_PPS) @@ -191,7 +195,7 @@ QQnxIntegration::QQnxIntegration(const QStringList ¶mList) // Create/start event thread #if defined(QQNX_SCREENEVENTTHREAD) - m_screenEventThread = new QQnxScreenEventThread(m_screenContext, m_screenEventHandler); + m_screenEventThread = new QQnxScreenEventThread(ms_screenContext, m_screenEventHandler); m_screenEventThread->start(); #endif @@ -251,6 +255,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 +278,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; @@ -314,13 +310,24 @@ QQnxIntegration::~QQnxIntegration() destroyDisplays(); // Close connection to QNX composition manager - screen_destroy_context(m_screenContext); + screen_destroy_context(ms_screenContext); #if !defined(QT_NO_OPENGL) // Cleanup global OpenGL resources 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; @@ -355,10 +362,10 @@ QPlatformWindow *QQnxIntegration::createPlatformWindow(QWindow *window) const const bool needRootWindow = options() & RootWindow; switch (surfaceType) { case QSurface::RasterSurface: - return new QQnxRasterWindow(window, m_screenContext, needRootWindow); + return new QQnxRasterWindow(window, ms_screenContext, needRootWindow); #if !defined(QT_NO_OPENGL) case QSurface::OpenGLSurface: - return new QQnxEglWindow(window, m_screenContext, needRootWindow); + return new QQnxEglWindow(window, ms_screenContext, needRootWindow); #endif default: qFatal("QQnxWindow: unsupported window API"); @@ -441,7 +448,7 @@ QPlatformDrag *QQnxIntegration::drag() const QVariant QQnxIntegration::styleHint(QPlatformIntegration::StyleHint hint) const { qIntegrationDebug() << Q_FUNC_INFO; - if ((hint == ShowIsFullScreen) && (m_options & FullScreenApplication)) + if ((hint == ShowIsFullScreen) && (ms_options & FullScreenApplication)) return true; return QPlatformIntegration::styleHint(hint); @@ -495,11 +502,10 @@ void QQnxIntegration::createDisplays() { qIntegrationDebug() << Q_FUNC_INFO; // Query number of displays - errno = 0; - int displayCount; - int result = screen_get_context_property_iv(m_screenContext, SCREEN_PROPERTY_DISPLAY_COUNT, &displayCount); - if (result != 0) - qFatal("QQnxIntegration: failed to query display count, errno=%d", errno); + int displayCount = 0; + int result = screen_get_context_property_iv(ms_screenContext, SCREEN_PROPERTY_DISPLAY_COUNT, + &displayCount); + Q_SCREEN_CRITICALERROR(result, "Failed to query display count"); if (displayCount < 1) { // Never happens, even if there's no display, libscreen returns 1 @@ -507,23 +513,20 @@ void QQnxIntegration::createDisplays() } // Get all displays - errno = 0; screen_display_t *displays = (screen_display_t *)alloca(sizeof(screen_display_t) * displayCount); - result = screen_get_context_property_pv(m_screenContext, SCREEN_PROPERTY_DISPLAYS, (void **)displays); - if (result != 0) - qFatal("QQnxIntegration: failed to query displays, errno=%d", errno); + result = screen_get_context_property_pv(ms_screenContext, SCREEN_PROPERTY_DISPLAYS, + (void **)displays); + Q_SCREEN_CRITICALERROR(result, "Failed to query displays"); // If it's primary, we create a QScreen for it even if it's not attached // since Qt will dereference QGuiApplication::primaryScreen() createDisplay(displays[0], /*isPrimary=*/true); for (int i=1; i<displayCount; i++) { - int isAttached = 0; - result = screen_get_display_property_iv(displays[i], SCREEN_PROPERTY_ATTACHED, &isAttached); - if (result != 0) { - qWarning("QQnxIntegration: failed to query display attachment, errno=%d", errno); - isAttached = 1; // assume attached - } + int isAttached = 1; + result = screen_get_display_property_iv(displays[i], SCREEN_PROPERTY_ATTACHED, + &isAttached); + Q_SCREEN_CHECKERROR(result, "Failed to query display attachment"); if (!isAttached) { qIntegrationDebug() << Q_FUNC_INFO << "Skipping non-attached display" << i; @@ -537,7 +540,7 @@ void QQnxIntegration::createDisplays() void QQnxIntegration::createDisplay(screen_display_t display, bool isPrimary) { - QQnxScreen *screen = new QQnxScreen(m_screenContext, display, isPrimary); + QQnxScreen *screen = new QQnxScreen(ms_screenContext, display, isPrimary); m_screens.append(screen); screenAdded(screen); screen->adjustOrientation(); @@ -584,11 +587,20 @@ QQnxScreen *QQnxIntegration::primaryDisplay() const return m_screens.first(); } -QQnxIntegration::Options QQnxIntegration::options() const +QQnxIntegration::Options QQnxIntegration::options() +{ + return ms_options; +} + +screen_context_t QQnxIntegration::screenContext() { - return m_options; + return ms_screenContext; } +screen_context_t QQnxIntegration::ms_screenContext = 0; + +QQnxIntegration::Options QQnxIntegration::ms_options = 0; + bool QQnxIntegration::supportsNavigatorEvents() const { // If QQNX_PPS or Q_OS_BLACKBERRY is defined then we have navigator diff --git a/src/plugins/platforms/qnx/qqnxintegration.h b/src/plugins/platforms/qnx/qqnxintegration.h index 8b5614fe4f..b5f03d4727 100644 --- a/src/plugins/platforms/qnx/qqnxintegration.h +++ b/src/plugins/platforms/qnx/qqnxintegration.h @@ -85,7 +85,8 @@ public: enum Option { // Options to be passed on command line. NoOptions = 0x0, FullScreenApplication = 0x1, - RootWindow = 0x2 + RootWindow = 0x2, + AlwaysFlushScreenContext = 0x4 }; Q_DECLARE_FLAGS(Options, Option) explicit QQnxIntegration(const QStringList ¶mList); @@ -137,7 +138,8 @@ public: void createDisplay(screen_display_t display, bool isPrimary); void removeDisplay(QQnxScreen *screen); QQnxScreen *primaryDisplay() const; - Options options() const; + static Options options(); + static screen_context_t screenContext(); private: void createDisplays(); @@ -146,7 +148,7 @@ private: static void addWindow(screen_window_t qnxWindow, QWindow *window); static void removeWindow(screen_window_t qnxWindow); - screen_context_t m_screenContext; + static screen_context_t ms_screenContext; #if defined(QQNX_SCREENEVENTTHREAD) QQnxScreenEventThread *m_screenEventThread; #endif @@ -176,7 +178,7 @@ private: static QQnxWindowMapper ms_windowMapper; static QMutex ms_windowMapperMutex; - const Options m_options; + static Options ms_options; friend class QQnxWindow; }; 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/qqnxrasterwindow.cpp b/src/plugins/platforms/qnx/qqnxrasterwindow.cpp index 0d8daac0ee..2c0639e8e3 100644 --- a/src/plugins/platforms/qnx/qqnxrasterwindow.cpp +++ b/src/plugins/platforms/qnx/qqnxrasterwindow.cpp @@ -39,6 +39,8 @@ ** ****************************************************************************/ +#include "qqnxglobal.h" + #include "qqnxrasterwindow.h" #include "qqnxscreen.h" @@ -108,10 +110,9 @@ void QQnxRasterWindow::post(const QRegion &dirty) int dirtyRect[4] = { rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height() }; // Update the display with contents of render buffer - errno = 0; - int result = screen_post_window(nativeHandle(), currentBuffer.nativeBuffer(), 1, dirtyRect, 0); - if (result != 0) - qFatal("QQnxWindow: failed to post window buffer, errno=%d", errno); + Q_SCREEN_CHECKERROR( + screen_post_window(nativeHandle(), currentBuffer.nativeBuffer(), 1, dirtyRect, 0), + "Failed to post window"); // Advance to next nender buffer m_previousBufferIndex = m_currentBufferIndex++; @@ -141,28 +142,23 @@ QQnxBuffer &QQnxRasterWindow::renderBuffer() // Check if render buffer is invalid if (m_currentBufferIndex == -1) { // Get all buffers available for rendering - errno = 0; screen_buffer_t buffers[MAX_BUFFER_COUNT]; - int result = screen_get_window_property_pv(nativeHandle(), SCREEN_PROPERTY_RENDER_BUFFERS, (void **)buffers); - if (result != 0) - qFatal("QQnxRasterWindow: failed to query window buffers, errno=%d", errno); + const int result = screen_get_window_property_pv(nativeHandle(), SCREEN_PROPERTY_RENDER_BUFFERS, + (void **)buffers); + Q_SCREEN_CRITICALERROR(result, "Failed to query window buffers"); // Wrap each buffer and clear for (int i = 0; i < MAX_BUFFER_COUNT; ++i) { m_buffers[i] = QQnxBuffer(buffers[i]); // Clear Buffer - errno = 0; int bg[] = { SCREEN_BLIT_COLOR, 0x00000000, SCREEN_BLIT_END }; - result = screen_fill(screen()->nativeContext(), buffers[i], bg); - if (result != 0) - qFatal("QQnxWindow: failed to clear window buffer, errno=%d", errno); + Q_SCREEN_CHECKERROR(screen_fill(screen()->nativeContext(), buffers[i], bg), + "Failed to clear window buffer"); } - errno = 0; - result = screen_flush_blits(screen()->nativeContext(), 0); - if (result != 0) - qFatal("QQnxWindow: failed to flush blits, errno=%d", errno); + Q_SCREEN_CHECKERROR(screen_flush_blits(screen()->nativeContext(), 0), + "Failed to flush blits"); // Use the first available render buffer m_currentBufferIndex = 0; @@ -172,11 +168,17 @@ QQnxBuffer &QQnxRasterWindow::renderBuffer() return m_buffers[m_currentBufferIndex]; } +void QQnxRasterWindow::setParent(const QPlatformWindow *wnd) +{ + QQnxWindow::setParent(wnd); + adjustBufferSize(); +} + void QQnxRasterWindow::adjustBufferSize() { // When having a raster window we don't need any buffers, since // Qt will draw to the parent TLW backing store. - const QSize windowSize = m_parentWindow ? QSize(1,1) : window()->size(); + const QSize windowSize = window()->parent() ? QSize(1,1) : window()->size(); if (windowSize != bufferSize()) setBufferSize(windowSize); } @@ -226,20 +228,16 @@ void QQnxRasterWindow::blitPreviousToCurrent(const QRegion ®ion, int dx, int SCREEN_BLIT_END }; // Queue blit operation - errno = 0; - const int result = screen_blit(m_screenContext, currentBuffer.nativeBuffer(), - previousBuffer.nativeBuffer(), attribs); - if (result != 0) - qFatal("QQnxWindow: failed to blit buffers, errno=%d", errno); + Q_SCREEN_CHECKERROR(screen_blit(m_screenContext, currentBuffer.nativeBuffer(), + previousBuffer.nativeBuffer(), attribs), + "Failed to blit buffers"); } // Check if flush requested if (flush) { // Wait for all blits to complete - errno = 0; - const int result = screen_flush_blits(m_screenContext, SCREEN_WAIT_IDLE); - if (result != 0) - qFatal("QQnxWindow: failed to flush blits, errno=%d", errno); + Q_SCREEN_CHECKERROR(screen_flush_blits(m_screenContext, SCREEN_WAIT_IDLE), + "Failed to flush blits"); // Buffer was modified outside the CPU currentBuffer.invalidateInCache(); diff --git a/src/plugins/platforms/qnx/qqnxrasterwindow.h b/src/plugins/platforms/qnx/qqnxrasterwindow.h index ad34b3ccf2..2be5f63464 100644 --- a/src/plugins/platforms/qnx/qqnxrasterwindow.h +++ b/src/plugins/platforms/qnx/qqnxrasterwindow.h @@ -60,6 +60,8 @@ public: bool hasBuffers() const { return !bufferSize().isEmpty(); } + void setParent(const QPlatformWindow *window); + void adjustBufferSize(); protected: diff --git a/src/plugins/platforms/qnx/qqnxscreen.cpp b/src/plugins/platforms/qnx/qqnxscreen.cpp index 3a0607f214..a6c69164c7 100644 --- a/src/plugins/platforms/qnx/qqnxscreen.cpp +++ b/src/plugins/platforms/qnx/qqnxscreen.cpp @@ -39,6 +39,8 @@ ** ****************************************************************************/ +#include "qqnxglobal.h" + #include "qqnxscreen.h" #include "qqnxwindow.h" #include "qqnxcursor.h" @@ -75,10 +77,9 @@ QT_BEGIN_NAMESPACE static QSize determineScreenSize(screen_display_t display, bool primaryScreen) { int val[2]; - errno = 0; const int result = screen_get_display_property_iv(display, SCREEN_PROPERTY_PHYSICAL_SIZE, val); + Q_SCREEN_CHECKERROR(result, "Failed to query display physical size"); if (result != 0) { - qFatal("QQnxScreen: failed to query display physical size, errno=%d", errno); return QSize(150, 90); } @@ -163,19 +164,16 @@ QQnxScreen::QQnxScreen(screen_context_t screenContext, screen_display_t display, { qScreenDebug() << Q_FUNC_INFO; // Cache initial orientation of this display - errno = 0; - int result = screen_get_display_property_iv(m_display, SCREEN_PROPERTY_ROTATION, &m_initialRotation); - if (result != 0) - qFatal("QQnxScreen: failed to query display rotation, errno=%d", errno); + int result = screen_get_display_property_iv(m_display, SCREEN_PROPERTY_ROTATION, + &m_initialRotation); + Q_SCREEN_CHECKERROR(result, "Failed to query display rotation"); m_currentRotation = m_initialRotation; // Cache size of this display in pixels - errno = 0; int val[2]; - result = screen_get_display_property_iv(m_display, SCREEN_PROPERTY_SIZE, val); - if (result != 0) - qFatal("QQnxScreen: failed to query display size, errno=%d", errno); + Q_SCREEN_CRITICALERROR(screen_get_display_property_iv(m_display, SCREEN_PROPERTY_SIZE, val), + "Failed to query display size"); m_currentGeometry = m_initialGeometry = QRect(0, 0, val[0], val[1]); @@ -200,6 +198,9 @@ QQnxScreen::~QQnxScreen() Q_FOREACH (QQnxWindow *childWindow, m_childWindows) childWindow->setScreen(0); + if (m_coverWindow) + m_coverWindow->setScreen(0); + delete m_cursor; } @@ -505,7 +506,6 @@ void QQnxScreen::raiseWindow(QQnxWindow *window) if (window != m_coverWindow) { removeWindow(window); m_childWindows.push_back(window); - updateHierarchy(); } } @@ -516,7 +516,6 @@ void QQnxScreen::lowerWindow(QQnxWindow *window) if (window != m_coverWindow) { removeWindow(window); m_childWindows.push_front(window); - updateHierarchy(); } } @@ -671,7 +670,7 @@ void QQnxScreen::newWindowCreated(void *window) // Otherwise, assume that if a foreign window already has a Z-Order both negative and // less than the default Z-Order installed by mmrender on windows it creates, // the windows should be treated as an underlay. Otherwise, we treat it as an overlay. - if (!windowName.isEmpty() && windowName.startsWith("BbVideoWindowControl")) { + if (!windowName.isEmpty() && windowName.startsWith("MmRendererVideoWindowControl")) { addMultimediaWindow(windowName, windowHandle); } else if (!findWindow(windowHandle)) { if (zorder <= MAX_UNDERLAY_ZORDER) @@ -728,8 +727,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 +741,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..8757e391ef 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. @@ -39,6 +39,8 @@ ** ****************************************************************************/ +#include "qqnxglobal.h" + #include "qqnxscreeneventhandler.h" #if defined(QQNX_SCREENEVENTTHREAD) #include "qqnxscreeneventthread.h" @@ -46,6 +48,7 @@ #include "qqnxintegration.h" #include "qqnxkeytranslator.h" #include "qqnxscreen.h" +#include "qqnxscreeneventfilter.h" #include <QDebug> #include <QGuiApplication> @@ -90,14 +93,22 @@ 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 - errno = 0; int qnxType; - int result = screen_get_event_property_iv(event, SCREEN_PROPERTY_TYPE, &qnxType); - if (result) - qFatal("QQNX: failed to query event type, errno=%d", errno); + Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_TYPE, &qnxType), + "Failed to query event type"); return handleEvent(event, qnxType); } @@ -228,35 +239,44 @@ void QQnxScreenEventHandler::processEventsFromScreenThread() void QQnxScreenEventHandler::handleKeyboardEvent(screen_event_t event) { // get flags of key event - errno = 0; int flags; - int result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_FLAGS, &flags); - if (result) - qFatal("QQNX: failed to query event flags, errno=%d", errno); + Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_FLAGS, &flags), + "Failed to query event flags"); // get key code - errno = 0; int sym; - result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_SYM, &sym); - if (result) - qFatal("QQNX: failed to query event sym, errno=%d", errno); + Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_SYM, &sym), + "Failed to query event sym"); int modifiers; - result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_MODIFIERS, &modifiers); - if (result) - qFatal("QQNX: failed to query event modifiers, errno=%d", errno); + Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_MODIFIERS, &modifiers), + "Failed to query event modifieres"); int scan; - result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_SCAN, &scan); - if (result) - qFatal("QQNX: failed to query event modifiers, errno=%d", errno); + Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_SCAN, &scan), + "Failed to query event scan"); int cap; - result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_CAP, &cap); - if (result) - qFatal("QQNX: failed to query event cap, errno=%d", errno); + Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_CAP, &cap), + "Failed to query event cap"); + + int sequenceId = 0; +#if defined(Q_OS_BLACKBERRY) + Q_SCREEN_CHECKERROR( + screen_get_event_property_iv(event, SCREEN_PROPERTY_SEQUENCE_ID, &sequenceId), + "Failed to query event seqId"); +#endif - injectKeyboardEvent(flags, sym, modifiers, scan, cap); + 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) @@ -266,35 +286,32 @@ void QQnxScreenEventHandler::handlePointerEvent(screen_event_t event) // Query the window that was clicked screen_window_t qnxWindow; void *handle; - int result = screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &handle); - if (result) - qFatal("QQNX: failed to query event window, errno=%d", errno); + Q_SCREEN_CHECKERROR(screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &handle), + "Failed to query event window"); qnxWindow = static_cast<screen_window_t>(handle); // Query the button states int buttonState = 0; - result = screen_get_event_property_iv(event, SCREEN_PROPERTY_BUTTONS, &buttonState); - if (result) - qFatal("QQNX: failed to query event button state, errno=%d", errno); + Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_BUTTONS, &buttonState), + "Failed to query event button state"); // Query the window position int windowPos[2]; - result = screen_get_event_property_iv(event, SCREEN_PROPERTY_SOURCE_POSITION, windowPos); - if (result) - qFatal("QQNX: failed to query event window position, errno=%d", errno); + Q_SCREEN_CHECKERROR( + screen_get_event_property_iv(event, SCREEN_PROPERTY_SOURCE_POSITION, windowPos), + "Failed to query event window position"); // Query the screen position int pos[2]; - result = screen_get_event_property_iv(event, SCREEN_PROPERTY_POSITION, pos); - if (result) - qFatal("QQNX: failed to query event position, errno=%d", errno); + Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_POSITION, pos), + "Failed to query event position"); // Query the wheel delta int wheelDelta = 0; - result = screen_get_event_property_iv(event, SCREEN_PROPERTY_MOUSE_WHEEL, &wheelDelta); - if (result) - qFatal("QQNX: failed to query event wheel delta, errno=%d", errno); + Q_SCREEN_CHECKERROR( + screen_get_event_property_iv(event, SCREEN_PROPERTY_MOUSE_WHEEL, &wheelDelta), + "Failed to query event wheel delta"); // Map window handle to top-level QWindow QWindow *w = QQnxIntegration::window(qnxWindow); @@ -314,10 +331,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 @@ -376,34 +389,36 @@ void QQnxScreenEventHandler::handlePointerEvent(screen_event_t event) void QQnxScreenEventHandler::handleTouchEvent(screen_event_t event, int qnxType) { // get display coordinates of touch - errno = 0; int pos[2]; - int result = screen_get_event_property_iv(event, SCREEN_PROPERTY_POSITION, pos); - if (result) - qFatal("QQNX: failed to query event position, errno=%d", errno); + Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_POSITION, pos), + "Failed to query event position"); QCursor::setPos(pos[0], pos[1]); // get window coordinates of touch - errno = 0; int windowPos[2]; - result = screen_get_event_property_iv(event, SCREEN_PROPERTY_SOURCE_POSITION, windowPos); - if (result) - qFatal("QQNX: failed to query event window position, errno=%d", errno); + Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_SOURCE_POSITION, windowPos), + "Failed to query event window position"); // determine which finger touched - errno = 0; int touchId; - result = screen_get_event_property_iv(event, SCREEN_PROPERTY_TOUCH_ID, &touchId); - if (result) - qFatal("QQNX: failed to query event touch id, errno=%d", errno); + Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_TOUCH_ID, &touchId), + "Failed to query event touch id"); // determine which window was touched - errno = 0; void *handle; - result = screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &handle); - if (result) - qFatal("QQNX: failed to query event window, errno=%d", errno); + Q_SCREEN_CHECKERROR(screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &handle), + "Failed to query event window"); + + errno = 0; + int touchArea[2]; + Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_SIZE, touchArea), + "Failed to query event touch area"); + + int touchPressure; + Q_SCREEN_CHECKERROR( + screen_get_event_property_iv(event, SCREEN_PROPERTY_TOUCH_PRESSURE, &touchPressure), + "Failed to query event touch pressure"); screen_window_t qnxWindow = static_cast<screen_window_t>(handle); @@ -439,14 +454,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) { @@ -489,8 +513,9 @@ void QQnxScreenEventHandler::handleTouchEvent(screen_event_t event, int qnxType) void QQnxScreenEventHandler::handleCloseEvent(screen_event_t event) { screen_window_t window = 0; - if (screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, (void**)&window) != 0) - qFatal("QQnx: failed to query window property, errno=%d", errno); + Q_SCREEN_CHECKERROR( + screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, (void**)&window), + "Failed to query window property"); Q_EMIT windowClosed(window); @@ -503,8 +528,9 @@ void QQnxScreenEventHandler::handleCloseEvent(screen_event_t event) void QQnxScreenEventHandler::handleCreateEvent(screen_event_t event) { screen_window_t window = 0; - if (screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, (void**)&window) != 0) - qFatal("QQnx: failed to query window property, errno=%d", errno); + Q_SCREEN_CHECKERROR( + screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, (void**)&window), + "Failed to query window property"); Q_EMIT newWindowCreated(window); } @@ -556,8 +582,9 @@ void QQnxScreenEventHandler::handlePropertyEvent(screen_event_t event) { errno = 0; int objectType; - if (screen_get_event_property_iv(event, SCREEN_PROPERTY_OBJECT_TYPE, &objectType) != 0) - qFatal("QQNX: failed to query object type property, errno=%d", errno); + Q_SCREEN_CHECKERROR( + screen_get_event_property_iv(event, SCREEN_PROPERTY_OBJECT_TYPE, &objectType), + "Failed to query object type property"); if (objectType != SCREEN_OBJECT_TYPE_WINDOW) return; @@ -589,9 +616,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/qqnxscreeneventthread.cpp b/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp index 25a597bab9..156ba8a780 100644 --- a/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp +++ b/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp @@ -39,6 +39,8 @@ ** ****************************************************************************/ +#include "qqnxglobal.h" + #include "qqnxscreeneventthread.h" #include "qqnxscreeneventhandler.h" @@ -92,30 +94,34 @@ void QQnxScreenEventThread::run() { qScreenEventThreadDebug() << Q_FUNC_INFO << "screen event thread started"; + int errorCounter = 0; // loop indefinitely while (!m_quit) { screen_event_t event; // create screen event - errno = 0; - int result = screen_create_event(&event); - if (result) - qFatal("QQNX: failed to create screen event, errno=%d", errno); - + Q_SCREEN_CHECKERROR(screen_create_event(&event), "Failed to create screen event"); // block until screen event is available - errno = 0; - result = screen_get_event(m_screenContext, event, -1); - if (result) - qFatal("QQNX: failed to get screen event, errno=%d", errno); + const int result = screen_get_event(m_screenContext, event, -1); + Q_SCREEN_CRITICALERROR(result, "Failed to get screen event"); + // Only allow 50 consecutive errors before we exit the thread + if (!result) { + errorCounter++; + if (errorCounter > 50) + m_quit = true; + + screen_destroy_event(event); + continue; + } else { + errorCounter = 0; + } // process received event // get the event type - errno = 0; int qnxType; - result = screen_get_event_property_iv(event, SCREEN_PROPERTY_TYPE, &qnxType); - if (result) - qFatal("QQNX: failed to query screen event type, errno=%d", errno); + Q_SCREEN_CHECKERROR(screen_get_event_property_iv(event, SCREEN_PROPERTY_TYPE, &qnxType), + "Failed to query screen event type"); if (qnxType == SCREEN_EVENT_USER) { // treat all user events as shutdown requests @@ -145,25 +151,19 @@ void QQnxScreenEventThread::shutdown() screen_event_t event; // create screen event - errno = 0; - int result = screen_create_event(&event); - if (result) - qFatal("QQNX: failed to create screen event, errno=%d", errno); + Q_SCREEN_CHECKERROR(screen_create_event(&event), + "Failed to create screen event"); // set the event type as user - errno = 0; int type = SCREEN_EVENT_USER; - result = screen_set_event_property_iv(event, SCREEN_PROPERTY_TYPE, &type); - if (result) - qFatal("QQNX: failed to set screen event type, errno=%d", errno); + Q_SCREEN_CHECKERROR(screen_set_event_property_iv(event, SCREEN_PROPERTY_TYPE, &type), + "Failed to set screen type"); // NOTE: ignore SCREEN_PROPERTY_USER_DATA; treat all user events as shutdown events // post event to event loop so it will wake up and die - errno = 0; - result = screen_send_event(m_screenContext, event, getpid()); - if (result) - qFatal("QQNX: failed to set screen event type, errno=%d", errno); + Q_SCREEN_CHECKERROR(screen_send_event(m_screenContext, event, getpid()), + "Failed to set screen event type"); // cleanup screen_destroy_event(event); 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..bb76efea64 100644 --- a/src/plugins/platforms/qnx/qqnxwindow.cpp +++ b/src/plugins/platforms/qnx/qqnxwindow.cpp @@ -39,6 +39,8 @@ ** ****************************************************************************/ +#include "qqnxglobal.h" + #include "qqnxwindow.h" #include "qqnxintegration.h" #include "qqnxscreen.h" @@ -73,36 +75,45 @@ QT_BEGIN_NAMESPACE QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, bool needRootWindow) : QPlatformWindow(window), m_screenContext(context), - m_parentWindow(0), m_window(0), m_screen(0), + m_parentWindow(0), m_visible(false), m_exposed(true), m_windowState(Qt::WindowNoState), m_mmRendererWindow(0) { qWindowDebug() << Q_FUNC_INFO << "window =" << window << ", size =" << window->size(); - int result; 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) { - result = screen_create_window(&m_window, m_screenContext); // Creates an application window + Q_SCREEN_CRITICALERROR(screen_create_window(&m_window, m_screenContext), + "Could not create top level window"); // Creates an application window if (window->type() != Qt::CoverWindow) { if (needRootWindow) platformScreen->setRootWindow(this); - createWindowGroup(); } } else { - result = screen_create_window_type(&m_window, m_screenContext, SCREEN_CHILD_WINDOW); + Q_SCREEN_CHECKERROR( + screen_create_window_type(&m_window, m_screenContext, SCREEN_CHILD_WINDOW), + "Could not create child window"); } - if (result != 0) - qFatal("QQnxWindow: failed to create window, errno=%d", errno); + + createWindowGroup(); } QQnxWindow::~QQnxWindow() @@ -130,7 +141,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,71 +151,34 @@ 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 - errno = 0; int val[2]; val[0] = rect.x(); val[1] = rect.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_SCREEN_CHECKERROR(screen_set_window_property_iv(m_window, SCREEN_PROPERTY_POSITION, val), + "Failed to set window position"); - errno = 0; val[0] = rect.width(); val[1] = rect.height(); - result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SIZE, val); - if (result != 0) - qFatal("QQnxWindow: failed to set window size, errno=%d", errno); + Q_SCREEN_CHECKERROR(screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SIZE, val), + "Failed to set window size"); // Set viewport size equal to window size - errno = 0; - result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SOURCE_SIZE, val); - 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]; + Q_SCREEN_CHECKERROR(screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SOURCE_SIZE, val), + "Failed to set window source size"); - 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 +188,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; @@ -222,8 +202,6 @@ void QQnxWindow::setVisible(bool visible) root->updateVisibility(root->m_visible); - window()->requestActivate(); - QWindowSystemInterface::handleExposeEvent(window(), window()->geometry()); if (visible) { @@ -238,11 +216,9 @@ void QQnxWindow::updateVisibility(bool parentVisible) { qWindowDebug() << Q_FUNC_INFO << "parentVisible =" << parentVisible << "window =" << window(); // Set window visibility - errno = 0; int val = (m_visible && parentVisible) ? 1 : 0; - int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_VISIBLE, &val); - if (result != 0) - qFatal("QQnxWindow: failed to set window visibility, errno=%d", errno); + Q_SCREEN_CHECKERROR(screen_set_window_property_iv(m_window, SCREEN_PROPERTY_VISIBLE, &val), + "Failed to set window visibility"); Q_FOREACH (QQnxWindow *childWindow, m_childWindows) childWindow->updateVisibility(m_visible && parentVisible); @@ -252,14 +228,11 @@ void QQnxWindow::setOpacity(qreal level) { qWindowDebug() << Q_FUNC_INFO << "window =" << window() << "opacity =" << level; // Set window global alpha - errno = 0; int val = (int)(level * 255); - int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_GLOBAL_ALPHA, &val); - if (result != 0) - qFatal("QQnxWindow: failed to set window global alpha, errno=%d", errno); + Q_SCREEN_CHECKERROR(screen_set_window_property_iv(m_window, SCREEN_PROPERTY_GLOBAL_ALPHA, &val), + "Failed to set global alpha"); - // TODO: How to handle children of this window? If we change all the visibilities, then - // the transparency will look wrong... + screen_flush_context(m_screenContext, 0); } void QQnxWindow::setExposed(bool exposed) @@ -282,15 +255,12 @@ void QQnxWindow::setBufferSize(const QSize &size) qWindowDebug() << Q_FUNC_INFO << "window =" << window() << "size =" << size; // Set window buffer size - errno = 0; - // libscreen fails when creating empty buffers const QSize nonEmptySize = size.isEmpty() ? QSize(1, 1) : size; int val[2] = { nonEmptySize.width(), nonEmptySize.height() }; - int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_BUFFER_SIZE, val); - if (result != 0) - qFatal("QQnxWindow: failed to set window buffer size, errno=%d", errno); + Q_SCREEN_CHECKERROR(screen_set_window_property_iv(m_window, SCREEN_PROPERTY_BUFFER_SIZE, val), + "Failed to set window buffer size"); // Create window buffers if they do not exist if (m_bufferSize.isEmpty()) { @@ -298,24 +268,18 @@ void QQnxWindow::setBufferSize(const QSize &size) if (val[0] == -1) // The platform GL context was not set yet on the window, so we can't procede return; - errno = 0; - result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_FORMAT, val); - if (result != 0) - qFatal("QQnxWindow: failed to set window pixel format, errno=%d", errno); + Q_SCREEN_CRITICALERROR( + screen_set_window_property_iv(m_window, SCREEN_PROPERTY_FORMAT, val), + "Failed to set window format"); - errno = 0; - result = screen_create_window_buffers(m_window, MAX_BUFFER_COUNT); - if (result != 0) { - qWarning() << "QQnxWindow: Buffer size was" << size; - qFatal("QQnxWindow: failed to create window buffers, errno=%d", errno); - } + Q_SCREEN_CRITICALERROR(screen_create_window_buffers(m_window, MAX_BUFFER_COUNT), + "Failed to create window buffers"); // check if there are any buffers available int bufferCount = 0; - result = screen_get_window_property_iv(m_window, SCREEN_PROPERTY_RENDER_BUFFER_COUNT, &bufferCount); - - if (result != 0) - qFatal("QQnxWindow: failed to query window buffer count, errno=%d", errno); + Q_SCREEN_CRITICALERROR( + screen_get_window_property_iv(m_window, SCREEN_PROPERTY_RENDER_BUFFER_COUNT, &bufferCount), + "Failed to query render buffer count"); if (bufferCount != MAX_BUFFER_COUNT) { qFatal("QQnxWindow: invalid buffer count. Expected = %d, got = %d. You might experience problems.", @@ -338,10 +302,8 @@ void QQnxWindow::setBufferSize(const QSize &size) val[0] = SCREEN_TRANSPARENCY_SOURCE_OVER; } - errno = 0; - result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_TRANSPARENCY, val); - if (result != 0) - qFatal("QQnxWindow: failed to set window transparency, errno=%d", errno); + Q_SCREEN_CHECKERROR(screen_set_window_property_iv(m_window, SCREEN_PROPERTY_TRANSPARENCY, val), + "Failed to set window transparency"); // Cache new buffer size m_bufferSize = nonEmptySize; @@ -366,9 +328,8 @@ void QQnxWindow::setScreen(QQnxScreen *platformScreen) if (m_screen) { qWindowDebug() << Q_FUNC_INFO << "Moving window to different screen"; m_screen->removeWindow(this); - QQnxIntegration *platformIntegration = static_cast<QQnxIntegration*>(QGuiApplicationPrivate::platformIntegration()); - if ((platformIntegration->options() & QQnxIntegration::RootWindow)) { + if ((QQnxIntegration::options() & QQnxIntegration::RootWindow)) { screen_leave_window_group(m_window); } } @@ -378,25 +339,12 @@ void QQnxWindow::setScreen(QQnxScreen *platformScreen) platformScreen->addWindow(this); } if (m_isTopLevel) { - // Move window to proper screen/display - errno = 0; + // Move window to proper screen/display screen_display_t display = platformScreen->nativeDisplay(); - int result = screen_set_window_property_pv(m_window, SCREEN_PROPERTY_DISPLAY, (void **)&display); - if (result != 0) - qFatal("QQnxWindow: failed to set window display, errno=%d", errno); + Q_SCREEN_CHECKERROR( + screen_set_window_property_pv(m_window, SCREEN_PROPERTY_DISPLAY, (void **)&display), + "Failed to set window display"); } 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. if (window()->type() == Qt::SubWindow || window()->type() == Qt::ToolTip) @@ -430,6 +378,11 @@ void QQnxWindow::setParent(const QPlatformWindow *window) if (newParent == m_parentWindow) return; + if (screen()->rootWindow() == this) { + qWarning() << "Application window cannot be reparented"; + return; + } + removeFromParent(); m_parentWindow = newParent; @@ -439,12 +392,12 @@ 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(); - m_screen->updateHierarchy(); } @@ -478,14 +431,59 @@ void QQnxWindow::lower() void QQnxWindow::requestActivateWindow() { - qWindowDebug() << Q_FUNC_INFO << "window =" << window(); + QQnxWindow *focusWindow = 0; + if (QGuiApplication::focusWindow()) + focusWindow = static_cast<QQnxWindow*>(QGuiApplication::focusWindow()->handle()); + + if (focusWindow == this) + return; + + if (screen()->rootWindow() == this || + (focusWindow && findWindow(focusWindow->nativeHandle()))) { + // If the focus window is a child, we can just set the focus of our own window + // group to our window handle + setFocus(nativeHandle()); + } else { + // In order to receive focus the parent's window group has to give focus to the + // child. If we have several hierarchy layers, we have to do that several times + QQnxWindow *currentWindow = this; + QList<QQnxWindow*> windowList; + while (currentWindow) { + windowList.prepend(currentWindow); + // If we find the focus window, we don't have to go further + if (currentWindow == focusWindow) + break; + + if (currentWindow->parent()){ + currentWindow = static_cast<QQnxWindow*>(currentWindow->parent()); + } else if (screen()->rootWindow() && + screen()->rootWindow()->m_windowGroupName == currentWindow->m_parentGroupName) { + currentWindow = screen()->rootWindow(); + } else { + currentWindow = 0; + } + } - // TODO: Tell screen to set keyboard focus to this window. + // We have to apply the focus from parent to child windows + for (int i = 1; i < windowList.size(); ++i) + windowList.at(i-1)->setFocus(windowList.at(i)->nativeHandle()); + + windowList.last()->setFocus(windowList.last()->nativeHandle()); + } - // Notify that we gained focus. - gainedFocus(); + screen_flush_context(m_screenContext, 0); } +void QQnxWindow::setFocus(screen_window_t newFocusWindow) +{ + screen_group_t screenGroup = 0; + screen_get_window_property_pv(nativeHandle(), SCREEN_PROPERTY_GROUP, + reinterpret_cast<void**>(&screenGroup)); + if (screenGroup) { + screen_set_group_property_pv(screenGroup, SCREEN_PROPERTY_KEYBOARD_FOCUS, + reinterpret_cast<void**>(&newFocusWindow)); + } +} void QQnxWindow::setWindowState(Qt::WindowState state) { @@ -507,14 +505,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; @@ -569,43 +559,43 @@ void QQnxWindow::minimize() void QQnxWindow::setRotation(int rotation) { qWindowDebug() << Q_FUNC_INFO << "angle =" << rotation; - errno = 0; - int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ROTATION, &rotation); - if (result != 0) - qFatal("QQnxRootWindow: failed to set window rotation, errno=%d", errno); + Q_SCREEN_CHECKERROR( + screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ROTATION, &rotation), + "Failed to set window rotation"); } void QQnxWindow::initWindow() { // Alpha channel is always pre-multiplied if present - errno = 0; int val = SCREEN_PRE_MULTIPLIED_ALPHA; - int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ALPHA_MODE, &val); - if (result != 0) - qFatal("QQnxWindow: failed to set window alpha mode, errno=%d", errno); + Q_SCREEN_CHECKERROR(screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ALPHA_MODE, &val), + "Failed to set alpha mode"); // Set the window swap interval - errno = 0; val = 1; - result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SWAP_INTERVAL, &val); - if (result != 0) - qFatal("QQnxWindow: failed to set window swap interval, errno=%d", errno); + Q_SCREEN_CHECKERROR( + screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SWAP_INTERVAL, &val), + "Failed to set swap interval"); if (window()->flags() & Qt::WindowDoesNotAcceptFocus) { - errno = 0; val = SCREEN_SENSITIVITY_NO_FOCUS; - result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SENSITIVITY, &val); - if (result != 0) - qFatal("QQnxWindow: failed to set window sensitivity, errno=%d", errno); + Q_SCREEN_CHECKERROR( + screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SENSITIVITY, &val), + "Failed to set window sensitivity"); } - 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; } @@ -615,6 +605,8 @@ void QQnxWindow::initWindow() // Qt never calls these setters after creating the window, so we need to do that ourselves here setWindowState(window()->windowState()); + setOpacity(window()->opacity()); + if (window()->parent() && window()->parent()->handle()) setParent(window()->parent()->handle()); @@ -632,10 +624,36 @@ void QQnxWindow::createWindowGroup() m_windowGroupName = QUuid::createUuid().toString().toLatin1(); // Create window group so child windows can be parented by container window - errno = 0; - int result = screen_create_window_group(m_window, m_windowGroupName.constData()); - if (result != 0) - qFatal("QQnxRootWindow: failed to create app window group, errno=%d", errno); + Q_SCREEN_CHECKERROR(screen_create_window_group(m_window, m_windowGroupName.constData()), + "Failed to create window group"); +} + +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) @@ -651,12 +669,9 @@ void QQnxWindow::updateZorder(int &topZorder) void QQnxWindow::updateZorder(screen_window_t window, int &topZorder) { - errno = 0; - int result = screen_set_window_property_iv(window, SCREEN_PROPERTY_ZORDER, &topZorder); + Q_SCREEN_CHECKERROR(screen_set_window_property_iv(window, SCREEN_PROPERTY_ZORDER, &topZorder), + "Failed to set window z-order"); topZorder++; - - if (result != 0) - qFatal("QQnxWindow: failed to set window z-order=%d, errno=%d, mWindow=%p", topZorder, errno, window); } void QQnxWindow::applyWindowState() diff --git a/src/plugins/platforms/qnx/qqnxwindow.h b/src/plugins/platforms/qnx/qqnxwindow.h index 3c8070b0be..ea7b388e9f 100644 --- a/src/plugins/platforms/qnx/qqnxwindow.h +++ b/src/plugins/platforms/qnx/qqnxwindow.h @@ -78,7 +78,6 @@ public: WId winId() const { return (WId)m_window; } screen_window_t nativeHandle() const { return m_window; } - virtual void adjustBufferSize() = 0; void setBufferSize(const QSize &size); QSize bufferSize() const { return m_bufferSize; } @@ -93,7 +92,6 @@ public: void propagateSizeHints(); - void gainedFocus(); void setMMRendererWindowName(const QString &name); void setMMRendererWindow(screen_window_t handle); void clearMMRendererWindow(); @@ -112,6 +110,7 @@ public: void setRotation(int rotation); QByteArray groupName() const { return m_windowGroupName; } + void joinWindowGroup(const QByteArray &groupName); protected: virtual int pixelFormat() const = 0; @@ -122,22 +121,21 @@ protected: screen_context_t m_screenContext; QScopedPointer<QQnxAbstractCover> m_cover; - QQnxWindow *m_parentWindow; - 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); void applyWindowState(); + void setFocus(screen_window_t newFocusWindow); screen_window_t m_window; QSize m_bufferSize; QQnxScreen *m_screen; + QQnxWindow *m_parentWindow; QList<QQnxWindow*> m_childWindows; bool m_visible; bool m_exposed; @@ -146,7 +144,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/accessible/iaccessible2.cpp b/src/plugins/platforms/windows/accessible/iaccessible2.cpp index 66ed9d85dc..7f2ed86404 100644 --- a/src/plugins/platforms/windows/accessible/iaccessible2.cpp +++ b/src/plugins/platforms/windows/accessible/iaccessible2.cpp @@ -59,10 +59,10 @@ HRESULT STDMETHODCALLTYPE AccessibleApplication::QueryInterface(REFIID id, LPVOI { *iface = 0; if (id == IID_IUnknown) { - accessibleDebug("AccessibleApplication::QI(): IID_IUnknown"); + qCDebug(lcQpaAccessibility) << "AccessibleApplication::QI(): IID_IUnknown"; *iface = (IUnknown*)this; } else if (id == IID_IAccessibleApplication) { - accessibleDebug("AccessibleApplication::QI(): IID_IAccessibleApplication"); + qCDebug(lcQpaAccessibility) << "AccessibleApplication::QI(): IID_IAccessibleApplication"; *iface = static_cast<IAccessibleApplication*>(this); } @@ -476,7 +476,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_uniqueID(long *outUniqueID) if (!accessible) return E_FAIL; - accessibleDebug("uniqueID: %08x", id); + qCDebug(lcQpaAccessibility) << "uniqueID: " << showbase << hex << id; *outUniqueID = (long)id; return int(id) < 0 ? S_OK : S_FALSE; @@ -841,7 +841,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_cellAt( long row, long colu *cell = QWindowsAccessibility::wrap(qtCell); } } - accessibleDebug("found cell? %p", *cell); + qCDebug(lcQpaAccessibility) << "found cell? " << *cell; return *cell ? S_OK : S_FALSE; } @@ -1574,7 +1574,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::QueryService(REFGUID guidServic return E_POINTER; Q_UNUSED(guidService); *iface = 0; - accessibleDebug("QWindowsIA2Accessible::QS(): %s", IIDToString(riid).constData()); + qCDebug(lcQpaAccessibility) << "QWindowsIA2Accessible::QS(): " << IIDToString(riid); if (guidService == IID_IAccessible) { diff --git a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp index 885bc37cff..307f2fc3bb 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp +++ b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp @@ -100,6 +100,25 @@ QWindowsAccessibility::QWindowsAccessibility() { } +// Retrieve sound name by checking the icon property of a message box +static inline QString messageBoxAlertSound(const QObject *messageBox) +{ + enum MessageBoxIcon { // Keep in sync with QMessageBox::Icon + Information = 1, + Warning = 2, + Critical = 3 + }; + switch (messageBox->property("icon").toInt()) { + case Information: + return QStringLiteral("SystemAsterisk"); + case Warning: + return QStringLiteral("SystemExclamation"); + case Critical: + return QStringLiteral("SystemHand"); + } + return QString(); +} + void QWindowsAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event) { QString soundName; @@ -113,32 +132,8 @@ void QWindowsAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event) break; case QAccessible::Alert: - { - /* ### FIXME -#ifndef QT_NO_MESSAGEBOX - QMessageBox *mb = qobject_cast<QMessageBox*>(o); - if (mb) { - switch (mb->icon()) { - case QMessageBox::Warning: - soundName = QLatin1String("SystemExclamation"); - break; - case QMessageBox::Critical: - soundName = QLatin1String("SystemHand"); - break; - case QMessageBox::Information: - soundName = QLatin1String("SystemAsterisk"); - break; - default: - break; - } - } else -#endif // QT_NO_MESSAGEBOX -*/ - { - soundName = QLatin1String("SystemAsterisk"); - } - - } + soundName = event->object()->inherits("QMessageBox") ? + messageBoxAlertSound(event->object()) : QStringLiteral("SystemAsterisk"); break; default: break; diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp index 8bb7646258..49d4a712d8 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp +++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp @@ -185,23 +185,10 @@ HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Skip(unsigned long celt) return S_OK; } -#ifndef QT_NO_DEBUG -bool debug_accessibility() -{ - static int debugging = -1; - if (debugging == -1) - debugging = qgetenv("QT_DEBUG_ACCESSIBILITY").toInt(); - return !!debugging; -} -#endif - #if defined(DEBUG_SHOW_ATCLIENT_COMMANDS) void accessibleDebugClientCalls_helper(const char* funcName, const QAccessibleInterface *iface) { - QString str; - QDebug dbg(&str); - dbg << iface << QLatin1String(funcName); - accessibleDebug("%s", qPrintable(str)); + qCDebug(lcQpaAccessibility) << iface << funcName; } #endif @@ -216,10 +203,8 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::QueryInterface(REFIID id, LPVO QByteArray strIID = IIDToString(id); if (!strIID.isEmpty()) { - QString ss; - QDebug dbg(&ss); - dbg << accessibleInterface(); - accessibleDebug("QWindowsIA2Accessible::QI() - IID:%s, iface:%s ", strIID.constData(), qPrintable(ss)); + qCDebug(lcQpaAccessibility) << "QWindowsIA2Accessible::QI() - IID:" + << strIID << ", iface:" << accessibleInterface(); } if (id == IID_IUnknown) { *iface = (IUnknown*)(IDispatch*)this; @@ -1057,7 +1042,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accValue(VARIANT varID, BS } *pszValue = 0; - accessibleDebug("return S_FALSE"); + qCDebug(lcQpaAccessibility) << "return S_FALSE"; return S_FALSE; } @@ -1196,7 +1181,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::GetWindow(HWND *phwnd) QPlatformNativeInterface *platform = QGuiApplication::platformNativeInterface(); Q_ASSERT(platform); *phwnd = (HWND)platform->nativeResourceForWindow("handle", window); - accessibleDebug("QWindowsAccessible::GetWindow(): %p", *phwnd); + qCDebug(lcQpaAccessibility) << "QWindowsAccessible::GetWindow(): " << *phwnd; return S_OK; } diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h index 5b8d08d3c8..43482da4be 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h +++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h @@ -59,13 +59,6 @@ QT_BEGIN_NAMESPACE -#if !defined(QT_NO_DEBUG) && !defined(QT_NO_DEBUG_OUTPUT) -bool debug_accessibility(); -# define accessibleDebug !debug_accessibility() ? (void)0 : qDebug -#else -# define accessibleDebug while (false) qDebug -#endif - #ifndef QT_NO_DEBUG_OUTPUT #define DEBUG_SHOW_ATCLIENT_COMMANDS #endif 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..f12c828d8a 100644 --- a/src/plugins/platforms/windows/qwindowsbackingstore.cpp +++ b/src/plugins/platforms/windows/qwindowsbackingstore.cpp @@ -61,14 +61,12 @@ QT_BEGIN_NAMESPACE QWindowsBackingStore::QWindowsBackingStore(QWindow *window) : QPlatformBackingStore(window) { - if (QWindowsContext::verboseBackingStore) - qDebug() << __FUNCTION__ << this << window; + qCDebug(lcQpaBackingStore) << __FUNCTION__ << this << window; } QWindowsBackingStore::~QWindowsBackingStore() { - if (QWindowsContext::verboseBackingStore) - qDebug() << __FUNCTION__ << this; + qCDebug(lcQpaBackingStore) << __FUNCTION__ << this; } QPaintDevice *QWindowsBackingStore::paintDevice() @@ -83,8 +81,8 @@ void QWindowsBackingStore::flush(QWindow *window, const QRegion ®ion, Q_ASSERT(window); const QRect br = region.boundingRect(); - if (QWindowsContext::verboseBackingStore > 1) - qDebug() << __FUNCTION__ << window << offset << br; + if (QWindowsContext::verbose > 1) + qCDebug(lcQpaBackingStore) << __FUNCTION__ << this << window << offset << br; QWindowsWindow *rw = QWindowsWindow::baseWindowOf(window); #ifndef Q_OS_WINCE @@ -117,20 +115,23 @@ 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 } #endif // Write image for debug purposes. - if (QWindowsContext::verboseBackingStore > 2) { + if (QWindowsContext::verbose > 2 && lcQpaBackingStore().isDebugEnabled()) { static int n = 0; const QString fileName = QString::fromLatin1("win%1_%2.png"). arg(rw->winId()).arg(n++); m_image->image().save(fileName); - qDebug() << "Wrote " << m_image->image().size() << fileName; + qCDebug(lcQpaBackingStore) << "Wrote " << m_image->image().size() << fileName; } } @@ -138,16 +139,14 @@ void QWindowsBackingStore::resize(const QSize &size, const QRegion ®ion) { if (m_image.isNull() || m_image->image().size() != size) { #ifndef QT_NO_DEBUG_OUTPUT - if (QWindowsContext::verboseBackingStore) { - QDebug nsp = qDebug().nospace(); - nsp << __FUNCTION__ << ' ' << rasterWindow()->window() - << ' ' << size << ' ' << region; - if (!m_image.isNull()) - nsp << " from: " << m_image->image().size(); + if (QWindowsContext::verbose && lcQpaBackingStore().isDebugEnabled()) { + qCDebug(lcQpaBackingStore) + << __FUNCTION__ << ' ' << window() << ' ' << size << ' ' << region + << " from: " << (m_image.isNull() ? QSize() : m_image->image().size()); } #endif QImage::Format format = QWindowsNativeImage::systemFormat(); - if (format == QImage::Format_RGB32 && rasterWindow()->window()->format().hasAlpha()) + if (format == QImage::Format_RGB32 && window()->format().hasAlpha()) format = QImage::Format_ARGB32_Premultiplied; QWindowsNativeImage *oldwni = m_image.data(); @@ -185,8 +184,8 @@ bool QWindowsBackingStore::scroll(const QRegion &area, int dx, int dy) void QWindowsBackingStore::beginPaint(const QRegion ®ion) { - if (QWindowsContext::verboseBackingStore > 1) - qDebug() << __FUNCTION__; + if (QWindowsContext::verbose > 1) + qCDebug(lcQpaBackingStore) <<__FUNCTION__ << region; if (m_image->image().hasAlphaChannel()) { QPainter p(&m_image->image()); @@ -197,14 +196,6 @@ void QWindowsBackingStore::beginPaint(const QRegion ®ion) } } -QWindowsWindow *QWindowsBackingStore::rasterWindow() const -{ - if (const QWindow *w = window()) - if (QPlatformWindow *pw = w->handle()) - return static_cast<QWindowsWindow *>(pw); - return 0; -} - HDC QWindowsBackingStore::getDC() const { if (!m_image.isNull()) diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.h b/src/plugins/platforms/windows/qwindowsbackingstore.h index d50570dd2c..b655aca835 100644 --- a/src/plugins/platforms/windows/qwindowsbackingstore.h +++ b/src/plugins/platforms/windows/qwindowsbackingstore.h @@ -68,8 +68,6 @@ public: HDC getDC() const; private: - QWindowsWindow *rasterWindow() const; - QScopedPointer<QWindowsNativeImage> m_image; }; diff --git a/src/plugins/platforms/windows/qwindowsclipboard.cpp b/src/plugins/platforms/windows/qwindowsclipboard.cpp index 51e0d0e803..5370d556fd 100644 --- a/src/plugins/platforms/windows/qwindowsclipboard.cpp +++ b/src/plugins/platforms/windows/qwindowsclipboard.cpp @@ -164,9 +164,7 @@ void QWindowsClipboard::registerViewer() qClipboardViewerWndProc, WS_OVERLAPPED); m_nextClipboardViewer = SetClipboardViewer(m_clipboardViewer); - if (QWindowsContext::verboseOLE) - qDebug("%s m_clipboardViewer: %p next=%p", __FUNCTION__, - m_clipboardViewer, m_nextClipboardViewer); + qCDebug(lcQpaMime) << __FUNCTION__ << "m_clipboardViewer: " << m_clipboardViewer << "next: " << m_nextClipboardViewer; } void QWindowsClipboard::unregisterViewer() @@ -219,9 +217,8 @@ void QWindowsClipboard::propagateClipboardMessage(UINT message, WPARAM wParam, L bool QWindowsClipboard::clipboardViewerWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result) { *result = 0; - if (QWindowsContext::verboseOLE) - qDebug("%s HWND=%p 0x%x %s", __FUNCTION__, hwnd, message, - QWindowsGuiEventDispatcher::windowsMessageName(message)); + if (QWindowsContext::verbose) + qCDebug(lcQpaMime) << __FUNCTION__ << hwnd << message << QWindowsGuiEventDispatcher::windowsMessageName(message); switch (message) { case WM_CHANGECBCHAIN: { @@ -235,8 +232,7 @@ bool QWindowsClipboard::clipboardViewerWndProc(HWND hwnd, UINT message, WPARAM w return true; case WM_DRAWCLIPBOARD: { const bool owned = ownsClipboard(); - if (QWindowsContext::verboseOLE) - qDebug("Clipboard changed owned %d", owned); + qCDebug(lcQpaMime) << "Clipboard changed owned " << owned; emitChanged(QClipboard::Clipboard); // clean up the clipboard object if we no longer own the clipboard if (!owned && m_data) @@ -247,8 +243,7 @@ bool QWindowsClipboard::clipboardViewerWndProc(HWND hwnd, UINT message, WPARAM w case WM_DESTROY: // Recommended shutdown if (ownsClipboard()) { - if (QWindowsContext::verboseOLE) - qDebug("Clipboard owner on shutdown, releasing."); + qCDebug(lcQpaMime) << "Clipboard owner on shutdown, releasing."; OleFlushClipboard(); releaseIData(); } @@ -259,8 +254,7 @@ bool QWindowsClipboard::clipboardViewerWndProc(HWND hwnd, UINT message, WPARAM w QMimeData *QWindowsClipboard::mimeData(QClipboard::Mode mode) { - if (QWindowsContext::verboseOLE) - qDebug() << __FUNCTION__ << mode; + qCDebug(lcQpaMime) << __FUNCTION__ << mode; if (mode != QClipboard::Clipboard) return 0; if (ownsClipboard()) @@ -270,8 +264,7 @@ QMimeData *QWindowsClipboard::mimeData(QClipboard::Mode mode) void QWindowsClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode) { - if (QWindowsContext::verboseOLE) - qDebug() << __FUNCTION__ << mode << *mimeData; + qCDebug(lcQpaMime) << __FUNCTION__ << mode << *mimeData; if (mode != QClipboard::Clipboard) return; @@ -316,8 +309,7 @@ bool QWindowsClipboard::ownsMode(QClipboard::Mode mode) const { const bool result = mode == QClipboard::Clipboard ? ownsClipboard() : false; - if (QWindowsContext::verboseOLE) - qDebug("%s %d returns %d", __FUNCTION__, mode, result); + qCDebug(lcQpaMime) << __FUNCTION__ << mode << result; return result; } diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 77cac647ba..8380aba13b 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -79,18 +79,18 @@ QT_BEGIN_NAMESPACE -// Verbosity of components -int QWindowsContext::verboseIntegration = 0; -int QWindowsContext::verboseWindows = 0; -int QWindowsContext::verboseEvents = 0; -int QWindowsContext::verboseBackingStore = 0; -int QWindowsContext::verboseFonts = 0; -int QWindowsContext::verboseGL = 0; -int QWindowsContext::verboseOLE = 0; -int QWindowsContext::verboseInputMethods = 0; -int QWindowsContext::verboseDialogs = 0; -int QWindowsContext::verboseTheming = 0; -int QWindowsContext::verboseTablet = 0; +Q_LOGGING_CATEGORY(lcQpaWindows, "qt.qpa.windows") +Q_LOGGING_CATEGORY(lcQpaBackingStore, "qt.qpa.backingstore") +Q_LOGGING_CATEGORY(lcQpaEvents, "qt.qpa.events") +Q_LOGGING_CATEGORY(lcQpaFonts, "qt.qpa.fonts") +Q_LOGGING_CATEGORY(lcQpaGl, "qt.qpa.gl") +Q_LOGGING_CATEGORY(lcQpaMime, "qt.qpa.mime") +Q_LOGGING_CATEGORY(lcQpaInputMethods, "qt.qpa.inputmethods") +Q_LOGGING_CATEGORY(lcQpaDialogs, "qt.qpa.dialogs") +Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.tabletsupport") +Q_LOGGING_CATEGORY(lcQpaAccessibility, "qt.qpa.accessibility") + +int QWindowsContext::verbose = 0; // Get verbosity of components from "foo:2,bar:3" static inline int componentVerbose(const char *v, const char *keyWord) @@ -318,25 +318,13 @@ QWindowsContext::QWindowsContext() : # pragma warning( disable : 4996 ) #endif m_instance = this; + // ### FIXME: Remove this once the logging system has other options of configurations. 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"); - QWindowsContext::verboseFonts = componentVerbose(v, "fonts"); - QWindowsContext::verboseGL = componentVerbose(v, "gl"); - 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 (!bv.isEmpty()) + QLoggingCategory::setFilterRules(QString::fromLocal8Bit(bv)); #if !defined(QT_NO_TABLETEVENT) && !defined(Q_OS_WINCE) d->m_tabletSupport.reset(QWindowsTabletSupport::create()); - if (QWindowsContext::verboseTablet) - qDebug() << "Tablet support: " << (d->m_tabletSupport.isNull() ? QStringLiteral("None") : d->m_tabletSupport->description()); + qCDebug(lcQpaTablet) << "Tablet support: " << (d->m_tabletSupport.isNull() ? QStringLiteral("None") : d->m_tabletSupport->description()); #endif } @@ -407,7 +395,7 @@ QString QWindowsContext::registerWindowClass(const QWindow *w, bool isGL) bool icon = true; if (isGL || (flags & Qt::MSWindowsOwnDC)) style |= CS_OWNDC; - if ((QSysInfo::WindowsVersion & QSysInfo::WV_NT_based) + if (!(flags & Qt::NoDropShadowWindowHint) && (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based) && (type == Qt::Popup || w->property("_q_windowsDropShadow").toBool())) { style |= CS_DROPSHADOW; } @@ -519,8 +507,7 @@ QString QWindowsContext::registerWindowClass(QString cname, qPrintable(cname)); d->m_registeredWindowClassNames.insert(cname); - if (QWindowsContext::verboseIntegration || QWindowsContext::verboseWindows) - qDebug().nospace() << __FUNCTION__ << ' ' << cname + qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << ' ' << cname << " style=0x" << QString::number(style, 16) << " brush=" << brush << " icon=" << icon << " atom=" << atom; return cname; @@ -530,11 +517,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(); } @@ -750,8 +734,20 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, msg.message = message; // time and pt fields ignored msg.wParam = wParam; msg.lParam = lParam; - msg.pt.x = GET_X_LPARAM(lParam); - msg.pt.y = GET_Y_LPARAM(lParam); + msg.pt.x = msg.pt.y = 0; + if (et != QtWindows::CursorEvent && (et & (QtWindows::MouseEventFlag | QtWindows::NonClientEventFlag))) { + msg.pt.x = GET_X_LPARAM(lParam); + msg.pt.y = GET_Y_LPARAM(lParam); + // For non-client-area messages, these are screen coordinates (as expected + // in the MSG structure), otherwise they are client coordinates. + if (!(et & QtWindows::NonClientEventFlag)) { + ClientToScreen(msg.hwnd, &msg.pt); + } + } else { +#ifndef Q_OS_WINCE + GetCursorPos(&msg.pt); +#endif + } // Run the native event filters. long filterResult = 0; @@ -834,8 +830,8 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, // Suppress events sent during DestroyWindow() for native children. if (platformWindow->testFlag(QWindowsWindow::WithinDestroy)) return false; - if (QWindowsContext::verboseEvents > 1) - qDebug().nospace() << "Event window: " << platformWindow->window(); + if (QWindowsContext::verbose > 1) + qCDebug(lcQpaEvents) << "Event window: " << platformWindow->window(); } else { qWarning("%s: No Qt Window found for event 0x%x (%s), hwnd=0x%p.", __FUNCTION__, message, @@ -928,6 +924,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 +936,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: @@ -1071,11 +1077,13 @@ extern "C" LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND hwnd, UINT message, WPAR LRESULT result; const QtWindows::WindowsEventType et = windowsEventType(message, wParam); const bool handled = QWindowsContext::instance()->windowsProc(hwnd, message, et, wParam, lParam, &result); - if (QWindowsContext::verboseEvents > 1) - if (const char *eventName = QWindowsGuiEventDispatcher::windowsMessageName(message)) - qDebug("EVENT: hwd=%p %s msg=0x%x et=0x%x wp=%d at %d,%d handled=%d", - hwnd, eventName, message, et, int(wParam), - GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), handled); + if (QWindowsContext::verbose > 1 && lcQpaEvents().isDebugEnabled()) { + if (const char *eventName = QWindowsGuiEventDispatcher::windowsMessageName(message)) { + qCDebug(lcQpaEvents) << "EVENT: hwd=" << hwnd << eventName << hex << "msg=0x" << message + << "et=0x" << et << dec << "wp=" << int(wParam) << "at" + << GET_X_LPARAM(lParam) << GET_Y_LPARAM(lParam) << "handled=" << handled; + } + } if (!handled) result = DefWindowProc(hwnd, message, wParam, lParam); return result; diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h index 173df58570..1fea059ed9 100644 --- a/src/plugins/platforms/windows/qwindowscontext.h +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -47,12 +47,24 @@ #include <QtCore/QScopedPointer> #include <QtCore/QSharedPointer> +#include <QtCore/QLoggingCategory> struct IBindCtx; struct _SHSTOCKICONINFO; QT_BEGIN_NAMESPACE +Q_DECLARE_LOGGING_CATEGORY(lcQpaWindows) +Q_DECLARE_LOGGING_CATEGORY(lcQpaBackingStore) +Q_DECLARE_LOGGING_CATEGORY(lcQpaEvents) +Q_DECLARE_LOGGING_CATEGORY(lcQpaFonts) +Q_DECLARE_LOGGING_CATEGORY(lcQpaGl) +Q_DECLARE_LOGGING_CATEGORY(lcQpaMime) +Q_DECLARE_LOGGING_CATEGORY(lcQpaInputMethods) +Q_DECLARE_LOGGING_CATEGORY(lcQpaDialogs) +Q_DECLARE_LOGGING_CATEGORY(lcQpaTablet) +Q_DECLARE_LOGGING_CATEGORY(lcQpaAccessibility) + class QWindow; class QPlatformScreen; class QWindowsScreenManager; @@ -128,17 +140,7 @@ public: }; // Verbose flag set by environment variable QT_QPA_VERBOSE - static int verboseIntegration; - static int verboseWindows; - static int verboseBackingStore; - static int verboseEvents; - static int verboseFonts; - static int verboseGL; - static int verboseOLE; - static int verboseInputMethods; - static int verboseDialogs; - static int verboseTheming; - static int verboseTablet; + static int verbose; explicit QWindowsContext(); ~QWindowsContext(); diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp index 5e7944a4cf..d8fb104b3c 100644 --- a/src/plugins/platforms/windows/qwindowscursor.cpp +++ b/src/plugins/platforms/windows/qwindowscursor.cpp @@ -186,32 +186,6 @@ HCURSOR QWindowsCursor::createSystemCursor(const QCursor &c) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - static const uchar phand_bits[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, - 0x80, 0x04, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, - 0x80, 0x1c, 0x00, 0x00, 0x80, 0xe4, 0x00, 0x00, 0x80, 0x24, 0x03, 0x00, - 0x80, 0x24, 0x05, 0x00, 0xb8, 0x24, 0x09, 0x00, 0xc8, 0x00, 0x09, 0x00, - 0x88, 0x00, 0x08, 0x00, 0x90, 0x00, 0x08, 0x00, 0xa0, 0x00, 0x08, 0x00, - 0x20, 0x00, 0x08, 0x00, 0x40, 0x00, 0x08, 0x00, 0x40, 0x00, 0x04, 0x00, - 0x80, 0x00, 0x04, 0x00, 0x80, 0x00, 0x04, 0x00, 0x00, 0x01, 0x02, 0x00, - 0x00, 0x01, 0x02, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - - static const uchar phandm_bits[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, - 0x80, 0x07, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, - 0x80, 0x1f, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x80, 0xff, 0x03, 0x00, - 0x80, 0xff, 0x07, 0x00, 0xb8, 0xff, 0x0f, 0x00, 0xf8, 0xff, 0x0f, 0x00, - 0xf8, 0xff, 0x0f, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0xe0, 0xff, 0x0f, 0x00, - 0xe0, 0xff, 0x0f, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0xc0, 0xff, 0x07, 0x00, - 0x80, 0xff, 0x07, 0x00, 0x80, 0xff, 0x07, 0x00, 0x00, 0xff, 0x03, 0x00, - 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - static const uchar openhand_bits[] = { 0x80,0x01,0x58,0x0e,0x64,0x12,0x64,0x52,0x48,0xb2,0x48,0x92, 0x16,0x90,0x19,0x80,0x11,0x40,0x02,0x40,0x04,0x40,0x04,0x20, @@ -229,11 +203,6 @@ HCURSOR QWindowsCursor::createSystemCursor(const QCursor &c) 0xf0,0x7f,0xf8,0x7f,0xfc,0x7f,0xfc,0x3f,0xf8,0x3f,0xf0,0x1f, 0xe0,0x1f,0xe0,0x1f,0x00,0x00,0x00,0x00}; - static const uchar * const cursor_bits32[] = { - vsplit_bits, vsplitm_bits, hsplit_bits, hsplitm_bits, - phand_bits, phandm_bits - }; - wchar_t *sh = 0; switch (c.shape()) { // map to windows cursor case Qt::ArrowCursor: @@ -300,23 +269,18 @@ HCURSOR QWindowsCursor::createSystemCursor(const QCursor &c) mbits = cm.toImage().convertToFormat(QImage::Format_Mono); hx = hy = 8; invb = invm = false; - } else if (cshape != Qt::BitmapCursor) { - int i = cshape - Qt::SplitVCursor; - QBitmap cb = QBitmap::fromData(QSize(32, 32), cursor_bits32[i * 2]); - QBitmap cm = QBitmap::fromData(QSize(32, 32), cursor_bits32[i * 2 + 1]); - bbits = cb.toImage().convertToFormat(QImage::Format_Mono); - mbits = cm.toImage().convertToFormat(QImage::Format_Mono); - if (cshape == Qt::PointingHandCursor) { - hx = 7; - hy = 0; - } else - hx = hy = 16; - invb = invm = false; - } else { + } else if (cshape == Qt::BitmapCursor) { bbits = c.bitmap()->toImage().convertToFormat(QImage::Format_Mono); mbits = c.mask()->toImage().convertToFormat(QImage::Format_Mono); invb = bbits.colorCount() > 1 && qGray(bbits.color(0)) < qGray(bbits.color(1)); invm = mbits.colorCount() > 1 && qGray(mbits.color(0)) < qGray(mbits.color(1)); + } else { // Qt::SplitVCursor, Qt::SplitHCursor + const QBitmap cb = QBitmap::fromData(QSize(32, 32), cshape == Qt::SplitVCursor ? vsplit_bits : hsplit_bits); + const QBitmap cm = QBitmap::fromData(QSize(32, 32), cshape == Qt::SplitVCursor ? vsplitm_bits : hsplitm_bits); + bbits = cb.toImage().convertToFormat(QImage::Format_Mono); + mbits = cm.toImage().convertToFormat(QImage::Format_Mono); + hx = hy = 16; + invb = invm = false; } const int n = qMax(1, bbits.width() / 8); const int h = bbits.height(); @@ -441,9 +405,6 @@ QWindowsWindowCursor QWindowsCursor::pixmapWindowCursor(const QCursor &c) void QWindowsCursor::changeCursor(QCursor *cursorIn, QWindow *window) { - - if (QWindowsContext::verboseWindows > 1) - qDebug() << __FUNCTION__ << cursorIn << window; if (!window) return; if (!cursorIn) { @@ -468,10 +429,24 @@ QPoint QWindowsCursor::mousePosition() return QPoint(p.x, p.y); } +QWindowsCursor::CursorState QWindowsCursor::cursorState() +{ +#ifndef Q_OS_WINCE + enum { cursorShowing = 0x1, cursorSuppressed = 0x2 }; // Windows 8: CURSOR_SUPPRESSED + CURSORINFO cursorInfo; + cursorInfo.cbSize = sizeof(CURSORINFO); + if (GetCursorInfo(&cursorInfo)) { + if (cursorInfo.flags & CursorShowing) + return CursorShowing; + if (cursorInfo.flags & cursorSuppressed) + return CursorSuppressed; + } +#endif // !Q_OS_WINCE + return CursorHidden; +} + void QWindowsCursor::setPos(const QPoint &pos) { - if (QWindowsContext::verboseWindows) - qDebug("%s %d,%d", __FUNCTION__, pos.x(), pos.y()); SetCursorPos(pos.x(), pos.y()); } diff --git a/src/plugins/platforms/windows/qwindowscursor.h b/src/plugins/platforms/windows/qwindowscursor.h index b366d9a06a..31da4e367d 100644 --- a/src/plugins/platforms/windows/qwindowscursor.h +++ b/src/plugins/platforms/windows/qwindowscursor.h @@ -93,6 +93,12 @@ private: class QWindowsCursor : public QPlatformCursor { public: + enum CursorState { + CursorShowing, + CursorHidden, + CursorSuppressed // Cursor suppressed by touch interaction (Windows 8). + }; + QWindowsCursor() {} virtual void changeCursor(QCursor * widgetCursor, QWindow * widget); @@ -102,6 +108,7 @@ public: static HCURSOR createPixmapCursor(const QPixmap &pixmap, int hotX, int hotY); static HCURSOR createSystemCursor(const QCursor &c); static QPoint mousePosition(); + static CursorState cursorState(); QWindowsWindowCursor standardWindowCursor(Qt::CursorShape s = Qt::ArrowCursor); QWindowsWindowCursor pixmapWindowCursor(const QCursor &c); diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index 8ebfd018d0..2abfb426cc 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -422,8 +422,7 @@ void eatMouseMove() ; if (msg.message == WM_MOUSEMOVE) PostMessage(msg.hwnd, msg.message, 0, msg.lParam); - if (QWindowsContext::verboseDialogs) - qDebug("%s triggered=%d" , __FUNCTION__, msg.message == WM_MOUSEMOVE); + qCDebug(lcQpaDialogs) << __FUNCTION__ << "triggered=" << (msg.message == WM_MOUSEMOVE); } } // namespace QWindowsDialogs @@ -558,12 +557,10 @@ private: void QWindowsDialogThread::run() { - if (QWindowsContext::verboseDialogs) - qDebug(">%s" , __FUNCTION__); + qCDebug(lcQpaDialogs) << '>' << __FUNCTION__; m_dialog->exec(m_owner); deleteLater(); - if (QWindowsContext::verboseDialogs) - qDebug("<%s" , __FUNCTION__); + qCDebug(lcQpaDialogs) << '<' << __FUNCTION__; } template <class BaseClass> @@ -579,9 +576,9 @@ bool QWindowsDialogHelperBase<BaseClass>::show(Qt::WindowFlags, } else { m_ownerWindow = 0; } - if (QWindowsContext::verboseDialogs) - qDebug("%s modal=%d modal supported? %d native=%p parent=%p" , - __FUNCTION__, modal, supportsNonModalDialog(parent), m_nativeDialog.data(), m_ownerWindow); + qCDebug(lcQpaDialogs) << __FUNCTION__ << "modal=" << modal + << " modal supported? " << supportsNonModalDialog(parent) + << "native=" << m_nativeDialog.data() << "owner" << m_ownerWindow; if (!modal && !supportsNonModalDialog(parent)) return false; // Was it changed in-between? if (!ensureNativeDialog()) @@ -665,8 +662,7 @@ void QWindowsDialogHelperBase<BaseClass>::hide() template <class BaseClass> void QWindowsDialogHelperBase<BaseClass>::exec() { - if (QWindowsContext::verboseDialogs) - qDebug("%s" , __FUNCTION__); + qCDebug(lcQpaDialogs) << __FUNCTION__; stopTimer(); if (QWindowsNativeDialogBase *nd = nativeDialog()) { nd->exec(m_ownerWindow); @@ -956,8 +952,7 @@ bool QWindowsNativeFileDialogBase::init(const CLSID &clsId, const IID &iid) qErrnoWarning("IFileDialog::Advise failed"); return false; } - if (QWindowsContext::verboseDialogs) - qDebug("%s %p %p cookie=%lu" , __FUNCTION__, m_fileDialog, m_dialogEvents, m_cookie); + qCDebug(lcQpaDialogs) << __FUNCTION__ << m_fileDialog << m_dialogEvents << m_cookie; return true; } @@ -1008,14 +1003,12 @@ QString QWindowsNativeFileDialogBase::directory() const void QWindowsNativeFileDialogBase::doExec(HWND owner) { - if (QWindowsContext::verboseDialogs) - qDebug(">%s on %p", __FUNCTION__, (void *)owner); + qCDebug(lcQpaDialogs) << '>' << __FUNCTION__; // Show() blocks until the user closes the dialog, the dialog window // gets a WM_CLOSE or the parent window is destroyed. const HRESULT hr = m_fileDialog->Show(owner); QWindowsDialogs::eatMouseMove(); - if (QWindowsContext::verboseDialogs) - qDebug("<%s returns 0x%lx", __FUNCTION__, hr); + qCDebug(lcQpaDialogs) << '<' << __FUNCTION__ << " returns " << hex << hr; if (hr == S_OK) { emit accepted(); } else { @@ -1045,10 +1038,8 @@ void QWindowsNativeFileDialogBase::setMode(QFileDialogOptions::FileMode mode, QF flags |= FOS_FILEMUSTEXIST | FOS_ALLOWMULTISELECT; break; } - if (QWindowsContext::verboseDialogs) - qDebug().nospace() - << __FUNCTION__ << " mode=" << mode << " options" - << options << " results in 0x" << flags; + qCDebug(lcQpaDialogs) << __FUNCTION__ << " mode=" << mode << " options" + << options << " results in 0x" << flags; if (FAILED(m_fileDialog->SetOptions(flags))) qErrnoWarning("%s: SetOptions() failed", __FUNCTION__); @@ -1352,8 +1343,7 @@ void QWindowsNativeFileDialogBase::close() // IFileDialog::Close() does not work unless invoked from a callback. // Try to find the window and send it a WM_CLOSE in addition. const HWND hwnd = findDialogWindow(m_title); - if (QWindowsContext::verboseDialogs) - qDebug() << __FUNCTION__ << "closing" << hwnd; + qCDebug(lcQpaDialogs) << __FUNCTION__ << "closing" << hwnd; if (hwnd && IsWindowVisible(hwnd)) PostMessageW(hwnd, WM_CLOSE, 0, 0); #endif // !Q_OS_WINCE @@ -1617,8 +1607,7 @@ QWindowsNativeDialogBase *QWindowsFileDialogHelper::createNativeDialog() void QWindowsFileDialogHelper::setDirectory(const QUrl &directory) { - if (QWindowsContext::verboseDialogs) - qDebug("%s %s" , __FUNCTION__, qPrintable(directory.toString())); + qCDebug(lcQpaDialogs) << __FUNCTION__ << directory.toString(); m_data.setDirectory(directory); if (hasNativeDialog()) @@ -1632,8 +1621,7 @@ QUrl QWindowsFileDialogHelper::directory() const void QWindowsFileDialogHelper::selectFile(const QUrl &fileName) { - if (QWindowsContext::verboseDialogs) - qDebug("%s %s" , __FUNCTION__, qPrintable(fileName.toString())); + qCDebug(lcQpaDialogs) << __FUNCTION__ << fileName.toString(); if (hasNativeDialog()) // Might be invoked from the QFileDialog constructor. nativeFileDialog()->selectFile(fileName.toLocalFile()); // ## should use QUrl::fileName() once it exists @@ -1646,8 +1634,7 @@ QList<QUrl> QWindowsFileDialogHelper::selectedFiles() const void QWindowsFileDialogHelper::setFilter() { - if (QWindowsContext::verboseDialogs) - qDebug("%s" , __FUNCTION__); + qCDebug(lcQpaDialogs) << __FUNCTION__; } void QWindowsFileDialogHelper::selectNameFilter(const QString &filter) @@ -2039,8 +2026,6 @@ void QWindowsNativeColorDialog::doExec(HWND owner) typedef BOOL (WINAPI *ChooseColorWType)(LPCHOOSECOLORW); CHOOSECOLOR chooseColor; - if (QWindowsContext::verboseDialogs) - qDebug() << '>' << __FUNCTION__ << " on " << owner; ZeroMemory(&chooseColor, sizeof(chooseColor)); chooseColor.lStructSize = sizeof(chooseColor); chooseColor.hwndOwner = owner; @@ -2069,8 +2054,6 @@ void QWindowsNativeColorDialog::doExec(HWND owner) for (int c= 0; c < customColorCount; ++c) qCustomColors[c] = COLORREFToQColor(m_customColors[c]).rgb(); emit accepted(); - if (QWindowsContext::verboseDialogs) - qDebug() << '<' << __FUNCTION__ << *m_color; } else { emit rejected(); } diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp index fedda750d9..8f3ccdc0be 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.cpp +++ b/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -54,6 +54,9 @@ #include <QtGui/QMouseEvent> #include <QtGui/QPixmap> #include <QtGui/QPainter> +#include <QtGui/QPaintDevice> +#include <QtGui/QBackingStore> +#include <QtGui/QWindow> #include <QtGui/QGuiApplication> #include <qpa/qwindowsysteminterface_p.h> #include <QtGui/private/qguiapplication_p.h> @@ -207,6 +210,77 @@ static const char * const ignoreDragCursorXpmC[] = { "...............XXXX....."}; /*! + \class QWindowsDragCursorWindow + \brief A toplevel window showing the drag icon in case of touch drag. + + \sa QWindowsOleDropSource + \internal + \ingroup qt-lighthouse-win +*/ + +class QWindowsDragCursorWindow : public QWindow +{ +public: + explicit QWindowsDragCursorWindow(QWindow *parent = 0); + + void setPixmap(const QPixmap &p); + +protected: + void exposeEvent(QExposeEvent *); + +private: + void render(); + + QBackingStore m_backingStore; + QPixmap m_pixmap; +}; + +QWindowsDragCursorWindow::QWindowsDragCursorWindow(QWindow *parent) + : QWindow(parent) + , m_backingStore(this) +{ + QSurfaceFormat windowFormat = format(); + windowFormat.setAlphaBufferSize(8); + setFormat(windowFormat); + setObjectName(QStringLiteral("QWindowsDragCursorWindow")); + setFlags(Qt::Popup | Qt::NoDropShadowWindowHint + | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint + | Qt::WindowDoesNotAcceptFocus | Qt::WindowTransparentForInput); +} + +void QWindowsDragCursorWindow::setPixmap(const QPixmap &p) +{ + if (p.cacheKey() == m_pixmap.cacheKey()) + return; + const QSize oldSize = m_pixmap.size(); + const QSize newSize = p.size(); + qCDebug(lcQpaMime) << __FUNCTION__ << p.cacheKey() << newSize; + m_pixmap = p; + if (oldSize != newSize) { + resize(newSize); + m_backingStore.resize(newSize); + } + if (isVisible()) + render(); +} + +void QWindowsDragCursorWindow::exposeEvent(QExposeEvent *) +{ + Q_ASSERT(!m_pixmap.isNull()); + render(); +} + +void QWindowsDragCursorWindow::render() +{ + const QRect rect(QPoint(0, 0), m_pixmap.size()); + m_backingStore.beginPaint(rect); + QPainter painter(m_backingStore.paintDevice()); + painter.drawPixmap(0, 0, m_pixmap); + m_backingStore.endPaint(); + m_backingStore.flush(rect); +} + +/*! \class QWindowsDropMimeData \brief Special mime data class for data retrieval from Drag operations. @@ -286,6 +360,11 @@ static inline Qt::KeyboardModifiers toQtKeyboardModifiers(DWORD keyState) class QWindowsOleDropSource : public IDropSource { public: + enum Mode { + MouseDrag, + TouchDrag // Mouse cursor suppressed, use window as cursor. + }; + explicit QWindowsOleDropSource(QWindowsDrag *drag); virtual ~QWindowsOleDropSource(); @@ -304,34 +383,64 @@ private: class DragCursorHandle { Q_DISABLE_COPY(DragCursorHandle) public: - DragCursorHandle(HCURSOR c, qint64 k) : cursor(c), cacheKey(k) {} + DragCursorHandle(HCURSOR c) : cursor(c) {} ~DragCursorHandle() { DestroyCursor(cursor); } - HCURSOR cursor; - qint64 cacheKey; + const HCURSOR cursor; + }; + typedef QSharedPointer<DragCursorHandle> DragCursorHandlePtr; + + struct CursorEntry { + CursorEntry() : cacheKey(0) {} + CursorEntry(const QPixmap &p, qint64 cK, const DragCursorHandlePtr &c, const QPoint &h) : + pixmap(p), cacheKey(cK), cursor(c), hotSpot(h) {} + + QPixmap pixmap; + qint64 cacheKey; // Cache key of cursor + DragCursorHandlePtr cursor; + QPoint hotSpot; }; - typedef QMap <Qt::DropAction, QSharedPointer<DragCursorHandle> > ActionCursorMap; + typedef QMap<Qt::DropAction, CursorEntry> ActionCursorMap; + typedef ActionCursorMap::Iterator ActionCursorMapIt; + typedef ActionCursorMap::ConstIterator ActionCursorMapConstIt; + + const Mode m_mode; QWindowsDrag *m_drag; Qt::MouseButtons m_currentButtons; ActionCursorMap m_cursors; + QWindowsDragCursorWindow *m_touchDragWindow; ULONG m_refs; +#ifndef QT_NO_DEBUG_OUTPUT + friend QDebug operator<<(QDebug, const QWindowsOleDropSource::CursorEntry &); +#endif }; -QWindowsOleDropSource::QWindowsOleDropSource(QWindowsDrag *drag) : - m_drag(drag), m_currentButtons(Qt::NoButton), - m_refs(1) +QWindowsOleDropSource::QWindowsOleDropSource(QWindowsDrag *drag) + : m_mode(QWindowsCursor::cursorState() != QWindowsCursor::CursorSuppressed ? MouseDrag : TouchDrag) + , m_drag(drag) + , m_currentButtons(Qt::NoButton) + , m_touchDragWindow(0) + , m_refs(1) { - if (QWindowsContext::verboseOLE) - qDebug("%s", __FUNCTION__); + qCDebug(lcQpaMime) << __FUNCTION__ << m_mode; } QWindowsOleDropSource::~QWindowsOleDropSource() { m_cursors.clear(); - if (QWindowsContext::verboseOLE) - qDebug("%s", __FUNCTION__); + delete m_touchDragWindow; + qCDebug(lcQpaMime) << __FUNCTION__; +} + +#ifndef QT_NO_DEBUG_OUTPUT +QDebug operator<<(QDebug d, const QWindowsOleDropSource::CursorEntry &e) +{ + d << "CursorEntry:" << e.pixmap.size() << '#' << e.cacheKey + << "HCURSOR" << e.cursor->cursor << "hotspot:" << e.hotSpot; + return d; } +#endif // !QT_NO_DEBUG_OUTPUT /*! \brief Blend custom pixmap with cursors. @@ -343,59 +452,56 @@ void QWindowsOleDropSource::createCursors() const QPixmap pixmap = drag->pixmap(); const bool hasPixmap = !pixmap.isNull(); - QList<Qt::DropAction> actions; - actions << Qt::MoveAction << Qt::CopyAction << Qt::LinkAction; - if (hasPixmap) - actions << Qt::IgnoreAction; + Qt::DropAction actions[] = { Qt::MoveAction, Qt::CopyAction, Qt::LinkAction, Qt::IgnoreAction }; + int actionCount = int(sizeof(actions) / sizeof(actions[0])); + if (!hasPixmap) + --actionCount; // No Qt::IgnoreAction unless pixmap const QPoint hotSpot = drag->hotSpot(); - for (int cnum = 0; cnum < actions.size(); ++cnum) { - const Qt::DropAction action = actions.at(cnum); - QPixmap cpm = drag->dragCursor(action); - if (cpm.isNull()) - cpm = m_drag->defaultCursor(action); - QSharedPointer<DragCursorHandle> cursorHandler = m_cursors.value(action); - if (!cursorHandler.isNull() && cpm.cacheKey() == cursorHandler->cacheKey) + for (int cnum = 0; cnum < actionCount; ++cnum) { + const Qt::DropAction action = actions[cnum]; + QPixmap cursorPixmap = drag->dragCursor(action); + if (cursorPixmap.isNull()) + cursorPixmap = m_drag->defaultCursor(action); + const qint64 cacheKey = cursorPixmap.cacheKey(); + const ActionCursorMapIt it = m_cursors.find(action); + if (it != m_cursors.end() && it.value().cacheKey == cacheKey) continue; - if (cpm.isNull()) { + if (cursorPixmap.isNull()) { qWarning("%s: Unable to obtain drag cursor for %d.", __FUNCTION__, action); continue; } - int w = cpm.width(); - int h = cpm.height(); + QPoint newHotSpot(0, 0); + QPixmap newPixmap = cursorPixmap; if (hasPixmap) { const int x1 = qMin(-hotSpot.x(), 0); - const int x2 = qMax(pixmap.width() - hotSpot.x(), cpm.width()); + const int x2 = qMax(pixmap.width() - hotSpot.x(), cursorPixmap.width()); const int y1 = qMin(-hotSpot.y(), 0); - const int y2 = qMax(pixmap.height() - hotSpot.y(), cpm.height()); - - w = x2 - x1 + 1; - h = y2 - y1 + 1; - } - - const QPoint newHotSpot = hotSpot; - QPixmap newCursor(w, h); - if (hasPixmap) { + const int y2 = qMax(pixmap.height() - hotSpot.y(), cursorPixmap.height()); + QPixmap newCursor(x2 - x1 + 1, y2 - y1 + 1); newCursor.fill(Qt::transparent); QPainter p(&newCursor); const QRect srcRect = pixmap.rect(); const QPoint pmDest = QPoint(qMax(0, -hotSpot.x()), qMax(0, -hotSpot.y())); p.drawPixmap(pmDest, pixmap, srcRect); - p.drawPixmap(qMax(0,newHotSpot.x()),qMax(0,newHotSpot.y()),cpm); - } else { - newCursor = cpm; + p.drawPixmap(qMax(0, hotSpot.x()),qMax(0, hotSpot.y()), cursorPixmap); + newPixmap = newCursor; + newHotSpot = QPoint(qMax(0, hotSpot.x()), qMax(0, hotSpot.y())); } - const int hotX = hasPixmap ? qMax(0,newHotSpot.x()) : 0; - const int hotY = hasPixmap ? qMax(0,newHotSpot.y()) : 0; - - if (const HCURSOR sysCursor = QWindowsCursor::createPixmapCursor(newCursor, hotX, hotY)) { - m_cursors.insert(action, QSharedPointer<DragCursorHandle>(new DragCursorHandle(sysCursor, cpm.cacheKey()))); + if (const HCURSOR sysCursor = QWindowsCursor::createPixmapCursor(newPixmap, newHotSpot.x(), newHotSpot.y())) { + const CursorEntry entry(newPixmap, cacheKey, DragCursorHandlePtr(new DragCursorHandle(sysCursor)), newHotSpot); + if (it == m_cursors.end()) + m_cursors.insert(action, entry); + else + it.value() = entry; } } - if (QWindowsContext::verboseOLE) - qDebug("%s %d cursors", __FUNCTION__, m_cursors.size()); +#ifndef QT_NO_DEBUG_OUTPUT + if (lcQpaMime().isDebugEnabled()) + qCDebug(lcQpaMime) << __FUNCTION__ << "pixmap" << pixmap.size() << m_cursors.size() << "cursors:\n" << m_cursors; +#endif // !QT_NO_DEBUG_OUTPUT } //--------------------------------------------------------------------- @@ -468,11 +574,11 @@ QWindowsOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) } while (false); - if (QWindowsContext::verboseOLE - && (QWindowsContext::verboseOLE > 1 || hr != S_OK)) - qDebug("%s fEscapePressed=%d, grfKeyState=%lu buttons=%d returns 0x%x", - __FUNCTION__, fEscapePressed,grfKeyState, int(m_currentButtons), - int(hr)); + if (QWindowsContext::verbose > 1 || hr != S_OK) { + qCDebug(lcQpaMime) << __FUNCTION__ << "fEscapePressed=" << fEscapePressed + << "grfKeyState=" << grfKeyState << "buttons" << m_currentButtons + << "returns 0x" << hex <<int(hr) << dec; + } return hr; } @@ -486,17 +592,29 @@ QWindowsOleDropSource::GiveFeedback(DWORD dwEffect) const Qt::DropAction action = translateToQDragDropAction(dwEffect); m_drag->updateAction(action); - if (QWindowsContext::verboseOLE > 2) - qDebug("%s dwEffect=%lu, action=%d", __FUNCTION__, dwEffect, action); - - QSharedPointer<DragCursorHandle> cursorHandler = m_cursors.value(action); - qint64 currentCacheKey = m_drag->currentDrag()->dragCursor(action).cacheKey(); - if (cursorHandler.isNull() || currentCacheKey != cursorHandler->cacheKey) + const qint64 currentCacheKey = m_drag->currentDrag()->dragCursor(action).cacheKey(); + ActionCursorMapConstIt it = m_cursors.constFind(action); + // If a custom drag cursor is set, check its cache key to detect changes. + if (it == m_cursors.constEnd() || (currentCacheKey && currentCacheKey != it.value().cacheKey)) { createCursors(); + it = m_cursors.constFind(action); + } - const ActionCursorMap::const_iterator it = m_cursors.constFind(action); if (it != m_cursors.constEnd()) { - SetCursor(it.value()->cursor); + const CursorEntry &e = it.value(); + switch (m_mode) { + case MouseDrag: + SetCursor(e.cursor->cursor); + break; + case TouchDrag: + if (!m_touchDragWindow) + m_touchDragWindow = new QWindowsDragCursorWindow; + m_touchDragWindow->setPixmap(e.pixmap); + m_touchDragWindow->setFramePosition(QWindowsCursor::mousePosition() - e.hotSpot); + if (!m_touchDragWindow->isVisible()) + m_touchDragWindow->show(); + break; + } return ResultFromScode(S_OK); } @@ -519,14 +637,12 @@ QWindowsOleDropSource::GiveFeedback(DWORD dwEffect) QWindowsOleDropTarget::QWindowsOleDropTarget(QWindow *w) : m_refs(1), m_window(w), m_chosenEffect(0), m_lastKeyState(0) { - if (QWindowsContext::verboseOLE) - qDebug() << __FUNCTION__ << this << w; + qCDebug(lcQpaMime) << __FUNCTION__ << this << w; } QWindowsOleDropTarget::~QWindowsOleDropTarget() { - if (QWindowsContext::verboseOLE) - qDebug("%s %p", __FUNCTION__, this); + qCDebug(lcQpaMime) << __FUNCTION__ << this; } STDMETHODIMP @@ -588,13 +704,12 @@ void QWindowsOleDropTarget::handleDrag(QWindow *window, DWORD grfKeyState, m_chosenEffect = DROPEFFECT_NONE; } *pdwEffect = m_chosenEffect; - if (QWindowsContext::verboseOLE) - qDebug() << __FUNCTION__ << m_window - << windowsDrag->dropData() << " supported actions=" << actions - << " mods=" << QGuiApplicationPrivate::modifier_buttons - << " mouse=" << QGuiApplicationPrivate::mouse_buttons - << " accepted: " << response.isAccepted() << action - << m_answerRect << " effect" << *pdwEffect; + qCDebug(lcQpaMime) << __FUNCTION__ << m_window + << windowsDrag->dropData() << " supported actions=" << actions + << " mods=" << QGuiApplicationPrivate::modifier_buttons + << " mouse=" << QGuiApplicationPrivate::mouse_buttons + << " accepted: " << response.isAccepted() << action + << m_answerRect << " effect" << *pdwEffect; } QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP @@ -604,8 +719,8 @@ QWindowsOleDropTarget::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState, if (IDropTargetHelper* dh = QWindowsDrag::instance()->dropHelper()) dh->DragEnter(reinterpret_cast<HWND>(m_window->winId()), pDataObj, reinterpret_cast<POINT*>(&pt), *pdwEffect); - if (QWindowsContext::verboseOLE) - qDebug("%s widget=%p key=%lu, pt=%ld,%ld", __FUNCTION__, m_window, grfKeyState, pt.x, pt.y); + qCDebug(lcQpaMime) << __FUNCTION__ << "widget=" << m_window << " key=" << grfKeyState + << "pt=" << pt.x << pt.y; QWindowsDrag::instance()->setDropDataObject(pDataObj); pDataObj->AddRef(); @@ -621,15 +736,14 @@ QWindowsOleDropTarget::DragOver(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) dh->DragOver(reinterpret_cast<POINT*>(&pt), *pdwEffect); QWindow *dragOverWindow = findDragOverWindow(pt); - if (QWindowsContext::verboseOLE) - qDebug("%s widget=%p key=%lu, pt=%ld,%ld", __FUNCTION__, dragOverWindow, grfKeyState, pt.x, pt.y); + qCDebug(lcQpaMime) << __FUNCTION__ << "widget=" << dragOverWindow << " key=" << grfKeyState + << "pt=" << pt.x << pt.y; const QPoint tmpPoint = QWindowsGeometryHint::mapFromGlobal(dragOverWindow, QPoint(pt.x,pt.y)); // see if we should compress this event if ((tmpPoint == m_lastPoint || m_answerRect.contains(tmpPoint)) && m_lastKeyState == grfKeyState) { *pdwEffect = m_chosenEffect; - if (QWindowsContext::verboseOLE) - qDebug("%s: compressed event", __FUNCTION__); + qCDebug(lcQpaMime) << __FUNCTION__ << "compressed event"; return NOERROR; } @@ -643,8 +757,7 @@ QWindowsOleDropTarget::DragLeave() if (IDropTargetHelper* dh = QWindowsDrag::instance()->dropHelper()) dh->DragLeave(); - if (QWindowsContext::verboseOLE) - qDebug().nospace() <<__FUNCTION__ << ' ' << m_window; + qCDebug(lcQpaMime) << __FUNCTION__ << ' ' << m_window; QWindowSystemInterface::handleDrag(m_window, 0, QPoint(), Qt::IgnoreAction); QWindowsDrag::instance()->releaseDropDataObject(); @@ -663,11 +776,8 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState, QWindow *dropWindow = findDragOverWindow(pt); - if (QWindowsContext::verboseOLE) - qDebug().nospace() << __FUNCTION__ << ' ' << m_window - << " on " << dropWindow - << " keys=" << grfKeyState << " pt=" - << pt.x << ',' << pt.y; + qCDebug(lcQpaMime) << __FUNCTION__ << ' ' << m_window + << " on " << dropWindow << " keys=" << grfKeyState << " pt=" << pt.x << ',' << pt.y; m_lastPoint = QWindowsGeometryHint::mapFromGlobal(dropWindow, QPoint(pt.x,pt.y)); // grfKeyState does not all ways contain button state in the drop so if @@ -796,9 +906,8 @@ Qt::DropAction QWindowsDrag::drag(QDrag *drag) QWindowsOleDataObject *dropDataObject = new QWindowsOleDataObject(dropData); const Qt::DropActions possibleActions = drag->supportedActions(); const DWORD allowedEffects = translateToWinDragEffects(possibleActions); - if (QWindowsContext::verboseOLE) - qDebug(">%s possible Actions=%x, effects=0x%lx", __FUNCTION__, - int(possibleActions), allowedEffects); + qCDebug(lcQpaMime) << '>' << __FUNCTION__ << "possible Actions=0x" + << hex << int(possibleActions) << "effects=0x" << allowedEffects << dec; const HRESULT r = DoDragDrop(dropDataObject, windowDropSource, allowedEffects, &resultEffect); const DWORD reportedPerformedEffect = dropDataObject->reportedPerformedEffect(); if (r == DRAGDROP_S_DROP) { @@ -819,10 +928,9 @@ Qt::DropAction QWindowsDrag::drag(QDrag *drag) dropDataObject->releaseQt(); dropDataObject->Release(); // Will delete obj if refcount becomes 0 windowDropSource->Release(); // Will delete src if refcount becomes 0 - if (QWindowsContext::verboseOLE) - qDebug("<%s allowedEffects=0x%lx, reportedPerformedEffect=0x%lx, resultEffect=0x%lx, hr=0x%x, dropAction=%d", - __FUNCTION__, allowedEffects, reportedPerformedEffect, - resultEffect, int(r), dragResult); + qCDebug(lcQpaMime) << '<' << __FUNCTION__ << hex << "allowedEffects=0x" << allowedEffects + << "reportedPerformedEffect=0x" << reportedPerformedEffect + << " resultEffect=0x" << resultEffect << "hr=0x" << int(r) << dec << "dropAction=" << dragResult; return dragResult; } @@ -833,8 +941,7 @@ QWindowsDrag *QWindowsDrag::instance() void QWindowsDrag::releaseDropDataObject() { - if (QWindowsContext::verboseOLE) - qDebug("%s %p", __FUNCTION__, m_dropDataObject); + qCDebug(lcQpaMime) << __FUNCTION__ << m_dropDataObject; if (m_dropDataObject) { m_dropDataObject->Release(); m_dropDataObject = 0; diff --git a/src/plugins/platforms/windows/qwindowseglcontext.cpp b/src/plugins/platforms/windows/qwindowseglcontext.cpp index d029249eeb..a8617b2c2b 100644 --- a/src/plugins/platforms/windows/qwindowseglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowseglcontext.cpp @@ -89,16 +89,14 @@ QWindowsEGLStaticContext *QWindowsEGLStaticContext::create() Q_FUNC_INFO, eglGetError()); return 0; } - if (QWindowsContext::verboseGL) - qDebug("%s: Created EGL display %p v%d.%d", - __FUNCTION__, display, major, minor); + + qCDebug(lcQpaGl) << __FUNCTION__ << "Created EGL display" << display << 'v' <<major << '.' << minor; return new QWindowsEGLStaticContext(display, (major << 8) | minor); } QWindowsEGLStaticContext::~QWindowsEGLStaticContext() { - if (QWindowsContext::verboseGL) - qDebug("%s: Releasing EGL display %p", __FUNCTION__, m_display); + qCDebug(lcQpaGl) << __FUNCTION__ << "Releasing EGL display " << m_display; eglTerminate(m_display); } diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp index 3a6f9f72e3..c273219181 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp @@ -857,19 +857,20 @@ static bool addFontToDatabase(const QString &familyName, uchar charSet, const QFont::Stretch stretch = QFont::Unstretched; #ifndef QT_NO_DEBUG_OUTPUT - if (QWindowsContext::verboseFonts > 2) { - QDebug nospace = qDebug().nospace(); - nospace << __FUNCTION__ << familyName << charSet - << "TTF=" << ttf; + if (QWindowsContext::verbose > 2) { + QString message; + QTextStream str(&message); + str << __FUNCTION__ << ' ' << familyName << ' ' << charSet << " TTF=" << ttf; if (type & DEVICE_FONTTYPE) - nospace << " DEVICE"; + str << " DEVICE"; if (type & RASTER_FONTTYPE) - nospace << " RASTER"; + str << " RASTER"; if (type & TRUETYPE_FONTTYPE) - nospace << " TRUETYPE"; - nospace << " scalable=" << scalable << " Size=" << size + str << " TRUETYPE"; + str << " scalable=" << scalable << " Size=" << size << " Style=" << style << " Weight=" << weight << " stretch=" << stretch; + qCDebug(lcQpaFonts) << message; } #endif @@ -973,8 +974,7 @@ void QWindowsFontDatabase::populateFontDatabase() void QWindowsFontDatabase::populate(const QString &family) { - if (QWindowsContext::verboseFonts) - qDebug() << __FUNCTION__ << m_families.size() << family; + qCDebug(lcQpaFonts) << __FUNCTION__ << m_families.size() << family; HDC dummy = GetDC(0); LOGFONT lf; @@ -1026,11 +1026,10 @@ QWindowsFontDatabase::QWindowsFontDatabase() Q_UNUSED(hfontMetaTypeId) Q_UNUSED(logFontMetaTypeId) - if (QWindowsContext::verboseFonts) { + if (lcQpaFonts().isDebugEnabled()) { const QWindowsFontEngineDataPtr data = sharedFontData(); - qDebug() << __FUNCTION__ << "Clear type: " - << data->clearTypeEnabled << "gamma: " - << data->fontSmoothingGamma; + qCDebug(lcQpaFonts) << __FUNCTION__ << "Clear type: " + << data->clearTypeEnabled << "gamma: " << data->fontSmoothingGamma; } } @@ -1044,8 +1043,7 @@ QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef, QChar::S QFontEngine *fe = QWindowsFontDatabase::createEngine(script, fontDef, 0, QWindowsContext::instance()->defaultDPI(), false, QStringList(), sharedFontData()); - if (QWindowsContext::verboseFonts) - qDebug() << __FUNCTION__ << "FONTDEF" << fontDef << script << fe << handle; + qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDEF" << fontDef << script << fe << handle; return fe; } @@ -1200,8 +1198,7 @@ QFontEngine *QWindowsFontDatabase::fontEngine(const QByteArray &fontData, qreal } } - if (QWindowsContext::verboseFonts) - qDebug() << __FUNCTION__ << "FONTDATA" << fontData << pixelSize << hintingPreference << fontEngine; + qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDATA" << fontData << pixelSize << hintingPreference << fontEngine; return fontEngine; } @@ -1361,17 +1358,14 @@ void QWindowsFontDatabase::removeApplicationFonts() m_applicationFonts.clear(); } -void QWindowsFontDatabase::releaseHandle(void *handle) +void QWindowsFontDatabase::releaseHandle(void * /* handle */) { - if (handle && QWindowsContext::verboseFonts) - qDebug() << __FUNCTION__ << handle; } QString QWindowsFontDatabase::fontDir() const { const QString result = QPlatformFontDatabase::fontDir(); - if (QWindowsContext::verboseFonts) - qDebug() << __FUNCTION__ << result; + qCDebug(lcQpaFonts) << __FUNCTION__ << result; return result; } @@ -1550,7 +1544,7 @@ LOGFONT QWindowsFontDatabase::fontDefToLOGFONT(const QFontDef &request) return lf; } -static QStringList extraTryFontsForFamily(const QString& family) +QStringList QWindowsFontDatabase::extraTryFontsForFamily(const QString &family) { QStringList result; QFontDatabase db; @@ -1620,11 +1614,11 @@ 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(QWindowsFontDatabase::extraTryFontsForFamily(family)); - if (QWindowsContext::verboseFonts) - qDebug() << __FUNCTION__ << family << style << styleHint - << script << result << m_families.size(); + qCDebug(lcQpaFonts) << __FUNCTION__ << family << style << styleHint + << script << result << m_families.size(); return result; } @@ -1785,7 +1779,7 @@ QFontEngine *QWindowsFontDatabase::createEngine(int script, const QFontDef &requ if ((script == QChar::Script_Common || script == QChar::Script_Han) && !(request.styleStrategy & QFont::NoFontMerging)) { - QStringList extraFonts = extraTryFontsForFamily(request.family); + const QStringList extraFonts = QWindowsFontDatabase::extraTryFontsForFamily(request.family); if (extraFonts.size()) { QStringList list = family_list; list.append(extraFonts); @@ -1810,8 +1804,7 @@ QFont QWindowsFontDatabase::systemDefaultFont() // "MS Shell Dlg 2" is the correct system font >= Win2k if (systemFont.family() == QStringLiteral("MS Shell Dlg")) systemFont.setFamily(QStringLiteral("MS Shell Dlg 2")); - if (QWindowsContext::verboseFonts) - qDebug() << __FUNCTION__ << systemFont; + qCDebug(lcQpaFonts) << __FUNCTION__ << systemFont; return systemFont; } @@ -1825,9 +1818,9 @@ QFont QWindowsFontDatabase::LOGFONT_to_QFont(const LOGFONT& logFont, int vertica qFont.setWeight(weightFromInteger(logFont.lfWeight)); const qreal logFontHeight = qAbs(logFont.lfHeight); qFont.setPointSizeF(logFontHeight * 72.0 / qreal(verticalDPI_In)); - qFont.setUnderline(false); + qFont.setUnderline(logFont.lfUnderline); qFont.setOverline(false); - qFont.setStrikeOut(false); + qFont.setStrikeOut(logFont.lfStrikeOut); return qFont; } diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.h b/src/plugins/platforms/windows/qwindowsfontdatabase.h index b9e6c38eaa..7dfcfbc2b5 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.h +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.h @@ -103,6 +103,8 @@ public: static qreal fontSmoothingGamma(); static LOGFONT fontDefToLOGFONT(const QFontDef &fontDef); + static QStringList extraTryFontsForFamily(const QString &family); + private: void populate(const QString &family = QString()); void removeApplicationFonts(); diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp index 51f79736f2..c4fc2f4759 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp @@ -151,19 +151,20 @@ static bool addFontToDatabase(const QString &familyName, uchar charSet, const QFont::Stretch stretch = QFont::Unstretched; #ifndef QT_NO_DEBUG_OUTPUT - if (QWindowsContext::verboseFonts > 2) { - QDebug nospace = qDebug().nospace(); - nospace << __FUNCTION__ << familyName << faceName << fullName << charSet - << "TTF=" << ttf; + if (QWindowsContext::verbose > 2) { + QString message; + QTextStream str(&message); + str << __FUNCTION__ << ' ' << familyName << ' ' << charSet << " TTF=" << ttf; if (type & DEVICE_FONTTYPE) - nospace << " DEVICE"; + str << " DEVICE"; if (type & RASTER_FONTTYPE) - nospace << " RASTER"; + str << " RASTER"; if (type & TRUETYPE_FONTTYPE) - nospace << " TRUETYPE"; - nospace << " scalable=" << scalable << " Size=" << size + str << " TRUETYPE"; + str << " scalable=" << scalable << " Size=" << size << " Style=" << style << " Weight=" << weight << " stretch=" << stretch; + qCDebug(lcQpaFonts) << message; } #endif @@ -403,8 +404,7 @@ void QWindowsFontDatabaseFT::populateFontDatabase() void QWindowsFontDatabaseFT::populate(const QString &family) { - if (QWindowsContext::verboseFonts) - qDebug() << __FUNCTION__ << m_families.size() << family; + qCDebug(lcQpaFonts) << __FUNCTION__ << m_families.size() << family; HDC dummy = GetDC(0); LOGFONT lf; @@ -425,108 +425,19 @@ void QWindowsFontDatabaseFT::populate(const QString &family) QFontEngine * QWindowsFontDatabaseFT::fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle) { QFontEngine *fe = QBasicFontDatabase::fontEngine(fontDef, script, handle); - if (QWindowsContext::verboseFonts) - qDebug() << __FUNCTION__ << "FONTDEF" << /*fontDef <<*/ script << fe << handle; + qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDEF" << fontDef.family << script << fe << handle; return fe; } QFontEngine *QWindowsFontDatabaseFT::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) { QFontEngine *fe = QBasicFontDatabase::fontEngine(fontData, pixelSize, hintingPreference); - if (QWindowsContext::verboseFonts) - qDebug() << __FUNCTION__ << "FONTDATA" << fontData << pixelSize << hintingPreference << fe; + qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDATA" << fontData << pixelSize << hintingPreference << fe; return fe; } -static const char *other_tryFonts[] = { - "Arial", - "MS UI Gothic", - "Gulim", - "SimSun", - "PMingLiU", - "Arial Unicode MS", - 0 -}; - -static const char *jp_tryFonts [] = { - "MS UI Gothic", - "Arial", - "Gulim", - "SimSun", - "PMingLiU", - "Arial Unicode MS", - 0 -}; - -static const char *ch_CN_tryFonts [] = { - "SimSun", - "Arial", - "PMingLiU", - "Gulim", - "MS UI Gothic", - "Arial Unicode MS", - 0 -}; - -static const char *ch_TW_tryFonts [] = { - "PMingLiU", - "Arial", - "SimSun", - "Gulim", - "MS UI Gothic", - "Arial Unicode MS", - 0 -}; - -static const char *kr_tryFonts[] = { - "Gulim", - "Arial", - "PMingLiU", - "SimSun", - "MS UI Gothic", - "Arial Unicode MS", - 0 -}; - -static const char **tryFonts = 0; - QStringList QWindowsFontDatabaseFT::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const { - if (script == QChar::Script_Common || script == QChar::Script_Han) { -// && !(request.styleStrategy & QFont::NoFontMerging)) { - QFontDatabase db; - if (!db.writingSystems(family).contains(QFontDatabase::Symbol)) { - if(!tryFonts) { - LANGID lid = GetUserDefaultLangID(); - switch( lid&0xff ) { - case LANG_CHINESE: // Chinese (Taiwan) - if ( lid == 0x0804 ) // Taiwan - tryFonts = ch_TW_tryFonts; - else - tryFonts = ch_CN_tryFonts; - break; - case LANG_JAPANESE: - tryFonts = jp_tryFonts; - break; - case LANG_KOREAN: - tryFonts = kr_tryFonts; - break; - default: - tryFonts = other_tryFonts; - break; - } - } - QStringList list; - const char **tf = tryFonts; - while(tf && *tf) { - if(m_families.contains(QLatin1String(*tf))) - list << QLatin1String(*tf); - ++tf; - } - if (!list.isEmpty()) - return list; - } - } QStringList result = QPlatformFontDatabase::fallbacksForFamily(family, style, styleHint, script); if (!result.isEmpty()) return result; @@ -566,51 +477,24 @@ QStringList QWindowsFontDatabaseFT::fallbacksForFamily(const QString &family, QF } #endif - if (QWindowsContext::verboseFonts) - qDebug() << __FUNCTION__ << family << style << styleHint - << script << result << m_families; + if (script == QChar::Script_Common || script == QChar::Script_Han) + result.append(QWindowsFontDatabase::extraTryFontsForFamily(family)); + + qCDebug(lcQpaFonts) << __FUNCTION__ << family << style << styleHint + << script << result << m_families; + return result; } QString QWindowsFontDatabaseFT::fontDir() const { const QString result = QLatin1String(qgetenv("windir")) + QLatin1String("/Fonts");//QPlatformFontDatabase::fontDir(); - if (QWindowsContext::verboseFonts) - qDebug() << __FUNCTION__ << result; + qCDebug(lcQpaFonts) << __FUNCTION__ << result; return result; } -HFONT QWindowsFontDatabaseFT::systemFont() -{ - static const HFONT stock_sysfont = (HFONT)GetStockObject(SYSTEM_FONT); - return stock_sysfont; -} - -// Creation functions - -static inline int verticalDPI() -{ - return GetDeviceCaps(QWindowsContext::instance()->displayContext(), LOGPIXELSY); -} - QFont QWindowsFontDatabaseFT::defaultFont() const { return QWindowsFontDatabase::systemDefaultFont(); } -QFont QWindowsFontDatabaseFT::LOGFONT_to_QFont(const LOGFONT& logFont, int verticalDPI_In) -{ - if (verticalDPI_In <= 0) - verticalDPI_In = verticalDPI(); - QFont qFont(QString::fromWCharArray(logFont.lfFaceName)); - qFont.setItalic(logFont.lfItalic); - if (logFont.lfWeight != FW_DONTCARE) - qFont.setWeight(weightFromInteger(logFont.lfWeight)); - const qreal logFontHeight = qAbs(logFont.lfHeight); - qFont.setPointSizeF(logFontHeight * 72.0 / qreal(verticalDPI_In)); - qFont.setUnderline(logFont.lfUnderline); - qFont.setOverline(false); - qFont.setStrikeOut(logFont.lfStrikeOut); - return qFont; -} - QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h index d3cbc0210a..9544974ad1 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h +++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h @@ -60,9 +60,6 @@ public: virtual QString fontDir() const; virtual QFont defaultFont() const; - static HFONT systemFont(); - static QFont LOGFONT_to_QFont(const LOGFONT& lf, int verticalDPI = 0); - private: void populate(const QString &family = QString()); diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp index 6c928119b3..1676b73658 100644 --- a/src/plugins/platforms/windows/qwindowsfontengine.cpp +++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp @@ -219,44 +219,11 @@ inline unsigned int getChar(const QChar *str, int &i, const int len) return uc; } -int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLayout *glyphs, bool mirrored) const +int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLayout *glyphs) const { int i = 0; int glyph_pos = 0; - if (mirrored) { -#if defined(Q_OS_WINCE) - { -#else - if (symbol) { - for (; i < numChars; ++i, ++glyph_pos) { - unsigned int uc = getChar(str, i, numChars); - glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc); - if (!glyphs->glyphs[glyph_pos] && uc < 0x100) - glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000); - } - } else if (ttf) { - for (; i < numChars; ++i, ++glyph_pos) { - unsigned int uc = getChar(str, i, numChars); - glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, QChar::mirroredChar(uc)); - } - } else { -#endif - wchar_t first = tm.tmFirstChar; - wchar_t last = tm.tmLastChar; - - for (; i < numChars; ++i, ++glyph_pos) { - uint ucs = QChar::mirroredChar(getChar(str, i, numChars)); - if ( -#ifdef Q_WS_WINCE - tm.tmFirstChar > 60000 || -#endif - ucs >= first && ucs <= last) - glyphs->glyphs[glyph_pos] = ucs; - else - glyphs->glyphs[glyph_pos] = 0; - } - } - } else { + { #if defined(Q_OS_WINCE) { #else @@ -325,8 +292,7 @@ QWindowsFontEngine::QWindowsFontEngine(const QString &name, designAdvances(0), designAdvancesSize(0) { - if (QWindowsContext::verboseFonts) - qDebug("%s: font='%s', size=%ld", __FUNCTION__, qPrintable(name), lf.lfHeight); + qCDebug(lcQpaFonts) << __FUNCTION__ << name << lf.lfHeight; HDC hdc = m_fontEngineData->hdc; SelectObject(hdc, hfont); fontDef.pixelSize = -lf.lfHeight; @@ -366,9 +332,7 @@ QWindowsFontEngine::~QWindowsFontEngine() if (!DeleteObject(hfont)) qErrnoWarning("%s: QFontEngineWin: failed to delete non-stock font... failed", __FUNCTION__); } - if (QWindowsContext::verboseFonts) - if (QWindowsContext::verboseFonts) - qDebug("%s: font='%s", __FUNCTION__, qPrintable(_name)); + qCDebug(lcQpaFonts) << __FUNCTION__ << _name; if (!uniqueFamilyName.isEmpty()) { QPlatformFontDatabase *pfdb = QWindowsIntegration::instance()->fontDatabase(); @@ -393,7 +357,7 @@ bool QWindowsFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *g } glyphs->numGlyphs = *nglyphs; - *nglyphs = getGlyphIndexes(str, len, glyphs, flags & RightToLeft); + *nglyphs = getGlyphIndexes(str, len, glyphs); if (!(flags & GlyphIndicesOnly)) recalcAdvances(glyphs, flags); @@ -434,8 +398,7 @@ void QWindowsFontEngine::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::Shape calculateTTFGlyphWidth(hdc, glyph, width); designAdvances[glyph] = QFixed(width) / designToDevice; } - glyphs->advances_x[i] = designAdvances[glyph]; - glyphs->advances_y[i] = 0; + glyphs->advances[i] = designAdvances[glyph]; } if(oldFont) DeleteObject(SelectObject(hdc, oldFont)); @@ -443,8 +406,6 @@ void QWindowsFontEngine::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::Shape for(int i = 0; i < glyphs->numGlyphs; i++) { unsigned int glyph = glyphs->glyphs[i]; - glyphs->advances_y[i] = 0; - if (glyph >= widthCacheSize) { int newSize = (glyph + 256) >> 8 << 8; widthCache = q_check_ptr((unsigned char *)realloc(widthCache, @@ -452,9 +413,9 @@ void QWindowsFontEngine::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::Shape memset(widthCache + widthCacheSize, 0, newSize - widthCacheSize); widthCacheSize = newSize; } - glyphs->advances_x[i] = widthCache[glyph]; + glyphs->advances[i] = widthCache[glyph]; // font-width cache failed - if (glyphs->advances_x[i] == 0) { + if (glyphs->advances[i].value() == 0) { int width = 0; if (!oldFont) oldFont = SelectObject(hdc, hfont); @@ -473,7 +434,7 @@ void QWindowsFontEngine::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::Shape } else { calculateTTFGlyphWidth(hdc, glyph, width); } - glyphs->advances_x[i] = width; + glyphs->advances[i] = width; // if glyph's within cache range, store it for later if (width > 0 && width < 0x100) widthCache[glyph] = width; @@ -1347,8 +1308,7 @@ QWindowsMultiFontEngine::QWindowsMultiFontEngine(QFontEngine *first, const QStri : QFontEngineMulti(fallbacks.size()+1), fallbacks(fallbacks) { - if (QWindowsContext::verboseFonts) - qDebug() << __FUNCTION__ << engines.size() << first << first->fontDef.family << fallbacks; + qCDebug(lcQpaFonts) << __FUNCTION__ << engines.size() << first << first->fontDef.family << fallbacks; engines[0] = first; first->ref.ref(); fontDef = engines[0]->fontDef; @@ -1357,8 +1317,7 @@ QWindowsMultiFontEngine::QWindowsMultiFontEngine(QFontEngine *first, const QStri QWindowsMultiFontEngine::~QWindowsMultiFontEngine() { - if (QWindowsContext::verboseFonts) - qDebug("%s", __FUNCTION__); + qCDebug(lcQpaFonts) << __FUNCTION__; } void QWindowsMultiFontEngine::loadEngine(int at) @@ -1409,9 +1368,7 @@ void QWindowsMultiFontEngine::loadEngine(int at) fedw->ref.ref(); engines[at] = fedw; - if (QWindowsContext::verboseFonts) - qDebug("%s %d %s", __FUNCTION__, at, qPrintable(fam)); - + qCDebug(lcQpaFonts) << __FUNCTION__ << at << fam; return; } else { qErrnoWarning("%s: CreateFontFace failed", __FUNCTION__); @@ -1433,9 +1390,7 @@ void QWindowsMultiFontEngine::loadEngine(int at) engines[at] = new QWindowsFontEngine(fam, hfont, stockFont, lf, data); engines[at]->ref.ref(); engines[at]->fontDef = fontDef; - if (QWindowsContext::verboseFonts) - qDebug("%s %d %s", __FUNCTION__, at, qPrintable(fam)); - + qCDebug(lcQpaFonts) << __FUNCTION__ << at << fam; // TODO: increase cost in QFontCache for the font engine loaded here } diff --git a/src/plugins/platforms/windows/qwindowsfontengine.h b/src/plugins/platforms/windows/qwindowsfontengine.h index acf84d270c..e3fb3281a3 100644 --- a/src/plugins/platforms/windows/qwindowsfontengine.h +++ b/src/plugins/platforms/windows/qwindowsfontengine.h @@ -127,7 +127,7 @@ public: virtual void getGlyphBearings(glyph_t glyph, qreal *leftBearing = 0, qreal *rightBearing = 0); #endif - int getGlyphIndexes(const QChar *ch, int numChars, QGlyphLayout *glyphs, bool mirrored) const; + int getGlyphIndexes(const QChar *ch, int numChars, QGlyphLayout *glyphs) const; void getCMap(); bool getOutlineMetrics(glyph_t glyph, const QTransform &t, glyph_metrics_t *metrics) const; diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp index d81848fcc7..ce5ea8167f 100644 --- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp +++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp @@ -212,8 +212,7 @@ QWindowsFontEngineDirectWrite::QWindowsFontEngineDirectWrite(IDWriteFontFace *di , m_xHeight(-1) , m_lineGap(-1) { - if (QWindowsContext::verboseFonts) - qDebug("%s %g", __FUNCTION__, pixelSize); + qCDebug(lcQpaFonts) << __FUNCTION__ << pixelSize; Q_ASSERT(m_directWriteFontFace); @@ -227,8 +226,7 @@ QWindowsFontEngineDirectWrite::QWindowsFontEngineDirectWrite(IDWriteFontFace *di QWindowsFontEngineDirectWrite::~QWindowsFontEngineDirectWrite() { - if (QWindowsContext::verboseFonts) - qDebug("%s", __FUNCTION__); + qCDebug(lcQpaFonts) << __FUNCTION__; m_fontEngineData->directWriteFactory->Release(); m_directWriteFontFace->Release(); @@ -327,13 +325,8 @@ bool QWindowsFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGly QVarLengthArray<UINT32> codePoints(len); int actualLength = 0; - if (flags & QFontEngine::RightToLeft) { - for (int i = 0; i < len; ++i) - codePoints[actualLength++] = QChar::mirroredChar(getChar(str, i, len)); - } else { - for (int i = 0; i < len; ++i) - codePoints[actualLength++] = getChar(str, i, len); - } + for (int i = 0; i < len; ++i) + codePoints[actualLength++] = getChar(str, i, len); QVarLengthArray<UINT16> glyphIndices(actualLength); HRESULT hr = m_directWriteFontFace->GetGlyphIndicesW(codePoints.data(), actualLength, @@ -368,13 +361,11 @@ void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEn glyphIndices.size(), glyphMetrics.data()); if (SUCCEEDED(hr)) { - for (int i=0; i<glyphs->numGlyphs; ++i) { - glyphs->advances_x[i] = DESIGN_TO_LOGICAL(glyphMetrics[i].advanceWidth); - glyphs->advances_y[i] = 0; - } + for (int i = 0; i < glyphs->numGlyphs; ++i) + glyphs->advances[i] = DESIGN_TO_LOGICAL(glyphMetrics[i].advanceWidth); if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) { for (int i = 0; i < glyphs->numGlyphs; ++i) - glyphs->advances_x[i] = glyphs->advances_x[i].round(); + glyphs->advances[i] = glyphs->advances[i].round(); } } else { qErrnoWarning("%s: GetDesignGlyphMetrics failed", __FUNCTION__); diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h index 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/kms/qkmsvthandler.h b/src/plugins/platforms/windows/qwindowsgdinativeinterface.h index 8c4f511bc8..3aa3a0b175 100644 --- a/src/plugins/platforms/kms/qkmsvthandler.h +++ b/src/plugins/platforms/windows/qwindowsgdinativeinterface.h @@ -39,30 +39,20 @@ ** ****************************************************************************/ -#ifndef QKMSVTHANDLER_H -#define QKMSVTHANDLER_H +#ifndef QWINDOWSGDINATIVEINTERFACE_H +#define QWINDOWSGDINATIVEINTERFACE_H -#include <QObject> +#include "qwindowsnativeinterface.h" QT_BEGIN_NAMESPACE -class QKmsVTHandler : public QObject +class QWindowsGdiNativeInterface : public QWindowsNativeInterface { Q_OBJECT - public: - QKmsVTHandler(QObject *parent = 0); - ~QKmsVTHandler(); - -private: - void cleanup(); - static void crashHandler(); - - static QKmsVTHandler *self; - int m_tty; - int m_oldKbdMode; + void *nativeResourceForBackingStore(const QByteArray &resource, QBackingStore *bs) Q_DECL_OVERRIDE; }; QT_END_NAMESPACE -#endif +#endif // QWINDOWSGDINATIVEINTERFACE_H diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp index 82deb0f473..b046879314 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -223,7 +223,7 @@ static void describeFormats(HDC hdc) PIXELFORMATDESCRIPTOR pfd; initPixelFormatDescriptor(&pfd); DescribePixelFormat(hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd); - qDebug() << '#' << i << '/' << pfiMax << ':' << pfd; + qCDebug(lcQpaGl) << '#' << i << '/' << pfiMax << ':' << pfd; } } @@ -341,10 +341,8 @@ static int choosePixelFormat(HDC hdc, const QSurfaceFormat &format, bestPfi = pfi; *obtainedPfd = checkPfd; } - if (QWindowsContext::verboseGL) - qDebug() << __FUNCTION__ << " checking " << pfi << '/' << pfiMax - << " score=" << score << " (best " << bestPfi << '/' << bestScore - << ") " << checkPfd; + qCDebug(lcQpaGl) << __FUNCTION__ << " checking " << pfi << '/' << pfiMax + << " score=" << score << " (best " << bestPfi << '/' << bestScore << ") " << checkPfd; } } // for if (bestPfi > 0) @@ -471,15 +469,15 @@ static int choosePixelFormat(HDC hdc, initPixelFormatDescriptor(obtainedPfd); DescribePixelFormat(hdc, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), obtainedPfd); if (!isAcceptableFormat(additional, *obtainedPfd, true)) { - if (QWindowsContext::verboseGL) - qDebug() << __FUNCTION__ << " obtained px #" << pixelFormat - << " not acceptable=" << *obtainedPfd; + qCDebug(lcQpaGl) << __FUNCTION__ << " obtained px #" << pixelFormat + << " not acceptable=" << *obtainedPfd; pixelFormat = 0; } #ifndef QT_NO_DEBUG_OUTPUT - if (QWindowsContext::verboseGL) { - QDebug nsp = qDebug().nospace(); + if (lcQpaGl().isDebugEnabled()) { + QString message; + QDebug nsp(&message); nsp << __FUNCTION__; if (sampleBuffersRequested) nsp << " samples=" << iAttributes[samplesValuePosition]; @@ -488,6 +486,7 @@ static int choosePixelFormat(HDC hdc, nsp << iAttributes[ii] << ','; nsp << noshowbase << dec << "\n obtained px #" << pixelFormat << " of " << numFormats << "\n " << *obtainedPfd; + qCDebug(lcQpaGl) << message; } // Debug #endif @@ -611,9 +610,8 @@ static HGLRC createContext(const QOpenGLStaticContext &staticContext, break; } } - if (QWindowsContext::verboseGL) - qDebug("%s: Creating context version %d.%d with %d attributes", - __FUNCTION__, majorVersion, minorVersion, attribIndex / 2); + qCDebug(lcQpaGl) << __FUNCTION__ << "Creating context version" + << majorVersion << '.' << minorVersion << attribIndex / 2 << "attributes"; const HGLRC result = staticContext.wglCreateContextAttribsARB(hdc, shared, attributes); @@ -842,8 +840,7 @@ QOpenGLStaticContext *QOpenGLStaticContext::create() if (!wglGetCurrentContext()) temporaryContext.reset(new QOpenGLTemporaryContext); QOpenGLStaticContext *result = new QOpenGLStaticContext; - if (QWindowsContext::verboseGL) - qDebug() << __FUNCTION__ << *result; + qCDebug(lcQpaGl) << __FUNCTION__ << *result; return result; } @@ -857,7 +854,7 @@ QDebug operator<<(QDebug d, const QOpenGLStaticContext &s) if (s.hasExtensions()) nsp << ", Extension-API present"; nsp << "\nExtensions: " << (s.extensionNames.count(' ') + 1); - if (QWindowsContext::verboseGL > 1) + if (QWindowsContext::verbose > 1) nsp << s.extensionNames; return d; } @@ -882,7 +879,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) @@ -915,7 +914,7 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex if (!hdc) break; - if (QWindowsContext::verboseGL > 1) + if (QWindowsContext::verbose > 1) describeFormats(hdc); // Preferably use direct rendering and ARB extensions (unless pixmap // or explicitly turned off on command line). @@ -979,11 +978,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) @@ -991,14 +988,12 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex if (dummyWindow) DestroyWindow(dummyWindow); - if (QWindowsContext::verboseGL) - qDebug() << __FUNCTION__ << this << (tryExtensions ? "ARB" : "GDI") - << " requested: " << context->format() - << "\n obtained #" << m_pixelFormat << (m_extensionsUsed ? "ARB" : "GDI") - << m_obtainedFormat << "\n " << m_obtainedPixelFormatDescriptor - << " swap interval: " << obtainedSwapInternal - << "\n default: " << m_staticContext->defaultFormat - << "\n HGLRC=" << m_renderingContext; + qCDebug(lcQpaGl()) << __FUNCTION__ << this << (tryExtensions ? "ARB" : "GDI") + << " requested: " << context->format() + << "\n obtained #" << m_pixelFormat << (m_extensionsUsed ? "ARB" : "GDI") << m_obtainedFormat + << "\n " << m_obtainedPixelFormatDescriptor << " swap interval: " << obtainedSwapInternal + << "\n default: " << m_staticContext->defaultFormat + << "\n HGLRC=" << m_renderingContext; } QWindowsGLContext::~QWindowsGLContext() @@ -1039,8 +1034,8 @@ static inline const QOpenGLContextData * void QWindowsGLContext::swapBuffers(QPlatformSurface *surface) { - if (QWindowsContext::verboseGL > 1) - qDebug() << __FUNCTION__ << surface; + if (QWindowsContext::verbose > 1) + qCDebug(lcQpaGl) << __FUNCTION__ << surface; if (const QOpenGLContextData *contextData = findByHWND(m_windowContexts, handleOf(surface))) { SwapBuffers(contextData->hdc); } else { @@ -1051,8 +1046,8 @@ void QWindowsGLContext::swapBuffers(QPlatformSurface *surface) bool QWindowsGLContext::makeCurrent(QPlatformSurface *surface) { #ifdef DEBUG_GL - if (QWindowsContext::verboseGL > 1) - qDebug("%s context=%p contexts=%d", __FUNCTION__, this, m_windowContexts.size()); + if (QWindowsContext::verbose > 1) + qCDebug(lcQpaGl) << __FUNCTION__ << this << m_windowContexts.size() << "contexts"; #endif // DEBUG_GL Q_ASSERT(surface->surface()->surfaceType() == QSurface::OpenGLSurface); @@ -1087,14 +1082,26 @@ 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() { #ifdef DEBUG_GL - if (QWindowsContext::verboseGL > 1) - qDebug("%s context=%p %d contexts", __FUNCTION__, this, m_windowContexts.size()); + if (QWindowsContext::verbose > 1) + qCDebug(lcQpaGl) << __FUNCTION__ << this << m_windowContexts.size() << "contexts"; #endif // DEBUG_GL wglMakeCurrent(0, 0); releaseDCs(); @@ -1104,10 +1111,8 @@ QWindowsGLContext::GL_Proc QWindowsGLContext::getProcAddress(const QByteArray &p { // TODO: Will that work with the calling conventions? GL_Proc procAddress = reinterpret_cast<GL_Proc>(wglGetProcAddress(procName.constData())); - if (QWindowsContext::verboseGL > 1) - qDebug("%s('%s') with current_hglrc=%p returns %p", - __FUNCTION__, procName.constData(), - wglGetCurrentContext(), procAddress); + if (QWindowsContext::verbose > 1) + qCDebug(lcQpaGl) << __FUNCTION__ << procName << wglGetCurrentContext() << "returns" << procAddress; if (!procAddress) qWarning("%s: Unable to resolve '%s'", __FUNCTION__, procName.constData()); return procAddress; 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/qwindowsguieventdispatcher.cpp b/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp index e7cd0bc6c8..878db7185d 100644 --- a/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp +++ b/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp @@ -75,11 +75,11 @@ QWindowsGuiEventDispatcher::QWindowsGuiEventDispatcher(QObject *parent) : bool QWindowsGuiEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) { m_flags = flags; - if (QWindowsContext::verboseEvents > 2) - qDebug(">%s %s %d", __FUNCTION__, qPrintable(objectName()), int(flags)); + if (QWindowsContext::verbose > 2 && lcQpaEvents().isDebugEnabled()) + qCDebug(lcQpaEvents) << '>' << __FUNCTION__ << objectName() << flags; const bool rc = QEventDispatcherWin32::processEvents(flags); - if (QWindowsContext::verboseEvents > 2) - qDebug("<%s %s returns %d", __FUNCTION__, qPrintable(objectName()), rc); + if (QWindowsContext::verbose > 2 && lcQpaEvents().isDebugEnabled()) + qCDebug(lcQpaEvents) << '<' << __FUNCTION__ << "returns" << rc; return rc; } diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp index a84d30de0f..2429e8a4fa 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp @@ -188,8 +188,7 @@ void QWindowsInputContext::reset() if (!m_compositionContext.hwnd) return; QObject *fo = qApp->focusObject(); - if (QWindowsContext::verboseInputMethods) - qDebug() << __FUNCTION__<< fo; + qCDebug(lcQpaInputMethods) << __FUNCTION__<< fo; if (!fo) return; if (m_compositionContext.isComposing) { @@ -221,8 +220,7 @@ void QWindowsInputContext::cursorRectChanged() if (!cursorRectangle.isValid()) return; - if (QWindowsContext::verboseInputMethods) - qDebug() << __FUNCTION__<< cursorRectangle; + qCDebug(lcQpaInputMethods) << __FUNCTION__<< cursorRectangle; const HIMC himc = ImmGetContext(m_compositionContext.hwnd); if (!himc) @@ -259,8 +257,7 @@ void QWindowsInputContext::invokeAction(QInputMethod::Action action, int cursorP return; } - if (QWindowsContext::verboseInputMethods) - qDebug() << __FUNCTION__ << cursorPosition << action; + qCDebug(lcQpaInputMethods) << __FUNCTION__ << cursorPosition << action; if (cursorPosition < 0 || cursorPosition > m_compositionContext.composition.size()) reset(); @@ -339,8 +336,7 @@ bool QWindowsInputContext::startComposition(HWND hwnd) QWindow *window = qApp->focusWindow(); if (!window) return false; - if (QWindowsContext::verboseInputMethods) - qDebug() << __FUNCTION__ << fo << window; + qCDebug(lcQpaInputMethods) << __FUNCTION__ << fo << window; if (!fo || QWindowsWindow::handleOf(window) != hwnd) return false; initContext(hwnd); @@ -402,9 +398,8 @@ bool QWindowsInputContext::composition(HWND hwnd, LPARAM lParamIn) { QObject *fo = qApp->focusObject(); const int lParam = int(lParamIn); - if (QWindowsContext::verboseInputMethods) - qDebug() << '>' << __FUNCTION__ << fo << debugComposition(lParam) - << " composing=" << m_compositionContext.isComposing; + qCDebug(lcQpaInputMethods) << '>' << __FUNCTION__ << fo << debugComposition(lParam) + << " composing=" << m_compositionContext.isComposing; if (!fo || m_compositionContext.hwnd != hwnd || !lParam) return false; const HIMC himc = ImmGetContext(m_compositionContext.hwnd); @@ -443,11 +438,9 @@ bool QWindowsInputContext::composition(HWND hwnd, LPARAM lParamIn) endContextComposition(); } const bool result = QCoreApplication::sendEvent(fo, event.data()); - if (QWindowsContext::verboseInputMethods) - qDebug() << '<' << __FUNCTION__ << "sending markup=" - << event->attributes().size() - << " commit=" << event->commitString() - << " to " << fo << " returns " << result; + qCDebug(lcQpaInputMethods) << '<' << __FUNCTION__ << "sending markup=" + << event->attributes().size() << " commit=" << event->commitString() + << " to " << fo << " returns " << result; update(Qt::ImQueryAll); ImmReleaseContext(m_compositionContext.hwnd, himc); return result; @@ -455,8 +448,7 @@ bool QWindowsInputContext::composition(HWND hwnd, LPARAM lParamIn) bool QWindowsInputContext::endComposition(HWND hwnd) { - if (QWindowsContext::verboseInputMethods) - qDebug() << __FUNCTION__ << m_endCompositionRecursionGuard << hwnd; + qCDebug(lcQpaInputMethods) << __FUNCTION__ << m_endCompositionRecursionGuard << hwnd; // Googles Pinyin Input Method likes to call endComposition again // when we call notifyIME with CPS_CANCEL, so protect ourselves // against that. @@ -549,10 +541,8 @@ int QWindowsInputContext::reconvertString(RECONVERTSTRING *reconv) return -1; const DWORD memSize = sizeof(RECONVERTSTRING) + (surroundingText.length() + 1) * sizeof(ushort); - if (QWindowsContext::verboseInputMethods) - qDebug() << __FUNCTION__ << " reconv=" << reconv - << " surroundingText=" << surroundingText - << " size=" << memSize; + qCDebug(lcQpaInputMethods) << __FUNCTION__ << " reconv=" << reconv + << " surroundingText=" << surroundingText << " size=" << memSize; // If memory is not allocated, return the required size. if (!reconv) return surroundingText.isEmpty() ? -1 : int(memSize); @@ -567,8 +557,7 @@ int QWindowsInputContext::reconvertString(RECONVERTSTRING *reconv) const int startPos = bounds.position(); bounds.toNextBoundary(); const int endPos = bounds.position(); - if (QWindowsContext::verboseInputMethods) - qDebug() << __FUNCTION__ << " boundary=" << startPos << endPos; + qCDebug(lcQpaInputMethods) << __FUNCTION__ << " boundary=" << startPos << endPos; // Select the text, this will be overwritten by following IME events. QList<QInputMethodEvent::Attribute> attributes; attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, startPos, endPos-startPos, QVariant()); diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index b6e75929f8..8a91929733 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,10 @@ 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; + } else if (param.startsWith(QLatin1String("verbose="))) { + QWindowsContext::verbose = param.right(param.size() - 8).toInt(); } } return options; @@ -375,8 +205,6 @@ QWindowsIntegration::QWindowsIntegration(const QStringList ¶mList) : QWindowsIntegration::~QWindowsIntegration() { - if (QWindowsContext::verboseIntegration) - qDebug("%s", __FUNCTION__); } bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) const @@ -406,14 +234,9 @@ bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) co return false; } -QPlatformPixmap *QWindowsIntegration::createPlatformPixmap(QPlatformPixmap::PixelType type) const +QWindowsWindowData QWindowsIntegration::createWindowData(QWindow *window) const { - return new QRasterPlatformPixmap(type); -} - -QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) const -{ - QWindowsWindow::WindowData requested; + QWindowsWindowData requested; requested.flags = window->flags(); requested.geometry = window->geometry(); // Apply custom margins (see QWindowsWindow::setCustomMargins())). @@ -421,42 +244,40 @@ QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) cons if (customMarginsV.isValid()) requested.customMargins = qvariant_cast<QMargins>(customMarginsV); - const QWindowsWindow::WindowData obtained - = QWindowsWindow::WindowData::create(window, requested, window->title()); - if (QWindowsContext::verboseIntegration || QWindowsContext::verboseWindows) - qDebug().nospace() - << __FUNCTION__ << '<' << window << '\n' - << " Requested: " << requested.geometry << "frame incl.: " - << QWindowsGeometryHint::positionIncludesFrame(window) - << " Flags=" - << QWindowsWindow::debugWindowFlags(requested.flags) << '\n' - << " Obtained : " << obtained.geometry << " Margins " - << obtained.frame << " Flags=" - << QWindowsWindow::debugWindowFlags(obtained.flags) - << " Handle=" << obtained.hwnd << '\n'; - if (!obtained.hwnd) - return 0; - if (requested.flags != obtained.flags) - window->setFlags(obtained.flags); - // Trigger geometry change signals of QWindow. - if ((obtained.flags & Qt::Desktop) != Qt::Desktop && requested.geometry != obtained.geometry) - QWindowSystemInterface::handleGeometryChange(window, obtained.geometry); - return new QWindowsWindow(window, obtained); + const QWindowsWindowData obtained + = QWindowsWindowData::create(window, requested, window->title()); + qCDebug(lcQpaWindows).nospace() + << __FUNCTION__ << '<' << window + << "\n Requested: " << requested.geometry << "frame incl.: " + << QWindowsGeometryHint::positionIncludesFrame(window) + << " Flags=" << QWindowsWindow::debugWindowFlags(requested.flags) + << "\n Obtained : " << obtained.geometry << " Margins "<< obtained.frame + << " Flags=" << QWindowsWindow::debugWindowFlags(obtained.flags) + << " Handle=" << obtained.hwnd << '\n'; + + if (obtained.hwnd) { + if (requested.flags != obtained.flags) + window->setFlags(obtained.flags); + // Trigger geometry change signals of QWindow. + if ((obtained.flags & Qt::Desktop) != Qt::Desktop && requested.geometry != obtained.geometry) + QWindowSystemInterface::handleGeometryChange(window, obtained.geometry); + } + + return obtained; } -QPlatformBackingStore *QWindowsIntegration::createPlatformBackingStore(QWindow *window) const +QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) const { - if (QWindowsContext::verboseIntegration) - qDebug() << __FUNCTION__ << window; - return new QWindowsBackingStore(window); + QWindowsWindowData data = createWindowData(window); + return data.hwnd ? new QWindowsWindow(window, data) + : Q_NULLPTR; } #ifndef QT_NO_OPENGL QPlatformOpenGLContext *QWindowsIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { - if (QWindowsContext::verboseIntegration) - qDebug() << __FUNCTION__ << context->format(); + qCDebug(lcQpaGl) << __FUNCTION__ << context->format(); #ifdef QT_OPENGL_ES_2 if (d->m_staticEGLContext.isNull()) { QWindowsEGLStaticContext *staticContext = QWindowsEGLStaticContext::create(); @@ -510,9 +331,7 @@ QPlatformFontDatabase *QWindowsIntegration::fontDatabase() const d->m_fontDatabase = new QWindowsFontDatabase; #else if (isQMLApplication()) { - if (QWindowsContext::verboseIntegration) { - qDebug() << "QML application detected, using FreeType rendering"; - } + qCDebug(lcQpaFonts) << "QML application detected, using FreeType rendering"; d->m_fontDatabase = new QWindowsFontDatabaseFT; } else @@ -563,11 +382,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 +402,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 +467,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..2202ebd39e 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.h +++ b/src/plugins/platforms/windows/qwindowsintegration.h @@ -50,6 +50,8 @@ QT_BEGIN_NAMESPACE struct QWindowsIntegrationPrivate; +struct QWindowsWindowData; +class QWindowsWindow; class QWindowsIntegration : public QPlatformIntegration { @@ -60,7 +62,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 +70,8 @@ public: bool hasCapability(QPlatformIntegration::Capability cap) const; - virtual QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const; + QWindowsWindowData createWindowData(QWindow *window) const; QPlatformWindow *createPlatformWindow(QWindow *window) const; - QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; #ifndef QT_NO_OPENGL virtual QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; #endif @@ -85,7 +86,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/qwindowsinternalmimedata.cpp b/src/plugins/platforms/windows/qwindowsinternalmimedata.cpp index 5d22ea1a83..75686182cf 100644 --- a/src/plugins/platforms/windows/qwindowsinternalmimedata.cpp +++ b/src/plugins/platforms/windows/qwindowsinternalmimedata.cpp @@ -75,8 +75,7 @@ bool QWindowsInternalMimeData::hasFormat_sys(const QString &mime) const const QWindowsMimeConverter &mc = QWindowsContext::instance()->mimeConverter(); const bool has = mc.converterToMime(mime, pDataObj) != 0; releaseDataObject(pDataObj); - if (QWindowsContext::verboseOLE) - qDebug() << __FUNCTION__ << mime << has; + qCDebug(lcQpaMime) << __FUNCTION__ << mime << has; return has; } @@ -89,8 +88,7 @@ QStringList QWindowsInternalMimeData::formats_sys() const const QWindowsMimeConverter &mc = QWindowsContext::instance()->mimeConverter(); const QStringList fmts = mc.allMimesForFormats(pDataObj); releaseDataObject(pDataObj); - if (QWindowsContext::verboseOLE) - qDebug() << __FUNCTION__ << fmts; + qCDebug(lcQpaMime) << __FUNCTION__ << fmts; return fmts; } @@ -106,12 +104,10 @@ QVariant QWindowsInternalMimeData::retrieveData_sys(const QString &mimeType, if (const QWindowsMime *converter = mc.converterToMime(mimeType, pDataObj)) result = converter->convertToMime(mimeType, pDataObj, type); releaseDataObject(pDataObj); - if (QWindowsContext::verboseOLE) { - QDebug nospace = qDebug().nospace(); - nospace << __FUNCTION__ << ' ' << mimeType << ' ' << type - << " returns " << result.type(); - if (result.type() != QVariant::ByteArray) - nospace << ' ' << result; + if (QWindowsContext::verbose) { + qCDebug(lcQpaMime) <<__FUNCTION__ << ' ' << mimeType << ' ' << type + << " returns " << result.type() + << (result.type() != QVariant::ByteArray ? result.toString() : QStringLiteral("<data>")); } return result; } diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index 334df17026..0b257cc48f 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -653,16 +653,20 @@ void QWindowsKeyMapper::updatePossibleKeyCodes(unsigned char *kbdBuffer, quint32 ::ToAscii(VK_SPACE, 0, emptyBuffer, reinterpret_cast<LPWORD>(&buffer), 0); ::ToAscii(vk_key, scancode, kbdBuffer, reinterpret_cast<LPWORD>(&buffer), 0); } - - if (QWindowsContext::verboseEvents > 1) { - qDebug("updatePossibleKeyCodes for virtual key = 0x%02x!", vk_key); + if (QWindowsContext::verbose > 1 && lcQpaEvents().isDebugEnabled()) { + QString message; + QDebug debug(&message); + debug <<__FUNCTION__ << " for virtual key = 0x" << hex << vk_key << dec<< '\n'; for (size_t i = 0; i < NumMods; ++i) { - qDebug(" [%d] (%d,0x%02x,'%c') %s", int(i), - keyLayout[vk_key].qtKey[i], - keyLayout[vk_key].qtKey[i], - keyLayout[vk_key].qtKey[i] ? keyLayout[vk_key].qtKey[i] : 0x03, - keyLayout[vk_key].deadkeys & (1<<i) ? "deadkey" : ""); + const quint32 qtKey = keyLayout[vk_key].qtKey[i]; + debug << " [" << i << "] (" << qtKey << ',' + << hex << showbase << qtKey << noshowbase << dec + << ",'" << char(qtKey ? qtKey : 0x03) << "')"; + if (keyLayout[vk_key].deadkeys & (1<<i)) + debug << " deadkey"; + debug << '\n'; } + qCDebug(lcQpaEvents) << message; } } diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmime.cpp index f62b8a6139..3af2cff9a0 100644 --- a/src/plugins/platforms/windows/qwindowsmime.cpp +++ b/src/plugins/platforms/windows/qwindowsmime.cpp @@ -675,8 +675,7 @@ QVariant QWindowsMimeText::convertToMime(const QString &mime, LPDATAOBJECT pData else ret = str.toUtf8(); } - if (QWindowsContext::verboseOLE) - qDebug() << __FUNCTION__ << ret; + qCDebug(lcQpaMime) << __FUNCTION__ << ret; return ret; } @@ -1490,8 +1489,7 @@ QStringList QWindowsMimeConverter::allMimesForFormats(IDataObject *pDataObj) con } fmtenum->Release(); } - if (QWindowsContext::verboseOLE) - qDebug() << __FUNCTION__ << pDataObj << formats; + qCDebug(lcQpaMime) << __FUNCTION__ << pDataObj << formats; return formats; } @@ -1541,9 +1539,8 @@ QVariant QWindowsMimeConverter::convertToMime(const QStringList &mimeTypes, if (converter->canConvertToMime(format, pDataObj)) { const QVariant dataV = converter->convertToMime(format, pDataObj, preferredType); if (dataV.isValid()) { - if (QWindowsContext::verboseOLE) - qDebug() << __FUNCTION__ << mimeTypes << "\nFormat: " - << format << pDataObj << " returns " << dataV; + qCDebug(lcQpaMime) << __FUNCTION__ << mimeTypes << "\nFormat: " + << format << pDataObj << " returns " << dataV; if (formatIn) *formatIn = format; return dataV; @@ -1551,8 +1548,7 @@ QVariant QWindowsMimeConverter::convertToMime(const QStringList &mimeTypes, } } } - if (QWindowsContext::verboseOLE) - qDebug() << __FUNCTION__ << "fails" << mimeTypes << pDataObj << preferredType; + qCDebug(lcQpaMime) << __FUNCTION__ << "fails" << mimeTypes << pDataObj << preferredType; return QVariant(); } diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp index 3dd8c5a0cd..d8c0a9e426 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,22 +192,21 @@ 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). } *result = 0; if (msg.message == WM_MOUSELEAVE) { - if (QWindowsContext::verboseEvents) - qDebug() << "WM_MOUSELEAVE for " << window << " previous window under mouse = " << m_windowUnderMouse << " tracked window =" << m_trackedWindow; + qCDebug(lcQpaEvents) << "WM_MOUSELEAVE for " << window << " previous window under mouse = " << m_windowUnderMouse << " tracked window =" << m_trackedWindow; // When moving out of a window, WM_MOUSEMOVE within the moved-to window is received first, // so if m_trackedWindow is not the window here, it means the cursor has left the // application. if (window == m_trackedWindow) { QWindow *leaveTarget = m_windowUnderMouse ? m_windowUnderMouse : m_trackedWindow; - if (QWindowsContext::verboseEvents) - qDebug() << "Generating leave event for " << leaveTarget; + qCDebug(lcQpaEvents) << "Generating leave event for " << leaveTarget; QWindowSystemInterface::handleLeaveEvent(leaveTarget); m_trackedWindow = 0; m_windowUnderMouse = 0; @@ -231,8 +235,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, QWindowsWindow::baseWindowOf(window)->applyCursor(); platformWindow->setMouseGrabEnabled(true); platformWindow->setFlag(QWindowsWindow::AutoMouseCapture); - if (QWindowsContext::verboseEvents) - qDebug() << "Automatic mouse capture for missing buttondown event" << window; + qCDebug(lcQpaEvents) << "Automatic mouse capture for missing buttondown event" << window; } m_previousCaptureWindow = window; return true; @@ -257,8 +260,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, || msg.message == WM_RBUTTONDBLCLK || msg.message == WM_XBUTTONDBLCLK)) { platformWindow->setMouseGrabEnabled(true); platformWindow->setFlag(QWindowsWindow::AutoMouseCapture); - if (QWindowsContext::verboseEvents) - qDebug() << "Automatic mouse capture " << window; + qCDebug(lcQpaEvents) << "Automatic mouse capture " << window; // Implement "Click to focus" for native child windows (unless it is a native widget window). if (!window->isTopLevel() && !window->inherits("QWidgetWindow") && QGuiApplication::focusWindow() != window) window->requestActivate(); @@ -268,8 +270,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, || msg.message == WM_RBUTTONUP || msg.message == WM_XBUTTONUP) && !buttons) { platformWindow->setMouseGrabEnabled(false); - if (QWindowsContext::verboseEvents) - qDebug() << "Releasing automatic mouse capture " << window; + qCDebug(lcQpaEvents) << "Releasing automatic mouse capture " << window; } const bool hasCapture = platformWindow->hasMouseCapture(); @@ -301,8 +302,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, && (!hasCapture || window == m_windowUnderMouse)) || (hasCapture && m_previousCaptureWindow != window && m_windowUnderMouse && m_windowUnderMouse != window)) { - if (QWindowsContext::verboseEvents) - qDebug() << "Synthetic leave for " << m_windowUnderMouse; + qCDebug(lcQpaEvents) << "Synthetic leave for " << m_windowUnderMouse; QWindowSystemInterface::handleLeaveEvent(m_windowUnderMouse); if (currentNotCapturing) { // Clear tracking if capturing and current window is not the capturing window @@ -321,8 +321,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, && (!hasCapture || currentWindowUnderMouse == window)) || (m_previousCaptureWindow && window != m_previousCaptureWindow && currentWindowUnderMouse && currentWindowUnderMouse != m_previousCaptureWindow)) { - if (QWindowsContext::verboseEvents) - qDebug() << "Entering " << currentWindowUnderMouse; + qCDebug(lcQpaEvents) << "Entering " << currentWindowUnderMouse; QWindowsWindow::baseWindowOf(currentWindowUnderMouse)->applyCursor(); QWindowSystemInterface::handleEnterEvent(currentWindowUnderMouse, currentWindowUnderMouse->mapFromGlobal(globalPosition), @@ -335,7 +334,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/qwindowsole.cpp b/src/plugins/platforms/windows/qwindowsole.cpp index 0cea691f39..4f641d781d 100644 --- a/src/plugins/platforms/windows/qwindowsole.cpp +++ b/src/plugins/platforms/windows/qwindowsole.cpp @@ -80,14 +80,11 @@ QWindowsOleDataObject::QWindowsOleDataObject(QMimeData *mimeData) : CF_PERFORMEDDROPEFFECT(RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT)), performedEffect(DROPEFFECT_NONE) { - if (QWindowsContext::verboseOLE) - qDebug("%s '%s'", __FUNCTION__, qPrintable(mimeData->formats().join(QStringLiteral(", ")))); + qCDebug(lcQpaMime) << __FUNCTION__ << mimeData->formats(); } QWindowsOleDataObject::~QWindowsOleDataObject() { - if (QWindowsContext::verboseOLE) - qDebug("%s", __FUNCTION__); } void QWindowsOleDataObject::releaseQt() @@ -143,10 +140,10 @@ QWindowsOleDataObject::GetData(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium) { HRESULT hr = ResultFromScode(DATA_E_FORMATETC); - if (QWindowsContext::verboseOLE) { + if (QWindowsContext::verbose > 1 && lcQpaMime().isDebugEnabled()) { wchar_t buf[256] = {0}; GetClipboardFormatName(pformatetc->cfFormat, buf, 255); - qDebug("%s CF = %d : %s", __FUNCTION__, pformatetc->cfFormat, qPrintable(QString::fromWCharArray(buf))); + qCDebug(lcQpaMime) <<__FUNCTION__ << "CF = " << pformatetc->cfFormat << QString::fromWCharArray(buf); } if (data) { @@ -156,11 +153,10 @@ QWindowsOleDataObject::GetData(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium) hr = ResultFromScode(S_OK); } - if (QWindowsContext::verboseOLE) { + if (QWindowsContext::verbose > 1) { wchar_t buf[256] = {0}; GetClipboardFormatName(pformatetc->cfFormat, buf, 255); - qDebug("%s CF = %d : %s returns 0x%x", __FUNCTION__, pformatetc->cfFormat, - qPrintable(QString::fromWCharArray(buf)), int(hr)); + qCDebug(lcQpaMime) <<__FUNCTION__ << "CF = " << pformatetc->cfFormat << " returns 0x" << int(hr) << dec; } return hr; @@ -177,16 +173,16 @@ QWindowsOleDataObject::QueryGetData(LPFORMATETC pformatetc) { HRESULT hr = ResultFromScode(DATA_E_FORMATETC); - if (QWindowsContext::verboseOLE > 1) - qDebug("%s", __FUNCTION__); + if (QWindowsContext::verbose > 1) + qCDebug(lcQpaMime) << __FUNCTION__; if (data) { const QWindowsMimeConverter &mc = QWindowsContext::instance()->mimeConverter(); hr = mc.converterFromMime(*pformatetc, data) ? ResultFromScode(S_OK) : ResultFromScode(S_FALSE); } - if (QWindowsContext::verboseOLE > 1) - qDebug("%s returns 0x%x", __FUNCTION__, int(hr)); + if (QWindowsContext::verbose > 1) + qCDebug(lcQpaMime) << __FUNCTION__ << " returns 0x" << hex << int(hr); return hr; } @@ -200,8 +196,8 @@ QWindowsOleDataObject::GetCanonicalFormatEtc(LPFORMATETC, LPFORMATETC pformatetc STDMETHODIMP QWindowsOleDataObject::SetData(LPFORMATETC pFormatetc, STGMEDIUM *pMedium, BOOL fRelease) { - if (QWindowsContext::verboseOLE > 1) - qDebug("%s", __FUNCTION__); + if (QWindowsContext::verbose > 1) + qCDebug(lcQpaMime) << __FUNCTION__; HRESULT hr = ResultFromScode(E_NOTIMPL); @@ -213,8 +209,8 @@ QWindowsOleDataObject::SetData(LPFORMATETC pFormatetc, STGMEDIUM *pMedium, BOOL ReleaseStgMedium(pMedium); hr = ResultFromScode(S_OK); } - if (QWindowsContext::verboseOLE > 1) - qDebug("%s returns 0x%x", __FUNCTION__, int(hr)); + if (QWindowsContext::verbose > 1) + qCDebug(lcQpaMime) << __FUNCTION__ << " returns 0x" << hex << int(hr); return hr; } @@ -222,8 +218,8 @@ QWindowsOleDataObject::SetData(LPFORMATETC pFormatetc, STGMEDIUM *pMedium, BOOL STDMETHODIMP QWindowsOleDataObject::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC FAR* ppenumFormatEtc) { - if (QWindowsContext::verboseOLE > 1) - qDebug("%s", __FUNCTION__); + if (QWindowsContext::verbose > 1) + qCDebug(lcQpaMime) << __FUNCTION__; if (!data) return ResultFromScode(DATA_E_FORMATETC); @@ -285,8 +281,8 @@ QWindowsOleDataObject::EnumDAdvise(LPENUMSTATDATA FAR*) QWindowsOleEnumFmtEtc::QWindowsOleEnumFmtEtc(const QVector<FORMATETC> &fmtetcs) : m_dwRefs(1), m_nIndex(0), m_isNull(false) { - if (QWindowsContext::verboseOLE > 1) - qDebug("%s", __FUNCTION__); + if (QWindowsContext::verbose > 1) + qCDebug(lcQpaMime) << __FUNCTION__; m_lpfmtetcs.reserve(fmtetcs.count()); for (int idx = 0; idx < fmtetcs.count(); ++idx) { LPFORMATETC destetc = new FORMATETC(); @@ -303,8 +299,8 @@ QWindowsOleEnumFmtEtc::QWindowsOleEnumFmtEtc(const QVector<FORMATETC> &fmtetcs) QWindowsOleEnumFmtEtc::QWindowsOleEnumFmtEtc(const QVector<LPFORMATETC> &lpfmtetcs) : m_dwRefs(1), m_nIndex(0), m_isNull(false) { - if (QWindowsContext::verboseOLE > 1) - qDebug("%s", __FUNCTION__); + if (QWindowsContext::verbose > 1) + qCDebug(lcQpaMime) << __FUNCTION__; m_lpfmtetcs.reserve(lpfmtetcs.count()); for (int idx = 0; idx < lpfmtetcs.count(); ++idx) { LPFORMATETC srcetc = lpfmtetcs.at(idx); diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index 1fc1be53c7..a6e2aabaf0 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); @@ -243,8 +241,7 @@ QWindow *QWindowsScreen::findTopLevelAt(const QPoint &point, unsigned flags) if (QPlatformWindow *bw = QWindowsContext::instance()-> findPlatformWindowAt(GetDesktopWindow(), point, flags)) result = QWindowsWindow::topLevelOf(bw->window()); - if (QWindowsContext::verboseWindows) - qDebug() << __FUNCTION__ << point << flags << result; + qCDebug(lcQpaWindows) <<__FUNCTION__ << point << flags << result; return result; } @@ -254,8 +251,7 @@ QWindow *QWindowsScreen::windowAt(const QPoint &screenPoint, unsigned flags) if (QPlatformWindow *bw = QWindowsContext::instance()-> findPlatformWindowAt(GetDesktopWindow(), screenPoint, flags)) result = bw->window(); - if (QWindowsContext::verboseWindows) - qDebug() << __FUNCTION__ << screenPoint << " returns " << result; + qCDebug(lcQpaWindows) <<__FUNCTION__ << screenPoint << " returns " << result; return result; } @@ -366,9 +362,8 @@ bool QWindowsScreenManager::handleDisplayChange(WPARAM wParam, LPARAM lParam) m_lastDepth = newDepth; m_lastHorizontalResolution = newHorizontalResolution; m_lastVerticalResolution = newVerticalResolution; - if (QWindowsContext::verboseWindows) - qDebug("%s: Depth=%d, resolution=%hux%hu", - __FUNCTION__, newDepth, newHorizontalResolution, newVerticalResolution); + qCDebug(lcQpaWindows) << __FUNCTION__ << "Depth=" << newDepth + << ", resolution " << newHorizontalResolution << 'x' << newVerticalResolution; handleScreenChanges(); } return false; @@ -410,8 +405,7 @@ bool QWindowsScreenManager::handleScreenChanges() QWindowsScreen *newScreen = new QWindowsScreen(newData); m_screens.push_back(newScreen); QWindowsIntegration::instance()->emitScreenAdded(newScreen); - if (QWindowsContext::verboseWindows) - qDebug() << "New Monitor: " << newData; + qCDebug(lcQpaWindows) << "New Monitor: " << newData; } // exists } // for new screens. // Remove deleted ones but keep main monitors if we get only the @@ -419,8 +413,7 @@ bool QWindowsScreenManager::handleScreenChanges() if (!lockScreen) { for (int i = m_screens.size() - 1; i >= 0; --i) { if (indexOfMonitor(newDataList, m_screens.at(i)->data().name) == -1) { - if (QWindowsContext::verboseWindows) - qDebug() << "Removing Monitor: " << m_screens.at(i) ->data(); + qCDebug(lcQpaWindows) << "Removing Monitor: " << m_screens.at(i) ->data(); delete m_screens.takeAt(i); } // not found } // for existing screens diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.cpp b/src/plugins/platforms/windows/qwindowstabletsupport.cpp index 1a5c1a2e0c..8b863ec43d 100644 --- a/src/plugins/platforms/windows/qwindowstabletsupport.cpp +++ b/src/plugins/platforms/windows/qwindowstabletsupport.cpp @@ -182,8 +182,7 @@ QWindowsTabletSupport *QWindowsTabletSupport::create() L"TabletDummyWindow", qWindowsTabletSupportWndProc); if (!window) { - if (QWindowsContext::verboseTablet) - qWarning() << __FUNCTION__ << "Unable to create window for tablet."; + qCWarning(lcQpaTablet) << __FUNCTION__ << "Unable to create window for tablet."; return 0; } LOGCONTEXT lcMine; @@ -199,8 +198,7 @@ QWindowsTabletSupport *QWindowsTabletSupport::create() lcMine.lcOutExtY = -lcMine.lcInExtY; const HCTX context = QWindowsTabletSupport::m_winTab32DLL.wTOpen(window, &lcMine, true); if (!context) { - if (QWindowsContext::verboseTablet) - qWarning() << __FUNCTION__ << "Unable to open tablet."; + qCDebug(lcQpaTablet) << __FUNCTION__ << "Unable to open tablet."; DestroyWindow(window); return 0; @@ -217,9 +215,9 @@ QWindowsTabletSupport *QWindowsTabletSupport::create() } // cannot restore old size } // cannot set } // mismatch - if (QWindowsContext::verboseTablet) - qDebug("Opened tablet context %p on window %p, changed packet queue size %d -> %d", - context, window, currentQueueSize, TabletPacketQSize); + qCDebug(lcQpaTablet) << "Opened tablet context " << context << " on window " + << window << "changed packet queue size " << currentQueueSize + << "->" << TabletPacketQSize; return new QWindowsTabletSupport(window, context); } @@ -261,8 +259,7 @@ void QWindowsTabletSupport::notifyActivate() // Cooperate with other tablet applications, but when we get focus, I want to use the tablet. const bool result = QWindowsTabletSupport::m_winTab32DLL.wTEnable(m_context, true) && QWindowsTabletSupport::m_winTab32DLL.wTOverlap(m_context, true); - if (QWindowsContext::verboseTablet) - qDebug() << __FUNCTION__ << result; + qCDebug(lcQpaTablet) << __FUNCTION__ << result; } static inline int indexOfDevice(const QVector<QWindowsTabletDeviceData> &devices, qint64 uniqueId) @@ -369,10 +366,8 @@ bool QWindowsTabletSupport::translateTabletProximityEvent(WPARAM /* wParam */, L m_devices.push_back(tabletInit(uniqueId, cursorType)); } m_devices[m_currentDevice].currentPointerType = pointerType(currentCursor); - if (QWindowsContext::verboseTablet) - qDebug() << __FUNCTION__ << (enteredProximity ? "enter" : "leave") - << " proximity for device #" - << m_currentDevice << m_devices.at(m_currentDevice); + qCDebug(lcQpaTablet) << __FUNCTION__ << (enteredProximity ? "enter" : "leave") + << " proximity for device #" << m_currentDevice << m_devices.at(m_currentDevice); if (enteredProximity) { QWindowSystemInterface::handleTabletEnterProximityEvent(m_devices.at(m_currentDevice).currentDevice, m_devices.at(m_currentDevice).currentPointerType, @@ -410,9 +405,8 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() enum { absoluteRange = 20 }; const QRect virtualDesktopArea = QGuiApplication::primaryScreen()->virtualGeometry(); - if (QWindowsContext::verboseTablet) - qDebug() << __FUNCTION__ << "processing " << packetCount - << "target:" << QGuiApplicationPrivate::tabletPressTarget; + qCDebug(lcQpaTablet) << __FUNCTION__ << "processing " << packetCount + << "target:" << QGuiApplicationPrivate::tabletPressTarget; const Qt::KeyboardModifiers keyboardModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); @@ -474,8 +468,8 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() rotation = packet.pkOrientation.orTwist; } - if (QWindowsContext::verboseTablet > 1) { - qDebug() + if (QWindowsContext::verbose > 1) { + qCDebug(lcQpaTablet) << "Packet #" << i << '/' << packetCount << "button:" << packet.pkButtons << globalPosF << z << "to:" << target << localPos << "(packet" << packet.pkX << packet.pkY << ") dev:" << currentDevice << "pointer:" 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..5b6fced031 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -358,7 +358,7 @@ static void setWindowOpacity(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, bo struct WindowCreationData { - typedef QWindowsWindow::WindowData WindowData; + typedef QWindowsWindowData WindowData; enum Flags { ForceChild = 0x1, ForceTopLevel = 0x2 }; WindowCreationData() : parentHandle(0), type(Qt::Widget), style(0), exStyle(0), @@ -534,7 +534,7 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag } } -QWindowsWindow::WindowData +QWindowsWindowData WindowCreationData::create(const QWindow *w, const WindowData &data, QString title) const { typedef QSharedPointer<QWindowCreationContext> QWindowCreationContextPtr; @@ -546,8 +546,7 @@ QWindowsWindow::WindowData result.hwnd = GetDesktopWindow(); result.geometry = frameGeometry(result.hwnd, true); result.embedded = false; - if (QWindowsContext::verboseWindows) - qDebug().nospace() << "Created desktop window " << w << result.hwnd; + qCDebug(lcQpaWindows) << "Created desktop window " << w << result.hwnd; return result; } if ((flags & Qt::WindowType_Mask) == Qt::ForeignWindow) { @@ -558,8 +557,7 @@ QWindowsWindow::WindowData result.geometry = frameGeometry(result.hwnd, !GetParent(result.hwnd)); result.frame = QWindowsGeometryHint::frame(style, exStyle); result.embedded = false; - if (QWindowsContext::verboseWindows) - qDebug() << "Foreign window: " << w << result.hwnd << result.geometry << result.frame; + qCDebug(lcQpaWindows) << "Foreign window: " << w << result.hwnd << result.geometry << result.frame; return result; } @@ -580,24 +578,21 @@ QWindowsWindow::WindowData const QWindowCreationContextPtr context(new QWindowCreationContext(w, rect, data.customMargins, style, exStyle)); QWindowsContext::instance()->setWindowCreationContext(context); - if (QWindowsContext::verboseWindows) - qDebug().nospace() - << "CreateWindowEx: " << w << *this - << " class=" <<windowClassName << " title=" << title - << "\nrequested: " << rect << ": " - << context->frameWidth << 'x' << context->frameHeight - << '+' << context->frameX << '+' << context->frameY - << " custom margins: " << context->customMargins; + qCDebug(lcQpaWindows).nospace() + << "CreateWindowEx: " << w << *this << " class=" <<windowClassName << " title=" << title + << "\nrequested: " << rect << ": " + << context->frameWidth << 'x' << context->frameHeight + << '+' << context->frameX << '+' << context->frameY + << " custom margins: " << context->customMargins; result.hwnd = CreateWindowEx(exStyle, classNameUtf16, titleUtf16, style, context->frameX, context->frameY, context->frameWidth, context->frameHeight, parentHandle, NULL, appinst, NULL); - if (QWindowsContext::verboseWindows) - qDebug().nospace() - << "CreateWindowEx: returns " << w << ' ' << result.hwnd << " obtained geometry: " - << context->obtainedGeometry << context->margins; + qCDebug(lcQpaWindows).nospace() + << "CreateWindowEx: returns " << w << ' ' << result.hwnd << " obtained geometry: " + << context->obtainedGeometry << context->margins; if (!result.hwnd) { qErrnoWarning("%s: CreateWindowEx failed", __FUNCTION__); @@ -627,8 +622,7 @@ void WindowCreationData::applyWindowFlags(HWND hwnd) const const LONG_PTR newExStyle = exStyle; if (newExStyle != oldExStyle) SetWindowLongPtr(hwnd, GWL_EXSTYLE, newExStyle); - if (QWindowsContext::verboseWindows) - qDebug().nospace() << __FUNCTION__ << hwnd << *this + qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << hwnd << *this << "\n Style from " << debugWinStyle(oldStyle) << "\n to " << debugWinStyle(newStyle) << "\n ExStyle from " << debugWinExStyle(oldExStyle) << " to " @@ -705,10 +699,8 @@ QMargins QWindowsGeometryHint::frame(DWORD style, DWORD exStyle) qErrnoWarning("%s: AdjustWindowRectEx failed", __FUNCTION__); const QMargins result(qAbs(rect.left), qAbs(rect.top), qAbs(rect.right), qAbs(rect.bottom)); - if (QWindowsContext::verboseWindows) - qDebug().nospace() << __FUNCTION__ << " style= 0x" - << QString::number(style, 16) - << " exStyle=0x" << QString::number(exStyle, 16) << ' ' << rect << ' ' << result; + qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << " style= 0x" + << QString::number(style, 16) << " exStyle=0x" << QString::number(exStyle, 16) << ' ' << rect << ' ' << result; return result; } @@ -727,10 +719,9 @@ bool QWindowsGeometryHint::handleCalculateSize(const QMargins &customMargins, co ncp->rgrc[0].right -= customMargins.right(); ncp->rgrc[0].bottom -= customMargins.bottom(); result = 0; - if (QWindowsContext::verboseWindows) - qDebug() << __FUNCTION__ << oldClientArea << '+' << customMargins << "-->" - << ncp->rgrc[0] << ' ' << ncp->rgrc[1] << ' ' << ncp->rgrc[2] - << ' ' << ncp->lppos->cx << ',' << ncp->lppos->cy; + qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << oldClientArea << '+' << customMargins << "-->" + << ncp->rgrc[0] << ' ' << ncp->rgrc[1] << ' ' << ncp->rgrc[2] + << ' ' << ncp->lppos->cx << ',' << ncp->lppos->cy; return true; #else Q_UNUSED(customMargins) @@ -749,11 +740,10 @@ void QWindowsGeometryHint::applyToMinMaxInfo(HWND hwnd, MINMAXINFO *mmi) const void QWindowsGeometryHint::applyToMinMaxInfo(DWORD style, DWORD exStyle, MINMAXINFO *mmi) const { - if (QWindowsContext::verboseWindows) - qDebug().nospace() << '>' << __FUNCTION__ << '<' << " min=" - << minimumSize.width() << ',' << minimumSize.height() - << " max=" << maximumSize.width() << ',' << maximumSize.height() - << " in " << *mmi; + qCDebug(lcQpaWindows).nospace() << '>' << __FUNCTION__ << '<' << " min=" + << minimumSize.width() << ',' << minimumSize.height() + << " max=" << maximumSize.width() << ',' << maximumSize.height() + << " in " << *mmi; const QMargins margins = QWindowsGeometryHint::frame(style, exStyle); const int frameWidth = margins.left() + margins.right() + customMargins.left() + customMargins.right(); @@ -770,10 +760,9 @@ void QWindowsGeometryHint::applyToMinMaxInfo(DWORD style, DWORD exStyle, MINMAXI // windows with title bar have an implicit size limit of 112 pixels if (maximumHeight < QWINDOWSIZE_MAX) mmi->ptMaxTrackSize.y = qMax(maximumHeight + frameHeight, 112); - if (QWindowsContext::verboseWindows) - qDebug().nospace() << '<' << __FUNCTION__ - << " frame=" << margins << ' ' << frameWidth << ',' << frameHeight - << " out " << *mmi; + qCDebug(lcQpaWindows).nospace() << '<' << __FUNCTION__ + << " frame=" << margins << ' ' << frameWidth << ',' << frameHeight + << " out " << *mmi; } #endif // !Q_OS_WINCE @@ -831,15 +820,13 @@ QWindowCreationContext::QWindowCreationContext(const QWindow *w, } } - if (QWindowsContext::verboseWindows) - qDebug().nospace() - << __FUNCTION__ << ' ' << w << geometry - << " pos incl. frame" << QWindowsGeometryHint::positionIncludesFrame(w) - << " frame: " << frameWidth << 'x' << frameHeight << '+' - << frameX << '+' << frameY - << " min" << geometryHint.minimumSize - << " max" << geometryHint.maximumSize - << " custom margins " << customMargins; + qCDebug(lcQpaWindows).nospace() + << __FUNCTION__ << ' ' << w << geometry + << " pos incl. frame" << QWindowsGeometryHint::positionIncludesFrame(w) + << " frame: " << frameWidth << 'x' << frameHeight << '+' + << frameX << '+' << frameY + << " min" << geometryHint.minimumSize << " max" << geometryHint.maximumSize + << " custom margins " << customMargins; } /*! @@ -864,7 +851,7 @@ QWindowCreationContext::QWindowCreationContext(const QWindow *w, \ingroup qt-lighthouse-win */ -QWindowsWindow::QWindowsWindow(QWindow *aWindow, const WindowData &data) : +QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) : QPlatformWindow(aWindow), m_data(data), m_flags(WithinCreate), @@ -949,8 +936,7 @@ void QWindowsWindow::fireExpose(const QRegion ®ion, bool force) void QWindowsWindow::destroyWindow() { - if (QWindowsContext::verboseIntegration || QWindowsContext::verboseWindows) - qDebug() << __FUNCTION__ << this << window() << m_data.hwnd; + qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() << m_data.hwnd; if (m_data.hwnd) { // Stop event dispatching before Window is destroyed. setFlag(WithinDestroy); QWindowsContext *context = QWindowsContext::instance(); @@ -961,9 +947,7 @@ void QWindowsWindow::destroyWindow() unregisterDropSite(); #ifdef QT_OPENGL_ES_2 if (m_eglSurface) { - if (QWindowsContext::verboseGL) - qDebug("%s: Freeing EGL surface %p, this = %p", - __FUNCTION__, m_eglSurface, this); + qCDebug(lcQpaGl) << __FUNCTION__ << "Freeing EGL surface " << m_eglSurface << window(); eglDestroySurface(m_staticEglContext->display(), m_eglSurface); m_eglSurface = 0; } @@ -1033,14 +1017,14 @@ QWindow *QWindowsWindow::topLevelOf(QWindow *w) return w; } -QWindowsWindow::WindowData - QWindowsWindow::WindowData::create(const QWindow *w, - const WindowData ¶meters, +QWindowsWindowData + QWindowsWindowData::create(const QWindow *w, + const QWindowsWindowData ¶meters, const QString &title) { WindowCreationData creationData; creationData.fromWindow(w, parameters.flags); - WindowData result = creationData.create(w, parameters, title); + QWindowsWindowData result = creationData.create(w, parameters, title); // Force WM_NCCALCSIZE (with wParam=1) via SWP_FRAMECHANGED for custom margin. creationData.initialize(result.hwnd, !parameters.customMargins.isNull(), 1); return result; @@ -1048,8 +1032,7 @@ QWindowsWindow::WindowData void QWindowsWindow::setVisible(bool visible) { - if (QWindowsContext::verboseWindows) - qDebug() << __FUNCTION__ << this << window() << m_data.hwnd << visible; + qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() << m_data.hwnd << visible; if (m_data.hwnd) { if (visible) { show_sys(); @@ -1193,14 +1176,13 @@ 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); } } void QWindowsWindow::setParent(const QPlatformWindow *newParent) { - if (QWindowsContext::verboseWindows) - qDebug() << __FUNCTION__ << window() << newParent; + qCDebug(lcQpaWindows) << __FUNCTION__ << window() << newParent; if (m_data.hwnd) setParent_sys(newParent); @@ -1350,8 +1332,7 @@ void QWindowsWindow::handleGeometryChange() if (testFlag(SynchronousGeometryChangeEvent)) QWindowSystemInterface::flushWindowSystemEvents(); - if (QWindowsContext::verboseEvents || QWindowsContext::verboseWindows) - qDebug() << __FUNCTION__ << this << window() << m_data.geometry; + qCDebug(lcQpaEvents) << __FUNCTION__ << this << window() << m_data.geometry; } void QWindowsWindow::setGeometry_sys(const QRect &rect) const @@ -1359,17 +1340,15 @@ void QWindowsWindow::setGeometry_sys(const QRect &rect) const const QMargins margins = frameMargins(); const QRect frameGeometry = rect + margins; - if (QWindowsContext::verboseWindows) - qDebug() << '>' << __FUNCTION__ << this << window() + qCDebug(lcQpaWindows) << '>' << __FUNCTION__ << this << window() << " \n from " << geometry_sys() << " frame: " << margins << " to " <<rect << " new frame: " << frameGeometry; const bool rc = MoveWindow(m_data.hwnd, frameGeometry.x(), frameGeometry.y(), frameGeometry.width(), frameGeometry.height(), true); - if (QWindowsContext::verboseWindows) - qDebug() << '<' << __FUNCTION__ << this << window() - << " \n resulting " << rc << geometry_sys(); + qCDebug(lcQpaWindows) << '<' << __FUNCTION__ << this << window() + << " \n resulting " << rc << geometry_sys(); } QRect QWindowsWindow::frameGeometry_sys() const @@ -1442,8 +1421,7 @@ bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message, void QWindowsWindow::setWindowTitle(const QString &title) { - if (QWindowsContext::verboseWindows) - qDebug() << __FUNCTION__ << this << window() <<title; + qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() <<title; if (m_data.hwnd) { const QString fullTitle = formatWindowTitle(title, QStringLiteral(" - ")); SetWindowText(m_data.hwnd, (const wchar_t*)fullTitle.utf16()); @@ -1452,10 +1430,9 @@ void QWindowsWindow::setWindowTitle(const QString &title) void QWindowsWindow::setWindowFlags(Qt::WindowFlags flags) { - if (QWindowsContext::verboseWindows) - qDebug() << '>' << __FUNCTION__ << this << window() << "\n from: " - << QWindowsWindow::debugWindowFlags(m_data.flags) - << "\n to: " << QWindowsWindow::debugWindowFlags(flags); + qCDebug(lcQpaWindows) << '>' << __FUNCTION__ << this << window() << "\n from: " + << QWindowsWindow::debugWindowFlags(m_data.flags) + << "\n to: " << QWindowsWindow::debugWindowFlags(flags); const QRect oldGeometry = geometry(); if (m_data.flags != flags) { m_data.flags = flags; @@ -1470,13 +1447,12 @@ void QWindowsWindow::setWindowFlags(Qt::WindowFlags flags) if (oldGeometry != newGeometry) handleGeometryChange(); - if (QWindowsContext::verboseWindows) - qDebug() << '<' << __FUNCTION__ << "\n returns: " - << QWindowsWindow::debugWindowFlags(m_data.flags) - << " geometry " << oldGeometry << "->" << newGeometry; + qCDebug(lcQpaWindows) << '<' << __FUNCTION__ << "\n returns: " + << QWindowsWindow::debugWindowFlags(m_data.flags) + << " geometry " << oldGeometry << "->" << newGeometry; } -QWindowsWindow::WindowData QWindowsWindow::setWindowFlags_sys(Qt::WindowFlags wt, +QWindowsWindowData QWindowsWindow::setWindowFlags_sys(Qt::WindowFlags wt, unsigned flags) const { WindowCreationData creationData; @@ -1484,7 +1460,7 @@ QWindowsWindow::WindowData QWindowsWindow::setWindowFlags_sys(Qt::WindowFlags wt creationData.applyWindowFlags(m_data.hwnd); creationData.initialize(m_data.hwnd, true, m_opacity); - WindowData result = m_data; + QWindowsWindowData result = m_data; result.flags = creationData.flags; result.embedded = creationData.embedded; setFlag(FrameDirty); @@ -1493,8 +1469,7 @@ QWindowsWindow::WindowData QWindowsWindow::setWindowFlags_sys(Qt::WindowFlags wt void QWindowsWindow::handleWindowStateChange(Qt::WindowState state) { - if (QWindowsContext::verboseWindows) - qDebug() << __FUNCTION__ << this << window() + qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() << "\n from " << debugWindowStates(m_windowState) << " to " << debugWindowStates(state); setFlag(FrameDirty); @@ -1577,10 +1552,8 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) const Qt::WindowState oldState = m_windowState; if (oldState == newState) return; - if (QWindowsContext::verboseWindows) - qDebug() << '>' << __FUNCTION__ << this << window() - << " from " << debugWindowStates(oldState) - << " to " << debugWindowStates(newState); + qCDebug(lcQpaWindows) << '>' << __FUNCTION__ << this << window() + << " from " << debugWindowStates(oldState) << " to " << debugWindowStates(newState); const bool visible = isVisible(); @@ -1677,15 +1650,12 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) ShowWindow(m_data.hwnd, (newState == Qt::WindowMinimized) ? SW_MINIMIZE : (newState == Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNOACTIVATE); } - if (QWindowsContext::verboseWindows) - qDebug() << '<' << __FUNCTION__ << this << window() - << debugWindowStates(newState); + qCDebug(lcQpaWindows) << '<' << __FUNCTION__ << this << window() << debugWindowStates(newState); } void QWindowsWindow::setStyle(unsigned s) const { - if (QWindowsContext::verboseWindows) - qDebug() << __FUNCTION__ << this << window() << debugWinStyle(s); + qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() << debugWinStyle(s); setFlag(WithinSetStyle); setFlag(FrameDirty); SetWindowLongPtr(m_data.hwnd, GWL_STYLE, s); @@ -1694,8 +1664,7 @@ void QWindowsWindow::setStyle(unsigned s) const void QWindowsWindow::setExStyle(unsigned s) const { - if (QWindowsContext::verboseWindows) - qDebug().nospace() << __FUNCTION__ << ' ' << this << ' ' << window() + qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << ' ' << this << ' ' << window() << " 0x" << QByteArray::number(s, 16); setFlag(FrameDirty); SetWindowLongPtr(m_data.hwnd, GWL_EXSTYLE, s); @@ -1703,15 +1672,13 @@ void QWindowsWindow::setExStyle(unsigned s) const void QWindowsWindow::raise() { - if (QWindowsContext::verboseWindows) - qDebug() << __FUNCTION__ << this << window(); + qCDebug(lcQpaWindows) << __FUNCTION__ << this << window(); SetWindowPos(m_data.hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); } void QWindowsWindow::lower() { - if (QWindowsContext::verboseWindows) - qDebug() << __FUNCTION__ << this << window(); + qCDebug(lcQpaWindows) << __FUNCTION__ << this << window(); if (m_data.hwnd) SetWindowPos(m_data.hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); } @@ -1734,8 +1701,7 @@ void QWindowsWindow::windowEvent(QEvent *event) void QWindowsWindow::propagateSizeHints() { - if (QWindowsContext::verboseWindows) - qDebug() << __FUNCTION__ << this << window(); + qCDebug(lcQpaWindows) << __FUNCTION__ << this << window(); } QMargins QWindowsWindow::frameMargins() const @@ -1753,8 +1719,7 @@ QMargins QWindowsWindow::frameMargins() const void QWindowsWindow::setOpacity(qreal level) { - if (QWindowsContext::verboseWindows) - qDebug() << __FUNCTION__ << level; + qCDebug(lcQpaWindows) << __FUNCTION__ << level; if (m_opacity != level) { m_opacity = level; if (m_data.hwnd) @@ -1816,8 +1781,7 @@ void QWindowsWindow::setMask(const QRegion ®ion) void QWindowsWindow::requestActivateWindow() { - if (QWindowsContext::verboseWindows) - qDebug() << __FUNCTION__ << this << window(); + qCDebug(lcQpaWindows) << __FUNCTION__ << this << window(); // 'Active' state handling is based in focus since it needs to work for // child windows as well. if (m_data.hwnd) { @@ -1832,8 +1796,7 @@ bool QWindowsWindow::setKeyboardGrabEnabled(bool grab) qWarning("%s: No handle", __FUNCTION__); return false; } - if (QWindowsContext::verboseWindows) - qDebug() << __FUNCTION__ << this << window() << grab; + qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() << grab; QWindowsContext *context = QWindowsContext::instance(); if (grab) { @@ -1847,8 +1810,7 @@ bool QWindowsWindow::setKeyboardGrabEnabled(bool grab) bool QWindowsWindow::setMouseGrabEnabled(bool grab) { - if (QWindowsContext::verboseWindows) - qDebug() << __FUNCTION__ << window() << grab; + qCDebug(lcQpaWindows) << __FUNCTION__ << window() << grab; if (!m_data.hwnd) { qWarning("%s: No handle", __FUNCTION__); return false; @@ -1930,8 +1892,7 @@ void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const } } - if (QWindowsContext::verboseWindows) - qDebug() << __FUNCTION__ << window() << *mmi; + qCDebug(lcQpaWindows) << __FUNCTION__ << window() << *mmi; } bool QWindowsWindow::handleNonClientHitTest(const QPoint &globalPos, LRESULT *result) const @@ -2031,9 +1992,8 @@ void QWindowsWindow::setCursor(const QWindowsWindowCursor &c) #ifndef QT_NO_CURSOR if (c.handle() != m_cursor.handle()) { const bool apply = applyNewCursor(window()); - if (QWindowsContext::verboseWindows) - qDebug() << window() << __FUNCTION__ << "Shape=" << c.cursor().shape() - << " doApply=" << apply; + qCDebug(lcQpaWindows) <<window() << __FUNCTION__ + << "Shape=" << c.cursor().shape() << " doApply=" << apply; m_cursor = c; if (apply) applyCursor(); @@ -2131,9 +2091,7 @@ EGLSurface QWindowsWindow::ensureEglSurfaceHandle(const QWindowsWindow::QWindows Q_FUNC_INFO, window()->metaObject()->className(), qPrintable(window()->objectName()), eglGetError()); - if (QWindowsContext::verboseGL) - qDebug("%s: Created EGL surface %p, this = %p", - __FUNCTION__, m_eglSurface, this); + qCDebug(lcQpaGl) << __FUNCTION__<<"Created EGL surface "<< m_eglSurface <<window(); } return m_eglSurface; } @@ -2244,9 +2202,8 @@ void QWindowsWindow::setCustomMargins(const QMargins &newCustomMargins) QRect newFrame = currentFrameGeometry.marginsRemoved(oldCustomMargins) + m_data.customMargins; newFrame.moveTo(topLeft); setFlag(FrameDirty); - if (QWindowsContext::verboseWindows) - qDebug() << __FUNCTION__ << oldCustomMargins << "->" << newCustomMargins - << currentFrameGeometry << "->" << newFrame; + qCDebug(lcQpaWindows) << __FUNCTION__ << oldCustomMargins << "->" << newCustomMargins + << currentFrameGeometry << "->" << newFrame; SetWindowPos(m_data.hwnd, 0, newFrame.x(), newFrame.y(), newFrame.width(), newFrame.height(), SWP_NOZORDER | SWP_FRAMECHANGED); } } diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 61dc3e2dc2..3a9516e0e5 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -111,6 +111,22 @@ struct QWindowCreationContext int frameHeight; }; +struct QWindowsWindowData +{ + QWindowsWindowData() : hwnd(0), embedded(false) {} + + Qt::WindowFlags flags; + QRect geometry; + QMargins frame; // Do not use directly for windows, see FrameDirty. + QMargins customMargins; // User-defined, additional frame for NCCALCSIZE + HWND hwnd; + bool embedded; + + static QWindowsWindowData create(const QWindow *w, + const QWindowsWindowData ¶meters, + const QString &title); +}; + class QWindowsWindow : public QPlatformWindow { public: @@ -140,23 +156,7 @@ public: WithinMaximize = 0x40000 }; - struct WindowData - { - WindowData() : hwnd(0) {} - - Qt::WindowFlags flags; - QRect geometry; - QMargins frame; // Do not use directly for windows, see FrameDirty. - QMargins customMargins; // User-defined, additional frame for NCCALCSIZE - HWND hwnd; - bool embedded; - - static WindowData create(const QWindow *w, - const WindowData ¶meters, - const QString &title); - }; - - QWindowsWindow(QWindow *window, const WindowData &data); + QWindowsWindow(QWindow *window, const QWindowsWindowData &data); ~QWindowsWindow(); virtual QSurfaceFormat format() const { return m_format; } @@ -274,7 +274,7 @@ private: inline void setGeometry_sys(const QRect &rect) const; inline QRect frameGeometry_sys() const; inline QRect geometry_sys() const; - inline WindowData setWindowFlags_sys(Qt::WindowFlags wt, unsigned flags = 0) const; + inline QWindowsWindowData setWindowFlags_sys(Qt::WindowFlags wt, unsigned flags = 0) const; inline bool isFullScreen_sys() const; inline void setWindowState_sys(Qt::WindowState newState); inline void setParent_sys(const QPlatformWindow *parent) const; @@ -287,7 +287,7 @@ private: inline void destroyIcon(); void fireExpose(const QRegion ®ion, bool force=false); - mutable WindowData m_data; + mutable QWindowsWindowData m_data; mutable unsigned m_flags; HDC m_hdc; Qt::WindowState m_windowState; 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..5bbf73a945 --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -0,0 +1,1003 @@ +/**************************************************************************** +** +** 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.Applicationmodel.h> +#include <Windows.ApplicationModel.core.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::ApplicationModel; +using namespace ABI::Windows::ApplicationModel::Core; +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 IEventHandler<IInspectable*> ResumeHandler; +typedef IEventHandler<SuspendingEventArgs*> SuspendHandler; +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 + + + if (SUCCEEDED(RoGetActivationFactory(Wrappers::HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(), + IID_PPV_ARGS(&m_application)))) { + m_application->add_Suspending(Callback<SuspendHandler>(this, &QWinRTScreen::onSuspended).Get(), &m_suspendTokens[Qt::ApplicationSuspended]); + m_application->add_Resuming(Callback<ResumeHandler>(this, &QWinRTScreen::onResume).Get(), &m_suspendTokens[Qt::ApplicationHidden]); + } +} + +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::onSuspended(IInspectable *, ISuspendingEventArgs *) +{ + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationSuspended); + QWindowSystemInterface::flushWindowSystemEvents(); + return S_OK; +} + +HRESULT QWinRTScreen::onResume(IInspectable *, IInspectable *) +{ + // First the system invokes onResume and then changes + // the visibility of the screen to be active. + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationHidden); + 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..3131f879b5 --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrtscreen.h @@ -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$ +** +****************************************************************************/ + +#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 ApplicationModel { + struct ISuspendingEventArgs; + namespace Core { + struct ICoreApplication; + } + } + 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; + QHash<Qt::ApplicationState, EventRegistrationToken> m_suspendTokens; + + 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 onSuspended(IInspectable *, ABI::Windows::ApplicationModel::ISuspendingEventArgs *); + HRESULT onResume(IInspectable *, IInspectable *); + + 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; + ABI::Windows::ApplicationModel::Core::ICoreApplication *m_application; + 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..030090d98d 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()); } @@ -1163,6 +1154,7 @@ void QXcbConnection::processXcbEvents() xcb_generic_event_t *event = eventqueue->at(i); if (!event) continue; + QScopedPointer<xcb_generic_event_t, QScopedPointerPodDeleter> eventGuard(event); (*eventqueue)[i] = 0; uint response_type = event->response_type & ~0x80; @@ -1213,8 +1205,6 @@ void QXcbConnection::processXcbEvents() handleXcbEvent(event); m_reader->lock(); } - - free(event); } eventqueue->clear(); @@ -1450,6 +1440,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 +1725,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 +1750,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 a2ef8bf20f..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,14 +342,14 @@ XInput2DeviceData *QXcbConnection::deviceForId(int id) return dev; } -#if defined(XCB_USE_XINPUT22) || !defined(QT_NO_TABLETEVENT) +#if defined(XCB_USE_XINPUT21) || !defined(QT_NO_TABLETEVENT) static qreal fixed1616ToReal(FP1616 val) { return (qreal(val >> 16)) + (val & 0xFF) / (qreal)0xFF; } -#endif +#endif // defined(XCB_USE_XINPUT21) || !defined(QT_NO_TABLETEVENT) -#ifdef XCB_USE_XINPUT22 +#if defined(XCB_USE_XINPUT21) static qreal valuatorNormalized(double value, XIValuatorClassInfo *vci) { if (value > vci->max) @@ -303,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) { @@ -319,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); @@ -463,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/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp index 15e5bf27f1..ce9e445ba2 100644 --- a/src/plugins/platforms/xcb/qxcbcursor.cpp +++ b/src/plugins/platforms/xcb/qxcbcursor.cpp @@ -549,7 +549,7 @@ xcb_cursor_t QXcbCursor::createFontCursor(int cshape) void *dpy = connection()->xlib_display(); // special case for non-standard dnd-* cursors cursor = loadCursor(dpy, cshape); - if (!cursor && !m_gtkCursorThemeInitialized) { + if (!cursor && !m_gtkCursorThemeInitialized && m_screen->xSettings()->initialized()) { QByteArray gtkCursorTheme = m_screen->xSettings()->setting("Gtk/CursorThemeName").toByteArray(); m_screen->xSettings()->registerCallbackForProperty("Gtk/CursorThemeName",cursorThemePropertyChanged,this); if (updateCursorTheme(dpy,gtkCursorTheme)) { 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..0098f47e33 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 { @@ -390,16 +391,6 @@ void* QXcbSessionManager::handle() const return (void*) smcConnection; } -void QXcbSessionManager::setSessionId(const QString &id) -{ - m_sessionId = id; -} - -void QXcbSessionManager::setSessionKey(const QString &key) -{ - m_sessionKey = key; -} - bool QXcbSessionManager::allowsInteraction() { if (sm_interactionActive) @@ -495,16 +486,6 @@ void QXcbSessionManager::requestPhase2() sm_phase2 = true; } -void QXcbSessionManager::appCommitData() -{ - QPlatformSessionManager::appCommitData(); -} - -void QXcbSessionManager::appSaveState() -{ - QPlatformSessionManager::appSaveState(); -} - void QXcbSessionManager::exitEventLoop() { m_eventLoop->exit(); diff --git a/src/plugins/platforms/xcb/qxcbsessionmanager.h b/src/plugins/platforms/xcb/qxcbsessionmanager.h index 28eb287097..3c7c968890 100644 --- a/src/plugins/platforms/xcb/qxcbsessionmanager.h +++ b/src/plugins/platforms/xcb/qxcbsessionmanager.h @@ -66,8 +66,8 @@ public: void *handle() const; - void setSessionId(const QString &id); - void setSessionKey(const QString &key); + void setSessionId(const QString &id) { m_sessionId = id; } + void setSessionKey(const QString &key) { m_sessionKey = key; } bool allowsInteraction() Q_DECL_OVERRIDE; bool allowsErrorInteraction() Q_DECL_OVERRIDE; @@ -81,9 +81,6 @@ public: bool isPhase2() const Q_DECL_OVERRIDE; void requestPhase2() Q_DECL_OVERRIDE; - void appCommitData() Q_DECL_OVERRIDE; - void appSaveState() Q_DECL_OVERRIDE; - void exitEventLoop(); private: diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 3d8f91649a..3d79f742b3 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(); } @@ -1586,6 +1584,16 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t * QPlatformWindow::setGeometry(rect); QWindowSystemInterface::handleGeometryChange(window(), rect); + if (!m_screen->availableGeometry().intersects(rect)) { + Q_FOREACH (QPlatformScreen* screen, m_screen->virtualSiblings()) { + if (screen->availableGeometry().intersects(rect)) { + m_screen = static_cast<QXcbScreen*>(screen); + QWindowSystemInterface::handleWindowScreenChanged(window(), m_screen->QPlatformScreen::screen()); + break; + } + } + } + m_configureNotifyPending = false; if (m_deferredExpose) { @@ -1695,6 +1703,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 +1712,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 +1903,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/qxcbxsettings.cpp b/src/plugins/platforms/xcb/qxcbxsettings.cpp index 8679d502d9..141a6cc0cb 100644 --- a/src/plugins/platforms/xcb/qxcbxsettings.cpp +++ b/src/plugins/platforms/xcb/qxcbxsettings.cpp @@ -99,6 +99,7 @@ class QXcbXSettingsPrivate public: QXcbXSettingsPrivate(QXcbScreen *screen) : screen(screen) + , initialized(false) { } @@ -202,6 +203,7 @@ public: QXcbScreen *screen; xcb_window_t x_settings_window; QMap<QByteArray, QXcbXSettingsPropertyValue> settings; + bool initialized; }; @@ -217,7 +219,6 @@ QXcbXSettings::QXcbXSettings(QXcbScreen *screen) xcb_generic_error_t *error = 0; xcb_intern_atom_reply_t *atom_reply = xcb_intern_atom_reply(screen->xcb_connection(),atom_cookie,&error); if (error) { - qWarning() << Q_FUNC_INFO << "Failed to find XSETTINGS_S atom"; free(error); return; } @@ -230,7 +231,6 @@ QXcbXSettings::QXcbXSettings(QXcbScreen *screen) xcb_get_selection_owner_reply_t *selection_result = xcb_get_selection_owner_reply(screen->xcb_connection(), selection_cookie, &error); if (error) { - qWarning() << Q_FUNC_INFO << "Failed to get selection owner for XSETTINGS_S atom"; free(error); return; } @@ -246,6 +246,13 @@ QXcbXSettings::QXcbXSettings(QXcbScreen *screen) xcb_change_window_attributes(screen->xcb_connection(),d_ptr->x_settings_window,event,event_mask); d_ptr->populateSettings(d_ptr->getSettings()); + d_ptr->initialized = true; +} + +bool QXcbXSettings::initialized() const +{ + Q_D(const QXcbXSettings); + return d->initialized; } void QXcbXSettings::handlePropertyNotifyEvent(const xcb_property_notify_event_t *event) diff --git a/src/plugins/platforms/xcb/qxcbxsettings.h b/src/plugins/platforms/xcb/qxcbxsettings.h index 16fed862bc..f6a07a6091 100644 --- a/src/plugins/platforms/xcb/qxcbxsettings.h +++ b/src/plugins/platforms/xcb/qxcbxsettings.h @@ -53,6 +53,7 @@ class QXcbXSettings : public QXcbWindowEventListener Q_DECLARE_PRIVATE(QXcbXSettings) public: QXcbXSettings(QXcbScreen *screen); + bool initialized() const; QVariant setting(const QByteArray &property) const; 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 diff --git a/src/plugins/printsupport/cups/qcupsprintengine.cpp b/src/plugins/printsupport/cups/qcupsprintengine.cpp index 1c86420cb2..2fecdc00e9 100644 --- a/src/plugins/printsupport/cups/qcupsprintengine.cpp +++ b/src/plugins/printsupport/cups/qcupsprintengine.cpp @@ -221,7 +221,7 @@ void QCupsPrintEnginePrivate::closePrintDevice() if (copies > 1) options.append(QPair<QByteArray, QByteArray>("copies", QString::number(copies).toLocal8Bit())); - if (collate) + if (copies > 1 && collate) options.append(QPair<QByteArray, QByteArray>("Collate", "True")); switch (duplex) { |