diff options
Diffstat (limited to 'src/plugins/platforms/windows')
21 files changed, 766 insertions, 522 deletions
diff --git a/src/plugins/platforms/windows/accessible/iaccessible2.cpp b/src/plugins/platforms/windows/accessible/iaccessible2.cpp index d5cd9ac6db..d9c3d6ac14 100644 --- a/src/plugins/platforms/windows/accessible/iaccessible2.cpp +++ b/src/plugins/platforms/windows/accessible/iaccessible2.cpp @@ -61,40 +61,7 @@ static inline T *coTaskMemAllocArray(int size) /**************************************************************\ * AccessibleApplication * **************************************************************/ -// IUnknown -HRESULT STDMETHODCALLTYPE AccessibleApplication::QueryInterface(REFIID id, LPVOID *iface) -{ - *iface = 0; - if (id == IID_IUnknown) { - qCDebug(lcQpaAccessibility) << "AccessibleApplication::QI(): IID_IUnknown"; - *iface = static_cast<IUnknown *>(this); - } else if (id == IID_IAccessibleApplication) { - qCDebug(lcQpaAccessibility) << "AccessibleApplication::QI(): IID_IAccessibleApplication"; - *iface = static_cast<IAccessibleApplication*>(this); - } - - if (*iface) { - AddRef(); - return S_OK; - } - return E_NOINTERFACE; -} - -ULONG STDMETHODCALLTYPE AccessibleApplication::AddRef() -{ - return ++m_ref; -} -ULONG STDMETHODCALLTYPE AccessibleApplication::Release() -{ - if (!--m_ref) { - delete this; - return 0; - } - return m_ref; -} - -/* IAccessibleApplication */ HRESULT STDMETHODCALLTYPE AccessibleApplication::get_appName(/* [retval][out] */ BSTR *name) { const QString appName = QGuiApplication::applicationName(); @@ -127,40 +94,11 @@ HRESULT STDMETHODCALLTYPE AccessibleApplication::get_toolkitVersion(/* [retval][ **************************************************************/ AccessibleRelation::AccessibleRelation(const QList<QAccessibleInterface *> &targets, QAccessible::Relation relation) - : m_targets(targets), m_relation(relation), m_ref(1) + : m_targets(targets), m_relation(relation) { Q_ASSERT(m_targets.count()); } -/* IUnknown */ -HRESULT STDMETHODCALLTYPE AccessibleRelation::QueryInterface(REFIID id, LPVOID *iface) -{ - *iface = 0; - if (id == IID_IUnknown || id == IID_IAccessibleRelation) - *iface = static_cast<IUnknown *>(this); - - if (*iface) { - AddRef(); - return S_OK; - } - - return E_NOINTERFACE; -} - -ULONG STDMETHODCALLTYPE AccessibleRelation::AddRef() -{ - return ++m_ref; -} - -ULONG STDMETHODCALLTYPE AccessibleRelation::Release() -{ - if (!--m_ref) { - delete this; - return 0; - } - return m_ref; -} - /* IAccessibleRelation */ HRESULT STDMETHODCALLTYPE AccessibleRelation::get_relationType( /* [retval][out] */ BSTR *relationType) @@ -237,56 +175,53 @@ HRESULT STDMETHODCALLTYPE AccessibleRelation::get_targets( **************************************************************/ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::QueryInterface(REFIID id, LPVOID *iface) { + *iface = nullptr; QAccessibleInterface *accessible = accessibleInterface(); if (!accessible) return E_NOINTERFACE; - HRESULT hr = QWindowsMsaaAccessible::QueryInterface(id, iface); - if (!SUCCEEDED(hr)) { - if (id == IID_IServiceProvider) { - *iface = static_cast<IServiceProvider *>(this); - } else if (id == IID_IAccessible2) { - *iface = static_cast<IAccessible2 *>(this); - } else if (id == IID_IAccessibleAction) { - if (accessible->actionInterface()) - *iface = static_cast<IAccessibleAction *>(this); - } else if (id == IID_IAccessibleComponent) { - *iface = static_cast<IAccessibleComponent *>(this); - } else if (id == IID_IAccessibleEditableText) { - if (accessible->editableTextInterface() || - accessible->role() == QAccessible::EditableText) - { - *iface = static_cast<IAccessibleEditableText *>(this); - } - } else if (id == IID_IAccessibleHyperlink) { - //*iface = static_cast<IAccessibleHyperlink *>(this); - } else if (id == IID_IAccessibleHypertext) { - //*iface = static_cast<IAccessibleHypertext *>(this); - } else if (id == IID_IAccessibleImage) { - //*iface = static_cast<IAccessibleImage *>(this); - } else if (id == IID_IAccessibleTable) { - //*iface = static_cast<IAccessibleTable *>(this); // not supported - } else if (id == IID_IAccessibleTable2) { - if (accessible->tableInterface()) - *iface = static_cast<IAccessibleTable2 *>(this); - } else if (id == IID_IAccessibleTableCell) { - if (accessible->tableCellInterface()) - *iface = static_cast<IAccessibleTableCell *>(this); - } else if (id == IID_IAccessibleText) { - if (accessible->textInterface()) - *iface = static_cast<IAccessibleText *>(this); - } else if (id == IID_IAccessibleValue) { - if (accessible->valueInterface()) - *iface = static_cast<IAccessibleValue *>(this); - } - if (*iface) { - AddRef(); - hr = S_OK; - } else { - hr = E_NOINTERFACE; + if (SUCCEEDED(QWindowsMsaaAccessible::QueryInterface(id, iface)) + || qWindowsComQueryInterface<IServiceProvider>(this, id, iface) + || qWindowsComQueryInterface<IAccessible2>(this, id, iface) + || qWindowsComQueryInterface<IAccessibleComponent>(this, id, iface)) { + return S_OK; + } + + if (id == IID_IAccessibleAction) { + if (accessible->actionInterface()) + *iface = static_cast<IAccessibleAction *>(this); + } else if (id == IID_IAccessibleEditableText) { + if (accessible->editableTextInterface() || + accessible->role() == QAccessible::EditableText) + { + *iface = static_cast<IAccessibleEditableText *>(this); } + } else if (id == IID_IAccessibleHyperlink) { + //*iface = static_cast<IAccessibleHyperlink *>(this); + } else if (id == IID_IAccessibleHypertext) { + //*iface = static_cast<IAccessibleHypertext *>(this); + } else if (id == IID_IAccessibleImage) { + //*iface = static_cast<IAccessibleImage *>(this); + } else if (id == IID_IAccessibleTable) { + //*iface = static_cast<IAccessibleTable *>(this); // not supported + } else if (id == IID_IAccessibleTable2) { + if (accessible->tableInterface()) + *iface = static_cast<IAccessibleTable2 *>(this); + } else if (id == IID_IAccessibleTableCell) { + if (accessible->tableCellInterface()) + *iface = static_cast<IAccessibleTableCell *>(this); + } else if (id == IID_IAccessibleText) { + if (accessible->textInterface()) + *iface = static_cast<IAccessibleText *>(this); + } else if (id == IID_IAccessibleValue) { + if (accessible->valueInterface()) + *iface = static_cast<IAccessibleValue *>(this); } - return hr; + if (*iface) { + AddRef(); + return S_OK; + } + return E_NOINTERFACE; } @@ -1593,7 +1528,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::QueryService(REFGUID guidServic return E_POINTER; Q_UNUSED(guidService); *iface = 0; - qCDebug(lcQpaAccessibility) << "QWindowsIA2Accessible::QS(): " << IIDToString(riid); + qCDebug(lcQpaAccessibility) << "QWindowsIA2Accessible::QS(): " << QWindowsAccessibleGuid(riid); if (guidService == IID_IAccessible) { @@ -1692,45 +1627,6 @@ HRESULT QWindowsIA2Accessible::wrapListOfCells(const QList<QAccessibleInterface* return count > 0 ? S_OK : S_FALSE; } -#define IF_EQUAL_RETURN_IIDSTRING(id, iid) if (id == iid) return QByteArray(#iid) - -QByteArray QWindowsIA2Accessible::IIDToString(REFIID id) -{ - QByteArray strGuid = QWindowsMsaaAccessible::IIDToString(id); - if (!strGuid.isEmpty()) - return strGuid; - - IF_EQUAL_RETURN_IIDSTRING(id, IID_IUnknown); - IF_EQUAL_RETURN_IIDSTRING(id, IID_IDispatch); - IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessible); - IF_EQUAL_RETURN_IIDSTRING(id, IID_IOleWindow); - IF_EQUAL_RETURN_IIDSTRING(id, IID_IServiceProvider); - IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessible2); - IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleAction); - IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleApplication); - IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleComponent); - IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleEditableText); - IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleHyperlink); - IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleHypertext); - IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleImage); - IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleRelation); - IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleTable); - IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleTable2); - IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleTableCell); - IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleText); - IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessibleValue); - - // else... -#if 0 // Can be useful for debugging, but normally we'd like to reduce the noise a bit... - OLECHAR szGuid[39]={0}; - ::StringFromGUID2(id, szGuid, 39); - strGuid.reserve(40); - ::WideCharToMultiByte(CP_UTF8, 0, szGuid, 39, strGuid.data(), 39, NULL, NULL); - strGuid[38] = '\0'; -#endif - return strGuid; -} - // Q_STATIC_ASSERT(IA2_ROLE_CANVAS == QAccessible::Canvas); // ### Qt 6: make them the same Q_STATIC_ASSERT(IA2_ROLE_COLOR_CHOOSER == static_cast<IA2Role>(QAccessible::ColorChooser)); Q_STATIC_ASSERT(IA2_ROLE_FOOTER == static_cast<IA2Role>(QAccessible::Footer)); diff --git a/src/plugins/platforms/windows/accessible/iaccessible2.h b/src/plugins/platforms/windows/accessible/iaccessible2.h index bc5f5be60f..d5c67f8b51 100644 --- a/src/plugins/platforms/windows/accessible/iaccessible2.h +++ b/src/plugins/platforms/windows/accessible/iaccessible2.h @@ -42,6 +42,7 @@ #include <QtCore/QtConfig> #ifndef QT_NO_ACCESSIBILITY +#include "qwindowscombase.h" #include "qwindowsmsaaaccessible.h" #include "comutils.h" @@ -249,7 +250,6 @@ private: HRESULT getRelationsHelper(IAccessibleRelation **relations, int startIndex, long maxRelations, long *nRelations = 0); HRESULT wrapListOfCells(const QList<QAccessibleInterface*> &inputCells, IUnknown ***outputAccessibles, long *nCellCount); - QByteArray IIDToString(REFIID id); QString textForRange(int startOffset, int endOffset) const; void replaceTextFallback(long startOffset, long endOffset, const QString &txt); @@ -258,28 +258,18 @@ private: /**************************************************************\ * AccessibleApplication * **************************************************************/ -class AccessibleApplication : public IAccessibleApplication +class AccessibleApplication : public QWindowsComBase<IAccessibleApplication> { public: - AccessibleApplication() : m_ref(1) - { - - } + AccessibleApplication() {} virtual ~AccessibleApplication() {} - /* IUnknown */ - HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID *); - ULONG STDMETHODCALLTYPE AddRef(); - ULONG STDMETHODCALLTYPE Release(); - /* IAccessibleApplication */ HRESULT STDMETHODCALLTYPE get_appName(/* [retval][out] */ BSTR *name); HRESULT STDMETHODCALLTYPE get_appVersion(/* [retval][out] */ BSTR *version); HRESULT STDMETHODCALLTYPE get_toolkitName(/* [retval][out] */ BSTR *name); HRESULT STDMETHODCALLTYPE get_toolkitVersion(/* [retval][out] */ BSTR *version); -private: - ULONG m_ref; }; @@ -287,7 +277,7 @@ private: /**************************************************************\ * AccessibleRelation * **************************************************************/ -class AccessibleRelation : public IAccessibleRelation +class AccessibleRelation : public QWindowsComBase<IAccessibleRelation> { public: AccessibleRelation(const QList<QAccessibleInterface *> &targets, @@ -295,11 +285,6 @@ public: virtual ~AccessibleRelation() {} - /* IUnknown */ - HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id, LPVOID *iface); - ULONG STDMETHODCALLTYPE AddRef(); - ULONG STDMETHODCALLTYPE Release(); - /* IAccessibleRelation */ HRESULT STDMETHODCALLTYPE get_relationType(BSTR *relationType); HRESULT STDMETHODCALLTYPE get_localizedRelationType(BSTR *localizedRelationType); @@ -341,7 +326,6 @@ private: QList<QAccessibleInterface *> m_targets; QAccessible::Relation m_relation; - ULONG m_ref; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp index 25b1577772..308ff59c49 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp +++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp @@ -42,6 +42,7 @@ #include "qwindowsmsaaaccessible.h" #include "qwindowsaccessibility.h" +#include "qwindowscombase.h" #include <oleacc.h> #include <servprov.h> #include <winuser.h> @@ -71,61 +72,22 @@ QT_BEGIN_NAMESPACE -class QWindowsEnumerate : public IEnumVARIANT +class QWindowsEnumerate : public QWindowsComBase<IEnumVARIANT> { public: - QWindowsEnumerate(const QVector<int> &a) - : ref(0), current(0),array(a) - { - } - + QWindowsEnumerate(const QVector<int> &a) : QWindowsComBase<IEnumVARIANT>(0), current(0),array(a) {} virtual ~QWindowsEnumerate() {} - HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID *); - ULONG STDMETHODCALLTYPE AddRef(); - ULONG STDMETHODCALLTYPE Release(); - HRESULT STDMETHODCALLTYPE Clone(IEnumVARIANT **ppEnum); HRESULT STDMETHODCALLTYPE Next(unsigned long celt, VARIANT FAR* rgVar, unsigned long FAR* pCeltFetched); HRESULT STDMETHODCALLTYPE Reset(); HRESULT STDMETHODCALLTYPE Skip(unsigned long celt); private: - ULONG ref; ULONG current; QVector<int> array; }; -HRESULT STDMETHODCALLTYPE QWindowsEnumerate::QueryInterface(REFIID id, LPVOID *iface) -{ - *iface = 0; - if (id == IID_IUnknown) - *iface = static_cast<IUnknown *>(this); - else if (id == IID_IEnumVARIANT) - *iface = static_cast<IEnumVARIANT *>(this); - - if (*iface) { - AddRef(); - return S_OK; - } - - return E_NOINTERFACE; -} - -ULONG STDMETHODCALLTYPE QWindowsEnumerate::AddRef() -{ - return ++ref; -} - -ULONG STDMETHODCALLTYPE QWindowsEnumerate::Release() -{ - if (!--ref) { - delete this; - return 0; - } - return ref; -} - HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Clone(IEnumVARIANT **ppEnum) { QWindowsEnumerate *penum = 0; @@ -193,29 +155,17 @@ void accessibleDebugClientCalls_helper(const char* funcName, const QAccessibleIn **************************************************************/ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::QueryInterface(REFIID id, LPVOID *iface) { - *iface = 0; - - QByteArray strIID = IIDToString(id); - if (!strIID.isEmpty()) { - qCDebug(lcQpaAccessibility) << "QWindowsIA2Accessible::QI() - IID:" - << strIID << ", iface:" << accessibleInterface(); + *iface = nullptr; + const bool result = qWindowsComQueryUnknownInterfaceMulti<AccessibleBase>(this, id, iface) + || qWindowsComQueryInterface<IDispatch>(this, id, iface) + || qWindowsComQueryInterface<IAccessible>(this, id, iface) + || qWindowsComQueryInterface<IOleWindow>(this, id, iface); + + if (result) { + qCDebug(lcQpaAccessibility) << "QWindowsIA2Accessible::QI() - " + << QWindowsAccessibleGuid(id) << ", iface:" << accessibleInterface(); } - if (id == IID_IUnknown) { - *iface = static_cast<IUnknown *>(static_cast<IDispatch *>(this)); - } else if (id == IID_IDispatch) { - *iface = static_cast<IDispatch *>(this); - } else if (id == IID_IAccessible) { - *iface = static_cast<IAccessible *>(this); - } else if (id == IID_IOleWindow) { - *iface = static_cast<IOleWindow *>(this); - } - - if (*iface) { - AddRef(); - return S_OK; - } - - return E_NOINTERFACE; + return result ? S_OK : E_NOINTERFACE; } ULONG STDMETHODCALLTYPE QWindowsMsaaAccessible::AddRef() @@ -1209,16 +1159,66 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::ContextSensitiveHelp(BOOL) return S_OK; } -#define IF_EQUAL_RETURN_IIDSTRING(id, iid) if (id == iid) return QByteArray(#iid) -QByteArray QWindowsMsaaAccessible::IIDToString(REFIID id) +const char *QWindowsAccessibleGuid::iidToString(const GUID &id) { - IF_EQUAL_RETURN_IIDSTRING(id, IID_IUnknown); - IF_EQUAL_RETURN_IIDSTRING(id, IID_IDispatch); - IF_EQUAL_RETURN_IIDSTRING(id, IID_IAccessible); - IF_EQUAL_RETURN_IIDSTRING(id, IID_IOleWindow); + const char *result = nullptr; + if (id == IID_IUnknown) + result = "IID_IUnknown"; + else if (id == IID_IDispatch) + result = "IID_IDispatch"; + else if (id == IID_IAccessible) + result = "IID_IAccessible"; + else if (id == IID_IOleWindow) + result = "IID_IOleWindow"; + else if (id == IID_IServiceProvider) + result = "IID_IServiceProvider"; +#ifndef Q_CC_MINGW + else if (id == IID_IAccessible2) + result = "IID_IAccessible2"; + else if (id == IID_IAccessibleAction) + result = "IID_IAccessibleAction"; + else if (id == IID_IAccessibleApplication) + result = "IID_IAccessibleApplication"; + else if (id == IID_IAccessibleComponent) + result = "IID_IAccessibleComponent"; + else if (id == IID_IAccessibleEditableText) + result = "IID_IAccessibleEditableText"; + else if (id == IID_IAccessibleHyperlink) + result = "IID_IAccessibleHyperlink"; + else if (id == IID_IAccessibleHypertext) + result = "IID_IAccessibleHypertext"; + else if (id == IID_IAccessibleImage) + result = "IID_IAccessibleImage"; + else if (id == IID_IAccessibleRelation) + result = "IID_IAccessibleRelation"; + else if (id == IID_IAccessibleTable) + result = "IID_IAccessibleTable"; + else if (id == IID_IAccessibleTable2) + result = "IID_IAccessibleTable2"; + else if (id == IID_IAccessibleTableCell) + result = "IID_IAccessibleTableCell"; + else if (id == IID_IAccessibleText) + result = "IID_IAccessibleText"; + else if (id == IID_IAccessibleValue) + result = "IID_IAccessibleValue"; +#endif // !Q_CC_MINGW + return result; +} + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug, const GUID &); - return QByteArray(); +QDebug operator<<(QDebug d, const QWindowsAccessibleGuid &aguid) +{ + QDebugStateSaver saver(d); + d.nospace(); + if (const char *ids = QWindowsAccessibleGuid::iidToString(aguid.guid())) + d << ids; + else + d << aguid.guid(); + return d; } +#endif // !QT_NO_DEBUG_STREAM QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h index fd00f8ac8b..07f10da99a 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h +++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h @@ -69,16 +69,32 @@ void accessibleDebugClientCalls_helper(const char* funcName, const QAccessibleIn QWindow *window_helper(const QAccessibleInterface *iface); +class QWindowsAccessibleGuid // Helper for QDebug, outputs known ids by name. +{ +public: + explicit QWindowsAccessibleGuid(const GUID &g) : m_guid(g) {} + GUID guid () const { return m_guid; } + static const char *iidToString(const GUID &id); + +private: + GUID m_guid; +}; + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const QWindowsAccessibleGuid &aguid); +#endif + /**************************************************************\ * QWindowsAccessible * **************************************************************/ -class QWindowsMsaaAccessible : public -#ifdef Q_CC_MINGW - IAccessible + +#ifndef Q_CC_MINGW +typedef IAccessible2 AccessibleBase; #else - IAccessible2 +typedef IAccessible AccessibleBase; #endif - , public IOleWindow + +class QWindowsMsaaAccessible : public AccessibleBase, public IOleWindow { public: QWindowsMsaaAccessible(QAccessibleInterface *a) @@ -132,8 +148,6 @@ public: HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode); protected: - virtual QByteArray IIDToString(REFIID id); - QAccessible::Id id; QAccessibleInterface *accessibleInterface() const diff --git a/src/plugins/platforms/windows/qwindowscombase.h b/src/plugins/platforms/windows/qwindowscombase.h new file mode 100644 index 0000000000..f8afcc81cf --- /dev/null +++ b/src/plugins/platforms/windows/qwindowscombase.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSCOMBASE_H +#define QWINDOWSCOMBASE_H + +#include <QtCore/QtGlobal> + +#include <unknwn.h> + +QT_BEGIN_NAMESPACE + +// Helper for implementing IUnknown::QueryInterface. +template <class DesiredInterface, class Derived> +bool qWindowsComQueryInterface(Derived *d, REFIID id, LPVOID *iface) +{ + if (id == __uuidof(DesiredInterface)) { + *iface = static_cast<DesiredInterface *>(d); + d->AddRef(); + return true; + } + return false; +} + +// Helper for implementing IUnknown::QueryInterface for IUnknown +// in the case of multiple inheritance via the first inherited class. +template <class FirstInheritedInterface, class Derived> +bool qWindowsComQueryUnknownInterfaceMulti(Derived *d, REFIID id, LPVOID *iface) +{ + if (id == __uuidof(IUnknown)) { + *iface = static_cast<FirstInheritedInterface *>(d); + d->AddRef(); + return true; + } + return false; +} + +// Helper base class to provide IUnknown methods for COM classes (single inheritance) +template <class ComInterface> class QWindowsComBase : public ComInterface +{ + Q_DISABLE_COPY(QWindowsComBase) +public: + explicit QWindowsComBase(ULONG initialRefCount = 1) : m_ref(initialRefCount) {} + virtual ~QWindowsComBase() {} + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id, LPVOID *iface) + { + *iface = nullptr; + return qWindowsComQueryInterface<IUnknown>(this, id, iface) || qWindowsComQueryInterface<ComInterface>(this, id, iface) + ? S_OK : E_NOINTERFACE; + } + + ULONG STDMETHODCALLTYPE AddRef() { return ++m_ref; } + + ULONG STDMETHODCALLTYPE Release() + { + if (!--m_ref) { + delete this; + return 0; + } + return m_ref; + } + +private: + ULONG m_ref; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSCOMBASE_H diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index f4527bcc60..59e2aacee9 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -41,6 +41,7 @@ #define _WIN32_WINNT 0x0600 +#include "qwindowscombase.h" #include "qwindowsdialoghelpers.h" #include "qwindowscontext.h" @@ -504,33 +505,11 @@ inline void QWindowsFileDialogSharedData::fromOptions(const QSharedPointer<QFile class QWindowsNativeFileDialogBase; -class QWindowsNativeFileDialogEventHandler : public IFileDialogEvents +class QWindowsNativeFileDialogEventHandler : public QWindowsComBase<IFileDialogEvents> { public: static IFileDialogEvents *create(QWindowsNativeFileDialogBase *nativeFileDialog); - // IUnknown methods - IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv) - { - if (riid != IID_IUnknown && riid != IID_IFileDialogEvents) { - *ppv = NULL; - return ResultFromScode(E_NOINTERFACE); - } - *ppv = this; - AddRef(); - return NOERROR; - } - - IFACEMETHODIMP_(ULONG) AddRef() { return InterlockedIncrement(&m_ref); } - - IFACEMETHODIMP_(ULONG) Release() - { - const long ref = InterlockedDecrement(&m_ref); - if (!ref) - delete this; - return ref; - } - // IFileDialogEvents methods IFACEMETHODIMP OnFileOk(IFileDialog *); IFACEMETHODIMP OnFolderChange(IFileDialog *) { return S_OK; } @@ -546,7 +525,6 @@ public: virtual ~QWindowsNativeFileDialogEventHandler() {} private: - long m_ref = 1; QWindowsNativeFileDialogBase *m_nativeFileDialog; }; diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp index 58175b39fa..a326ccac3e 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.cpp +++ b/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -215,7 +215,7 @@ static inline Qt::MouseButtons toQtMouseButtons(DWORD keyState) \ingroup qt-lighthouse-win */ -class QWindowsOleDropSource : public IDropSource +class QWindowsOleDropSource : public QWindowsComBase<IDropSource> { public: enum Mode { @@ -228,11 +228,6 @@ public: void createCursors(); - // IUnknown methods - STDMETHOD(QueryInterface)(REFIID riid, void ** ppvObj); - STDMETHOD_(ULONG,AddRef)(void); - STDMETHOD_(ULONG,Release)(void); - // IDropSource methods STDMETHOD(QueryContinueDrag)(BOOL fEscapePressed, DWORD grfKeyState); STDMETHOD(GiveFeedback)(DWORD dwEffect); @@ -257,7 +252,6 @@ private: ActionCursorMap m_cursors; QWindowsDragCursorWindow *m_touchDragWindow; - ULONG m_refs; #ifndef QT_NO_DEBUG_STREAM friend QDebug operator<<(QDebug, const QWindowsOleDropSource::CursorEntry &); #endif @@ -268,7 +262,6 @@ QWindowsOleDropSource::QWindowsOleDropSource(QWindowsDrag *drag) , m_drag(drag) , m_currentButtons(Qt::NoButton) , m_touchDragWindow(0) - , m_refs(1) { qCDebug(lcQpaMime) << __FUNCTION__ << m_mode; } @@ -373,38 +366,6 @@ void QWindowsOleDropSource::createCursors() #endif // !QT_NO_DEBUG_OUTPUT } -//--------------------------------------------------------------------- -// IUnknown Methods -//--------------------------------------------------------------------- - -STDMETHODIMP -QWindowsOleDropSource::QueryInterface(REFIID iid, void FAR* FAR* ppv) -{ - if (iid == IID_IUnknown || iid == IID_IDropSource) { - *ppv = this; - ++m_refs; - return NOERROR; - } - *ppv = NULL; - return ResultFromScode(E_NOINTERFACE); -} - -STDMETHODIMP_(ULONG) -QWindowsOleDropSource::AddRef(void) -{ - return ++m_refs; -} - -STDMETHODIMP_(ULONG) -QWindowsOleDropSource::Release(void) -{ - if (--m_refs == 0) { - delete this; - return 0; - } - return m_refs; -} - /*! \brief Check for cancel. */ @@ -509,34 +470,6 @@ QWindowsOleDropTarget::~QWindowsOleDropTarget() qCDebug(lcQpaMime) << __FUNCTION__ << this; } -STDMETHODIMP -QWindowsOleDropTarget::QueryInterface(REFIID iid, void FAR* FAR* ppv) -{ - if (iid == IID_IUnknown || iid == IID_IDropTarget) { - *ppv = this; - AddRef(); - return NOERROR; - } - *ppv = NULL; - return ResultFromScode(E_NOINTERFACE); -} - -STDMETHODIMP_(ULONG) -QWindowsOleDropTarget::AddRef(void) -{ - return ++m_refs; -} - -STDMETHODIMP_(ULONG) -QWindowsOleDropTarget::Release(void) -{ - if (--m_refs == 0) { - delete this; - return 0; - } - return m_refs; -} - void QWindowsOleDropTarget::handleDrag(QWindow *window, DWORD grfKeyState, const QPoint &point, LPDWORD pdwEffect) { diff --git a/src/plugins/platforms/windows/qwindowsdrag.h b/src/plugins/platforms/windows/qwindowsdrag.h index 983f3a67b4..2b4ca2dce1 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.h +++ b/src/plugins/platforms/windows/qwindowsdrag.h @@ -40,6 +40,7 @@ #ifndef QWINDOWSDRAG_H #define QWINDOWSDRAG_H +#include "qwindowscombase.h" #include "qwindowsinternalmimedata.h" #include <qpa/qplatformdrag.h> @@ -57,17 +58,12 @@ public: IDataObject *retrieveDataObject() const override; }; -class QWindowsOleDropTarget : public IDropTarget +class QWindowsOleDropTarget : public QWindowsComBase<IDropTarget> { public: explicit QWindowsOleDropTarget(QWindow *w); virtual ~QWindowsOleDropTarget(); - // IUnknown methods - STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppvObj); - STDMETHOD_(ULONG, AddRef)(void); - STDMETHOD_(ULONG, Release)(void); - // IDropTarget methods STDMETHOD(DragEnter)(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect); STDMETHOD(DragOver)(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect); @@ -77,7 +73,6 @@ public: private: void handleDrag(QWindow *window, DWORD grfKeyState, const QPoint &, LPDWORD pdwEffect); - ULONG m_refs = 1; QWindow *const m_window; QRect m_answerRect; QPoint m_lastPoint; @@ -91,8 +86,6 @@ public: QWindowsDrag(); virtual ~QWindowsDrag(); - QMimeData *platformDropData() override { return &m_dropData; } - Qt::DropAction drag(QDrag *drag) override; static QWindowsDrag *instance(); diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp index 751807e897..78368d87de 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -145,6 +145,10 @@ #define RESET_NOTIFICATION_STRATEGY_ARB 0x8256 #define LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#ifndef WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT +#define WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20A9 +#endif + QT_BEGIN_NAMESPACE QWindowsOpengl32DLL QOpenGLStaticContext::opengl32; @@ -489,7 +493,7 @@ static int choosePixelFormat(HDC hdc, const QWindowsOpenGLAdditionalFormat &additional, PIXELFORMATDESCRIPTOR *obtainedPfd) { - enum { attribSize =40 }; + enum { attribSize = 42 }; if ((additional.formatFlags & QWindowsGLRenderToPixmap) || !staticContext.hasExtensions()) return 0; @@ -570,7 +574,15 @@ static int choosePixelFormat(HDC hdc, iAttributes[i++] = WGL_SAMPLE_BUFFERS_ARB; iAttributes[i++] = FALSE; } - // If sample buffer request cannot be satisfied, reduce request. + // must be the last + bool srgbRequested = format.colorSpace() == QSurfaceFormat::sRGBColorSpace; + int srgbValuePosition = 0; + if (srgbRequested) { + srgbValuePosition = i; + iAttributes[i++] = WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT; + iAttributes[i++] = TRUE; + } + // If sample or sRGB request cannot be satisfied, reduce request. int pixelFormat = 0; uint numFormats = 0; while (true) { @@ -578,20 +590,25 @@ static int choosePixelFormat(HDC hdc, staticContext.wglChoosePixelFormatARB(hdc, iAttributes, 0, 1, &pixelFormat, &numFormats) && numFormats >= 1; - if (valid || !sampleBuffersRequested) - break; - if (iAttributes[samplesValuePosition] > 1) { - iAttributes[samplesValuePosition] /= 2; - } else if (iAttributes[samplesValuePosition] == 1) { - // Fallback in case it is unable to initialize with any - // samples to avoid falling back to the GDI path - // NB: The sample attributes needs to be at the end for this - // to work correctly - iAttributes[samplesValuePosition - 1] = FALSE; - iAttributes[samplesValuePosition] = 0; - iAttributes[samplesValuePosition + 1] = 0; - } else { + if (valid || (!sampleBuffersRequested && !srgbRequested)) break; + if (srgbRequested) { + iAttributes[srgbValuePosition] = 0; + srgbRequested = false; + } else if (sampleBuffersRequested) { + if (iAttributes[samplesValuePosition] > 1) { + iAttributes[samplesValuePosition] /= 2; + } else if (iAttributes[samplesValuePosition] == 1) { + // Fallback in case it is unable to initialize with any + // samples to avoid falling back to the GDI path + // NB: The sample attributes needs to be at the end for this + // to work correctly + iAttributes[samplesValuePosition - 1] = FALSE; + iAttributes[samplesValuePosition] = 0; + iAttributes[samplesValuePosition + 1] = 0; + } else { + break; + } } } // Verify if format is acceptable. Note that the returned @@ -628,7 +645,7 @@ static QSurfaceFormat HDC hdc, int pixelFormat, QWindowsOpenGLAdditionalFormat *additionalIn = 0) { - enum { attribSize =40 }; + enum { attribSize = 42 }; QSurfaceFormat result; result.setRenderableType(QSurfaceFormat::OpenGL); @@ -641,6 +658,7 @@ static QSurfaceFormat int i = 0; const bool hasSampleBuffers = testFlag(staticContext.extensions, QOpenGLStaticContext::SampleBuffers); + const bool hasSrgbSupport = testFlag(staticContext.extensions, QOpenGLStaticContext::sRGBCapableFramebuffer); iAttributes[i++] = WGL_DOUBLE_BUFFER_ARB; // 0 iAttributes[i++] = WGL_DEPTH_BITS_ARB; // 1 @@ -658,6 +676,9 @@ static QSurfaceFormat iAttributes[i++] = WGL_SAMPLE_BUFFERS_ARB; // 12 iAttributes[i++] = WGL_SAMPLES_ARB; // 13 } + if (hasSrgbSupport) + iAttributes[i++] = WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT; // 12 or 14 + if (!staticContext.wglGetPixelFormatAttribIVARB(hdc, pixelFormat, 0, i, iAttributes, iValues)) { qErrnoWarning("%s: wglGetPixelFormatAttribIVARB() failed for basic parameters.", __FUNCTION__); @@ -673,8 +694,14 @@ static QSurfaceFormat if (iValues[9]) result.setOption(QSurfaceFormat::StereoBuffers); - if (hasSampleBuffers) + if (hasSampleBuffers) { result.setSamples(iValues[13]); + if (hasSrgbSupport && iValues[14]) + result.setColorSpace(QSurfaceFormat::sRGBColorSpace); + } else { + if (hasSrgbSupport && iValues[12]) + result.setColorSpace(QSurfaceFormat::sRGBColorSpace); + } if (additionalIn) { if (iValues[7]) additionalIn->formatFlags |= QWindowsGLAccumBuffer; @@ -947,7 +974,8 @@ QOpenGLStaticContext::QOpenGLStaticContext() : wglChoosePixelFormatARB((WglChoosePixelFormatARB)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglChoosePixelFormatARB")), wglCreateContextAttribsARB((WglCreateContextAttribsARB)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglCreateContextAttribsARB")), wglSwapInternalExt((WglSwapInternalExt)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglSwapIntervalEXT")), - wglGetSwapInternalExt((WglGetSwapInternalExt)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetSwapIntervalEXT")) + wglGetSwapInternalExt((WglGetSwapInternalExt)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetSwapIntervalEXT")), + wglGetExtensionsStringARB((WglGetExtensionsStringARB)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetExtensionsStringARB")) { if (extensionNames.startsWith(SAMPLE_BUFFER_EXTENSION " ") || extensionNames.indexOf(" " SAMPLE_BUFFER_EXTENSION " ") != -1) @@ -1091,6 +1119,14 @@ QWindowsGLContext::QWindowsGLContext(QOpenGLStaticContext *staticContext, && !(QWindowsIntegration::instance()->options() & QWindowsIntegration::DisableArb); QWindowsOpenGLAdditionalFormat obtainedAdditional; if (tryExtensions) { + if (m_staticContext->wglGetExtensionsStringARB) { + const char *exts = m_staticContext->wglGetExtensionsStringARB(hdc); + if (exts) { + qCDebug(lcQpaGl) << __FUNCTION__ << "WGL extensions:" << exts; + if (strstr(exts, "WGL_EXT_framebuffer_sRGB")) + m_staticContext->extensions |= QOpenGLStaticContext::sRGBCapableFramebuffer; + } + } m_pixelFormat = ARB::choosePixelFormat(hdc, *m_staticContext, format, requestedAdditional, &m_obtainedPixelFormatDescriptor); diff --git a/src/plugins/platforms/windows/qwindowsglcontext.h b/src/plugins/platforms/windows/qwindowsglcontext.h index dfaa428520..2d5b94af0e 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.h +++ b/src/plugins/platforms/windows/qwindowsglcontext.h @@ -139,7 +139,8 @@ class QOpenGLStaticContext : public QWindowsStaticOpenGLContext public: enum Extensions { - SampleBuffers = 0x1 + SampleBuffers = 0x1, + sRGBCapableFramebuffer = 0x2 }; typedef bool @@ -160,6 +161,9 @@ public: typedef int (APIENTRY *WglGetSwapInternalExt)(void); + typedef const char * + (APIENTRY *WglGetExtensionsStringARB)(HDC); + bool hasExtensions() const { return wglGetPixelFormatAttribIVARB && wglChoosePixelFormatARB && wglCreateContextAttribsARB; } @@ -185,6 +189,7 @@ public: WglCreateContextAttribsARB wglCreateContextAttribsARB; WglSwapInternalExt wglSwapInternalExt; WglGetSwapInternalExt wglGetSwapInternalExt; + WglGetExtensionsStringARB wglGetExtensionsStringARB; static QWindowsOpengl32DLL opengl32; }; diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 316f93e3ac..6614c76a53 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -606,4 +606,11 @@ void QWindowsIntegration::beep() const MessageBeep(MB_OK); // For QApplication } +#if QT_CONFIG(vulkan) +QPlatformVulkanInstance *QWindowsIntegration::createPlatformVulkanInstance(QVulkanInstance *instance) const +{ + return new QWindowsVulkanInstance(instance); +} +#endif + QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h index 607203829f..fbdb341dab 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.h +++ b/src/plugins/platforms/windows/qwindowsintegration.h @@ -113,6 +113,10 @@ public: QPlatformSessionManager *createPlatformSessionManager(const QString &id, const QString &key) const override; #endif +#if QT_CONFIG(vulkan) + QPlatformVulkanInstance *createPlatformVulkanInstance(QVulkanInstance *instance) const override; +#endif + protected: virtual QWindowsWindow *createPlatformWindowHelper(QWindow *window, const QWindowsWindowData &) const; diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp index d750eef19d..dc8e97c886 100644 --- a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp +++ b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp @@ -64,7 +64,8 @@ enum ResourceType { HandleType, GlHandleType, GetDCType, - ReleaseDCType + ReleaseDCType, + VkSurface }; static int resourceType(const QByteArray &key) @@ -77,7 +78,8 @@ static int resourceType(const QByteArray &key) "handle", "glhandle", "getdc", - "releasedc" + "releasedc", + "vkSurface" }; const char ** const end = names + sizeof(names) / sizeof(names[0]); const char **result = std::find(names, end, key); @@ -112,6 +114,12 @@ void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resourc case QWindow::OpenGLSurface: case QWindow::OpenVGSurface: break; + case QWindow::VulkanSurface: +#if QT_CONFIG(vulkan) + if (type == VkSurface) + return bw->surface(nullptr, nullptr); // returns the address of the VkSurfaceKHR, not the value, as expected +#endif + break; } qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData()); return 0; diff --git a/src/plugins/platforms/windows/qwindowsole.cpp b/src/plugins/platforms/windows/qwindowsole.cpp index 9b71061aa5..0ceb0d82fa 100644 --- a/src/plugins/platforms/windows/qwindowsole.cpp +++ b/src/plugins/platforms/windows/qwindowsole.cpp @@ -99,39 +99,6 @@ DWORD QWindowsOleDataObject::reportedPerformedEffect() const return performedEffect; } -//--------------------------------------------------------------------- -// IUnknown Methods -//--------------------------------------------------------------------- - -STDMETHODIMP -QWindowsOleDataObject::QueryInterface(REFIID iid, void FAR* FAR* ppv) -{ - if (iid == IID_IUnknown || iid == IID_IDataObject) { - *ppv = this; - AddRef(); - return NOERROR; - } - *ppv = NULL; - return ResultFromScode(E_NOINTERFACE); -} - -STDMETHODIMP_(ULONG) -QWindowsOleDataObject::AddRef(void) -{ - return ++m_refs; -} - -STDMETHODIMP_(ULONG) -QWindowsOleDataObject::Release(void) -{ - if (--m_refs == 0) { - releaseQt(); - delete this; - return 0; - } - return m_refs; -} - STDMETHODIMP QWindowsOleDataObject::GetData(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium) { @@ -323,35 +290,6 @@ bool QWindowsOleEnumFmtEtc::isNull() const return m_isNull; } -// IUnknown methods -STDMETHODIMP -QWindowsOleEnumFmtEtc::QueryInterface(REFIID riid, void FAR* FAR* ppvObj) -{ - if (riid == IID_IUnknown || riid == IID_IEnumFORMATETC) { - *ppvObj = this; - AddRef(); - return NOERROR; - } - *ppvObj = NULL; - return ResultFromScode(E_NOINTERFACE); -} - -STDMETHODIMP_(ULONG) -QWindowsOleEnumFmtEtc::AddRef(void) -{ - return ++m_dwRefs; -} - -STDMETHODIMP_(ULONG) -QWindowsOleEnumFmtEtc::Release(void) -{ - if (--m_dwRefs == 0) { - delete this; - return 0; - } - return m_dwRefs; -} - // IEnumFORMATETC methods STDMETHODIMP QWindowsOleEnumFmtEtc::Next(ULONG celt, LPFORMATETC rgelt, ULONG FAR* pceltFetched) diff --git a/src/plugins/platforms/windows/qwindowsole.h b/src/plugins/platforms/windows/qwindowsole.h index 643011272b..fc58858f2c 100644 --- a/src/plugins/platforms/windows/qwindowsole.h +++ b/src/plugins/platforms/windows/qwindowsole.h @@ -40,6 +40,7 @@ #ifndef QWINDOWSOLE_H #define QWINDOWSOLE_H +#include "qwindowscombase.h" #include <QtCore/qt_windows.h> #include <QtCore/QMap> @@ -53,7 +54,7 @@ QT_BEGIN_NAMESPACE class QMimeData; class QWindow; -class QWindowsOleDataObject : public IDataObject +class QWindowsOleDataObject : public QWindowsComBase<IDataObject> { public: explicit QWindowsOleDataObject(QMimeData *mimeData); @@ -63,11 +64,6 @@ public: QMimeData *mimeData() const; DWORD reportedPerformedEffect() const; - // IUnknown methods - STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppvObj); - STDMETHOD_(ULONG,AddRef)(void); - STDMETHOD_(ULONG,Release)(void); - // IDataObject methods STDMETHOD(GetData)(LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium); STDMETHOD(GetDataHere)(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium); @@ -82,13 +78,12 @@ public: STDMETHOD(EnumDAdvise)(LPENUMSTATDATA FAR* ppenumAdvise); private: - ULONG m_refs = 1; QPointer<QMimeData> data; const int CF_PERFORMEDDROPEFFECT; DWORD performedEffect = DROPEFFECT_NONE; }; -class QWindowsOleEnumFmtEtc : public IEnumFORMATETC +class QWindowsOleEnumFmtEtc : public QWindowsComBase<IEnumFORMATETC> { public: explicit QWindowsOleEnumFmtEtc(const QVector<FORMATETC> &fmtetcs); @@ -97,11 +92,6 @@ public: bool isNull() const; - // IUnknown methods - STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppvObj); - STDMETHOD_(ULONG,AddRef)(void); - STDMETHOD_(ULONG,Release)(void); - // IEnumFORMATETC methods STDMETHOD(Next)(ULONG celt, LPFORMATETC rgelt, ULONG FAR* pceltFetched); STDMETHOD(Skip)(ULONG celt); @@ -111,7 +101,6 @@ public: private: bool copyFormatEtc(LPFORMATETC dest, const FORMATETC *src) const; - ULONG m_dwRefs = 1; ULONG m_nIndex = 0; QVector<LPFORMATETC> m_lpfmtetcs; bool m_isNull = false; diff --git a/src/plugins/platforms/windows/qwindowsvulkaninstance.cpp b/src/plugins/platforms/windows/qwindowsvulkaninstance.cpp new file mode 100644 index 0000000000..d81ee8ba29 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsvulkaninstance.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowsvulkaninstance.h" + +QT_BEGIN_NAMESPACE + +QWindowsVulkanInstance::QWindowsVulkanInstance(QVulkanInstance *instance) + : m_instance(instance), + m_getPhysDevPresSupport(nullptr), + m_createSurface(nullptr), + m_destroySurface(nullptr) +{ + if (qEnvironmentVariableIsSet("QT_VULKAN_LIB")) + m_lib.setFileName(QString::fromUtf8(qgetenv("QT_VULKAN_LIB"))); + else + m_lib.setFileName(QStringLiteral("vulkan-1")); + + if (!m_lib.load()) { + qWarning("Failed to load %s: %s", qPrintable(m_lib.fileName()), qPrintable(m_lib.errorString())); + return; + } + + init(&m_lib); +} + +void QWindowsVulkanInstance::createOrAdoptInstance() +{ + initInstance(m_instance, QByteArrayList() << QByteArrayLiteral("VK_KHR_win32_surface")); + + if (!m_vkInst) + return; + + m_getPhysDevPresSupport = reinterpret_cast<PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR>( + m_vkGetInstanceProcAddr(m_vkInst, "vkGetPhysicalDeviceWin32PresentationSupportKHR")); + if (!m_getPhysDevPresSupport) + qWarning("Failed to find vkGetPhysicalDeviceWin32PresentationSupportKHR"); +} + +QWindowsVulkanInstance::~QWindowsVulkanInstance() +{ +} + +bool QWindowsVulkanInstance::supportsPresent(VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + QWindow *window) +{ + if (!m_getPhysDevPresSupport || !m_getPhysDevSurfaceSupport) + return true; + + bool ok = m_getPhysDevPresSupport(physicalDevice, queueFamilyIndex); + + VkSurfaceKHR surface = QVulkanInstance::surfaceForWindow(window); + VkBool32 supported = false; + m_getPhysDevSurfaceSupport(physicalDevice, queueFamilyIndex, surface, &supported); + ok &= bool(supported); + + return ok; +} + +VkSurfaceKHR QWindowsVulkanInstance::createSurface(HWND win) +{ + VkSurfaceKHR surface = 0; + + if (!m_createSurface) { + m_createSurface = reinterpret_cast<PFN_vkCreateWin32SurfaceKHR>( + m_vkGetInstanceProcAddr(m_vkInst, "vkCreateWin32SurfaceKHR")); + } + if (!m_createSurface) { + qWarning("Failed to find vkCreateWin32SurfaceKHR"); + return surface; + } + if (!m_destroySurface) { + m_destroySurface = reinterpret_cast<PFN_vkDestroySurfaceKHR>( + m_vkGetInstanceProcAddr(m_vkInst, "vkDestroySurfaceKHR")); + } + if (!m_destroySurface) { + qWarning("Failed to find vkDestroySurfaceKHR"); + return surface; + } + + VkWin32SurfaceCreateInfoKHR surfaceInfo; + memset(&surfaceInfo, 0, sizeof(surfaceInfo)); + surfaceInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; + surfaceInfo.hinstance = GetModuleHandle(nullptr); + surfaceInfo.hwnd = win; + VkResult err = m_createSurface(m_vkInst, &surfaceInfo, nullptr, &surface); + if (err != VK_SUCCESS) + qWarning("Failed to create Vulkan surface: %d", err); + + return surface; +} + +void QWindowsVulkanInstance::destroySurface(VkSurfaceKHR surface) +{ + if (m_destroySurface && surface) + m_destroySurface(m_vkInst, surface, nullptr); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsvulkaninstance.h b/src/plugins/platforms/windows/qwindowsvulkaninstance.h new file mode 100644 index 0000000000..ca60ab7627 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsvulkaninstance.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSVULKANINSTANCE_H +#define QWINDOWSVULKANINSTANCE_H + +#if defined(VULKAN_H_) && !defined(VK_USE_PLATFORM_WIN32_KHR) +#error "vulkan.h included without Win32 WSI" +#endif + +#define VK_USE_PLATFORM_WIN32_KHR + +#include <QtVulkanSupport/private/qbasicvulkanplatforminstance_p.h> +#include <QLibrary> + +QT_BEGIN_NAMESPACE + +class QWindowsVulkanInstance : public QBasicPlatformVulkanInstance +{ +public: + QWindowsVulkanInstance(QVulkanInstance *instance); + ~QWindowsVulkanInstance(); + + void createOrAdoptInstance() override; + bool supportsPresent(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, QWindow *window) override; + + VkSurfaceKHR createSurface(HWND win); + void destroySurface(VkSurfaceKHR surface); + +private: + QVulkanInstance *m_instance; + QLibrary m_lib; + PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR m_getPhysDevPresSupport; + PFN_vkCreateWin32SurfaceKHR m_createSurface; + PFN_vkDestroySurfaceKHR m_destroySurface; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSVULKANINSTANCE_H diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 2875463e62..a3337509a7 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -67,6 +67,10 @@ #include <dwmapi.h> +#if QT_CONFIG(vulkan) +#include "qwindowsvulkaninstance.h" +#endif + QT_BEGIN_NAMESPACE enum { @@ -224,6 +228,23 @@ QDebug operator<<(QDebug d, const WINDOWPLACEMENT &wp) << ", rcNormalPosition=" << wp.rcNormalPosition; return d; } + +QDebug operator<<(QDebug d, const GUID &guid) +{ + QDebugStateSaver saver(d); + d.nospace(); + d << '{' << hex << uppercasedigits << qSetPadChar(QLatin1Char('0')) + << qSetFieldWidth(8) << guid.Data1 + << qSetFieldWidth(0) << '-' << qSetFieldWidth(4) + << guid.Data2 << qSetFieldWidth(0) << '-' << qSetFieldWidth(4) + << guid.Data3 << qSetFieldWidth(0) << '-' << qSetFieldWidth(4) + << qSetFieldWidth(2) << guid.Data4[0] << guid.Data4[1] + << qSetFieldWidth(0) << '-' << qSetFieldWidth(2); + for (int i = 2; i < 8; ++i) + d << guid.Data4[i]; + d << qSetFieldWidth(0) << '}'; + return d; +} #endif // !QT_NO_DEBUG_STREAM // QTBUG-43872, for windows that do not have WS_EX_TOOLWINDOW set, WINDOWPLACEMENT @@ -291,13 +312,15 @@ static QWindow::Visibility windowVisibility_sys(HWND hwnd) return QWindow::Windowed; } -static inline bool windowIsOpenGL(const QWindow *w) +static inline bool windowIsAccelerated(const QWindow *w) { switch (w->surfaceType()) { case QSurface::OpenGLSurface: return true; case QSurface::RasterGLSurface: return qt_window_private(const_cast<QWindow *>(w))->compositing; + case QSurface::VulkanSurface: + return true; default: return false; } @@ -358,11 +381,11 @@ bool QWindowsWindow::setWindowLayered(HWND hwnd, Qt::WindowFlags flags, bool has return needsLayered; } -static void setWindowOpacity(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, bool openGL, qreal level) +static void setWindowOpacity(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, bool accelerated, qreal level) { if (QWindowsWindow::setWindowLayered(hwnd, flags, hasAlpha, level)) { const BYTE alpha = BYTE(qRound(255.0 * level)); - if (hasAlpha && !openGL && (flags & Qt::FramelessWindowHint)) { + if (hasAlpha && !accelerated && (flags & Qt::FramelessWindowHint)) { // Non-GL windows with alpha: Use blend function to update. BLENDFUNCTION blend = {AC_SRC_OVER, 0, alpha, AC_SRC_ALPHA}; UpdateLayeredWindow(hwnd, NULL, NULL, NULL, NULL, NULL, 0, &blend, ULW_ALPHA); @@ -376,13 +399,13 @@ static void setWindowOpacity(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, bo static inline void updateGLWindowSettings(const QWindow *w, HWND hwnd, Qt::WindowFlags flags, qreal opacity) { - const bool isGL = windowIsOpenGL(w); + const bool isAccelerated = windowIsAccelerated(w); const bool hasAlpha = w->format().hasAlpha(); - if (isGL && hasAlpha) + if (isAccelerated && hasAlpha) applyBlurBehindWindow(hwnd); - setWindowOpacity(hwnd, flags, hasAlpha, isGL, opacity); + setWindowOpacity(hwnd, flags, hasAlpha, isAccelerated, opacity); } /*! @@ -1036,6 +1059,9 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) m_data(data), m_cursor(new CursorHandle), m_format(aWindow->requestedFormat()) +#if QT_CONFIG(vulkan) + , m_vkSurface(0) +#endif { // Clear the creation context as the window can be found in QWindowsContext's map. QWindowsContext::instance()->setWindowCreationContext(QSharedPointer<QWindowCreationContext>()); @@ -1051,10 +1077,14 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) setFlag(OpenGL_ES2); } #endif // QT_NO_OPENGL +#if QT_CONFIG(vulkan) + if (aWindow->surfaceType() == QSurface::VulkanSurface) + setFlag(VulkanSurface); +#endif updateDropSite(window()->isTopLevel()); registerTouchWindow(); - setWindowState(aWindow->windowState()); + setWindowState(aWindow->windowStates()); const qreal opacity = qt_window_private(aWindow)->opacity; if (!qFuzzyCompare(opacity, qreal(1.0))) setOpacity(opacity); @@ -1104,6 +1134,14 @@ void QWindowsWindow::destroyWindow() if (hasMouseCapture()) setMouseGrabEnabled(false); setDropSiteEnabled(false); +#if QT_CONFIG(vulkan) + if (m_vkSurface) { + QVulkanInstance *inst = window()->vulkanInstance(); + if (inst) + static_cast<QWindowsVulkanInstance *>(inst->handle())->destroySurface(m_vkSurface); + m_vkSurface = 0; + } +#endif #ifndef QT_NO_OPENGL if (m_surface) { if (QWindowsStaticOpenGLContext *staticOpenGLContext = QWindowsIntegration::staticOpenGLContext()) @@ -1321,20 +1359,48 @@ static inline bool testShowWithoutActivating(const QWindow *window) return showWithoutActivating.isValid() && showWithoutActivating.toBool(); } +static void setMinimizedGeometry(HWND hwnd, const QRect &r) +{ + WINDOWPLACEMENT windowPlacement; + windowPlacement.length = sizeof(WINDOWPLACEMENT); + if (GetWindowPlacement(hwnd, &windowPlacement)) { + windowPlacement.showCmd = SW_SHOWMINIMIZED; + windowPlacement.rcNormalPosition = RECTfromQRect(r); + SetWindowPlacement(hwnd, &windowPlacement); + } +} + +static void setRestoreMaximizedFlag(HWND hwnd, bool set = true) +{ + // Let Windows know that we need to restore as maximized + WINDOWPLACEMENT windowPlacement; + windowPlacement.length = sizeof(WINDOWPLACEMENT); + if (GetWindowPlacement(hwnd, &windowPlacement)) { + if (set) + windowPlacement.flags |= WPF_RESTORETOMAXIMIZED; + else + windowPlacement.flags &= ~WPF_RESTORETOMAXIMIZED; + SetWindowPlacement(hwnd, &windowPlacement); + } +} + // partially from QWidgetPrivate::show_sys() void QWindowsWindow::show_sys() const { int sm = SW_SHOWNORMAL; bool fakedMaximize = false; + bool restoreMaximize = false; const QWindow *w = window(); const Qt::WindowFlags flags = w->flags(); const Qt::WindowType type = w->type(); if (w->isTopLevel()) { - const Qt::WindowState state = w->windowState(); + const Qt::WindowStates state = w->windowStates(); if (state & Qt::WindowMinimized) { sm = SW_SHOWMINIMIZED; if (!isVisible()) sm = SW_SHOWMINNOACTIVE; + if (state & Qt::WindowMaximized) + restoreMaximize = true; } else { updateTransientParent(); if (state & Qt::WindowMaximized) { @@ -1355,7 +1421,7 @@ void QWindowsWindow::show_sys() const if (type == Qt::Popup || type == Qt::ToolTip || type == Qt::Tool || testShowWithoutActivating(w)) sm = SW_SHOWNOACTIVATE; - if (w->windowState() & Qt::WindowMaximized) + if (w->windowStates() & Qt::WindowMaximized) setFlag(WithinMaximize); // QTBUG-8361 ShowWindow(m_data.hwnd, sm); @@ -1368,6 +1434,8 @@ void QWindowsWindow::show_sys() const SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED); } + if (restoreMaximize) + setRestoreMaximizedFlag(m_data.hwnd); } void QWindowsWindow::setParent(const QPlatformWindow *newParent) @@ -1423,8 +1491,10 @@ void QWindowsWindow::handleHidden() void QWindowsWindow::handleCompositionSettingsChanged() { const QWindow *w = window(); - if (w->surfaceType() == QWindow::OpenGLSurface && w->format().hasAlpha()) + if ((w->surfaceType() == QWindow::OpenGLSurface || w->surfaceType() == QWindow::VulkanSurface) + && w->format().hasAlpha()) { applyBlurBehindWindow(handle()); + } } static QRect normalFrameGeometry(HWND hwnd) @@ -1441,7 +1511,8 @@ static QRect normalFrameGeometry(HWND hwnd) QRect QWindowsWindow::normalGeometry() const { // Check for fake 'fullscreen' mode. - const bool fakeFullScreen = m_savedFrameGeometry.isValid() && window()->windowState() == Qt::WindowFullScreen; + const bool fakeFullScreen = + m_savedFrameGeometry.isValid() && (window()->windowStates() & Qt::WindowFullScreen); const QRect frame = fakeFullScreen ? m_savedFrameGeometry : normalFrameGeometry(m_data.hwnd); const QMargins margins = fakeFullScreen ? QWindowsGeometryHint::frame(m_savedStyle, 0) : frameMargins(); return frame.isValid() ? frame.marginsRemoved(margins) : frame; @@ -1456,13 +1527,15 @@ void QWindowsWindow::setGeometry(const QRect &rectIn) const QMargins margins = frameMargins(); rect.moveTopLeft(rect.topLeft() + QPoint(margins.left(), margins.top())); } - if (m_windowState == Qt::WindowMinimized) + if (m_windowState & Qt::WindowMinimized) m_data.geometry = rect; // Otherwise set by handleGeometryChange() triggered by event. if (m_data.hwnd) { // A ResizeEvent with resulting geometry will be sent. If we cannot // achieve that size (for example, window title minimal constraint), // notify and warn. + setFlag(WithinSetGeometry); setGeometry_sys(rect); + clearFlag(WithinSetGeometry); if (m_data.geometry != rect) { qWarning("%s: Unable to set geometry %dx%d+%d+%d on %s/'%s'." " Resulting geometry: %dx%d+%d+%d " @@ -1499,18 +1572,21 @@ void QWindowsWindow::handleResized(int wParam) case SIZE_MAXSHOW: return; case SIZE_MINIMIZED: // QTBUG-53577, prevent state change events during programmatic state change - if (!testFlag(WithinSetStyle)) - handleWindowStateChange(Qt::WindowMinimized); + if (!testFlag(WithinSetStyle) && !testFlag(WithinSetGeometry)) + handleWindowStateChange(m_windowState | Qt::WindowMinimized); return; case SIZE_MAXIMIZED: - if (!testFlag(WithinSetStyle)) - handleWindowStateChange(Qt::WindowMaximized); + if (!testFlag(WithinSetStyle) && !testFlag(WithinSetGeometry)) + handleWindowStateChange(Qt::WindowMaximized | (isFullScreen_sys() ? Qt::WindowFullScreen + : Qt::WindowNoState)); handleGeometryChange(); break; case SIZE_RESTORED: - if (!testFlag(WithinSetStyle)) { + if (!testFlag(WithinSetStyle) && !testFlag(WithinSetGeometry)) { if (isFullScreen_sys()) - handleWindowStateChange(Qt::WindowFullScreen); + handleWindowStateChange( + Qt::WindowFullScreen + | (testFlag(MaximizeToFullScreen) ? Qt::WindowMaximized : Qt::WindowNoState)); else if (m_windowState != Qt::WindowNoState && !testFlag(MaximizeToFullScreen)) handleWindowStateChange(Qt::WindowNoState); } @@ -1640,8 +1716,11 @@ bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message, BeginPaint(hwnd, &ps); // Observed painting problems with Aero style disabled (QTBUG-7865). - if (Q_UNLIKELY(testFlag(OpenGLSurface) && testFlag(OpenGLDoubleBuffered) && !dwmIsCompositionEnabled())) + if (Q_UNLIKELY(!dwmIsCompositionEnabled()) + && ((testFlag(OpenGLSurface) && testFlag(OpenGLDoubleBuffered)) || testFlag(VulkanSurface))) + { SelectClipRgn(ps.hdc, NULL); + } // If the a window is obscured by another window (such as a child window) // we still need to send isExposed=true, for compatibility. @@ -1697,20 +1776,16 @@ QWindowsWindowData QWindowsWindow::setWindowFlags_sys(Qt::WindowFlags wt, return result; } -void QWindowsWindow::handleWindowStateChange(Qt::WindowState state) +void QWindowsWindow::handleWindowStateChange(Qt::WindowStates state) { qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() << "\n from " << m_windowState << " to " << state; m_windowState = state; QWindowSystemInterface::handleWindowStateChanged(window(), state); - switch (state) { - case Qt::WindowMinimized: + if (state & Qt::WindowMinimized) { handleHidden(); QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); // Tell QQuickWindow to stop rendering now. - break; - case Qt::WindowMaximized: - case Qt::WindowFullScreen: - case Qt::WindowNoState: { + } else { // QTBUG-17548: We send expose events when receiving WM_Paint, but for // layered windows and transient children, we won't receive any WM_Paint. QWindow *w = window(); @@ -1731,13 +1806,9 @@ void QWindowsWindow::handleWindowStateChange(Qt::WindowState state) if (exposeEventsSent && !QWindowsContext::instance()->asyncExpose()) QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); } - break; - default: - break; - } } -void QWindowsWindow::setWindowState(Qt::WindowState state) +void QWindowsWindow::setWindowState(Qt::WindowStates state) { if (m_data.hwnd) { setWindowState_sys(state); @@ -1766,18 +1837,19 @@ bool QWindowsWindow::isFullScreen_sys() const to ShowWindow. */ -void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) +void QWindowsWindow::setWindowState_sys(Qt::WindowStates newState) { - const Qt::WindowState oldState = m_windowState; + const Qt::WindowStates oldState = m_windowState; if (oldState == newState) return; qCDebug(lcQpaWindows) << '>' << __FUNCTION__ << this << window() << " from " << oldState << " to " << newState; const bool visible = isVisible(); + auto stateChange = oldState ^ newState; - if ((oldState == Qt::WindowFullScreen) != (newState == Qt::WindowFullScreen)) { - if (newState == Qt::WindowFullScreen) { + if (stateChange & Qt::WindowFullScreen) { + if (newState & Qt::WindowFullScreen) { #ifndef Q_FLATTEN_EXPOSE UINT newStyle = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP; #else @@ -1788,7 +1860,7 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) // Window state but emulated by changing geometry and style. if (!m_savedStyle) { m_savedStyle = style(); - if (oldState == Qt::WindowMinimized || oldState == Qt::WindowMaximized) { + if ((oldState & Qt::WindowMinimized) || (oldState & Qt::WindowMaximized)) { const QRect nf = normalFrameGeometry(m_data.hwnd); if (nf.isValid()) m_savedFrameGeometry = nf; @@ -1796,6 +1868,8 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) m_savedFrameGeometry = frameGeometry_sys(); } } + if (newState & Qt::WindowMaximized) + setFlag(MaximizeToFullScreen); if (m_savedStyle & WS_SYSMENU) newStyle |= WS_SYSMENU; if (visible) @@ -1809,15 +1883,23 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) if (!screen) screen = QGuiApplication::primaryScreen(); const QRect r = screen ? QHighDpi::toNativePixels(screen->geometry(), window()) : m_savedFrameGeometry; - const UINT swpf = SWP_FRAMECHANGED | SWP_NOACTIVATE; - const bool wasSync = testFlag(SynchronousGeometryChangeEvent); - setFlag(SynchronousGeometryChangeEvent); - SetWindowPos(m_data.hwnd, HWND_TOP, r.left(), r.top(), r.width(), r.height(), swpf); - if (!wasSync) - clearFlag(SynchronousGeometryChangeEvent); - QWindowSystemInterface::handleGeometryChange(window(), r); - QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); - } else if (newState != Qt::WindowMinimized) { + + if (newState & Qt::WindowMinimized) { + setMinimizedGeometry(m_data.hwnd, r); + if (stateChange & Qt::WindowMaximized) + setRestoreMaximizedFlag(m_data.hwnd, newState & Qt::WindowMaximized); + } else { + const UINT swpf = SWP_FRAMECHANGED | SWP_NOACTIVATE; + const bool wasSync = testFlag(SynchronousGeometryChangeEvent); + setFlag(SynchronousGeometryChangeEvent); + SetWindowPos(m_data.hwnd, HWND_TOP, r.left(), r.top(), r.width(), r.height(), swpf); + if (!wasSync) + clearFlag(SynchronousGeometryChangeEvent); + clearFlag(MaximizeToFullScreen); + QWindowSystemInterface::handleGeometryChange(window(), r); + QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); + } + } else { // Restore saved state. unsigned newStyle = m_savedStyle ? m_savedStyle : style(); if (visible) @@ -1831,43 +1913,58 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) if (!screen->geometry().intersects(m_savedFrameGeometry)) m_savedFrameGeometry.moveTo(screen->geometry().topLeft()); - UINT swpf = SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE; - if (!m_savedFrameGeometry.isValid()) - swpf |= SWP_NOSIZE | SWP_NOMOVE; - const bool wasSync = testFlag(SynchronousGeometryChangeEvent); - setFlag(SynchronousGeometryChangeEvent); - // After maximized/fullscreen; the window can be in a maximized state. Clear - // it before applying the normal geometry. - if (windowVisibility_sys(m_data.hwnd) == QWindow::Maximized) - ShowWindow(m_data.hwnd, SW_SHOWNOACTIVATE); - SetWindowPos(m_data.hwnd, 0, m_savedFrameGeometry.x(), m_savedFrameGeometry.y(), - m_savedFrameGeometry.width(), m_savedFrameGeometry.height(), swpf); - if (!wasSync) - clearFlag(SynchronousGeometryChangeEvent); - // preserve maximized state - if (visible) { - setFlag(WithinMaximize); - ShowWindow(m_data.hwnd, (newState == Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNA); - clearFlag(WithinMaximize); + if (newState & Qt::WindowMinimized) { + setMinimizedGeometry(m_data.hwnd, m_savedFrameGeometry); + if (stateChange & Qt::WindowMaximized) + setRestoreMaximizedFlag(m_data.hwnd, newState & Qt::WindowMaximized); + } else { + UINT swpf = SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE; + if (!m_savedFrameGeometry.isValid()) + swpf |= SWP_NOSIZE | SWP_NOMOVE; + const bool wasSync = testFlag(SynchronousGeometryChangeEvent); + setFlag(SynchronousGeometryChangeEvent); + // After maximized/fullscreen; the window can be in a maximized state. Clear + // it before applying the normal geometry. + if (windowVisibility_sys(m_data.hwnd) == QWindow::Maximized) + ShowWindow(m_data.hwnd, SW_SHOWNOACTIVATE); + SetWindowPos(m_data.hwnd, 0, m_savedFrameGeometry.x(), m_savedFrameGeometry.y(), + m_savedFrameGeometry.width(), m_savedFrameGeometry.height(), swpf); + if (!wasSync) + clearFlag(SynchronousGeometryChangeEvent); + // preserve maximized state + if (visible) { + setFlag(WithinMaximize); + ShowWindow(m_data.hwnd, + (newState & Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNA); + clearFlag(WithinMaximize); + } } m_savedStyle = 0; m_savedFrameGeometry = QRect(); } - } else if ((oldState == Qt::WindowMaximized) != (newState == Qt::WindowMaximized)) { - if (visible && !(newState == Qt::WindowMinimized)) { + } else if ((oldState & Qt::WindowMaximized) != (newState & Qt::WindowMaximized)) { + if (visible && !(newState & Qt::WindowMinimized)) { setFlag(WithinMaximize); - if (newState == Qt::WindowFullScreen) + if (newState & Qt::WindowFullScreen) setFlag(MaximizeToFullScreen); - ShowWindow(m_data.hwnd, (newState == Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNOACTIVATE); + ShowWindow(m_data.hwnd, + (newState & Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNOACTIVATE); clearFlag(WithinMaximize); clearFlag(MaximizeToFullScreen); + } else if (visible && (oldState & newState & Qt::WindowMinimized)) { + // change of the maximized state while keeping minimized + setRestoreMaximizedFlag(m_data.hwnd, newState & Qt::WindowMaximized); } } - if ((oldState == Qt::WindowMinimized) != (newState == Qt::WindowMinimized)) { - if (visible) - ShowWindow(m_data.hwnd, (newState == Qt::WindowMinimized) ? SW_MINIMIZE : - (newState == Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNORMAL); + if (stateChange & Qt::WindowMinimized) { + if (visible) { + ShowWindow(m_data.hwnd, + (newState & Qt::WindowMinimized) ? SW_MINIMIZE : + (newState & Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNORMAL); + if ((newState & Qt::WindowMinimized) && (stateChange & Qt::WindowMaximized)) + setRestoreMaximizedFlag(m_data.hwnd, newState & Qt::WindowMaximized); + } } qCDebug(lcQpaWindows) << '<' << __FUNCTION__ << this << window() << newState; } @@ -1959,7 +2056,7 @@ void QWindowsWindow::setOpacity(qreal level) m_opacity = level; if (m_data.hwnd) setWindowOpacity(m_data.hwnd, m_data.flags, - window()->format().hasAlpha(), testFlag(OpenGLSurface), + window()->format().hasAlpha(), testFlag(OpenGLSurface) || testFlag(VulkanSurface), level); } } @@ -2128,7 +2225,7 @@ void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const hint.applyToMinMaxInfo(m_data.hwnd, mmi); } - if ((testFlag(WithinMaximize) || (window()->windowState() == Qt::WindowMinimized)) + if ((testFlag(WithinMaximize) || (window()->windowStates() & Qt::WindowMinimized)) && (m_data.flags & Qt::FramelessWindowHint)) { // This block fixes QTBUG-8361: Frameless windows shouldn't cover the // taskbar when maximized @@ -2158,7 +2255,7 @@ bool QWindowsWindow::handleNonClientHitTest(const QPoint &globalPos, LRESULT *re // QTBUG-32663, suppress resize cursor for fixed size windows. const QWindow *w = window(); if (!w->isTopLevel() // Task 105852, minimized windows need to respond to user input. - || (m_windowState != Qt::WindowNoState && m_windowState != Qt::WindowActive) + || !(m_windowState & ~Qt::WindowActive) || (m_data.flags & Qt::FramelessWindowHint)) { return false; } @@ -2377,11 +2474,27 @@ void QWindowsWindow::setCustomMargins(const QMargins &newCustomMargins) void *QWindowsWindow::surface(void *nativeConfig, int *err) { -#ifdef QT_NO_OPENGL +#if QT_CONFIG(vulkan) + Q_UNUSED(nativeConfig); + Q_UNUSED(err); + if (window()->surfaceType() == QSurface::VulkanSurface) { + if (!m_vkSurface) { + QVulkanInstance *inst = window()->vulkanInstance(); + if (inst) + m_vkSurface = static_cast<QWindowsVulkanInstance *>(inst->handle())->createSurface(handle()); + else + qWarning("Attempted to create Vulkan surface without an instance; was QWindow::setVulkanInstance() called?"); + } + // Different semantics for VkSurfaces: the return value is the address, + // not the value, given that this is a 64-bit handle even on x86. + return &m_vkSurface; + } +#elif defined(QT_NO_OPENGL) Q_UNUSED(err) Q_UNUSED(nativeConfig) return 0; -#else +#endif +#ifndef QT_NO_OPENGL if (!m_surface) { if (QWindowsStaticOpenGLContext *staticOpenGLContext = QWindowsIntegration::staticOpenGLContext()) m_surface = staticOpenGLContext->createWindowSurface(m_data.hwnd, nativeConfig, err); @@ -2393,6 +2506,14 @@ void *QWindowsWindow::surface(void *nativeConfig, int *err) void QWindowsWindow::invalidateSurface() { +#if QT_CONFIG(vulkan) + if (m_vkSurface) { + QVulkanInstance *inst = window()->vulkanInstance(); + if (inst) + static_cast<QWindowsVulkanInstance *>(inst->handle())->destroySurface(m_vkSurface); + m_vkSurface = 0; + } +#endif #ifndef QT_NO_OPENGL if (m_surface) { if (QWindowsStaticOpenGLContext *staticOpenGLContext = QWindowsIntegration::staticOpenGLContext()) diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index e541b110a6..46236c10b5 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -46,6 +46,10 @@ #include <qpa/qplatformwindow.h> #include <QtPlatformHeaders/qwindowswindowfunctions.h> +#if QT_CONFIG(vulkan) +#include "qwindowsvulkaninstance.h" +#endif + QT_BEGIN_NAMESPACE class QWindowsOleDropTarget; @@ -188,6 +192,7 @@ public: { AutoMouseCapture = 0x1, //! Automatic mouse capture on button press. WithinSetParent = 0x2, + WithinSetGeometry = 0x8, OpenGLSurface = 0x10, OpenGL_ES2 = 0x20, OpenGLDoubleBuffered = 0x40, @@ -208,6 +213,7 @@ public: Compositing = 0x200000, HasBorderInFullScreen = 0x400000, WithinDpiChanged = 0x800000, + VulkanSurface = 0x1000000 }; QWindowsWindow(QWindow *window, const QWindowsWindowData &data); @@ -230,7 +236,7 @@ public: QPoint mapFromGlobal(const QPoint &pos) const override; void setWindowFlags(Qt::WindowFlags flags) override; - void setWindowState(Qt::WindowState state) override; + void setWindowState(Qt::WindowStates state) override; void setParent(const QPlatformWindow *window) override; @@ -323,7 +329,7 @@ private: inline void show_sys() const; inline QWindowsWindowData setWindowFlags_sys(Qt::WindowFlags wt, unsigned flags = 0) const; inline bool isFullScreen_sys() const; - inline void setWindowState_sys(Qt::WindowState newState); + inline void setWindowState_sys(Qt::WindowStates newState); inline void setParent_sys(const QPlatformWindow *parent); inline void updateTransientParent() const; void destroyWindow(); @@ -331,14 +337,14 @@ private: void setDropSiteEnabled(bool enabled); void updateDropSite(bool topLevel); void handleGeometryChange(); - void handleWindowStateChange(Qt::WindowState state); + void handleWindowStateChange(Qt::WindowStates state); inline void destroyIcon(); void fireExpose(const QRegion ®ion, bool force=false); mutable QWindowsWindowData m_data; mutable unsigned m_flags = WithinCreate; HDC m_hdc = 0; - Qt::WindowState m_windowState = Qt::WindowNoState; + Qt::WindowStates m_windowState = Qt::WindowNoState; qreal m_opacity = 1; #ifndef QT_NO_CURSOR CursorHandlePtr m_cursor; @@ -350,6 +356,11 @@ private: HICON m_iconSmall = 0; HICON m_iconBig = 0; void *m_surface = nullptr; + +#if QT_CONFIG(vulkan) + // note: intentionally not using void * in order to avoid breaking x86 + VkSurfaceKHR m_vkSurface = 0; +#endif }; #ifndef QT_NO_DEBUG_STREAM @@ -359,6 +370,7 @@ QDebug operator<<(QDebug d, const MINMAXINFO &i); QDebug operator<<(QDebug d, const NCCALCSIZE_PARAMS &p); QDebug operator<<(QDebug d, const WINDOWPLACEMENT &); QDebug operator<<(QDebug d, const WINDOWPOS &); +QDebug operator<<(QDebug d, const GUID &guid); #endif // !QT_NO_DEBUG_STREAM // ---------- QWindowsGeometryHint inline functions. diff --git a/src/plugins/platforms/windows/windows.pri b/src/plugins/platforms/windows/windows.pri index 7d3ecc8aa2..7694824d20 100644 --- a/src/plugins/platforms/windows/windows.pri +++ b/src/plugins/platforms/windows/windows.pri @@ -29,6 +29,7 @@ SOURCES += \ $$PWD/qwin10helpers.cpp HEADERS += \ + $$PWD/qwindowscombase.h \ $$PWD/qwindowswindow.h \ $$PWD/qwindowsintegration.h \ $$PWD/qwindowscontext.h \ @@ -67,6 +68,11 @@ qtConfig(dynamicgl) { HEADERS += $$PWD/qwindowseglcontext.h } +qtConfig(vulkan) { + SOURCES += $$PWD/qwindowsvulkaninstance.cpp + HEADERS += $$PWD/qwindowsvulkaninstance.h +} + !contains( DEFINES, QT_NO_CLIPBOARD ) { SOURCES += $$PWD/qwindowsclipboard.cpp HEADERS += $$PWD/qwindowsclipboard.h diff --git a/src/plugins/platforms/windows/windows.pro b/src/plugins/platforms/windows/windows.pro index 23168c10dc..4d788d91f8 100644 --- a/src/plugins/platforms/windows/windows.pro +++ b/src/plugins/platforms/windows/windows.pro @@ -5,6 +5,8 @@ QT += \ eventdispatcher_support-private accessibility_support-private \ fontdatabase_support-private theme_support-private +qtConfig(vulkan): QT += vulkan_support-private + LIBS += -lgdi32 -ldwmapi include(windows.pri) |