diff options
Diffstat (limited to 'src/plugins/platforms')
94 files changed, 4040 insertions, 1143 deletions
diff --git a/src/plugins/platforms/android/android.pro b/src/plugins/platforms/android/android.pro index 243eea071a..32c37ab17a 100644 --- a/src/plugins/platforms/android/android.pro +++ b/src/plugins/platforms/android/android.pro @@ -21,7 +21,9 @@ CONFIG += qpa/genericunixfontdatabase OTHER_FILES += $$PWD/android.json -INCLUDEPATH += $$PWD +INCLUDEPATH += \ + $$PWD \ + $$QT_SOURCE_TREE/src/3rdparty/android SOURCES += $$PWD/androidplatformplugin.cpp \ $$PWD/androidjnimain.cpp \ @@ -48,7 +50,8 @@ SOURCES += $$PWD/androidplatformplugin.cpp \ $$PWD/qandroidplatformrasterwindow.cpp \ $$PWD/qandroidplatformbackingstore.cpp \ $$PWD/qandroidplatformopenglcontext.cpp \ - $$PWD/qandroidplatformforeignwindow.cpp + $$PWD/qandroidplatformforeignwindow.cpp \ + $$PWD/extract.cpp HEADERS += $$PWD/qandroidplatformintegration.h \ $$PWD/androidjnimain.h \ diff --git a/src/plugins/platforms/android/androidjniaccessibility.cpp b/src/plugins/platforms/android/androidjniaccessibility.cpp index 3f58597c9b..a7fec8748b 100644 --- a/src/plugins/platforms/android/androidjniaccessibility.cpp +++ b/src/plugins/platforms/android/androidjniaccessibility.cpp @@ -43,10 +43,12 @@ #include "androidjnimain.h" #include "qandroidplatformintegration.h" #include "qpa/qplatformaccessibility.h" +#include <QtPlatformSupport/private/qaccessiblebridgeutils_p.h> #include "qguiapplication.h" #include "qwindow.h" #include "qrect.h" #include "QtGui/qaccessible.h" +#include <QtCore/qmath.h> #include <QtCore/private/qjnihelpers_p.h> #include "qdebug.h" @@ -67,6 +69,7 @@ namespace QtAndroidAccessibility static jmethodID m_setEnabledMethodID = 0; static jmethodID m_setFocusableMethodID = 0; static jmethodID m_setFocusedMethodID = 0; + static jmethodID m_setScrollableMethodID = 0; static jmethodID m_setTextSelectionMethodID = 0; static jmethodID m_setVisibleToUserMethodID = 0; @@ -169,6 +172,18 @@ namespace QtAndroidAccessibility return false; } + static jboolean scrollForward(JNIEnv */*env*/, jobject /*thiz*/, jint objectId) + { + QAccessibleInterface *iface = interfaceFromId(objectId); + return QAccessibleBridgeUtils::performEffectiveAction(iface, QAccessibleActionInterface::increaseAction()); + } + + static jboolean scrollBackward(JNIEnv */*env*/, jobject /*thiz*/, jint objectId) + { + QAccessibleInterface *iface = interfaceFromId(objectId); + return QAccessibleBridgeUtils::performEffectiveAction(iface, QAccessibleActionInterface::decreaseAction()); + } + #define FIND_AND_CHECK_CLASS(CLASS_NAME) \ clazz = env->FindClass(CLASS_NAME); \ @@ -202,6 +217,11 @@ if (!clazz) { \ return false; } QAccessible::State state = iface->state(); + const QStringList actions = QAccessibleBridgeUtils::effectiveActionNames(iface); + const bool hasClickableAction = actions.contains(QAccessibleActionInterface::pressAction()) + || actions.contains(QAccessibleActionInterface::toggleAction()); + const bool hasIncreaseAction = actions.contains(QAccessibleActionInterface::increaseAction()); + const bool hasDecreaseAction = actions.contains(QAccessibleActionInterface::decreaseAction()); // try to fill in the text property, this is what the screen reader reads QString desc = iface->text(QAccessible::Value); @@ -219,21 +239,26 @@ if (!clazz) { \ } env->CallVoidMethod(node, m_setEnabledMethodID, !state.disabled); + env->CallVoidMethod(node, m_setCheckableMethodID, (bool)state.checkable); env->CallVoidMethod(node, m_setCheckedMethodID, (bool)state.checked); env->CallVoidMethod(node, m_setFocusableMethodID, (bool)state.focusable); env->CallVoidMethod(node, m_setFocusedMethodID, (bool)state.focused); - env->CallVoidMethod(node, m_setCheckableMethodID, (bool)state.checkable); env->CallVoidMethod(node, m_setVisibleToUserMethodID, !state.invisible); + env->CallVoidMethod(node, m_setScrollableMethodID, hasIncreaseAction || hasDecreaseAction); + env->CallVoidMethod(node, m_setClickableMethodID, hasClickableAction); + + // Add ACTION_CLICK + if (hasClickableAction) + env->CallVoidMethod(node, m_addActionMethodID, (int)16); // ACTION_CLICK defined in AccessibilityNodeInfo + + // Add ACTION_SCROLL_FORWARD + if (hasIncreaseAction) + env->CallVoidMethod(node, m_addActionMethodID, (int)4096); // ACTION_SCROLL_FORWARD defined in AccessibilityNodeInfo + + // Add ACTION_SCROLL_BACKWARD + if (hasDecreaseAction) + env->CallVoidMethod(node, m_addActionMethodID, (int)8192); // ACTION_SCROLL_BACKWARD defined in AccessibilityNodeInfo - if (iface->actionInterface()) { - QStringList actions = iface->actionInterface()->actionNames(); - bool clickable = actions.contains(QAccessibleActionInterface::pressAction()); - bool toggle = actions.contains(QAccessibleActionInterface::toggleAction()); - if (clickable || toggle) { - env->CallVoidMethod(node, m_setClickableMethodID, (bool)clickable); - env->CallVoidMethod(node, m_addActionMethodID, (int)16); // ACTION_CLICK defined in AccessibilityNodeInfo - } - } jstring jdesc = env->NewString((jchar*) desc.constData(), (jsize) desc.size()); //CALL_METHOD(node, "setText", "(Ljava/lang/CharSequence;)V", jdesc) @@ -251,6 +276,8 @@ if (!clazz) { \ {"hitTest", "(FF)I", (void*)hitTest}, {"populateNode", "(ILandroid/view/accessibility/AccessibilityNodeInfo;)Z", (void*)populateNode}, {"clickAction", "(I)Z", (void*)clickAction}, + {"scrollForward", "(I)Z", (void*)scrollForward}, + {"scrollBackward", "(I)Z", (void*)scrollBackward}, }; #define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \ @@ -283,6 +310,7 @@ if (!clazz) { \ GET_AND_CHECK_STATIC_METHOD(m_setEnabledMethodID, nodeInfoClass, "setEnabled", "(Z)V"); GET_AND_CHECK_STATIC_METHOD(m_setFocusableMethodID, nodeInfoClass, "setFocusable", "(Z)V"); GET_AND_CHECK_STATIC_METHOD(m_setFocusedMethodID, nodeInfoClass, "setFocused", "(Z)V"); + GET_AND_CHECK_STATIC_METHOD(m_setScrollableMethodID, nodeInfoClass, "setScrollable", "(Z)V"); GET_AND_CHECK_STATIC_METHOD(m_setVisibleToUserMethodID, nodeInfoClass, "setVisibleToUser", "(Z)V"); if (QtAndroidPrivate::androidSdkVersion() >= 18) { diff --git a/src/plugins/platforms/android/extract.cpp b/src/plugins/platforms/android/extract.cpp new file mode 100644 index 0000000000..82687e61a7 --- /dev/null +++ b/src/plugins/platforms/android/extract.cpp @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** 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. +** +** $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 <jni.h> +#include <android/log.h> +#include <extract.h> +#include <alloca.h> + +#define LOG_TAG "extractSyleInfo" +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) +#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,LOG_TAG,__VA_ARGS__) + +extern "C" JNIEXPORT jintArray JNICALL Java_org_qtproject_qt5_android_ExtractStyle_extractNativeChunkInfo(JNIEnv * env, jobject, Res_png_9patch* chunk) +{ + Res_png_9patch::deserialize(chunk); + //printChunkInformation(chunk); + jintArray result; + size_t size = 3+chunk->numXDivs+chunk->numYDivs+chunk->numColors; + result = env->NewIntArray(size); + if (!result) + return 0; + + jint *data = (jint*)malloc(sizeof(jint)*size); + size_t pos = 0; + data[pos++]=chunk->numXDivs; + data[pos++]=chunk->numYDivs; + data[pos++]=chunk->numColors; + for (int x = 0; x <chunk->numXDivs; x ++) + data[pos++]=chunk->xDivs[x]; + for (int y = 0; y <chunk->numYDivs; y ++) + data[pos++]=chunk->yDivs[y]; + for (int c = 0; c <chunk->numColors; c ++) + data[pos++]=chunk->colors[c]; + env->SetIntArrayRegion(result, 0, size, data); + free(data); + return result; +} + +extern "C" JNIEXPORT jintArray JNICALL Java_org_qtproject_qt5_android_ExtractStyle_extractChunkInfo(JNIEnv * env, jobject obj, jbyteArray chunkObj) +{ + size_t chunkSize = env->GetArrayLength(chunkObj); + void* storage = alloca(chunkSize); + env->GetByteArrayRegion(chunkObj, 0, chunkSize, + reinterpret_cast<jbyte*>(storage)); + + if (!env->ExceptionCheck()) + return Java_org_qtproject_qt5_android_ExtractStyle_extractNativeChunkInfo(env, obj, static_cast<Res_png_9patch*>(storage)); + else + env->ExceptionClear(); + return 0; +} + +// The following part was shamelessly stolen from ResourceTypes.cpp from Android's sources +/* + * Copyright (C) 2005 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +static void deserializeInternal(const void* inData, Res_png_9patch* outData) { + char* patch = (char*) inData; + if (inData != outData) { + memmove(&outData->wasDeserialized, patch, 4); // copy wasDeserialized, numXDivs, numYDivs, numColors + memmove(&outData->paddingLeft, patch + 12, 4); // copy wasDeserialized, numXDivs, numYDivs, numColors + } + outData->wasDeserialized = true; + char* data = (char*)outData; + data += sizeof(Res_png_9patch); + outData->xDivs = (int32_t*) data; + data += outData->numXDivs * sizeof(int32_t); + outData->yDivs = (int32_t*) data; + data += outData->numYDivs * sizeof(int32_t); + outData->colors = (uint32_t*) data; +} + +Res_png_9patch* Res_png_9patch::deserialize(const void* inData) +{ + if (sizeof(void*) != sizeof(int32_t)) { + LOGE("Cannot deserialize on non 32-bit system\n"); + return NULL; + } + deserializeInternal(inData, (Res_png_9patch*) inData); + return (Res_png_9patch*) inData; +} diff --git a/src/plugins/platforms/android/qandroidplatformbackingstore.h b/src/plugins/platforms/android/qandroidplatformbackingstore.h index 4c24e129c3..c51ebe879d 100644 --- a/src/plugins/platforms/android/qandroidplatformbackingstore.h +++ b/src/plugins/platforms/android/qandroidplatformbackingstore.h @@ -55,7 +55,7 @@ public: 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; } + QImage toImage() const { return m_image; } void setBackingStore(QWindow *window); protected: QImage m_image; diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp index 714a670134..af184cde02 100644 --- a/src/plugins/platforms/android/qandroidplatformscreen.cpp +++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp @@ -332,7 +332,7 @@ void QAndroidPlatformScreen::doRedraw() QRect windowRect = targetRect.translated(-window->geometry().topLeft()); QAndroidPlatformBackingStore *backingStore = static_cast<QAndroidPlatformRasterWindow *>(window)->backingStore(); if (backingStore) - compositePainter.drawImage(targetRect.topLeft(), backingStore->image(), windowRect); + compositePainter.drawImage(targetRect.topLeft(), backingStore->toImage(), windowRect); } } diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro index 1f9c0e051d..ad6cb3a1fc 100644 --- a/src/plugins/platforms/cocoa/cocoa.pro +++ b/src/plugins/platforms/cocoa/cocoa.pro @@ -14,7 +14,6 @@ OBJECTIVE_SOURCES += main.mm \ qnsviewaccessibility.mm \ qcocoaautoreleasepool.mm \ qnswindowdelegate.mm \ - qcocoaglcontext.mm \ qcocoanativeinterface.mm \ qcocoaeventdispatcher.mm \ qcocoaapplicationdelegate.mm \ @@ -51,7 +50,6 @@ HEADERS += qcocoaintegration.h \ qnsview.h \ qcocoaautoreleasepool.h \ qnswindowdelegate.h \ - qcocoaglcontext.h \ qcocoanativeinterface.h \ qcocoaeventdispatcher.h \ qcocoaapplicationdelegate.h \ @@ -80,6 +78,12 @@ HEADERS += qcocoaintegration.h \ messages.h \ qcocoamimetypes.h +contains(QT_CONFIG, opengl.*) { + OBJECTIVE_SOURCES += qcocoaglcontext.mm + + HEADERS += qcocoaglcontext.h +} + RESOURCES += qcocoaresources.qrc LIBS += -framework Cocoa -framework Carbon -framework IOKit -lcups diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm index 72045a1bbb..ca660488b9 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm @@ -55,7 +55,7 @@ QCocoaAccessibility::~QCocoaAccessibility() void QCocoaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event) { - QCocoaAccessibleElement *element = [QCocoaAccessibleElement elementWithId: event->uniqueId()]; + QMacAccessibilityElement *element = [QMacAccessibilityElement elementWithId: event->uniqueId()]; if (!element) { qWarning() << "QCocoaAccessibility::notifyAccessibilityUpdate: invalid element"; return; @@ -244,7 +244,7 @@ NSArray *unignoredChildren(QAccessibleInterface *interface) QAccessible::Id childId = QAccessible::uniqueId(child); //qDebug() << " kid: " << childId << child; - QCocoaAccessibleElement *element = [QCocoaAccessibleElement elementWithId: childId]; + QMacAccessibilityElement *element = [QMacAccessibilityElement elementWithId: childId]; if (element) [kids addObject: element]; else diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h index 9760f492ea..4a5baefbc5 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h @@ -50,18 +50,18 @@ #import <qaccessible.h> -@class QT_MANGLE_NAMESPACE(QCocoaAccessibleElement); +@class QT_MANGLE_NAMESPACE(QMacAccessibilityElement); -@interface QT_MANGLE_NAMESPACE(QCocoaAccessibleElement) : NSObject { +@interface QT_MANGLE_NAMESPACE(QMacAccessibilityElement) : NSObject { NSString *role; QAccessible::Id axid; } - (id)initWithId:(QAccessible::Id)anId; -+ (QT_MANGLE_NAMESPACE(QCocoaAccessibleElement) *)elementWithId:(QAccessible::Id)anId; ++ (QT_MANGLE_NAMESPACE(QMacAccessibilityElement) *)elementWithId:(QAccessible::Id)anId; @end -QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaAccessibleElement); +QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement); #endif diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm index 078dc67cad..9f803e411d 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm @@ -43,12 +43,12 @@ #include "qcocoahelpers.h" #include "qcocoawindow.h" #include "private/qaccessiblecache_p.h" - +#include <QtPlatformSupport/private/qaccessiblebridgeutils_p.h> #include <QtGui/qaccessible.h> #import <AppKit/NSAccessibility.h> -@implementation QCocoaAccessibleElement +@implementation QMacAccessibilityElement - (id)initWithId:(QAccessible::Id)anId { @@ -72,7 +72,7 @@ QAccessibleCache *cache = QAccessibleCache::instance(); - QCocoaAccessibleElement *element = cache->elementForId(anId); + QMacAccessibilityElement *element = cache->elementForId(anId); if (!element) { QAccessibleInterface *iface = QAccessible::accessibleInterface(anId); Q_ASSERT(iface); @@ -95,8 +95,8 @@ } - (BOOL)isEqual:(id)object { - if ([object isKindOfClass:[QCocoaAccessibleElement class]]) { - QCocoaAccessibleElement *other = object; + if ([object isKindOfClass:[QMacAccessibilityElement class]]) { + QMacAccessibilityElement *other = object; return other->axid == axid; } else { return NO; @@ -196,7 +196,7 @@ } QAccessible::Id parentId = QAccessible::uniqueId(parent); - return [QCocoaAccessibleElement elementWithId: parentId]; + return [QMacAccessibilityElement elementWithId: parentId]; } @@ -345,7 +345,7 @@ } if ([attribute isEqualToString: NSAccessibilityLineForIndexParameterizedAttribute]) { int index = [parameter intValue]; - NSNumber *ln = [QCocoaAccessibleElement lineNumberForIndex: index forText: iface->text(QAccessible::Value)]; + NSNumber *ln = [QMacAccessibilityElement lineNumberForIndex: index forText: iface->text(QAccessible::Value)]; return ln; } if ([attribute isEqualToString: NSAccessibilityRangeForLineParameterizedAttribute]) { @@ -430,15 +430,11 @@ if (!iface) return nsActions; - QAccessibleActionInterface *actionInterface = iface->actionInterface(); - if (actionInterface) { - QStringList supportedActionNames = actionInterface->actionNames(); - - foreach (const QString &qtAction, supportedActionNames) { - NSString *nsAction = QCocoaAccessible::getTranslatedAction(qtAction); - if (nsAction) - [nsActions addObject : nsAction]; - } + const QStringList &supportedActionNames = QAccessibleBridgeUtils::effectiveActionNames(iface); + foreach (const QString &qtAction, supportedActionNames) { + NSString *nsAction = QCocoaAccessible::getTranslatedAction(qtAction); + if (nsAction) + [nsActions addObject : nsAction]; } return nsActions; @@ -448,27 +444,25 @@ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); if (!iface) return nil; // FIXME is that the right return type?? - QAccessibleActionInterface *actionInterface = iface->actionInterface(); - if (actionInterface) { - QString qtAction = QCocoaAccessible::translateAction(action); - - // Return a description from the action interface if this action is not known to the OS. - if (qtAction.isEmpty()) { - QString description = actionInterface->localizedActionDescription(qtAction); - return QCFString::toNSString(description); + QString qtAction = QCocoaAccessible::translateAction(action); + QString description; + // Return a description from the action interface if this action is not known to the OS. + if (qtAction.isEmpty()) { + if (QAccessibleActionInterface *actionInterface = iface->actionInterface()) { + qtAction = QString::fromNSString((NSString *)action); + description = actionInterface->localizedActionDescription(qtAction); } + } else { + description = qAccessibleLocalizedActionDescription(qtAction); } - - return NSAccessibilityActionDescription(action); + return QCFString::toNSString(description); } - (void)accessibilityPerformAction:(NSString *)action { QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); if (iface) { - QAccessibleActionInterface *actionInterface = iface->actionInterface(); - if (actionInterface) { - actionInterface->doAction(QCocoaAccessible::translateAction(action)); - } + const QString qtAction = QCocoaAccessible::translateAction(action); + QAccessibleBridgeUtils::performEffectiveAction(iface, qtAction); } } @@ -504,7 +498,7 @@ QAccessible::Id childId = QAccessible::uniqueId(childInterface); // hit a child, forward to child accessible interface. - QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement elementWithId:childId]; + QMacAccessibilityElement *accessibleElement = [QMacAccessibilityElement elementWithId:childId]; if (accessibleElement) return NSAccessibilityUnignoredAncestor(accessibleElement); return NSAccessibilityUnignoredAncestor(self); @@ -521,7 +515,7 @@ QAccessibleInterface *childInterface = iface->focusChild(); if (childInterface) { QAccessible::Id childAxid = QAccessible::uniqueId(childInterface); - QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement elementWithId:childAxid]; + QMacAccessibilityElement *accessibleElement = [QMacAccessibilityElement elementWithId:childAxid]; return NSAccessibilityUnignoredAncestor(accessibleElement); } diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm index 92358ecc74..efe3269d42 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm +++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm @@ -340,6 +340,7 @@ static void cleanupCocoaApplicationDelegate() && [reflectionDelegate respondsToSelector:@selector(applicationDidBecomeActive:)]) [reflectionDelegate applicationDidBecomeActive:notification]; + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive); /* onApplicationChangedActivation(true); @@ -363,6 +364,7 @@ static void cleanupCocoaApplicationDelegate() && [reflectionDelegate respondsToSelector:@selector(applicationDidResignActive:)]) [reflectionDelegate applicationDidResignActive:notification]; + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive); /* onApplicationChangedActivation(false); @@ -374,6 +376,26 @@ static void cleanupCocoaApplicationDelegate() */ } +- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag +{ + Q_UNUSED(theApplication); + Q_UNUSED(flag); + if (reflectionDelegate + && [reflectionDelegate respondsToSelector:@selector(applicationShouldHandleReopen:hasVisibleWindows:)]) + return [reflectionDelegate applicationShouldHandleReopen:theApplication hasVisibleWindows:flag]; + + /* + true to force delivery of the event even if the application state is already active, + because rapp (handle reopen) events are sent each time the dock icon is clicked regardless + of the active state of the application or number of visible windows. For example, a browser + app that has no windows opened would need the event be to delivered even if it was already + active in order to create a new window as per OS X conventions. + */ + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive, true /*forcePropagate*/); + + return NO; +} + - (void)setReflectionDelegate:(NSObject <NSApplicationDelegate> *)oldDelegate { [oldDelegate retain]; diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h index a33373c4c1..8a4e2e68df 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.h +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h @@ -59,7 +59,9 @@ public: QPaintDevice *paintDevice(); void flush(QWindow *widget, const QRegion ®ion, const QPoint &offset); +#ifndef QT_NO_OPENGL QImage toImage() const Q_DECL_OVERRIDE; +#endif void resize (const QSize &size, const QRegion &); bool scroll(const QRegion &area, int dx, int dy); CGImageRef getBackingStoreCGImage(); diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm index d76645c668..e13e295511 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm @@ -96,10 +96,12 @@ void QCocoaBackingStore::flush(QWindow *win, const QRegion ®ion, const QPoint } } +#ifndef QT_NO_OPENGL QImage QCocoaBackingStore::toImage() const { return m_qImage; } +#endif void QCocoaBackingStore::resize(const QSize &size, const QRegion &) { diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.h b/src/plugins/platforms/cocoa/qcocoaglcontext.h index 30f1cdc278..2aa22ea759 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.h +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.h @@ -55,7 +55,7 @@ QT_BEGIN_NAMESPACE class QCocoaGLContext : public QPlatformOpenGLContext { public: - QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share); + QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, const QVariant &nativeHandle); ~QCocoaGLContext(); QSurfaceFormat format() const; @@ -77,6 +77,8 @@ public: void windowWasHidden(); + QVariant nativeHandle() const; + private: void setActiveWindow(QWindow *window); void updateSurfaceFormat(); diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm index 3f61bd81ee..7b70fbb4bb 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -46,6 +46,7 @@ #include <qdebug.h> #include <QtCore/private/qcore_mac_p.h> #include <QtPlatformSupport/private/cglconvenience_p.h> +#include <QtPlatformHeaders/qcocoanativecontext.h> #import <Cocoa/Cocoa.h> @@ -117,11 +118,33 @@ static void updateFormatFromContext(QSurfaceFormat *format) format->setProfile(QSurfaceFormat::CompatibilityProfile); } -QCocoaGLContext::QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share) +QCocoaGLContext::QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, + const QVariant &nativeHandle) : m_context(nil), m_shareContext(nil), m_format(format) { + if (!nativeHandle.isNull()) { + if (!nativeHandle.canConvert<QCocoaNativeContext>()) { + qWarning("QCocoaGLContext: Requires a QCocoaNativeContext"); + return; + } + QCocoaNativeContext handle = nativeHandle.value<QCocoaNativeContext>(); + NSOpenGLContext *context = handle.context(); + if (!context) { + qWarning("QCocoaGLContext: No NSOpenGLContext given"); + return; + } + m_context = context; + [m_context retain]; + m_shareContext = share ? static_cast<QCocoaGLContext *>(share)->nsOpenGLContext() : nil; + // OpenGL surfaces can be ordered either above(default) or below the NSWindow. + const GLint order = qt_mac_resolveOption(1, "QT_MAC_OPENGL_SURFACE_ORDER"); + [m_context setValues:&order forParameter:NSOpenGLCPSurfaceOrder]; + updateSurfaceFormat(); + return; + } + // we only support OpenGL contexts under Cocoa if (m_format.renderableType() == QSurfaceFormat::DefaultRenderableType) m_format.setRenderableType(QSurfaceFormat::OpenGL); @@ -168,6 +191,11 @@ QCocoaGLContext::~QCocoaGLContext() [m_context release]; } +QVariant QCocoaGLContext::nativeHandle() const +{ + return QVariant::fromValue<QCocoaNativeContext>(QCocoaNativeContext(m_context)); +} + // Match up with createNSOpenGLPixelFormat! QSurfaceFormat QCocoaGLContext::format() const { diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h index 3b72184d83..d692a179fd 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.h +++ b/src/plugins/platforms/cocoa/qcocoahelpers.h @@ -80,6 +80,7 @@ NSRect qt_mac_toNSRect(const QRect &rect); QRect qt_mac_toQRect(const NSRect &rect); QColor qt_mac_toQColor(const NSColor *color); +QColor qt_mac_toQColor(CGColorRef color); // Creates a mutable shape, it's the caller's responsibility to release. diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm index 9850f83dea..526204a414 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.mm +++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm @@ -225,6 +225,24 @@ QColor qt_mac_toQColor(const NSColor *color) return qtColor; } +QColor qt_mac_toQColor(CGColorRef color) +{ + QColor qtColor; + CGColorSpaceModel model = CGColorSpaceGetModel(CGColorGetColorSpace(color)); + const CGFloat *components = CGColorGetComponents(color); + if (model == kCGColorSpaceModelRGB) { + qtColor.setRgbF(components[0], components[1], components[2], components[3]); + } else if (model == kCGColorSpaceModelCMYK) { + qtColor.setCmykF(components[0], components[1], components[2], components[3]); + } else if (model == kCGColorSpaceModelMonochrome) { + qtColor.setRgbF(components[0], components[0], components[0], components[1]); + } else { + // Colorspace we can't deal with. + qWarning("Qt: qt_mac_toQColor: cannot convert from colorspace model: %d", model); + Q_ASSERT(false); + } + return qtColor; +} // Use this method to keep all the information in the TextSegment. As long as it is ordered // we are in OK shape, and we can influence that ourselves. diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h index 07b73c1a7a..5ca2ccc571 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.h +++ b/src/plugins/platforms/cocoa/qcocoaintegration.h @@ -113,7 +113,9 @@ public: bool hasCapability(QPlatformIntegration::Capability cap) const; QPlatformWindow *createPlatformWindow(QWindow *window) const; +#ifndef QT_NO_OPENGL QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; +#endif QPlatformBackingStore *createPlatformBackingStore(QWindow *widget) const; QAbstractEventDispatcher *createEventDispatcher() const; diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index fca7fa042c..4be49ed68f 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -420,30 +420,37 @@ bool QCocoaIntegration::hasCapability(QPlatformIntegration::Capability cap) cons { switch (cap) { case ThreadedPixmaps: +#ifndef QT_NO_OPENGL case OpenGL: case ThreadedOpenGL: case BufferQueueingOpenGL: +#endif case WindowMasks: case MultipleWindows: case ForeignWindows: case RasterGLSurface: + case ApplicationState: return true; default: return QPlatformIntegration::hasCapability(cap); } } - - QPlatformWindow *QCocoaIntegration::createPlatformWindow(QWindow *window) const { return new QCocoaWindow(window); } +#ifndef QT_NO_OPENGL QPlatformOpenGLContext *QCocoaIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { - return new QCocoaGLContext(context->format(), context->shareHandle()); + QCocoaGLContext *glContext = new QCocoaGLContext(context->format(), + context->shareHandle(), + context->nativeHandle()); + context->setNativeHandle(glContext->nativeHandle()); + return glContext; } +#endif QPlatformBackingStore *QCocoaIntegration::createPlatformBackingStore(QWindow *window) const { diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.h b/src/plugins/platforms/cocoa/qcocoanativeinterface.h index 54e45a1d99..da60afd4e7 100644 --- a/src/plugins/platforms/cocoa/qcocoanativeinterface.h +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.h @@ -61,15 +61,19 @@ class QCocoaNativeInterface : public QPlatformNativeInterface public: QCocoaNativeInterface(); +#ifndef QT_NO_OPENGL void *nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context); +#endif void *nativeResourceForWindow(const QByteArray &resourceString, QWindow *window); NativeResourceForIntegrationFunction nativeResourceFunctionForIntegration(const QByteArray &resource) Q_DECL_OVERRIDE; Q_INVOKABLE void beep(); +#ifndef QT_NO_OPENGL static void *cglContextForContext(QOpenGLContext *context); static void *nsOpenGLContextForContext(QOpenGLContext* context); +#endif public Q_SLOTS: void onAppFocusWindowChanged(QWindow *window); diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm index e09c31231d..7b314665de 100644 --- a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm @@ -40,7 +40,6 @@ ****************************************************************************/ #include "qcocoanativeinterface.h" -#include "qcocoaglcontext.h" #include "qcocoawindow.h" #include "qcocoamenu.h" #include "qcocoamenubar.h" @@ -53,8 +52,11 @@ #include <qpixmap.h> #include <qpa/qplatformwindow.h> #include "qsurfaceformat.h" +#ifndef QT_NO_OPENGL #include <qpa/qplatformopenglcontext.h> #include "qopenglcontext.h" +#include "qcocoaglcontext.h" +#endif #include "qguiapplication.h" #include <qdebug.h> @@ -72,6 +74,7 @@ QCocoaNativeInterface::QCocoaNativeInterface() { } +#ifndef QT_NO_OPENGL void *QCocoaNativeInterface::nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context) { if (!context) @@ -83,16 +86,19 @@ void *QCocoaNativeInterface::nativeResourceForContext(const QByteArray &resource return 0; } +#endif void *QCocoaNativeInterface::nativeResourceForWindow(const QByteArray &resourceString, QWindow *window) { if (!window->handle()) return 0; - if (resourceString == "nsopenglcontext") { - return static_cast<QCocoaWindow *>(window->handle())->currentContext()->nsOpenGLContext(); - } else if (resourceString == "nsview") { + if (resourceString == "nsview") { return static_cast<QCocoaWindow *>(window->handle())->m_contentView; +#ifndef QT_NO_OPENGL + } else if (resourceString == "nsopenglcontext") { + return static_cast<QCocoaWindow *>(window->handle())->currentContext()->nsOpenGLContext(); +#endif } else if (resourceString == "nswindow") { return static_cast<QCocoaWindow *>(window->handle())->m_nsWindow; } @@ -198,6 +204,7 @@ void QCocoaNativeInterface::onAppFocusWindowChanged(QWindow *window) QCocoaMenuBar::updateMenuBarImmediately(); } +#ifndef QT_NO_OPENGL void *QCocoaNativeInterface::cglContextForContext(QOpenGLContext* context) { NSOpenGLContext *nsOpenGLContext = static_cast<NSOpenGLContext*>(nsOpenGLContextForContext(context)); @@ -216,6 +223,7 @@ void *QCocoaNativeInterface::nsOpenGLContextForContext(QOpenGLContext* context) } return 0; } +#endif void QCocoaNativeInterface::addToMimeList(void *macPasteboardMime) { diff --git a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm index f18be8b69c..26aa871998 100644 --- a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm +++ b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm @@ -41,6 +41,8 @@ #include "qcocoasystemsettings.h" +#include "qcocoahelpers.h" + #include <QtCore/private/qcore_mac_p.h> #include <QtGui/qfont.h> @@ -48,30 +50,11 @@ QT_BEGIN_NAMESPACE -QColor qt_mac_colorFromCGColor(CGColorRef cgcolor) -{ - QColor pc; - CGColorSpaceModel model = CGColorSpaceGetModel(CGColorGetColorSpace(cgcolor)); - const CGFloat *components = CGColorGetComponents(cgcolor); - if (model == kCGColorSpaceModelRGB) { - pc.setRgbF(components[0], components[1], components[2], components[3]); - } else if (model == kCGColorSpaceModelCMYK) { - pc.setCmykF(components[0], components[1], components[2], components[3]); - } else if (model == kCGColorSpaceModelMonochrome) { - pc.setRgbF(components[0], components[0], components[0], components[1]); - } else { - // Colorspace we can't deal with. - qWarning("Qt: qcolorFromCGColor: cannot convert from colorspace model: %d", model); - Q_ASSERT(false); - } - return pc; -} - QColor qt_mac_colorForTheme(ThemeBrush brush) { QCFType<CGColorRef> cgClr = 0; HIThemeBrushCreateCGColor(brush, &cgClr); - return qt_mac_colorFromCGColor(cgClr); + return qt_mac_toQColor(cgClr); } QColor qt_mac_colorForThemeTextColor(ThemeTextColor themeColor) diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index 7a21f7a8d3..8f885ab5f3 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -47,7 +47,9 @@ #include <qpa/qplatformwindow.h> #include <QRect> +#ifndef QT_NO_OPENGL #include "qcocoaglcontext.h" +#endif #include "qnsview.h" #include "qt_mac_p.h" @@ -201,8 +203,10 @@ public: void setWindowShadow(Qt::WindowFlags flags); void setWindowZoomButton(Qt::WindowFlags flags); +#ifndef QT_NO_OPENGL void setCurrentContext(QCocoaGLContext *context); QCocoaGLContext *currentContext() const; +#endif bool setWindowModified(bool modified) Q_DECL_OVERRIDE; @@ -272,7 +276,9 @@ public: // for QNSView bool m_inConstructor; bool m_inSetVisible; +#ifndef QT_NO_OPENGL QCocoaGLContext *m_glContext; +#endif QCocoaMenuBar *m_menubar; NSCursor *m_windowCursor; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 4d0458a4aa..29b983cd89 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -43,7 +43,9 @@ #include "qnswindowdelegate.h" #include "qcocoaautoreleasepool.h" #include "qcocoaeventdispatcher.h" +#ifndef QT_NO_OPENGL #include "qcocoaglcontext.h" +#endif #include "qcocoahelpers.h" #include "qcocoanativeinterface.h" #include "qnsview.h" @@ -373,7 +375,9 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw) , m_windowUnderMouse(false) , m_inConstructor(true) , m_inSetVisible(false) +#ifndef QT_NO_OPENGL , m_glContext(0) +#endif , m_menubar(0) , m_windowCursor(0) , m_hasModalSession(false) @@ -712,8 +716,10 @@ void QCocoaWindow::setVisible(bool visible) [m_contentView setHidden:NO]; } else { // qDebug() << "close" << this; +#ifndef QT_NO_OPENGL if (m_glContext) m_glContext->windowWasHidden(); +#endif QCocoaEventDispatcher *cocoaEventDispatcher = qobject_cast<QCocoaEventDispatcher *>(QGuiApplication::instance()->eventDispatcher()); QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = 0; if (cocoaEventDispatcher) @@ -1224,6 +1230,7 @@ bool QCocoaWindow::windowIsPopupType(Qt::WindowType type) const return ((type & Qt::Popup) == Qt::Popup); } +#ifndef QT_NO_OPENGL void QCocoaWindow::setCurrentContext(QCocoaGLContext *context) { m_glContext = context; @@ -1233,6 +1240,7 @@ QCocoaGLContext *QCocoaWindow::currentContext() const { return m_glContext; } +#endif void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) { diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h index 5387f2a825..a75e366a73 100644 --- a/src/plugins/platforms/cocoa/qnsview.h +++ b/src/plugins/platforms/cocoa/qnsview.h @@ -72,15 +72,19 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QNSViewMouseMoveHelper); bool m_sendUpAsRightButton; Qt::KeyboardModifiers currentWheelModifiers; bool m_subscribesForGlobalFrameNotifications; +#ifndef QT_NO_OPENGL QCocoaGLContext *m_glContext; bool m_shouldSetGLContextinDrawRect; +#endif NSString *m_inputSource; QNSViewMouseMoveHelper *m_mouseMoveHelper; } - (id)init; - (id)initWithQWindow:(QWindow *)window platformWindow:(QCocoaWindow *) platformWindow; +#ifndef QT_NO_OPENGL - (void)setQCocoaGLContext:(QCocoaGLContext *)context; +#endif - (void)flushBackingStore:(QCocoaBackingStore *)backingStore region:(const QRegion &)region offset:(QPoint)offset; - (void)setMaskRegion:(const QRegion *)region; - (void)invalidateWindowShadowIfNeeded; diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index a18ee7ff71..cc8fe51e0f 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -57,7 +57,9 @@ #include <QtCore/QDebug> #include <private/qguiapplication_p.h> #include "qcocoabackingstore.h" +#ifndef QT_NO_OPENGL #include "qcocoaglcontext.h" +#endif #include "qcocoaintegration.h" #ifdef QT_COCOA_ENABLE_ACCESSIBILITY_INSPECTOR @@ -143,8 +145,10 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; m_frameStrutButtons = Qt::NoButton; m_sendKeyEvent = false; m_subscribesForGlobalFrameNotifications = false; +#ifndef QT_NO_OPENGL m_glContext = 0; m_shouldSetGLContextinDrawRect = false; +#endif currentCustomDragTypes = 0; m_sendUpAsRightButton = false; m_inputSource = 0; @@ -210,6 +214,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; return self; } +#ifndef QT_NO_OPENGL - (void) setQCocoaGLContext:(QCocoaGLContext *)context { m_glContext = context; @@ -231,6 +236,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; object:self]; } } +#endif - (void) globalFrameChanged:(NSNotification*)notification { @@ -516,10 +522,12 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; - (void) drawRect:(NSRect)dirtyRect { +#ifndef QT_NO_OPENGL if (m_glContext && m_shouldSetGLContextinDrawRect) { [m_glContext->nsOpenGLContext() setView:self]; m_shouldSetGLContextinDrawRect = false; } +#endif if (m_platformWindow->m_drawContentBorderGradient) NSDrawWindowBackground(dirtyRect); diff --git a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm index d18a01b11c..a02b074771 100644 --- a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm +++ b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm @@ -59,7 +59,7 @@ return nil; QAccessible::Id childId = QAccessible::uniqueId(m_window->accessibleRoot()); - return [QCocoaAccessibleElement elementWithId: childId]; + return [QMacAccessibilityElement elementWithId: childId]; } // The QNSView is a container that the user does not interact directly with: diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac.mm b/src/plugins/platforms/cocoa/qpaintengine_mac.mm index ef67d1166f..f4cd071ab7 100644 --- a/src/plugins/platforms/cocoa/qpaintengine_mac.mm +++ b/src/plugins/platforms/cocoa/qpaintengine_mac.mm @@ -193,7 +193,6 @@ CGImageRef qt_mac_create_imagemask(const QPixmap &pixmap, const QRectF &sr) //conversion inline static float qt_mac_convert_color_to_cg(int c) { return ((float)c * 1000 / 255) / 1000; } -inline static int qt_mac_convert_color_from_cg(float c) { return qRound(c * 255); } CGAffineTransform qt_mac_convert_transform_to_cg(const QTransform &t) { return CGAffineTransformMake(t.m11(), t.m12(), t.m21(), t.m22(), t.dx(), t.dy()); } @@ -974,11 +973,6 @@ void QCoreGraphicsPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, co d->restoreGraphicsState(); } -static void drawImageReleaseData (void *info, const void *, size_t) -{ - delete static_cast<QImage *>(info); -} - void QCoreGraphicsPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRectF &sr, Qt::ImageConversionFlags flags) { diff --git a/src/plugins/platforms/eglfs/qeglfscontext.cpp b/src/plugins/platforms/eglfs/qeglfscontext.cpp index 4d443b91e3..71c3c1e59b 100644 --- a/src/plugins/platforms/eglfs/qeglfscontext.cpp +++ b/src/plugins/platforms/eglfs/qeglfscontext.cpp @@ -42,7 +42,6 @@ #include "qeglfscontext.h" #include "qeglfswindow.h" #include "qeglfshooks.h" -#include "qeglfsintegration.h" #include <QtPlatformSupport/private/qeglconvenience_p.h> #include <QtPlatformSupport/private/qeglpbuffer_p.h> @@ -52,9 +51,9 @@ QT_BEGIN_NAMESPACE -QEglFSContext::QEglFSContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display) - : QEGLPlatformContext(format, share, display, - QEglFSIntegration::chooseConfig(display, format)) +QEglFSContext::QEglFSContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, + EGLConfig *config, const QVariant &nativeHandle) + : QEGLPlatformContext(format, share, display, config, nativeHandle) { } diff --git a/src/plugins/platforms/eglfs/qeglfscontext.h b/src/plugins/platforms/eglfs/qeglfscontext.h index 5d406f09f1..d378b7818b 100644 --- a/src/plugins/platforms/eglfs/qeglfscontext.h +++ b/src/plugins/platforms/eglfs/qeglfscontext.h @@ -43,13 +43,15 @@ #define QEGLFSCONTEXT_H #include <QtPlatformSupport/private/qeglplatformcontext_p.h> +#include <QtCore/QVariant> QT_BEGIN_NAMESPACE class QEglFSContext : public QEGLPlatformContext { public: - QEglFSContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display); + QEglFSContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, + EGLConfig *config, const QVariant &nativeHandle); EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface) Q_DECL_OVERRIDE; void swapBuffers(QPlatformSurface *surface) Q_DECL_OVERRIDE; }; diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/qeglfsintegration.cpp index 2941806f17..d770ea763a 100644 --- a/src/plugins/platforms/eglfs/qeglfsintegration.cpp +++ b/src/plugins/platforms/eglfs/qeglfsintegration.cpp @@ -50,6 +50,7 @@ #include <QtPlatformSupport/private/qeglconvenience_p.h> #include <QtPlatformSupport/private/qeglplatformcontext_p.h> #include <QtPlatformSupport/private/qeglpbuffer_p.h> +#include <QtPlatformHeaders/QEGLNativeContext> #include <qpa/qplatformwindow.h> #include <QtGui/QSurfaceFormat> @@ -115,9 +116,20 @@ QEGLPlatformWindow *QEglFSIntegration::createWindow(QWindow *window) const QEGLPlatformContext *QEglFSIntegration::createContext(const QSurfaceFormat &format, QPlatformOpenGLContext *shareContext, - EGLDisplay display) const + EGLDisplay display, + QVariant *nativeHandle) const { - return new QEglFSContext(QEglFSHooks::hooks()->surfaceFormatFor(format), shareContext, display); + QEglFSContext *ctx; + if (!nativeHandle || nativeHandle->isNull()) { + EGLConfig config = QEglFSIntegration::chooseConfig(display, format); + ctx = new QEglFSContext(QEglFSHooks::hooks()->surfaceFormatFor(format), shareContext, display, + &config, QVariant()); + } else { + ctx = new QEglFSContext(QEglFSHooks::hooks()->surfaceFormatFor(format), shareContext, display, + 0, *nativeHandle); + } + *nativeHandle = QVariant::fromValue<QEGLNativeContext>(QEGLNativeContext(ctx->eglContext(), display)); + return ctx; } QPlatformOffscreenSurface *QEglFSIntegration::createOffscreenSurface(EGLDisplay display, diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.h b/src/plugins/platforms/eglfs/qeglfsintegration.h index 99dda1ea96..fea05cd400 100644 --- a/src/plugins/platforms/eglfs/qeglfsintegration.h +++ b/src/plugins/platforms/eglfs/qeglfsintegration.h @@ -66,7 +66,8 @@ protected: QEGLPlatformWindow *createWindow(QWindow *window) const Q_DECL_OVERRIDE; QEGLPlatformContext *createContext(const QSurfaceFormat &format, QPlatformOpenGLContext *shareContext, - EGLDisplay display) const Q_DECL_OVERRIDE; + EGLDisplay display, + QVariant *nativeHandle) const Q_DECL_OVERRIDE; QPlatformOffscreenSurface *createOffscreenSurface(EGLDisplay display, const QSurfaceFormat &format, QOffscreenSurface *surface) const Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/eglfs/qeglfswindow.cpp b/src/plugins/platforms/eglfs/qeglfswindow.cpp index 2d36c0b58e..a0150b7ade 100644 --- a/src/plugins/platforms/eglfs/qeglfswindow.cpp +++ b/src/plugins/platforms/eglfs/qeglfswindow.cpp @@ -82,8 +82,10 @@ void QEglFSWindow::create() // they will be composited onto the root window's surface. QEglFSScreen *screen = this->screen(); if (screen->primarySurface() != EGL_NO_SURFACE) { - if (isRaster() && screen->compositingWindow()) + if (isRaster() && screen->compositingWindow()) { + m_format = screen->compositingWindow()->format(); return; + } #if !defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_NO_SDK) // We can have either a single OpenGL window or multiple raster windows. diff --git a/src/plugins/platforms/ios/ios.pro b/src/plugins/platforms/ios/ios.pro index ffc4ff9b12..57d4ac1770 100644 --- a/src/plugins/platforms/ios/ios.pro +++ b/src/plugins/platforms/ios/ios.pro @@ -23,7 +23,9 @@ OBJECTIVE_SOURCES = \ qiostheme.mm \ qiosglobal.mm \ qiosservices.mm \ - qiosclipboard.mm + qiosclipboard.mm \ + quiaccessibilityelement.mm \ + qiosplatformaccessibility.mm \ HEADERS = \ qiosintegration.h \ @@ -40,7 +42,9 @@ HEADERS = \ qiosglobal.h \ qiosservices.h \ quiview.h \ - qiosclipboard.h + qiosclipboard.h \ + quiaccessibilityelement.h \ + qiosplatformaccessibility.h \ OTHER_FILES = \ quiview_textinput.mm diff --git a/src/plugins/platforms/ios/qiosintegration.h b/src/plugins/platforms/ios/qiosintegration.h index 956c112399..733c8dc270 100644 --- a/src/plugins/platforms/ios/qiosintegration.h +++ b/src/plugins/platforms/ios/qiosintegration.h @@ -82,6 +82,8 @@ public: void *nativeResourceForWindow(const QByteArray &resource, QWindow *window); QTouchDevice *touchDevice(); + QPlatformAccessibility *accessibility() const Q_DECL_OVERRIDE; + private: QPlatformFontDatabase *m_fontDatabase; QPlatformClipboard *m_clipboard; @@ -90,6 +92,7 @@ private: QTouchDevice *m_touchDevice; QIOSApplicationState m_applicationState; QIOSServices *m_platformServices; + mutable QPlatformAccessibility *m_accessibility; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm index 0fe7adff9f..3334e3a094 100644 --- a/src/plugins/platforms/ios/qiosintegration.mm +++ b/src/plugins/platforms/ios/qiosintegration.mm @@ -45,6 +45,7 @@ #include "qioswindow.h" #include "qiosbackingstore.h" #include "qiosscreen.h" +#include "qiosplatformaccessibility.h" #include "qioscontext.h" #include "qiosclipboard.h" #include "qiosinputcontext.h" @@ -67,6 +68,7 @@ QIOSIntegration::QIOSIntegration() , m_inputContext(new QIOSInputContext) , m_screen(new QIOSScreen(QIOSScreen::MainScreen)) , m_platformServices(new QIOSServices) + , m_accessibility(0) { if (![UIApplication sharedApplication]) { qWarning() @@ -106,6 +108,9 @@ QIOSIntegration::~QIOSIntegration() delete m_platformServices; m_platformServices = 0; + + delete m_accessibility; + m_accessibility = 0; } bool QIOSIntegration::hasCapability(Capability cap) const @@ -229,4 +234,11 @@ QTouchDevice *QIOSIntegration::touchDevice() return m_touchDevice; } +QPlatformAccessibility *QIOSIntegration::accessibility() const +{ + if (!m_accessibility) + m_accessibility = new QIOSPlatformAccessibility; + return m_accessibility; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiosplatformaccessibility.h b/src/plugins/platforms/ios/qiosplatformaccessibility.h new file mode 100644 index 0000000000..beb0d006e1 --- /dev/null +++ b/src/plugins/platforms/ios/qiosplatformaccessibility.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** 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 QIOSPLATFORMACCESSIBILITY_H +#define QIOSPLATFORMACCESSIBILITY_H + +#include <qpa/qplatformaccessibility.h> + +QT_BEGIN_NAMESPACE + +class QIOSPlatformAccessibility: public QPlatformAccessibility +{ +public: + QIOSPlatformAccessibility(); + ~QIOSPlatformAccessibility(); + + virtual void notifyAccessibilityUpdate(QAccessibleEvent *event); +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/ios/qiosplatformaccessibility.mm b/src/plugins/platforms/ios/qiosplatformaccessibility.mm new file mode 100644 index 0000000000..db579ba559 --- /dev/null +++ b/src/plugins/platforms/ios/qiosplatformaccessibility.mm @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** 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 "qiosplatformaccessibility.h" + +#include <QtGui/QtGui> +#include "qioswindow.h" + +QIOSPlatformAccessibility::QIOSPlatformAccessibility() +{} + +QIOSPlatformAccessibility::~QIOSPlatformAccessibility() +{} + + +void invalidateCache(QAccessibleInterface *iface) +{ + if (!iface || !iface->isValid()) { + qWarning() << "invalid accessible interface: " << iface; + return; + } + + QWindow *win = 0; + QAccessibleInterface *parent = iface; + do { + win = parent->window(); + parent = parent->parent(); + } while (!win && parent); + Q_ASSERT(win && win->handle()); + QIOSWindow *window = static_cast<QIOSWindow*>(win->handle()); + window->clearAccessibleCache(); +} + + +void QIOSPlatformAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event) +{ + switch (event->type()) { + case QAccessible::ObjectCreated: + case QAccessible::ObjectShow: + case QAccessible::ObjectHide: + case QAccessible::ObjectDestroyed: + invalidateCache(event->accessibleInterface()); + break; + default: + break; + } +} diff --git a/src/plugins/platforms/ios/qioswindow.h b/src/plugins/platforms/ios/qioswindow.h index 6b6892e6e4..bcff3e202c 100644 --- a/src/plugins/platforms/ios/qioswindow.h +++ b/src/plugins/platforms/ios/qioswindow.h @@ -87,6 +87,8 @@ public: WId winId() const { return WId(m_view); }; + void clearAccessibleCache(); + private: void applicationStateChanged(Qt::ApplicationState state); void applyGeometry(const QRect &rect); diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm index 6f5c96cfc1..3ed2bbe1a1 100644 --- a/src/plugins/platforms/ios/qioswindow.mm +++ b/src/plugins/platforms/ios/qioswindow.mm @@ -52,6 +52,9 @@ #include <QtGui/private/qwindow_p.h> #include <qpa/qplatformintegration.h> +#include "qiosplatformaccessibility.h" +#import "quiaccessibilityelement.h" + #import <QuartzCore/CAEAGLLayer.h> #include <QtGui/QKeyEvent> @@ -82,9 +85,74 @@ if (self = [self initWithFrame:toCGRect(window->geometry())]) m_qioswindow = window; + m_accessibleElements = [[NSMutableArray alloc] init]; return self; } +- (void)createAccessibleElement:(QAccessibleInterface *)iface +{ + if (!iface || iface->state().invisible) + return; + QAccessible::Id accessibleId = QAccessible::uniqueId(iface); + UIAccessibilityElement *elem = [[QMacAccessibilityElement alloc] initWithId: accessibleId withAccessibilityContainer: self]; + [m_accessibleElements addObject: elem]; +} + +- (void)createAccessibleContainer:(QAccessibleInterface *)iface +{ + if (!iface) + return; + + if (iface->childCount() == 0) { + [self createAccessibleElement: iface]; + } else { + for (int i = 0; i < iface->childCount(); ++i) + [self createAccessibleContainer: iface->child(i)]; + } +} + +- (void)initAccessibility +{ + static bool init = false; + if (!init) + QGuiApplicationPrivate::platformIntegration()->accessibility()->setActive(true); + init = true; + + if ([m_accessibleElements count]) + return; + + QWindow *win = m_qioswindow->window(); + QAccessibleInterface *iface = win->accessibleRoot(); + if (iface) + [self createAccessibleContainer: iface]; +} + +- (void)clearAccessibleCache +{ + [m_accessibleElements removeAllObjects]; + UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, @""); +} + +// this is a container, returning yes here means the functions below will never be called +- (BOOL)isAccessibilityElement { + return NO; +} + +- (NSInteger)accessibilityElementCount { + [self initAccessibility]; + return [m_accessibleElements count]; +} + +- (id)accessibilityElementAtIndex:(NSInteger)index { + [self initAccessibility]; + return m_accessibleElements[index]; +} + +- (NSInteger)indexOfAccessibilityElement:(id)element { + [self initAccessibility]; + return [m_accessibleElements indexOfObject:element]; +} + - (id)initWithFrame:(CGRect)frame { if ((self = [super initWithFrame:frame])) { @@ -634,6 +702,11 @@ qreal QIOSWindow::devicePixelRatio() const return m_view.contentScaleFactor; } +void QIOSWindow::clearAccessibleCache() +{ + [m_view clearAccessibleCache]; +} + #include "moc_qioswindow.cpp" QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/quiaccessibilityelement.h b/src/plugins/platforms/ios/quiaccessibilityelement.h new file mode 100644 index 0000000000..7c5a930e86 --- /dev/null +++ b/src/plugins/platforms/ios/quiaccessibilityelement.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** 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 QUIACCESSIBILITYELEMENT_H +#define QUIACCESSIBILITYELEMENT_H + +#import <UIKit/UIKit.h> +#import <QtGui/QtGui> + +@interface QMacAccessibilityElement : UIAccessibilityElement +{} + +@property (readonly) QAccessible::Id axid; + +- (id) initWithId: (QAccessible::Id) anId withAccessibilityContainer: (id) view; ++ (QMacAccessibilityElement *) elementWithId: (QAccessible::Id) anId withAccessibilityContainer: (id) view; + +@end + +#endif diff --git a/src/plugins/platforms/ios/quiaccessibilityelement.mm b/src/plugins/platforms/ios/quiaccessibilityelement.mm new file mode 100644 index 0000000000..c9e9e34cbd --- /dev/null +++ b/src/plugins/platforms/ios/quiaccessibilityelement.mm @@ -0,0 +1,194 @@ +/**************************************************************************** +** +** 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 "quiaccessibilityelement.h" + +#include "private/qaccessiblecache_p.h" + +@implementation QMacAccessibilityElement + +- (id) initWithId: (QAccessible::Id) anId withAccessibilityContainer: (id) view +{ + Q_ASSERT((int)anId < 0); + self = [super initWithAccessibilityContainer: view]; + if (self) + _axid = anId; + + return self; +} + ++ (id) elementWithId: (QAccessible::Id) anId withAccessibilityContainer: (id) view +{ + Q_ASSERT(anId); + if (!anId) + return nil; + + QAccessibleCache *cache = QAccessibleCache::instance(); + + QMacAccessibilityElement *element = cache->elementForId(anId); + if (!element) { + QAccessibleInterface *iface = QAccessible::accessibleInterface(anId); + Q_ASSERT(iface); + element = [[self alloc] initWithId:anId withAccessibilityContainer: view]; + cache->insertElement(anId, element); + } + return element; +} + +- (void) invalidate +{ + [self release]; +} + +- (BOOL) isAccessibilityElement +{ + return YES; +} + +- (NSString*) accessibilityLabel +{ + QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); + if (!iface) { + qWarning() << "invalid accessible interface for: " << self.axid; + return @""; + } + + return iface->text(QAccessible::Name).toNSString(); +} + +- (NSString*) accessibilityHint +{ + QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); + if (!iface) { + qWarning() << "invalid accessible interface for: " << self.axid; + return @""; + } + return iface->text(QAccessible::Description).toNSString(); +} + +- (NSString*) accessibilityValue +{ + QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); + if (!iface) { + qWarning() << "invalid accessible interface for: " << self.axid; + return @""; + } + + QAccessible::State state = iface->state(); + + if (state.checkable) + return state.checked ? @"checked" : @"unchecked"; // FIXME: translation + + QAccessibleValueInterface *val = iface->valueInterface(); + if (val) { + return val->currentValue().toString().toNSString(); + } else if (QAccessibleTextInterface *text = iface->textInterface()) { + // FIXME doesn't work? + return text->text(0, text->characterCount() - 1).toNSString(); + } + + return [super accessibilityHint]; +} + +- (CGRect) accessibilityFrame +{ + QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); + if (!iface) { + qWarning() << "invalid accessible interface for: " << self.axid; + return CGRect(); + } + + QRect rect = iface->rect(); + return CGRectMake(rect.x(), rect.y(), rect.width(), rect.height()); +} + +- (UIAccessibilityTraits) accessibilityTraits +{ + UIAccessibilityTraits traits = UIAccessibilityTraitNone; + + QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); + if (!iface) { + qWarning() << "invalid accessible interface for: " << self.axid; + return traits; + } + QAccessible::State state = iface->state(); + if (state.disabled) + traits |= UIAccessibilityTraitNotEnabled; + + if (iface->role() == QAccessible::Button) + traits |= UIAccessibilityTraitButton; + + if (iface->valueInterface()) + traits |= UIAccessibilityTraitAdjustable; + + return traits; +} + +- (BOOL) accessibilityActivate +{ + QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); + if (QAccessibleActionInterface *action = iface->actionInterface()) { + if (action->actionNames().contains(QAccessibleActionInterface::pressAction())) { + action->doAction(QAccessibleActionInterface::pressAction()); + return YES; + } else if (action->actionNames().contains(QAccessibleActionInterface::showMenuAction())) { + action->doAction(QAccessibleActionInterface::showMenuAction()); + return YES; + } + } + return NO; // fall back to sending mouse clicks +} + +- (void) accessibilityIncrement +{ + QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); + if (QAccessibleActionInterface *action = iface->actionInterface()) + action->doAction(QAccessibleActionInterface::increaseAction()); +} + +- (void) accessibilityDecrement +{ + QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); + if (QAccessibleActionInterface *action = iface->actionInterface()) + action->doAction(QAccessibleActionInterface::decreaseAction()); +} + +@end diff --git a/src/plugins/platforms/ios/quiview.h b/src/plugins/platforms/ios/quiview.h index 122e7c604b..7c65037004 100644 --- a/src/plugins/platforms/ios/quiview.h +++ b/src/plugins/platforms/ios/quiview.h @@ -57,6 +57,8 @@ int m_nextTouchId; QString m_markedText; BOOL m_inSendEventToFocusObject; + + NSMutableArray *m_accessibleElements; } @property(nonatomic, assign) id<UITextInputDelegate> inputDelegate; diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp index 6c6c516a4e..3f959b859c 100644 --- a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp +++ b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp @@ -179,7 +179,7 @@ QOffscreenX11GLXContext::QOffscreenX11GLXContext(QOffscreenX11Info *x11, QOpenGL // Get the basic surface format details if (d->context) - qglx_surfaceFormatFromGLXFBConfig(&d->format, x11->display(), config, d->context); + qglx_surfaceFormatFromGLXFBConfig(&d->format, x11->display(), config); // Create a temporary window so that we can make the new context current d->window = createDummyWindow(x11, config); diff --git a/src/plugins/platforms/windows/accessible/iaccessible2.cpp b/src/plugins/platforms/windows/accessible/iaccessible2.cpp index 032f33163a..082ddf625a 100644 --- a/src/plugins/platforms/windows/accessible/iaccessible2.cpp +++ b/src/plugins/platforms/windows/accessible/iaccessible2.cpp @@ -43,7 +43,7 @@ #include "iaccessible2.h" #include "qwindowsaccessibility.h" - +#include <QtPlatformSupport/private/qaccessiblebridgeutils_p.h> #include <QtGui/qaccessible.h> #include <QtGui/qclipboard.h> #include <QtWidgets/qapplication.h> @@ -545,10 +545,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::nActions(long *nActions) accessibleDebugClientCalls(accessible); if (!accessible) return E_FAIL; - *nActions = 0; - - if (QAccessibleActionInterface *actionIface = actionInterface()) - *nActions = actionIface->actionNames().count(); + *nActions = QAccessibleBridgeUtils::effectiveActionNames(accessible).count(); return S_OK; } @@ -558,15 +555,11 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::doAction(long actionIndex) accessibleDebugClientCalls(accessible); if (!accessible) return E_FAIL; - if (QAccessibleActionInterface *actionIface = actionInterface()) { - const QStringList actionNames = actionIface->actionNames(); - if (actionIndex < 0 || actionIndex >= actionNames.count()) - return E_INVALIDARG; - const QString actionName = actionNames.at(actionIndex); - actionIface->doAction(actionName); - return S_OK; - } - return S_FALSE; + const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(accessible); + if (actionIndex < 0 || actionIndex >= actionNames.count()) + return E_INVALIDARG; + const QString actionName = actionNames.at(actionIndex); + return QAccessibleBridgeUtils::performEffectiveAction(accessible, actionName) ? S_OK : S_FALSE; } HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_description(long actionIndex, BSTR *description) @@ -576,13 +569,15 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_description(long actionInde if (!accessible) return E_FAIL; *description = 0; - if (QAccessibleActionInterface *actionIface = actionInterface()) { - const QStringList actionNames = actionIface->actionNames(); - if (actionIndex < 0 || actionIndex >= actionNames.count()) - return E_INVALIDARG; - const QString actionName = actionNames.at(actionIndex); + const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(accessible); + if (actionIndex < 0 || actionIndex >= actionNames.count()) + return E_INVALIDARG; + const QString actionName = actionNames.at(actionIndex); + if (QAccessibleActionInterface *actionIface = actionInterface()) *description = QStringToBSTR(actionIface->localizedActionDescription(actionName)); - } + else + *description = QStringToBSTR(qAccessibleLocalizedActionDescription(actionName)); + return *description ? S_OK : S_FALSE; } @@ -622,13 +617,11 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_name(long actionIndex, BSTR if (!accessible) return E_FAIL; *name = 0; - if (QAccessibleActionInterface *actionIface = actionInterface()) { - const QStringList actionNames = actionIface->actionNames(); - if (actionIndex < 0 || actionIndex >= actionNames.count()) - return E_INVALIDARG; - const QString actionName = actionNames.at(actionIndex); - *name = QStringToBSTR(actionName); - } + const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(accessible); + if (actionIndex < 0 || actionIndex >= actionNames.count()) + return E_INVALIDARG; + const QString actionName = actionNames.at(actionIndex); + *name = QStringToBSTR(actionName); return *name ? S_OK : S_FALSE; } @@ -639,14 +632,16 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_localizedName(long actionIn if (!accessible) return E_FAIL; *localizedName = 0; - if (QAccessibleActionInterface *actionIface = actionInterface()) { - const QStringList actionNames = actionIface->actionNames(); - if (actionIndex < 0 || actionIndex >= actionNames.count()) - return E_INVALIDARG; + const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(accessible); + if (actionIndex < 0 || actionIndex >= actionNames.count()) + return E_INVALIDARG; - const QString actionName = actionNames.at(actionIndex); + const QString actionName = actionNames.at(actionIndex); + if (QAccessibleActionInterface *actionIface = actionInterface()) *localizedName = QStringToBSTR(actionIface->localizedActionName(actionName)); - } + else + *localizedName = QStringToBSTR(QAccessibleActionInterface::tr(qPrintable(actionName))); + return *localizedName ? S_OK : S_FALSE; } diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h index ee640224cf..3992f2d297 100644 --- a/src/plugins/platforms/windows/qtwindowsglobal.h +++ b/src/plugins/platforms/windows/qtwindowsglobal.h @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch> -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** 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. @@ -117,6 +117,14 @@ enum WindowsEventType // Simplify event types UnknownEvent = 542 }; +// Matches Process_DPI_Awareness (Windows 8.1 onwards), used for SetProcessDpiAwareness() +enum ProcessDpiAwareness +{ + ProcessDpiUnaware, + ProcessSystemDpiAware, + ProcessPerMonitorDpiAware +}; + } // namespace QtWindows inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamIn) diff --git a/src/plugins/platforms/windows/qwindowsclipboard.cpp b/src/plugins/platforms/windows/qwindowsclipboard.cpp index dcfeba12fa..e43b524aa8 100644 --- a/src/plugins/platforms/windows/qwindowsclipboard.cpp +++ b/src/plugins/platforms/windows/qwindowsclipboard.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** 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. @@ -145,7 +145,7 @@ static void cleanClipboardPostRoutine() QWindowsClipboard *QWindowsClipboard::m_instance = 0; QWindowsClipboard::QWindowsClipboard() : - m_data(0), m_clipboardViewer(0), m_nextClipboardViewer(0) + m_data(0), m_clipboardViewer(0), m_nextClipboardViewer(0), m_formatListenerRegistered(false) { QWindowsClipboard::m_instance = this; qAddPostRoutine(cleanClipboardPostRoutine); @@ -178,20 +178,40 @@ void QWindowsClipboard::registerViewer() m_clipboardViewer = QWindowsContext::instance()-> createDummyWindow(QStringLiteral("Qt5ClipboardView"), L"Qt5ClipboardView", qClipboardViewerWndProc, WS_OVERLAPPED); - m_nextClipboardViewer = SetClipboardViewer(m_clipboardViewer); - qCDebug(lcQpaMime) << __FUNCTION__ << "m_clipboardViewer: " << m_clipboardViewer << "next: " << m_nextClipboardViewer; + // Try format listener API (Vista onwards) first. + if (QWindowsContext::user32dll.addClipboardFormatListener && QWindowsContext::user32dll.removeClipboardFormatListener) { + m_formatListenerRegistered = QWindowsContext::user32dll.addClipboardFormatListener(m_clipboardViewer); + if (!m_formatListenerRegistered) + qErrnoWarning("AddClipboardFormatListener() failed."); + } + + if (!m_formatListenerRegistered) + m_nextClipboardViewer = SetClipboardViewer(m_clipboardViewer); + + qCDebug(lcQpaMime) << __FUNCTION__ << "m_clipboardViewer:" << m_clipboardViewer + << "format listener:" << m_formatListenerRegistered + << "next:" << m_nextClipboardViewer; } void QWindowsClipboard::unregisterViewer() { if (m_clipboardViewer) { - ChangeClipboardChain(m_clipboardViewer, m_nextClipboardViewer); + if (m_formatListenerRegistered) { + QWindowsContext::user32dll.removeClipboardFormatListener(m_clipboardViewer); + m_formatListenerRegistered = false; + } else { + ChangeClipboardChain(m_clipboardViewer, m_nextClipboardViewer); + m_nextClipboardViewer = 0; + } DestroyWindow(m_clipboardViewer); - m_clipboardViewer = m_nextClipboardViewer = 0; + m_clipboardViewer = 0; } } +// ### FIXME: Qt 6: Remove the clipboard chain handling code and make the +// format listener the default. + static bool isProcessBeingDebugged(HWND hwnd) { DWORD pid = 0; @@ -232,6 +252,8 @@ void QWindowsClipboard::propagateClipboardMessage(UINT message, WPARAM wParam, L bool QWindowsClipboard::clipboardViewerWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result) { + enum { wMClipboardUpdate = 0x031D }; + *result = 0; if (QWindowsContext::verbose) qCDebug(lcQpaMime) << __FUNCTION__ << hwnd << message << QWindowsGuiEventDispatcher::windowsMessageName(message); @@ -246,14 +268,16 @@ bool QWindowsClipboard::clipboardViewerWndProc(HWND hwnd, UINT message, WPARAM w } } return true; - case WM_DRAWCLIPBOARD: { + case wMClipboardUpdate: // Clipboard Format listener (Vista onwards) + case WM_DRAWCLIPBOARD: { // Clipboard Viewer Chain handling (up to XP) const bool owned = ownsClipboard(); 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) releaseIData(); - propagateClipboardMessage(message, wParam, lParam); + if (!m_formatListenerRegistered) + propagateClipboardMessage(message, wParam, lParam); } return true; case WM_DESTROY: diff --git a/src/plugins/platforms/windows/qwindowsclipboard.h b/src/plugins/platforms/windows/qwindowsclipboard.h index 30bc0143f4..61c5967e98 100644 --- a/src/plugins/platforms/windows/qwindowsclipboard.h +++ b/src/plugins/platforms/windows/qwindowsclipboard.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** 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. @@ -88,6 +88,7 @@ private: QWindowsOleDataObject *m_data; HWND m_clipboardViewer; HWND m_nextClipboardViewer; + bool m_formatListenerRegistered; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index f2f285f0f6..322bae10aa 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -191,7 +191,8 @@ QWindowsUser32DLL::QWindowsUser32DLL() : updateLayeredWindowIndirect(0), isHungAppWindow(0), registerTouchWindow(0), unregisterTouchWindow(0), - getTouchInputInfo(0), closeTouchInputHandle(0), setProcessDPIAware(0) + getTouchInputInfo(0), closeTouchInputHandle(0), setProcessDPIAware(0), + addClipboardFormatListener(0), removeClipboardFormatListener(0) { } @@ -207,6 +208,11 @@ void QWindowsUser32DLL::init() updateLayeredWindowIndirect = (UpdateLayeredWindowIndirect)(library.resolve("UpdateLayeredWindowIndirect")); isHungAppWindow = (IsHungAppWindow)library.resolve("IsHungAppWindow"); setProcessDPIAware = (SetProcessDPIAware)library.resolve("SetProcessDPIAware"); + + if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA) { + addClipboardFormatListener = (AddClipboardFormatListener)library.resolve("AddClipboardFormatListener"); + removeClipboardFormatListener = (RemoveClipboardFormatListener)library.resolve("RemoveClipboardFormatListener"); + } } bool QWindowsUser32DLL::initTouch() @@ -247,8 +253,26 @@ void QWindowsShell32DLL::init() sHGetImageList = (SHGetImageList)library.resolve("SHGetImageList"); } +QWindowsShcoreDLL::QWindowsShcoreDLL() + : getProcessDpiAwareness(0) + , setProcessDpiAwareness(0) + , getDpiForMonitor(0) +{ +} + +void QWindowsShcoreDLL::init() +{ + if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS8_1) + return; + QSystemLibrary library(QStringLiteral("SHCore")); + getProcessDpiAwareness = (GetProcessDpiAwareness)library.resolve("GetProcessDpiAwareness"); + setProcessDpiAwareness = (SetProcessDpiAwareness)library.resolve("SetProcessDpiAwareness"); + getDpiForMonitor = (GetDpiForMonitor)library.resolve("GetDpiForMonitor"); +} + QWindowsUser32DLL QWindowsContext::user32dll; QWindowsShell32DLL QWindowsContext::shell32dll; +QWindowsShcoreDLL QWindowsContext::shcoredll; #endif // !Q_OS_WINCE @@ -299,9 +323,7 @@ QWindowsContextPrivate::QWindowsContextPrivate() #ifndef Q_OS_WINCE QWindowsContext::user32dll.init(); QWindowsContext::shell32dll.init(); - // Ensure metrics functions report correct data, QTBUG-30063. - if (QWindowsContext::user32dll.setProcessDPIAware) - QWindowsContext::user32dll.setProcessDPIAware(); + QWindowsContext::shcoredll.init(); if (hasTouchSupport(ver) && QWindowsContext::user32dll.initTouch()) m_systemInfo |= QWindowsContext::SI_SupportsTouch; @@ -358,6 +380,25 @@ void QWindowsContext::setTabletAbsoluteRange(int a) #endif } +void QWindowsContext::setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiAwareness) +{ +#ifndef Q_OS_WINCE + qCDebug(lcQpaWindows) << __FUNCTION__ << dpiAwareness; + if (QWindowsContext::shcoredll.isValid()) { + const HRESULT hr = QWindowsContext::shcoredll.setProcessDpiAwareness(dpiAwareness); + if (FAILED(hr)) + qWarning() << "SetProcessDpiAwareness failed:" << QWindowsContext::comErrorString(hr); + } else { + if (dpiAwareness != QtWindows::ProcessDpiUnaware && QWindowsContext::user32dll.setProcessDPIAware) { + if (!QWindowsContext::user32dll.setProcessDPIAware()) + qErrnoWarning("SetProcessDPIAware() failed"); + } + } +#else // !Q_OS_WINCE + Q_UNUSED(dpiAwareness) +#endif +} + QWindowsContext *QWindowsContext::instance() { return m_instance; @@ -419,9 +460,17 @@ QString QWindowsContext::registerWindowClass(const QWindow *w, bool isGL) && (type == Qt::Popup || w->property("_q_windowsDropShadow").toBool())) { style |= CS_DROPSHADOW; } - if (type == Qt::Tool || type == Qt::ToolTip || type == Qt::Popup) { + switch (type) { + case Qt::Tool: + case Qt::ToolTip: + case Qt::Popup: style |= CS_SAVEBITS; // Save/restore background icon = false; + break; + case Qt::Dialog: + if (!(flags & Qt::WindowSystemMenuHint)) + icon = false; // QTBUG-2027, dialogs without system menu. + break; } // Create a unique name for the flag combination QString cname = QStringLiteral("Qt5QWindow"); diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h index f5dbd072c7..086b968255 100644 --- a/src/plugins/platforms/windows/qwindowscontext.h +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -94,6 +94,8 @@ struct QWindowsUser32DLL typedef BOOL (WINAPI *UpdateLayeredWindowIndirect)(HWND, const UPDATELAYEREDWINDOWINFO *); typedef BOOL (WINAPI *IsHungAppWindow)(HWND); typedef BOOL (WINAPI *SetProcessDPIAware)(); + typedef BOOL (WINAPI *AddClipboardFormatListener)(HWND); + typedef BOOL (WINAPI *RemoveClipboardFormatListener)(HWND); // Functions missing in Q_CC_GNU stub libraries. SetLayeredWindowAttributes setLayeredWindowAttributes; @@ -111,6 +113,10 @@ struct QWindowsUser32DLL // Windows Vista onwards SetProcessDPIAware setProcessDPIAware; + + // Clipboard listeners, Windows Vista onwards + AddClipboardFormatListener addClipboardFormatListener; + RemoveClipboardFormatListener removeClipboardFormatListener; }; struct QWindowsShell32DLL @@ -126,6 +132,22 @@ struct QWindowsShell32DLL SHGetStockIconInfo sHGetStockIconInfo; SHGetImageList sHGetImageList; }; + +// Shell scaling library (Windows 8.1 onwards) +struct QWindowsShcoreDLL { + QWindowsShcoreDLL(); + void init(); + inline bool isValid() const { return getProcessDpiAwareness && setProcessDpiAwareness && getDpiForMonitor; } + + typedef HRESULT (WINAPI *GetProcessDpiAwareness)(HANDLE,int); + typedef HRESULT (WINAPI *SetProcessDpiAwareness)(int); + typedef HRESULT (WINAPI *GetDpiForMonitor)(HMONITOR,int,UINT *,UINT *); + + GetProcessDpiAwareness getProcessDpiAwareness; + SetProcessDpiAwareness setProcessDpiAwareness; + GetDpiForMonitor getDpiForMonitor; +}; + #endif // Q_OS_WINCE class QWindowsContext @@ -184,6 +206,7 @@ public: void setWindowCreationContext(const QSharedPointer<QWindowCreationContext> &ctx); void setTabletAbsoluteRange(int a); + void setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiAwareness); // Returns a combination of SystemInfoFlags unsigned systemInfo() const; @@ -197,6 +220,7 @@ public: #ifndef Q_OS_WINCE static QWindowsUser32DLL user32dll; static QWindowsShell32DLL shell32dll; + static QWindowsShcoreDLL shcoredll; #endif static QByteArray comErrorString(HRESULT hr); diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp index d8fb104b3c..bfe22dac3f 100644 --- a/src/plugins/platforms/windows/qwindowscursor.cpp +++ b/src/plugins/platforms/windows/qwindowscursor.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** 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. @@ -98,7 +98,7 @@ QWindowsCursorCacheKey::QWindowsCursorCacheKey(const QCursor &c) \sa QWindowsWindowCursor */ -HCURSOR QWindowsCursor::createPixmapCursor(const QPixmap &pixmap, int hotX, int hotY) +HCURSOR QWindowsCursor::createPixmapCursor(const QPixmap &pixmap, const QPoint &hotSpot) { HCURSOR cur = 0; QBitmap mask = pixmap.mask(); @@ -112,8 +112,8 @@ HCURSOR QWindowsCursor::createPixmapCursor(const QPixmap &pixmap, int hotX, int ICONINFO ii; ii.fIcon = 0; - ii.xHotspot = hotX; - ii.yHotspot = hotY; + ii.xHotspot = hotSpot.x(); + ii.yHotspot = hotSpot.y(); ii.hbmMask = im; ii.hbmColor = ic; @@ -124,20 +124,141 @@ HCURSOR QWindowsCursor::createPixmapCursor(const QPixmap &pixmap, int hotX, int return cur; } -HCURSOR QWindowsCursor::createSystemCursor(const QCursor &c) +// Create a cursor from image and mask of the format QImage::Format_Mono. +static HCURSOR createBitmapCursor(const QImage &bbits, const QImage &mbits, + QPoint hotSpot = QPoint(), + bool invb = false, bool invm = false) { - int hx = c.hotSpot().x(); - int hy = c.hotSpot().y(); - const Qt::CursorShape cshape = c.shape(); - if (cshape == Qt::BitmapCursor) { - const QPixmap pixmap = c.pixmap(); - if (!pixmap.isNull()) - if (const HCURSOR hc = createPixmapCursor(pixmap, hx, hy)) - return hc; + const int width = bbits.width(); + const int height = bbits.height(); + if (hotSpot.isNull()) + hotSpot = QPoint(width / 2, height / 2); + const int n = qMax(1, width / 8); +#if !defined(Q_OS_WINCE) + QScopedArrayPointer<uchar> xBits(new uchar[height * n]); + QScopedArrayPointer<uchar> xMask(new uchar[height * n]); + int x = 0; + for (int i = 0; i < height; ++i) { + const uchar *bits = bbits.scanLine(i); + const uchar *mask = mbits.scanLine(i); + for (int j = 0; j < n; ++j) { + uchar b = bits[j]; + uchar m = mask[j]; + if (invb) + b ^= 0xff; + if (invm) + m ^= 0xff; + xBits[x] = ~m; + xMask[x] = b ^ m; + ++x; + } + } + return CreateCursor(GetModuleHandle(0), hotSpot.x(), hotSpot.y(), width, height, + xBits.data(), xMask.data()); +#elif defined(GWES_ICONCURS) // Q_OS_WINCE + // Windows CE only supports fixed cursor size. + int sysW = GetSystemMetrics(SM_CXCURSOR); + int sysH = GetSystemMetrics(SM_CYCURSOR); + int sysN = qMax(1, sysW / 8); + uchar* xBits = new uchar[sysH * sysN]; + uchar* xMask = new uchar[sysH * sysN]; + int x = 0; + for (int i = 0; i < sysH; ++i) { + if (i >= height) { + memset(&xBits[x] , 255, sysN); + memset(&xMask[x] , 0, sysN); + x += sysN; + } else { + int fillWidth = n > sysN ? sysN : n; + const uchar *bits = bbits.scanLine(i); + const uchar *mask = mbits.scanLine(i); + for (int j = 0; j < fillWidth; ++j) { + uchar b = bits[j]; + uchar m = mask[j]; + if (invb) + b ^= 0xFF; + if (invm) + m ^= 0xFF; + xBits[x] = ~m; + xMask[x] = b ^ m; + ++x; + } + for (int j = fillWidth; j < sysN; ++j ) { + xBits[x] = 255; + xMask[x] = 0; + ++x; + } + } } - // Non-standard Windows cursors are created from bitmaps + HCURSOR hcurs = CreateCursor(qWinAppInst(), hotSpot.x(), hotSpot.y(), sysW, sysH, + xBits, xMask); + delete [] xBits; + delete [] xMask; + return hcurs; +#else + Q_UNUSED(n); + Q_UNUSED(invm); + Q_UNUSED(invb); + Q_UNUSED(mbits); + return 0; +#endif +} + +static inline QSize systemCursorSize() { return QSize(GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR)); } +static inline QSize standardCursorSize() { return QSize(32, 32); } + +// Create pixmap cursors from data and scale the image if the cursor size is +// higher than the standard 32. Note that bitmap cursors as produced by +// createBitmapCursor() only work for standard sizes (32,48,64...), which does +// not work when scaling the 16x16 openhand cursor bitmaps to 150% (resulting +// in a non-standard 24x24 size). +static HCURSOR createPixmapCursorFromData(const QSize &systemCursorSize, + // The cursor size the bitmap is targeted for + const QSize &bitmapTargetCursorSize, + // The actual size of the bitmap data + int bitmapSize, const uchar *bits, + const uchar *maskBits) +{ + QPixmap rawImage = QPixmap::fromImage(QBitmap::fromData(QSize(bitmapSize, bitmapSize), bits).toImage()); + rawImage.setMask(QBitmap::fromData(QSize(bitmapSize, bitmapSize), maskBits)); + + const qreal factor = qreal(systemCursorSize.width()) / qreal(bitmapTargetCursorSize.width()); + // Scale images if the cursor size is significantly different, starting with 150% where the system cursor + // size is 48. + if (qAbs(factor - 1.0) > 0.4) { + const QTransform transform = QTransform::fromScale(factor, factor); + rawImage = rawImage.transformed(transform, Qt::SmoothTransformation); + } + const QPoint hotSpot(rawImage.width() / 2, rawImage.height() / 2); + return QWindowsCursor::createPixmapCursor(rawImage, hotSpot); +} + +struct QWindowsStandardCursorMapping { + Qt::CursorShape shape; + LPCWSTR resource; +}; +HCURSOR QWindowsCursor::createSystemCursor(const QCursor &c) +{ + static const QWindowsStandardCursorMapping standardCursors[] = { + { Qt::ArrowCursor, IDC_ARROW}, + { Qt::UpArrowCursor, IDC_UPARROW }, + { Qt::CrossCursor, IDC_CROSS }, + { Qt::WaitCursor, IDC_WAIT }, + { Qt::IBeamCursor, IDC_IBEAM }, + { Qt::SizeVerCursor, IDC_SIZENS }, + { Qt::SizeHorCursor, IDC_SIZEWE }, + { Qt::SizeBDiagCursor, IDC_SIZENESW }, + { Qt::SizeFDiagCursor, IDC_SIZENWSE }, + { Qt::SizeAllCursor, IDC_SIZEALL }, + { Qt::ForbiddenCursor, IDC_NO }, + { Qt::WhatsThisCursor, IDC_HELP }, + { Qt::BusyCursor, IDC_APPSTARTING }, + { Qt::PointingHandCursor, IDC_HAND } + }; + + // Non-standard Windows cursors are created from bitmaps static const uchar vsplit_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -203,171 +324,53 @@ 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}; - wchar_t *sh = 0; - switch (c.shape()) { // map to windows cursor - case Qt::ArrowCursor: - sh = IDC_ARROW; - break; - case Qt::UpArrowCursor: - sh = IDC_UPARROW; - break; - case Qt::CrossCursor: - sh = IDC_CROSS; - break; - case Qt::WaitCursor: - sh = IDC_WAIT; - break; - case Qt::IBeamCursor: - sh = IDC_IBEAM; - break; - case Qt::SizeVerCursor: - sh = IDC_SIZENS; - break; - case Qt::SizeHorCursor: - sh = IDC_SIZEWE; - break; - case Qt::SizeBDiagCursor: - sh = IDC_SIZENESW; - break; - case Qt::SizeFDiagCursor: - sh = IDC_SIZENWSE; - break; - case Qt::SizeAllCursor: - sh = IDC_SIZEALL; - break; - case Qt::ForbiddenCursor: - sh = IDC_NO; - break; - case Qt::WhatsThisCursor: - sh = IDC_HELP; - break; - case Qt::BusyCursor: - sh = IDC_APPSTARTING; - break; - case Qt::PointingHandCursor: - sh = IDC_HAND; - break; - case Qt::BlankCursor: + const Qt::CursorShape cursorShape = c.shape(); + switch (cursorShape) { + case Qt::BitmapCursor: { + const QPixmap pixmap = c.pixmap(); + if (!pixmap.isNull()) + return QWindowsCursor::createPixmapCursor(pixmap, c.hotSpot()); + const QImage bbits = c.bitmap()->toImage().convertToFormat(QImage::Format_Mono); + const QImage mbits = c.mask()->toImage().convertToFormat(QImage::Format_Mono); + const bool invb = bbits.colorCount() > 1 && qGray(bbits.color(0)) < qGray(bbits.color(1)); + const bool invm = mbits.colorCount() > 1 && qGray(mbits.color(0)) < qGray(mbits.color(1)); + return createBitmapCursor(bbits, mbits, c.hotSpot(), invb, invm); + } + case Qt::BlankCursor: { + QImage blank = QImage(systemCursorSize(), QImage::Format_Mono); + blank.fill(0); // ignore color table + return createBitmapCursor(blank, blank); + } case Qt::SplitVCursor: + return createPixmapCursorFromData(systemCursorSize(), standardCursorSize(), 32, vsplit_bits, vsplitm_bits); case Qt::SplitHCursor: + return createPixmapCursorFromData(systemCursorSize(), standardCursorSize(), 32, hsplit_bits, hsplitm_bits); case Qt::OpenHandCursor: + return createPixmapCursorFromData(systemCursorSize(), standardCursorSize(), 16, openhand_bits, openhandm_bits); case Qt::ClosedHandCursor: - case Qt::BitmapCursor: { - QImage bbits, mbits; - bool invb, invm; - if (cshape == Qt::BlankCursor) { - bbits = QImage(32, 32, QImage::Format_Mono); - bbits.fill(0); // ignore color table - mbits = bbits.copy(); - hx = hy = 16; - invb = invm = false; - } else if (cshape == Qt::OpenHandCursor || cshape == Qt::ClosedHandCursor) { - bool open = cshape == Qt::OpenHandCursor; - QBitmap cb = QBitmap::fromData(QSize(16, 16), open ? openhand_bits : closedhand_bits); - QBitmap cm = QBitmap::fromData(QSize(16, 16), open ? openhandm_bits : closedhandm_bits); - bbits = cb.toImage().convertToFormat(QImage::Format_Mono); - mbits = cm.toImage().convertToFormat(QImage::Format_Mono); - hx = hy = 8; - invb = invm = false; - } 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(); -#if !defined(Q_OS_WINCE) - QScopedArrayPointer<uchar> xBits(new uchar[h * n]); - QScopedArrayPointer<uchar> xMask(new uchar[h * n]); - int x = 0; - for (int i = 0; i < h; ++i) { - uchar *bits = bbits.scanLine(i); - uchar *mask = mbits.scanLine(i); - for (int j = 0; j < n; ++j) { - uchar b = bits[j]; - uchar m = mask[j]; - if (invb) - b ^= 0xff; - if (invm) - m ^= 0xff; - xBits[x] = ~m; - xMask[x] = b ^ m; - ++x; - } - } - return CreateCursor(GetModuleHandle(0), hx, hy, bbits.width(), bbits.height(), - xBits.data(), xMask.data()); -#elif defined(GWES_ICONCURS) // Q_WS_WINCE - // Windows CE only supports fixed cursor size. - int sysW = GetSystemMetrics(SM_CXCURSOR); - int sysH = GetSystemMetrics(SM_CYCURSOR); - int sysN = qMax(1, sysW / 8); - uchar* xBits = new uchar[sysH * sysN]; - uchar* xMask = new uchar[sysH * sysN]; - int x = 0; - for (int i = 0; i < sysH; ++i) { - if (i >= h) { - memset(&xBits[x] , 255, sysN); - memset(&xMask[x] , 0, sysN); - x += sysN; - } else { - int fillWidth = n > sysN ? sysN : n; - uchar *bits = bbits.scanLine(i); - uchar *mask = mbits.scanLine(i); - for (int j = 0; j < fillWidth; ++j) { - uchar b = bits[j]; - uchar m = mask[j]; - if (invb) - b ^= 0xFF; - if (invm) - m ^= 0xFF; - xBits[x] = ~m; - xMask[x] = b ^ m; - ++x; - } - for (int j = fillWidth; j < sysN; ++j ) { - xBits[x] = 255; - xMask[x] = 0; - ++x; - } - } - } - - HCURSOR hcurs = CreateCursor(qWinAppInst(), hx, hy, sysW, sysH, - xBits, xMask); - delete [] xBits; - delete [] xMask; - return hcurs; -#else - Q_UNUSED(n); - Q_UNUSED(h); - return 0; -#endif - - } + return createPixmapCursorFromData(systemCursorSize(), standardCursorSize(), 16, closedhand_bits, closedhandm_bits); case Qt::DragCopyCursor: case Qt::DragMoveCursor: - case Qt::DragLinkCursor: { - const QPixmap pixmap = QGuiApplicationPrivate::instance()->getPixmapCursor(cshape); - return createPixmapCursor(pixmap, hx, hy); - } + case Qt::DragLinkCursor: + return createPixmapCursor(QGuiApplicationPrivate::instance()->getPixmapCursor(cursorShape), c.hotSpot()); default: - qWarning("%s: Invalid cursor shape %d", __FUNCTION__, cshape); - return 0; + break; } -#ifdef Q_OS_WINCE - return LoadCursor(0, sh); + + // Load available standard cursors from resources + const QWindowsStandardCursorMapping *sEnd = standardCursors + sizeof(standardCursors) / sizeof(standardCursors[0]); + for (const QWindowsStandardCursorMapping *s = standardCursors; s < sEnd; ++s) { + if (s->shape == cursorShape) { +#ifndef Q_OS_WINCE + return (HCURSOR)LoadImage(0, s->resource, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED); #else - return (HCURSOR)LoadImage(0, sh, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED); + return LoadCursor(0, s->resource); #endif + } + } + + qWarning("%s: Invalid cursor shape %d", __FUNCTION__, cursorShape); + return 0; } /*! diff --git a/src/plugins/platforms/windows/qwindowscursor.h b/src/plugins/platforms/windows/qwindowscursor.h index 31da4e367d..81ae051824 100644 --- a/src/plugins/platforms/windows/qwindowscursor.h +++ b/src/plugins/platforms/windows/qwindowscursor.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** 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. @@ -105,7 +105,7 @@ public: virtual QPoint pos() const { return mousePosition(); } virtual void setPos(const QPoint &pos); - static HCURSOR createPixmapCursor(const QPixmap &pixmap, int hotX, int hotY); + static HCURSOR createPixmapCursor(const QPixmap &pixmap, const QPoint &hotSpot); static HCURSOR createSystemCursor(const QCursor &c); static QPoint mousePosition(); static CursorState cursorState(); diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp index 60c3daff23..f7d65f211a 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.cpp +++ b/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -490,7 +490,7 @@ void QWindowsOleDropSource::createCursors() newHotSpot = QPoint(qMax(0, hotSpot.x()), qMax(0, hotSpot.y())); } - if (const HCURSOR sysCursor = QWindowsCursor::createPixmapCursor(newPixmap, newHotSpot.x(), newHotSpot.y())) { + if (const HCURSOR sysCursor = QWindowsCursor::createPixmapCursor(newPixmap, newHotSpot)) { const CursorEntry entry(newPixmap, cacheKey, DragCursorHandlePtr(new DragCursorHandle(sysCursor)), newHotSpot); if (it == m_cursors.end()) m_cursors.insert(action, entry); diff --git a/src/plugins/platforms/windows/qwindowseglcontext.cpp b/src/plugins/platforms/windows/qwindowseglcontext.cpp index d5ca06bb3f..6ceddf865c 100644 --- a/src/plugins/platforms/windows/qwindowseglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowseglcontext.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** 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. @@ -46,23 +46,282 @@ #include <QtCore/QDebug> #include <QtGui/QOpenGLContext> -#include <QtPlatformSupport/private/qeglconvenience_p.h> - QT_BEGIN_NAMESPACE /*! \class QWindowsEGLStaticContext \brief Static data for QWindowsEGLContext. - Keeps the display. The class is shared via - QSharedPointer in the windows, the contexts - and in QWindowsIntegration. The display will - be closed if the last instance is deleted. + Keeps the display. The class is shared via QSharedPointer in the windows, the + contexts and in QWindowsIntegration. The display will be closed if the last instance + is deleted. + + No EGL or OpenGL functions are called directly. Instead, they are resolved + dynamically. This works even if the plugin links directly to libegl/libglesv2 so + there is no need to differentiate between dynamic or Angle-only builds in here. \internal \ingroup qt-lighthouse-win */ +QWindowsLibEGL QWindowsEGLStaticContext::libEGL; +QWindowsLibGLESv2 QWindowsEGLStaticContext::libGLESv2; + +#ifdef Q_CC_MINGW +static void *resolveFunc(HMODULE lib, const char *name) +{ + QString baseNameStr = QString::fromLatin1(name); + QString nameStr; + void *proc = 0; + + // Play nice with 32-bit mingw: Try func first, then func@0, func@4, + // func@8, func@12, ..., func@64. The def file does not provide any aliases + // in libEGL and libGLESv2 in these builds which results in exporting + // function names like eglInitialize@12. This cannot be fixed without + // breaking binary compatibility. So be flexible here instead. + + int argSize = -1; + while (!proc && argSize <= 64) { + nameStr = baseNameStr; + if (argSize >= 0) + nameStr += QLatin1Char('@') + QString::number(argSize); + argSize = argSize < 0 ? 0 : argSize + 4; + proc = (void *) ::GetProcAddress(lib, nameStr.toLatin1().constData()); + } + return proc; +} +#else +static void *resolveFunc(HMODULE lib, const char *name) +{ +# ifndef Q_OS_WINCE + return (void *) ::GetProcAddress(lib, name); +# else + return (void *) ::GetProcAddress(lib, (const wchar_t *) QString::fromLatin1(name).utf16()); +# endif // Q_OS_WINCE +} +#endif // Q_CC_MINGW + +void *QWindowsLibEGL::resolve(const char *name) +{ + void *proc = m_lib ? resolveFunc(m_lib, name) : 0; + if (!proc) + qErrnoWarning(::GetLastError(), "Failed to resolve EGL function %s", name); + + return proc; +} + +bool QWindowsLibEGL::init() +{ +#ifdef QT_DEBUG + const char dllName[] = "libEGLd.dll"; +#else + const char dllName[] = "libEGL.dll"; +#endif + + qCDebug(lcQpaGl) << "Qt: Using EGL from" << dllName; + + m_lib = ::LoadLibraryW((const wchar_t *) QString::fromLatin1(dllName).utf16()); + if (!m_lib) { + qErrnoWarning(::GetLastError(), "Failed to load %s", dllName); + return false; + } + + eglGetError = reinterpret_cast<EGLint (EGLAPIENTRY *)(void)>(resolve("eglGetError")); + eglGetDisplay = reinterpret_cast<EGLDisplay (EGLAPIENTRY *)(EGLNativeDisplayType)>(resolve("eglGetDisplay")); + eglInitialize = reinterpret_cast<EGLBoolean (EGLAPIENTRY *)(EGLDisplay, EGLint *, EGLint *)>(resolve("eglInitialize")); + eglTerminate = reinterpret_cast<EGLBoolean (EGLAPIENTRY *)(EGLDisplay)>(resolve("eglTerminate")); + eglChooseConfig = reinterpret_cast<EGLBoolean (EGLAPIENTRY *)(EGLDisplay, const EGLint *, EGLConfig *, EGLint, EGLint *)>(resolve("eglChooseConfig")); + eglGetConfigAttrib = reinterpret_cast<EGLBoolean (EGLAPIENTRY *)(EGLDisplay, EGLConfig, EGLint, EGLint *)>(resolve("eglGetConfigAttrib")); + eglCreateWindowSurface = reinterpret_cast<EGLSurface (EGLAPIENTRY *)(EGLDisplay, EGLConfig, EGLNativeWindowType, const EGLint *)>(resolve("eglCreateWindowSurface")); + eglCreatePbufferSurface = reinterpret_cast<EGLSurface (EGLAPIENTRY *)(EGLDisplay , EGLConfig, const EGLint *)>(resolve("eglCreatePbufferSurface")); + eglDestroySurface = reinterpret_cast<EGLBoolean (EGLAPIENTRY *)(EGLDisplay , EGLSurface )>(resolve("eglDestroySurface")); + eglBindAPI = reinterpret_cast<EGLBoolean (EGLAPIENTRY * )(EGLenum )>(resolve("eglBindAPI")); + eglSwapInterval = reinterpret_cast<EGLBoolean (EGLAPIENTRY *)(EGLDisplay , EGLint )>(resolve("eglSwapInterval")); + eglCreateContext = reinterpret_cast<EGLContext (EGLAPIENTRY *)(EGLDisplay , EGLConfig , EGLContext , const EGLint *)>(resolve("eglCreateContext")); + eglDestroyContext = reinterpret_cast<EGLBoolean (EGLAPIENTRY *)(EGLDisplay, EGLContext)>(resolve("eglDestroyContext")); + eglMakeCurrent = reinterpret_cast<EGLBoolean (EGLAPIENTRY *)(EGLDisplay , EGLSurface , EGLSurface , EGLContext )>(resolve("eglMakeCurrent")); + eglGetCurrentContext = reinterpret_cast<EGLContext (EGLAPIENTRY *)(void)>(resolve("eglGetCurrentContext")); + eglGetCurrentSurface = reinterpret_cast<EGLSurface (EGLAPIENTRY *)(EGLint )>(resolve("eglGetCurrentSurface")); + eglGetCurrentDisplay = reinterpret_cast<EGLDisplay (EGLAPIENTRY *)(void)>(resolve("eglGetCurrentDisplay")); + eglSwapBuffers = reinterpret_cast<EGLBoolean (EGLAPIENTRY *)(EGLDisplay , EGLSurface)>(resolve("eglSwapBuffers")); + eglGetProcAddress = reinterpret_cast<__eglMustCastToProperFunctionPointerType (EGLAPIENTRY * )(const char *)>(resolve("eglGetProcAddress")); + + return eglGetError && eglGetDisplay && eglInitialize; +} + +void *QWindowsLibGLESv2::resolve(const char *name) +{ + void *proc = m_lib ? resolveFunc(m_lib, name) : 0; + if (!proc) + qWarning() << "Failed to resolve OpenGL ES function" << name; + + return proc; +} + +bool QWindowsLibGLESv2::init() +{ +#ifdef QT_DEBUG + const char dllName[] = "libGLESv2d.dll"; +#else + const char dllName[] = "libGLESv2.dll"; +#endif + + qCDebug(lcQpaGl) << "Qt: Using OpenGL ES 2.0 from" << dllName; + + m_lib = ::LoadLibraryW((const wchar_t *) QString::fromLatin1(dllName).utf16()); + if (!m_lib) { + qErrnoWarning(::GetLastError(), "Failed to load %s", dllName); + return false; + } + + glBindTexture = reinterpret_cast<void (APIENTRY *)(GLenum , GLuint )>(resolve("glBindTexture")); + glBlendFunc = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum )>(resolve("glBlendFunc")); + glClear = reinterpret_cast<void (APIENTRY *)(GLbitfield )>(resolve("glClear")); + glClearColor = reinterpret_cast<void (APIENTRY *)(GLfloat , GLfloat , GLfloat , GLfloat )>(resolve("glClearColor")); + glClearStencil = reinterpret_cast<void (APIENTRY *)(GLint )>(resolve("glClearStencil")); + glColorMask = reinterpret_cast<void (APIENTRY *)(GLboolean , GLboolean , GLboolean , GLboolean )>(resolve("glColorMask")); + glCopyTexImage2D = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLenum , GLint , GLint , GLsizei , GLsizei , GLint )>(resolve("glCopyTexImage2D")); + glCopyTexSubImage2D = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLint , GLint , GLint , GLint , GLsizei , GLsizei )>(resolve("glCopyTexSubImage2D")); + glCullFace = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolve("glCullFace")); + glDeleteTextures = reinterpret_cast<void (APIENTRY *)(GLsizei , const GLuint *)>(resolve("glDeleteTextures")); + glDepthFunc = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolve("glDepthFunc")); + glDepthMask = reinterpret_cast<void (APIENTRY *)(GLboolean )>(resolve("glDepthMask")); + glDisable = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolve("glDisable")); + glDrawArrays = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLsizei )>(resolve("glDrawArrays")); + glDrawElements = reinterpret_cast<void (APIENTRY *)(GLenum , GLsizei , GLenum , const GLvoid *)>(resolve("glDrawElements")); + glEnable = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolve("glEnable")); + glFinish = reinterpret_cast<void (APIENTRY *)()>(resolve("glFinish")); + glFlush = reinterpret_cast<void (APIENTRY *)()>(resolve("glFlush")); + glFrontFace = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolve("glFrontFace")); + glGenTextures = reinterpret_cast<void (APIENTRY *)(GLsizei , GLuint *)>(resolve("glGenTextures")); + glGetBooleanv = reinterpret_cast<void (APIENTRY *)(GLenum , GLboolean *)>(resolve("glGetBooleanv")); + glGetError = reinterpret_cast<GLenum (APIENTRY *)()>(resolve("glGetError")); + glGetFloatv = reinterpret_cast<void (APIENTRY *)(GLenum , GLfloat *)>(resolve("glGetFloatv")); + glGetIntegerv = reinterpret_cast<void (APIENTRY *)(GLenum , GLint *)>(resolve("glGetIntegerv")); + glGetString = reinterpret_cast<const GLubyte * (APIENTRY *)(GLenum )>(resolve("glGetString")); + glGetTexParameterfv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLfloat *)>(resolve("glGetTexParameterfv")); + glGetTexParameteriv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLint *)>(resolve("glGetTexParameteriv")); + glHint = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum )>(resolve("glHint")); + glIsEnabled = reinterpret_cast<GLboolean (APIENTRY *)(GLenum )>(resolve("glIsEnabled")); + glIsTexture = reinterpret_cast<GLboolean (APIENTRY *)(GLuint )>(resolve("glIsTexture")); + glLineWidth = reinterpret_cast<void (APIENTRY *)(GLfloat )>(resolve("glLineWidth")); + glPixelStorei = reinterpret_cast<void (APIENTRY *)(GLenum , GLint )>(resolve("glPixelStorei")); + glPolygonOffset = reinterpret_cast<void (APIENTRY *)(GLfloat , GLfloat )>(resolve("glPolygonOffset")); + glReadPixels = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLsizei , GLsizei , GLenum , GLenum , GLvoid *)>(resolve("glReadPixels")); + glScissor = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLsizei , GLsizei )>(resolve("glScissor")); + glStencilFunc = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLuint )>(resolve("glStencilFunc")); + glStencilMask = reinterpret_cast<void (APIENTRY *)(GLuint )>(resolve("glStencilMask")); + glStencilOp = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLenum )>(resolve("glStencilOp")); + glTexImage2D = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLint , GLsizei , GLsizei , GLint , GLenum , GLenum , const GLvoid *)>(resolve("glTexImage2D")); + glTexParameterf = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLfloat )>(resolve("glTexParameterf")); + glTexParameterfv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , const GLfloat *)>(resolve("glTexParameterfv")); + glTexParameteri = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLint )>(resolve("glTexParameteri")); + glTexParameteriv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , const GLint *)>(resolve("glTexParameteriv")); + glTexSubImage2D = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLint , GLint , GLsizei , GLsizei , GLenum , GLenum , const GLvoid *)>(resolve("glTexSubImage2D")); + glViewport = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLsizei , GLsizei )>(resolve("glViewport")); + + glActiveTexture = reinterpret_cast<void (APIENTRY *)(GLenum)>(resolve("glActiveTexture")); + glAttachShader = reinterpret_cast<void (APIENTRY *)(GLuint , GLuint )>(resolve("glAttachShader")); + glBindAttribLocation = reinterpret_cast<void (APIENTRY *)(GLuint , GLuint , const GLchar* )>(resolve("glBindAttribLocation")); + glBindBuffer = reinterpret_cast<void (APIENTRY *)(GLenum , GLuint )>(resolve("glBindBuffer")); + glBindFramebuffer = reinterpret_cast<void (APIENTRY *)(GLenum , GLuint )>(resolve("glBindFramebuffer")); + glBindRenderbuffer = reinterpret_cast<void (APIENTRY *)(GLenum , GLuint )>(resolve("glBindRenderbuffer")); + glBlendColor = reinterpret_cast<void (APIENTRY *)(GLclampf , GLclampf , GLclampf , GLclampf )>(resolve("glBlendColor")); + glBlendEquation = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolve("glBlendEquation")); + glBlendEquationSeparate = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum )>(resolve("glBlendEquationSeparate")); + glBlendFuncSeparate = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLenum , GLenum )>(resolve("glBlendFuncSeparate")); + glBufferData = reinterpret_cast<void (APIENTRY *)(GLenum , qopengl_GLsizeiptr , const GLvoid* , GLenum )>(resolve("glBufferData")); + glBufferSubData = reinterpret_cast<void (APIENTRY *)(GLenum , qopengl_GLintptr , qopengl_GLsizeiptr , const GLvoid* )>(resolve("glBufferSubData")); + glCheckFramebufferStatus = reinterpret_cast<GLenum (APIENTRY *)(GLenum )>(resolve("glCheckFramebufferStatus")); + glCompileShader = reinterpret_cast<void (APIENTRY *)(GLuint )>(resolve("glCompileShader")); + glCompressedTexImage2D = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLenum , GLsizei , GLsizei, GLint, GLsizei, const GLvoid* )>(resolve("glCompressedTexImage2D")); + glCompressedTexSubImage2D = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLint , GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid* )>(resolve("glCompressedTexSubImage2D")); + glCreateProgram = reinterpret_cast<GLuint (APIENTRY *)(void)>(resolve("glCreateProgram")); + glCreateShader = reinterpret_cast<GLuint (APIENTRY *)(GLenum )>(resolve("glCreateShader")); + glDeleteBuffers = reinterpret_cast<void (APIENTRY *)(GLsizei , const GLuint*)>(resolve("glDeleteBuffers")); + glDeleteFramebuffers = reinterpret_cast<void (APIENTRY *)(GLsizei , const GLuint* )>(resolve("glDeleteFramebuffers")); + glDeleteProgram = reinterpret_cast<void (APIENTRY *)(GLuint )>(resolve("glDeleteProgram")); + glDeleteRenderbuffers = reinterpret_cast<void (APIENTRY *)(GLsizei , const GLuint* )>(resolve("glDeleteRenderbuffers")); + glDeleteShader = reinterpret_cast<void (APIENTRY *)(GLuint )>(resolve("glDeleteShader")); + glDetachShader = reinterpret_cast<void (APIENTRY *)(GLuint , GLuint )>(resolve("glDetachShader")); + glDisableVertexAttribArray = reinterpret_cast<void (APIENTRY *)(GLuint )>(resolve("glDisableVertexAttribArray")); + glEnableVertexAttribArray = reinterpret_cast<void (APIENTRY *)(GLuint )>(resolve("glEnableVertexAttribArray")); + glFramebufferRenderbuffer = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLenum , GLuint )>(resolve("glFramebufferRenderbuffer")); + glFramebufferTexture2D = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLenum , GLuint , GLint )>(resolve("glFramebufferTexture2D")); + glGenBuffers = reinterpret_cast<void (APIENTRY *)(GLsizei , GLuint* )>(resolve("glGenBuffers")); + glGenerateMipmap = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolve("glGenerateMipmap")); + glGenFramebuffers = reinterpret_cast<void (APIENTRY *)(GLsizei , GLuint* )>(resolve("glGenFramebuffers")); + glGenRenderbuffers = reinterpret_cast<void (APIENTRY *)(GLsizei , GLuint* )>(resolve("glGenRenderbuffers")); + glGetActiveAttrib = reinterpret_cast<void (APIENTRY *)(GLuint , GLuint , GLsizei , GLsizei* , GLint* , GLenum* , GLchar* )>(resolve("glGetActiveAttrib")); + glGetActiveUniform = reinterpret_cast<void (APIENTRY *)(GLuint , GLuint , GLsizei , GLsizei* , GLint* , GLenum* , GLchar* )>(resolve("glGetActiveUniform")); + glGetAttachedShaders = reinterpret_cast<void (APIENTRY *)(GLuint , GLsizei , GLsizei*, GLuint* )>(resolve("glGetAttachedShaders")); + glGetAttribLocation = reinterpret_cast<int (APIENTRY *)(GLuint , const GLchar* )>(resolve("glGetAttribLocation")); + glGetBufferParameteriv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLint* )>(resolve("glGetBufferParameteriv")); + glGetFramebufferAttachmentParameteriv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum, GLenum , GLint* )>(resolve("glGetFramebufferAttachmentParameteriv")); + glGetProgramiv = reinterpret_cast<void (APIENTRY *)(GLuint , GLenum , GLint* )>(resolve("glGetProgramiv")); + glGetProgramInfoLog = reinterpret_cast<void (APIENTRY *)(GLuint , GLsizei , GLsizei* , GLchar* )>(resolve("glGetProgramInfoLog")); + glGetRenderbufferParameteriv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLint* )>(resolve("glGetRenderbufferParameteriv")); + glGetShaderiv = reinterpret_cast<void (APIENTRY *)(GLuint , GLenum , GLint* )>(resolve("glGetShaderiv")); + glGetShaderInfoLog = reinterpret_cast<void (APIENTRY *)(GLuint , GLsizei , GLsizei*, GLchar*)>(resolve("glGetShaderInfoLog")); + glGetShaderPrecisionFormat = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLint* , GLint* )>(resolve("glGetShaderPrecisionFormat")); + glGetShaderSource = reinterpret_cast<void (APIENTRY *)(GLuint , GLsizei , GLsizei* , GLchar* )>(resolve("glGetShaderSource")); + glGetUniformfv = reinterpret_cast<void (APIENTRY *)(GLuint , GLint , GLfloat*)>(resolve("glGetUniformfv")); + glGetUniformiv = reinterpret_cast<void (APIENTRY *)(GLuint , GLint , GLint*)>(resolve("glGetUniformiv")); + glGetUniformLocation = reinterpret_cast<int (APIENTRY *)(GLuint , const GLchar* )>(resolve("glGetUniformLocation")); + glGetVertexAttribfv = reinterpret_cast<void (APIENTRY *)(GLuint , GLenum , GLfloat* )>(resolve("glGetVertexAttribfv")); + glGetVertexAttribiv = reinterpret_cast<void (APIENTRY *)(GLuint , GLenum , GLint* )>(resolve("glGetVertexAttribiv")); + glGetVertexAttribPointerv = reinterpret_cast<void (APIENTRY *)(GLuint , GLenum , GLvoid** pointer)>(resolve("glGetVertexAttribPointerv")); + glIsBuffer = reinterpret_cast<GLboolean (APIENTRY *)(GLuint )>(resolve("glIsBuffer")); + glIsFramebuffer = reinterpret_cast<GLboolean (APIENTRY *)(GLuint )>(resolve("glIsFramebuffer")); + glIsProgram = reinterpret_cast<GLboolean (APIENTRY *)(GLuint )>(resolve("glIsProgram")); + glIsRenderbuffer = reinterpret_cast<GLboolean (APIENTRY *)(GLuint )>(resolve("glIsRenderbuffer")); + glIsShader = reinterpret_cast<GLboolean (APIENTRY *)(GLuint )>(resolve("glIsShader")); + glLinkProgram = reinterpret_cast<void (APIENTRY *)(GLuint )>(resolve("glLinkProgram")); + glReleaseShaderCompiler = reinterpret_cast<void (APIENTRY *)(void)>(resolve("glReleaseShaderCompiler")); + glRenderbufferStorage = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLsizei , GLsizei )>(resolve("glRenderbufferStorage")); + glSampleCoverage = reinterpret_cast<void (APIENTRY *)(GLclampf , GLboolean )>(resolve("glSampleCoverage")); + glShaderBinary = reinterpret_cast<void (APIENTRY *)(GLsizei , const GLuint*, GLenum , const GLvoid* , GLsizei )>(resolve("glShaderBinary")); + glShaderSource = reinterpret_cast<void (APIENTRY *)(GLuint , GLsizei , const GLchar* *, const GLint* )>(resolve("glShaderSource")); + glStencilFuncSeparate = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLint , GLuint )>(resolve("glStencilFuncSeparate")); + glStencilMaskSeparate = reinterpret_cast<void (APIENTRY *)(GLenum , GLuint )>(resolve("glStencilMaskSeparate")); + glStencilOpSeparate = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLenum , GLenum )>(resolve("glStencilOpSeparate")); + glUniform1f = reinterpret_cast<void (APIENTRY *)(GLint , GLfloat )>(resolve("glUniform1f")); + glUniform1fv = reinterpret_cast<void (APIENTRY *)(GLint , GLsizei , const GLfloat* )>(resolve("glUniform1fv")); + glUniform1i = reinterpret_cast<void (APIENTRY *)(GLint , GLint )>(resolve("glUniform1i")); + glUniform1iv = reinterpret_cast<void (APIENTRY *)(GLint , GLsizei , const GLint* )>(resolve("glUniform1iv")); + glUniform2f = reinterpret_cast<void (APIENTRY *)(GLint , GLfloat , GLfloat )>(resolve("glUniform2f")); + glUniform2fv = reinterpret_cast<void (APIENTRY *)(GLint , GLsizei , const GLfloat* )>(resolve("glUniform2fv")); + glUniform2i = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLint )>(resolve("glUniform2i")); + glUniform2iv = reinterpret_cast<void (APIENTRY *)(GLint , GLsizei , const GLint* )>(resolve("glUniform2iv")); + glUniform3f = reinterpret_cast<void (APIENTRY *)(GLint , GLfloat , GLfloat , GLfloat )>(resolve("glUniform3f")); + glUniform3fv = reinterpret_cast<void (APIENTRY *)(GLint , GLsizei , const GLfloat* )>(resolve("glUniform3fv")); + glUniform3i = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLint , GLint )>(resolve("glUniform3i")); + glUniform3iv = reinterpret_cast<void (APIENTRY *)(GLint , GLsizei , const GLint* )>(resolve("glUniform3iv")); + glUniform4f = reinterpret_cast<void (APIENTRY *)(GLint , GLfloat , GLfloat , GLfloat , GLfloat )>(resolve("glUniform4f")); + glUniform4fv = reinterpret_cast<void (APIENTRY *)(GLint , GLsizei , const GLfloat* )>(resolve("glUniform4fv")); + glUniform4i = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLint , GLint , GLint )>(resolve("glUniform4i")); + glUniform4iv = reinterpret_cast<void (APIENTRY *)(GLint , GLsizei , const GLint* )>(resolve("glUniform4iv")); + glUniformMatrix2fv = reinterpret_cast<void (APIENTRY *)(GLint , GLsizei , GLboolean , const GLfloat* )>(resolve("glUniformMatrix2fv")); + glUniformMatrix3fv = reinterpret_cast<void (APIENTRY *)(GLint , GLsizei , GLboolean , const GLfloat* )>(resolve("glUniformMatrix3fv")); + glUniformMatrix4fv = reinterpret_cast<void (APIENTRY *)(GLint , GLsizei , GLboolean , const GLfloat* )>(resolve("glUniformMatrix4fv")); + glUseProgram = reinterpret_cast<void (APIENTRY *)(GLuint )>(resolve("glUseProgram")); + glValidateProgram = reinterpret_cast<void (APIENTRY *)(GLuint )>(resolve("glValidateProgram")); + glVertexAttrib1f = reinterpret_cast<void (APIENTRY *)(GLuint , GLfloat )>(resolve("glVertexAttrib1f")); + glVertexAttrib1fv = reinterpret_cast<void (APIENTRY *)(GLuint , const GLfloat* )>(resolve("glVertexAttrib1fv")); + glVertexAttrib2f = reinterpret_cast<void (APIENTRY *)(GLuint , GLfloat , GLfloat )>(resolve("glVertexAttrib2f")); + glVertexAttrib2fv = reinterpret_cast<void (APIENTRY *)(GLuint , const GLfloat* )>(resolve("glVertexAttrib2fv")); + glVertexAttrib3f = reinterpret_cast<void (APIENTRY *)(GLuint , GLfloat , GLfloat , GLfloat )>(resolve("glVertexAttrib3f")); + glVertexAttrib3fv = reinterpret_cast<void (APIENTRY *)(GLuint , const GLfloat* )>(resolve("glVertexAttrib3fv")); + glVertexAttrib4f = reinterpret_cast<void (APIENTRY *)(GLuint , GLfloat , GLfloat , GLfloat , GLfloat )>(resolve("glVertexAttrib4f")); + glVertexAttrib4fv = reinterpret_cast<void (APIENTRY *)(GLuint , const GLfloat* )>(resolve("glVertexAttrib4fv")); + glVertexAttribPointer = reinterpret_cast<void (APIENTRY *)(GLuint , GLint, GLenum, GLboolean, GLsizei, const GLvoid* )>(resolve("glVertexAttribPointer")); + + glClearDepthf = reinterpret_cast<void (APIENTRY *)(GLclampf )>(resolve("glClearDepthf")); + glDepthRangef = reinterpret_cast<void (APIENTRY *)(GLclampf , GLclampf )>(resolve("glDepthRangef")); + + return glBindTexture && glCreateShader && glClearDepthf; +} + QWindowsEGLStaticContext::QWindowsEGLStaticContext(EGLDisplay display, int version) : m_display(display), m_version(version) { @@ -76,7 +335,16 @@ QWindowsEGLStaticContext *QWindowsEGLStaticContext::create() return 0; } - EGLDisplay display = eglGetDisplay((EGLNativeDisplayType)dc); + if (!libEGL.init()) { + qWarning("%s: Failed to load and resolve libEGL functions", Q_FUNC_INFO); + return 0; + } + if (!libGLESv2.init()) { + qWarning("%s: Failed to load and resolve libGLESv2 functions", Q_FUNC_INFO); + return 0; + } + + EGLDisplay display = libEGL.eglGetDisplay((EGLNativeDisplayType)dc); if (!display) { qWarning("%s: Could not obtain EGL display", Q_FUNC_INFO); return 0; @@ -84,9 +352,11 @@ QWindowsEGLStaticContext *QWindowsEGLStaticContext::create() EGLint major; EGLint minor; - if (!eglInitialize(display, &major, &minor)) { - qWarning("%s: Could not initialize egl display: error %d\n", - Q_FUNC_INFO, eglGetError()); + if (!libEGL.eglInitialize(display, &major, &minor)) { + int err = libEGL.eglGetError(); + qWarning("%s: Could not initialize EGL display: error 0x%x\n", Q_FUNC_INFO, err); + if (err == 0x3001) + qWarning("%s: When using ANGLE, check if d3dcompiler_4x.dll is available", Q_FUNC_INFO); return 0; } @@ -97,7 +367,70 @@ QWindowsEGLStaticContext *QWindowsEGLStaticContext::create() QWindowsEGLStaticContext::~QWindowsEGLStaticContext() { qCDebug(lcQpaGl) << __FUNCTION__ << "Releasing EGL display " << m_display; - eglTerminate(m_display); + libEGL.eglTerminate(m_display); +} + +QWindowsOpenGLContext *QWindowsEGLStaticContext::createContext(QOpenGLContext *context) +{ + return new QWindowsEGLContext(this, context->format(), context->shareHandle()); +} + +void *QWindowsEGLStaticContext::createWindowSurface(void *nativeWindow, void *nativeConfig) +{ + EGLSurface surface = libEGL.eglCreateWindowSurface(m_display, (EGLConfig) nativeConfig, + (EGLNativeWindowType) nativeWindow, 0); + if (surface == EGL_NO_SURFACE) + qWarning("%s: Could not create the EGL window surface: 0x%x\n", Q_FUNC_INFO, libEGL.eglGetError()); + + return surface; +} + +void QWindowsEGLStaticContext::destroyWindowSurface(void *nativeSurface) +{ + libEGL.eglDestroySurface(m_display, (EGLSurface) nativeSurface); +} + +QSurfaceFormat QWindowsEGLStaticContext::formatFromConfig(EGLDisplay display, EGLConfig config, + const QSurfaceFormat &referenceFormat) +{ + QSurfaceFormat format; + EGLint redSize = 0; + EGLint greenSize = 0; + EGLint blueSize = 0; + EGLint alphaSize = 0; + EGLint depthSize = 0; + EGLint stencilSize = 0; + EGLint sampleCount = 0; + + libEGL.eglGetConfigAttrib(display, config, EGL_RED_SIZE, &redSize); + libEGL.eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &greenSize); + libEGL.eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &blueSize); + libEGL.eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &alphaSize); + libEGL.eglGetConfigAttrib(display, config, EGL_DEPTH_SIZE, &depthSize); + libEGL.eglGetConfigAttrib(display, config, EGL_STENCIL_SIZE, &stencilSize); + libEGL.eglGetConfigAttrib(display, config, EGL_SAMPLES, &sampleCount); + + format.setRenderableType(QSurfaceFormat::OpenGLES); + format.setVersion(referenceFormat.majorVersion(), referenceFormat.minorVersion()); + format.setProfile(referenceFormat.profile()); + format.setOptions(referenceFormat.options()); + + format.setRedBufferSize(redSize); + format.setGreenBufferSize(greenSize); + format.setBlueBufferSize(blueSize); + format.setAlphaBufferSize(alphaSize); + format.setDepthBufferSize(depthSize); + format.setStencilBufferSize(stencilSize); + format.setSamples(sampleCount); + format.setStereo(false); + format.setSwapInterval(referenceFormat.swapInterval()); + + // Clear the EGL error state because some of the above may + // have errored out because the attribute is not applicable + // to the surface type. Such errors don't matter. + libEGL.eglGetError(); + + return format; } /*! @@ -121,40 +454,465 @@ QWindowsEGLStaticContext::~QWindowsEGLStaticContext() \ingroup qt-lighthouse-win */ -QWindowsEGLContext::QWindowsEGLContext(const QWindowsEGLStaticContextPtr &staticContext, +QWindowsEGLContext::QWindowsEGLContext(QWindowsEGLStaticContext *staticContext, const QSurfaceFormat &format, QPlatformOpenGLContext *share) - : QEGLPlatformContext(format, share, staticContext->display()) - , m_staticContext(staticContext) + : m_staticContext(staticContext) + , m_eglDisplay(staticContext->display()) + , m_api(EGL_OPENGL_ES_API) + , m_swapInterval(-1) { + if (!m_staticContext) + return; + + m_eglConfig = chooseConfig(format); + m_format = m_staticContext->formatFromConfig(m_eglDisplay, m_eglConfig, format); + m_shareContext = share ? static_cast<QWindowsEGLContext *>(share)->m_eglContext : 0; + + QVector<EGLint> contextAttrs; + contextAttrs.append(EGL_CONTEXT_CLIENT_VERSION); + contextAttrs.append(m_format.majorVersion()); + contextAttrs.append(EGL_NONE); + + QWindowsEGLStaticContext::libEGL.eglBindAPI(m_api); + m_eglContext = QWindowsEGLStaticContext::libEGL.eglCreateContext(m_eglDisplay, m_eglConfig, m_shareContext, contextAttrs.constData()); + if (m_eglContext == EGL_NO_CONTEXT && m_shareContext != EGL_NO_CONTEXT) { + m_shareContext = 0; + m_eglContext = QWindowsEGLStaticContext::libEGL.eglCreateContext(m_eglDisplay, m_eglConfig, 0, contextAttrs.constData()); + } + + if (m_eglContext == EGL_NO_CONTEXT) { + qWarning("QWindowsEGLContext: eglError: %x, this: %p \n", QWindowsEGLStaticContext::libEGL.eglGetError(), this); + return; + } + + // Make the context current to ensure the GL version query works. This needs a surface too. + const EGLint pbufferAttributes[] = { + EGL_WIDTH, 1, + EGL_HEIGHT, 1, + EGL_LARGEST_PBUFFER, EGL_FALSE, + EGL_NONE + }; + EGLSurface pbuffer = QWindowsEGLStaticContext::libEGL.eglCreatePbufferSurface(m_eglDisplay, m_eglConfig, pbufferAttributes); + if (pbuffer == EGL_NO_SURFACE) + return; + + if (QWindowsEGLStaticContext::libEGL.eglMakeCurrent(m_eglDisplay, pbuffer, pbuffer, m_eglContext)) { + const GLubyte *s = QWindowsEGLStaticContext::libGLESv2.glGetString(GL_VERSION); + if (s) { + QByteArray version = QByteArray(reinterpret_cast<const char *>(s)); + int major, minor; + if (QPlatformOpenGLContext::parseOpenGLVersion(version, major, minor)) { + m_format.setMajorVersion(major); + m_format.setMinorVersion(minor); + } + } + m_format.setProfile(QSurfaceFormat::NoProfile); + m_format.setOptions(QSurfaceFormat::FormatOptions()); + QWindowsEGLStaticContext::libEGL.eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + } + QWindowsEGLStaticContext::libEGL.eglDestroySurface(m_eglDisplay, pbuffer); } QWindowsEGLContext::~QWindowsEGLContext() { + if (m_eglContext != EGL_NO_CONTEXT) { + QWindowsEGLStaticContext::libEGL.eglDestroyContext(m_eglDisplay, m_eglContext); + m_eglContext = EGL_NO_CONTEXT; + } } -bool QWindowsEGLContext::hasThreadedOpenGLCapability() +bool QWindowsEGLContext::makeCurrent(QPlatformSurface *surface) { - return false; + Q_ASSERT(surface->surface()->supportsOpenGL()); + + QWindowsEGLStaticContext::libEGL.eglBindAPI(m_api); + + QWindowsWindow *window = static_cast<QWindowsWindow *>(surface); + EGLSurface eglSurface = static_cast<EGLSurface>(window->surface(m_eglConfig)); + Q_ASSERT(eglSurface); + + // shortcut: on some GPUs, eglMakeCurrent is not a cheap operation + if (QWindowsEGLStaticContext::libEGL.eglGetCurrentContext() == m_eglContext && + QWindowsEGLStaticContext::libEGL.eglGetCurrentDisplay() == m_eglDisplay && + QWindowsEGLStaticContext::libEGL.eglGetCurrentSurface(EGL_READ) == eglSurface && + QWindowsEGLStaticContext::libEGL.eglGetCurrentSurface(EGL_DRAW) == eglSurface) { + return true; + } + + const bool ok = QWindowsEGLStaticContext::libEGL.eglMakeCurrent(m_eglDisplay, eglSurface, eglSurface, m_eglContext); + if (ok) { + const int requestedSwapInterval = surface->format().swapInterval(); + if (requestedSwapInterval >= 0 && m_swapInterval != requestedSwapInterval) { + m_swapInterval = requestedSwapInterval; + QWindowsEGLStaticContext::libEGL.eglSwapInterval(m_staticContext->display(), m_swapInterval); + } + } else { + qWarning("QWindowsEGLContext::makeCurrent: eglError: %x, this: %p \n", QWindowsEGLStaticContext::libEGL.eglGetError(), this); + } + + return ok; } -EGLSurface QWindowsEGLContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface) +void QWindowsEGLContext::doneCurrent() { - const QWindowsWindow *window = static_cast<const QWindowsWindow *>(surface); - return window->eglSurfaceHandle(); + QWindowsEGLStaticContext::libEGL.eglBindAPI(m_api); + bool ok = QWindowsEGLStaticContext::libEGL.eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (!ok) + qWarning("QWindowsEGLContext::doneCurrent: eglError: %d, this: %p \n", QWindowsEGLStaticContext::libEGL.eglGetError(), this); } -bool QWindowsEGLContext::makeCurrent(QPlatformSurface *surface) +void QWindowsEGLContext::swapBuffers(QPlatformSurface *surface) { - bool ok = false; + QWindowsEGLStaticContext::libEGL.eglBindAPI(m_api); QWindowsWindow *window = static_cast<QWindowsWindow *>(surface); - if (EGLSurface eglSurface = window->ensureEglSurfaceHandle(m_staticContext, eglConfig())) { - ok = eglMakeCurrent(eglDisplay(), eglSurface, eglSurface, eglContext()); - if (!ok) - qWarning("%s: eglMakeCurrent() failed, eglError: 0x%x, this: %p \n", - Q_FUNC_INFO, eglGetError(), this); + EGLSurface eglSurface = static_cast<EGLSurface>(window->surface(m_eglConfig)); + Q_ASSERT(eglSurface); + + bool ok = QWindowsEGLStaticContext::libEGL.eglSwapBuffers(m_eglDisplay, eglSurface); + if (!ok) + qWarning("QWindowsEGLContext::swapBuffers: eglError: %d, this: %p \n", QWindowsEGLStaticContext::libEGL.eglGetError(), this); +} + +QFunctionPointer QWindowsEGLContext::getProcAddress(const QByteArray &procName) +{ + // We support AllGLFunctionsQueryable, which means this function must be able to + // return a function pointer for standard GLES2 functions too. These are not + // guaranteed to be queryable via eglGetProcAddress(). + static struct StdFunc { + const char *name; + void *func; + } standardFuncs[] = { + { "glBindTexture", (void *) QWindowsEGLStaticContext::libGLESv2.glBindTexture }, + { "glBlendFunc", (void *) QWindowsEGLStaticContext::libGLESv2.glBlendFunc }, + { "glClear", (void *) QWindowsEGLStaticContext::libGLESv2.glClear }, + { "glClearColor", (void *) QWindowsEGLStaticContext::libGLESv2.glClearColor }, + { "glClearStencil", (void *) QWindowsEGLStaticContext::libGLESv2.glClearStencil }, + { "glColorMask", (void *) QWindowsEGLStaticContext::libGLESv2.glColorMask }, + { "glCopyTexImage2D", (void *) QWindowsEGLStaticContext::libGLESv2.glCopyTexImage2D }, + { "glCopyTexSubImage2D", (void *) QWindowsEGLStaticContext::libGLESv2.glCopyTexSubImage2D }, + { "glCullFace", (void *) QWindowsEGLStaticContext::libGLESv2.glCullFace }, + { "glDeleteTextures", (void *) QWindowsEGLStaticContext::libGLESv2.glDeleteTextures }, + { "glDepthFunc", (void *) QWindowsEGLStaticContext::libGLESv2.glDepthFunc }, + { "glDepthMask", (void *) QWindowsEGLStaticContext::libGLESv2.glDepthMask }, + { "glDisable", (void *) QWindowsEGLStaticContext::libGLESv2.glDisable }, + { "glDrawArrays", (void *) QWindowsEGLStaticContext::libGLESv2.glDrawArrays }, + { "glDrawElements", (void *) QWindowsEGLStaticContext::libGLESv2.glDrawElements }, + { "glEnable", (void *) QWindowsEGLStaticContext::libGLESv2.glEnable }, + { "glFinish", (void *) QWindowsEGLStaticContext::libGLESv2.glFinish }, + { "glFlush", (void *) QWindowsEGLStaticContext::libGLESv2.glFlush }, + { "glFrontFace", (void *) QWindowsEGLStaticContext::libGLESv2.glFrontFace }, + { "glGenTextures", (void *) QWindowsEGLStaticContext::libGLESv2.glGenTextures }, + { "glGetBooleanv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetBooleanv }, + { "glGetError", (void *) QWindowsEGLStaticContext::libGLESv2.glGetError }, + { "glGetFloatv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetFloatv }, + { "glGetIntegerv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetIntegerv }, + { "glGetString", (void *) QWindowsEGLStaticContext::libGLESv2.glGetString }, + { "glGetTexParameterfv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetTexParameterfv }, + { "glGetTexParameteriv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetTexParameteriv }, + { "glHint", (void *) QWindowsEGLStaticContext::libGLESv2.glHint }, + { "glIsEnabled", (void *) QWindowsEGLStaticContext::libGLESv2.glIsEnabled }, + { "glIsTexture", (void *) QWindowsEGLStaticContext::libGLESv2.glIsTexture }, + { "glLineWidth", (void *) QWindowsEGLStaticContext::libGLESv2.glLineWidth }, + { "glPixelStorei", (void *) QWindowsEGLStaticContext::libGLESv2.glPixelStorei }, + { "glPolygonOffset", (void *) QWindowsEGLStaticContext::libGLESv2.glPolygonOffset }, + { "glReadPixels", (void *) QWindowsEGLStaticContext::libGLESv2.glReadPixels }, + { "glScissor", (void *) QWindowsEGLStaticContext::libGLESv2.glScissor }, + { "glStencilFunc", (void *) QWindowsEGLStaticContext::libGLESv2.glStencilFunc }, + { "glStencilMask", (void *) QWindowsEGLStaticContext::libGLESv2.glStencilMask }, + { "glStencilOp", (void *) QWindowsEGLStaticContext::libGLESv2.glStencilOp }, + { "glTexImage2D", (void *) QWindowsEGLStaticContext::libGLESv2.glTexImage2D }, + { "glTexParameterf", (void *) QWindowsEGLStaticContext::libGLESv2.glTexParameterf }, + { "glTexParameterfv", (void *) QWindowsEGLStaticContext::libGLESv2.glTexParameterfv }, + { "glTexParameteri", (void *) QWindowsEGLStaticContext::libGLESv2.glTexParameteri }, + { "glTexParameteriv", (void *) QWindowsEGLStaticContext::libGLESv2.glTexParameteriv }, + { "glTexSubImage2D", (void *) QWindowsEGLStaticContext::libGLESv2.glTexSubImage2D }, + { "glViewport", (void *) QWindowsEGLStaticContext::libGLESv2.glViewport }, + + { "glActiveTexture", (void *) QWindowsEGLStaticContext::libGLESv2.glActiveTexture }, + { "glAttachShader", (void *) QWindowsEGLStaticContext::libGLESv2.glAttachShader }, + { "glBindAttribLocation", (void *) QWindowsEGLStaticContext::libGLESv2.glBindAttribLocation }, + { "glBindBuffer", (void *) QWindowsEGLStaticContext::libGLESv2.glBindBuffer }, + { "glBindFramebuffer", (void *) QWindowsEGLStaticContext::libGLESv2.glBindFramebuffer }, + { "glBindRenderbuffer", (void *) QWindowsEGLStaticContext::libGLESv2.glBindRenderbuffer }, + { "glBlendColor", (void *) QWindowsEGLStaticContext::libGLESv2.glBlendColor }, + { "glBlendEquation", (void *) QWindowsEGLStaticContext::libGLESv2.glBlendEquation }, + { "glBlendEquationSeparate", (void *) QWindowsEGLStaticContext::libGLESv2.glBlendEquationSeparate }, + { "glBlendFuncSeparate", (void *) QWindowsEGLStaticContext::libGLESv2.glBlendFuncSeparate }, + { "glBufferData", (void *) QWindowsEGLStaticContext::libGLESv2.glBufferData }, + { "glBufferSubData", (void *) QWindowsEGLStaticContext::libGLESv2.glBufferSubData }, + { "glCheckFramebufferStatus", (void *) QWindowsEGLStaticContext::libGLESv2.glCheckFramebufferStatus }, + { "glCompileShader", (void *) QWindowsEGLStaticContext::libGLESv2.glCompileShader }, + { "glCompressedTexImage2D", (void *) QWindowsEGLStaticContext::libGLESv2.glCompressedTexImage2D }, + { "glCompressedTexSubImage2D", (void *) QWindowsEGLStaticContext::libGLESv2.glCompressedTexSubImage2D }, + { "glCreateProgram", (void *) QWindowsEGLStaticContext::libGLESv2.glCreateProgram }, + { "glCreateShader", (void *) QWindowsEGLStaticContext::libGLESv2.glCreateShader }, + { "glDeleteBuffers", (void *) QWindowsEGLStaticContext::libGLESv2.glDeleteBuffers }, + { "glDeleteFramebuffers", (void *) QWindowsEGLStaticContext::libGLESv2.glDeleteFramebuffers }, + { "glDeleteProgram", (void *) QWindowsEGLStaticContext::libGLESv2.glDeleteProgram }, + { "glDeleteRenderbuffers", (void *) QWindowsEGLStaticContext::libGLESv2.glDeleteRenderbuffers }, + { "glDeleteShader", (void *) QWindowsEGLStaticContext::libGLESv2.glDeleteShader }, + { "glDetachShader", (void *) QWindowsEGLStaticContext::libGLESv2.glDetachShader }, + { "glDisableVertexAttribArray", (void *) QWindowsEGLStaticContext::libGLESv2.glDisableVertexAttribArray }, + { "glEnableVertexAttribArray", (void *) QWindowsEGLStaticContext::libGLESv2.glEnableVertexAttribArray }, + { "glFramebufferRenderbuffer", (void *) QWindowsEGLStaticContext::libGLESv2.glFramebufferRenderbuffer }, + { "glFramebufferTexture2D", (void *) QWindowsEGLStaticContext::libGLESv2.glFramebufferTexture2D }, + { "glGenBuffers", (void *) QWindowsEGLStaticContext::libGLESv2.glGenBuffers }, + { "glGenerateMipmap", (void *) QWindowsEGLStaticContext::libGLESv2.glGenerateMipmap }, + { "glGenFramebuffers", (void *) QWindowsEGLStaticContext::libGLESv2.glGenFramebuffers }, + { "glGenRenderbuffers", (void *) QWindowsEGLStaticContext::libGLESv2.glGenRenderbuffers }, + { "glGetActiveAttrib", (void *) QWindowsEGLStaticContext::libGLESv2.glGetActiveAttrib }, + { "glGetActiveUniform", (void *) QWindowsEGLStaticContext::libGLESv2.glGetActiveUniform }, + { "glGetAttachedShaders", (void *) QWindowsEGLStaticContext::libGLESv2.glGetAttachedShaders }, + { "glGetAttribLocation", (void *) QWindowsEGLStaticContext::libGLESv2.glGetAttribLocation }, + { "glGetBufferParameteriv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetBufferParameteriv }, + { "glGetFramebufferAttachmentParameteriv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetFramebufferAttachmentParameteriv }, + { "glGetProgramiv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetProgramiv }, + { "glGetProgramInfoLog", (void *) QWindowsEGLStaticContext::libGLESv2.glGetProgramInfoLog }, + { "glGetRenderbufferParameteriv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetRenderbufferParameteriv }, + { "glGetShaderiv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetShaderiv }, + { "glGetShaderInfoLog", (void *) QWindowsEGLStaticContext::libGLESv2.glGetShaderInfoLog }, + { "glGetShaderPrecisionFormat", (void *) QWindowsEGLStaticContext::libGLESv2.glGetShaderPrecisionFormat }, + { "glGetShaderSource", (void *) QWindowsEGLStaticContext::libGLESv2.glGetShaderSource }, + { "glGetUniformfv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetUniformfv }, + { "glGetUniformiv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetUniformiv }, + { "glGetUniformLocation", (void *) QWindowsEGLStaticContext::libGLESv2.glGetUniformLocation }, + { "glGetVertexAttribfv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetVertexAttribfv }, + { "glGetVertexAttribiv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetVertexAttribiv }, + { "glGetVertexAttribPointerv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetVertexAttribPointerv }, + { "glIsBuffer", (void *) QWindowsEGLStaticContext::libGLESv2.glIsBuffer }, + { "glIsFramebuffer", (void *) QWindowsEGLStaticContext::libGLESv2.glIsFramebuffer }, + { "glIsProgram", (void *) QWindowsEGLStaticContext::libGLESv2.glIsProgram }, + { "glIsRenderbuffer", (void *) QWindowsEGLStaticContext::libGLESv2.glIsRenderbuffer }, + { "glIsShader", (void *) QWindowsEGLStaticContext::libGLESv2.glIsShader }, + { "glLinkProgram", (void *) QWindowsEGLStaticContext::libGLESv2.glLinkProgram }, + { "glReleaseShaderCompiler", (void *) QWindowsEGLStaticContext::libGLESv2.glReleaseShaderCompiler }, + { "glRenderbufferStorage", (void *) QWindowsEGLStaticContext::libGLESv2.glRenderbufferStorage }, + { "glSampleCoverage", (void *) QWindowsEGLStaticContext::libGLESv2.glSampleCoverage }, + { "glShaderBinary", (void *) QWindowsEGLStaticContext::libGLESv2.glShaderBinary }, + { "glShaderSource", (void *) QWindowsEGLStaticContext::libGLESv2.glShaderSource }, + { "glStencilFuncSeparate", (void *) QWindowsEGLStaticContext::libGLESv2.glStencilFuncSeparate }, + { "glStencilMaskSeparate", (void *) QWindowsEGLStaticContext::libGLESv2.glStencilMaskSeparate }, + { "glStencilOpSeparate", (void *) QWindowsEGLStaticContext::libGLESv2.glStencilOpSeparate }, + { "glUniform1f", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform1f }, + { "glUniform1fv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform1fv }, + { "glUniform1i", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform1i }, + { "glUniform1iv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform1iv }, + { "glUniform2f", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform2f }, + { "glUniform2fv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform2fv }, + { "glUniform2i", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform2i }, + { "glUniform2iv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform2iv }, + { "glUniform3f", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform3f }, + { "glUniform3fv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform3fv }, + { "glUniform3i", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform3i }, + { "glUniform3iv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform3iv }, + { "glUniform4f", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform4f }, + { "glUniform4fv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform4fv }, + { "glUniform4i", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform4i }, + { "glUniform4iv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform4iv }, + { "glUniformMatrix2fv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniformMatrix2fv }, + { "glUniformMatrix3fv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniformMatrix3fv }, + { "glUniformMatrix4fv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniformMatrix4fv }, + { "glUseProgram", (void *) QWindowsEGLStaticContext::libGLESv2.glUseProgram }, + { "glValidateProgram", (void *) QWindowsEGLStaticContext::libGLESv2.glValidateProgram }, + { "glVertexAttrib1f", (void *) QWindowsEGLStaticContext::libGLESv2.glVertexAttrib1f }, + { "glVertexAttrib1fv", (void *) QWindowsEGLStaticContext::libGLESv2.glVertexAttrib1fv }, + { "glVertexAttrib2f", (void *) QWindowsEGLStaticContext::libGLESv2.glVertexAttrib2f }, + { "glVertexAttrib2fv", (void *) QWindowsEGLStaticContext::libGLESv2.glVertexAttrib2fv }, + { "glVertexAttrib3f", (void *) QWindowsEGLStaticContext::libGLESv2.glVertexAttrib3f }, + { "glVertexAttrib3fv", (void *) QWindowsEGLStaticContext::libGLESv2.glVertexAttrib3fv }, + { "glVertexAttrib4f", (void *) QWindowsEGLStaticContext::libGLESv2.glVertexAttrib4f }, + { "glVertexAttrib4fv", (void *) QWindowsEGLStaticContext::libGLESv2.glVertexAttrib4fv }, + { "glVertexAttribPointer", (void *) QWindowsEGLStaticContext::libGLESv2.glVertexAttribPointer }, + + { "glClearDepthf", (void *) QWindowsEGLStaticContext::libGLESv2.glClearDepthf }, + { "glDepthRangef", (void *) QWindowsEGLStaticContext::libGLESv2.glDepthRangef } + }; + for (size_t i = 0; i < sizeof(standardFuncs) / sizeof(StdFunc); ++i) + if (procName == standardFuncs[i].name) + return reinterpret_cast<QFunctionPointer>(standardFuncs[i].func); + + QWindowsEGLStaticContext::libEGL.eglBindAPI(m_api); + QFunctionPointer procAddress = reinterpret_cast<QFunctionPointer>(QWindowsEGLStaticContext::libEGL.eglGetProcAddress(procName.constData())); + if (QWindowsContext::verbose > 1) + qCDebug(lcQpaGl) << __FUNCTION__ << procName << QWindowsEGLStaticContext::libEGL.eglGetCurrentContext() << "returns" << procAddress; + if (!procAddress) + qWarning("%s: Unable to resolve '%s'", __FUNCTION__, procName.constData()); + return procAddress; +} + +static QVector<EGLint> createConfigAttributesFromFormat(const QSurfaceFormat &format) +{ + int redSize = format.redBufferSize(); + int greenSize = format.greenBufferSize(); + int blueSize = format.blueBufferSize(); + int alphaSize = format.alphaBufferSize(); + int depthSize = format.depthBufferSize(); + int stencilSize = format.stencilBufferSize(); + int sampleCount = format.samples(); + + QVector<EGLint> configAttributes; + configAttributes.reserve(16); + + configAttributes.append(EGL_RED_SIZE); + configAttributes.append(redSize > 0 ? redSize : 0); + + configAttributes.append(EGL_GREEN_SIZE); + configAttributes.append(greenSize > 0 ? greenSize : 0); + + configAttributes.append(EGL_BLUE_SIZE); + configAttributes.append(blueSize > 0 ? blueSize : 0); + + configAttributes.append(EGL_ALPHA_SIZE); + configAttributes.append(alphaSize > 0 ? alphaSize : 0); + + configAttributes.append(EGL_DEPTH_SIZE); + configAttributes.append(depthSize > 0 ? depthSize : 0); + + configAttributes.append(EGL_STENCIL_SIZE); + configAttributes.append(stencilSize > 0 ? stencilSize : 0); + + configAttributes.append(EGL_SAMPLES); + configAttributes.append(sampleCount > 0 ? sampleCount : 0); + + configAttributes.append(EGL_SAMPLE_BUFFERS); + configAttributes.append(sampleCount > 0); + + return configAttributes; +} + +static bool reduceConfigAttributes(QVector<EGLint> *configAttributes) +{ + int i = -1; + + i = configAttributes->indexOf(EGL_SWAP_BEHAVIOR); + if (i >= 0) { + configAttributes->remove(i,2); } - return ok; + + i = configAttributes->indexOf(EGL_BUFFER_SIZE); + if (i >= 0) { + if (configAttributes->at(i+1) == 16) { + configAttributes->remove(i,2); + return true; + } + } + + i = configAttributes->indexOf(EGL_SAMPLES); + if (i >= 0) { + EGLint value = configAttributes->value(i+1, 0); + if (value > 1) + configAttributes->replace(i+1, qMin(EGLint(16), value / 2)); + else + configAttributes->remove(i, 2); + return true; + } + + i = configAttributes->indexOf(EGL_SAMPLE_BUFFERS); + if (i >= 0) { + configAttributes->remove(i,2); + return true; + } + + i = configAttributes->indexOf(EGL_ALPHA_SIZE); + if (i >= 0) { + configAttributes->remove(i,2); +#if defined(EGL_BIND_TO_TEXTURE_RGBA) && defined(EGL_BIND_TO_TEXTURE_RGB) + i = configAttributes->indexOf(EGL_BIND_TO_TEXTURE_RGBA); + if (i >= 0) { + configAttributes->replace(i,EGL_BIND_TO_TEXTURE_RGB); + configAttributes->replace(i+1,true); + + } +#endif + return true; + } + + i = configAttributes->indexOf(EGL_STENCIL_SIZE); + if (i >= 0) { + if (configAttributes->at(i + 1) > 1) + configAttributes->replace(i + 1, 1); + else + configAttributes->remove(i, 2); + return true; + } + + i = configAttributes->indexOf(EGL_DEPTH_SIZE); + if (i >= 0) { + if (configAttributes->at(i + 1) > 1) + configAttributes->replace(i + 1, 1); + else + configAttributes->remove(i, 2); + return true; + } +#ifdef EGL_BIND_TO_TEXTURE_RGB + i = configAttributes->indexOf(EGL_BIND_TO_TEXTURE_RGB); + if (i >= 0) { + configAttributes->remove(i,2); + return true; + } +#endif + + return false; +} + +EGLConfig QWindowsEGLContext::chooseConfig(const QSurfaceFormat &format) +{ + QVector<EGLint> configureAttributes = createConfigAttributesFromFormat(format); + configureAttributes.append(EGL_SURFACE_TYPE); + configureAttributes.append(EGL_WINDOW_BIT); + configureAttributes.append(EGL_RENDERABLE_TYPE); + configureAttributes.append(EGL_OPENGL_ES2_BIT); + configureAttributes.append(EGL_NONE); + + EGLDisplay display = m_staticContext->display(); + EGLConfig cfg = 0; + do { + // Get the number of matching configurations for this set of properties. + EGLint matching = 0; + if (!QWindowsEGLStaticContext::libEGL.eglChooseConfig(display, configureAttributes.constData(), 0, 0, &matching) || !matching) + continue; + + // Fetch all of the matching configurations and find the + // first that matches the pixel format we wanted. + int i = configureAttributes.indexOf(EGL_RED_SIZE); + int confAttrRed = configureAttributes.at(i+1); + i = configureAttributes.indexOf(EGL_GREEN_SIZE); + int confAttrGreen = configureAttributes.at(i+1); + i = configureAttributes.indexOf(EGL_BLUE_SIZE); + int confAttrBlue = configureAttributes.at(i+1); + i = configureAttributes.indexOf(EGL_ALPHA_SIZE); + int confAttrAlpha = i == -1 ? 0 : configureAttributes.at(i+1); + + QVector<EGLConfig> configs(matching); + QWindowsEGLStaticContext::libEGL.eglChooseConfig(display, configureAttributes.constData(), configs.data(), configs.size(), &matching); + if (!cfg && matching > 0) + cfg = configs.first(); + + EGLint red = 0; + EGLint green = 0; + EGLint blue = 0; + EGLint alpha = 0; + for (int i = 0; i < configs.size(); ++i) { + if (confAttrRed) + QWindowsEGLStaticContext::libEGL.eglGetConfigAttrib(display, configs[i], EGL_RED_SIZE, &red); + if (confAttrGreen) + QWindowsEGLStaticContext::libEGL.eglGetConfigAttrib(display, configs[i], EGL_GREEN_SIZE, &green); + if (confAttrBlue) + QWindowsEGLStaticContext::libEGL.eglGetConfigAttrib(display, configs[i], EGL_BLUE_SIZE, &blue); + if (confAttrAlpha) + QWindowsEGLStaticContext::libEGL.eglGetConfigAttrib(display, configs[i], EGL_ALPHA_SIZE, &alpha); + + if (red == confAttrRed && green == confAttrGreen + && blue == confAttrBlue && alpha == confAttrAlpha) + return configs[i]; + } + } while (reduceConfigAttributes(&configureAttributes)); + + if (!cfg) + qWarning("Cannot find EGLConfig, returning null config"); + + return cfg; } QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowseglcontext.h b/src/plugins/platforms/windows/qwindowseglcontext.h index 33653b2f2e..813c605396 100644 --- a/src/plugins/platforms/windows/qwindowseglcontext.h +++ b/src/plugins/platforms/windows/qwindowseglcontext.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** 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. @@ -42,20 +42,229 @@ #ifndef QWINDOWSEGLCONTEXT_H #define QWINDOWSEGLCONTEXT_H -#include <QtPlatformSupport/private/qeglplatformcontext_p.h> -#include <QSharedPointer> +#include "qwindowsopenglcontext.h" +#include <EGL/egl.h> QT_BEGIN_NAMESPACE -class QWindowsEGLStaticContext +struct QWindowsLibEGL +{ + bool init(); + + EGLint (EGLAPIENTRY * eglGetError)(void); + EGLDisplay (EGLAPIENTRY * eglGetDisplay)(EGLNativeDisplayType display_id); + EGLBoolean (EGLAPIENTRY * eglInitialize)(EGLDisplay dpy, EGLint *major, EGLint *minor); + EGLBoolean (EGLAPIENTRY * eglTerminate)(EGLDisplay dpy); + EGLBoolean (EGLAPIENTRY * eglChooseConfig)(EGLDisplay dpy, const EGLint *attrib_list, + EGLConfig *configs, EGLint config_size, + EGLint *num_config); + EGLBoolean (EGLAPIENTRY * eglGetConfigAttrib)(EGLDisplay dpy, EGLConfig config, + EGLint attribute, EGLint *value); + EGLSurface (EGLAPIENTRY * eglCreateWindowSurface)(EGLDisplay dpy, EGLConfig config, + EGLNativeWindowType win, + const EGLint *attrib_list); + EGLSurface (EGLAPIENTRY * eglCreatePbufferSurface)(EGLDisplay dpy, EGLConfig config, + const EGLint *attrib_list); + EGLBoolean (EGLAPIENTRY * eglDestroySurface)(EGLDisplay dpy, EGLSurface surface); + EGLBoolean (EGLAPIENTRY * eglBindAPI)(EGLenum api); + EGLBoolean (EGLAPIENTRY * eglSwapInterval)(EGLDisplay dpy, EGLint interval); + EGLContext (EGLAPIENTRY * eglCreateContext)(EGLDisplay dpy, EGLConfig config, + EGLContext share_context, + const EGLint *attrib_list); + EGLBoolean (EGLAPIENTRY * eglDestroyContext)(EGLDisplay dpy, EGLContext ctx); + EGLBoolean (EGLAPIENTRY * eglMakeCurrent)(EGLDisplay dpy, EGLSurface draw, + EGLSurface read, EGLContext ctx); + EGLContext (EGLAPIENTRY * eglGetCurrentContext)(void); + EGLSurface (EGLAPIENTRY * eglGetCurrentSurface)(EGLint readdraw); + EGLDisplay (EGLAPIENTRY * eglGetCurrentDisplay)(void); + EGLBoolean (EGLAPIENTRY * eglSwapBuffers)(EGLDisplay dpy, EGLSurface surface); + __eglMustCastToProperFunctionPointerType (EGLAPIENTRY * eglGetProcAddress)(const char *procname); + +private: + void *resolve(const char *name); + HMODULE m_lib; +}; + +struct QWindowsLibGLESv2 +{ + bool init(); + void *moduleHandle() const { return m_lib; } + + // GL1+GLES2 common + void (APIENTRY * glBindTexture)(GLenum target, GLuint texture); + void (APIENTRY * glBlendFunc)(GLenum sfactor, GLenum dfactor); + void (APIENTRY * glClear)(GLbitfield mask); + void (APIENTRY * glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); + void (APIENTRY * glClearStencil)(GLint s); + void (APIENTRY * glColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); + void (APIENTRY * glCopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); + void (APIENTRY * glCopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY * glCullFace)(GLenum mode); + void (APIENTRY * glDeleteTextures)(GLsizei n, const GLuint* textures); + void (APIENTRY * glDepthFunc)(GLenum func); + void (APIENTRY * glDepthMask)(GLboolean flag); + void (APIENTRY * glDisable)(GLenum cap); + void (APIENTRY * glDrawArrays)(GLenum mode, GLint first, GLsizei count); + void (APIENTRY * glDrawElements)(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices); + void (APIENTRY * glEnable)(GLenum cap); + void (APIENTRY * glFinish)(); + void (APIENTRY * glFlush)(); + void (APIENTRY * glFrontFace)(GLenum mode); + void (APIENTRY * glGenTextures)(GLsizei n, GLuint* textures); + void (APIENTRY * glGetBooleanv)(GLenum pname, GLboolean* params); + GLenum (APIENTRY * glGetError)(); + void (APIENTRY * glGetFloatv)(GLenum pname, GLfloat* params); + void (APIENTRY * glGetIntegerv)(GLenum pname, GLint* params); + const GLubyte * (APIENTRY * glGetString)(GLenum name); + void (APIENTRY * glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat* params); + void (APIENTRY * glGetTexParameteriv)(GLenum target, GLenum pname, GLint* params); + void (APIENTRY * glHint)(GLenum target, GLenum mode); + GLboolean (APIENTRY * glIsEnabled)(GLenum cap); + GLboolean (APIENTRY * glIsTexture)(GLuint texture); + void (APIENTRY * glLineWidth)(GLfloat width); + void (APIENTRY * glPixelStorei)(GLenum pname, GLint param); + void (APIENTRY * glPolygonOffset)(GLfloat factor, GLfloat units); + void (APIENTRY * glReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels); + void (APIENTRY * glScissor)(GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY * glStencilFunc)(GLenum func, GLint ref, GLuint mask); + void (APIENTRY * glStencilMask)(GLuint mask); + void (APIENTRY * glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass); + void (APIENTRY * glTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels); + void (APIENTRY * glTexParameterf)(GLenum target, GLenum pname, GLfloat param); + void (APIENTRY * glTexParameterfv)(GLenum target, GLenum pname, const GLfloat* params); + void (APIENTRY * glTexParameteri)(GLenum target, GLenum pname, GLint param); + void (APIENTRY * glTexParameteriv)(GLenum target, GLenum pname, const GLint* params); + void (APIENTRY * glTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels); + void (APIENTRY * glViewport)(GLint x, GLint y, GLsizei width, GLsizei height); + + // GLES2 + void (APIENTRY * glActiveTexture)(GLenum texture); + void (APIENTRY * glAttachShader)(GLuint program, GLuint shader); + void (APIENTRY * glBindAttribLocation)(GLuint program, GLuint index, const char* name); + void (APIENTRY * glBindBuffer)(GLenum target, GLuint buffer); + void (APIENTRY * glBindFramebuffer)(GLenum target, GLuint framebuffer); + void (APIENTRY * glBindRenderbuffer)(GLenum target, GLuint renderbuffer); + void (APIENTRY * glBlendColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); + void (APIENTRY * glBlendEquation)(GLenum mode); + void (APIENTRY * glBlendEquationSeparate)(GLenum modeRGB, GLenum modeAlpha); + void (APIENTRY * glBlendFuncSeparate)(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); + void (APIENTRY * glBufferData)(GLenum target, qopengl_GLsizeiptr size, const void* data, GLenum usage); + void (APIENTRY * glBufferSubData)(GLenum target, qopengl_GLintptr offset, qopengl_GLsizeiptr size, const void* data); + GLenum (APIENTRY * glCheckFramebufferStatus)(GLenum target); + void (APIENTRY * glCompileShader)(GLuint shader); + void (APIENTRY * glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data); + void (APIENTRY * glCompressedTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data); + GLuint (APIENTRY * glCreateProgram)(); + GLuint (APIENTRY * glCreateShader)(GLenum type); + void (APIENTRY * glDeleteBuffers)(GLsizei n, const GLuint* buffers); + void (APIENTRY * glDeleteFramebuffers)(GLsizei n, const GLuint* framebuffers); + void (APIENTRY * glDeleteProgram)(GLuint program); + void (APIENTRY * glDeleteRenderbuffers)(GLsizei n, const GLuint* renderbuffers); + void (APIENTRY * glDeleteShader)(GLuint shader); + void (APIENTRY * glDetachShader)(GLuint program, GLuint shader); + void (APIENTRY * glDisableVertexAttribArray)(GLuint index); + void (APIENTRY * glEnableVertexAttribArray)(GLuint index); + void (APIENTRY * glFramebufferRenderbuffer)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); + void (APIENTRY * glFramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); + void (APIENTRY * glGenBuffers)(GLsizei n, GLuint* buffers); + void (APIENTRY * glGenerateMipmap)(GLenum target); + void (APIENTRY * glGenFramebuffers)(GLsizei n, GLuint* framebuffers); + void (APIENTRY * glGenRenderbuffers)(GLsizei n, GLuint* renderbuffers); + void (APIENTRY * glGetActiveAttrib)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name); + void (APIENTRY * glGetActiveUniform)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name); + void (APIENTRY * glGetAttachedShaders)(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders); + GLint (APIENTRY * glGetAttribLocation)(GLuint program, const char* name); + void (APIENTRY * glGetBufferParameteriv)(GLenum target, GLenum pname, GLint* params); + void (APIENTRY * glGetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint* params); + void (APIENTRY * glGetProgramiv)(GLuint program, GLenum pname, GLint* params); + void (APIENTRY * glGetProgramInfoLog)(GLuint program, GLsizei bufsize, GLsizei* length, char* infolog); + void (APIENTRY * glGetRenderbufferParameteriv)(GLenum target, GLenum pname, GLint* params); + void (APIENTRY * glGetShaderiv)(GLuint shader, GLenum pname, GLint* params); + void (APIENTRY * glGetShaderInfoLog)(GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog); + void (APIENTRY * glGetShaderPrecisionFormat)(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision); + void (APIENTRY * glGetShaderSource)(GLuint shader, GLsizei bufsize, GLsizei* length, char* source); + void (APIENTRY * glGetUniformfv)(GLuint program, GLint location, GLfloat* params); + void (APIENTRY * glGetUniformiv)(GLuint program, GLint location, GLint* params); + GLint (APIENTRY * glGetUniformLocation)(GLuint program, const char* name); + void (APIENTRY * glGetVertexAttribfv)(GLuint index, GLenum pname, GLfloat* params); + void (APIENTRY * glGetVertexAttribiv)(GLuint index, GLenum pname, GLint* params); + void (APIENTRY * glGetVertexAttribPointerv)(GLuint index, GLenum pname, void** pointer); + GLboolean (APIENTRY * glIsBuffer)(GLuint buffer); + GLboolean (APIENTRY * glIsFramebuffer)(GLuint framebuffer); + GLboolean (APIENTRY * glIsProgram)(GLuint program); + GLboolean (APIENTRY * glIsRenderbuffer)(GLuint renderbuffer); + GLboolean (APIENTRY * glIsShader)(GLuint shader); + void (APIENTRY * glLinkProgram)(GLuint program); + void (APIENTRY * glReleaseShaderCompiler)(); + void (APIENTRY * glRenderbufferStorage)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); + void (APIENTRY * glSampleCoverage)(GLclampf value, GLboolean invert); + void (APIENTRY * glShaderBinary)(GLint n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLint length); + void (APIENTRY * glShaderSource)(GLuint shader, GLsizei count, const char** string, const GLint* length); + void (APIENTRY * glStencilFuncSeparate)(GLenum face, GLenum func, GLint ref, GLuint mask); + void (APIENTRY * glStencilMaskSeparate)(GLenum face, GLuint mask); + void (APIENTRY * glStencilOpSeparate)(GLenum face, GLenum fail, GLenum zfail, GLenum zpass); + void (APIENTRY * glUniform1f)(GLint location, GLfloat x); + void (APIENTRY * glUniform1fv)(GLint location, GLsizei count, const GLfloat* v); + void (APIENTRY * glUniform1i)(GLint location, GLint x); + void (APIENTRY * glUniform1iv)(GLint location, GLsizei count, const GLint* v); + void (APIENTRY * glUniform2f)(GLint location, GLfloat x, GLfloat y); + void (APIENTRY * glUniform2fv)(GLint location, GLsizei count, const GLfloat* v); + void (APIENTRY * glUniform2i)(GLint location, GLint x, GLint y); + void (APIENTRY * glUniform2iv)(GLint location, GLsizei count, const GLint* v); + void (APIENTRY * glUniform3f)(GLint location, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY * glUniform3fv)(GLint location, GLsizei count, const GLfloat* v); + void (APIENTRY * glUniform3i)(GLint location, GLint x, GLint y, GLint z); + void (APIENTRY * glUniform3iv)(GLint location, GLsizei count, const GLint* v); + void (APIENTRY * glUniform4f)(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY * glUniform4fv)(GLint location, GLsizei count, const GLfloat* v); + void (APIENTRY * glUniform4i)(GLint location, GLint x, GLint y, GLint z, GLint w); + void (APIENTRY * glUniform4iv)(GLint location, GLsizei count, const GLint* v); + void (APIENTRY * glUniformMatrix2fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + void (APIENTRY * glUniformMatrix3fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + void (APIENTRY * glUniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + void (APIENTRY * glUseProgram)(GLuint program); + void (APIENTRY * glValidateProgram)(GLuint program); + void (APIENTRY * glVertexAttrib1f)(GLuint indx, GLfloat x); + void (APIENTRY * glVertexAttrib1fv)(GLuint indx, const GLfloat* values); + void (APIENTRY * glVertexAttrib2f)(GLuint indx, GLfloat x, GLfloat y); + void (APIENTRY * glVertexAttrib2fv)(GLuint indx, const GLfloat* values); + void (APIENTRY * glVertexAttrib3f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY * glVertexAttrib3fv)(GLuint indx, const GLfloat* values); + void (APIENTRY * glVertexAttrib4f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY * glVertexAttrib4fv)(GLuint indx, const GLfloat* values); + void (APIENTRY * glVertexAttribPointer)(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr); + + // ES only + void (APIENTRY * glClearDepthf)(GLclampf depth); + void (APIENTRY * glDepthRangef)(GLclampf nearVal, GLclampf farVal); + +private: + void *resolve(const char *name); + HMODULE m_lib; +}; + +class QWindowsEGLStaticContext : public QWindowsStaticOpenGLContext { Q_DISABLE_COPY(QWindowsEGLStaticContext) + public: static QWindowsEGLStaticContext *create(); ~QWindowsEGLStaticContext(); EGLDisplay display() const { return m_display; } + QWindowsOpenGLContext *createContext(QOpenGLContext *context); + void *moduleHandle() const { return libGLESv2.moduleHandle(); } + QOpenGLContext::OpenGLModuleType moduleType() const { return QOpenGLContext::LibGLES; } + + void *createWindowSurface(void *nativeWindow, void *nativeConfig) Q_DECL_OVERRIDE; + void destroyWindowSurface(void *nativeSurface) Q_DECL_OVERRIDE; + + QSurfaceFormat formatFromConfig(EGLDisplay display, EGLConfig config, const QSurfaceFormat &referenceFormat); + + static QWindowsLibEGL libEGL; + static QWindowsLibGLESv2 libGLESv2; + private: QWindowsEGLStaticContext(EGLDisplay display, int version); @@ -63,26 +272,38 @@ private: const int m_version; //! majorVersion<<8 + minorVersion }; -class QWindowsEGLContext : public QEGLPlatformContext +class QWindowsEGLContext : public QWindowsOpenGLContext { public: - typedef QSharedPointer<QWindowsEGLStaticContext> QWindowsEGLStaticContextPtr; - - QWindowsEGLContext(const QWindowsEGLStaticContextPtr& staticContext, + QWindowsEGLContext(QWindowsEGLStaticContext *staticContext, const QSurfaceFormat &format, QPlatformOpenGLContext *share); - ~QWindowsEGLContext(); - static bool hasThreadedOpenGLCapability(); + bool makeCurrent(QPlatformSurface *surface) Q_DECL_OVERRIDE; + void doneCurrent() Q_DECL_OVERRIDE; + void swapBuffers(QPlatformSurface *surface) Q_DECL_OVERRIDE; + QFunctionPointer getProcAddress(const QByteArray &procName) Q_DECL_OVERRIDE; - bool makeCurrent(QPlatformSurface *surface); + QSurfaceFormat format() const Q_DECL_OVERRIDE { return m_format; } + bool isSharing() const Q_DECL_OVERRIDE { return m_shareContext != EGL_NO_CONTEXT; } + bool isValid() const Q_DECL_OVERRIDE { return m_eglContext != EGL_NO_CONTEXT; } -protected: - EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface); + void *nativeContext() const Q_DECL_OVERRIDE { return m_eglContext; } + void *nativeDisplay() const Q_DECL_OVERRIDE { return m_eglDisplay; } + void *nativeConfig() const Q_DECL_OVERRIDE { return m_eglConfig; } private: - const QWindowsEGLStaticContextPtr m_staticContext; + EGLConfig chooseConfig(const QSurfaceFormat &format); + + QWindowsEGLStaticContext *m_staticContext; + EGLContext m_eglContext; + EGLContext m_shareContext; + EGLDisplay m_eglDisplay; + EGLConfig m_eglConfig; + QSurfaceFormat m_format; + EGLenum m_api; + int m_swapInterval; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp index 696dc06cee..7058406b4a 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp @@ -1064,7 +1064,7 @@ QFontEngineMulti *QWindowsFontDatabase::fontEngineMulti(QFontEngine *fontEngine, if (script == QChar::Script_Common) return new QWindowsMultiFontEngine(fontEngine, script); // ### as long as fallbacksForFamily() does not take script parameter into account, - // prefer QFontEngineMultiQPA's loadEngine() implementation for complex scripts + // prefer QFontEngineMultiBasicImpl's loadEngine() implementation for complex scripts return QPlatformFontDatabase::fontEngineMulti(fontEngine, script); } @@ -1639,9 +1639,12 @@ QStringList QWindowsFontDatabase::fallbacksForFamily(const QString &family, QFon result << QString::fromLatin1("Old English"); break; case QFont::Helvetica: + result << QString::fromLatin1("Arial"); + break; case QFont::System: default: - result << QString::fromLatin1("Arial"); + result << QString::fromLatin1("MS Sans Serif"); + break; } result.append(QWindowsFontDatabase::extraTryFontsForFamily(family)); diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp index 6f97c8584b..d3cbea0b92 100644 --- a/src/plugins/platforms/windows/qwindowsfontengine.cpp +++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp @@ -111,11 +111,6 @@ static void resolveGetCharWidthI() ptrGetCharWidthI = (PtrGetCharWidthI)QSystemLibrary::resolve(QStringLiteral("gdi32"), "GetCharWidthI"); } -// defined in qtextengine_win.cpp -typedef void *SCRIPT_CACHE; -typedef HRESULT (WINAPI *fScriptFreeCache)(SCRIPT_CACHE *); -extern fScriptFreeCache ScriptFreeCache; - static inline quint32 getUInt(unsigned char *p) { quint32 val; @@ -1300,7 +1295,7 @@ void QWindowsFontEngine::initFontInfo(const QFontDef &request, Will probably be superseded by a common Free Type font engine in Qt 5.X. */ QWindowsMultiFontEngine::QWindowsMultiFontEngine(QFontEngine *fe, int script) - : QFontEngineMultiQPA(fe, script) + : QFontEngineMultiBasicImpl(fe, script) { } diff --git a/src/plugins/platforms/windows/qwindowsfontengine.h b/src/plugins/platforms/windows/qwindowsfontengine.h index 0ddf778fa0..637c8521a3 100644 --- a/src/plugins/platforms/windows/qwindowsfontengine.h +++ b/src/plugins/platforms/windows/qwindowsfontengine.h @@ -53,7 +53,7 @@ // We mean it. // -#include <QtGui/private/qfontengine_qpa_p.h> +#include <QtGui/private/qfontengine_p.h> #include <QtGui/QImage> #include <QtCore/QSharedPointer> @@ -172,7 +172,7 @@ private: }; -class QWindowsMultiFontEngine : public QFontEngineMultiQPA +class QWindowsMultiFontEngine : public QFontEngineMultiBasicImpl { public: explicit QWindowsMultiFontEngine(QFontEngine *fe, int script); diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp index eaa4eca84e..b1152de854 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -144,6 +144,131 @@ QT_BEGIN_NAMESPACE +QWindowsOpengl32DLL QOpenGLStaticContext::opengl32; + +void *QWindowsOpengl32DLL::resolve(const char *name) +{ +#ifndef Q_OS_WINCE + void *proc = m_lib ? (void *) ::GetProcAddress(m_lib, name) : 0; +#else + void *proc = m_lib ? (void *) ::GetProcAddress(m_lib, (const wchar_t *) QString::fromLatin1(name).utf16()) : 0; +#endif + if (!proc) + qErrnoWarning(::GetLastError(), "Failed to resolve OpenGL function %s", name); + + return proc; +} + +bool QWindowsOpengl32DLL::init(bool softwareRendering) +{ + const QByteArray opengl32 = QByteArrayLiteral("opengl32.dll"); + const QByteArray swopengl = QByteArrayLiteral("QtSoftwareOpenGL.dll"); + + QByteArray openglDll = qgetenv("QT_OPENGL_DLL"); + if (openglDll.isEmpty()) + openglDll = softwareRendering ? swopengl : opengl32; + + openglDll = openglDll.toLower(); + m_nonOpengl32 = openglDll != opengl32; + + qCDebug(lcQpaGl) << "Qt: Using WGL and OpenGL from" << openglDll; + + m_lib = ::LoadLibraryA(openglDll.constData()); + if (!m_lib) { + qErrnoWarning(::GetLastError(), "Failed to load %s", openglDll.constData()); + return false; + } + + if (moduleIsNotOpengl32()) { + // Load opengl32.dll always. GDI functions like ChoosePixelFormat do + // GetModuleHandle for opengl32.dll and behave differently (and call back into + // opengl32) when the module is present. This is fine for dummy contexts and windows. + ::LoadLibraryA("opengl32.dll"); + } + + wglCreateContext = reinterpret_cast<HGLRC (WINAPI *)(HDC)>(resolve("wglCreateContext")); + wglDeleteContext = reinterpret_cast<BOOL (WINAPI *)(HGLRC)>(resolve("wglDeleteContext")); + wglGetCurrentContext = reinterpret_cast<HGLRC (WINAPI *)()>(resolve("wglGetCurrentContext")); + wglGetCurrentDC = reinterpret_cast<HDC (WINAPI *)()>(resolve("wglGetCurrentDC")); + wglGetProcAddress = reinterpret_cast<PROC (WINAPI *)(LPCSTR)>(resolve("wglGetProcAddress")); + wglMakeCurrent = reinterpret_cast<BOOL (WINAPI *)(HDC, HGLRC)>(resolve("wglMakeCurrent")); + wglShareLists = reinterpret_cast<BOOL (WINAPI *)(HGLRC, HGLRC)>(resolve("wglShareLists")); + wglSwapBuffers = reinterpret_cast<BOOL (WINAPI *)(HDC)>(resolve("wglSwapBuffers")); + wglSetPixelFormat = reinterpret_cast<BOOL (WINAPI *)(HDC, int, const PIXELFORMATDESCRIPTOR *)>(resolve("wglSetPixelFormat")); + + glBindTexture = reinterpret_cast<void (APIENTRY *)(GLenum , GLuint )>(resolve("glBindTexture")); + glBlendFunc = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum )>(resolve("glBlendFunc")); + glClear = reinterpret_cast<void (APIENTRY *)(GLbitfield )>(resolve("glClear")); + glClearColor = reinterpret_cast<void (APIENTRY *)(GLfloat , GLfloat , GLfloat , GLfloat )>(resolve("glClearColor")); + glClearStencil = reinterpret_cast<void (APIENTRY *)(GLint )>(resolve("glClearStencil")); + glColorMask = reinterpret_cast<void (APIENTRY *)(GLboolean , GLboolean , GLboolean , GLboolean )>(resolve("glColorMask")); + glCopyTexImage2D = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLenum , GLint , GLint , GLsizei , GLsizei , GLint )>(resolve("glCopyTexImage2D")); + glCopyTexSubImage2D = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLint , GLint , GLint , GLint , GLsizei , GLsizei )>(resolve("glCopyTexSubImage2D")); + glCullFace = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolve("glCullFace")); + glDeleteTextures = reinterpret_cast<void (APIENTRY *)(GLsizei , const GLuint *)>(resolve("glDeleteTextures")); + glDepthFunc = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolve("glDepthFunc")); + glDepthMask = reinterpret_cast<void (APIENTRY *)(GLboolean )>(resolve("glDepthMask")); + glDisable = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolve("glDisable")); + glDrawArrays = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLsizei )>(resolve("glDrawArrays")); + glDrawElements = reinterpret_cast<void (APIENTRY *)(GLenum , GLsizei , GLenum , const GLvoid *)>(resolve("glDrawElements")); + glEnable = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolve("glEnable")); + glFinish = reinterpret_cast<void (APIENTRY *)()>(resolve("glFinish")); + glFlush = reinterpret_cast<void (APIENTRY *)()>(resolve("glFlush")); + glFrontFace = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolve("glFrontFace")); + glGenTextures = reinterpret_cast<void (APIENTRY *)(GLsizei , GLuint *)>(resolve("glGenTextures")); + glGetBooleanv = reinterpret_cast<void (APIENTRY *)(GLenum , GLboolean *)>(resolve("glGetBooleanv")); + glGetError = reinterpret_cast<GLenum (APIENTRY *)()>(resolve("glGetError")); + glGetFloatv = reinterpret_cast<void (APIENTRY *)(GLenum , GLfloat *)>(resolve("glGetFloatv")); + glGetIntegerv = reinterpret_cast<void (APIENTRY *)(GLenum , GLint *)>(resolve("glGetIntegerv")); + glGetString = reinterpret_cast<const GLubyte * (APIENTRY *)(GLenum )>(resolve("glGetString")); + glGetTexParameterfv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLfloat *)>(resolve("glGetTexParameterfv")); + glGetTexParameteriv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLint *)>(resolve("glGetTexParameteriv")); + glHint = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum )>(resolve("glHint")); + glIsEnabled = reinterpret_cast<GLboolean (APIENTRY *)(GLenum )>(resolve("glIsEnabled")); + glIsTexture = reinterpret_cast<GLboolean (APIENTRY *)(GLuint )>(resolve("glIsTexture")); + glLineWidth = reinterpret_cast<void (APIENTRY *)(GLfloat )>(resolve("glLineWidth")); + glPixelStorei = reinterpret_cast<void (APIENTRY *)(GLenum , GLint )>(resolve("glPixelStorei")); + glPolygonOffset = reinterpret_cast<void (APIENTRY *)(GLfloat , GLfloat )>(resolve("glPolygonOffset")); + glReadPixels = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLsizei , GLsizei , GLenum , GLenum , GLvoid *)>(resolve("glReadPixels")); + glScissor = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLsizei , GLsizei )>(resolve("glScissor")); + glStencilFunc = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLuint )>(resolve("glStencilFunc")); + glStencilMask = reinterpret_cast<void (APIENTRY *)(GLuint )>(resolve("glStencilMask")); + glStencilOp = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLenum )>(resolve("glStencilOp")); + glTexImage2D = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLint , GLsizei , GLsizei , GLint , GLenum , GLenum , const GLvoid *)>(resolve("glTexImage2D")); + glTexParameterf = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLfloat )>(resolve("glTexParameterf")); + glTexParameterfv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , const GLfloat *)>(resolve("glTexParameterfv")); + glTexParameteri = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLint )>(resolve("glTexParameteri")); + glTexParameteriv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , const GLint *)>(resolve("glTexParameteriv")); + glTexSubImage2D = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLint , GLint , GLsizei , GLsizei , GLenum , GLenum , const GLvoid *)>(resolve("glTexSubImage2D")); + glViewport = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLsizei , GLsizei )>(resolve("glViewport")); + + glClearDepth = reinterpret_cast<void (APIENTRY *)(GLdouble )>(resolve("glClearDepth")); + glDepthRange = reinterpret_cast<void (APIENTRY *)(GLdouble , GLdouble )>(resolve("glDepthRange")); + + return wglCreateContext && glBindTexture && glClearDepth; +} + +BOOL QWindowsOpengl32DLL::swapBuffers(HDC dc) +{ + if (moduleIsNotOpengl32()) + return wglSwapBuffers(dc); + else + return SwapBuffers(dc); +} + +BOOL QWindowsOpengl32DLL::setPixelFormat(HDC dc, int pf, const PIXELFORMATDESCRIPTOR *pfd) +{ + if (moduleIsNotOpengl32()) + return wglSetPixelFormat(dc, pf, pfd); + else + return SetPixelFormat(dc, pf, pfd); +} + +QWindowsOpenGLContext *QOpenGLStaticContext::createContext(QOpenGLContext *context) +{ + return new QWindowsGLContext(this, context); +} + template <class MaskType, class FlagType> inline bool testFlag(MaskType mask, FlagType flag) { return (mask & MaskType(flag)) != 0; @@ -210,10 +335,11 @@ static inline bool bool ignoreGLSupport = false) // ARB format may not contain it. { const bool pixmapRequested = testFlag(additional.formatFlags, QWindowsGLRenderToPixmap); - return (ignoreGLSupport || testFlag(pfd.dwFlags, PFD_SUPPORT_OPENGL)) - && testFlag(pfd.dwFlags, PFD_DRAW_TO_BITMAP) == pixmapRequested - && hasGLOverlay(pfd) == testFlag(additional.formatFlags, QWindowsGLOverlay) - && (!pixmapRequested || pfd.cColorBits == additional.pixmapDepth); + const bool pixmapOk = !pixmapRequested || testFlag(pfd.dwFlags, PFD_DRAW_TO_BITMAP); + const bool colorOk = !pixmapRequested || pfd.cColorBits == additional.pixmapDepth; + const bool glOk = ignoreGLSupport || testFlag(pfd.dwFlags, PFD_SUPPORT_OPENGL); + const bool overlayOk = hasGLOverlay(pfd) == testFlag(additional.formatFlags, QWindowsGLOverlay); + return pixmapOk && glOk && overlayOk && colorOk; } static void describeFormats(HDC hdc) @@ -299,10 +425,23 @@ static PIXELFORMATDESCRIPTOR // over the available formats to find the best one. // Note: As of Windows 7, it seems direct-rendering is handled, so, // the code might be obsolete? +// +// NB! When using an implementation with a name different than opengl32.dll +// this code path should not be used since it will result in a mess due to GDI +// relying on and possibly calling back into functions in opengl32.dll (and not +// the one we are using). This is not a problem usually since for Mesa, which +// we are most likely to ship with a name other than opengl32.dll, the ARB code +// path should work. Hence the early bail out below. +// static int choosePixelFormat(HDC hdc, const QSurfaceFormat &format, const QWindowsOpenGLAdditionalFormat &additional, PIXELFORMATDESCRIPTOR *obtainedPfd) { + if (QOpenGLStaticContext::opengl32.moduleIsNotOpengl32()) { + qWarning("%s: Attempted to use GDI functions with a non-opengl32.dll library", Q_FUNC_INFO); + return 0; + } + // 1) Try ChoosePixelFormat(). PIXELFORMATDESCRIPTOR requestedPfd = qPixelFormatFromSurfaceFormat(format, QWindowsGLDirectRendering); initPixelFormatDescriptor(obtainedPfd); @@ -352,12 +491,12 @@ static int choosePixelFormat(HDC hdc, const QSurfaceFormat &format, static inline HGLRC createContext(HDC hdc, HGLRC shared) { - HGLRC result = wglCreateContext(hdc); + HGLRC result = QOpenGLStaticContext::opengl32.wglCreateContext(hdc); if (!result) { qErrnoWarning("%s: wglCreateContext failed.", __FUNCTION__); return 0; } - if (shared && !wglShareLists(shared, result)) + if (shared && !QOpenGLStaticContext::opengl32.wglShareLists(shared, result)) qErrnoWarning("%s: wglShareLists() failed.", __FUNCTION__); return result; } @@ -623,7 +762,7 @@ static HGLRC createContext(const QOpenGLStaticContext &staticContext, if (!result) { QString message; QDebug(&message).nospace() << __FUNCTION__ << ": wglCreateContextAttribsARB() failed (GL error code: 0x" - << hex << glGetError() << dec << ") for format: " << format << ", shared context: " << shared; + << hex << staticContext.opengl32.glGetError() << dec << ") for format: " << format << ", shared context: " << shared; qErrnoWarning("%s", qPrintable(message)); } return result; @@ -648,16 +787,17 @@ static inline HGLRC createDummyGLContext(HDC dc) initPixelFormatDescriptor(&pixelFormDescriptor); pixelFormDescriptor.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_GENERIC_FORMAT; pixelFormDescriptor.iPixelType = PFD_TYPE_RGBA; + // Use the GDI variant, for the dummy this is fine, even when using something other than opengl32.dll. const int pixelFormat = ChoosePixelFormat(dc, &pixelFormDescriptor); if (!pixelFormat) { qErrnoWarning("%s: ChoosePixelFormat failed.", __FUNCTION__); return 0; } - if (!SetPixelFormat(dc, pixelFormat, &pixelFormDescriptor)) { + if (!QOpenGLStaticContext::opengl32.setPixelFormat(dc, pixelFormat, &pixelFormDescriptor)) { qErrnoWarning("%s: SetPixelFormat failed.", __FUNCTION__); return 0; } - HGLRC rc = wglCreateContext(dc); + HGLRC rc = QOpenGLStaticContext::opengl32.wglCreateContext(dc); if (!rc) { qErrnoWarning("%s: wglCreateContext failed.", __FUNCTION__); return 0; @@ -668,8 +808,8 @@ static inline HGLRC createDummyGLContext(HDC dc) static inline QOpenGLContextData currentOpenGLContextData() { QOpenGLContextData result; - result.hdc = wglGetCurrentDC(); - result.renderingContext = wglGetCurrentContext(); + result.hdc = QOpenGLStaticContext::opengl32.wglGetCurrentDC(); + result.renderingContext = QOpenGLStaticContext::opengl32.wglGetCurrentContext(); return result; } @@ -721,7 +861,7 @@ QWindowsOpenGLContextFormat QWindowsOpenGLContextFormat::current() } // v3 onwards GLint value = 0; - glGetIntegerv(GL_CONTEXT_FLAGS, &value); + QOpenGLStaticContext::opengl32.glGetIntegerv(GL_CONTEXT_FLAGS, &value); if (!(value & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT)) result.options |= QSurfaceFormat::DeprecatedFunctions; if (value & GL_CONTEXT_FLAG_DEBUG_BIT) @@ -730,7 +870,7 @@ QWindowsOpenGLContextFormat QWindowsOpenGLContextFormat::current() return result; // v3.2 onwards: Profiles value = 0; - glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &value); + QOpenGLStaticContext::opengl32.glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &value); if (value & GL_CONTEXT_CORE_PROFILE_BIT) result.profile = QSurfaceFormat::CoreProfile; else if (value & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) @@ -784,15 +924,15 @@ QOpenGLTemporaryContext::QOpenGLTemporaryContext() : m_previous(currentOpenGLContextData()), m_current(createDummyWindowOpenGLContextData()) { - wglMakeCurrent(m_current.hdc, m_current.renderingContext); + QOpenGLStaticContext::opengl32.wglMakeCurrent(m_current.hdc, m_current.renderingContext); } QOpenGLTemporaryContext::~QOpenGLTemporaryContext() { - wglMakeCurrent(m_previous.hdc, m_previous.renderingContext); + QOpenGLStaticContext::opengl32.wglMakeCurrent(m_previous.hdc, m_previous.renderingContext); ReleaseDC(m_current.hwnd, m_current.hdc); DestroyWindow(m_current.hwnd); - wglDeleteContext(m_current.renderingContext); + QOpenGLStaticContext::opengl32.wglDeleteContext(m_current.renderingContext); } /*! @@ -807,6 +947,11 @@ QOpenGLTemporaryContext::~QOpenGLTemporaryContext() Functions pending integration in the next version of OpenGL are post-fixed ARB. + No WGL or OpenGL functions are called directly from the windows plugin. Instead, the + static context loads opengl32.dll and resolves the necessary functions. This allows + building the plugin without linking to opengl32 and enables QT_OPENGL_DYNAMIC builds + where both the EGL and WGL (this) based implementation of the context are built. + \note Initialization requires an active context (see create()). \sa QWindowsGLContext @@ -822,11 +967,11 @@ QOpenGLStaticContext::QOpenGLStaticContext() : extensionNames(QOpenGLStaticContext::getGlString(GL_EXTENSIONS)), extensions(0), defaultFormat(QWindowsOpenGLContextFormat::current()), - wglGetPixelFormatAttribIVARB((WglGetPixelFormatAttribIVARB)wglGetProcAddress("wglGetPixelFormatAttribivARB")), - wglChoosePixelFormatARB((WglChoosePixelFormatARB)wglGetProcAddress("wglChoosePixelFormatARB")), - wglCreateContextAttribsARB((WglCreateContextAttribsARB)wglGetProcAddress("wglCreateContextAttribsARB")), - wglSwapInternalExt((WglSwapInternalExt)wglGetProcAddress("wglSwapIntervalEXT")), - wglGetSwapInternalExt((WglGetSwapInternalExt)wglGetProcAddress("wglGetSwapIntervalEXT")) + wglGetPixelFormatAttribIVARB((WglGetPixelFormatAttribIVARB)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetPixelFormatAttribivARB")), + wglChoosePixelFormatARB((WglChoosePixelFormatARB)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglChoosePixelFormatARB")), + wglCreateContextAttribsARB((WglCreateContextAttribsARB)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglCreateContextAttribsARB")), + wglSwapInternalExt((WglSwapInternalExt)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglSwapIntervalEXT")), + wglGetSwapInternalExt((WglGetSwapInternalExt)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetSwapIntervalEXT")) { if (extensionNames.startsWith(SAMPLE_BUFFER_EXTENSION " ") || extensionNames.indexOf(" " SAMPLE_BUFFER_EXTENSION " ") != -1) @@ -835,16 +980,21 @@ QOpenGLStaticContext::QOpenGLStaticContext() : QByteArray QOpenGLStaticContext::getGlString(unsigned int which) { - if (const GLubyte *s = glGetString(which)) + if (const GLubyte *s = opengl32.glGetString(which)) return QByteArray((const char*)s); return QByteArray(); } -QOpenGLStaticContext *QOpenGLStaticContext::create() +QOpenGLStaticContext *QOpenGLStaticContext::create(bool softwareRendering) { + if (!opengl32.init(softwareRendering)) { + qWarning("%s: Failed to load and resolve WGL/OpenGL functions", Q_FUNC_INFO); + return 0; + } + // We need a current context for wglGetProcAdress()/getGLString() to work. QScopedPointer<QOpenGLTemporaryContext> temporaryContext; - if (!wglGetCurrentContext()) + if (!QOpenGLStaticContext::opengl32.wglGetCurrentContext()) temporaryContext.reset(new QOpenGLTemporaryContext); QOpenGLStaticContext *result = new QOpenGLStaticContext; qCDebug(lcQpaGl) << __FUNCTION__ << *result; @@ -881,7 +1031,7 @@ QDebug operator<<(QDebug d, const QOpenGLStaticContext &s) \ingroup qt-lighthouse-win */ -QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContext, +QWindowsGLContext::QWindowsGLContext(QOpenGLStaticContext *staticContext, QOpenGLContext *context) : m_staticContext(staticContext), m_context(context), @@ -890,6 +1040,9 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex m_extensionsUsed(false), m_swapInterval(-1) { + if (!m_staticContext) // Something went very wrong. Stop here, isValid() will return false. + return; + QSurfaceFormat format = context->format(); if (format.renderableType() == QSurfaceFormat::DefaultRenderableType) format.setRenderableType(QSurfaceFormat::OpenGL); @@ -901,7 +1054,7 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex static bool opengl32dll = false; if (!opengl32dll) { GLint params; - glGetIntegerv(GL_DEPTH_BITS, ¶ms); + staticContext->opengl32.glGetIntegerv(GL_DEPTH_BITS, ¶ms); opengl32dll = true; } @@ -954,7 +1107,7 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex qWarning("%s: Unable find a suitable pixel format.", __FUNCTION__); break; } - if (!SetPixelFormat(hdc, m_pixelFormat, &m_obtainedPixelFormatDescriptor)) { + if (!QOpenGLStaticContext::opengl32.setPixelFormat(hdc, m_pixelFormat, &m_obtainedPixelFormatDescriptor)) { qErrnoWarning("SetPixelFormat failed."); break; } @@ -978,7 +1131,7 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex } // Query obtained parameters and apply swap interval. - if (!wglMakeCurrent(hdc, m_renderingContext)) { + if (!QOpenGLStaticContext::opengl32.wglMakeCurrent(hdc, m_renderingContext)) { qWarning("Failed to make context current."); break; } @@ -988,7 +1141,7 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex if (m_staticContext->wglGetSwapInternalExt) obtainedSwapInternal = m_staticContext->wglGetSwapInternalExt(); - wglMakeCurrent(0, 0); + QOpenGLStaticContext::opengl32.wglMakeCurrent(0, 0); } while (false); if (hdc) ReleaseDC(dummyWindow, hdc); @@ -1006,7 +1159,7 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex QWindowsGLContext::~QWindowsGLContext() { if (m_renderingContext) - wglDeleteContext(m_renderingContext); + QOpenGLStaticContext::opengl32.wglDeleteContext(m_renderingContext); releaseDCs(); } @@ -1043,11 +1196,11 @@ void QWindowsGLContext::swapBuffers(QPlatformSurface *surface) { if (QWindowsContext::verbose > 1) qCDebug(lcQpaGl) << __FUNCTION__ << surface; - if (const QOpenGLContextData *contextData = findByHWND(m_windowContexts, handleOf(surface))) { - SwapBuffers(contextData->hdc); - } else { + + if (const QOpenGLContextData *contextData = findByHWND(m_windowContexts, handleOf(surface))) + QOpenGLStaticContext::opengl32.swapBuffers(contextData->hdc); + else qWarning("%s: Cannot find window %p", __FUNCTION__, handleOf(surface)); - } } bool QWindowsGLContext::makeCurrent(QPlatformSurface *surface) @@ -1066,11 +1219,11 @@ bool QWindowsGLContext::makeCurrent(QPlatformSurface *surface) // Repeated calls to wglMakeCurrent when vsync is enabled in the driver will // often result in 100% cpuload. This check is cheap and avoids the problem. // This is reproducable on NVidia cards and Intel onboard chips. - if (wglGetCurrentContext() == contextData->renderingContext - && wglGetCurrentDC() == contextData->hdc) { + if (QOpenGLStaticContext::opengl32.wglGetCurrentContext() == contextData->renderingContext + && QOpenGLStaticContext::opengl32.wglGetCurrentDC() == contextData->hdc) { return true; } - return wglMakeCurrent(contextData->hdc, contextData->renderingContext); + return QOpenGLStaticContext::opengl32.wglMakeCurrent(contextData->hdc, contextData->renderingContext); } // Create a new entry. const QOpenGLContextData newContext(m_renderingContext, hwnd, GetDC(hwnd)); @@ -1079,7 +1232,7 @@ bool QWindowsGLContext::makeCurrent(QPlatformSurface *surface) // Initialize pixel format first time. This will apply to // the HWND as well and must be done only once. if (!window->testFlag(QWindowsWindow::OpenGlPixelFormatInitialized)) { - if (!SetPixelFormat(newContext.hdc, m_pixelFormat, &m_obtainedPixelFormatDescriptor)) { + if (!QOpenGLStaticContext::opengl32.setPixelFormat(newContext.hdc, m_pixelFormat, &m_obtainedPixelFormatDescriptor)) { qErrnoWarning("%s: SetPixelFormat() failed", __FUNCTION__); ReleaseDC(newContext.hwnd, newContext.hdc); return false; @@ -1090,7 +1243,7 @@ bool QWindowsGLContext::makeCurrent(QPlatformSurface *surface) } m_windowContexts.append(newContext); - bool success = wglMakeCurrent(newContext.hdc, newContext.renderingContext); + bool success = QOpenGLStaticContext::opengl32.wglMakeCurrent(newContext.hdc, newContext.renderingContext); // Set the swap interval if (m_staticContext->wglSwapInternalExt) { @@ -1110,16 +1263,82 @@ void QWindowsGLContext::doneCurrent() if (QWindowsContext::verbose > 1) qCDebug(lcQpaGl) << __FUNCTION__ << this << m_windowContexts.size() << "contexts"; #endif // DEBUG_GL - wglMakeCurrent(0, 0); + QOpenGLStaticContext::opengl32.wglMakeCurrent(0, 0); releaseDCs(); } -QWindowsGLContext::GL_Proc QWindowsGLContext::getProcAddress(const QByteArray &procName) +QFunctionPointer QWindowsGLContext::getProcAddress(const QByteArray &procName) { - // TODO: Will that work with the calling conventions? - GL_Proc procAddress = reinterpret_cast<GL_Proc>(wglGetProcAddress(procName.constData())); + // We support AllGLFunctionsQueryable, which means this function must be able to + // return a function pointer even for functions that are in GL.h and exported + // normally from opengl32.dll. wglGetProcAddress() is not guaranteed to work for such + // functions, however in QT_OPENGL_DYNAMIC builds QOpenGLFunctions will just blindly + // call into here for _any_ OpenGL function. Hence the need to handle these specially + // here. The list has to match QOpenGLFunctions. See + // QOpenGLFunctionsPrivate::QOpenGLFunctionsPrivate(QOpenGLContext *). + static struct StdFunc { + const char *name; + void *func; + } standardFuncs[] = { + { "glBindTexture", (void *) QOpenGLStaticContext::opengl32.glBindTexture }, + { "glBlendFunc", (void *) QOpenGLStaticContext::opengl32.glBlendFunc }, + { "glClear", (void *) QOpenGLStaticContext::opengl32.glClear }, + { "glClearColor", (void *) QOpenGLStaticContext::opengl32.glClearColor }, + { "glClearStencil", (void *) QOpenGLStaticContext::opengl32.glClearStencil }, + { "glColorMask", (void *) QOpenGLStaticContext::opengl32.glColorMask }, + { "glCopyTexImage2D", (void *) QOpenGLStaticContext::opengl32.glCopyTexImage2D }, + { "glCopyTexSubImage2D", (void *) QOpenGLStaticContext::opengl32.glCopyTexSubImage2D }, + { "glCullFace", (void *) QOpenGLStaticContext::opengl32.glCullFace }, + { "glDeleteTextures", (void *) QOpenGLStaticContext::opengl32.glDeleteTextures }, + { "glDepthFunc", (void *) QOpenGLStaticContext::opengl32.glDepthFunc }, + { "glDepthMask", (void *) QOpenGLStaticContext::opengl32.glDepthMask }, + { "glDisable", (void *) QOpenGLStaticContext::opengl32.glDisable }, + { "glDrawArrays", (void *) QOpenGLStaticContext::opengl32.glDrawArrays }, + { "glDrawElements", (void *) QOpenGLStaticContext::opengl32.glDrawElements }, + { "glEnable", (void *) QOpenGLStaticContext::opengl32.glEnable }, + { "glFinish", (void *) QOpenGLStaticContext::opengl32.glFinish }, + { "glFlush", (void *) QOpenGLStaticContext::opengl32.glFlush }, + { "glFrontFace", (void *) QOpenGLStaticContext::opengl32.glFrontFace }, + { "glGenTextures", (void *) QOpenGLStaticContext::opengl32.glGenTextures }, + { "glGetBooleanv", (void *) QOpenGLStaticContext::opengl32.glGetBooleanv }, + { "glGetError", (void *) QOpenGLStaticContext::opengl32.glGetError }, + { "glGetFloatv", (void *) QOpenGLStaticContext::opengl32.glGetFloatv }, + { "glGetIntegerv", (void *) QOpenGLStaticContext::opengl32.glGetIntegerv }, + { "glGetString", (void *) QOpenGLStaticContext::opengl32.glGetString }, + { "glGetTexParameterfv", (void *) QOpenGLStaticContext::opengl32.glGetTexParameterfv }, + { "glGetTexParameteriv", (void *) QOpenGLStaticContext::opengl32.glGetTexParameteriv }, + { "glHint", (void *) QOpenGLStaticContext::opengl32.glHint }, + { "glIsEnabled", (void *) QOpenGLStaticContext::opengl32.glIsEnabled }, + { "glIsTexture", (void *) QOpenGLStaticContext::opengl32.glIsTexture }, + { "glLineWidth", (void *) QOpenGLStaticContext::opengl32.glLineWidth }, + { "glPixelStorei", (void *) QOpenGLStaticContext::opengl32.glPixelStorei }, + { "glPolygonOffset", (void *) QOpenGLStaticContext::opengl32.glPolygonOffset }, + { "glReadPixels", (void *) QOpenGLStaticContext::opengl32.glReadPixels }, + { "glScissor", (void *) QOpenGLStaticContext::opengl32.glScissor }, + { "glStencilFunc", (void *) QOpenGLStaticContext::opengl32.glStencilFunc }, + { "glStencilMask", (void *) QOpenGLStaticContext::opengl32.glStencilMask }, + { "glStencilOp", (void *) QOpenGLStaticContext::opengl32.glStencilOp }, + { "glTexImage2D", (void *) QOpenGLStaticContext::opengl32.glTexImage2D }, + { "glTexParameterf", (void *) QOpenGLStaticContext::opengl32.glTexParameterf }, + { "glTexParameterfv", (void *) QOpenGLStaticContext::opengl32.glTexParameterfv }, + { "glTexParameteri", (void *) QOpenGLStaticContext::opengl32.glTexParameteri }, + { "glTexParameteriv", (void *) QOpenGLStaticContext::opengl32.glTexParameteriv }, + { "glTexSubImage2D", (void *) QOpenGLStaticContext::opengl32.glTexSubImage2D }, + { "glViewport", (void *) QOpenGLStaticContext::opengl32.glViewport }, + + { "glClearDepth", (void *) QOpenGLStaticContext::opengl32.glClearDepth }, + { "glDepthRange", (void *) QOpenGLStaticContext::opengl32.glDepthRange }, + }; + for (size_t i = 0; i < sizeof(standardFuncs) / sizeof(StdFunc); ++i) + if (procName == standardFuncs[i].name) + return reinterpret_cast<QFunctionPointer>(standardFuncs[i].func); + + // Even though we use QFunctionPointer, it does not mean the function can be called. + // It will need to be cast to the proper function type with the correct calling + // convention. QFunctionPointer is nothing more than a glorified void* here. + QFunctionPointer procAddress = reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress(procName.constData())); if (QWindowsContext::verbose > 1) - qCDebug(lcQpaGl) << __FUNCTION__ << procName << wglGetCurrentContext() << "returns" << procAddress; + qCDebug(lcQpaGl) << __FUNCTION__ << procName << QOpenGLStaticContext::opengl32.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 c6b477128a..dcc31c6197 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.h +++ b/src/plugins/platforms/windows/qwindowsglcontext.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** 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. @@ -44,10 +44,9 @@ #include "array.h" #include "qtwindows_additional.h" +#include "qwindowsopenglcontext.h" -#include <qpa/qplatformopenglcontext.h> #include <QtGui/QOpenGLContext> -#include <QtCore/QSharedPointer> QT_BEGIN_NAMESPACE @@ -81,6 +80,8 @@ struct QOpenGLContextData HDC hdc; }; +class QOpenGLStaticContext; + struct QWindowsOpenGLContextFormat { QWindowsOpenGLContextFormat(); @@ -94,7 +95,87 @@ struct QWindowsOpenGLContextFormat QDebug operator<<(QDebug d, const QWindowsOpenGLContextFormat &); -class QOpenGLStaticContext +struct QWindowsOpengl32DLL +{ + bool init(bool softwareRendering); + void *moduleHandle() const { return m_lib; } + bool moduleIsNotOpengl32() const { return m_nonOpengl32; } + + // Wrappers. Always use these instead of SwapBuffers/wglSwapBuffers/etc. + BOOL swapBuffers(HDC dc); + BOOL setPixelFormat(HDC dc, int pf, const PIXELFORMATDESCRIPTOR *pfd); + + // WGL + HGLRC (WINAPI * wglCreateContext)(HDC dc); + BOOL (WINAPI * wglDeleteContext)(HGLRC context); + HGLRC (WINAPI * wglGetCurrentContext)(); + HDC (WINAPI * wglGetCurrentDC)(); + PROC (WINAPI * wglGetProcAddress)(LPCSTR name); + BOOL (WINAPI * wglMakeCurrent)(HDC dc, HGLRC context); + BOOL (WINAPI * wglShareLists)(HGLRC context1, HGLRC context2); + + // GL1+GLES2 common + void (APIENTRY * glBindTexture)(GLenum target, GLuint texture); + void (APIENTRY * glBlendFunc)(GLenum sfactor, GLenum dfactor); + void (APIENTRY * glClear)(GLbitfield mask); + void (APIENTRY * glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); + void (APIENTRY * glClearStencil)(GLint s); + void (APIENTRY * glColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); + void (APIENTRY * glCopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); + void (APIENTRY * glCopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY * glCullFace)(GLenum mode); + void (APIENTRY * glDeleteTextures)(GLsizei n, const GLuint* textures); + void (APIENTRY * glDepthFunc)(GLenum func); + void (APIENTRY * glDepthMask)(GLboolean flag); + void (APIENTRY * glDisable)(GLenum cap); + void (APIENTRY * glDrawArrays)(GLenum mode, GLint first, GLsizei count); + void (APIENTRY * glDrawElements)(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices); + void (APIENTRY * glEnable)(GLenum cap); + void (APIENTRY * glFinish)(); + void (APIENTRY * glFlush)(); + void (APIENTRY * glFrontFace)(GLenum mode); + void (APIENTRY * glGenTextures)(GLsizei n, GLuint* textures); + void (APIENTRY * glGetBooleanv)(GLenum pname, GLboolean* params); + GLenum (APIENTRY * glGetError)(); + void (APIENTRY * glGetFloatv)(GLenum pname, GLfloat* params); + void (APIENTRY * glGetIntegerv)(GLenum pname, GLint* params); + const GLubyte * (APIENTRY * glGetString)(GLenum name); + void (APIENTRY * glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat* params); + void (APIENTRY * glGetTexParameteriv)(GLenum target, GLenum pname, GLint* params); + void (APIENTRY * glHint)(GLenum target, GLenum mode); + GLboolean (APIENTRY * glIsEnabled)(GLenum cap); + GLboolean (APIENTRY * glIsTexture)(GLuint texture); + void (APIENTRY * glLineWidth)(GLfloat width); + void (APIENTRY * glPixelStorei)(GLenum pname, GLint param); + void (APIENTRY * glPolygonOffset)(GLfloat factor, GLfloat units); + void (APIENTRY * glReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels); + void (APIENTRY * glScissor)(GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY * glStencilFunc)(GLenum func, GLint ref, GLuint mask); + void (APIENTRY * glStencilMask)(GLuint mask); + void (APIENTRY * glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass); + void (APIENTRY * glTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels); + void (APIENTRY * glTexParameterf)(GLenum target, GLenum pname, GLfloat param); + void (APIENTRY * glTexParameterfv)(GLenum target, GLenum pname, const GLfloat* params); + void (APIENTRY * glTexParameteri)(GLenum target, GLenum pname, GLint param); + void (APIENTRY * glTexParameteriv)(GLenum target, GLenum pname, const GLint* params); + void (APIENTRY * glTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels); + void (APIENTRY * glViewport)(GLint x, GLint y, GLsizei width, GLsizei height); + + // GL only + void (APIENTRY * glClearDepth)(GLdouble depth); + void (APIENTRY * glDepthRange)(GLdouble zNear, GLdouble zFar); + +private: + void *resolve(const char *name); + HMODULE m_lib; + bool m_nonOpengl32; + + // For Mesa llvmpipe shipped with a name other than opengl32.dll + BOOL (WINAPI * wglSwapBuffers)(HDC dc); + BOOL (WINAPI * wglSetPixelFormat)(HDC dc, int pf, const PIXELFORMATDESCRIPTOR *pfd); +}; + +class QOpenGLStaticContext : public QWindowsStaticOpenGLContext { Q_DISABLE_COPY(QOpenGLStaticContext) QOpenGLStaticContext(); @@ -125,9 +206,17 @@ public: bool hasExtensions() const { return wglGetPixelFormatAttribIVARB && wglChoosePixelFormatARB && wglCreateContextAttribsARB; } - static QOpenGLStaticContext *create(); + static QOpenGLStaticContext *create(bool softwareRendering = false); static QByteArray getGlString(unsigned int which); + QWindowsOpenGLContext *createContext(QOpenGLContext *context); + void *moduleHandle() const { return opengl32.moduleHandle(); } + QOpenGLContext::OpenGLModuleType moduleType() const { return QOpenGLContext::LibGL; } + + // For a regular opengl32.dll report the ThreadedOpenGL capability. + // For others, which are likely to be software-only, don't. + bool supportsThreadedOpenGL() const { return !opengl32.moduleIsNotOpengl32(); } + const QByteArray vendor; const QByteArray renderer; const QByteArray extensionNames; @@ -139,37 +228,38 @@ public: WglCreateContextAttribsARB wglCreateContextAttribsARB; WglSwapInternalExt wglSwapInternalExt; WglGetSwapInternalExt wglGetSwapInternalExt; + + static QWindowsOpengl32DLL opengl32; }; QDebug operator<<(QDebug d, const QOpenGLStaticContext &); -class QWindowsGLContext : public QPlatformOpenGLContext +class QWindowsGLContext : public QWindowsOpenGLContext { public: - typedef QSharedPointer<QOpenGLStaticContext> QOpenGLStaticContextPtr; - - explicit QWindowsGLContext(const QOpenGLStaticContextPtr &staticContext, - QOpenGLContext *context); + explicit QWindowsGLContext(QOpenGLStaticContext *staticContext, QOpenGLContext *context); virtual ~QWindowsGLContext(); - bool isSharing() const { return m_context->shareHandle(); } - bool isValid() const { return m_renderingContext; } - virtual QSurfaceFormat format() const { return m_obtainedFormat; } + bool isSharing() const Q_DECL_OVERRIDE { return m_context->shareHandle(); } + bool isValid() const Q_DECL_OVERRIDE { return m_renderingContext; } + virtual QSurfaceFormat format() const Q_DECL_OVERRIDE { return m_obtainedFormat; } - virtual void swapBuffers(QPlatformSurface *surface); + virtual void swapBuffers(QPlatformSurface *surface) Q_DECL_OVERRIDE; - virtual bool makeCurrent(QPlatformSurface *surface); - virtual void doneCurrent(); + virtual bool makeCurrent(QPlatformSurface *surface) Q_DECL_OVERRIDE; + virtual void doneCurrent() Q_DECL_OVERRIDE; typedef void (*GL_Proc) (); - virtual GL_Proc getProcAddress(const QByteArray &procName); + virtual QFunctionPointer getProcAddress(const QByteArray &procName) Q_DECL_OVERRIDE; + + HGLRC renderingContext() const { return m_renderingContext; } - HGLRC renderingContext() const { return m_renderingContext; } + void *nativeContext() const Q_DECL_OVERRIDE { return m_renderingContext; } private: inline void releaseDCs(); - const QOpenGLStaticContextPtr m_staticContext; + QOpenGLStaticContext *m_staticContext; QOpenGLContext *m_context; QSurfaceFormat m_obtainedFormat; HGLRC m_renderingContext; diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 78bf833526..529dd75ed5 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch> -** 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. @@ -43,19 +43,7 @@ #include "qwindowsintegration.h" #include "qwindowswindow.h" #include "qwindowscontext.h" - -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) -# include "qwindowseglcontext.h" -# include <QtGui/QOpenGLContext> -#endif - -#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2) -# include "qwindowsglcontext.h" -#endif - -#if !defined(QT_NO_OPENGL) -# include <QtGui/QOpenGLFunctions> -#endif +#include "qwindowsopenglcontext.h" #include "qwindowsscreen.h" #include "qwindowstheme.h" @@ -89,6 +77,19 @@ #include <QtCore/QDebug> #include <QtCore/QVariant> +#include <limits.h> + +#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) +# include "qwindowseglcontext.h" +#endif +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2) +# include "qwindowsglcontext.h" +#endif + +#ifndef Q_OS_WINCE +# include "qwindowsopengltester.h" +#endif + QT_BEGIN_NAMESPACE /*! @@ -134,15 +135,9 @@ QT_BEGIN_NAMESPACE struct QWindowsIntegrationPrivate { -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - typedef QSharedPointer<QWindowsEGLStaticContext> QEGLStaticContextPtr; -#endif -#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2) - typedef QSharedPointer<QOpenGLStaticContext> QOpenGLStaticContextPtr; -#endif - explicit QWindowsIntegrationPrivate(const QStringList ¶mList); ~QWindowsIntegrationPrivate(); + bool ensureStaticOpenGLContext(); unsigned m_options; QWindowsContext m_context; @@ -153,12 +148,9 @@ struct QWindowsIntegrationPrivate QWindowsDrag m_drag; # endif #endif -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - QEGLStaticContextPtr m_staticEGLContext; -#endif -#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2) - QOpenGLStaticContextPtr m_staticOpenGLContext; -#endif +#ifndef QT_NO_OPENGL + QSharedPointer<QWindowsStaticOpenGLContext> m_staticOpenGLContext; +#endif // QT_NO_OPENGL QScopedPointer<QPlatformInputContext> m_inputContext; #ifndef QT_NO_ACCESSIBILITY QWindowsAccessibility m_accessibility; @@ -166,8 +158,32 @@ struct QWindowsIntegrationPrivate QWindowsServices m_services; }; +template <typename IntType> +bool parseIntOption(const QString ¶meter,const QLatin1String &option, + IntType minimumValue, IntType maximumValue, IntType *target) +{ + const int valueLength = parameter.size() - option.size() - 1; + if (valueLength < 1 || !parameter.startsWith(option) || parameter.at(option.size()) != QLatin1Char('=')) + return false; + bool ok; + const QStringRef valueRef = parameter.rightRef(valueLength); + const int value = valueRef.toInt(&ok); + if (ok) { + if (value >= minimumValue && value <= maximumValue) + *target = static_cast<IntType>(value); + else { + qWarning() << "Value" << value << "for option" << option << "out of range" + << minimumValue << ".." << maximumValue; + } + } else { + qWarning() << "Invalid value" << valueRef << "for option" << option; + } + return true; +} + static inline unsigned parseOptions(const QStringList ¶mList, - int *tabletAbsoluteRange) + int *tabletAbsoluteRange, + QtWindows::ProcessDpiAwareness *dpiAwareness) { unsigned options = 0; foreach (const QString ¶m, paramList) { @@ -187,10 +203,11 @@ static inline unsigned parseOptions(const QStringList ¶mList, options |= QWindowsIntegration::DisableArb; } else if (param == QLatin1String("nomousefromtouch")) { options |= QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch; - } else if (param.startsWith(QLatin1String("verbose="))) { - QWindowsContext::verbose = param.right(param.size() - 8).toInt(); - } else if (param.startsWith(QLatin1String("tabletabsoluterange="))) { - *tabletAbsoluteRange = param.rightRef(param.size() - 20).toInt(); + } else if (parseIntOption(param, QLatin1String("verbose"), 0, INT_MAX, &QWindowsContext::verbose) + || parseIntOption(param, QLatin1String("tabletabsoluterange"), 0, INT_MAX, tabletAbsoluteRange) + || parseIntOption(param, QLatin1String("dpiawareness"), QtWindows::ProcessDpiUnaware, QtWindows::ProcessPerMonitorDpiAware, dpiAwareness)) { + } else { + qWarning() << "Unknown option" << param; } } return options; @@ -201,9 +218,13 @@ QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(const QStringList ¶mL , m_fontDatabase(0) { int tabletAbsoluteRange = -1; - m_options = parseOptions(paramList, &tabletAbsoluteRange); + // Default to per-monitor awareness to avoid being scaled when monitors with different DPI + // are connected to Windows 8.1 + QtWindows::ProcessDpiAwareness dpiAwareness = QtWindows::ProcessPerMonitorDpiAware; + m_options = parseOptions(paramList, &tabletAbsoluteRange, &dpiAwareness); if (tabletAbsoluteRange >= 0) m_context.setTabletAbsoluteRange(tabletAbsoluteRange); + m_context.setProcessDpiAwareness(dpiAwareness); } QWindowsIntegrationPrivate::~QWindowsIntegrationPrivate() @@ -242,12 +263,7 @@ bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) co case OpenGL: return true; case ThreadedOpenGL: -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - return QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL - ? QWindowsEGLContext::hasThreadedOpenGLCapability() : true; -# else - return true; -# endif // QT_OPENGL_ES_2 + return d->ensureStaticOpenGLContext() ? d->m_staticOpenGLContext->supportsThreadedOpenGL() : false; #endif // !QT_NO_OPENGL case WindowMasks: return true; @@ -257,6 +273,8 @@ bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) co return true; case RasterGLSurface: return true; + case AllGLFunctionsQueryable: + return true; default: return QPlatformIntegration::hasCapability(cap); } @@ -273,8 +291,7 @@ QWindowsWindowData QWindowsIntegration::createWindowData(QWindow *window) const if (customMarginsV.isValid()) requested.customMargins = qvariant_cast<QMargins>(customMarginsV); - const QWindowsWindowData obtained - = QWindowsWindowData::create(window, requested, window->title()); + QWindowsWindowData obtained = QWindowsWindowData::create(window, requested, window->title()); qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << '<' << window << "\n Requested: " << requested.geometry << "frame incl.: " @@ -292,6 +309,11 @@ QWindowsWindowData QWindowsIntegration::createWindowData(QWindow *window) const QWindowSystemInterface::handleGeometryChange(window, obtained.geometry); } +#ifndef QT_NO_OPENGL + d->ensureStaticOpenGLContext(); + obtained.staticOpenGLContext = d->m_staticOpenGLContext; +#endif // QT_NO_OPENGL + return obtained; } @@ -303,32 +325,80 @@ QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) cons } #ifndef QT_NO_OPENGL -QPlatformOpenGLContext - *QWindowsIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const +static QWindowsStaticOpenGLContext *q_staticOpenGLContext = 0; + +QWindowsStaticOpenGLContext *QWindowsStaticOpenGLContext::create() { - qCDebug(lcQpaGl) << __FUNCTION__ << context->format(); -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - if (QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL) { - if (d->m_staticEGLContext.isNull()) { - QWindowsEGLStaticContext *staticContext = QWindowsEGLStaticContext::create(); - if (!staticContext) - return 0; - d->m_staticEGLContext = QSharedPointer<QWindowsEGLStaticContext>(staticContext); + QWindowsStaticOpenGLContext *ctx = 0; + +#if defined(QT_OPENGL_DYNAMIC) + const QByteArray requested = qgetenv("QT_OPENGL"); // angle, desktop, software + const bool angleRequested = QCoreApplication::testAttribute(Qt::AA_UseOpenGLES) || requested == QByteArrayLiteral("angle"); + const bool desktopRequested = QCoreApplication::testAttribute(Qt::AA_UseDesktopOpenGL) || requested == QByteArrayLiteral("desktop"); + const bool softwareRequested = QCoreApplication::testAttribute(Qt::AA_UseSoftwareOpenGL) || requested == QByteArrayLiteral("software"); + + // If ANGLE is requested, use it, don't try anything else. + if (angleRequested) { + ctx = QWindowsEGLStaticContext::create(); + } else { + // If opengl32.dll seems to be OpenGL 2.x capable, or desktop OpenGL is requested, use it. + if (!softwareRequested && (desktopRequested || QWindowsOpenGLTester::testDesktopGL())) + ctx = QOpenGLStaticContext::create(); + // If failed and desktop OpenGL is not explicitly requested, try ANGLE. + if (!ctx && !desktopRequested && !softwareRequested) + ctx = QWindowsEGLStaticContext::create(); + // Try software. + if (!ctx) { + ctx = QOpenGLStaticContext::create(true); + // If software was explicitly requested but failed, try the regular one. + if (!ctx && softwareRequested && QWindowsOpenGLTester::testDesktopGL()) + ctx = QOpenGLStaticContext::create(); } - return new QWindowsEGLContext(d->m_staticEGLContext, context->format(), context->shareHandle()); } +#elif defined(QT_OPENGL_ES_2) + ctx = QWindowsEGLStaticContext::create(); +#elif !defined(QT_NO_OPENGL) + ctx = QOpenGLStaticContext::create(); #endif -#if !defined(QT_OPENGL_ES_2) - if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) { - if (d->m_staticOpenGLContext.isNull()) - d->m_staticOpenGLContext = - QSharedPointer<QOpenGLStaticContext>(QOpenGLStaticContext::create()); - QScopedPointer<QWindowsGLContext> result(new QWindowsGLContext(d->m_staticOpenGLContext, context)); - return result->isValid() ? result.take() : 0; + + q_staticOpenGLContext = ctx; + + return ctx; +} + +bool QWindowsIntegrationPrivate::ensureStaticOpenGLContext() +{ + if (m_staticOpenGLContext.isNull()) + m_staticOpenGLContext = QSharedPointer<QWindowsStaticOpenGLContext>(QWindowsStaticOpenGLContext::create()); + return !m_staticOpenGLContext.isNull(); +} + +QPlatformOpenGLContext *QWindowsIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const +{ + qCDebug(lcQpaGl) << __FUNCTION__ << context->format(); + if (d->ensureStaticOpenGLContext()) { + QScopedPointer<QWindowsOpenGLContext> result(d->m_staticOpenGLContext->createContext(context)); + if (result->isValid()) + return result.take(); } -#endif // !QT_OPENGL_ES_2 return 0; } + +QOpenGLContext::OpenGLModuleType QWindowsIntegration::openGLModuleType() +{ +#if defined(QT_OPENGL_ES_2) + return QOpenGLContext::LibGLES; +#elif !defined(QT_OPENGL_DYNAMIC) + return QOpenGLContext::LibGL; +#else + return d->ensureStaticOpenGLContext() ? d->m_staticOpenGLContext->moduleType() : QOpenGLContext::LibGL; +#endif +} + +QWindowsStaticOpenGLContext *QWindowsIntegration::staticOpenGLContext() +{ + return q_staticOpenGLContext; +} #endif // !QT_NO_OPENGL /* Workaround for QTBUG-24205: In 'Auto', pick the FreeType engine for diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h index 0f417c8239..a5bf5718c1 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.h +++ b/src/plugins/platforms/windows/qwindowsintegration.h @@ -52,6 +52,7 @@ QT_BEGIN_NAMESPACE struct QWindowsIntegrationPrivate; struct QWindowsWindowData; class QWindowsWindow; +class QWindowsStaticOpenGLContext; class QWindowsIntegration : public QPlatformIntegration { @@ -74,6 +75,8 @@ public: QPlatformWindow *createPlatformWindow(QWindow *window) const; #ifndef QT_NO_OPENGL virtual QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; + QOpenGLContext::OpenGLModuleType openGLModuleType(); + static QWindowsStaticOpenGLContext *staticOpenGLContext(); #endif virtual QAbstractEventDispatcher *createEventDispatcher() const; void initialize() Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmime.cpp index 3af2cff9a0..0343b7f110 100644 --- a/src/plugins/platforms/windows/qwindowsmime.cpp +++ b/src/plugins/platforms/windows/qwindowsmime.cpp @@ -1442,13 +1442,13 @@ QString QLastResortMimes::mimeForFormat(const FORMATETC &formatetc) const \sa QWindowsMime */ -QWindowsMimeConverter::QWindowsMimeConverter() +QWindowsMimeConverter::QWindowsMimeConverter() : m_internalMimeCount(0) { } QWindowsMimeConverter::~QWindowsMimeConverter() { - qDeleteAll(m_mimes); + qDeleteAll(m_mimes.begin(), m_mimes.begin() + m_internalMimeCount); } QWindowsMime * QWindowsMimeConverter::converterToMime(const QString &mimeType, IDataObject *pDataObj) const @@ -1526,6 +1526,7 @@ void QWindowsMimeConverter::ensureInitialized() const m_mimes << new QWindowsMimeImage << new QLastResortMimes << new QWindowsMimeText << new QWindowsMimeURI << new QWindowsMimeHtml << new QBuiltInMimes; + m_internalMimeCount = m_mimes.size(); } } @@ -1552,4 +1553,10 @@ QVariant QWindowsMimeConverter::convertToMime(const QStringList &mimeTypes, return QVariant(); } +void QWindowsMimeConverter::registerMime(QWindowsMime *mime) +{ + ensureInitialized(); + m_mimes.append(mime); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsmime.h b/src/plugins/platforms/windows/qwindowsmime.h index cd0fb4d8b3..e2818422bf 100644 --- a/src/plugins/platforms/windows/qwindowsmime.h +++ b/src/plugins/platforms/windows/qwindowsmime.h @@ -89,12 +89,14 @@ public: QVariant convertToMime(const QStringList &mimeTypes, IDataObject *pDataObj, QVariant::Type preferredType, QString *format = 0) const; -private: - typedef QSharedPointer<QWindowsMime> MimePtr; + void registerMime(QWindowsMime *mime); + void unregisterMime(QWindowsMime *mime) { m_mimes.removeOne(mime); } +private: void ensureInitialized() const; mutable QList<QWindowsMime *> m_mimes; + mutable int m_internalMimeCount; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp index 06c0122bbb..8ec1d8eb2f 100644 --- a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp +++ b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** 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. @@ -42,21 +42,12 @@ #include "qwindowsnativeinterface.h" #include "qwindowswindow.h" #include "qwindowscontext.h" - -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) -# include "qwindowseglcontext.h" -# include <QtGui/QOpenGLContext> -#endif - -#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2) -# include "qwindowsglcontext.h" -#endif - -#if !defined(QT_NO_OPENGL) -# include <QtGui/QOpenGLFunctions> -#endif +#include "qwindowsopenglcontext.h" +#include "qwindowsintegration.h" +#include "qwindowsmime.h" #include <QtGui/QWindow> +#include <QtGui/QOpenGLContext> QT_BEGIN_NAMESPACE @@ -117,6 +108,16 @@ QVariantMap QWindowsNativeInterface::windowProperties(QPlatformWindow *window) c return result; } +void *QWindowsNativeInterface::nativeResourceForIntegration(const QByteArray &resource) +{ +#ifndef QT_NO_OPENGL + if (resource == QByteArrayLiteral("glhandle")) + return QWindowsIntegration::staticOpenGLContext()->moduleHandle(); +#endif + + return 0; +} + #ifndef QT_NO_OPENGL void *QWindowsNativeInterface::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) { @@ -124,24 +125,14 @@ void *QWindowsNativeInterface::nativeResourceForContext(const QByteArray &resour qWarning("%s: '%s' requested for null context or context without handle.", __FUNCTION__, resource.constData()); return 0; } -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - if (QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL) { - 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(); - } -#endif // QT_OPENGL_ES_2 || QT_OPENGL_DYNAMIC -#if !defined(QT_OPENGL_ES_2) - if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) { - QWindowsGLContext *windowsContext = static_cast<QWindowsGLContext *>(context->handle()); - if (resource == QByteArrayLiteral("renderingContext")) - return windowsContext->renderingContext(); - } -#endif // QT_OPENGL_ES_2 || QT_OPENGL_DYNAMIC + + QWindowsOpenGLContext *glcontext = static_cast<QWindowsOpenGLContext *>(context->handle()); + if (resource == QByteArrayLiteral("renderingContext") || resource == QByteArrayLiteral("eglContext")) + return glcontext->nativeContext(); + if (resource == QByteArrayLiteral("eglDisplay")) + return glcontext->nativeDisplay(); + if (resource == QByteArrayLiteral("eglConfig")) + return glcontext->nativeConfig(); qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData()); return 0; @@ -182,4 +173,19 @@ void QWindowsNativeInterface::setAsyncExpose(bool value) QWindowsContext::instance()->setAsyncExpose(value); } +void QWindowsNativeInterface::registerWindowsMime(void *mimeIn) +{ + QWindowsContext::instance()->mimeConverter().registerMime(reinterpret_cast<QWindowsMime *>(mimeIn)); +} + +void QWindowsNativeInterface::unregisterWindowsMime(void *mimeIn) +{ + QWindowsContext::instance()->mimeConverter().unregisterMime(reinterpret_cast<QWindowsMime *>(mimeIn)); +} + +int QWindowsNativeInterface::registerMimeType(const QString &mimeType) +{ + return QWindowsMime::registerMimeType(mimeType); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.h b/src/plugins/platforms/windows/qwindowsnativeinterface.h index 20100d0f49..1afa0571a0 100644 --- a/src/plugins/platforms/windows/qwindowsnativeinterface.h +++ b/src/plugins/platforms/windows/qwindowsnativeinterface.h @@ -66,11 +66,13 @@ class QWindowsNativeInterface : public QPlatformNativeInterface { Q_OBJECT Q_PROPERTY(bool asyncExpose READ asyncExpose WRITE setAsyncExpose) + public: + void *nativeResourceForIntegration(const QByteArray &resource) Q_DECL_OVERRIDE; #ifndef QT_NO_OPENGL - virtual void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context); + void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) Q_DECL_OVERRIDE; #endif - virtual void *nativeResourceForWindow(const QByteArray &resource, QWindow *window); + void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) Q_DECL_OVERRIDE; Q_INVOKABLE void *createMessageWindow(const QString &classNameTemplate, const QString &windowName, @@ -80,13 +82,17 @@ public: Q_INVOKABLE void beep() { MessageBeep(MB_OK); } // For QApplication + Q_INVOKABLE void registerWindowsMime(void *mimeIn); + Q_INVOKABLE void unregisterWindowsMime(void *mime); + Q_INVOKABLE int registerMimeType(const QString &mimeType); + 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); + QVariantMap windowProperties(QPlatformWindow *window) const Q_DECL_OVERRIDE; + QVariant windowProperty(QPlatformWindow *window, const QString &name) const Q_DECL_OVERRIDE; + QVariant windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const Q_DECL_OVERRIDE; + void setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value) Q_DECL_OVERRIDE; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsopenglcontext.h b/src/plugins/platforms/windows/qwindowsopenglcontext.h new file mode 100644 index 0000000000..555af72f37 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsopenglcontext.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** 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 QWINDOWSOPENGLCONTEXT_H +#define QWINDOWSOPENGLCONTEXT_H + +#include <QtGui/QOpenGLContext> +#include <qpa/qplatformopenglcontext.h> + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_OPENGL + +class QWindowsOpenGLContext; + +class QWindowsStaticOpenGLContext +{ +public: + static QWindowsStaticOpenGLContext *create(); + virtual ~QWindowsStaticOpenGLContext() { } + + virtual QWindowsOpenGLContext *createContext(QOpenGLContext *context) = 0; + virtual void *moduleHandle() const = 0; + virtual QOpenGLContext::OpenGLModuleType moduleType() const = 0; + virtual bool supportsThreadedOpenGL() const { return false; } + + // If the windowing system interface needs explicitly created window surfaces (like EGL), + // reimplement these. + virtual void *createWindowSurface(void * /*nativeWindow*/, void * /*nativeConfig*/) { return 0; } + virtual void destroyWindowSurface(void * /*nativeSurface*/) { } +}; + +class QWindowsOpenGLContext : public QPlatformOpenGLContext +{ +public: + virtual ~QWindowsOpenGLContext() { } + + // Returns the native context handle (e.g. HGLRC for WGL, EGLContext for EGL). + virtual void *nativeContext() const = 0; + + // These should be implemented only for some winsys interfaces, for example EGL. + // For others, like WGL, they are not relevant. + virtual void *nativeDisplay() const { return 0; } + virtual void *nativeConfig() const { return 0; } +}; + +#endif // QT_NO_OPENGL + +QT_END_NAMESPACE + +#endif // QWINDOWSOPENGLCONTEXT_H diff --git a/src/plugins/platforms/windows/qwindowsopengltester.cpp b/src/plugins/platforms/windows/qwindowsopengltester.cpp new file mode 100644 index 0000000000..9ee62e6d56 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsopengltester.cpp @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** 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 "qwindowsopengltester.h" +#include "qt_windows.h" +#include "qwindowscontext.h" + +QT_BEGIN_NAMESPACE + +bool QWindowsOpenGLTester::testDesktopGL() +{ + HMODULE lib = 0; + HWND wnd = 0; + HDC dc = 0; + HGLRC context = 0; + LPCTSTR className = L"qtopengltest"; + + HGLRC (WINAPI * CreateContext)(HDC dc) = 0; + BOOL (WINAPI * DeleteContext)(HGLRC context) = 0; + BOOL (WINAPI * MakeCurrent)(HDC dc, HGLRC context) = 0; + PROC (WINAPI * WGL_GetProcAddress)(LPCSTR name) = 0; + + bool result = false; + + // Test #1: Load opengl32.dll and try to resolve an OpenGL 2 function. + // This will typically fail on systems that do not have a real OpenGL driver. + lib = LoadLibraryA("opengl32.dll"); + if (lib) { + CreateContext = reinterpret_cast<HGLRC (WINAPI *)(HDC)>(::GetProcAddress(lib, "wglCreateContext")); + if (!CreateContext) + goto cleanup; + DeleteContext = reinterpret_cast<BOOL (WINAPI *)(HGLRC)>(::GetProcAddress(lib, "wglDeleteContext")); + if (!DeleteContext) + goto cleanup; + MakeCurrent = reinterpret_cast<BOOL (WINAPI *)(HDC, HGLRC)>(::GetProcAddress(lib, "wglMakeCurrent")); + if (!MakeCurrent) + goto cleanup; + WGL_GetProcAddress = reinterpret_cast<PROC (WINAPI *)(LPCSTR)>(::GetProcAddress(lib, "wglGetProcAddress")); + if (!WGL_GetProcAddress) + goto cleanup; + + WNDCLASS wclass; + wclass.cbClsExtra = 0; + wclass.cbWndExtra = 0; + wclass.hInstance = (HINSTANCE) GetModuleHandle(0); + wclass.hIcon = 0; + wclass.hCursor = 0; + wclass.hbrBackground = (HBRUSH) (COLOR_BACKGROUND); + wclass.lpszMenuName = 0; + wclass.lpfnWndProc = DefWindowProc; + wclass.lpszClassName = className; + wclass.style = CS_OWNDC; + if (!RegisterClass(&wclass)) + goto cleanup; + wnd = CreateWindow(className, L"qtopenglproxytest", WS_OVERLAPPED, + 0, 0, 640, 480, 0, 0, wclass.hInstance, 0); + if (!wnd) + goto cleanup; + dc = GetDC(wnd); + if (!dc) + goto cleanup; + + PIXELFORMATDESCRIPTOR pfd; + memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR)); + pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); + pfd.nVersion = 1; + pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_GENERIC_FORMAT; + pfd.iPixelType = PFD_TYPE_RGBA; + // Use the GDI functions. Under the hood this will call the wgl variants in opengl32.dll. + int pixelFormat = ChoosePixelFormat(dc, &pfd); + if (!pixelFormat) + goto cleanup; + if (!SetPixelFormat(dc, pixelFormat, &pfd)) + goto cleanup; + context = CreateContext(dc); + if (!context) + goto cleanup; + if (!MakeCurrent(dc, context)) + goto cleanup; + + // Now that there is finally a context current, try doing something useful. + if (WGL_GetProcAddress("glCreateShader")) { + result = true; + qCDebug(lcQpaGl, "OpenGL 2.0 entry points available"); + } else { + qCDebug(lcQpaGl, "OpenGL 2.0 entry points not found"); + } + } else { + qCDebug(lcQpaGl, "Failed to load opengl32.dll"); + } + +cleanup: + if (MakeCurrent) + MakeCurrent(0, 0); + if (context) + DeleteContext(context); + if (dc && wnd) + ReleaseDC(wnd, dc); + if (wnd) { + DestroyWindow(wnd); + UnregisterClass(className, GetModuleHandle(0)); + } + // No FreeLibrary. Some implementations, Mesa in particular, deadlock when trying to unload. + + return result; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsopengltester.h b/src/plugins/platforms/windows/qwindowsopengltester.h new file mode 100644 index 0000000000..f7cd7e3005 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsopengltester.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** 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 <qtwindowsglobal.h> + +QT_BEGIN_NAMESPACE + +class QWindowsOpenGLTester +{ +public: + static bool testDesktopGL(); +}; + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index a6e2aabaf0..bcdb8a2352 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** 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. @@ -68,6 +68,21 @@ static inline QDpi deviceDPI(HDC hdc) return QDpi(GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY)); } +#ifndef Q_OS_WINCE + +static inline QDpi monitorDPI(HMONITOR hMonitor) +{ + if (QWindowsContext::shcoredll.isValid()) { + UINT dpiX; + UINT dpiY; + if (SUCCEEDED(QWindowsContext::shcoredll.getDpiForMonitor(hMonitor, 0, &dpiX, &dpiY))) + return QDpi(dpiX, dpiY); + } + return QDpi(0, 0); +} + +#endif // !Q_OS_WINCE + static inline QSizeF deviceSizeMM(const QSize &pixels, const QDpi &dpi) { const qreal inchToMM = 25.4; @@ -110,7 +125,12 @@ BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM HDC hdc = CreateDC(info.szDevice, NULL, NULL, NULL); #endif if (hdc) { +#ifndef Q_OS_WINCE + const QDpi dpi = monitorDPI(hMonitor); + data.dpi = dpi.first ? dpi : deviceDPI(hdc); +#else data.dpi = deviceDPI(hdc); +#endif data.depth = GetDeviceCaps(hdc, BITSPIXEL); data.format = data.depth == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32; data.physicalSizeMM = QSizeF(GetDeviceCaps(hdc, HORZSIZE), GetDeviceCaps(hdc, VERTSIZE)); @@ -387,6 +407,30 @@ static inline int indexOfMonitor(const QList<QWindowsScreenData> &screenData, return -1; } +void QWindowsScreenManager::removeScreen(int index) +{ + qCDebug(lcQpaWindows) << "Removing Monitor:" << m_screens.at(index)->data(); + QScreen *screen = m_screens.at(index)->screen(); + QScreen *primaryScreen = QGuiApplication::primaryScreen(); + // QTBUG-38650: When a screen is disconnected, Windows will automatically + // move the Window to another screen. This will trigger a geometry change + // event, but unfortunately after the screen destruction signal. To prevent + // QtGui from automatically hiding the QWindow, pretend all Windows move to + // the primary screen first (which is likely the correct, final screen). + if (screen != primaryScreen) { + unsigned movedWindowCount = 0; + foreach (QWindow *w, QGuiApplication::topLevelWindows()) { + if (w->screen() == screen && w->handle() && w->type() != Qt::Desktop) { + QWindowSystemInterface::handleWindowScreenChanged(w, primaryScreen); + ++movedWindowCount; + } + } + if (movedWindowCount) + QWindowSystemInterface::flushWindowSystemEvents(); + } + delete m_screens.takeAt(index); +} + /*! \brief Synchronizes the screen list, adds new screens, removes deleted ones and propagates resolution changes to QWindowSystemInterface. @@ -412,10 +456,8 @@ bool QWindowsScreenManager::handleScreenChanges() // temporary lock screen to avoid window recreation (QTBUG-33062). if (!lockScreen) { for (int i = m_screens.size() - 1; i >= 0; --i) { - if (indexOfMonitor(newDataList, m_screens.at(i)->data().name) == -1) { - qCDebug(lcQpaWindows) << "Removing Monitor: " << m_screens.at(i) ->data(); - delete m_screens.takeAt(i); - } // not found + if (indexOfMonitor(newDataList, m_screens.at(i)->data().name) == -1) + removeScreen(i); } // for existing screens } // not lock screen return true; diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h index 930814a17d..00f0b316c2 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.h +++ b/src/plugins/platforms/windows/qwindowsscreen.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** 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. @@ -143,6 +143,8 @@ public: const WindowsScreenList &screens() const { return m_screens; } private: + void removeScreen(int index); + WindowsScreenList m_screens; int m_lastDepth; WORD m_lastHorizontalResolution; diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index cdc0b24464..18b4cc85cc 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** 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. @@ -48,15 +48,11 @@ # include "qwindowscursor.h" #endif -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) -# include "qwindowseglcontext.h" -# include <QtGui/QOpenGLFunctions> -#endif - #include <QtGui/QGuiApplication> #include <QtGui/QScreen> #include <QtGui/QWindow> #include <QtGui/QRegion> +#include <QtGui/QOpenGLContext> #include <private/qsystemlibrary_p.h> #include <private/qwindow_p.h> #include <private/qguiapplication_p.h> @@ -110,6 +106,8 @@ static QByteArray debugWinExStyle(DWORD exStyle) rc += " WS_EX_CONTEXTHELP"; if (exStyle & WS_EX_LAYERED) rc += " WS_EX_LAYERED"; + if (exStyle & WS_EX_DLGMODALFRAME) + rc += " WS_EX_DLGMODALFRAME"; return rc; } @@ -183,6 +181,14 @@ QDebug operator<<(QDebug d, const NCCALCSIZE_PARAMS &p) static inline QRect frameGeometry(HWND hwnd, bool topLevel) { RECT rect = { 0, 0, 0, 0 }; +#ifndef Q_OS_WINCE + if (topLevel) { + WINDOWPLACEMENT windowPlacement; + GetWindowPlacement(hwnd, &windowPlacement); + if (windowPlacement.showCmd == SW_SHOWMINIMIZED) + return qrectFromRECT(windowPlacement.rcNormalPosition); + } +#endif // !Q_OS_WINCE GetWindowRect(hwnd, &rect); // Screen coordinates. const HWND parent = GetParent(hwnd); if (parent && !topLevel) { @@ -513,6 +519,10 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag } if (flags & Qt::WindowSystemMenuHint) style |= WS_SYSMENU; + else if (dialog) { + style |= WS_SYSMENU | WS_BORDER; // QTBUG-2027, dialogs without system menu. + exStyle |= WS_EX_DLGMODALFRAME; + } if (flags & Qt::WindowMinimizeButtonHint) style |= WS_MINIMIZEBOX; if (shouldShowMaximizeButton(w, flags)) @@ -861,15 +871,13 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) m_opacity(1.0), m_dropTarget(0), m_savedStyle(0), - m_format(aWindow->format()), -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - m_eglSurface(0), -#endif + m_format(aWindow->requestedFormat()), #ifdef Q_OS_WINCE m_previouslyHidden(false), #endif m_iconSmall(0), - m_iconBig(0) + m_iconBig(0), + m_surface(0) { // Clear the creation context as the window can be found in QWindowsContext's map. QWindowsContext::instance()->setWindowCreationContext(QSharedPointer<QWindowCreationContext>()); @@ -877,13 +885,14 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) const Qt::WindowType type = aWindow->type(); if (type == Qt::Desktop) return; // No further handling for Qt::Desktop +#ifndef QT_NO_OPENGL if (aWindow->surfaceType() == QWindow::OpenGLSurface) { - setFlag(OpenGLSurface); -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - if (QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL) + if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) + setFlag(OpenGLSurface); + else setFlag(OpenGL_ES2); -#endif } +#endif // QT_NO_OPENGL updateDropSite(); #ifndef Q_OS_WINCE @@ -947,13 +956,10 @@ void QWindowsWindow::destroyWindow() if (hasMouseCapture()) setMouseGrabEnabled(false); setDropSiteEnabled(false); -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - if (m_eglSurface) { - qCDebug(lcQpaGl) << __FUNCTION__ << "Freeing EGL surface " << m_eglSurface << window(); - eglDestroySurface(m_staticEglContext->display(), m_eglSurface); - m_eglSurface = 0; + if (m_surface) { + m_data.staticOpenGLContext->destroyWindowSurface(m_surface); + m_surface = 0; } -#endif #ifdef Q_OS_WINCE if ((m_windowState & Qt::WindowFullScreen) && !m_previouslyHidden) { HWND handle = FindWindow(L"HHTaskBar", L""); @@ -1368,6 +1374,25 @@ void QWindowsWindow::handleResized(int wParam) } } +// Return the effective screen for full screen mode in a virtual desktop. +static QScreen *effectiveScreen(const QWindow *w) +{ + QRect geometry = w->geometry(); + if (!w->isTopLevel()) + geometry.moveTopLeft(w->mapToGlobal(geometry.topLeft())); + + QScreen *screen = w->screen(); + if (!screen->geometry().intersects(geometry)) { + foreach (QScreen *sibling, screen->virtualSiblings()) { + if (sibling->geometry().intersects(geometry)) { + screen = sibling; + break; + } + } + } + return screen; +} + void QWindowsWindow::handleGeometryChange() { //Prevent recursive resizes for Windows CE @@ -1383,6 +1408,14 @@ void QWindowsWindow::handleGeometryChange() && !(m_data.geometry.width() > previousGeometry.width() || m_data.geometry.height() > previousGeometry.height())) { fireExpose(QRegion(m_data.geometry), true); } + if (previousGeometry.topLeft() != m_data.geometry.topLeft()) { + QWindow *w = window(); + if (w->isTopLevel()) { + QScreen *newScreen = effectiveScreen(w); + if (newScreen != w->screen()) + QWindowSystemInterface::handleWindowScreenChanged(w, newScreen); + } + } if (testFlag(SynchronousGeometryChangeEvent)) QWindowSystemInterface::flushWindowSystemEvents(); @@ -1399,15 +1432,29 @@ void QWindowsWindow::setGeometry_sys(const QRect &rect) const << margins << " to " <<rect << " new frame: " << frameGeometry; - const bool rc = MoveWindow(m_data.hwnd, frameGeometry.x(), frameGeometry.y(), - frameGeometry.width(), frameGeometry.height(), true); + bool result = false; +#ifndef Q_OS_WINCE + WINDOWPLACEMENT windowPlacement; + GetWindowPlacement(m_data.hwnd, &windowPlacement); + // If the window is hidden and in maximized state or minimized, instead of moving the + // window, set the normal position of the window. + if ((windowPlacement.showCmd == SW_MAXIMIZE && !IsWindowVisible(m_data.hwnd)) + || windowPlacement.showCmd == SW_SHOWMINIMIZED) { + windowPlacement.rcNormalPosition = RECTfromQRect(frameGeometry); + windowPlacement.showCmd = windowPlacement.showCmd == SW_SHOWMINIMIZED ? SW_SHOWMINIMIZED : SW_HIDE; + result = SetWindowPlacement(m_data.hwnd, &windowPlacement); + } else +#endif // !Q_OS_WINCE + { + result = MoveWindow(m_data.hwnd, frameGeometry.x(), frameGeometry.y(), + frameGeometry.width(), frameGeometry.height(), true); + } qCDebug(lcQpaWindows) << '<' << __FUNCTION__ << this << window() - << " \n resulting " << rc << geometry_sys(); + << " \n resulting " << result << geometry_sys(); } QRect QWindowsWindow::frameGeometry_sys() const { - // Warning: Returns bogus values when minimized. bool isRealTopLevel = window()->isTopLevel() && !m_data.embedded; return frameGeometry(m_data.hwnd, isRealTopLevel); } @@ -1573,23 +1620,9 @@ void QWindowsWindow::setWindowState(Qt::WindowState state) } } -// Return the effective screen for full screen mode in a virtual desktop. -static const QScreen *effectiveScreen(const QWindow *w) -{ - QPoint center = w->geometry().center(); - if (!w->isTopLevel()) - center = w->mapToGlobal(center); - const QScreen *screen = w->screen(); - if (!screen->geometry().contains(center)) - foreach (const QScreen *sibling, screen->virtualSiblings()) - if (sibling->geometry().contains(center)) - return sibling; - return screen; -} - bool QWindowsWindow::isFullScreen_sys() const { - return window()->isTopLevel() && geometry_sys() == effectiveScreen(window())->geometry(); + return window()->isTopLevel() && geometry_sys() == window()->screen()->geometry(); } /*! @@ -1669,7 +1702,7 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) setStyle(newStyle); // Use geometry of QWindow::screen() within creation or the virtual screen the // window is in (QTBUG-31166, QTBUG-30724). - const QScreen *screen = testFlag(WithinCreate) ? window()->screen() : effectiveScreen(window()); + const QScreen *screen = window()->screen(); const QRect r = screen->geometry(); const UINT swpf = SWP_FRAMECHANGED | SWP_NOACTIVATE; const bool wasSync = testFlag(SynchronousGeometryChangeEvent); @@ -1936,7 +1969,7 @@ void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const && (m_data.flags & Qt::FramelessWindowHint)) { // This block fixes QTBUG-8361: Frameless windows shouldn't cover the // taskbar when maximized - const QScreen *screen = effectiveScreen(window()); + const QScreen *screen = window()->screen(); // Documentation of MINMAXINFO states that it will only work for the primary screen if (screen && screen == QGuiApplication::primaryScreen()) { @@ -2141,23 +2174,6 @@ void QWindowsWindow::setEnabled(bool enabled) setStyle(newStyle); } -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) -EGLSurface QWindowsWindow::ensureEglSurfaceHandle(const QWindowsWindow::QWindowsEGLStaticContextPtr &staticContext, EGLConfig config) -{ - if (!m_eglSurface) { - m_staticEglContext = staticContext; - m_eglSurface = eglCreateWindowSurface(staticContext->display(), config, (EGLNativeWindowType)m_data.hwnd, NULL); - if (m_eglSurface == EGL_NO_SURFACE) - qWarning("%s: Could not create the egl surface for %s/'%s' (eglCreateWindowSurface failed): error = 0x%x\n", - Q_FUNC_INFO, window()->metaObject()->className(), - qPrintable(window()->objectName()), eglGetError()); - - qCDebug(lcQpaGl) << __FUNCTION__<<"Created EGL surface "<< m_eglSurface <<window(); - } - return m_eglSurface; -} -#endif // QT_OPENGL_ES_2 - QByteArray QWindowsWindow::debugWindowFlags(Qt::WindowFlags wf) { const int iwf = int(wf); @@ -2269,4 +2285,12 @@ void QWindowsWindow::setCustomMargins(const QMargins &newCustomMargins) } } +void *QWindowsWindow::surface(void *nativeConfig) +{ + if (!m_surface) + m_surface = m_data.staticOpenGLContext->createWindowSurface(m_data.hwnd, nativeConfig); + + return m_surface; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index cb437b76d0..d6d671a3e4 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** 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. @@ -47,23 +47,15 @@ # include "qplatformfunctions_wince.h" #endif #include "qwindowscursor.h" +#include "qwindowsopenglcontext.h" #include <qpa/qplatformwindow.h> -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) -# include <QtCore/QSharedPointer> -# include <EGL/egl.h> -#endif - QT_BEGIN_NAMESPACE class QWindowsOleDropTarget; class QDebug; -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) -class QWindowsEGLStaticContext; -#endif - struct QWindowsGeometryHint { QWindowsGeometryHint() {} @@ -121,6 +113,9 @@ struct QWindowsWindowData QMargins customMargins; // User-defined, additional frame for NCCALCSIZE HWND hwnd; bool embedded; +#ifndef QT_NO_OPENGL + QSharedPointer<QWindowsStaticOpenGLContext> staticOpenGLContext; +#endif // QT_NO_OPENGL static QWindowsWindowData create(const QWindow *w, const QWindowsWindowData ¶meters, @@ -130,10 +125,6 @@ struct QWindowsWindowData class QWindowsWindow : public QPlatformWindow { public: -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - typedef QSharedPointer<QWindowsEGLStaticContext> QWindowsEGLStaticContextPtr; -#endif - enum Flags { AutoMouseCapture = 0x1, //! Automatic mouse capture on button press. @@ -207,11 +198,6 @@ public: QMargins customMargins() const { return m_data.customMargins; } void setCustomMargins(const QMargins &m); -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - EGLSurface eglSurfaceHandle() const { return m_eglSurface;} - EGLSurface ensureEglSurfaceHandle(const QWindowsEGLStaticContextPtr &staticContext, EGLConfig config); -#endif - inline unsigned style() const { return GetWindowLongPtr(m_data.hwnd, GWL_STYLE); } void setStyle(unsigned s) const; @@ -263,6 +249,8 @@ public: bool isEnabled() const; void setWindowIcon(const QIcon &icon); + void *surface(void *nativeConfig); + #ifndef Q_OS_WINCE void setAlertState(bool enabled); bool isAlertState() const { return testFlag(AlertState); } @@ -302,15 +290,12 @@ private: unsigned m_savedStyle; QRect m_savedFrameGeometry; const QSurfaceFormat m_format; -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - EGLSurface m_eglSurface; - QSharedPointer<QWindowsEGLStaticContext> m_staticEglContext; -#endif #ifdef Q_OS_WINCE bool m_previouslyHidden; #endif HICON m_iconSmall; HICON m_iconBig; + void *m_surface; }; // Debug diff --git a/src/plugins/platforms/windows/windows.pri b/src/plugins/platforms/windows/windows.pri index 13799ba1ba..fec9af2645 100644 --- a/src/plugins/platforms/windows/windows.pri +++ b/src/plugins/platforms/windows/windows.pri @@ -66,8 +66,12 @@ HEADERS += \ $$PWD/qwindowsnativeimage.h \ $$PWD/qwindowsnativeinterface.h +!wince: HEADERS += $$PWD/qwindowsopengltester.h + INCLUDEPATH += $$PWD +contains(QT_CONFIG,opengl): HEADERS += $$PWD/qwindowsopenglcontext.h + contains(QT_CONFIG, opengles2) { SOURCES += $$PWD/qwindowseglcontext.cpp HEADERS += $$PWD/qwindowseglcontext.h @@ -78,7 +82,8 @@ contains(QT_CONFIG, opengles2) { # Dynamic GL needs both WGL and EGL contains(QT_CONFIG,dynamicgl) { - SOURCES += $$PWD/qwindowseglcontext.cpp + SOURCES += $$PWD/qwindowseglcontext.cpp \ + $$PWD/qwindowsopengltester.cpp HEADERS += $$PWD/qwindowseglcontext.h } diff --git a/src/plugins/platforms/winrt/qwinrtcursor.cpp b/src/plugins/platforms/winrt/qwinrtcursor.cpp index f09454ebc3..d2d87bde0b 100644 --- a/src/plugins/platforms/winrt/qwinrtcursor.cpp +++ b/src/plugins/platforms/winrt/qwinrtcursor.cpp @@ -40,40 +40,54 @@ ****************************************************************************/ #include "qwinrtcursor.h" +#include "qwinrtscreen.h" + +#include <QtCore/qfunctions_winrt.h> +#include <QtGui/QGuiApplication> +#include <QtGui/QScreen> #include <wrl.h> #include <windows.ui.core.h> #include <windows.foundation.h> +using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; using namespace ABI::Windows::UI::Core; using namespace ABI::Windows::Foundation; -QT_BEGIN_NAMESPACE +QT_USE_NAMESPACE + +class QWinRTCursorPrivate +{ +public: + ComPtr<ICoreCursorFactory> cursorFactory; +}; -QWinRTCursor::QWinRTCursor(ICoreWindow *window) : m_window(window), m_cursorFactory(nullptr) +QWinRTCursor::QWinRTCursor() + : d_ptr(new QWinRTCursorPrivate) { -#ifndef Q_OS_WINPHONE - GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Core_CoreCursor).Get(), &m_cursorFactory); -#endif + Q_D(QWinRTCursor); + + HRESULT hr; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Core_CoreCursor).Get(), + IID_PPV_ARGS(&d->cursorFactory)); + Q_ASSERT_SUCCEEDED(hr); } QWinRTCursor::~QWinRTCursor() { - if (m_cursorFactory) - m_cursorFactory->Release(); } #ifndef QT_NO_CURSOR -void QWinRTCursor::changeCursor(QCursor *windowCursor, QWindow *) +void QWinRTCursor::changeCursor(QCursor *windowCursor, QWindow *window) { -#ifndef Q_OS_WINPHONE - if (!m_cursorFactory) - return; + Q_D(QWinRTCursor); + + ICoreWindow *coreWindow = static_cast<QWinRTScreen *>(window->screen()->handle())->coreWindow(); CoreCursorType type; switch (windowCursor ? windowCursor->shape() : Qt::ArrowCursor) { case Qt::BlankCursor: - m_window->put_PointerCursor(nullptr); + coreWindow->put_PointerCursor(Q_NULLPTR); return; default: case Qt::OpenHandCursor: @@ -132,24 +146,20 @@ void QWinRTCursor::changeCursor(QCursor *windowCursor, QWindow *) break; } - ICoreCursor *cursor; - if (SUCCEEDED(m_cursorFactory->CreateCursor(type, 0, &cursor))) - m_window->put_PointerCursor(cursor); -#else // Q_OS_WINPHONE - Q_UNUSED(windowCursor) -#endif // Q_OS_WINPHONE + ComPtr<ICoreCursor> cursor; + HRESULT hr = d->cursorFactory->CreateCursor(type, 0, &cursor); + RETURN_VOID_IF_FAILED("Failed to create native cursor."); + + hr = coreWindow->put_PointerCursor(cursor.Get()); + RETURN_VOID_IF_FAILED("Failed to set native cursor."); } #endif // QT_NO_CURSOR QPoint QWinRTCursor::pos() const { -#ifdef Q_OS_WINPHONE - return QPlatformCursor::pos(); -#else + ICoreWindow *coreWindow = + static_cast<QWinRTScreen *>(QGuiApplication::primaryScreen()->handle())->coreWindow(); Point point; - m_window->get_PointerPosition(&point); + coreWindow->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 index f7b301a98b..a08002f34c 100644 --- a/src/plugins/platforms/winrt/qwinrtcursor.h +++ b/src/plugins/platforms/winrt/qwinrtcursor.h @@ -44,34 +44,22 @@ #include <qpa/qplatformcursor.h> -namespace ABI { - namespace Windows { - namespace UI { - namespace Core { - struct ICoreWindow; - struct ICoreCursorFactory; - } - } - } -} - -QT_BEGIN_NAMESPACE +QT_USE_NAMESPACE +class QWinRTCursorPrivate; class QWinRTCursor : public QPlatformCursor { public: - explicit QWinRTCursor(ABI::Windows::UI::Core::ICoreWindow *window); + explicit QWinRTCursor(); ~QWinRTCursor(); #ifndef QT_NO_CURSOR - void changeCursor(QCursor * windowCursor, QWindow *); + void changeCursor(QCursor * windowCursor, QWindow *window); #endif QPoint pos() const; private: - ABI::Windows::UI::Core::ICoreWindow *m_window; - ABI::Windows::UI::Core::ICoreCursorFactory *m_cursorFactory; + QScopedPointer<QWinRTCursorPrivate> d_ptr; + Q_DECLARE_PRIVATE(QWinRTCursor) }; -QT_END_NAMESPACE - #endif // QWINRTCURSOR_H diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp index b3a2cafa2e..806b8f99bb 100644 --- a/src/plugins/platforms/winrt/qwinrtintegration.cpp +++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp @@ -82,26 +82,7 @@ QWinRTIntegration::QWinRTIntegration() , 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); + m_screen = new QWinRTScreen; screenAdded(m_screen); m_success = true; diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index f948cf9924..cbc7449591 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** 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. @@ -51,6 +51,7 @@ #include <QtPlatformSupport/private/qeglconvenience_p.h> #include <qpa/qwindowsysteminterface.h> #include <QtCore/qt_windows.h> +#include <QtCore/qfunctions_winrt.h> #include <wrl.h> #include <windows.system.h> @@ -93,11 +94,7 @@ typedef ITypedEventHandler<CoreWindow*, PointerEventArgs*> PointerHandler; typedef ITypedEventHandler<CoreWindow*, WindowSizeChangedEventArgs*> SizeChangedHandler; typedef ITypedEventHandler<CoreWindow*, VisibilityChangedEventArgs*> VisibilityChangedHandler; typedef ITypedEventHandler<CoreWindow*, AutomationProviderRequestedEventArgs*> AutomationProviderRequestedHandler; -#if _MSC_VER <=1700 -typedef IDisplayPropertiesEventHandler DisplayInformationHandler; -#else typedef ITypedEventHandler<DisplayInformation*, IInspectable*> DisplayInformationHandler; -#endif #ifdef Q_OS_WINPHONE typedef IEventHandler<BackPressedEventArgs*> BackPressedHandler; #endif @@ -419,199 +416,272 @@ static inline Qt::Key qKeyFromCode(quint32 code, int mods) return static_cast<Qt::Key>(code & 0xff); } -QWinRTScreen::QWinRTScreen(ICoreWindow *window) - : m_coreWindow(window) - , m_depth(32) - , m_format(QImage::Format_ARGB32_Premultiplied) +typedef HRESULT (__stdcall ICoreApplication::*CoreApplicationCallbackRemover)(EventRegistrationToken); +uint qHash(CoreApplicationCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } +typedef HRESULT (__stdcall ICoreWindow::*CoreWindowCallbackRemover)(EventRegistrationToken); +uint qHash(CoreWindowCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } +typedef HRESULT (__stdcall IDisplayInformation::*DisplayCallbackRemover)(EventRegistrationToken); +uint qHash(DisplayCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } +#ifdef Q_OS_WINPHONE +typedef HRESULT (__stdcall IHardwareButtonsStatics::*HardwareButtonsCallbackRemover)(EventRegistrationToken); +uint qHash(HardwareButtonsCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } +#endif + +class QWinRTScreenPrivate +{ +public: + ComPtr<ICoreApplication> application; + ComPtr<ICoreWindow> coreWindow; + ComPtr<IDisplayInformationStatics> displayInformationStatics; + ComPtr<IDisplayInformation> displayInformation; #ifdef Q_OS_WINPHONE - , m_inputContext(new QWinRTInputContext(m_coreWindow)) + ComPtr<IHardwareButtonsStatics> hardwareButtons; +#endif + + QScopedPointer<QWinRTCursor> cursor; +#ifdef Q_OS_WINPHONE + QScopedPointer<QWinRTInputContext> inputContext; #else - , m_inputContext(Make<QWinRTInputContext>(m_coreWindow).Detach()) + ComPtr<QWinRTInputContext> inputContext; +#endif + + QRectF geometry; + QSurfaceFormat surfaceFormat; + qreal dpi; + qreal devicePixelRatio; + Qt::ScreenOrientation nativeOrientation; + Qt::ScreenOrientation orientation; + QList<QWindow *> visibleWindows; +#ifndef Q_OS_WINPHONE + QHash<quint32, QPair<Qt::Key, QString>> activeKeys; +#endif + QTouchDevice *touchDevice; + QHash<quint32, QWindowSystemInterface::TouchPoint> touchPoints; + + EGLDisplay eglDisplay; + EGLSurface eglSurface; + + QHash<CoreApplicationCallbackRemover, EventRegistrationToken> applicationTokens; + QHash<CoreWindowCallbackRemover, EventRegistrationToken> windowTokens; + QHash<DisplayCallbackRemover, EventRegistrationToken> displayTokens; +#ifdef Q_OS_WINPHONE + QHash<HardwareButtonsCallbackRemover, EventRegistrationToken> buttonsTokens; #endif - , m_cursor(new QWinRTCursor(window)) - , m_devicePixelRatio(1.0) - , m_orientation(Qt::PrimaryOrientation) - , m_touchDevice(Q_NULLPTR) +}; + +QWinRTScreen::QWinRTScreen() + : d_ptr(new QWinRTScreenPrivate) { + Q_D(QWinRTScreen); + d->orientation = Qt::PrimaryOrientation; + d->touchDevice = Q_NULLPTR; + + // Obtain the WinRT Application, view, and window + HRESULT hr; + hr = RoGetActivationFactory(Wrappers::HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(), + IID_PPV_ARGS(&d->application)); + Q_ASSERT_SUCCEEDED(hr); + hr = d->application->add_Suspending(Callback<SuspendHandler>(this, &QWinRTScreen::onSuspended).Get(), &d->applicationTokens[&ICoreApplication::remove_Resuming]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->application->add_Resuming(Callback<ResumeHandler>(this, &QWinRTScreen::onResume).Get(), &d->applicationTokens[&ICoreApplication::remove_Resuming]); + Q_ASSERT_SUCCEEDED(hr); + + ComPtr<ICoreApplicationView> view; + hr = d->application->GetCurrentView(&view); + Q_ASSERT_SUCCEEDED(hr); + hr = view->get_CoreWindow(&d->coreWindow); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->Activate(); + Q_ASSERT_SUCCEEDED(hr); + +#ifdef Q_OS_WINPHONE + d->inputContext.reset(new QWinRTInputContext(d->coreWindow.Get())); +#else + d->inputContext = Make<QWinRTInputContext>(d->coreWindow.Get()); +#endif + Rect rect; - window->get_Bounds(&rect); - m_geometry = QRectF(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) + d->coreWindow->get_Bounds(&rect); + d->geometry = QRectF(0, 0, rect.Width, rect.Height); + + d->surfaceFormat.setAlphaBufferSize(0); + d->surfaceFormat.setRedBufferSize(8); + d->surfaceFormat.setGreenBufferSize(8); + d->surfaceFormat.setBlueBufferSize(8); + d->surfaceFormat.setRenderableType(QSurfaceFormat::OpenGLES); + d->surfaceFormat.setSamples(1); + d->surfaceFormat.setSwapBehavior(QSurfaceFormat::DoubleBuffer); + d->surfaceFormat.setDepthBufferSize(24); + d->surfaceFormat.setStencilBufferSize(8); + + d->eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (d->eglDisplay == EGL_NO_DISPLAY) qFatal("Qt WinRT platform plugin: failed to initialize EGL display."); - if (!eglInitialize(m_eglDisplay, NULL, NULL)) + if (!eglInitialize(d->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) + d->eglSurface = eglCreateWindowSurface(d->eglDisplay, q_configFromGLFormat(d->eglDisplay, d->surfaceFormat), d->coreWindow.Get(), NULL); + if (d->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]); + hr = d->coreWindow->add_KeyDown(Callback<KeyHandler>(this, &QWinRTScreen::onKeyDown).Get(), &d->windowTokens[&ICoreWindow::remove_KeyDown]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_KeyUp(Callback<KeyHandler>(this, &QWinRTScreen::onKeyUp).Get(), &d->windowTokens[&ICoreWindow::remove_KeyUp]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_CharacterReceived(Callback<CharacterReceivedHandler>(this, &QWinRTScreen::onCharacterReceived).Get(), &d->windowTokens[&ICoreWindow::remove_CharacterReceived]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_PointerEntered(Callback<PointerHandler>(this, &QWinRTScreen::onPointerEntered).Get(), &d->windowTokens[&ICoreWindow::remove_PointerEntered]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_PointerExited(Callback<PointerHandler>(this, &QWinRTScreen::onPointerExited).Get(), &d->windowTokens[&ICoreWindow::remove_PointerExited]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_PointerMoved(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerMoved]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_PointerPressed(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerPressed]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_PointerReleased(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerReleased]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_PointerWheelChanged(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerWheelChanged]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_SizeChanged(Callback<SizeChangedHandler>(this, &QWinRTScreen::onSizeChanged).Get(), &d->windowTokens[&ICoreWindow::remove_SizeChanged]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_Activated(Callback<ActivatedHandler>(this, &QWinRTScreen::onActivated).Get(), &d->windowTokens[&ICoreWindow::remove_Activated]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_Closed(Callback<ClosedHandler>(this, &QWinRTScreen::onClosed).Get(), &d->windowTokens[&ICoreWindow::remove_Closed]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_VisibilityChanged(Callback<VisibilityChangedHandler>(this, &QWinRTScreen::onVisibilityChanged).Get(), &d->windowTokens[&ICoreWindow::remove_VisibilityChanged]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->coreWindow->add_AutomationProviderRequested(Callback<AutomationProviderRequestedHandler>(this, &QWinRTScreen::onAutomationProviderRequested).Get(), &d->windowTokens[&ICoreWindow::remove_AutomationProviderRequested]); + Q_ASSERT_SUCCEEDED(hr); #ifdef Q_OS_WINPHONE - ComPtr<IHardwareButtonsStatics> hardwareButtons; - if (SUCCEEDED(GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Phone_UI_Input_HardwareButtons).Get(), &hardwareButtons))) - hardwareButtons->add_BackPressed(Callback<BackPressedHandler>(this, &QWinRTScreen::onBackButtonPressed).Get(), &m_tokens[QEvent::User]); + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Phone_UI_Input_HardwareButtons).Get(), IID_PPV_ARGS(&d->hardwareButtons)); + Q_ASSERT_SUCCEEDED(hr); + hr = d->hardwareButtons->add_BackPressed(Callback<BackPressedHandler>(this, &QWinRTScreen::onBackButtonPressed).Get(), &d->buttonsTokens[&IHardwareButtonsStatics::remove_BackPressed]); + Q_ASSERT_SUCCEEDED(hr); #endif // Q_OS_WINPHONE - // 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 _MSC_VER<=1700 - HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Graphics_Display_DisplayProperties).Get(), - &m_displayInformation); -#else - HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Graphics_Display_DisplayInformation).Get(), - &m_displayInformationFactory); - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to get display information factory."); - return; - } + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Graphics_Display_DisplayInformation).Get(), + IID_PPV_ARGS(&d->displayInformationStatics)); + Q_ASSERT_SUCCEEDED(hr); - hr = m_displayInformationFactory->GetForCurrentView(&m_displayInformation); -#endif - - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to get display information for the current view."); - return; - } + hr = d->displayInformationStatics->GetForCurrentView(&d->displayInformation); + Q_ASSERT_SUCCEEDED(hr); // Set native orientation DisplayOrientations displayOrientation; - hr = m_displayInformation->get_NativeOrientation(&displayOrientation); - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to get native orientation."); - return; - } + hr = d->displayInformation->get_NativeOrientation(&displayOrientation); + Q_ASSERT_SUCCEEDED(hr); + d->nativeOrientation = static_cast<Qt::ScreenOrientation>(static_cast<int>(qtOrientationsFromNative(displayOrientation))); - m_nativeOrientation = static_cast<Qt::ScreenOrientation>(static_cast<int>(qtOrientationsFromNative(displayOrientation))); + hr = d->displayInformation->add_OrientationChanged(Callback<DisplayInformationHandler>(this, &QWinRTScreen::onOrientationChanged).Get(), &d->displayTokens[&IDisplayInformation::remove_OrientationChanged]); + Q_ASSERT_SUCCEEDED(hr); - hr = m_displayInformation->add_OrientationChanged(Callback<DisplayInformationHandler>(this, &QWinRTScreen::onOrientationChanged).Get(), - &m_tokens[QEvent::OrientationChange]); - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to add orientation change callback."); - return; - } - -#if _MSC_VER<=1700 - hr = m_displayInformation->add_LogicalDpiChanged(Callback<DisplayInformationHandler>(this, &QWinRTScreen::onDpiChanged).Get(), - &m_tokens[QEvent::Type(QEvent::User + 1)]); -#else - hr = m_displayInformation->add_DpiChanged(Callback<DisplayInformationHandler>(this, &QWinRTScreen::onDpiChanged).Get(), - &m_tokens[QEvent::Type(QEvent::User + 1)]); -#endif - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to add logical dpi change callback."); - return; - } + hr = d->displayInformation->add_DpiChanged(Callback<DisplayInformationHandler>(this, &QWinRTScreen::onDpiChanged).Get(), &d->displayTokens[&IDisplayInformation::remove_DpiChanged]); + Q_ASSERT_SUCCEEDED(hr); // Set initial orientation & pixel density -#if _MSC_VER<=1700 - onOrientationChanged(Q_NULLPTR); - onDpiChanged(Q_NULLPTR); -#else onOrientationChanged(Q_NULLPTR, Q_NULLPTR); onDpiChanged(Q_NULLPTR, Q_NULLPTR); -#endif - setOrientationUpdateMask(m_nativeOrientation); + setOrientationUpdateMask(d->nativeOrientation); +} - 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]); - } +QWinRTScreen::~QWinRTScreen() +{ + Q_D(QWinRTScreen); + + // Unregister callbacks + for (QHash<CoreApplicationCallbackRemover, EventRegistrationToken>::const_iterator i = d->applicationTokens.begin(); i != d->applicationTokens.end(); ++i) + (d->application.Get()->*i.key())(i.value()); + for (QHash<CoreWindowCallbackRemover, EventRegistrationToken>::const_iterator i = d->windowTokens.begin(); i != d->windowTokens.end(); ++i) + (d->coreWindow.Get()->*i.key())(i.value()); + for (QHash<DisplayCallbackRemover, EventRegistrationToken>::const_iterator i = d->displayTokens.begin(); i != d->displayTokens.end(); ++i) + (d->displayInformation.Get()->*i.key())(i.value()); +#ifdef Q_OS_WINPHONE + for (QHash<HardwareButtonsCallbackRemover, EventRegistrationToken>::const_iterator i = d->buttonsTokens.begin(); i != d->buttonsTokens.end(); ++i) + (d->hardwareButtons.Get()->*i.key())(i.value()); +#endif } QRect QWinRTScreen::geometry() const { - return m_geometry.toRect(); + Q_D(const QWinRTScreen); + return d->geometry.toRect(); } int QWinRTScreen::depth() const { - return m_depth; + return 32; } QImage::Format QWinRTScreen::format() const { - return m_format; + return QImage::Format_ARGB32_Premultiplied; } QSurfaceFormat QWinRTScreen::surfaceFormat() const { - return m_surfaceFormat; + Q_D(const QWinRTScreen); + return d->surfaceFormat; } QSizeF QWinRTScreen::physicalSize() const { - return m_geometry.size() / m_dpi * qreal(25.4); + Q_D(const QWinRTScreen); + return d->geometry.size() / d->dpi * qreal(25.4); } QDpi QWinRTScreen::logicalDpi() const { - return QDpi(m_dpi, m_dpi); + Q_D(const QWinRTScreen); + return QDpi(d->dpi, d->dpi); } qreal QWinRTScreen::devicePixelRatio() const { - return m_devicePixelRatio; + Q_D(const QWinRTScreen); + return d->devicePixelRatio; } QWinRTInputContext *QWinRTScreen::inputContext() const { - return m_inputContext; + Q_D(const QWinRTScreen); +#ifdef Q_OS_WINPHONE + return d->inputContext.data(); +#else + return d->inputContext.Get(); +#endif } QPlatformCursor *QWinRTScreen::cursor() const { - return m_cursor; + Q_D(const QWinRTScreen); + if (!d->cursor) + const_cast<QWinRTScreenPrivate *>(d)->cursor.reset(new QWinRTCursor); + return d->cursor.data(); } Qt::KeyboardModifiers QWinRTScreen::keyboardModifiers() const { + Q_D(const QWinRTScreen); + Qt::KeyboardModifiers mods; CoreVirtualKeyStates mod; - m_coreWindow->GetAsyncKeyState(VirtualKey_Shift, &mod); + d->coreWindow->GetAsyncKeyState(VirtualKey_Shift, &mod); if (mod == CoreVirtualKeyStates_Down) mods |= Qt::ShiftModifier; - m_coreWindow->GetAsyncKeyState(VirtualKey_Menu, &mod); + d->coreWindow->GetAsyncKeyState(VirtualKey_Menu, &mod); if (mod == CoreVirtualKeyStates_Down) mods |= Qt::AltModifier; - m_coreWindow->GetAsyncKeyState(VirtualKey_Control, &mod); + d->coreWindow->GetAsyncKeyState(VirtualKey_Control, &mod); if (mod == CoreVirtualKeyStates_Down) mods |= Qt::ControlModifier; - m_coreWindow->GetAsyncKeyState(VirtualKey_LeftWindows, &mod); + d->coreWindow->GetAsyncKeyState(VirtualKey_LeftWindows, &mod); if (mod == CoreVirtualKeyStates_Down) { mods |= Qt::MetaModifier; } else { - m_coreWindow->GetAsyncKeyState(VirtualKey_RightWindows, &mod); + d->coreWindow->GetAsyncKeyState(VirtualKey_RightWindows, &mod); if (mod == CoreVirtualKeyStates_Down) mods |= Qt::MetaModifier; } @@ -620,56 +690,63 @@ Qt::KeyboardModifiers QWinRTScreen::keyboardModifiers() const Qt::ScreenOrientation QWinRTScreen::nativeOrientation() const { - return m_nativeOrientation; + Q_D(const QWinRTScreen); + return d->nativeOrientation; } Qt::ScreenOrientation QWinRTScreen::orientation() const { - return m_orientation; + Q_D(const QWinRTScreen); + return d->orientation; } void QWinRTScreen::setOrientationUpdateMask(Qt::ScreenOrientations mask) { -#if _MSC_VER<=1700 - m_displayInformation->put_AutoRotationPreferences(nativeOrientationsFromQt(mask)); -#else - m_displayInformationFactory->put_AutoRotationPreferences(nativeOrientationsFromQt(mask)); -#endif + Q_D(QWinRTScreen); + + HRESULT hr = d->displayInformationStatics->put_AutoRotationPreferences(nativeOrientationsFromQt(mask)); + RETURN_VOID_IF_FAILED("Failed to set display auto rotation preferences."); } ICoreWindow *QWinRTScreen::coreWindow() const { - return m_coreWindow; + Q_D(const QWinRTScreen); + return d->coreWindow.Get(); } EGLDisplay QWinRTScreen::eglDisplay() const { - return m_eglDisplay; + Q_D(const QWinRTScreen); + return d->eglDisplay; } EGLSurface QWinRTScreen::eglSurface() const { - return m_eglSurface; + Q_D(const QWinRTScreen); + return d->eglSurface; } QWindow *QWinRTScreen::topWindow() const { - return m_visibleWindows.isEmpty() ? 0 : m_visibleWindows.first(); + Q_D(const QWinRTScreen); + return d->visibleWindows.isEmpty() ? 0 : d->visibleWindows.first(); } void QWinRTScreen::addWindow(QWindow *window) { + Q_D(QWinRTScreen); if (window == topWindow()) return; - m_visibleWindows.prepend(window); + d->visibleWindows.prepend(window); QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason); handleExpose(); } void QWinRTScreen::removeWindow(QWindow *window) { + Q_D(QWinRTScreen); const bool wasTopWindow = window == topWindow(); - if (!m_visibleWindows.removeAll(window)) + if (!d->visibleWindows.removeAll(window)) return; if (wasTopWindow) QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason); @@ -678,17 +755,19 @@ void QWinRTScreen::removeWindow(QWindow *window) void QWinRTScreen::raise(QWindow *window) { - m_visibleWindows.removeAll(window); + Q_D(QWinRTScreen); + d->visibleWindows.removeAll(window); addWindow(window); } void QWinRTScreen::lower(QWindow *window) { + Q_D(QWinRTScreen); const bool wasTopWindow = window == topWindow(); - if (wasTopWindow && m_visibleWindows.size() == 1) + if (wasTopWindow && d->visibleWindows.size() == 1) return; - m_visibleWindows.removeAll(window); - m_visibleWindows.append(window); + d->visibleWindows.removeAll(window); + d->visibleWindows.append(window); if (wasTopWindow) QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason); handleExpose(); @@ -696,18 +775,18 @@ void QWinRTScreen::lower(QWindow *window) void QWinRTScreen::handleExpose() { - if (m_visibleWindows.isEmpty()) + Q_D(QWinRTScreen); + if (d->visibleWindows.isEmpty()) return; - QList<QWindow *>::const_iterator it = m_visibleWindows.constBegin(); - QWindowSystemInterface::handleExposeEvent(*it, m_geometry.toRect()); - while (++it != m_visibleWindows.constEnd()) + QList<QWindow *>::const_iterator it = d->visibleWindows.constBegin(); + QWindowSystemInterface::handleExposeEvent(*it, d->geometry.toRect()); + while (++it != d->visibleWindows.constEnd()) QWindowSystemInterface::handleExposeEvent(*it, QRegion()); QWindowSystemInterface::flushWindowSystemEvents(); } -HRESULT QWinRTScreen::onKeyDown(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IKeyEventArgs *args) +HRESULT QWinRTScreen::onKeyDown(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IKeyEventArgs *args) { - Q_UNUSED(window); VirtualKey virtualKey; args->get_VirtualKey(&virtualKey); Qt::Key key = qKeyFromVirtual(virtualKey); @@ -718,14 +797,14 @@ HRESULT QWinRTScreen::onKeyDown(ABI::Windows::UI::Core::ICoreWindow *window, ABI return S_OK; } -HRESULT QWinRTScreen::onKeyUp(ABI::Windows::UI::Core::ICoreWindow *window, ABI::Windows::UI::Core::IKeyEventArgs *args) +HRESULT QWinRTScreen::onKeyUp(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IKeyEventArgs *args) { - Q_UNUSED(window); Qt::KeyboardModifiers mods = keyboardModifiers(); #ifndef Q_OS_WINPHONE + Q_D(QWinRTScreen); 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); + if (SUCCEEDED(args->get_KeyStatus(&status)) && d->activeKeys.contains(status.ScanCode)) { + QPair<Qt::Key, QString> keyStatus = d->activeKeys.take(status.ScanCode); QWindowSystemInterface::handleKeyEvent(topWindow(), QEvent::KeyRelease, keyStatus.first, mods, keyStatus.second); return S_OK; @@ -738,10 +817,8 @@ HRESULT QWinRTScreen::onKeyUp(ABI::Windows::UI::Core::ICoreWindow *window, ABI:: return S_OK; } -HRESULT QWinRTScreen::onCharacterReceived(ICoreWindow *window, ICharacterReceivedEventArgs *args) +HRESULT QWinRTScreen::onCharacterReceived(ICoreWindow *, 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 @@ -753,9 +830,10 @@ HRESULT QWinRTScreen::onCharacterReceived(ICoreWindow *window, ICharacterReceive QString text = QChar(keyCode); QWindowSystemInterface::handleKeyEvent(topWindow(), QEvent::KeyPress, key, mods, text); #ifndef Q_OS_WINPHONE + Q_D(QWinRTScreen); 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)); + d->activeKeys.insert(status.ScanCode, qMakePair(key, text)); return S_OK; } #endif // !Q_OS_WINPHONE @@ -763,10 +841,9 @@ HRESULT QWinRTScreen::onCharacterReceived(ICoreWindow *window, ICharacterReceive return S_OK; } -HRESULT QWinRTScreen::onPointerEntered(ICoreWindow *window, IPointerEventArgs *args) +HRESULT QWinRTScreen::onPointerEntered(ICoreWindow *, IPointerEventArgs *args) { - Q_UNUSED(window); - IPointerPoint *pointerPoint; + ComPtr<IPointerPoint> pointerPoint; if (SUCCEEDED(args->get_CurrentPoint(&pointerPoint))) { // Assumes full-screen window Point point; @@ -774,24 +851,20 @@ HRESULT QWinRTScreen::onPointerEntered(ICoreWindow *window, IPointerEventArgs *a QPoint pos(point.X, point.Y); QWindowSystemInterface::handleEnterEvent(topWindow(), pos, pos); - pointerPoint->Release(); } return S_OK; } -HRESULT QWinRTScreen::onPointerExited(ICoreWindow *window, IPointerEventArgs *args) +HRESULT QWinRTScreen::onPointerExited(ICoreWindow *, IPointerEventArgs *) { - Q_UNUSED(window); - Q_UNUSED(args); QWindowSystemInterface::handleLeaveEvent(0); return S_OK; } -HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *window, IPointerEventArgs *args) +HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) { - Q_UNUSED(window); - - IPointerPoint *pointerPoint; + Q_D(QWinRTScreen); + ComPtr<IPointerPoint> pointerPoint; if (FAILED(args->get_CurrentPoint(&pointerPoint))) return E_INVALIDARG; @@ -812,27 +885,18 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *window, IPointerEventArgs *a if (modifiers & VirtualKeyModifiers_Windows) mods |= Qt::MetaModifier; - IPointerPointProperties *properties; + ComPtr<IPointerPointProperties> properties; if (FAILED(pointerPoint->get_Properties(&properties))) return E_INVALIDARG; - PointerDeviceType pointerDeviceType; -#if defined(Q_OS_WINPHONE) && _MSC_VER <= 1700 - pointerDeviceType = PointerDeviceType_Touch; -#else ComPtr<IPointerDevice> pointerDevice; HRESULT hr = pointerPoint->get_PointerDevice(&pointerDevice); - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to get pointer device."); - return S_OK; - } + RETURN_OK_IF_FAILED("Failed to get pointer device."); + PointerDeviceType pointerDeviceType; hr = pointerDevice->get_PointerDeviceType(&pointerDeviceType); - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to get pointer device type."); - return S_OK; - } -#endif + RETURN_OK_IF_FAILED("Failed to get pointer device type."); + switch (pointerDeviceType) { case PointerDeviceType_Mouse: { qint32 delta; @@ -872,12 +936,12 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *window, IPointerEventArgs *a break; } case PointerDeviceType_Touch: { - if (!m_touchDevice) { - m_touchDevice = new QTouchDevice; - m_touchDevice->setName(QStringLiteral("WinRTTouchScreen")); - m_touchDevice->setType(QTouchDevice::TouchScreen); - m_touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure | QTouchDevice::NormalizedPosition); - QWindowSystemInterface::registerTouchDevice(m_touchDevice); + if (!d->touchDevice) { + d->touchDevice = new QTouchDevice; + d->touchDevice->setName(QStringLiteral("WinRTTouchScreen")); + d->touchDevice->setType(QTouchDevice::TouchScreen); + d->touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure | QTouchDevice::NormalizedPosition); + QWindowSystemInterface::registerTouchDevice(d->touchDevice); } quint32 id; @@ -889,8 +953,8 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *window, IPointerEventArgs *a float pressure; properties->get_Pressure(&pressure); - QHash<quint32, QWindowSystemInterface::TouchPoint>::iterator it = m_touchPoints.find(id); - if (it != m_touchPoints.end()) { + QHash<quint32, QWindowSystemInterface::TouchPoint>::iterator it = d->touchPoints.find(id); + if (it != d->touchPoints.end()) { boolean isPressed; #ifndef Q_OS_WINPHONE pointerPoint->get_IsInContact(&isPressed); @@ -899,20 +963,20 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *window, IPointerEventArgs *a #endif it.value().state = isPressed ? Qt::TouchPointMoved : Qt::TouchPointReleased; } else { - it = m_touchPoints.insert(id, QWindowSystemInterface::TouchPoint()); + it = d->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().normalPosition = QPointF(pos.x()/d->geometry.width(), pos.y()/d->geometry.height()); it.value().pressure = pressure; - QWindowSystemInterface::handleTouchEvent(topWindow(), m_touchDevice, m_touchPoints.values(), mods); + QWindowSystemInterface::handleTouchEvent(topWindow(), d->touchDevice, d->touchPoints.values(), mods); // Remove released points, station others - for (QHash<quint32, QWindowSystemInterface::TouchPoint>::iterator i = m_touchPoints.begin(); i != m_touchPoints.end();) { + for (QHash<quint32, QWindowSystemInterface::TouchPoint>::iterator i = d->touchPoints.begin(); i != d->touchPoints.end();) { if (i.value().state == Qt::TouchPointReleased) - i = m_touchPoints.erase(i); + i = d->touchPoints.erase(i); else (i++).value().state = Qt::TouchPointStationary; } @@ -950,46 +1014,42 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *window, IPointerEventArgs *a } } - properties->Release(); - pointerPoint->Release(); - return S_OK; } HRESULT QWinRTScreen::onAutomationProviderRequested(ICoreWindow *, IAutomationProviderRequestedEventArgs *args) { + Q_D(const QWinRTScreen); #ifndef Q_OS_WINPHONE - args->put_AutomationProvider(m_inputContext); + args->put_AutomationProvider(d->inputContext.Get()); #else Q_UNUSED(args) #endif return S_OK; } -HRESULT QWinRTScreen::onSizeChanged(ICoreWindow *window, IWindowSizeChangedEventArgs *args) +HRESULT QWinRTScreen::onSizeChanged(ICoreWindow *, IWindowSizeChangedEventArgs *args) { - Q_UNUSED(window); + Q_D(QWinRTScreen); Size size; - if (FAILED(args->get_Size(&size))) { - qWarning(Q_FUNC_INFO ": failed to get size"); - return S_OK; - } + HRESULT hr = args->get_Size(&size); + RETURN_OK_IF_FAILED("Failed to get window size."); // Regardless of state, all top-level windows are viewport-sized - this might change if // a more advanced compositor is written. - m_geometry.setSize(QSizeF(size.Width, size.Height)); - QWindowSystemInterface::handleScreenGeometryChange(screen(), m_geometry.toRect()); - QWindowSystemInterface::handleScreenAvailableGeometryChange(screen(), m_geometry.toRect()); + d->geometry.setSize(QSizeF(size.Width, size.Height)); + QWindowSystemInterface::handleScreenGeometryChange(screen(), d->geometry.toRect()); + QWindowSystemInterface::handleScreenAvailableGeometryChange(screen(), d->geometry.toRect()); QPlatformScreen::resizeMaximizedWindows(); handleExpose(); return S_OK; } -HRESULT QWinRTScreen::onActivated(ICoreWindow *window, IWindowActivatedEventArgs *args) +HRESULT QWinRTScreen::onActivated(ICoreWindow *, IWindowActivatedEventArgs *args) { - Q_UNUSED(window); + Q_D(QWinRTScreen); CoreWindowActivationState activationState; args->get_WindowActivationState(&activationState); @@ -999,7 +1059,7 @@ HRESULT QWinRTScreen::onActivated(ICoreWindow *window, IWindowActivatedEventArgs } // Activate topWindow - if (!m_visibleWindows.isEmpty()) { + if (!d->visibleWindows.isEmpty()) { Qt::FocusReason focusReason = activationState == CoreWindowActivationState_PointerActivated ? Qt::MouseFocusReason : Qt::ActiveWindowFocusReason; QWindowSystemInterface::handleWindowActivated(topWindow(), focusReason); @@ -1022,21 +1082,15 @@ HRESULT QWinRTScreen::onResume(IInspectable *, IInspectable *) return S_OK; } -HRESULT QWinRTScreen::onClosed(ICoreWindow *window, ICoreWindowEventArgs *args) +HRESULT QWinRTScreen::onClosed(ICoreWindow *, ICoreWindowEventArgs *) { - Q_UNUSED(window); - Q_UNUSED(args); - foreach (QWindow *w, QGuiApplication::topLevelWindows()) QWindowSystemInterface::handleCloseEvent(w); return S_OK; } -HRESULT QWinRTScreen::onVisibilityChanged(ICoreWindow *window, IVisibilityChangedEventArgs *args) +HRESULT QWinRTScreen::onVisibilityChanged(ICoreWindow *, IVisibilityChangedEventArgs *args) { - Q_UNUSED(window); - Q_UNUSED(args); - boolean visible; args->get_Visible(&visible); QWindowSystemInterface::handleApplicationStateChanged(visible ? Qt::ApplicationActive : Qt::ApplicationHidden); @@ -1045,60 +1099,48 @@ HRESULT QWinRTScreen::onVisibilityChanged(ICoreWindow *window, IVisibilityChange return S_OK; } -#if _MSC_VER<=1700 -HRESULT QWinRTScreen::onOrientationChanged(IInspectable *) -#else HRESULT QWinRTScreen::onOrientationChanged(IDisplayInformation *, IInspectable *) -#endif { + Q_D(QWinRTScreen); + DisplayOrientations displayOrientation; - m_displayInformation->get_CurrentOrientation(&displayOrientation); + HRESULT hr = d->displayInformation->get_CurrentOrientation(&displayOrientation); + RETURN_OK_IF_FAILED("Failed to get current orientations."); + Qt::ScreenOrientation newOrientation = static_cast<Qt::ScreenOrientation>(static_cast<int>(qtOrientationsFromNative(displayOrientation))); - if (m_orientation != newOrientation) { - m_orientation = newOrientation; - QWindowSystemInterface::handleScreenOrientationChange(screen(), m_orientation); + if (d->orientation != newOrientation) { + d->orientation = newOrientation; + QWindowSystemInterface::handleScreenOrientationChange(screen(), d->orientation); } return S_OK; } -#if _MSC_VER<=1700 -HRESULT QWinRTScreen::onDpiChanged(IInspectable *) -#else HRESULT QWinRTScreen::onDpiChanged(IDisplayInformation *, IInspectable *) -#endif { -#if defined(Q_OS_WINPHONE) && _MSC_VER>=1800 // WP 8.1 + Q_D(QWinRTScreen); + + HRESULT hr; +#ifdef Q_OS_WINPHONE ComPtr<IDisplayInformation2> displayInformation; - HRESULT hr = m_displayInformation->QueryInterface(IID_IDisplayInformation2, &displayInformation); - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to cast display information."); - return S_OK; - } - hr = displayInformation->get_RawPixelsPerViewPixel(&m_devicePixelRatio); + hr = d->displayInformation.As(&displayInformation); + RETURN_OK_IF_FAILED("Failed to cast display information."); + hr = displayInformation->get_RawPixelsPerViewPixel(&d->devicePixelRatio); #else ResolutionScale resolutionScale; - HRESULT hr = m_displayInformation->get_ResolutionScale(&resolutionScale); -#endif - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to get display resolution scale."); - return S_OK; - } -#if !(defined(Q_OS_WINPHONE) && _MSC_VER>=1800) // !WP8.1 - m_devicePixelRatio = qreal(resolutionScale) / 100; + hr = d->displayInformation->get_ResolutionScale(&resolutionScale); + d->devicePixelRatio = qreal(resolutionScale) / 100; #endif + RETURN_OK_IF_FAILED("Failed to get resolution scale"); // Correct the scale factor for integer window size - m_devicePixelRatio = m_devicePixelRatio * ((m_geometry.width()/qRound(m_geometry.width()) + - m_geometry.height()/qRound(m_geometry.height())) / 2.0); + d->devicePixelRatio = d->devicePixelRatio * ((d->geometry.width()/qRound(d->geometry.width()) + + d->geometry.height()/qRound(d->geometry.height())) / 2.0); FLOAT dpi; - hr = m_displayInformation->get_LogicalDpi(&dpi); - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to get logical DPI."); - return S_OK; - } - m_dpi = dpi; + hr = d->displayInformation->get_LogicalDpi(&dpi); + RETURN_OK_IF_FAILED("Failed to get logical DPI."); + d->dpi = dpi; return S_OK; } @@ -1106,14 +1148,16 @@ HRESULT QWinRTScreen::onDpiChanged(IDisplayInformation *, IInspectable *) #ifdef Q_OS_WINPHONE HRESULT QWinRTScreen::onBackButtonPressed(IInspectable *, IBackPressedEventArgs *args) { + Q_D(QWinRTScreen); + QKeyEvent backPress(QEvent::KeyPress, Qt::Key_Back, Qt::NoModifier); QKeyEvent backRelease(QEvent::KeyRelease, Qt::Key_Back, Qt::NoModifier); backPress.setAccepted(false); backRelease.setAccepted(false); - QObject *receiver = m_visibleWindows.isEmpty() + QObject *receiver = d->visibleWindows.isEmpty() ? static_cast<QObject *>(QGuiApplication::instance()) - : static_cast<QObject *>(m_visibleWindows.first()); + : static_cast<QObject *>(d->visibleWindows.first()); // If the event is ignored, the app will suspend QGuiApplication::sendEvent(receiver, &backPress); diff --git a/src/plugins/platforms/winrt/qwinrtscreen.h b/src/plugins/platforms/winrt/qwinrtscreen.h index d39683a960..18745f1017 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.h +++ b/src/plugins/platforms/winrt/qwinrtscreen.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** 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. @@ -45,19 +45,12 @@ #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 { @@ -71,14 +64,9 @@ namespace ABI { struct IWindowActivatedEventArgs; struct IWindowSizeChangedEventArgs; } - namespace ViewManagement { - struct IApplicationViewStatics; - } } namespace Graphics { namespace Display { - struct IDisplayPropertiesStatics; - struct IDisplayInformationStatics; struct IDisplayInformation; } } @@ -99,14 +87,14 @@ QT_BEGIN_NAMESPACE class QTouchDevice; class QWinRTEGLContext; -class QWinRTPageFlipper; class QWinRTCursor; class QWinRTInputContext; - +class QWinRTScreenPrivate; class QWinRTScreen : public QPlatformScreen { public: - explicit QWinRTScreen(ABI::Windows::UI::Core::ICoreWindow *window); + explicit QWinRTScreen(); + ~QWinRTScreen(); QRect geometry() const; int depth() const; QImage::Format format() const; @@ -135,69 +123,31 @@ public: private: void handleExpose(); - // Event handlers - QHash<QEvent::Type, EventRegistrationToken> m_tokens; - QHash<Qt::ApplicationState, EventRegistrationToken> m_suspendTokens; + HRESULT onKeyDown(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IKeyEventArgs *); + HRESULT onKeyUp(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IKeyEventArgs *); + HRESULT onCharacterReceived(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::ICharacterReceivedEventArgs *); + HRESULT onPointerEntered(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IPointerEventArgs *); + HRESULT onPointerExited(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IPointerEventArgs *); + HRESULT onPointerUpdated(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IPointerEventArgs *); + HRESULT onSizeChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *); - 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 onActivated(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowActivatedEventArgs *); 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 onClosed(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::ICoreWindowEventArgs *); + HRESULT onVisibilityChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IVisibilityChangedEventArgs *); + HRESULT onAutomationProviderRequested(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IAutomationProviderRequestedEventArgs *); -#if _MSC_VER<=1700 - HRESULT onOrientationChanged(IInspectable *); - HRESULT onDpiChanged(IInspectable *); -#else HRESULT onOrientationChanged(ABI::Windows::Graphics::Display::IDisplayInformation *, IInspectable *); HRESULT onDpiChanged(ABI::Windows::Graphics::Display::IDisplayInformation *, IInspectable *); -#endif #ifdef Q_OS_WINPHONE HRESULT onBackButtonPressed(IInspectable *, ABI::Windows::Phone::UI::Input::IBackPressedEventArgs *args); #endif - ABI::Windows::UI::Core::ICoreWindow *m_coreWindow; - ABI::Windows::UI::ViewManagement::IApplicationViewStatics *m_applicationView; - ABI::Windows::ApplicationModel::Core::ICoreApplication *m_application; - - QRectF m_geometry; - QImage::Format m_format; - QSurfaceFormat m_surfaceFormat; - qreal m_dpi; - int m_depth; - QWinRTInputContext *m_inputContext; - QWinRTCursor *m_cursor; - QList<QWindow *> m_visibleWindows; - - EGLDisplay m_eglDisplay; - EGLSurface m_eglSurface; - -#if _MSC_VER<=1700 - ABI::Windows::Graphics::Display::IDisplayPropertiesStatics *m_displayInformation; -#else - ABI::Windows::Graphics::Display::IDisplayInformationStatics *m_displayInformationFactory; - ABI::Windows::Graphics::Display::IDisplayInformation *m_displayInformation; -#endif - qreal m_devicePixelRatio; - Qt::ScreenOrientation m_nativeOrientation; - Qt::ScreenOrientation m_orientation; - -#ifndef Q_OS_WINPHONE - QHash<quint32, QPair<Qt::Key, QString> > m_activeKeys; -#endif - QTouchDevice *m_touchDevice; - QHash<quint32, QWindowSystemInterface::TouchPoint> m_touchPoints; + QScopedPointer<QWinRTScreenPrivate> d_ptr; + Q_DECLARE_PRIVATE(QWinRTScreen) }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtservices.cpp b/src/plugins/platforms/winrt/qwinrtservices.cpp index b0f9247d36..6272b46f44 100644 --- a/src/plugins/platforms/winrt/qwinrtservices.cpp +++ b/src/plugins/platforms/winrt/qwinrtservices.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** 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. @@ -43,6 +43,7 @@ #include <QtCore/QUrl> #include <QtCore/QDir> #include <QtCore/QCoreApplication> +#include <QtCore/qfunctions_winrt.h> #include <wrl.h> #include <windows.foundation.h> @@ -56,83 +57,84 @@ using namespace ABI::Windows::System; QT_BEGIN_NAMESPACE +class QWinRTServicesPrivate +{ +public: + ComPtr<IUriRuntimeClassFactory> uriFactory; + ComPtr<IStorageFileStatics> fileFactory; + ComPtr<ILauncherStatics> launcher; +}; + QWinRTServices::QWinRTServices() + : d_ptr(new QWinRTServicesPrivate) { - 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); + Q_D(QWinRTServices); + + HRESULT hr; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Foundation_Uri).Get(), + IID_PPV_ARGS(&d->uriFactory)); + Q_ASSERT_X(SUCCEEDED(hr), Q_FUNC_INFO, qPrintable(qt_error_string(hr))); + + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_StorageFile).Get(), + IID_PPV_ARGS(&d->fileFactory)); + Q_ASSERT_X(SUCCEEDED(hr), Q_FUNC_INFO, qPrintable(qt_error_string(hr))); + + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_System_Launcher).Get(), + IID_PPV_ARGS(&d->launcher)); + Q_ASSERT_X(SUCCEEDED(hr), Q_FUNC_INFO, qPrintable(qt_error_string(hr))); } 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); + Q_D(QWinRTServices); - IUriRuntimeClass *uri; + ComPtr<IUriRuntimeClass> uri; QString urlString = url.toString(); - // ### TODO: Replace with HStringReference when WP8.0 support is removed - HString uriString; - uriString.Set((const wchar_t*)urlString.utf16(), urlString.length()); - m_uriFactory->CreateUri(uriString.Get(), &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(); + HStringReference uriString(reinterpret_cast<LPCWSTR>(urlString.utf16()), urlString.length()); + HRESULT hr = d->uriFactory->CreateUri(uriString.Get(), &uri); + RETURN_FALSE_IF_FAILED("Failed to create URI from QUrl."); + + ComPtr<IAsyncOperation<bool>> op; + hr = d->launcher->LaunchUriAsync(uri.Get(), &op); + RETURN_FALSE_IF_FAILED("Failed to start URI launch."); + + boolean result; + hr = QWinRTFunctions::await(op, &result); + RETURN_FALSE_IF_FAILED("Failed to launch URI."); return result; } bool QWinRTServices::openDocument(const QUrl &url) { - if (!(m_fileFactory && m_launcher)) - return QPlatformServices::openDocument(url); - - const QString pathString = QDir::toNativeSeparators(url.toLocalFile()); - // ### TODO: Replace with HStringReference when WP8.0 support is removed - HString path; - path.Set((const wchar_t*)pathString.utf16(), pathString.length()); - IAsyncOperation<StorageFile*> *fileOp; - m_fileFactory->GetFileFromPathAsync(path.Get(), &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(); + Q_D(QWinRTServices); + + HRESULT hr; + ComPtr<IStorageFile> file; + { + const QString pathString = QDir::toNativeSeparators(url.toLocalFile()); + HStringReference path(reinterpret_cast<LPCWSTR>(pathString.utf16()), pathString.length()); + ComPtr<IAsyncOperation<StorageFile *>> op; + hr = d->fileFactory->GetFileFromPathAsync(path.Get(), &op); + RETURN_FALSE_IF_FAILED("Failed to initialize file URI."); + + hr = QWinRTFunctions::await(op, file.GetAddressOf()); + RETURN_FALSE_IF_FAILED("Failed to get file URI."); + } + + boolean result; + { + ComPtr<IAsyncOperation<bool>> op; + hr = d->launcher->LaunchFileAsync(file.Get(), &op); + RETURN_FALSE_IF_FAILED("Failed to start file launch."); + + hr = QWinRTFunctions::await(op, &result); + RETURN_FALSE_IF_FAILED("Failed to launch file."); + } return result; } diff --git a/src/plugins/platforms/winrt/qwinrtservices.h b/src/plugins/platforms/winrt/qwinrtservices.h index 9cc917030a..d3abe6f2bd 100644 --- a/src/plugins/platforms/winrt/qwinrtservices.h +++ b/src/plugins/platforms/winrt/qwinrtservices.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** 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. @@ -43,23 +43,11 @@ #define QWINRTSERVICES_H #include <qpa/qplatformservices.h> +#include <QtCore/QScopedPointer> -namespace ABI { - namespace Windows { - namespace Foundation { - struct IUriRuntimeClassFactory; - } - namespace Storage { - struct IStorageFileStatics; - } - namespace System { - struct ILauncherStatics; - } - } -} - -QT_BEGIN_NAMESPACE +QT_USE_NAMESPACE +class QWinRTServicesPrivate; class QWinRTServices : public QPlatformServices { public: @@ -70,11 +58,8 @@ public: bool openDocument(const QUrl &url); private: - ABI::Windows::Foundation::IUriRuntimeClassFactory *m_uriFactory; - ABI::Windows::Storage::IStorageFileStatics *m_fileFactory; - ABI::Windows::System::ILauncherStatics *m_launcher; + QScopedPointer<QWinRTServicesPrivate> d_ptr; + Q_DECLARE_PRIVATE(QWinRTServices) }; -QT_END_NAMESPACE - #endif // QWINRTSERVICES_H diff --git a/src/plugins/platforms/xcb/qglxintegration.cpp b/src/plugins/platforms/xcb/qglxintegration.cpp index 9a56455940..df929c4b61 100644 --- a/src/plugins/platforms/xcb/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/qglxintegration.cpp @@ -54,6 +54,7 @@ #include "qglxintegration.h" #include <QtPlatformSupport/private/qglxconvenience_p.h> +#include <QtPlatformHeaders/QGLXNativeContext> #if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) #include <dlfcn.h> @@ -83,31 +84,32 @@ typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXC #define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 #endif -static Window createDummyWindow(QXcbScreen *screen, XVisualInfo *visualInfo) +static Window createDummyWindow(Display *dpy, XVisualInfo *visualInfo, int screenNumber, Window rootWin) { - Colormap cmap = XCreateColormap(DISPLAY_FROM_XCB(screen), screen->root(), visualInfo->visual, AllocNone); + Colormap cmap = XCreateColormap(dpy, rootWin, visualInfo->visual, AllocNone); XSetWindowAttributes a; - a.background_pixel = WhitePixel(DISPLAY_FROM_XCB(screen), screen->screenNumber()); - a.border_pixel = BlackPixel(DISPLAY_FROM_XCB(screen), screen->screenNumber()); + a.background_pixel = WhitePixel(dpy, screenNumber); + a.border_pixel = BlackPixel(dpy, screenNumber); a.colormap = cmap; + a.override_redirect = true; - Window window = XCreateWindow(DISPLAY_FROM_XCB(screen), screen->root(), + Window window = XCreateWindow(dpy, rootWin, 0, 0, 100, 100, 0, visualInfo->depth, InputOutput, visualInfo->visual, - CWBackPixel|CWBorderPixel|CWColormap, &a); + CWBackPixel|CWBorderPixel|CWColormap|CWOverrideRedirect, &a); #ifndef QT_NO_DEBUG - XStoreName(DISPLAY_FROM_XCB(screen), window, "Qt GLX dummy window"); + XStoreName(dpy, window, "Qt GLX dummy window"); #endif - XFreeColormap(DISPLAY_FROM_XCB(screen), cmap); + XFreeColormap(dpy, cmap); return window; } -static Window createDummyWindow(QXcbScreen *screen, GLXFBConfig config) +static Window createDummyWindow(Display *dpy, GLXFBConfig config, int screenNumber, Window rootWin) { - XVisualInfo *visualInfo = glXGetVisualFromFBConfig(DISPLAY_FROM_XCB(screen), config); + XVisualInfo *visualInfo = glXGetVisualFromFBConfig(dpy, config); if (!visualInfo) qFatal("Could not initialize GLX"); - Window window = createDummyWindow(screen, visualInfo); + Window window = createDummyWindow(dpy, visualInfo, screenNumber, rootWin); XFree(visualInfo); return window; } @@ -160,7 +162,8 @@ static void updateFormatFromContext(QSurfaceFormat &format) } } -QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlatformOpenGLContext *share) +QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlatformOpenGLContext *share, + const QVariant &nativeHandle) : QPlatformOpenGLContext() , m_screen(screen) , m_context(0) @@ -168,6 +171,15 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat , m_format(format) , m_isPBufferCurrent(false) , m_swapInterval(-1) + , m_ownsContext(nativeHandle.isNull()) +{ + if (nativeHandle.isNull()) + init(screen, share); + else + init(screen, share, nativeHandle); +} + +void QGLXContext::init(QXcbScreen *screen, QPlatformOpenGLContext *share) { if (m_format.renderableType() == QSurfaceFormat::DefaultRenderableType) m_format.setRenderableType(QSurfaceFormat::OpenGL); @@ -195,7 +207,7 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat && (m_format.renderableType() != QSurfaceFormat::OpenGLES || (supportsProfiles && glxExt.contains("GLX_EXT_create_context_es2_profile")))) { // Try to create an OpenGL context for each known OpenGL version in descending // order from the requested version. - const int requestedVersion = format.majorVersion() * 10 + qMin(format.minorVersion(), 9); + const int requestedVersion = m_format.majorVersion() * 10 + qMin(m_format.minorVersion(), 9); QVector<int> glVersions; if (m_format.renderableType() == QSurfaceFormat::OpenGL) { @@ -282,10 +294,10 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat // Get the basic surface format details if (m_context) - qglx_surfaceFormatFromGLXFBConfig(&m_format, DISPLAY_FROM_XCB(screen), config, m_context); + qglx_surfaceFormatFromGLXFBConfig(&m_format, DISPLAY_FROM_XCB(screen), config); // Create a temporary window so that we can make the new context current - window = createDummyWindow(screen, config); + window = createDummyWindow(DISPLAY_FROM_XCB(screen), config, screen->screenNumber(), screen->root()); } else { // requesting an OpenGL ES context requires glXCreateContextAttribsARB, so bail out if (m_format.renderableType() == QSurfaceFormat::OpenGLES) @@ -303,7 +315,7 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat } // Create a temporary window so that we can make the new context current - window = createDummyWindow(screen, visualInfo); + window = createDummyWindow(DISPLAY_FROM_XCB(screen), visualInfo, screen->screenNumber(), screen->root()); XFree(visualInfo); } @@ -320,9 +332,123 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat XDestroyWindow(DISPLAY_FROM_XCB(screen), window); } +void QGLXContext::init(QXcbScreen *screen, QPlatformOpenGLContext *share, const QVariant &nativeHandle) +{ + if (!nativeHandle.canConvert<QGLXNativeContext>()) { + qWarning("QGLXContext: Requires a QGLXNativeContext"); + return; + } + QGLXNativeContext handle = nativeHandle.value<QGLXNativeContext>(); + GLXContext context = handle.context(); + if (!context) { + qWarning("QGLXContext: No GLXContext given"); + return; + } + + // Use the provided Display, if available. If not, use our own. It may still work. + Display *dpy = handle.display(); + if (!dpy) + dpy = DISPLAY_FROM_XCB(screen); + + // Legacy contexts created using glXCreateContext are created using a visual + // and the FBConfig cannot be queried. The only way to adapt these contexts + // is to figure out the visual id. + XVisualInfo *vinfo = 0; + // If the VisualID is provided use it. + VisualID vid = handle.visualId(); + if (!vid) { + // In the absence of the VisualID figure it out from the window. + Window wnd = handle.window(); + if (wnd) { + XWindowAttributes attrs; + XGetWindowAttributes(dpy, wnd, &attrs); + vid = XVisualIDFromVisual(attrs.visual); + } + } + if (vid) { + XVisualInfo v; + v.screen = screen->screenNumber(); + v.visualid = vid; + int n = 0; + vinfo = XGetVisualInfo(dpy, VisualScreenMask | VisualIDMask, &v, &n); + if (n < 1) { + XFree(vinfo); + vinfo = 0; + } + } + + // For contexts created with an FBConfig using the modern functions providing the + // visual or window is not mandatory. Just query the config from the context. + GLXFBConfig config = 0; + if (!vinfo) { + int configId = 0; + if (glXQueryContext(dpy, context, GLX_FBCONFIG_ID, &configId) != Success) { + qWarning("QGLXContext: Failed to query config from the provided context"); + return; + } + + GLXFBConfig *configs; + int numConfigs = 0; + static const int attribs[] = { GLX_FBCONFIG_ID, configId, None }; + configs = glXChooseFBConfig(dpy, screen->screenNumber(), attribs, &numConfigs); + if (!configs || numConfigs < 1) { + qWarning("QGLXContext: Failed to find config"); + return; + } + if (configs && numConfigs > 1) // this is suspicious so warn but let it continue + qWarning("QGLXContext: Multiple configs for FBConfig ID %d", configId); + + config = configs[0]; + } + + Q_ASSERT(vinfo || config); + + int screenNumber = DefaultScreen(dpy); + Window window; + if (vinfo) + window = createDummyWindow(dpy, vinfo, screenNumber, RootWindow(dpy, screenNumber)); + else + window = createDummyWindow(dpy, config, screenNumber, RootWindow(dpy, screenNumber)); + if (!window) { + qWarning("QGLXContext: Failed to create dummy window"); + return; + } + + // Update OpenGL version and buffer sizes in our format. + if (!glXMakeCurrent(dpy, window, context)) { + qWarning("QGLXContext: Failed to make provided context current"); + return; + } + m_format = QSurfaceFormat(); + m_format.setRenderableType(QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL + ? QSurfaceFormat::OpenGL : QSurfaceFormat::OpenGLES); + updateFormatFromContext(m_format); + if (vinfo) + qglx_surfaceFormatFromVisualInfo(&m_format, dpy, vinfo); + else + qglx_surfaceFormatFromGLXFBConfig(&m_format, dpy, config); + glXMakeCurrent(dpy, 0, 0); + XDestroyWindow(dpy, window); + + if (vinfo) + XFree(vinfo); + + // Success. Store the context. From this point on isValid() is true. + m_context = context; + + if (share) + m_shareContext = static_cast<const QGLXContext*>(share)->glxContext(); +} + QGLXContext::~QGLXContext() { - glXDestroyContext(DISPLAY_FROM_XCB(m_screen), m_context); + if (m_ownsContext) + glXDestroyContext(DISPLAY_FROM_XCB(m_screen), m_context); +} + +QVariant QGLXContext::nativeHandle() const +{ + return QVariant::fromValue<QGLXNativeContext>(QGLXNativeContext(m_context)); } bool QGLXContext::makeCurrent(QPlatformSurface *surface) diff --git a/src/plugins/platforms/xcb/qglxintegration.h b/src/plugins/platforms/xcb/qglxintegration.h index 00bba94ab3..a7787f5f86 100644 --- a/src/plugins/platforms/xcb/qglxintegration.h +++ b/src/plugins/platforms/xcb/qglxintegration.h @@ -58,7 +58,8 @@ QT_BEGIN_NAMESPACE class QGLXContext : public QPlatformOpenGLContext { public: - QGLXContext(QXcbScreen *xd, const QSurfaceFormat &format, QPlatformOpenGLContext *share); + QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlatformOpenGLContext *share, + const QVariant &nativeHandle); ~QGLXContext(); bool makeCurrent(QPlatformSurface *surface); @@ -72,16 +73,22 @@ public: GLXContext glxContext() const { return m_context; } + QVariant nativeHandle() const; + static bool supportsThreading(); static void queryDummyContext(); private: + void init(QXcbScreen *screen, QPlatformOpenGLContext *share); + void init(QXcbScreen *screen, QPlatformOpenGLContext *share, const QVariant &nativeHandle); + QXcbScreen *m_screen; GLXContext m_context; GLXContext m_shareContext; QSurfaceFormat m_format; bool m_isPBufferCurrent; int m_swapInterval; + bool m_ownsContext; static bool m_queriedDummyContext; static bool m_supportsThreading; }; diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp index e7f8510706..3b30274f25 100644 --- a/src/plugins/platforms/xcb/qxcbclipboard.cpp +++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp @@ -135,9 +135,10 @@ protected: (void)formats(); // trigger update of format list - QList<xcb_atom_t> atoms; + QVector<xcb_atom_t> atoms; xcb_atom_t *targets = (xcb_atom_t *) format_atoms.data(); int size = format_atoms.size() / sizeof(xcb_atom_t); + atoms.reserve(size); for (int i = 0; i < size; ++i) atoms.append(targets[i]); @@ -524,7 +525,7 @@ xcb_atom_t QXcbClipboard::sendTargetsSelection(QMimeData *d, xcb_window_t window QVector<xcb_atom_t> types; QStringList formats = QInternalMimeData::formatsHelper(d); for (int i = 0; i < formats.size(); ++i) { - QList<xcb_atom_t> atoms = QXcbMime::mimeAtomsForFormat(connection(), formats.at(i)); + QVector<xcb_atom_t> atoms = QXcbMime::mimeAtomsForFormat(connection(), formats.at(i)); for (int j = 0; j < atoms.size(); ++j) { if (!types.contains(atoms.at(j))) types.append(atoms.at(j)); diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 0bfc2f8f76..15fdf50a1e 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -452,6 +452,7 @@ public: void setFocusWindow(QXcbWindow *); QByteArray startupId() const { return m_startupId; } + void setStartupId(const QByteArray &nextId) { m_startupId = nextId; } void clearStartupId() { m_startupId.clear(); } void grabServer(); diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp index 4f0f57c375..bd28548cba 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.cpp +++ b/src/plugins/platforms/xcb/qxcbdrag.cpp @@ -183,7 +183,7 @@ void QXcbDrag::startDrag() QStringList fmts = QXcbMime::formatsHelper(drag()->mimeData()); for (int i = 0; i < fmts.size(); ++i) { - QList<xcb_atom_t> atoms = QXcbMime::mimeAtomsForFormat(connection(), fmts.at(i)); + QVector<xcb_atom_t> atoms = QXcbMime::mimeAtomsForFormat(connection(), fmts.at(i)); for (int j = 0; j < atoms.size(); ++j) { if (!drag_types.contains(atoms.at(j))) drag_types.append(atoms.at(j)); @@ -1010,9 +1010,6 @@ void QXcbDrag::handleFinished(const xcb_client_message_event_t *event) // current_target = 0; // current_proxy_target = 0; - if (t.drag) - t.drag->deleteLater(); - // current_target = target; // current_proxy_target = proxy_target; // current_embedding_widget = embedding_widget; @@ -1211,7 +1208,7 @@ QVariant QXcbDropData::xdndObtainData(const QByteArray &format, QVariant::Type r return result; } - QList<xcb_atom_t> atoms = drag->xdnd_types; + QVector<xcb_atom_t> atoms = drag->xdnd_types; QByteArray encoding; xcb_atom_t a = mimeAtomForFormat(c, QLatin1String(format), requestedType, atoms, &encoding); if (a == XCB_NONE) diff --git a/src/plugins/platforms/xcb/qxcbdrag.h b/src/plugins/platforms/xcb/qxcbdrag.h index d94c42696f..7b0d337e7c 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.h +++ b/src/plugins/platforms/xcb/qxcbdrag.h @@ -46,7 +46,6 @@ #include <private/qsimpledrag_p.h> #include <qxcbobject.h> #include <xcb/xcb.h> -#include <qlist.h> #include <qpoint.h> #include <qrect.h> #include <qsharedpointer.h> @@ -127,7 +126,7 @@ private: // the types in this drop. 100 is no good, but at least it's big. enum { xdnd_max_type = 100 }; - QList<xcb_atom_t> xdnd_types; + QVector<xcb_atom_t> xdnd_types; // timestamp from XdndPosition and XdndDroptime for retrieving the data xcb_timestamp_t target_time; @@ -160,7 +159,7 @@ private: QPointer<QDrag> drag; QTime time; }; - QList<Transaction> transactions; + QVector<Transaction> transactions; int transaction_expiry_timer; void restartDropExpiryTimer(); diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index 1b1c20f02c..f537a38962 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -83,6 +83,7 @@ #include "qxcbeglsurface.h" #include <QtPlatformSupport/private/qeglplatformcontext_p.h> #include <QtPlatformSupport/private/qeglpbuffer_p.h> +#include <QtPlatformHeaders/QEGLNativeContext> #endif #include <QtGui/QOpenGLContext> @@ -187,8 +188,8 @@ class QEGLXcbPlatformContext : public QEGLPlatformContext { public: QEGLXcbPlatformContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share, - EGLDisplay display, QXcbConnection *c) - : QEGLPlatformContext(glFormat, share, display) + EGLDisplay display, QXcbConnection *c, const QVariant &nativeHandle) + : QEGLPlatformContext(glFormat, share, display, 0, nativeHandle) , m_connection(c) { Q_XCB_NOOP(m_connection); @@ -224,6 +225,10 @@ public: return static_cast<QEGLPbuffer *>(surface)->pbuffer(); } + QVariant nativeHandle() const { + return QVariant::fromValue<QEGLNativeContext>(QEGLNativeContext(eglContext(), eglDisplay())); + } + private: QXcbConnection *m_connection; }; @@ -234,10 +239,18 @@ QPlatformOpenGLContext *QXcbIntegration::createPlatformOpenGLContext(QOpenGLCont { QXcbScreen *screen = static_cast<QXcbScreen *>(context->screen()->handle()); #if defined(XCB_USE_GLX) - return new QGLXContext(screen, context->format(), context->shareHandle()); + QGLXContext *platformContext = new QGLXContext(screen, context->format(), + context->shareHandle(), context->nativeHandle()); + context->setNativeHandle(platformContext->nativeHandle()); + return platformContext; #elif defined(XCB_USE_EGL) - return new QEGLXcbPlatformContext(context->format(), context->shareHandle(), - screen->connection()->egl_display(), screen->connection()); + QEGLXcbPlatformContext *platformContext = new QEGLXcbPlatformContext(context->format(), + context->shareHandle(), + screen->connection()->egl_display(), + screen->connection(), + context->nativeHandle()); + context->setNativeHandle(platformContext->nativeHandle()); + return platformContext; #else Q_UNUSED(screen); qWarning("QXcbIntegration: Cannot create platform OpenGL context, neither GLX nor EGL are enabled"); diff --git a/src/plugins/platforms/xcb/qxcbmime.cpp b/src/plugins/platforms/xcb/qxcbmime.cpp index b205a63267..c0f6745e7f 100644 --- a/src/plugins/platforms/xcb/qxcbmime.cpp +++ b/src/plugins/platforms/xcb/qxcbmime.cpp @@ -136,9 +136,10 @@ bool QXcbMime::mimeDataForAtom(QXcbConnection *connection, xcb_atom_t a, QMimeDa return ret; } -QList<xcb_atom_t> QXcbMime::mimeAtomsForFormat(QXcbConnection *connection, const QString &format) +QVector<xcb_atom_t> QXcbMime::mimeAtomsForFormat(QXcbConnection *connection, const QString &format) { - QList<xcb_atom_t> atoms; + QVector<xcb_atom_t> atoms; + atoms.reserve(7); atoms.append(connection->internAtom(format.toLatin1())); // special cases for strings @@ -240,7 +241,7 @@ QVariant QXcbMime::mimeConvertToFormat(QXcbConnection *connection, xcb_atom_t a, } xcb_atom_t QXcbMime::mimeAtomForFormat(QXcbConnection *connection, const QString &format, QVariant::Type requestedType, - const QList<xcb_atom_t> &atoms, QByteArray *requestedEncoding) + const QVector<xcb_atom_t> &atoms, QByteArray *requestedEncoding) { requestedEncoding->clear(); diff --git a/src/plugins/platforms/xcb/qxcbmime.h b/src/plugins/platforms/xcb/qxcbmime.h index 4a69a35ced..563716a75b 100644 --- a/src/plugins/platforms/xcb/qxcbmime.h +++ b/src/plugins/platforms/xcb/qxcbmime.h @@ -59,14 +59,14 @@ public: QXcbMime(); ~QXcbMime(); - static QList<xcb_atom_t> mimeAtomsForFormat(QXcbConnection *connection, const QString &format); + static QVector<xcb_atom_t> mimeAtomsForFormat(QXcbConnection *connection, const QString &format); static QString mimeAtomToString(QXcbConnection *connection, xcb_atom_t a); static bool mimeDataForAtom(QXcbConnection *connection, xcb_atom_t a, QMimeData *mimeData, QByteArray *data, xcb_atom_t *atomFormat, int *dataFormat); static QVariant mimeConvertToFormat(QXcbConnection *connection, xcb_atom_t a, const QByteArray &data, const QString &format, QVariant::Type requestedType, const QByteArray &encoding); static xcb_atom_t mimeAtomForFormat(QXcbConnection *connection, const QString &format, QVariant::Type requestedType, - const QList<xcb_atom_t> &atoms, QByteArray *requestedEncoding); + const QVector<xcb_atom_t> &atoms, QByteArray *requestedEncoding); }; #endif // !(defined(QT_NO_DRAGANDDROP) && defined(QT_NO_CLIPBOARD)) diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp index b45bd6a82e..625a804c0c 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp @@ -60,6 +60,8 @@ #include "qglxintegration.h" #endif +#include <QtPlatformHeaders/qxcbwindowfunctions.h> + #ifdef XCB_USE_XLIB # include <X11/Xlib.h> #else @@ -225,6 +227,14 @@ void *QXcbNativeInterface::nativeResourceForWindow(const QByteArray &resourceStr return result; } +QPlatformNativeInterface::NativeResourceForIntegrationFunction QXcbNativeInterface::nativeResourceFunctionForIntegration(const QByteArray &resource) +{ + QByteArray lowerCaseResource = resource.toLower(); + if (lowerCaseResource == "setstartupid") + return NativeResourceForIntegrationFunction(setStartupId); + return 0; +} + QPlatformNativeInterface::NativeResourceForScreenFunction QXcbNativeInterface::nativeResourceFunctionForScreen(const QByteArray &resource) { const QByteArray lowerCaseResource = resource.toLower(); @@ -235,6 +245,14 @@ QPlatformNativeInterface::NativeResourceForScreenFunction QXcbNativeInterface::n return 0; } +QFunctionPointer QXcbNativeInterface::platformFunction(const QByteArray &function) const +{ + if (function == QXcbWindowFunctions::setWmWindowTypeIdentifier()) { + return QFunctionPointer(QXcbWindow::setWmWindowTypeStatic); + } + return Q_NULLPTR; +} + void *QXcbNativeInterface::appTime(const QXcbScreen *screen) { return reinterpret_cast<void *>(quintptr(screen->connection()->time())); @@ -287,6 +305,15 @@ void QXcbNativeInterface::setAppUserTime(QScreen* screen, xcb_timestamp_t time) static_cast<QXcbScreen *>(screen->handle())->connection()->setNetWmUserTime(time); } +void QXcbNativeInterface::setStartupId(const char *data) +{ + QByteArray startupId(data); + QXcbIntegration *integration = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration()); + QXcbConnection *defaultConnection = integration->defaultConnection(); + if (defaultConnection) + defaultConnection->setStartupId(startupId); +} + QPlatformNativeInterface::NativeResourceForContextFunction QXcbNativeInterface::nativeResourceFunctionForContext(const QByteArray &resource) { QByteArray lowerCaseResource = resource.toLower(); diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h index fb1a46014c..f860e0d267 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.h +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h @@ -77,13 +77,16 @@ public: QXcbNativeInterface(); void *nativeResourceForIntegration(const QByteArray &resource) Q_DECL_OVERRIDE; - void *nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context); - void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen); - void *nativeResourceForWindow(const QByteArray &resourceString, QWindow *window); + void *nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context) Q_DECL_OVERRIDE; + void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen) Q_DECL_OVERRIDE; + void *nativeResourceForWindow(const QByteArray &resourceString, QWindow *window) Q_DECL_OVERRIDE; - NativeResourceForContextFunction nativeResourceFunctionForContext(const QByteArray &resource); + NativeResourceForIntegrationFunction nativeResourceFunctionForIntegration(const QByteArray &resource) Q_DECL_OVERRIDE; + NativeResourceForContextFunction nativeResourceFunctionForContext(const QByteArray &resource) Q_DECL_OVERRIDE; NativeResourceForScreenFunction nativeResourceFunctionForScreen(const QByteArray &resource) Q_DECL_OVERRIDE; + QFunctionPointer platformFunction(const QByteArray &function) const Q_DECL_OVERRIDE; + inline const QByteArray &genericEventFilterType() const { return m_genericEventFilterType; } void *displayForWindow(QWindow *window); @@ -96,6 +99,7 @@ public: void *startupId(); void *x11Screen(); void *rootWindow(); + static void setStartupId(const char *); static void setAppTime(QScreen *screen, xcb_timestamp_t time); static void setAppUserTime(QScreen *screen, xcb_timestamp_t time); static void *eglContextForContext(QOpenGLContext *context); diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 586068d8d9..f002d473b7 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -183,6 +183,8 @@ static inline bool positionIncludesFrame(QWindow *w) return qt_window_private(w)->positionPolicy == QWindowPrivate::WindowFrameInclusive; } +static const char *wm_window_type_property_id = "_q_xcb_wm_window_type"; + QXcbWindow::QXcbWindow(QWindow *window) : QPlatformWindow(window) , m_window(0) @@ -698,6 +700,9 @@ void QXcbWindow::show() updateNetWmStateBeforeMap(); } + QXcbWindowFunctions::WmWindowTypes wmWindowTypes(window()->property(wm_window_type_property_id).value<int>()); + setWmWindowType(wmWindowTypes); + if (connection()->time() != XCB_TIME_CURRENT_TIME) updateNetWmUserTime(connection()->time()); @@ -1535,6 +1540,133 @@ QXcbEGLSurface *QXcbWindow::eglSurface() const } #endif +void QXcbWindow::setWmWindowTypeStatic(QWindow *window, QXcbWindowFunctions::WmWindowTypes windowTypes) +{ + if (window->handle()) + static_cast<QXcbWindow *>(window->handle())->setWmWindowType(windowTypes); + else + window->setProperty(wm_window_type_property_id, QVariant::fromValue(static_cast<int>(windowTypes))); +} + +QXcbWindowFunctions::WmWindowTypes QXcbWindow::wmWindowTypes() const +{ + QXcbWindowFunctions::WmWindowTypes result(0); + + xcb_get_property_cookie_t get_cookie = + xcb_get_property_unchecked(xcb_connection(), 0, m_window, atom(QXcbAtom::_NET_WM_WINDOW_TYPE), + XCB_ATOM_ATOM, 0, 1024); + + xcb_get_property_reply_t *reply = + xcb_get_property_reply(xcb_connection(), get_cookie, NULL); + + if (reply && reply->format == 32 && reply->type == XCB_ATOM_ATOM) { + const xcb_atom_t *types = static_cast<const xcb_atom_t *>(xcb_get_property_value(reply)); + const xcb_atom_t *types_end = types + reply->length; + for (; types != types_end; types++) { + QXcbAtom::Atom type = connection()->qatom(*types); + switch (type) { + case QXcbAtom::_NET_WM_WINDOW_TYPE_NORMAL: + result |= QXcbWindowFunctions::Normal; + break; + case QXcbAtom::_NET_WM_WINDOW_TYPE_DESKTOP: + result |= QXcbWindowFunctions::Desktop; + break; + case QXcbAtom::_NET_WM_WINDOW_TYPE_DOCK: + qDebug() << "IS DOCK"; + result |= QXcbWindowFunctions::Dock; + break; + case QXcbAtom::_NET_WM_WINDOW_TYPE_TOOLBAR: + result |= QXcbWindowFunctions::Toolbar; + break; + case QXcbAtom::_NET_WM_WINDOW_TYPE_MENU: + result |= QXcbWindowFunctions::Menu; + break; + case QXcbAtom::_NET_WM_WINDOW_TYPE_UTILITY: + result |= QXcbWindowFunctions::Utility; + break; + case QXcbAtom::_NET_WM_WINDOW_TYPE_SPLASH: + result |= QXcbWindowFunctions::Splash; + break; + case QXcbAtom::_NET_WM_WINDOW_TYPE_DIALOG: + result |= QXcbWindowFunctions::Dialog; + break; + case QXcbAtom::_NET_WM_WINDOW_TYPE_DROPDOWN_MENU: + result |= QXcbWindowFunctions::DropDownMenu; + break; + case QXcbAtom::_NET_WM_WINDOW_TYPE_POPUP_MENU: + result |= QXcbWindowFunctions::PopupMenu; + break; + case QXcbAtom::_NET_WM_WINDOW_TYPE_TOOLTIP: + result |= QXcbWindowFunctions::Tooltip; + break; + case QXcbAtom::_NET_WM_WINDOW_TYPE_NOTIFICATION: + result |= QXcbWindowFunctions::Notification; + break; + case QXcbAtom::_NET_WM_WINDOW_TYPE_COMBO: + result |= QXcbWindowFunctions::Combo; + break; + case QXcbAtom::_NET_WM_WINDOW_TYPE_DND: + result |= QXcbWindowFunctions::Dnd; + break; + case QXcbAtom::_KDE_NET_WM_WINDOW_TYPE_OVERRIDE: + result |= QXcbWindowFunctions::KdeOverride; + break; + default: + break; + } + } + free(reply); + } + return result; +} + +void QXcbWindow::setWmWindowType(QXcbWindowFunctions::WmWindowTypes types) +{ + QVector<xcb_atom_t> atoms; + + if (types & QXcbWindowFunctions::Normal) + atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_NORMAL)); + if (types & QXcbWindowFunctions::Desktop) + atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_DESKTOP)); + if (types & QXcbWindowFunctions::Dock) { + qDebug() << "setting to be dock"; + atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_DOCK)); + } + if (types & QXcbWindowFunctions::Toolbar) + atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_TOOLBAR)); + if (types & QXcbWindowFunctions::Menu) + atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_MENU)); + if (types & QXcbWindowFunctions::Utility) + atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_UTILITY)); + if (types & QXcbWindowFunctions::Splash) + atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_SPLASH)); + if (types & QXcbWindowFunctions::Dialog) + atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_DIALOG)); + if (types & QXcbWindowFunctions::DropDownMenu) + atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_DROPDOWN_MENU)); + if (types & QXcbWindowFunctions::PopupMenu) + atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_POPUP_MENU)); + if (types & QXcbWindowFunctions::Tooltip) + atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_TOOLTIP)); + if (types & QXcbWindowFunctions::Notification) + atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_NOTIFICATION)); + if (types & QXcbWindowFunctions::Combo) + atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_COMBO)); + if (types & QXcbWindowFunctions::Dnd) + atoms.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_DND)); + if (types & QXcbWindowFunctions::KdeOverride) + atoms.append(atom(QXcbAtom::_KDE_NET_WM_WINDOW_TYPE_OVERRIDE)); + + if (atoms.isEmpty()) { + Q_XCB_CALL(xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_WINDOW_TYPE))); + } else { + Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, + atom(QXcbAtom::_NET_WM_WINDOW_TYPE), XCB_ATOM_ATOM, 32, + atoms.count(), atoms.constData())); + } + xcb_flush(xcb_connection()); +} + class ExposeCompressor { public: diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index b924ee27e5..72b5c7bcc9 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -51,6 +51,8 @@ #include "qxcbobject.h" +#include <QtPlatformHeaders/qxcbwindowfunctions.h> + QT_BEGIN_NAMESPACE class QXcbScreen; @@ -150,6 +152,11 @@ public: QXcbEGLSurface *eglSurface() const; #endif + static void setWmWindowTypeStatic(QWindow *window, QXcbWindowFunctions::WmWindowTypes windowTypes); + + QXcbWindowFunctions::WmWindowTypes wmWindowTypes() const; + void setWmWindowType(QXcbWindowFunctions::WmWindowTypes types); + bool needsSync() const; public Q_SLOTS: diff --git a/src/plugins/platforms/xcb/qxcbxsettings.cpp b/src/plugins/platforms/xcb/qxcbxsettings.cpp index 141a6cc0cb..17b40a45e1 100644 --- a/src/plugins/platforms/xcb/qxcbxsettings.cpp +++ b/src/plugins/platforms/xcb/qxcbxsettings.cpp @@ -42,6 +42,7 @@ #include "qxcbxsettings.h" #include <QtCore/QByteArray> +#include <QtCore/QtEndian> #include <X11/extensions/XIproto.h> @@ -149,47 +150,67 @@ public: { if (xSettings.length() < 12) return; - // we ignore byteorder for now - char byteOrder = xSettings.at(1); - Q_UNUSED(byteOrder); - uint number_of_settings = *reinterpret_cast<const uint *>(xSettings.mid(8,4).constData()); + char byteOrder = xSettings.at(0); + if (byteOrder != LSBFirst && byteOrder != MSBFirst) { + qWarning("%s ByteOrder byte %d not 0 or 1", Q_FUNC_INFO , byteOrder); + return; + } + +#define ADJUST_BO(b, t, x) \ + ((b == LSBFirst) ? \ + qFromLittleEndian<t>((const uchar *)(x)) : \ + qFromBigEndian<t>((const uchar *)(x))) +#define VALIDATE_LENGTH(x) \ + if ((size_t)xSettings.length() < (offset + local_offset + 12 + x)) { \ + qWarning("%s Length %d runs past end of data", Q_FUNC_INFO , x); \ + return; \ + } + uint number_of_settings = ADJUST_BO(byteOrder, quint32, xSettings.mid(8,4).constData()); const char *data = xSettings.constData() + 12; size_t offset = 0; for (uint i = 0; i < number_of_settings; i++) { int local_offset = 0; + VALIDATE_LENGTH(2); XSettingsType type = static_cast<XSettingsType>(*reinterpret_cast<const quint8 *>(data + offset)); local_offset += 2; - quint16 name_len = *reinterpret_cast<const quint16 *>(data + offset + local_offset); + VALIDATE_LENGTH(2); + quint16 name_len = ADJUST_BO(byteOrder, quint16, data + offset + local_offset); local_offset += 2; + VALIDATE_LENGTH(name_len); QByteArray name(data + offset + local_offset, name_len); local_offset += round_to_nearest_multiple_of_4(name_len); - int last_change_serial = *reinterpret_cast<const int *>(data + offset + local_offset); + VALIDATE_LENGTH(4); + int last_change_serial = ADJUST_BO(byteOrder, qint32, data + offset + local_offset); Q_UNUSED(last_change_serial); local_offset += 4; QVariant value; if (type == XSettingsTypeString) { - int value_length = *reinterpret_cast<const int *>(data + offset + local_offset); + VALIDATE_LENGTH(4); + int value_length = ADJUST_BO(byteOrder, qint32, data + offset + local_offset); local_offset+=4; + VALIDATE_LENGTH(value_length); QByteArray value_string(data + offset + local_offset, value_length); value.setValue(value_string); local_offset += round_to_nearest_multiple_of_4(value_length); } else if (type == XSettingsTypeInteger) { - int value_length = *reinterpret_cast<const int *>(data + offset + local_offset); + VALIDATE_LENGTH(4); + int value_length = ADJUST_BO(byteOrder, qint32, data + offset + local_offset); local_offset += 4; value.setValue(value_length); } else if (type == XSettingsTypeColor) { - quint16 red = *reinterpret_cast<const quint16 *>(data + offset + local_offset); + VALIDATE_LENGTH(2*4); + quint16 red = ADJUST_BO(byteOrder, quint16, data + offset + local_offset); local_offset += 2; - quint16 green = *reinterpret_cast<const quint16 *>(data + offset + local_offset); + quint16 green = ADJUST_BO(byteOrder, quint16, data + offset + local_offset); local_offset += 2; - quint16 blue = *reinterpret_cast<const quint16 *>(data + offset + local_offset); + quint16 blue = ADJUST_BO(byteOrder, quint16, data + offset + local_offset); local_offset += 2; - quint16 alpha= *reinterpret_cast<const quint16 *>(data + offset + local_offset); + quint16 alpha= ADJUST_BO(byteOrder, quint16, data + offset + local_offset); local_offset += 2; QColor color_value(red,green,blue,alpha); value.setValue(color_value); |