summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/windows
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/windows')
-rw-r--r--src/plugins/platforms/windows/accessible/accessible.pri15
-rw-r--r--src/plugins/platforms/windows/accessible/iaccessible2.cpp192
-rw-r--r--src/plugins/platforms/windows/accessible/iaccessible2.h49
-rw-r--r--src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp12
-rw-r--r--src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp140
-rw-r--r--src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h39
-rw-r--r--src/plugins/platforms/windows/qtwindowsglobal.h8
-rw-r--r--src/plugins/platforms/windows/qwindowscombase.h112
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp101
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.h8
-rw-r--r--src/plugins/platforms/windows/qwindowscursor.cpp30
-rw-r--r--src/plugins/platforms/windows/qwindowscursor.h7
-rw-r--r--src/plugins/platforms/windows/qwindowsdialoghelpers.cpp40
-rw-r--r--src/plugins/platforms/windows/qwindowsdrag.cpp73
-rw-r--r--src/plugins/platforms/windows/qwindowsdrag.h11
-rw-r--r--src/plugins/platforms/windows/qwindowsdropdataobject.cpp98
-rw-r--r--src/plugins/platforms/windows/qwindowsdropdataobject.h63
-rw-r--r--src/plugins/platforms/windows/qwindowsglcontext.cpp72
-rw-r--r--src/plugins/platforms/windows/qwindowsglcontext.h7
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.cpp30
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.h8
-rw-r--r--src/plugins/platforms/windows/qwindowskeymapper.cpp6
-rw-r--r--src/plugins/platforms/windows/qwindowsmenu.cpp962
-rw-r--r--src/plugins/platforms/windows/qwindowsmenu.h243
-rw-r--r--src/plugins/platforms/windows/qwindowsmime.cpp18
-rw-r--r--src/plugins/platforms/windows/qwindowsmousehandler.cpp7
-rw-r--r--src/plugins/platforms/windows/qwindowsnativeinterface.cpp12
-rw-r--r--src/plugins/platforms/windows/qwindowsole.cpp62
-rw-r--r--src/plugins/platforms/windows/qwindowsole.h17
-rw-r--r--src/plugins/platforms/windows/qwindowssystemtrayicon.cpp443
-rw-r--r--src/plugins/platforms/windows/qwindowssystemtrayicon.h103
-rw-r--r--src/plugins/platforms/windows/qwindowstabletsupport.cpp12
-rw-r--r--src/plugins/platforms/windows/qwindowstheme.cpp74
-rw-r--r--src/plugins/platforms/windows/qwindowstheme.h10
-rw-r--r--src/plugins/platforms/windows/qwindowsvulkaninstance.cpp136
-rw-r--r--src/plugins/platforms/windows/qwindowsvulkaninstance.h76
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp324
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.h38
-rw-r--r--src/plugins/platforms/windows/windows.pri15
-rw-r--r--src/plugins/platforms/windows/windows.pro1
40 files changed, 3026 insertions, 648 deletions
diff --git a/src/plugins/platforms/windows/accessible/accessible.pri b/src/plugins/platforms/windows/accessible/accessible.pri
index 0e3aacc558..557bdfe307 100644
--- a/src/plugins/platforms/windows/accessible/accessible.pri
+++ b/src/plugins/platforms/windows/accessible/accessible.pri
@@ -6,13 +6,14 @@ HEADERS += \
$$PWD/qwindowsaccessibility.h \
$$PWD/comutils.h
-SOURCES += $$PWD/qwindowsmsaaaccessible.cpp
-HEADERS += $$PWD/qwindowsmsaaaccessible.h
+SOURCES += \
+ $$PWD/qwindowsmsaaaccessible.cpp \
+ $$PWD/iaccessible2.cpp
+
+HEADERS += \
+ $$PWD/qwindowsmsaaaccessible.h \
+ $$PWD/iaccessible2.h
-!mingw: {
- SOURCES += $$PWD/iaccessible2.cpp
- HEADERS += $$PWD/iaccessible2.h
- include(../../../../3rdparty/iaccessible2/iaccessible2.pri)
-}
+include(../../../../3rdparty/iaccessible2/iaccessible2.pri)
mingw: LIBS *= -luuid
diff --git a/src/plugins/platforms/windows/accessible/iaccessible2.cpp b/src/plugins/platforms/windows/accessible/iaccessible2.cpp
index f9e8231843..75af65b5ab 100644
--- a/src/plugins/platforms/windows/accessible/iaccessible2.cpp
+++ b/src/plugins/platforms/windows/accessible/iaccessible2.cpp
@@ -36,7 +36,7 @@
** $QT_END_LICENSE$
**
****************************************************************************/
-#include <QtCore/QtConfig>
+#include <QtCore/qglobal.h>
#ifndef QT_NO_ACCESSIBILITY
#include "iaccessible2.h"
@@ -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..d987016e15 100644
--- a/src/plugins/platforms/windows/accessible/iaccessible2.h
+++ b/src/plugins/platforms/windows/accessible/iaccessible2.h
@@ -39,9 +39,10 @@
#ifndef IACCESSIBLE2_H
#define IACCESSIBLE2_H
-#include <QtCore/QtConfig>
+#include <QtCore/qglobal.h>
#ifndef QT_NO_ACCESSIBILITY
+#include "qwindowscombase.h"
#include "qwindowsmsaaaccessible.h"
#include "comutils.h"
@@ -51,6 +52,13 @@
QT_BEGIN_NAMESPACE
+#ifdef Q_CC_MINGW
+QT_WARNING_DISABLE_GCC("-Wunused-function") // MinGW 7.X claims it is unused
+// MinGW's __uuidof operator does not work for the Accessible2 interfaces
+template <>
+IID qUuidOf<IAccessibleComponent>() { return IID_IAccessibleComponent; }
+#endif // Q_CC_MINGW
+
class QWindowsIA2Accessible : public QWindowsMsaaAccessible,
public IAccessibleAction,
public IAccessibleComponent,
@@ -249,7 +257,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 +265,31 @@ private:
/**************************************************************\
* AccessibleApplication *
**************************************************************/
-class AccessibleApplication : public IAccessibleApplication
+
+#ifdef Q_CC_MINGW
+// MinGW's __uuidof operator does not work for the IAccessible2 interfaces
+template <>
+IID qUuidOf<IAccessibleApplication>() { return IID_IAccessibleApplication; }
+
+template <>
+IID qUuidOf<IAccessible2>() { return IID_IAccessible2; }
+
+template <>
+IID qUuidOf<IAccessibleRelation>() { return IID_IAccessibleRelation; }
+#endif // Q_CC_MINGW
+
+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 +297,10 @@ private:
/**************************************************************\
* AccessibleRelation *
**************************************************************/
-class AccessibleRelation : public IAccessibleRelation
+
+
+
+class AccessibleRelation : public QWindowsComBase<IAccessibleRelation>
{
public:
AccessibleRelation(const QList<QAccessibleInterface *> &targets,
@@ -295,11 +308,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 +349,6 @@ private:
QList<QAccessibleInterface *> m_targets;
QAccessible::Relation m_relation;
- ULONG m_ref;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp
index aed9c94003..d48cb9674f 100644
--- a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp
+++ b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp
@@ -37,7 +37,7 @@
**
****************************************************************************/
-#include <QtCore/QtConfig>
+#include <QtCore/qglobal.h>
#ifndef QT_NO_ACCESSIBILITY
@@ -56,11 +56,7 @@
#include <QtFontDatabaseSupport/private/qwindowsfontdatabase_p.h> // registry helper
#include "qwindowsaccessibility.h"
-#ifdef Q_CC_MINGW
-# include "qwindowsmsaaaccessible.h"
-#else
-# include "iaccessible2.h"
-#endif
+#include "iaccessible2.h"
#include "comutils.h"
#include <oleacc.h>
@@ -198,11 +194,7 @@ IAccessible *QWindowsAccessibility::wrap(QAccessibleInterface *acc)
if (!QAccessible::uniqueId(acc))
QAccessible::registerAccessibleInterface(acc);
-# ifdef Q_CC_MINGW
- QWindowsMsaaAccessible *wacc = new QWindowsMsaaAccessible(acc);
-# else
QWindowsIA2Accessible *wacc = new QWindowsIA2Accessible(acc);
-# endif
IAccessible *iacc = 0;
wacc->QueryInterface(IID_IAccessible, reinterpret_cast<void **>(&iacc));
return iacc;
diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp
index 25b1577772..fe2b9335cb 100644
--- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp
+++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp
@@ -37,11 +37,12 @@
**
****************************************************************************/
-#include <QtCore/QtConfig>
+#include <QtCore/qglobal.h>
#ifndef QT_NO_ACCESSIBILITY
#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<IAccessible2>(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,64 @@ 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";
+ 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";
+ 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..5380fc2411 100644
--- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h
+++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h
@@ -39,21 +39,14 @@
#ifndef QWINDOWSMSAAACCESSIBLE_H
#define QWINDOWSMSAAACCESSIBLE_H
-#include <QtCore/QtConfig>
-#ifndef QT_NO_ACCESSIBILITY
#include <QtCore/qglobal.h>
+#ifndef QT_NO_ACCESSIBILITY
#include <QtCore/qt_windows.h>
#include <QtCore/qsharedpointer.h>
#include <QtGui/qaccessible.h>
-#ifndef Q_CC_MINGW
-# include <oleacc.h>
-# include "ia2_api_all.h" // IAccessible2 inherits from IAccessible
-#else
- // MinGW
-# include <basetyps.h>
-# include <oleacc.h>
-#endif
+#include <oleacc.h>
+#include "ia2_api_all.h" // IAccessible2 inherits from IAccessible
QT_BEGIN_NAMESPACE
@@ -69,16 +62,26 @@ 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
-#else
- IAccessible2
-#endif
- , public IOleWindow
+
+class QWindowsMsaaAccessible : public IAccessible2, public IOleWindow
{
public:
QWindowsMsaaAccessible(QAccessibleInterface *a)
@@ -132,8 +135,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/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h
index d2e1309280..c8bdc1c93e 100644
--- a/src/plugins/platforms/windows/qtwindowsglobal.h
+++ b/src/plugins/platforms/windows/qtwindowsglobal.h
@@ -123,6 +123,9 @@ enum WindowsEventType // Simplify event types
EndSessionApplicationEvent = ApplicationEventFlag + 5,
AppCommandEvent = ApplicationEventFlag + 6,
DeviceChangeEvent = ApplicationEventFlag + 7,
+ MenuAboutToShowEvent = ApplicationEventFlag + 8,
+ AcceleratorCommandEvent = ApplicationEventFlag + 9,
+ MenuCommandEvent = ApplicationEventFlag + 10,
InputMethodStartCompositionEvent = InputMethodEventFlag + 1,
InputMethodCompositionEvent = InputMethodEventFlag + 2,
InputMethodEndCompositionEvent = InputMethodEventFlag + 3,
@@ -274,6 +277,11 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI
return QtWindows::GestureEvent;
case WM_DEVICECHANGE:
return QtWindows::DeviceChangeEvent;
+ case WM_INITMENU:
+ case WM_INITMENUPOPUP:
+ return QtWindows::MenuAboutToShowEvent;
+ case WM_COMMAND:
+ return HIWORD(wParamIn) ? QtWindows::AcceleratorCommandEvent : QtWindows::MenuCommandEvent;
case WM_DPICHANGED:
return QtWindows::DpiChangedEvent;
case WM_ENTERSIZEMOVE:
diff --git a/src/plugins/platforms/windows/qwindowscombase.h b/src/plugins/platforms/windows/qwindowscombase.h
new file mode 100644
index 0000000000..5e51b6b7b7
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowscombase.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** 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
+
+// The __uuidof operator of MinGW does not work for all interfaces (for example,
+// IAccessible2). Specializations of this function can be provides to work
+// around this.
+template <class DesiredInterface>
+static IID qUuidOf() { return __uuidof(DesiredInterface); }
+
+// Helper for implementing IUnknown::QueryInterface.
+template <class DesiredInterface, class Derived>
+bool qWindowsComQueryInterface(Derived *d, REFIID id, LPVOID *iface)
+{
+ if (id == qUuidOf<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/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index cda6c99ad0..9912e03cb9 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -44,6 +44,7 @@
#include "qwindowskeymapper.h"
#include "qwindowsmousehandler.h"
#include "qtwindowsglobal.h"
+#include "qwindowsmenu.h"
#include "qwindowsmime.h"
#include "qwindowsinputcontext.h"
#if QT_CONFIG(tabletevent)
@@ -94,8 +95,10 @@ Q_LOGGING_CATEGORY(lcQpaGl, "qt.qpa.gl")
Q_LOGGING_CATEGORY(lcQpaMime, "qt.qpa.mime")
Q_LOGGING_CATEGORY(lcQpaInputMethods, "qt.qpa.input.methods")
Q_LOGGING_CATEGORY(lcQpaDialogs, "qt.qpa.dialogs")
+Q_LOGGING_CATEGORY(lcQpaMenus, "qt.qpa.menus")
Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
Q_LOGGING_CATEGORY(lcQpaAccessibility, "qt.qpa.accessibility")
+Q_LOGGING_CATEGORY(lcQpaTrayIcon, "qt.qpa.trayicon")
int QWindowsContext::verbose = 0;
@@ -126,11 +129,19 @@ static inline bool useRTL_Extensions()
}
#if QT_CONFIG(sessionmanager)
-static inline QWindowsSessionManager *platformSessionManager() {
+static inline QWindowsSessionManager *platformSessionManager()
+{
QGuiApplicationPrivate *guiPrivate = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(qApp));
QSessionManagerPrivate *managerPrivate = static_cast<QSessionManagerPrivate*>(QObjectPrivate::get(guiPrivate->session_manager));
return static_cast<QWindowsSessionManager *>(managerPrivate->platformSessionManager);
}
+
+static inline bool sessionManagerInteractionBlocked()
+{
+ return platformSessionManager()->isInteractionBlocked();
+}
+#else // QT_CONFIG(sessionmanager)
+static inline bool sessionManagerInteractionBlocked() { return false; }
#endif
static inline int windowDpiAwareness(HWND hwnd)
@@ -397,9 +408,11 @@ QList<int> QWindowsContext::possibleKeys(const QKeyEvent *e) const
return d->m_keyMapper.possibleKeys(e);
}
-void QWindowsContext::setWindowCreationContext(const QSharedPointer<QWindowCreationContext> &ctx)
+QSharedPointer<QWindowCreationContext> QWindowsContext::setWindowCreationContext(const QSharedPointer<QWindowCreationContext> &ctx)
{
+ const QSharedPointer<QWindowCreationContext> old = d->m_creationContext;
d->m_creationContext = ctx;
+ return old;
}
QSharedPointer<QWindowCreationContext> QWindowsContext::windowCreationContext() const
@@ -597,6 +610,15 @@ void QWindowsContext::removeWindow(HWND hwnd)
}
}
+QWindowsWindow *QWindowsContext::findPlatformWindow(const QWindowsMenuBar *mb) const
+{
+ for (auto it = d->m_windows.cbegin(), end = d->m_windows.cend(); it != end; ++it) {
+ if ((*it)->menuBar() == mb)
+ return *it;
+ }
+ return nullptr;
+}
+
QWindowsWindow *QWindowsContext::findPlatformWindow(HWND hwnd) const
{
return d->m_windows.value(hwnd);
@@ -934,11 +956,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
switch (et) {
case QtWindows::GestureEvent:
-#if QT_CONFIG(sessionmanager)
- return platformSessionManager()->isInteractionBlocked() ? true : d->m_mouseHandler.translateGestureEvent(platformWindow->window(), hwnd, et, msg, result);
-#else
- return d->m_mouseHandler.translateGestureEvent(platformWindow->window(), hwnd, et, msg, result);
-#endif
+ return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateGestureEvent(platformWindow->window(), hwnd, et, msg, result);
case QtWindows::InputMethodOpenCandidateWindowEvent:
case QtWindows::InputMethodCloseCandidateWindowEvent:
// TODO: Release/regrab mouse if a popup has mouse grab.
@@ -1027,11 +1045,23 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
case QtWindows::InputMethodKeyEvent:
case QtWindows::InputMethodKeyDownEvent:
case QtWindows::AppCommandEvent:
-#if QT_CONFIG(sessionmanager)
- return platformSessionManager()->isInteractionBlocked() ? true : d->m_keyMapper.translateKeyEvent(platformWindow->window(), hwnd, msg, result);
-#else
- return d->m_keyMapper.translateKeyEvent(platformWindow->window(), hwnd, msg, result);
-#endif
+ return sessionManagerInteractionBlocked() || d->m_keyMapper.translateKeyEvent(platformWindow->window(), hwnd, msg, result);
+ case QtWindows::MenuAboutToShowEvent:
+ if (sessionManagerInteractionBlocked())
+ return true;
+ if (QWindowsPopupMenu::notifyAboutToShow(reinterpret_cast<HMENU>(wParam)))
+ return true;
+ if (platformWindow == nullptr || platformWindow->menuBar() == nullptr)
+ return false;
+ return platformWindow->menuBar()->notifyAboutToShow(reinterpret_cast<HMENU>(wParam));
+ case QtWindows::MenuCommandEvent:
+ if (sessionManagerInteractionBlocked())
+ return true;
+ if (QWindowsPopupMenu::notifyTriggered(LOWORD(wParam)))
+ return true;
+ if (platformWindow == nullptr || platformWindow->menuBar() == nullptr)
+ return false;
+ return platformWindow->menuBar()->notifyTriggered(LOWORD(wParam));
case QtWindows::MoveEvent:
platformWindow->handleMoved();
return true;
@@ -1051,11 +1081,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
return platformWindow->handleWmPaint(hwnd, message, wParam, lParam);
case QtWindows::NonClientMouseEvent:
if (platformWindow->frameStrutEventsEnabled())
-#if QT_CONFIG(sessionmanager)
- return platformSessionManager()->isInteractionBlocked() ? true : d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
-#else
- return d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
-#endif
+ return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
break;
case QtWindows::EnterSizeMoveEvent:
platformWindow->setFlag(QWindowsWindow::ResizeMoveActive);
@@ -1065,11 +1091,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
platformWindow->checkForScreenChanged();
return true;
case QtWindows::ScrollEvent:
-#if QT_CONFIG(sessionmanager)
- return platformSessionManager()->isInteractionBlocked() ? true : d->m_mouseHandler.translateScrollEvent(platformWindow->window(), hwnd, msg, result);
-#else
- return d->m_mouseHandler.translateScrollEvent(platformWindow->window(), hwnd, msg, result);
-#endif
+ return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateScrollEvent(platformWindow->window(), hwnd, msg, result);
case QtWindows::MouseWheelEvent:
case QtWindows::MouseEvent:
case QtWindows::LeaveEvent:
@@ -1079,18 +1101,10 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
window = window->parent();
if (!window)
return false;
-#if QT_CONFIG(sessionmanager)
- return platformSessionManager()->isInteractionBlocked() ? true : d->m_mouseHandler.translateMouseEvent(window, hwnd, et, msg, result);
-#else
- return d->m_mouseHandler.translateMouseEvent(window, hwnd, et, msg, result);
-#endif
+ return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(window, hwnd, et, msg, result);
}
case QtWindows::TouchEvent:
-#if QT_CONFIG(sessionmanager)
- return platformSessionManager()->isInteractionBlocked() ? true : d->m_mouseHandler.translateTouchEvent(platformWindow->window(), hwnd, et, msg, result);
-#else
- return d->m_mouseHandler.translateTouchEvent(platformWindow->window(), hwnd, et, msg, result);
-#endif
+ return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateTouchEvent(platformWindow->window(), hwnd, et, msg, result);
case QtWindows::FocusInEvent: // see QWindowsWindow::requestActivateWindow().
case QtWindows::FocusOutEvent:
handleFocusEvent(et, platformWindow);
@@ -1292,6 +1306,29 @@ QTouchDevice *QWindowsContext::touchDevice() const
return d->m_mouseHandler.touchDevice();
}
+static DWORD readDwordRegistrySetting(const wchar_t *regKey, const wchar_t *subKey, DWORD defaultValue)
+{
+ DWORD result = defaultValue;
+ HKEY handle;
+ if (RegOpenKeyEx(HKEY_CURRENT_USER, regKey, 0, KEY_READ, &handle) == ERROR_SUCCESS) {
+ DWORD type;
+ if (RegQueryValueEx(handle, subKey, 0, &type, 0, 0) == ERROR_SUCCESS && type == REG_DWORD) {
+ DWORD value;
+ DWORD size = sizeof(result);
+ if (RegQueryValueEx(handle, subKey, 0, 0, reinterpret_cast<unsigned char *>(&value), &size) == ERROR_SUCCESS)
+ result = value;
+ }
+ RegCloseKey(handle);
+ }
+ return result;
+}
+
+DWORD QWindowsContext::readAdvancedExplorerSettings(const wchar_t *subKey, DWORD defaultValue)
+{
+ return readDwordRegistrySetting(L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced",
+ subKey, defaultValue);
+}
+
static inline bool isEmptyRect(const RECT &rect)
{
return rect.right - rect.left == 0 && rect.bottom - rect.top == 0;
diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h
index b50010321b..5c39b6068b 100644
--- a/src/plugins/platforms/windows/qwindowscontext.h
+++ b/src/plugins/platforms/windows/qwindowscontext.h
@@ -63,11 +63,14 @@ Q_DECLARE_LOGGING_CATEGORY(lcQpaGl)
Q_DECLARE_LOGGING_CATEGORY(lcQpaMime)
Q_DECLARE_LOGGING_CATEGORY(lcQpaInputMethods)
Q_DECLARE_LOGGING_CATEGORY(lcQpaDialogs)
+Q_DECLARE_LOGGING_CATEGORY(lcQpaMenus)
Q_DECLARE_LOGGING_CATEGORY(lcQpaTablet)
Q_DECLARE_LOGGING_CATEGORY(lcQpaAccessibility)
+Q_DECLARE_LOGGING_CATEGORY(lcQpaTrayIcon)
class QWindow;
class QPlatformScreen;
+class QWindowsMenuBar;
class QWindowsScreenManager;
class QWindowsTabletSupport;
class QWindowsWindow;
@@ -177,6 +180,7 @@ public:
QWindowsWindow *findClosestPlatformWindow(HWND) const;
QWindowsWindow *findPlatformWindow(HWND) const;
+ QWindowsWindow *findPlatformWindow(const QWindowsMenuBar *mb) const;
QWindow *findWindow(HWND) const;
QWindowsWindow *findPlatformWindowAt(HWND parent, const QPoint &screenPoint,
unsigned cwex_flags) const;
@@ -192,7 +196,7 @@ public:
QWindow *keyGrabber() const;
void setKeyGrabber(QWindow *hwnd);
- void setWindowCreationContext(const QSharedPointer<QWindowCreationContext> &ctx);
+ QSharedPointer<QWindowCreationContext> setWindowCreationContext(const QSharedPointer<QWindowCreationContext> &ctx);
QSharedPointer<QWindowCreationContext> windowCreationContext() const;
void setTabletAbsoluteRange(int a);
@@ -216,6 +220,8 @@ public:
bool asyncExpose() const;
void setAsyncExpose(bool value);
+ static DWORD readAdvancedExplorerSettings(const wchar_t *subKey, DWORD defaultValue);
+
QTouchDevice *touchDevice() const;
private:
diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp
index 0a09b87ba3..e7ba08b719 100644
--- a/src/plugins/platforms/windows/qwindowscursor.cpp
+++ b/src/plugins/platforms/windows/qwindowscursor.cpp
@@ -586,6 +586,13 @@ QWindowsCursor::QWindowsCursor(const QPlatformScreen *screen)
Q_UNUSED(dummy)
}
+inline CursorHandlePtr QWindowsCursor::cursorHandle(const QCursor &cursor)
+{
+ return cursor.shape() == Qt::BitmapCursor
+ ? pixmapWindowCursor(cursor)
+ : standardWindowCursor(cursor.shape());
+}
+
/*!
\brief Set a cursor on a window.
@@ -603,9 +610,7 @@ void QWindowsCursor::changeCursor(QCursor *cursorIn, QWindow *window)
platformWindow->setCursor(CursorHandlePtr(new CursorHandle));
return;
}
- const CursorHandlePtr wcursor =
- cursorIn->shape() == Qt::BitmapCursor ?
- pixmapWindowCursor(*cursorIn) : standardWindowCursor(cursorIn->shape());
+ const CursorHandlePtr wcursor = cursorHandle(*cursorIn);
if (wcursor->handle()) {
platformWindow->setCursor(wcursor);
} else {
@@ -614,6 +619,25 @@ void QWindowsCursor::changeCursor(QCursor *cursorIn, QWindow *window)
}
}
+void QWindowsCursor::setOverrideCursor(const QCursor &cursor)
+{
+ const CursorHandlePtr wcursor = cursorHandle(cursor);
+ if (wcursor->handle()) {
+ m_overriddenCursor = SetCursor(wcursor->handle());
+ } else {
+ qWarning("%s: Unable to obtain system cursor for %d",
+ __FUNCTION__, cursor.shape());
+ }
+}
+
+void QWindowsCursor::clearOverrideCursor()
+{
+ if (m_overriddenCursor) {
+ SetCursor(m_overriddenCursor);
+ m_overriddenCursor = nullptr;
+ }
+}
+
QPoint QWindowsCursor::mousePosition()
{
POINT p;
diff --git a/src/plugins/platforms/windows/qwindowscursor.h b/src/plugins/platforms/windows/qwindowscursor.h
index df2e22733b..9aa9523ac8 100644
--- a/src/plugins/platforms/windows/qwindowscursor.h
+++ b/src/plugins/platforms/windows/qwindowscursor.h
@@ -105,6 +105,9 @@ public:
explicit QWindowsCursor(const QPlatformScreen *screen);
void changeCursor(QCursor * widgetCursor, QWindow * widget) override;
+ void setOverrideCursor(const QCursor &cursor) override;
+ void clearOverrideCursor() override;
+
QPoint pos() const override;
void setPos(const QPoint &pos) override;
@@ -127,6 +130,8 @@ private:
typedef QHash<Qt::CursorShape, CursorHandlePtr> StandardCursorCache;
typedef QHash<QWindowsPixmapCursorCacheKey, CursorHandlePtr> PixmapCursorCache;
+ CursorHandlePtr cursorHandle(const QCursor &c);
+
const QPlatformScreen *const m_screen;
StandardCursorCache m_standardCursorCache;
PixmapCursorCache m_pixmapCursorCache;
@@ -135,6 +140,8 @@ private:
mutable QPixmap m_moveDragCursor;
mutable QPixmap m_linkDragCursor;
mutable QPixmap m_ignoreDragCursor;
+
+ HCURSOR m_overriddenCursor = nullptr;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
index 4b08528d17..e713debf5b 100644
--- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
+++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
@@ -39,8 +39,11 @@
#define QT_NO_URL_CAST_FROM_STRING 1
-#define _WIN32_WINNT 0x0600
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0601
+#endif
+#include "qwindowscombase.h"
#include "qwindowsdialoghelpers.h"
#include "qwindowscontext.h"
@@ -52,7 +55,7 @@
#include <QtGui/QColor>
#include <QtCore/QDebug>
-#include <QtCore/QRegExp>
+#include <QtCore/QRegularExpression>
#include <QtCore/QTimer>
#include <QtCore/QDir>
#include <QtCore/QScopedArrayPointer>
@@ -504,33 +507,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 +527,6 @@ public:
virtual ~QWindowsNativeFileDialogEventHandler() {}
private:
- long m_ref = 1;
QWindowsNativeFileDialogBase *m_nativeFileDialog;
};
@@ -931,7 +911,7 @@ IShellItem *QWindowsNativeFileDialogBase::shellItem(const QUrl &url)
// (see https://msdn.microsoft.com/en-us/library/windows/desktop/dd378457(v=vs.85).aspx)
// specified as "clsid:<GUID>" (without '{', '}').
IShellItem *result = Q_NULLPTR;
- const QUuid uuid(url.path());
+ const auto uuid = QUuid::fromString(url.path());
if (uuid.isNull()) {
qWarning() << __FUNCTION__ << ": Invalid CLSID: " << url.path();
return Q_NULLPTR;
@@ -995,7 +975,9 @@ void QWindowsNativeFileDialogBase::setMode(QFileDialogOptions::FileMode mode,
QFileDialogOptions::AcceptMode acceptMode,
QFileDialogOptions::FileDialogOptions options)
{
- DWORD flags = FOS_PATHMUSTEXIST | FOS_FORCESHOWHIDDEN;
+ DWORD flags = FOS_PATHMUSTEXIST;
+ if (QWindowsContext::readAdvancedExplorerSettings(L"Hidden", 1) == 1) // 1:show, 2:hidden
+ flags |= FOS_FORCESHOWHIDDEN;
if (options & QFileDialogOptions::DontResolveSymlinks)
flags |= FOS_NODEREFERENCELINKS;
switch (mode) {
@@ -1041,7 +1023,7 @@ static QList<FilterSpec> filterSpecs(const QStringList &filters,
result.reserve(filters.size());
*totalStringLength = 0;
- const QRegExp filterSeparatorRE(QStringLiteral("[;\\s]+"));
+ const QRegularExpression filterSeparatorRE(QStringLiteral("[;\\s]+"));
const QString separator = QStringLiteral(";");
Q_ASSERT(filterSeparatorRE.isValid());
// Split filter specification as 'Texts (*.txt[;] *.doc)', '*.txt[;] *.doc'
diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp
index 26403b68e5..aa6454ef63 100644
--- a/src/plugins/platforms/windows/qwindowsdrag.cpp
+++ b/src/plugins/platforms/windows/qwindowsdrag.cpp
@@ -44,7 +44,7 @@
# include "qwindowsclipboard.h"
#endif
#include "qwindowsintegration.h"
-#include "qwindowsole.h"
+#include "qwindowsdropdataobject.h"
#include <QtCore/qt_windows.h>
#include "qwindowswindow.h"
#include "qwindowsmousehandler.h"
@@ -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)
{
@@ -740,7 +673,7 @@ Qt::DropAction QWindowsDrag::drag(QDrag *drag)
QWindowsDrag::m_canceled = false;
QWindowsOleDropSource *windowDropSource = new QWindowsOleDropSource(this);
windowDropSource->createCursors();
- QWindowsOleDataObject *dropDataObject = new QWindowsOleDataObject(dropData);
+ QWindowsDropDataObject *dropDataObject = new QWindowsDropDataObject(dropData);
const Qt::DropActions possibleActions = drag->supportedActions();
const DWORD allowedEffects = translateToWinDragEffects(possibleActions);
qCDebug(lcQpaMime) << '>' << __FUNCTION__ << "possible Actions=0x"
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/qwindowsdropdataobject.cpp b/src/plugins/platforms/windows/qwindowsdropdataobject.cpp
new file mode 100644
index 0000000000..bd532ab70e
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsdropdataobject.cpp
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "qwindowsdropdataobject.h"
+
+#include <QtCore/QUrl>
+#include <QtCore/QMimeData>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QWindowsDropDataObject
+ \brief QWindowsOleDataObject subclass specialized for handling Drag&Drop.
+
+ Only allows "text/uri-list" data to be exported as CF_HDROP, to allow dropped
+ files to be attached to Office applications (instead of adding an URL link).
+
+ \internal
+ \ingroup qt-lighthouse-win
+*/
+
+QWindowsDropDataObject::QWindowsDropDataObject(QMimeData *mimeData) :
+ QWindowsOleDataObject(mimeData)
+{
+}
+
+QWindowsDropDataObject::~QWindowsDropDataObject()
+{
+}
+
+STDMETHODIMP
+QWindowsDropDataObject::GetData(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium)
+{
+ if (shouldIgnore(pformatetc))
+ return ResultFromScode(DATA_E_FORMATETC);
+
+ return QWindowsOleDataObject::GetData(pformatetc, pmedium);
+}
+
+STDMETHODIMP
+QWindowsDropDataObject::QueryGetData(LPFORMATETC pformatetc)
+{
+ if (shouldIgnore(pformatetc))
+ return ResultFromScode(DATA_E_FORMATETC);
+
+ return QWindowsOleDataObject::QueryGetData(pformatetc);
+}
+
+// If the data is text/uri-list for local files, tell we can only export it as CF_HDROP.
+bool QWindowsDropDataObject::shouldIgnore(LPFORMATETC pformatetc) const
+{
+ QMimeData *dropData = mimeData();
+
+ if (dropData && dropData->hasFormat(QStringLiteral("text/uri-list")) && (pformatetc->cfFormat != CF_HDROP)) {
+ QList<QUrl> urls = dropData->urls();
+ return std::any_of(urls.cbegin(), urls.cend(), [] (const QUrl &u) { return u.isLocalFile(); });
+ }
+
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsdropdataobject.h b/src/plugins/platforms/windows/qwindowsdropdataobject.h
new file mode 100644
index 0000000000..5ef72c9336
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsdropdataobject.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** 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 QWINDOWSDROPDATAOBJECT_H
+#define QWINDOWSDROPDATAOBJECT_H
+
+#include "qwindowsole.h"
+
+QT_BEGIN_NAMESPACE
+
+class QWindowsDropDataObject : public QWindowsOleDataObject
+{
+public:
+ explicit QWindowsDropDataObject(QMimeData *mimeData);
+ virtual ~QWindowsDropDataObject();
+
+ // overridden IDataObject methods
+ STDMETHOD(GetData)(LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium);
+ STDMETHOD(QueryGetData)(LPFORMATETC pformatetc);
+
+private:
+ bool shouldIgnore(LPFORMATETC pformatetc) const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSDROPDATAOBJECT_H
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 17cab69891..f9bac3920b 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.cpp
+++ b/src/plugins/platforms/windows/qwindowsintegration.cpp
@@ -42,6 +42,7 @@
#include "qwindowswindow.h"
#include "qwindowscontext.h"
#include "qwin10helpers.h"
+#include "qwindowsmenu.h"
#include "qwindowsopenglcontext.h"
#include "qwindowsscreen.h"
@@ -71,6 +72,7 @@
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qhighdpiscaling_p.h>
#include <QtGui/qpa/qplatforminputcontextfactory_p.h>
+#include <QtGui/qpa/qplatformcursor.h>
#include <QtEventDispatcherSupport/private/qwindowsguieventdispatcher_p.h>
@@ -206,6 +208,10 @@ static inline unsigned parseOptions(const QStringList &paramList,
} 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 if (param == QLatin1String("menus=native")) {
+ options |= QWindowsIntegration::AlwaysUseNativeMenus;
+ } else if (param == QLatin1String("menus=none")) {
+ options |= QWindowsIntegration::NoNativeMenus;
} else {
qWarning() << "Unknown option" << param;
}
@@ -237,6 +243,7 @@ QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(const QStringList &paramL
}
m_context.initTouch(m_options);
+ QPlatformCursor::setCapability(QPlatformCursor::OverrideCursor);
}
QWindowsIntegrationPrivate::~QWindowsIntegrationPrivate()
@@ -334,20 +341,8 @@ QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) cons
QWindowsWindow *result = createPlatformWindowHelper(window, obtained);
Q_ASSERT(result);
- if (requested.flags != obtained.flags)
- window->setFlags(obtained.flags);
- // Trigger geometry change (unless it has a special state in which case setWindowState()
- // will send the message) and screen change signals of QWindow.
- if ((obtained.flags & Qt::Desktop) != Qt::Desktop) {
- const Qt::WindowState state = window->windowState();
- if (state != Qt::WindowMaximized && state != Qt::WindowFullScreen
- && requested.geometry != obtained.geometry) {
- QWindowSystemInterface::handleGeometryChange(window, obtained.geometry);
- }
- QPlatformScreen *screen = result->screenForGeometry(obtained.geometry);
- if (screen && result->screen() != screen)
- QWindowSystemInterface::handleWindowScreenChanged(window, screen->screen());
- }
+ if (QWindowsMenuBar *menuBarToBeInstalled = QWindowsMenuBar::menuBarOf(window))
+ menuBarToBeInstalled->install(result);
return result;
}
@@ -611,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 28d4fd3026..23f3d9ef4e 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.h
+++ b/src/plugins/platforms/windows/qwindowsintegration.h
@@ -64,7 +64,9 @@ public:
DontPassOsMouseEventsSynthesizedFromTouch = 0x20, // Do not pass OS-generated mouse events from touch.
// Keep in sync with QWindowsFontDatabase::FontOptions
DontUseDirectWriteFonts = QWindowsFontDatabase::DontUseDirectWriteFonts,
- DontUseColorFonts = QWindowsFontDatabase::DontUseColorFonts
+ DontUseColorFonts = QWindowsFontDatabase::DontUseColorFonts,
+ AlwaysUseNativeMenus = 0x100,
+ NoNativeMenus = 0x200
};
explicit QWindowsIntegration(const QStringList &paramList);
@@ -113,6 +115,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/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp
index 3987d8ca29..af62936a18 100644
--- a/src/plugins/platforms/windows/qwindowskeymapper.cpp
+++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp
@@ -903,6 +903,12 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &ms
return true;
}
+ // Enable Alt accelerators ("&File") on menus
+ if (msgType == WM_SYSKEYDOWN && (nModifiers & AltAny) != 0 && GetMenu(msg.hwnd) != nullptr)
+ return false;
+ if (msgType == WM_SYSKEYUP && nModifiers == 0 && GetMenu(msg.hwnd) != nullptr)
+ return false;
+
bool result = false;
// handle Directionality changes (BiDi) with RTL extensions
if (m_useRTLExtensions) {
diff --git a/src/plugins/platforms/windows/qwindowsmenu.cpp b/src/plugins/platforms/windows/qwindowsmenu.cpp
new file mode 100644
index 0000000000..4e1997c4f8
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsmenu.cpp
@@ -0,0 +1,962 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "qwindowsmenu.h"
+#include "qwindowscontext.h"
+#include "qwindowswindow.h"
+
+#include <QtGui/qwindow.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qpointer.h>
+
+#include <algorithm>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QWindowsMenuBar
+ \brief Windows native menu bar
+
+ \list
+ \li \l{https://msdn.microsoft.com/de-de/library/windows/desktop/ms647553(v=vs.85).aspx#_win32_Menu_Creation_Functions},
+ \e{About Menus}
+ \endlist
+
+ \note The destruction order of the QWindowsMenu/Item/Bar instances is
+ arbitrary depending on whether the application is Qt Quick or
+ Qt Widgets, either the containers or the items might be deleted first.
+
+ \internal
+ \ingroup qt-lighthouse-win
+*/
+
+static uint nextId = 1;
+
+// Find a QPlatformMenu[Item]* in a vector of QWindowsMenu[Item], where
+// QVector::indexOf() cannot be used since it wants a QWindowsMenu[Item]*
+template <class Derived, class Needle>
+static int indexOf(const QVector<Derived *> &v, const Needle *needle)
+{
+ for (int i = 0, size = v.size(); i < size; ++i) {
+ if (v.at(i) == needle)
+ return i;
+ }
+ return -1;
+}
+
+// Helper for inserting a QPlatformMenu[Item]* into a vector of QWindowsMenu[Item].
+template <class Derived, class Base>
+static int insertBefore(QVector<Derived *> *v, Base *newItemIn, const Base *before = nullptr)
+{
+ int index = before ? indexOf(*v, before) : -1;
+ if (index != -1) {
+ v->insert(index, static_cast<Derived *>(newItemIn));
+ } else {
+ index = v->size();
+ v->append(static_cast<Derived *>(newItemIn));
+ }
+ return index;
+}
+
+static inline const wchar_t *qStringToWChar(const QString &s)
+{
+ return reinterpret_cast<const wchar_t *>(s.utf16());
+}
+
+// Traverse menu and return the item for which predicate
+// "bool Function(QWindowsMenuItem *)" returns true
+template <class Predicate>
+static QWindowsMenuItem *traverseMenuItems(const QWindowsMenu *menu, Predicate p)
+{
+ const QWindowsMenu::MenuItems &items = menu->menuItems();
+ for (QWindowsMenuItem *item : items) {
+ if (p(item))
+ return item;
+ if (item->subMenu()) {
+ if (QWindowsMenuItem *subMenuItem = traverseMenuItems(item->subMenu(), p))
+ return subMenuItem;
+ }
+ }
+ return nullptr;
+}
+
+// Traverse menu bar return the item for which predicate
+// "bool Function(QWindowsMenuItem *)" returns true
+template <class Predicate>
+static QWindowsMenuItem *traverseMenuItems(const QWindowsMenuBar *menuBar, Predicate p)
+{
+ const QWindowsMenuBar::Menus &menus = menuBar->menus();
+ for (QWindowsMenu *menu : menus) {
+ if (QWindowsMenuItem *item = traverseMenuItems(menu, p))
+ return item;
+ }
+ return nullptr;
+}
+
+template <class Menu /* Menu[Bar] */>
+static QWindowsMenuItem *findMenuItemById(const Menu *menu, uint id)
+{
+ return traverseMenuItems(menu, [id] (const QWindowsMenuItem *i) { return i->id() == id; });
+}
+
+// Traverse menu and return the menu for which predicate
+// "bool Function(QWindowsMenu *)" returns true
+template <class Predicate>
+static QWindowsMenu *traverseMenus(const QWindowsMenu *menu, Predicate p)
+{
+ const QWindowsMenu::MenuItems &items = menu->menuItems();
+ for (QWindowsMenuItem *item : items) {
+ if (QWindowsMenu *subMenu = item->subMenu()) {
+ if (p(subMenu))
+ return subMenu;
+ if (QWindowsMenu *menu = traverseMenus(subMenu, p))
+ return menu;
+ }
+ }
+ return nullptr;
+}
+
+// Traverse menu bar return the item for which
+// function "bool Function(QWindowsMenu *)" returns true
+template <class Predicate>
+static QWindowsMenu *traverseMenus(const QWindowsMenuBar *menuBar, Predicate p)
+{
+ const QWindowsMenuBar::Menus &menus = menuBar->menus();
+ for (QWindowsMenu *menu : menus) {
+ if (p(menu))
+ return menu;
+ if (QWindowsMenu *subMenu = traverseMenus(menu, p))
+ return subMenu;
+ }
+ return nullptr;
+}
+
+template <class Menu /* Menu[Bar] */>
+static QWindowsMenu *findMenuByHandle(const Menu *menu, HMENU hMenu)
+{
+ return traverseMenus(menu, [hMenu] (const QWindowsMenu *i) { return i->menuHandle() == hMenu; });
+}
+
+template <class MenuType>
+static int findNextVisibleEntry(const QVector<MenuType *> &entries, int pos)
+{
+ for (int i = pos, size = entries.size(); i < size; ++i) {
+ if (entries.at(i)->isVisible())
+ return i;
+ }
+ return -1;
+}
+
+static inline void menuItemInfoInit(MENUITEMINFO &menuItemInfo)
+{
+ memset(&menuItemInfo, 0, sizeof(MENUITEMINFO));
+ menuItemInfo.cbSize = sizeof(MENUITEMINFO);
+}
+
+static inline void menuItemInfoSetText(MENUITEMINFO &menuItemInfo, const QString &text)
+{
+ menuItemInfoInit(menuItemInfo);
+ menuItemInfo.fMask = MIIM_STRING;
+ menuItemInfo.dwTypeData = const_cast<wchar_t *>(qStringToWChar(text));
+ menuItemInfo.cch = UINT(text.size());
+}
+
+static UINT menuItemState(HMENU hMenu, UINT uItem, BOOL fByPosition)
+{
+ MENUITEMINFO menuItemInfo;
+ menuItemInfoInit(menuItemInfo);
+ menuItemInfo.fMask = MIIM_STATE;
+ return GetMenuItemInfo(hMenu, uItem, fByPosition, &menuItemInfo) == TRUE ? menuItemInfo.fState : 0;
+}
+
+static void menuItemSetState(HMENU hMenu, UINT uItem, BOOL fByPosition, UINT flags)
+{
+ MENUITEMINFO menuItemInfo;
+ menuItemInfoInit(menuItemInfo);
+ menuItemInfo.fMask = MIIM_STATE;
+ menuItemInfo.fState = flags;
+ SetMenuItemInfo(hMenu, uItem, fByPosition, &menuItemInfo);
+}
+
+static void menuItemSetChangeState(HMENU hMenu, UINT uItem, BOOL fByPosition,
+ bool value, UINT trueState, UINT falseState)
+{
+ const UINT oldState = menuItemState(hMenu, uItem, fByPosition);
+ UINT newState = oldState;
+ if (value) {
+ newState |= trueState;
+ newState &= ~falseState;
+ } else {
+ newState &= ~trueState;
+ newState |= falseState;
+ }
+ if (oldState != newState)
+ menuItemSetState(hMenu, uItem, fByPosition, newState);
+}
+
+// ------------ QWindowsMenuItem
+QWindowsMenuItem::QWindowsMenuItem(QWindowsMenu *parentMenu)
+ : m_parentMenu(parentMenu)
+ , m_id(0)
+{
+ qCDebug(lcQpaMenus) << __FUNCTION__ << static_cast<const void *>(this)
+ << "parentMenu=" << parentMenu;
+}
+
+QWindowsMenuItem::~QWindowsMenuItem()
+{
+ qCDebug(lcQpaMenus) << __FUNCTION__ << static_cast<const void *>(this);
+ removeFromMenu();
+ freeBitmap();
+}
+
+void QWindowsMenuItem::freeBitmap()
+{
+ if (m_hbitmap) {
+ DeleteObject(m_hbitmap);
+ m_hbitmap = nullptr;
+ }
+}
+
+void QWindowsMenuItem::setIcon(const QIcon &icon)
+{
+ qCDebug(lcQpaMenus) << __FUNCTION__ << '(' << icon << ')' << this;
+ if (m_icon.cacheKey() == icon.cacheKey())
+ return;
+ m_icon = icon;
+ if (m_parentMenu != nullptr)
+ updateBitmap();
+}
+
+Q_GUI_EXPORT HBITMAP qt_pixmapToWinHBITMAP(const QPixmap &p, int hbitmapFormat = 0);
+
+void QWindowsMenuItem::updateBitmap()
+{
+ freeBitmap();
+ if (!m_icon.isNull()) {
+ const int size = m_iconSize ? m_iconSize : GetSystemMetrics(SM_CYMENUCHECK);
+ m_hbitmap = qt_pixmapToWinHBITMAP(m_icon.pixmap(QSize(size, size)), 1);
+ }
+ MENUITEMINFO itemInfo;
+ menuItemInfoInit(itemInfo);
+ itemInfo.fMask = MIIM_BITMAP;
+ itemInfo.hbmpItem = m_hbitmap;
+ SetMenuItemInfo(parentMenuHandle(), m_id, FALSE, &itemInfo);
+}
+
+void QWindowsMenuItem::setText(const QString &text)
+{
+ qCDebug(lcQpaMenus).nospace().noquote()
+ << __FUNCTION__ << "(\"" << text << "\") " << this;
+ if (m_text == text)
+ return;
+ m_text = text;
+ if (m_parentMenu != nullptr)
+ updateText();
+}
+
+void QWindowsMenuItem::updateText()
+{
+ MENUITEMINFO menuItemInfo;
+ const QString &text = nativeText();
+ menuItemInfoSetText(menuItemInfo, text);
+ SetMenuItemInfo(parentMenuHandle(), m_id, FALSE, &menuItemInfo);
+}
+
+void QWindowsMenuItem::setMenu(QPlatformMenu *menuIn)
+{
+ qCDebug(lcQpaMenus) << __FUNCTION__ << '(' << menuIn << ')' << this;
+ if (menuIn == m_subMenu)
+ return;
+ const uint oldId = m_id;
+ if (menuIn != nullptr) { // Set submenu
+ m_subMenu = static_cast<QWindowsMenu *>(menuIn);
+ m_subMenu->setAsItemSubMenu(this);
+ m_id = m_subMenu->id();
+ if (m_parentMenu != nullptr) {
+ ModifyMenu(m_parentMenu->menuHandle(), oldId, MF_BYCOMMAND | MF_POPUP,
+ m_id, qStringToWChar(m_text));
+ }
+ return;
+ }
+ // Clear submenu
+ m_subMenu = nullptr;
+ if (m_parentMenu != nullptr) {
+ m_id = nextId++;
+ ModifyMenu(m_parentMenu->menuHandle(), oldId, MF_BYCOMMAND,
+ m_id, qStringToWChar(m_text));
+ } else {
+ m_id = 0;
+ }
+}
+
+void QWindowsMenuItem::setVisible(bool isVisible)
+{
+ qCDebug(lcQpaMenus) << __FUNCTION__ << '(' << isVisible << ')' << this;
+ if (m_visible == isVisible)
+ return;
+ m_visible = isVisible;
+ if (m_parentMenu == nullptr)
+ return;
+ // Windows menu items do not implement settable visibility, we need to work
+ // around by removing the item from the menu. It will be kept in the list.
+ if (isVisible)
+ insertIntoMenuHelper(m_parentMenu, false, m_parentMenu->menuItems().indexOf(this));
+ else
+ RemoveMenu(parentMenuHandle(), m_id, MF_BYCOMMAND);
+}
+
+void QWindowsMenuItem::setIsSeparator(bool isSeparator)
+{
+ qCDebug(lcQpaMenus) << __FUNCTION__ << '(' << isSeparator << ')' << this;
+ if (m_separator == isSeparator)
+ return;
+ m_separator = isSeparator;
+}
+
+void QWindowsMenuItem::setCheckable(bool checkable)
+{
+ qCDebug(lcQpaMenus) << __FUNCTION__ << '(' << checkable << ')' << this;
+ if (m_checkable == checkable)
+ return;
+ m_checkable = checkable;
+ if (m_parentMenu == nullptr)
+ return;
+ UINT state = menuItemState(parentMenuHandle(), m_id, FALSE);
+ if (m_checkable)
+ state |= m_checked ? MF_CHECKED : MF_UNCHECKED;
+ else
+ state &= ~(MF_CHECKED | MF_UNCHECKED);
+ menuItemSetState(parentMenuHandle(), m_id, FALSE, state);
+}
+
+void QWindowsMenuItem::setChecked(bool isChecked)
+{
+ qCDebug(lcQpaMenus) << __FUNCTION__ << '(' << isChecked << ')' << this;
+ if (m_checked == isChecked)
+ return;
+ m_checked = isChecked;
+ // Convenience: Allow to set checkable by calling setChecked(true) for
+ // Quick Controls 1
+ if (isChecked)
+ m_checkable = true;
+ if (m_parentMenu == nullptr || !m_checkable)
+ return;
+ menuItemSetChangeState(parentMenuHandle(), m_id, FALSE, m_checked, MF_CHECKED, MF_UNCHECKED);
+}
+
+void QWindowsMenuItem::setShortcut(const QKeySequence &shortcut)
+{
+ qCDebug(lcQpaMenus) << __FUNCTION__ << '(' << shortcut << ')' << this;
+ if (m_shortcut == shortcut)
+ return;
+ m_shortcut = shortcut;
+ if (m_parentMenu != nullptr)
+ updateText();
+}
+
+void QWindowsMenuItem::setEnabled(bool enabled)
+{
+ qCDebug(lcQpaMenus) << __FUNCTION__ << '(' << enabled << ')' << this;
+ if (m_enabled == enabled)
+ return;
+ m_enabled = enabled;
+ if (m_parentMenu != nullptr)
+ menuItemSetChangeState(parentMenuHandle(), m_id, FALSE, m_enabled, MF_ENABLED, MF_GRAYED);
+}
+
+void QWindowsMenuItem::setIconSize(int size)
+{
+ if (m_iconSize == size)
+ return;
+ m_iconSize = size;
+ if (m_parentMenu != nullptr)
+ updateBitmap();
+}
+
+HMENU QWindowsMenuItem::parentMenuHandle() const
+{
+ return m_parentMenu ? m_parentMenu->menuHandle() : nullptr;
+}
+
+UINT QWindowsMenuItem::state() const
+{
+ if (m_separator)
+ return MF_SEPARATOR;
+ UINT result = MF_STRING | (m_enabled ? MF_ENABLED : MF_GRAYED);
+ if (m_subMenu != nullptr)
+ result |= MF_POPUP;
+ if (m_checkable)
+ result |= m_checked ? MF_CHECKED : MF_UNCHECKED;
+ if (QGuiApplication::layoutDirection() == Qt::RightToLeft)
+ result |= MFT_RIGHTORDER;
+ return result;
+}
+
+QString QWindowsMenuItem::nativeText() const
+{
+ QString result = m_text;
+ if (!m_shortcut.isEmpty()) {
+ result += QLatin1Char('\t');
+ result += m_shortcut.toString(QKeySequence::NativeText);
+ }
+ return result;
+}
+
+void QWindowsMenuItem::insertIntoMenu(QWindowsMenu *menu, bool append, int index)
+{
+ if (m_id == 0 && m_subMenu == nullptr)
+ m_id = nextId++;
+ insertIntoMenuHelper(menu, append, index);
+ m_parentMenu = menu;
+}
+
+void QWindowsMenuItem::insertIntoMenuHelper(QWindowsMenu *menu, bool append, int index)
+{
+ const QString &text = nativeText();
+
+ UINT_PTR idBefore = 0;
+ if (!append) {
+ // Skip over self (either newly inserted or when called from setVisible()
+ const int nextIndex = findNextVisibleEntry(menu->menuItems(), index + 1);
+ if (nextIndex != -1)
+ idBefore = menu->menuItems().at(nextIndex)->id();
+ }
+
+ if (idBefore)
+ InsertMenu(menu->menuHandle(), idBefore, state(), m_id, qStringToWChar(text));
+ else
+ AppendMenu(menu->menuHandle(), state(), m_id, qStringToWChar(text));
+
+ updateBitmap();
+}
+
+bool QWindowsMenuItem::removeFromMenu()
+{
+ if (QWindowsMenu *parentMenu = m_parentMenu) {
+ m_parentMenu = nullptr;
+ RemoveMenu(parentMenu->menuHandle(), m_id, MF_BYCOMMAND);
+ parentMenu->notifyRemoved(this);
+ return true;
+ }
+ return false;
+}
+
+// ------------ QWindowsMenu
+
+QWindowsMenu::QWindowsMenu() : QWindowsMenu(nullptr, CreateMenu())
+{
+}
+
+QWindowsMenu::QWindowsMenu(QWindowsMenu *parentMenu, HMENU menu)
+ : m_parentMenu(parentMenu)
+ , m_hMenu(menu)
+{
+ qCDebug(lcQpaMenus) << __FUNCTION__ << static_cast<const void *>(this)
+ << "parentMenu=" << parentMenu << "HMENU=" << m_hMenu;
+}
+
+QWindowsMenu::~QWindowsMenu()
+{
+ qCDebug(lcQpaMenus).noquote().nospace() << __FUNCTION__
+ << " \"" <<m_text << "\", " << static_cast<const void *>(this);
+ for (int i = m_menuItems.size() - 1; i>= 0; --i)
+ m_menuItems.at(i)->removeFromMenu();
+ removeFromParent();
+ DestroyMenu(m_hMenu);
+}
+
+void QWindowsMenu::insertMenuItem(QPlatformMenuItem *menuItemIn, QPlatformMenuItem *before)
+{
+ qCDebug(lcQpaMenus) << __FUNCTION__ << '(' << menuItemIn << ", before=" << before << ')' << this;
+ QWindowsMenuItem *menuItem = static_cast<QWindowsMenuItem *>(menuItemIn);
+ const int index = insertBefore(&m_menuItems, menuItemIn, before);
+ const bool append = index == m_menuItems.size() - 1;
+ menuItem->insertIntoMenu(this, append, index);
+}
+
+void QWindowsMenu::removeMenuItem(QPlatformMenuItem *menuItemIn)
+{
+ qCDebug(lcQpaMenus) << __FUNCTION__ << '(' << menuItemIn << ')' << this;
+ static_cast<QWindowsMenuItem *>(menuItemIn)->removeFromMenu();
+}
+
+void QWindowsMenu::setText(const QString &text)
+{
+ qCDebug(lcQpaMenus).nospace().noquote()
+ << __FUNCTION__ << "(\"" << text << "\") " << this;
+ if (m_text == text)
+ return;
+ m_text = text;
+ if (!m_visible)
+ return;
+ const HMENU ph = parentHandle();
+ if (ph == nullptr)
+ return;
+ MENUITEMINFO menuItemInfo;
+ menuItemInfoSetText(menuItemInfo, m_text);
+ SetMenuItemInfo(ph, id(), FALSE, &menuItemInfo);
+}
+
+void QWindowsMenu::setIcon(const QIcon &icon)
+{
+ qCDebug(lcQpaMenus) << __FUNCTION__ << '(' << icon << ')' << this;
+ m_icon = icon;
+}
+
+void QWindowsMenu::setEnabled(bool enabled)
+{
+ qCDebug(lcQpaMenus) << __FUNCTION__ << '(' << enabled << ')' << this;
+ if (m_enabled == enabled)
+ return;
+ m_enabled = enabled;
+ if (!m_visible)
+ return;
+ if (const HMENU ph = parentHandle())
+ menuItemSetChangeState(ph, id(), FALSE, m_enabled, MF_ENABLED, MF_GRAYED);
+}
+
+QWindowsMenuItem *QWindowsMenu::itemForSubMenu(const QWindowsMenu *subMenu) const
+{
+ const auto it = std::find_if(m_menuItems.cbegin(), m_menuItems.cend(),
+ [subMenu] (const QWindowsMenuItem *i) { return i->subMenu() == subMenu; });
+ return it != m_menuItems.cend() ? *it : nullptr;
+}
+
+void QWindowsMenu::insertIntoMenuBar(QWindowsMenuBar *bar, bool append, int index)
+{
+ UINT_PTR idBefore = 0;
+ if (!append) {
+ // Skip over self (either newly inserted or when called from setVisible()
+ const int nextIndex = findNextVisibleEntry(bar->menus(), index + 1);
+ if (nextIndex != -1)
+ idBefore = bar->menus().at(nextIndex)->id();
+ }
+ m_parentMenuBar = bar;
+ m_parentMenu = nullptr;
+ if (idBefore)
+ InsertMenu(bar->menuBarHandle(), idBefore, MF_POPUP | MF_BYCOMMAND, id(), qStringToWChar(m_text));
+ else
+ AppendMenu(bar->menuBarHandle(), MF_POPUP, id(), qStringToWChar(m_text));
+}
+
+bool QWindowsMenu::removeFromParent()
+{
+ if (QWindowsMenuBar *bar = m_parentMenuBar) {
+ m_parentMenuBar = nullptr;
+ bar->notifyRemoved(this);
+ return RemoveMenu(bar->menuBarHandle(), id(), MF_BYCOMMAND) == TRUE;
+ }
+ if (QWindowsMenu *menu = m_parentMenu) {
+ m_parentMenu = nullptr;
+ QWindowsMenuItem *item = menu->itemForSubMenu(this);
+ if (item)
+ item->setMenu(nullptr);
+ return item != nullptr;
+ }
+ return false;
+}
+
+void QWindowsMenu::setVisible(bool visible)
+{
+ qCDebug(lcQpaMenus) << __FUNCTION__ << '(' << visible << ')' << this;
+ if (m_visible == visible)
+ return;
+ m_visible = visible;
+ const HMENU ph = parentHandle();
+ if (ph == nullptr)
+ return;
+ // Windows menus do not implement settable visibility, we need to work
+ // around by removing the menu from the parent. It will be kept in the list.
+ if (visible) {
+ if (m_parentMenuBar)
+ insertIntoMenuBar(m_parentMenuBar, false, m_parentMenuBar->menus().indexOf(this));
+ } else {
+ RemoveMenu(ph, id(), MF_BYCOMMAND);
+ }
+ if (m_parentMenuBar)
+ m_parentMenuBar->redraw();
+}
+
+QPlatformMenuItem *QWindowsMenu::menuItemAt(int position) const
+{
+ qCDebug(lcQpaMenus) << __FUNCTION__ << position;
+ return position >= 0 && position < m_menuItems.size()
+ ? m_menuItems.at(position) : nullptr;
+}
+
+QPlatformMenuItem *QWindowsMenu::menuItemForTag(quintptr tag) const
+{
+ return traverseMenuItems(this, [tag] (const QPlatformMenuItem *i) { return i->tag() == tag; });
+}
+
+QPlatformMenuItem *QWindowsMenu::createMenuItem() const
+{
+ QPlatformMenuItem *result = new QWindowsMenuItem;
+ qCDebug(lcQpaMenus) << __FUNCTION__ << this << "returns" << result;
+ return result;
+}
+
+QPlatformMenu *QWindowsMenu::createSubMenu() const
+{
+ QPlatformMenu *result = new QWindowsMenu;
+ qCDebug(lcQpaMenus) << __FUNCTION__ << this << "returns" << result;
+ return result;
+}
+
+void QWindowsMenu::setAsItemSubMenu(QWindowsMenuItem *item)
+{
+ m_parentMenu = item->parentMenu();
+}
+
+HMENU QWindowsMenu::parentMenuHandle() const
+{
+ return m_parentMenu ? m_parentMenu->menuHandle() : nullptr;
+}
+
+HMENU QWindowsMenu::parentMenuBarHandle() const
+{
+ return m_parentMenuBar ? m_parentMenuBar->menuBarHandle() : nullptr;
+}
+
+HMENU QWindowsMenu::parentHandle() const
+{
+ if (m_parentMenuBar)
+ return m_parentMenuBar->menuBarHandle();
+ if (m_parentMenu)
+ return m_parentMenu->menuHandle();
+ return nullptr;
+}
+
+// --------------- QWindowsPopupMenu
+
+static QPointer<QWindowsPopupMenu> lastShownPopupMenu;
+
+QWindowsPopupMenu::QWindowsPopupMenu() : QWindowsMenu(nullptr, CreatePopupMenu())
+{
+}
+
+void QWindowsPopupMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect,
+ const QPlatformMenuItem *item)
+{
+ qCDebug(lcQpaMenus) << __FUNCTION__ << '>' << this << parentWindow << targetRect << item;
+ const QWindowsBaseWindow *window = static_cast<const QWindowsBaseWindow *>(parentWindow->handle());
+ const QPoint globalPos = window->mapToGlobal(targetRect.topLeft());
+ trackPopupMenu(window->handle(), globalPos.x(), globalPos.y());
+}
+
+bool QWindowsPopupMenu::trackPopupMenu(HWND windowHandle, int x, int y)
+{
+ lastShownPopupMenu = this;
+ return TrackPopupMenu(menuHandle(),
+ QGuiApplication::layoutDirection() == Qt::RightToLeft ? UINT(TPM_RIGHTALIGN) : UINT(0),
+ x, y, 0, windowHandle, nullptr) == TRUE;
+}
+
+bool QWindowsPopupMenu::notifyTriggered(uint id)
+{
+ QPlatformMenuItem *result = lastShownPopupMenu.isNull()
+ ? nullptr
+ : findMenuItemById(lastShownPopupMenu.data(), id);
+ if (result != nullptr) {
+ qCDebug(lcQpaMenus) << __FUNCTION__ << "id=" << id;
+ emit result->activated();
+ }
+ lastShownPopupMenu = nullptr;
+ return result != nullptr;
+}
+
+bool QWindowsPopupMenu::notifyAboutToShow(HMENU hmenu)
+{
+ if (lastShownPopupMenu.isNull())
+ return false;
+ if (lastShownPopupMenu->menuHandle() == hmenu) {
+ emit lastShownPopupMenu->aboutToShow();
+ return true;
+ }
+ if (QWindowsMenu *menu = findMenuByHandle(lastShownPopupMenu.data(), hmenu)) {
+ emit menu->aboutToShow();
+ return true;
+ }
+ return false;
+}
+
+// --------------- QWindowsMenuBar
+
+QWindowsMenuBar::QWindowsMenuBar() : m_hMenuBar(CreateMenu())
+{
+ qCDebug(lcQpaMenus) << __FUNCTION__ << static_cast<const void *>(this);
+}
+
+QWindowsMenuBar::~QWindowsMenuBar()
+{
+ qCDebug(lcQpaMenus) << __FUNCTION__ << static_cast<const void *>(this);
+ for (int m = m_menus.size() - 1; m >= 0; --m)
+ m_menus.at(m)->removeFromParent();
+ removeFromWindow();
+ DestroyMenu(m_hMenuBar);
+}
+
+void QWindowsMenuBar::insertMenu(QPlatformMenu *menuIn, QPlatformMenu *before)
+{
+ qCDebug(lcQpaMenus) << __FUNCTION__ << menuIn << "before=" << before;
+ QWindowsMenu *menu = static_cast<QWindowsMenu *>(menuIn);
+ const int index = insertBefore(&m_menus, menuIn, before);
+ menu->insertIntoMenuBar(this, index == m_menus.size() - 1, index);
+}
+
+void QWindowsMenuBar::removeMenu(QPlatformMenu *menu)
+{
+ qCDebug(lcQpaMenus) << __FUNCTION__ << '(' << menu << ')' << this;
+ const int index = indexOf(m_menus, menu);
+ if (index != -1)
+ m_menus[index]->removeFromParent();
+}
+
+// When calling handleReparent() for a QWindow instances that does not have
+// a platform window yet, set the menubar as dynamic property to be installed
+// on platform window creation.
+static const char menuBarPropertyName[] = "_q_windowsNativeMenuBar";
+
+void QWindowsMenuBar::handleReparent(QWindow *newParentWindow)
+{
+ qCDebug(lcQpaMenus) << __FUNCTION__ << '(' << newParentWindow << ')' << this;
+ if (newParentWindow == nullptr) {
+ removeFromWindow();
+ return; // Happens during Quick Controls 1 property setup
+ }
+ if (QPlatformWindow *platWin = newParentWindow->handle())
+ install(static_cast<QWindowsWindow *>(platWin));
+ else // Store for later creation, see menuBarOf()
+ newParentWindow->setProperty(menuBarPropertyName, qVariantFromValue<QObject *>(this));
+}
+
+QWindowsMenuBar *QWindowsMenuBar::menuBarOf(const QWindow *notYetCreatedWindow)
+{
+ const QVariant menuBarV = notYetCreatedWindow->property(menuBarPropertyName);
+ return menuBarV.canConvert<QObject *>()
+ ? qobject_cast<QWindowsMenuBar *>(menuBarV.value<QObject *>()) : nullptr;
+}
+
+static inline void forceNcCalcSize(HWND hwnd)
+{
+ // Force WM_NCCALCSIZE to adjust margin: Does not appear to work?
+ SetWindowPos(hwnd, 0, 0, 0, 0, 0,
+ SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
+}
+
+void QWindowsMenuBar::install(QWindowsWindow *window)
+{
+ const HWND hwnd = window->handle();
+ const BOOL result = SetMenu(hwnd, m_hMenuBar);
+ if (result) {
+ window->setMenuBar(this);
+ forceNcCalcSize(hwnd);
+ }
+}
+
+void QWindowsMenuBar::removeFromWindow()
+{
+ if (QWindowsWindow *window = platformWindow()) {
+ const HWND hwnd = window->handle();
+ SetMenu(hwnd, nullptr);
+ window->setMenuBar(nullptr);
+ forceNcCalcSize(hwnd);
+ }
+}
+
+QPlatformMenu *QWindowsMenuBar::menuForTag(quintptr tag) const
+{
+ return traverseMenus(this, [tag] (const QWindowsMenu *m) { return m->tag() == tag; });
+}
+
+QPlatformMenu *QWindowsMenuBar::createMenu() const
+{
+ QPlatformMenu *result = new QWindowsMenu;
+ qCDebug(lcQpaMenus) << __FUNCTION__ << this << "returns" << result;
+ return result;
+}
+
+bool QWindowsMenuBar::notifyTriggered(uint id)
+{
+ QPlatformMenuItem *result = findMenuItemById(this, id);
+ if (result != nullptr) {
+ qCDebug(lcQpaMenus) << __FUNCTION__ << "id=" << id;
+ emit result->activated();
+ }
+ return result != nullptr;
+}
+
+bool QWindowsMenuBar::notifyAboutToShow(HMENU hmenu)
+{
+ if (QWindowsMenu *menu = findMenuByHandle(this, hmenu)) {
+ emit menu->aboutToShow();
+ return true;
+ }
+ return false;
+}
+
+QWindowsWindow *QWindowsMenuBar::platformWindow() const
+{
+ if (const QWindowsContext *ctx = QWindowsContext::instance()) {
+ if (QWindowsWindow *w = ctx->findPlatformWindow(this))
+ return w;
+ }
+ return nullptr;
+}
+
+void QWindowsMenuBar::redraw() const
+{
+ if (const QWindowsWindow *window = platformWindow())
+ DrawMenuBar(window->handle());
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+
+template <class M> /* Menu[Item] */
+static void formatTextSequence(QDebug &d, const QVector<M *> &v)
+{
+ if (const int size = v.size()) {
+ d << '[' << size << "](";
+ for (int i = 0; i < size; ++i) {
+ if (i)
+ d << ", ";
+ if (!v.at(i)->isVisible())
+ d << "[hidden] ";
+ d << '"' << v.at(i)->text() << '"';
+ }
+ d << ')';
+ }
+}
+
+void QWindowsMenuItem::formatDebug(QDebug &d) const
+{
+ if (m_separator)
+ d << "separator, ";
+ else
+ d << '"' << m_text << "\", ";
+ d << static_cast<const void *>(this);
+ if (m_parentMenu)
+ d << ", parentMenu=" << static_cast<const void *>(m_parentMenu);
+ if (m_subMenu)
+ d << ", subMenu=" << static_cast<const void *>(m_subMenu);
+ d << ", tag=" << showbase << hex
+ << tag() << noshowbase << dec << ", id=" << m_id;
+ if (!m_shortcut.isEmpty())
+ d << ", shortcut=" << m_shortcut;
+ if (m_visible)
+ d << " [visible]";
+ if (m_enabled)
+ d << " [enabled]";
+ if (m_checkable)
+ d << ", checked=" << m_checked;
+}
+
+QDebug operator<<(QDebug d, const QPlatformMenuItem *i)
+{
+ QDebugStateSaver saver(d);
+ d.nospace();
+ d.noquote();
+ d << "QPlatformMenuItem(";
+ if (i)
+ static_cast<const QWindowsMenuItem *>(i)->formatDebug(d);
+ else
+ d << '0';
+ d << ')';
+ return d;
+}
+
+void QWindowsMenu::formatDebug(QDebug &d) const
+{
+ d << '"' << m_text << "\", " << static_cast<const void *>(this)
+ << ", handle=" << m_hMenu;
+ if (m_parentMenuBar != nullptr)
+ d << " [on menubar]";
+ if (m_parentMenu != nullptr)
+ d << " [on menu]";
+ if (tag())
+ d << ", tag=" << showbase << hex << tag() << noshowbase << dec;
+ if (m_visible)
+ d << " [visible]";
+ if (m_enabled)
+ d << " [enabled]";
+ d <<' ';
+ formatTextSequence(d, m_menuItems);
+}
+
+void QWindowsMenuBar::formatDebug(QDebug &d) const
+{
+ d << static_cast<const void *>(this) << ' ';
+ formatTextSequence(d, m_menus);
+}
+
+QDebug operator<<(QDebug d, const QPlatformMenu *m)
+{
+ QDebugStateSaver saver(d);
+ d.nospace();
+ d.noquote();
+ if (m) {
+ d << m->metaObject()->className() << '(';
+ static_cast<const QWindowsMenu *>(m)->formatDebug(d);
+ d << ')';
+ } else {
+ d << "QPlatformMenu(0)";
+ }
+ return d;
+}
+
+QDebug operator<<(QDebug d, const QPlatformMenuBar *mb)
+{
+ QDebugStateSaver saver(d);
+ d.nospace();
+ d.noquote();
+ d << "QPlatformMenuBar(";
+ if (mb)
+ static_cast<const QWindowsMenuBar *>(mb)->formatDebug(d);
+ else
+ d << '0';
+ d << ')';
+ return d;
+}
+
+#endif // !QT_NO_DEBUG_STREAM
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsmenu.h b/src/plugins/platforms/windows/qwindowsmenu.h
new file mode 100644
index 0000000000..d51a29676e
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsmenu.h
@@ -0,0 +1,243 @@
+/****************************************************************************
+**
+** 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 QWINDOWSMENU_H
+#define QWINDOWSMENU_H
+
+#include "qtwindowsglobal.h"
+
+#include <qpa/qplatformmenu.h>
+
+#include <QtCore/QVector>
+#include <QtCore/QPair>
+
+QT_BEGIN_NAMESPACE
+
+class QDebug;
+
+class QWindowsMenu;
+class QWindowsMenuBar;
+class QWindowsWindow;
+
+class QWindowsMenuItem : public QPlatformMenuItem
+{
+ Q_OBJECT
+public:
+ explicit QWindowsMenuItem(QWindowsMenu *parentMenu = nullptr);
+ ~QWindowsMenuItem();
+
+ void setText(const QString &text) override;
+ void setIcon(const QIcon &icon) override;
+ void setMenu(QPlatformMenu *menu) override;
+ void setVisible(bool isVisible) override;
+ void setIsSeparator(bool isSeparator) override;
+ void setFont(const QFont &) override {}
+ void setRole(MenuRole) override {}
+ void setCheckable(bool checkable) override;
+ void setChecked(bool isChecked) override;
+#ifndef QT_NO_SHORTCUT
+ void setShortcut(const QKeySequence& shortcut) override;
+#endif
+ void setEnabled(bool enabled) override;
+ void setIconSize(int size) override;
+
+ const QWindowsMenu *parentMenu() const { return m_parentMenu; }
+ QWindowsMenu *parentMenu() { return m_parentMenu; }
+ HMENU parentMenuHandle() const;
+ QWindowsMenu *subMenu() const { return m_subMenu; }
+ UINT_PTR id() const { return m_id; }
+ void setId(uint id) { m_id = id; }
+ UINT state() const;
+ QString text() const { return m_text; }
+ QString nativeText() const;
+ bool isVisible() const { return m_visible; }
+
+ void insertIntoMenu(QWindowsMenu *menuItem, bool append, int index);
+ bool removeFromMenu();
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const;
+#endif
+
+private:
+ void updateBitmap();
+ void freeBitmap();
+ void updateText();
+ void insertIntoMenuHelper(QWindowsMenu *menu, bool append, int index);
+
+ QWindowsMenu *m_parentMenu = nullptr;
+ QWindowsMenu *m_subMenu = nullptr;
+ UINT_PTR m_id; // Windows Id sent as wParam with WM_COMMAND or submenu handle.
+ QString m_text;
+ QIcon m_icon;
+ HBITMAP m_hbitmap = nullptr;
+ int m_iconSize = 0;
+ bool m_separator = false;
+ bool m_visible = true;
+ bool m_checkable = false;
+ bool m_checked = false;
+ bool m_enabled = true;
+ QKeySequence m_shortcut;
+};
+
+class QWindowsMenu : public QPlatformMenu
+{
+ Q_OBJECT
+public:
+ typedef QVector<QWindowsMenuItem *> MenuItems;
+
+ QWindowsMenu();
+ ~QWindowsMenu();
+
+ void insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before) override;
+ void removeMenuItem(QPlatformMenuItem *menuItem) override;
+ void syncMenuItem(QPlatformMenuItem *) override {}
+ void syncSeparatorsCollapsible(bool) override {}
+
+ void setText(const QString &text) override;
+ void setIcon(const QIcon &icon) override;
+ void setEnabled(bool enabled) override;
+ bool isEnabled() const override { return m_enabled; }
+ void setVisible(bool visible) override;
+
+ QPlatformMenuItem *menuItemAt(int position) const override;
+ QPlatformMenuItem *menuItemForTag(quintptr tag) const override;
+
+ QPlatformMenuItem *createMenuItem() const override;
+ QPlatformMenu *createSubMenu() const override;
+
+ HMENU menuHandle() const { return m_hMenu; }
+ UINT_PTR id() const { return reinterpret_cast<UINT_PTR>(m_hMenu); }
+ QString text() const { return m_text; }
+ const MenuItems &menuItems() const { return m_menuItems; }
+ QWindowsMenuItem *itemForSubMenu(const QWindowsMenu *subMenu) const;
+
+ const QWindowsMenuBar *parentMenuBar() const { return m_parentMenuBar; }
+ HMENU parentMenuBarHandle() const;
+ const QWindowsMenu *parentMenu() const { return m_parentMenu; }
+ void setAsItemSubMenu(QWindowsMenuItem *item);
+ void notifyRemoved(QWindowsMenuItem *item) { m_menuItems.removeOne(item); }
+ HMENU parentMenuHandle() const;
+ HMENU parentHandle() const;
+ bool isVisible() const { return m_visible; }
+ void insertIntoMenuBar(QWindowsMenuBar *bar, bool append, int index);
+ bool removeFromParent();
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const;
+#endif
+
+protected:
+ explicit QWindowsMenu(QWindowsMenu *parentMenu, HMENU menu);
+
+private:
+ QWindowsMenuBar *m_parentMenuBar = nullptr;
+ QWindowsMenu *m_parentMenu = nullptr;
+ MenuItems m_menuItems;
+ HMENU m_hMenu = nullptr;
+ QString m_text;
+ QIcon m_icon;
+ bool m_visible = true;
+ bool m_enabled = true;
+};
+
+class QWindowsPopupMenu : public QWindowsMenu
+{
+ Q_OBJECT
+public:
+ QWindowsPopupMenu();
+
+ static bool notifyTriggered(uint id);
+ static bool notifyAboutToShow(HMENU hmenu);
+
+ void showPopup(const QWindow *parentWindow, const QRect &targetRect, const QPlatformMenuItem *item) override;
+ void dismiss() override {}
+
+ bool trackPopupMenu(HWND windowHandle, int x, int y);
+};
+
+class QWindowsMenuBar : public QPlatformMenuBar
+{
+ Q_OBJECT
+public:
+ typedef QVector<QWindowsMenu *> Menus;
+
+ QWindowsMenuBar();
+ ~QWindowsMenuBar();
+
+ void insertMenu(QPlatformMenu *menu, QPlatformMenu *before) override;
+ void removeMenu(QPlatformMenu *menu) override;
+ void syncMenu(QPlatformMenu *) override {}
+ void handleReparent(QWindow *newParentWindow) override;
+
+ QPlatformMenu *menuForTag(quintptr tag) const override;
+ QPlatformMenu *createMenu() const override;
+
+ HMENU menuBarHandle() const { return m_hMenuBar; }
+ const Menus &menus() const { return m_menus; }
+ bool notifyTriggered(uint id);
+ bool notifyAboutToShow(HMENU hmenu);
+ void notifyRemoved(QWindowsMenu *menu) { m_menus.removeOne(menu); }
+ void redraw() const;
+
+ void install(QWindowsWindow *window);
+
+ static QWindowsMenuBar *menuBarOf(const QWindow *notYetCreatedWindow);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const;
+#endif
+
+private:
+ QWindowsWindow *platformWindow() const;
+ void removeFromWindow();
+
+ Menus m_menus;
+ HMENU m_hMenuBar = nullptr;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const QPlatformMenuItem *);
+QDebug operator<<(QDebug d, const QPlatformMenu *);
+QDebug operator<<(QDebug d, const QPlatformMenuBar *);
+#endif // !QT_NO_DEBUG_STREAM
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSMENU_H
diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmime.cpp
index 9c9382c44c..b892f1610d 100644
--- a/src/plugins/platforms/windows/qwindowsmime.cpp
+++ b/src/plugins/platforms/windows/qwindowsmime.cpp
@@ -41,6 +41,7 @@
#include "qwindowscontext.h"
#include <QtGui/private/qdnd_p.h>
+#include <QtCore/QByteArrayMatcher>
#include <QtCore/QTextCodec>
#include <QtCore/QMap>
#include <QtCore/QUrl>
@@ -955,9 +956,11 @@ QVariant QWindowsMimeHtml::convertToMime(const QString &mime, IDataObject *pData
QVariant result;
if (canConvertToMime(mime, pDataObj)) {
QByteArray html = getData(CF_HTML, pDataObj);
+ static Q_RELAXED_CONSTEXPR auto startMatcher = qMakeStaticByteArrayMatcher("StartHTML:");
+ static Q_RELAXED_CONSTEXPR auto endMatcher = qMakeStaticByteArrayMatcher("EndHTML:");
qCDebug(lcQpaMime) << __FUNCTION__ << "raw:" << html;
- int start = html.indexOf("StartHTML:");
- int end = html.indexOf("EndHTML:");
+ int start = startMatcher.indexIn(html);
+ int end = endMatcher.indexIn(html);
if (start != -1) {
int startOffset = start + 10;
@@ -997,10 +1000,13 @@ bool QWindowsMimeHtml::convertFromMime(const FORMATETC &formatetc, const QMimeDa
"StartFragment:0000000000\r\n" // 56-81
"EndFragment:0000000000\r\n\r\n"; // 82-107
- if (data.indexOf("<!--StartFragment-->") == -1)
+ static Q_RELAXED_CONSTEXPR auto startFragmentMatcher = qMakeStaticByteArrayMatcher("<!--StartFragment-->");
+ static Q_RELAXED_CONSTEXPR auto endFragmentMatcher = qMakeStaticByteArrayMatcher("<!--EndFragment-->");
+
+ if (startFragmentMatcher.indexIn(data) == -1)
result += "<!--StartFragment-->";
result += data;
- if (data.indexOf("<!--EndFragment-->") == -1)
+ if (endFragmentMatcher.indexIn(data) == -1)
result += "<!--EndFragment-->";
// set the correct number for EndHTML
@@ -1008,9 +1014,9 @@ bool QWindowsMimeHtml::convertFromMime(const FORMATETC &formatetc, const QMimeDa
memcpy(reinterpret_cast<char *>(result.data() + 53 - pos.length()), pos.constData(), size_t(pos.length()));
// set correct numbers for StartFragment and EndFragment
- pos = QByteArray::number(result.indexOf("<!--StartFragment-->") + 20);
+ pos = QByteArray::number(startFragmentMatcher.indexIn(result) + 20);
memcpy(reinterpret_cast<char *>(result.data() + 79 - pos.length()), pos.constData(), size_t(pos.length()));
- pos = QByteArray::number(result.indexOf("<!--EndFragment-->"));
+ pos = QByteArray::number(endFragmentMatcher.indexIn(result));
memcpy(reinterpret_cast<char *>(result.data() + 103 - pos.length()), pos.constData(), size_t(pos.length()));
return setData(result, pmedium);
diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp
index 0cabb66bca..9544fb81f7 100644
--- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp
+++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp
@@ -60,7 +60,7 @@
* are present in the Windows SDK's, but not in older MSVC Express
* versions. */
-#if defined(Q_CC_MINGW) || !defined(TOUCHEVENTF_MOVE)
+#if !defined(TOUCHEVENTF_MOVE)
typedef struct tagTOUCHINPUT {
LONG x;
@@ -85,7 +85,7 @@ typedef TOUCHINPUT const * PCTOUCHINPUT;
# define TOUCHEVENTF_PALM 0x0080
# define TOUCHINPUTMASKF_CONTACTAREA 0x0004
# define TOUCHINPUTMASKF_EXTRAINFO 0x0002
-#endif // if defined(Q_CC_MINGW) || !defined(TOUCHEVENTF_MOVE)
+#endif // if !defined(TOUCHEVENTF_MOVE)
QT_BEGIN_NAMESPACE
@@ -574,7 +574,8 @@ bool QWindowsMouseHandler::translateTouchEvent(QWindow *window, HWND,
QWindowSystemInterface::handleTouchEvent(window,
m_touchDevice,
- touchPoints);
+ touchPoints,
+ QWindowsKeyMapper::queryKeyboardModifiers());
return true;
}
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/qwindowssystemtrayicon.cpp b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp
new file mode 100644
index 0000000000..901d132ea5
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp
@@ -0,0 +1,443 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#if defined(WINVER) && WINVER < 0x0601
+# undef WINVER
+#endif
+#if !defined(WINVER)
+# define WINVER 0x0601 // required for NOTIFYICONDATA_V2_SIZE, ChangeWindowMessageFilterEx() (MinGW 5.3)
+#endif
+
+#if defined(NTDDI_VERSION) && NTDDI_VERSION < 0x06010000
+# undef NTDDI_VERSION
+#endif
+#if !defined(NTDDI_VERSION)
+# define NTDDI_VERSION 0x06010000 // required for Shell_NotifyIconGetRect (MinGW 5.3)
+#endif
+
+#include "qwindowssystemtrayicon.h"
+#include "qwindowscontext.h"
+#include "qwindowstheme.h"
+#include "qwindowsmenu.h"
+#include "qwindowsscreen.h"
+
+#include <QtGui/qpixmap.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qsettings.h>
+
+#include <qt_windows.h>
+#include <commctrl.h>
+#include <shellapi.h>
+#include <shlobj.h>
+#include <windowsx.h>
+
+QT_BEGIN_NAMESPACE
+
+static const UINT q_uNOTIFYICONID = 0;
+
+static uint MYWM_TASKBARCREATED = 0;
+#define MYWM_NOTIFYICON (WM_APP+101)
+
+Q_GUI_EXPORT HICON qt_pixmapToWinHICON(const QPixmap &);
+
+// Copy QString data to a limited wchar_t array including \0.
+static inline void qStringToLimitedWCharArray(QString in, wchar_t *target, int maxLength)
+{
+ const int length = qMin(maxLength - 1, in.size());
+ if (length < in.size())
+ in.truncate(length);
+ in.toWCharArray(target);
+ target[length] = wchar_t(0);
+}
+
+static inline void initNotifyIconData(NOTIFYICONDATA &tnd)
+{
+ memset(&tnd, 0, sizeof(NOTIFYICONDATA));
+ tnd.cbSize = sizeof(NOTIFYICONDATA);
+ tnd.uVersion = NOTIFYICON_VERSION_4;
+}
+
+static void setIconContents(NOTIFYICONDATA &tnd, const QString &tip, HICON hIcon)
+{
+ tnd.uFlags |= NIF_MESSAGE | NIF_ICON | NIF_TIP;
+ tnd.uCallbackMessage = MYWM_NOTIFYICON;
+ tnd.hIcon = hIcon;
+ qStringToLimitedWCharArray(tip, tnd.szTip, sizeof(tnd.szTip) / sizeof(wchar_t));
+}
+
+// Match the HWND of the dummy window to the instances
+struct QWindowsHwndSystemTrayIconEntry
+{
+ HWND hwnd;
+ QWindowsSystemTrayIcon *trayIcon;
+};
+
+typedef QVector<QWindowsHwndSystemTrayIconEntry> HwndTrayIconEntries;
+
+Q_GLOBAL_STATIC(HwndTrayIconEntries, hwndTrayIconEntries)
+
+static int indexOfHwnd(HWND hwnd)
+{
+ const HwndTrayIconEntries *entries = hwndTrayIconEntries();
+ for (int i = 0, size = entries->size(); i < size; ++i) {
+ if (entries->at(i).hwnd == hwnd)
+ return i;
+ }
+ return -1;
+}
+
+extern "C" LRESULT QT_WIN_CALLBACK qWindowsTrayIconWndProc(HWND hwnd, UINT message,
+ WPARAM wParam, LPARAM lParam)
+{
+ if (message == MYWM_TASKBARCREATED || message == MYWM_NOTIFYICON
+ || message == WM_INITMENU || message == WM_INITMENUPOPUP
+ || message == WM_COMMAND) {
+ const int index = indexOfHwnd(hwnd);
+ if (index >= 0) {
+ MSG msg;
+ msg.hwnd = hwnd; // re-create MSG structure
+ msg.message = message; // time and pt fields ignored
+ msg.wParam = wParam;
+ msg.lParam = lParam;
+ msg.pt.x = GET_X_LPARAM(lParam);
+ msg.pt.y = GET_Y_LPARAM(lParam);
+ long result = 0;
+ if (hwndTrayIconEntries()->at(index).trayIcon->winEvent(msg, &result))
+ return result;
+ }
+ }
+ return DefWindowProc(hwnd, message, wParam, lParam);
+}
+
+// Note: Message windows (HWND_MESSAGE) are not sufficient, they
+// will not receive the "TaskbarCreated" message.
+static inline HWND createTrayIconMessageWindow()
+{
+ QWindowsContext *ctx = QWindowsContext::instance();
+ if (!ctx)
+ return 0;
+ // Register window class in the platform plugin.
+ const QString className =
+ ctx->registerWindowClass(QStringLiteral("QTrayIconMessageWindowClass"),
+ qWindowsTrayIconWndProc);
+ const wchar_t windowName[] = L"QTrayIconMessageWindow";
+ return CreateWindowEx(0, reinterpret_cast<const wchar_t *>(className.utf16()),
+ windowName, WS_OVERLAPPED,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ CW_USEDEFAULT, CW_USEDEFAULT,
+ NULL, NULL, (HINSTANCE)GetModuleHandle(0), NULL);
+}
+
+/*!
+ \class QWindowsSystemTrayIcon
+ \brief Windows native system tray icon
+
+ \internal
+ \ingroup qt-lighthouse-win
+*/
+
+QWindowsSystemTrayIcon::QWindowsSystemTrayIcon()
+{
+ // For restoring the tray icon after explorer crashes
+ if (!MYWM_TASKBARCREATED)
+ MYWM_TASKBARCREATED = RegisterWindowMessage(L"TaskbarCreated");
+ // Allow the WM_TASKBARCREATED message through the UIPI filter
+ ChangeWindowMessageFilterEx(m_hwnd, MYWM_TASKBARCREATED, MSGFLT_ALLOW, 0);
+ qCDebug(lcQpaTrayIcon) << __FUNCTION__ << this << "MYWM_TASKBARCREATED=" << MYWM_TASKBARCREATED;
+}
+
+QWindowsSystemTrayIcon::~QWindowsSystemTrayIcon()
+{
+ qCDebug(lcQpaTrayIcon) << __FUNCTION__ << this;
+ ensureCleanup();
+}
+
+void QWindowsSystemTrayIcon::init()
+{
+ qCDebug(lcQpaTrayIcon) << __FUNCTION__ << this;
+ ensureInstalled();
+}
+
+void QWindowsSystemTrayIcon::cleanup()
+{
+ qCDebug(lcQpaTrayIcon) << __FUNCTION__ << this;
+ ensureCleanup();
+}
+
+void QWindowsSystemTrayIcon::updateIcon(const QIcon &icon)
+{
+ qCDebug(lcQpaTrayIcon) << __FUNCTION__ << '(' << icon << ')' << this;
+ if (icon.cacheKey() == m_icon.cacheKey())
+ return;
+ const HICON hIconToDestroy = createIcon(icon);
+ if (ensureInstalled())
+ sendTrayMessage(NIM_MODIFY);
+ if (hIconToDestroy)
+ DestroyIcon(hIconToDestroy);
+}
+
+void QWindowsSystemTrayIcon::updateToolTip(const QString &tooltip)
+{
+ qCDebug(lcQpaTrayIcon) << __FUNCTION__ << '(' << tooltip << ')' << this;
+ if (m_toolTip == tooltip)
+ return;
+ m_toolTip = tooltip;
+ if (isInstalled())
+ sendTrayMessage(NIM_MODIFY);
+}
+
+QRect QWindowsSystemTrayIcon::geometry() const
+{
+ NOTIFYICONIDENTIFIER nid;
+ memset(&nid, 0, sizeof(nid));
+ nid.cbSize = sizeof(nid);
+ nid.hWnd = m_hwnd;
+ nid.uID = q_uNOTIFYICONID;
+ RECT rect;
+ const QRect result = SUCCEEDED(Shell_NotifyIconGetRect(&nid, &rect))
+ ? QRect(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top)
+ : QRect();
+ qCDebug(lcQpaTrayIcon) << __FUNCTION__ << this << "returns" << result;
+ return result;
+}
+
+void QWindowsSystemTrayIcon::showMessage(const QString &title, const QString &messageIn,
+ const QIcon &icon,
+ QPlatformSystemTrayIcon::MessageIcon iconType,
+ int msecsIn)
+{
+ qCDebug(lcQpaTrayIcon) << __FUNCTION__ << '(' << title << messageIn << icon
+ << iconType << msecsIn << ')' << this;
+ if (!supportsMessages())
+ return;
+ // For empty messages, ensures that they show when only title is set
+ QString message = messageIn;
+ if (message.isEmpty() && !title.isEmpty())
+ message.append(QLatin1Char(' '));
+
+ NOTIFYICONDATA tnd;
+ initNotifyIconData(tnd);
+ qStringToLimitedWCharArray(message, tnd.szInfo, 256);
+ qStringToLimitedWCharArray(title, tnd.szInfoTitle, 64);
+
+ tnd.uID = q_uNOTIFYICONID;
+ tnd.dwInfoFlags = NIIF_USER;
+
+ QSize size(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON));
+ const QSize largeIcon(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON));
+ const QSize more = icon.actualSize(largeIcon);
+ if (more.height() > (largeIcon.height() * 3/4) || more.width() > (largeIcon.width() * 3/4)) {
+ tnd.dwInfoFlags |= NIIF_LARGE_ICON;
+ size = largeIcon;
+ }
+ QPixmap pm = icon.pixmap(size);
+ if (pm.isNull()) {
+ tnd.dwInfoFlags = NIIF_INFO;
+ } else {
+ if (pm.size() != size) {
+ qWarning("QSystemTrayIcon::showMessage: Wrong icon size (%dx%d), please add standard one: %dx%d",
+ pm.size().width(), pm.size().height(), size.width(), size.height());
+ pm = pm.scaled(size, Qt::IgnoreAspectRatio);
+ }
+ tnd.hBalloonIcon = qt_pixmapToWinHICON(pm);
+ }
+ tnd.hWnd = m_hwnd;
+ tnd.uTimeout = msecsIn <= 0 ? UINT(10000) : UINT(msecsIn); // 10s default
+ tnd.uFlags = NIF_INFO | NIF_SHOWTIP;
+
+ Shell_NotifyIcon(NIM_MODIFY, &tnd);
+}
+
+bool QWindowsSystemTrayIcon::supportsMessages() const
+{
+ // The key does typically not exist on Windows 10, default to true.
+ return QWindowsContext::readAdvancedExplorerSettings(L"EnableBalloonTips", 1) != 0;
+}
+
+QPlatformMenu *QWindowsSystemTrayIcon::createMenu() const
+{
+ if (QWindowsTheme::useNativeMenus() && m_menu.isNull())
+ m_menu = new QWindowsPopupMenu;
+ qCDebug(lcQpaTrayIcon) << __FUNCTION__ << this << "returns" << m_menu.data();
+ return m_menu.data();
+}
+
+// Delay-install until an Icon exists
+bool QWindowsSystemTrayIcon::ensureInstalled()
+{
+ if (isInstalled())
+ return true;
+ if (m_hIcon == nullptr)
+ return false;
+ m_hwnd = createTrayIconMessageWindow();
+ if (Q_UNLIKELY(m_hwnd == nullptr))
+ return false;
+ QWindowsHwndSystemTrayIconEntry entry{m_hwnd, this};
+ hwndTrayIconEntries()->append(entry);
+ sendTrayMessage(NIM_ADD);
+ return true;
+}
+
+void QWindowsSystemTrayIcon::ensureCleanup()
+{
+ if (isInstalled()) {
+ const int index = indexOfHwnd(m_hwnd);
+ if (index >= 0)
+ hwndTrayIconEntries()->removeAt(index);
+ sendTrayMessage(NIM_DELETE);
+ DestroyWindow(m_hwnd);
+ m_hwnd = nullptr;
+ }
+ if (m_hIcon != nullptr)
+ DestroyIcon(m_hIcon);
+ m_hIcon = nullptr;
+ m_menu = nullptr; // externally owned
+ m_toolTip.clear();
+}
+
+bool QWindowsSystemTrayIcon::sendTrayMessage(DWORD msg)
+{
+ NOTIFYICONDATA tnd;
+ initNotifyIconData(tnd);
+ tnd.uID = q_uNOTIFYICONID;
+ tnd.hWnd = m_hwnd;
+ tnd.uFlags = NIF_SHOWTIP;
+ if (msg == NIM_ADD || msg == NIM_MODIFY)
+ setIconContents(tnd, m_toolTip, m_hIcon);
+ if (!Shell_NotifyIcon(msg, &tnd))
+ return false;
+ return msg != NIM_ADD || Shell_NotifyIcon(NIM_SETVERSION, &tnd);
+}
+
+// Return the old icon to be freed after modifying the tray icon.
+HICON QWindowsSystemTrayIcon::createIcon(const QIcon &icon)
+{
+ const HICON oldIcon = m_hIcon;
+ m_hIcon = nullptr;
+ if (icon.isNull())
+ return oldIcon;
+ const QSize requestedSize = QSize(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON));
+ const QSize size = icon.actualSize(requestedSize);
+ const QPixmap pm = icon.pixmap(size);
+ if (!pm.isNull())
+ m_hIcon = qt_pixmapToWinHICON(pm);
+ return oldIcon;
+}
+
+bool QWindowsSystemTrayIcon::winEvent(const MSG &message, long *result)
+{
+ *result = 0;
+ switch (message.message) {
+ case MYWM_NOTIFYICON: {
+ Q_ASSERT(q_uNOTIFYICONID == HIWORD(message.lParam));
+ const int trayMessage = LOWORD(message.lParam);
+ switch (trayMessage) {
+ case NIN_SELECT:
+ case NIN_KEYSELECT:
+ if (m_ignoreNextMouseRelease)
+ m_ignoreNextMouseRelease = false;
+ else
+ emit activated(Trigger);
+ break;
+ case WM_LBUTTONDBLCLK:
+ m_ignoreNextMouseRelease = true; // Since DBLCLICK Generates a second mouse
+ emit activated(DoubleClick); // release we must ignore it
+ break;
+ case WM_CONTEXTMENU: {
+ const QPoint globalPos = QPoint(GET_X_LPARAM(message.wParam), GET_Y_LPARAM(message.wParam));
+ const QPlatformScreen *screen = QWindowsContext::instance()->screenManager().screenAtDp(globalPos);
+ emit contextMenuRequested(globalPos, screen);
+ emit activated(Context);
+ if (m_menu)
+ m_menu->trackPopupMenu(message.hwnd, globalPos.x(), globalPos.y());
+ }
+ break;
+ case NIN_BALLOONUSERCLICK:
+ emit messageClicked();
+ break;
+ case WM_MBUTTONUP:
+ emit activated(MiddleClick);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case WM_INITMENU:
+ case WM_INITMENUPOPUP:
+ QWindowsPopupMenu::notifyAboutToShow(reinterpret_cast<HMENU>(message.wParam));
+ break;
+ case WM_COMMAND:
+ QWindowsPopupMenu::notifyTriggered(LOWORD(message.wParam));
+ break;
+ default:
+ if (message.message == MYWM_TASKBARCREATED) // self-registered message id (tray crashed)
+ sendTrayMessage(NIM_ADD);
+ break;
+ }
+ return false;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+
+void QWindowsSystemTrayIcon::formatDebug(QDebug &d) const
+{
+ d << static_cast<const void *>(this) << ", \"" << m_toolTip
+ << "\", hwnd=" << m_hwnd << ", m_hIcon=" << m_hIcon << ", menu="
+ << m_menu.data();
+}
+
+QDebug operator<<(QDebug d, const QWindowsSystemTrayIcon *t)
+{
+ QDebugStateSaver saver(d);
+ d.nospace();
+ d.noquote();
+ d << "QWindowsSystemTrayIcon(";
+ if (t)
+ t->formatDebug(d);
+ else
+ d << '0';
+ d << ')';
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowssystemtrayicon.h b/src/plugins/platforms/windows/qwindowssystemtrayicon.h
new file mode 100644
index 0000000000..1f696180cd
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowssystemtrayicon.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** 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 QWINDOWSSYSTEMTRAYICON_H
+#define QWINDOWSSYSTEMTRAYICON_H
+
+#include <QtGui/qicon.h>
+#include <QtGui/qpa/qplatformsystemtrayicon.h>
+
+#include <QtCore/qpointer.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qt_windows.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDebug;
+
+class QWindowsPopupMenu;
+
+class QWindowsSystemTrayIcon : public QPlatformSystemTrayIcon
+{
+public:
+ QWindowsSystemTrayIcon();
+ ~QWindowsSystemTrayIcon();
+
+ void init() override;
+ void cleanup() override;
+ void updateIcon(const QIcon &icon) override;
+ void updateToolTip(const QString &tooltip) override;
+ void updateMenu(QPlatformMenu *) override {}
+ QRect geometry() const override;
+ void showMessage(const QString &title, const QString &msg,
+ const QIcon &icon, MessageIcon iconType, int msecs) override;
+
+ bool isSystemTrayAvailable() const override { return true; }
+ bool supportsMessages() const override;
+
+ QPlatformMenu *createMenu() const override;
+
+ bool winEvent(const MSG &message, long *result);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const;
+#endif
+
+private:
+ bool isInstalled() const { return m_hwnd != nullptr; }
+ bool ensureInstalled();
+ void ensureCleanup();
+ bool sendTrayMessage(DWORD msg);
+ HICON createIcon(const QIcon &icon);
+
+ QIcon m_icon;
+ QString m_toolTip;
+ HWND m_hwnd = nullptr;
+ HICON m_hIcon = nullptr;
+ mutable QPointer<QWindowsPopupMenu> m_menu;
+ bool m_ignoreNextMouseRelease = false;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const QWindowsSystemTrayIcon *);
+#endif // !QT_NO_DEBUG_STREAM
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSSYSTEMTRAYICON_H
diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.cpp b/src/plugins/platforms/windows/qwindowstabletsupport.cpp
index 5fe58fbfa5..fba4e8f386 100644
--- a/src/plugins/platforms/windows/qwindowstabletsupport.cpp
+++ b/src/plugins/platforms/windows/qwindowstabletsupport.cpp
@@ -473,13 +473,13 @@ bool QWindowsTabletSupport::translateTabletPacketEvent()
// Z = sin(altitude)
// X Tilt = arctan(X / Z)
// Y Tilt = arctan(Y / Z)
- const double radAzim = (packet.pkOrientation.orAzimuth / 10.0) * (M_PI / 180);
- const double tanAlt = std::tan((std::abs(packet.pkOrientation.orAltitude / 10.0)) * (M_PI / 180));
+ const double radAzim = qDegreesToRadians(packet.pkOrientation.orAzimuth / 10.0);
+ const double tanAlt = std::tan(qDegreesToRadians(std::abs(packet.pkOrientation.orAltitude / 10.0)));
- const double degX = std::atan(std::sin(radAzim) / tanAlt);
- const double degY = std::atan(std::cos(radAzim) / tanAlt);
- tiltX = int(degX * (180 / M_PI));
- tiltY = int(-degY * (180 / M_PI));
+ const double radX = std::atan(std::sin(radAzim) / tanAlt);
+ const double radY = std::atan(std::cos(radAzim) / tanAlt);
+ tiltX = int(qRadiansToDegrees(radX));
+ tiltY = int(qRadiansToDegrees(-radY));
rotation = 360.0 - (packet.pkOrientation.orTwist / 10.0);
if (rotation > 180.0)
rotation -= 360.0;
diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp
index 7916211219..651c661d6b 100644
--- a/src/plugins/platforms/windows/qwindowstheme.cpp
+++ b/src/plugins/platforms/windows/qwindowstheme.cpp
@@ -38,15 +38,19 @@
****************************************************************************/
// SHSTOCKICONINFO is only available since Vista
-#if _WIN32_WINNT < 0x0600
+#if _WIN32_WINNT < 0x0601
# undef _WIN32_WINNT
-# define _WIN32_WINNT 0x0600
+# define _WIN32_WINNT 0x0601
#endif
#include "qwindowstheme.h"
+#include "qwindowsmenu.h"
#include "qwindowsdialoghelpers.h"
#include "qwindowscontext.h"
#include "qwindowsintegration.h"
+#if QT_CONFIG(systemtrayicon)
+# include "qwindowssystemtrayicon.h"
+#endif
#include "qt_windows.h"
#include <commctrl.h>
#include <objbase.h>
@@ -415,13 +419,7 @@ static inline QStringList iconThemeSearchPaths()
static inline QStringList styleNames()
{
- QStringList result;
- if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA)
- result.append(QStringLiteral("WindowsVista"));
- if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP)
- result.append(QStringLiteral("WindowsXP"));
- result.append(QStringLiteral("Windows"));
- return result;
+ return { QStringLiteral("WindowsVista"), QStringLiteral("Windows") };
}
static inline int uiEffects()
@@ -554,6 +552,13 @@ QPlatformDialogHelper *QWindowsTheme::createPlatformDialogHelper(DialogType type
return QWindowsDialogs::createHelper(type);
}
+#if QT_CONFIG(systemtrayicon)
+QPlatformSystemTrayIcon *QWindowsTheme::createPlatformSystemTrayIcon() const
+{
+ return new QWindowsSystemTrayIcon;
+}
+#endif
+
void QWindowsTheme::windowsThemeChanged(QWindow * window)
{
refresh();
@@ -922,4 +927,55 @@ QIcon QWindowsTheme::fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOpt
return QIcon(new QWindowsFileIconEngine(fileInfo, iconOptions));
}
+static inline bool doUseNativeMenus()
+{
+ const unsigned options = QWindowsIntegration::instance()->options();
+ if ((options & QWindowsIntegration::NoNativeMenus) != 0)
+ return false;
+ if ((options & QWindowsIntegration::AlwaysUseNativeMenus) != 0)
+ return true;
+ // "Auto" mode: For non-widget or Quick Controls 2 applications
+ if (!QCoreApplication::instance()->inherits("QApplication"))
+ return true;
+ const QWindowList &topLevels = QGuiApplication::topLevelWindows();
+ for (const QWindow *t : topLevels) {
+ if (t->inherits("QQuickApplicationWindow"))
+ return true;
+ }
+ return false;
+}
+
+bool QWindowsTheme::useNativeMenus()
+{
+ static const bool result = doUseNativeMenus();
+ return result;
+}
+
+QPlatformMenuItem *QWindowsTheme::createPlatformMenuItem() const
+{
+ qCDebug(lcQpaMenus) << __FUNCTION__;
+ return QWindowsTheme::useNativeMenus() ? new QWindowsMenuItem : nullptr;
+}
+
+QPlatformMenu *QWindowsTheme::createPlatformMenu() const
+{
+ qCDebug(lcQpaMenus) << __FUNCTION__;
+ // We create a popup menu here, since it will likely be used as context
+ // menu. Submenus should be created the factory functions of
+ // QPlatformMenu/Bar. Note though that Quick Controls 1 will use this
+ // function for submenus as well, but this has been found to work.
+ return QWindowsTheme::useNativeMenus() ? new QWindowsPopupMenu : nullptr;
+}
+
+QPlatformMenuBar *QWindowsTheme::createPlatformMenuBar() const
+{
+ qCDebug(lcQpaMenus) << __FUNCTION__;
+ return QWindowsTheme::useNativeMenus() ? new QWindowsMenuBar : nullptr;
+}
+
+void QWindowsTheme::showPlatformMenuBar()
+{
+ qCDebug(lcQpaMenus) << __FUNCTION__;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h
index a3019ff6eb..237e8158fa 100644
--- a/src/plugins/platforms/windows/qwindowstheme.h
+++ b/src/plugins/platforms/windows/qwindowstheme.h
@@ -59,6 +59,9 @@ public:
bool usePlatformNativeDialog(DialogType type) const override;
QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const override;
+#if QT_CONFIG(systemtrayicon)
+ QPlatformSystemTrayIcon *createPlatformSystemTrayIcon() const override;
+#endif
QVariant themeHint(ThemeHint) const override;
const QPalette *palette(Palette type = SystemPalette) const override
{ return m_palettes[type]; }
@@ -74,6 +77,13 @@ public:
QList<QSize> availableFileIconSizes() const { return m_fileIconSizes; }
+ QPlatformMenuItem *createPlatformMenuItem() const override;
+ QPlatformMenu *createPlatformMenu() const override;
+ QPlatformMenuBar *createPlatformMenuBar() const override;
+ void showPlatformMenuBar() override;
+
+ static bool useNativeMenus();
+
static const char *name;
private:
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 402009c70d..1d81fa9cd5 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -44,6 +44,7 @@
#endif
#include "qwindowsscreen.h"
#include "qwindowsintegration.h"
+#include "qwindowsmenu.h"
#include "qwindowsnativeinterface.h"
#if QT_CONFIG(dynamicgl)
# include "qwindowsglcontext.h"
@@ -70,8 +71,14 @@
#include <dwmapi.h>
+#if QT_CONFIG(vulkan)
+#include "qwindowsvulkaninstance.h"
+#endif
+
QT_BEGIN_NAMESPACE
+typedef QSharedPointer<QWindowCreationContext> QWindowCreationContextPtr;
+
enum {
defaultWindowWidth = 160,
defaultWindowHeight = 160
@@ -227,6 +234,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
@@ -294,13 +318,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;
}
@@ -361,11 +387,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);
@@ -379,13 +405,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);
}
/*!
@@ -598,8 +624,6 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag
QWindowsWindowData
WindowCreationData::create(const QWindow *w, const WindowData &data, QString title) const
{
- typedef QSharedPointer<QWindowCreationContext> QWindowCreationContextPtr;
-
WindowData result;
result.flags = flags;
@@ -617,7 +641,7 @@ QWindowsWindowData
// Capture events before CreateWindowEx() returns. The context is cleared in
// the QWindowsWindow constructor.
- const QWindowCreationContextPtr context(new QWindowCreationContext(w, rect, data.customMargins, style, exStyle));
+ const QWindowCreationContextPtr context(new QWindowCreationContext(w, data.geometry, rect, data.customMargins, style, exStyle));
QWindowsContext::instance()->setWindowCreationContext(context);
qCDebug(lcQpaWindows).nospace()
@@ -672,7 +696,7 @@ void WindowCreationData::initialize(const QWindow *w, HWND hwnd, bool frameChang
{
if (!hwnd)
return;
- UINT swpFlags = SWP_NOMOVE | SWP_NOSIZE;
+ UINT swpFlags = SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER;
if (frameChange)
swpFlags |= SWP_FRAMECHANGED;
if (topLevel) {
@@ -985,10 +1009,11 @@ void QWindowsForeignWindow::setVisible(bool visible)
*/
QWindowCreationContext::QWindowCreationContext(const QWindow *w,
- const QRect &geometry,
+ const QRect &geometryIn, const QRect &geometry,
const QMargins &cm,
DWORD style_, DWORD exStyle_) :
geometryHint(w, cm), window(w), style(style_), exStyle(exStyle_),
+ requestedGeometryIn(geometryIn),
requestedGeometry(geometry), obtainedGeometry(geometry),
margins(QWindowsGeometryHint::frame(style, exStyle)), customMargins(cm)
{
@@ -1002,6 +1027,8 @@ QWindowCreationContext::QWindowCreationContext(const QWindow *w,
const QMargins effectiveMargins = margins + customMargins;
frameWidth = effectiveMargins.left() + geometry.width() + effectiveMargins.right();
frameHeight = effectiveMargins.top() + geometry.height() + effectiveMargins.bottom();
+ if (QWindowsMenuBar::menuBarOf(w) != nullptr)
+ frameHeight += GetSystemMetrics(SM_CYMENU);
const bool isDefaultPosition = !frameX && !frameY && w->isTopLevel();
if (!QWindowsGeometryHint::positionIncludesFrame(w) && !isDefaultPosition) {
frameX -= effectiveMargins.left();
@@ -1047,9 +1074,10 @@ 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>());
QWindowsContext::instance()->addWindow(m_data.hwnd, this);
const Qt::WindowType type = aWindow->type();
if (type == Qt::Desktop)
@@ -1062,13 +1090,20 @@ 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);
+
+ setMask(QHighDpi::toNativeLocalRegion(window()->mask(), window()));
+
if (aWindow->isTopLevel())
setWindowIcon(aWindow->icon());
clearFlag(WithinCreate);
@@ -1083,6 +1118,27 @@ QWindowsWindow::~QWindowsWindow()
destroyIcon();
}
+void QWindowsWindow::initialize()
+{
+ // Clear the creation context as the window can be found in QWindowsContext's map.
+ QWindowCreationContextPtr creationContext =
+ QWindowsContext::instance()->setWindowCreationContext(QWindowCreationContextPtr());
+
+ // Trigger geometry change (unless it has a special state in which case setWindowState()
+ // will send the message) and screen change signals of QWindow.
+ QWindow *w = window();
+ if (w->type() != Qt::Desktop) {
+ const Qt::WindowState state = w->windowState();
+ if (state != Qt::WindowMaximized && state != Qt::WindowFullScreen
+ && creationContext->requestedGeometryIn != creationContext->obtainedGeometry) {
+ QWindowSystemInterface::handleGeometryChange(w, creationContext->obtainedGeometry);
+ }
+ QPlatformScreen *obtainedScreen = screenForGeometry(creationContext->obtainedGeometry);
+ if (obtainedScreen && screen() != obtainedScreen)
+ QWindowSystemInterface::handleWindowScreenChanged(w, obtainedScreen->screen());
+ }
+}
+
void QWindowsWindow::fireExpose(const QRegion &region, bool force)
{
if (region.isEmpty() && !force)
@@ -1115,6 +1171,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())
@@ -1332,20 +1396,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) {
@@ -1366,7 +1458,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);
@@ -1379,6 +1471,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)
@@ -1434,8 +1528,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)
@@ -1452,7 +1548,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;
@@ -1467,13 +1564,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 && (isVisible() || QLibraryInfo::isDebugBuild())) {
qWarning("%s: Unable to set geometry %dx%d+%d+%d on %s/'%s'."
" Resulting geometry: %dx%d+%d+%d "
@@ -1510,18 +1609,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);
}
@@ -1554,7 +1656,6 @@ void QWindowsWindow::handleGeometryChange()
{
const QRect previousGeometry = m_data.geometry;
m_data.geometry = geometry_sys();
- QPlatformWindow::setGeometry(m_data.geometry);
QWindowSystemInterface::handleGeometryChange(window(), m_data.geometry);
// QTBUG-32121: OpenGL/normal windows (with exception of ANGLE) do not receive
// expose events when shrinking, synthesize.
@@ -1668,8 +1769,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.
@@ -1725,20 +1829,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();
@@ -1759,13 +1859,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);
@@ -1796,18 +1892,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
@@ -1818,7 +1915,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;
@@ -1826,6 +1923,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)
@@ -1839,15 +1938,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)
@@ -1861,43 +1968,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;
}
@@ -1989,7 +2111,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);
}
}
@@ -2158,7 +2280,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
@@ -2188,7 +2310,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;
}
@@ -2379,6 +2501,16 @@ bool QWindowsWindow::isTopLevel() const
return window()->isTopLevel() && !m_data.embedded;
}
+QWindowsMenuBar *QWindowsWindow::menuBar() const
+{
+ return m_menuBar.data();
+}
+
+void QWindowsWindow::setMenuBar(QWindowsMenuBar *mb)
+{
+ m_menuBar = mb;
+}
+
/*!
\brief Sets custom margins to be added to the default margins determined by
the windows style in the handling of the WM_NCCALCSIZE message.
@@ -2407,11 +2539,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);
@@ -2423,6 +2571,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 2b447751ba..414d4a92f8 100644
--- a/src/plugins/platforms/windows/qwindowswindow.h
+++ b/src/plugins/platforms/windows/qwindowswindow.h
@@ -41,14 +41,20 @@
#define QWINDOWSWINDOW_H
#include <QtCore/qt_windows.h>
+#include <QtCore/QPointer>
#include "qwindowscursor.h"
#include <qpa/qplatformwindow.h>
#include <QtPlatformHeaders/qwindowswindowfunctions.h>
+#if QT_CONFIG(vulkan)
+#include "qwindowsvulkaninstance.h"
+#endif
+
QT_BEGIN_NAMESPACE
class QWindowsOleDropTarget;
+class QWindowsMenuBar;
class QDebug;
struct QWindowsGeometryHint
@@ -75,9 +81,10 @@ struct QWindowsGeometryHint
struct QWindowCreationContext
{
- QWindowCreationContext(const QWindow *w, const QRect &r,
- const QMargins &customMargins,
- DWORD style, DWORD exStyle);
+ explicit QWindowCreationContext(const QWindow *w,
+ const QRect &geometryIn, const QRect &geometry,
+ const QMargins &customMargins,
+ DWORD style, DWORD exStyle);
void applyToMinMaxInfo(MINMAXINFO *mmi) const
{ geometryHint.applyToMinMaxInfo(style, exStyle, mmi); }
@@ -85,7 +92,8 @@ struct QWindowCreationContext
const QWindow *window;
DWORD style;
DWORD exStyle;
- QRect requestedGeometry;
+ QRect requestedGeometryIn; // QWindow scaled
+ QRect requestedGeometry; // after QPlatformWindow::initialGeometry()
QRect obtainedGeometry;
QMargins margins;
QMargins customMargins; // User-defined, additional frame for WM_NCCALCSIZE
@@ -188,6 +196,7 @@ public:
{
AutoMouseCapture = 0x1, //! Automatic mouse capture on button press.
WithinSetParent = 0x2,
+ WithinSetGeometry = 0x8,
OpenGLSurface = 0x10,
OpenGL_ES2 = 0x20,
OpenGLDoubleBuffered = 0x40,
@@ -208,12 +217,15 @@ public:
Compositing = 0x200000,
HasBorderInFullScreen = 0x400000,
WithinDpiChanged = 0x800000,
+ VulkanSurface = 0x1000000,
ResizeMoveActive = 0x2000000
};
QWindowsWindow(QWindow *window, const QWindowsWindowData &data);
~QWindowsWindow();
+ void initialize() override;
+
using QPlatformWindow::screenForGeometry;
QSurfaceFormat format() const override { return m_format; }
@@ -231,7 +243,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;
@@ -265,6 +277,9 @@ public:
HWND handle() const override { return m_data.hwnd; }
bool isTopLevel() const override;
+ QWindowsMenuBar *menuBar() const;
+ void setMenuBar(QWindowsMenuBar *mb);
+
QMargins customMargins() const { return m_data.customMargins; }
void setCustomMargins(const QMargins &m);
@@ -328,7 +343,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();
@@ -336,14 +351,15 @@ 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 &region, bool force=false);
mutable QWindowsWindowData m_data;
+ QPointer<QWindowsMenuBar> m_menuBar;
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;
@@ -355,6 +371,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
@@ -364,6 +385,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 6d01d05fcc..b7790a66e3 100644
--- a/src/plugins/platforms/windows/windows.pri
+++ b/src/plugins/platforms/windows/windows.pri
@@ -19,11 +19,13 @@ SOURCES += \
$$PWD/qwindowskeymapper.cpp \
$$PWD/qwindowsmousehandler.cpp \
$$PWD/qwindowsole.cpp \
+ $$PWD/qwindowsdropdataobject.cpp \
$$PWD/qwindowsmime.cpp \
$$PWD/qwindowsinternalmimedata.cpp \
$$PWD/qwindowscursor.cpp \
$$PWD/qwindowsinputcontext.cpp \
$$PWD/qwindowstheme.cpp \
+ $$PWD/qwindowsmenu.cpp \
$$PWD/qwindowsdialoghelpers.cpp \
$$PWD/qwindowsservices.cpp \
$$PWD/qwindowsnativeinterface.cpp \
@@ -31,6 +33,7 @@ SOURCES += \
$$PWD/qwin10helpers.cpp
HEADERS += \
+ $$PWD/qwindowscombase.h \
$$PWD/qwindowswindow.h \
$$PWD/qwindowsintegration.h \
$$PWD/qwindowscontext.h \
@@ -39,11 +42,13 @@ HEADERS += \
$$PWD/qwindowsmousehandler.h \
$$PWD/qtwindowsglobal.h \
$$PWD/qwindowsole.h \
+ $$PWD/qwindowsdropdataobject.h \
$$PWD/qwindowsmime.h \
$$PWD/qwindowsinternalmimedata.h \
$$PWD/qwindowscursor.h \
$$PWD/qwindowsinputcontext.h \
$$PWD/qwindowstheme.h \
+ $$PWD/qwindowsmenu.h \
$$PWD/qwindowsdialoghelpers.h \
$$PWD/qwindowsservices.h \
$$PWD/qwindowsnativeinterface.h \
@@ -69,6 +74,16 @@ qtConfig(dynamicgl) {
HEADERS += $$PWD/qwindowseglcontext.h
}
+qtConfig(systemtrayicon) {
+ SOURCES += $$PWD/qwindowssystemtrayicon.cpp
+ HEADERS += $$PWD/qwindowssystemtrayicon.h
+}
+
+qtConfig(vulkan) {
+ SOURCES += $$PWD/qwindowsvulkaninstance.cpp
+ HEADERS += $$PWD/qwindowsvulkaninstance.h
+}
+
qtConfig(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 c5d76c5d1d..174bc7b609 100644
--- a/src/plugins/platforms/windows/windows.pro
+++ b/src/plugins/platforms/windows/windows.pro
@@ -6,6 +6,7 @@ QT += \
fontdatabase_support-private theme_support-private
qtConfig(accessibility): QT += accessibility_support-private
+qtConfig(vulkan): QT += vulkan_support-private
LIBS += -lgdi32 -ldwmapi