diff options
Diffstat (limited to 'src/plugins/platforms/windows')
83 files changed, 3671 insertions, 1145 deletions
diff --git a/src/plugins/platforms/windows/accessible/comutils.cpp b/src/plugins/platforms/windows/accessible/comutils.cpp index 6c67345e05..366adb9059 100644 --- a/src/plugins/platforms/windows/accessible/comutils.cpp +++ b/src/plugins/platforms/windows/accessible/comutils.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. diff --git a/src/plugins/platforms/windows/accessible/comutils.h b/src/plugins/platforms/windows/accessible/comutils.h index ebf16dfdf8..2ef11ec0dd 100644 --- a/src/plugins/platforms/windows/accessible/comutils.h +++ b/src/plugins/platforms/windows/accessible/comutils.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. diff --git a/src/plugins/platforms/windows/accessible/iaccessible2.cpp b/src/plugins/platforms/windows/accessible/iaccessible2.cpp index 032f33163a..dcb137c09e 100644 --- a/src/plugins/platforms/windows/accessible/iaccessible2.cpp +++ b/src/plugins/platforms/windows/accessible/iaccessible2.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -43,7 +43,7 @@ #include "iaccessible2.h" #include "qwindowsaccessibility.h" - +#include <QtPlatformSupport/private/qaccessiblebridgeutils_p.h> #include <QtGui/qaccessible.h> #include <QtGui/qclipboard.h> #include <QtWidgets/qapplication.h> @@ -358,6 +358,8 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::role(long *ia2role) case QAccessible::LayeredPane: r = IA2_ROLE_LAYERED_PANE; break; case QAccessible::Terminal: r = IA2_ROLE_TERMINAL; break; case QAccessible::Desktop: r = IA2_ROLE_DESKTOP_PANE; break; + case QAccessible::Paragraph: r = IA2_ROLE_PARAGRAPH; break; + case QAccessible::Section: r = IA2_ROLE_SECTION; break; default: break; } @@ -545,10 +547,7 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::nActions(long *nActions) accessibleDebugClientCalls(accessible); if (!accessible) return E_FAIL; - *nActions = 0; - - if (QAccessibleActionInterface *actionIface = actionInterface()) - *nActions = actionIface->actionNames().count(); + *nActions = QAccessibleBridgeUtils::effectiveActionNames(accessible).count(); return S_OK; } @@ -558,15 +557,11 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::doAction(long actionIndex) accessibleDebugClientCalls(accessible); if (!accessible) return E_FAIL; - if (QAccessibleActionInterface *actionIface = actionInterface()) { - const QStringList actionNames = actionIface->actionNames(); - if (actionIndex < 0 || actionIndex >= actionNames.count()) - return E_INVALIDARG; - const QString actionName = actionNames.at(actionIndex); - actionIface->doAction(actionName); - return S_OK; - } - return S_FALSE; + const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(accessible); + if (actionIndex < 0 || actionIndex >= actionNames.count()) + return E_INVALIDARG; + const QString actionName = actionNames.at(actionIndex); + return QAccessibleBridgeUtils::performEffectiveAction(accessible, actionName) ? S_OK : S_FALSE; } HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_description(long actionIndex, BSTR *description) @@ -576,13 +571,15 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_description(long actionInde if (!accessible) return E_FAIL; *description = 0; - if (QAccessibleActionInterface *actionIface = actionInterface()) { - const QStringList actionNames = actionIface->actionNames(); - if (actionIndex < 0 || actionIndex >= actionNames.count()) - return E_INVALIDARG; - const QString actionName = actionNames.at(actionIndex); + const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(accessible); + if (actionIndex < 0 || actionIndex >= actionNames.count()) + return E_INVALIDARG; + const QString actionName = actionNames.at(actionIndex); + if (QAccessibleActionInterface *actionIface = actionInterface()) *description = QStringToBSTR(actionIface->localizedActionDescription(actionName)); - } + else + *description = QStringToBSTR(qAccessibleLocalizedActionDescription(actionName)); + return *description ? S_OK : S_FALSE; } @@ -622,13 +619,11 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_name(long actionIndex, BSTR if (!accessible) return E_FAIL; *name = 0; - if (QAccessibleActionInterface *actionIface = actionInterface()) { - const QStringList actionNames = actionIface->actionNames(); - if (actionIndex < 0 || actionIndex >= actionNames.count()) - return E_INVALIDARG; - const QString actionName = actionNames.at(actionIndex); - *name = QStringToBSTR(actionName); - } + const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(accessible); + if (actionIndex < 0 || actionIndex >= actionNames.count()) + return E_INVALIDARG; + const QString actionName = actionNames.at(actionIndex); + *name = QStringToBSTR(actionName); return *name ? S_OK : S_FALSE; } @@ -639,14 +634,16 @@ HRESULT STDMETHODCALLTYPE QWindowsIA2Accessible::get_localizedName(long actionIn if (!accessible) return E_FAIL; *localizedName = 0; - if (QAccessibleActionInterface *actionIface = actionInterface()) { - const QStringList actionNames = actionIface->actionNames(); - if (actionIndex < 0 || actionIndex >= actionNames.count()) - return E_INVALIDARG; + const QStringList actionNames = QAccessibleBridgeUtils::effectiveActionNames(accessible); + if (actionIndex < 0 || actionIndex >= actionNames.count()) + return E_INVALIDARG; - const QString actionName = actionNames.at(actionIndex); + const QString actionName = actionNames.at(actionIndex); + if (QAccessibleActionInterface *actionIface = actionInterface()) *localizedName = QStringToBSTR(actionIface->localizedActionName(actionName)); - } + else + *localizedName = QStringToBSTR(QAccessibleActionInterface::tr(qPrintable(actionName))); + return *localizedName ? S_OK : S_FALSE; } @@ -1709,6 +1706,13 @@ QByteArray QWindowsIA2Accessible::IIDToString(REFIID id) return strGuid; } +// Q_STATIC_ASSERT(IA2_ROLE_CANVAS == QAccessible::Canvas); // ### Qt 6: make them the same +Q_STATIC_ASSERT(IA2_ROLE_COLOR_CHOOSER == QAccessible::ColorChooser); +Q_STATIC_ASSERT(IA2_ROLE_FOOTER == QAccessible::Footer); +Q_STATIC_ASSERT(IA2_ROLE_FORM == QAccessible::Form); +Q_STATIC_ASSERT(IA2_ROLE_HEADING == QAccessible::Heading); +Q_STATIC_ASSERT(IA2_ROLE_NOTE == QAccessible::Note); +Q_STATIC_ASSERT(IA2_ROLE_COMPLEMENTARY_CONTENT == QAccessible::ComplementaryContent); QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/accessible/iaccessible2.h b/src/plugins/platforms/windows/accessible/iaccessible2.h index 9c42fdc631..fd92fb25bf 100644 --- a/src/plugins/platforms/windows/accessible/iaccessible2.h +++ b/src/plugins/platforms/windows/accessible/iaccessible2.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. diff --git a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp index 307f2fc3bb..f5b0f2f166 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp +++ b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. diff --git a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h index f25e2281a0..9e14868415 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h +++ b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp index bda806d102..d606ecb6a5 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp +++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -890,6 +890,11 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accName(VARIANT varID, BST } } } + + QString shortcut = accessible->text(QAccessible::Accelerator); + if (!shortcut.isEmpty()) + name.append(QLatin1Char(' ') + shortcut); + if (name.size()) { *pszName = QStringToBSTR(name); return S_OK; @@ -930,6 +935,8 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accRole(VARIANT varID, VAR // does not support IAccessible2, since it should prefer IA2::role() then. if (role == QAccessible::LayeredPane) role = QAccessible::Pane; + else if (role == QAccessible::WebDocument) + role = QAccessible::Document; else role = QAccessible::Client; } @@ -1034,7 +1041,7 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accValue(VARIANT varID, BS QString value; if (accessible->valueInterface()) { - value = QString::number(accessible->valueInterface()->currentValue().toDouble()); + value = accessible->valueInterface()->currentValue().toString(); } else { value = accessible->text(QAccessible::Value); } diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h index 43482da4be..b9cc2ccb44 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h +++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. diff --git a/src/plugins/platforms/windows/cursors.qrc b/src/plugins/platforms/windows/cursors.qrc new file mode 100644 index 0000000000..fded527aac --- /dev/null +++ b/src/plugins/platforms/windows/cursors.qrc @@ -0,0 +1,25 @@ +<RCC> + <qresource prefix="/qt-project.org/windows/cursors"> + <file>images/closedhandcursor_32.png</file> + <file>images/closedhandcursor_48.png</file> + <file>images/closedhandcursor_64.png</file> + <file>images/dragcopycursor_32.png</file> + <file>images/dragcopycursor_48.png</file> + <file>images/dragcopycursor_64.png</file> + <file>images/draglinkcursor_32.png</file> + <file>images/draglinkcursor_48.png</file> + <file>images/draglinkcursor_64.png</file> + <file>images/dragmovecursor_32.png</file> + <file>images/dragmovecursor_48.png</file> + <file>images/dragmovecursor_64.png</file> + <file>images/openhandcursor_32.png</file> + <file>images/openhandcursor_48.png</file> + <file>images/openhandcursor_64.png</file> + <file>images/splithcursor_32.png</file> + <file>images/splithcursor_48.png</file> + <file>images/splithcursor_64.png</file> + <file>images/splitvcursor_32.png</file> + <file>images/splitvcursor_48.png</file> + <file>images/splitvcursor_64.png</file> + </qresource> +</RCC> diff --git a/src/plugins/platforms/windows/images/closedhandcursor_32.png b/src/plugins/platforms/windows/images/closedhandcursor_32.png Binary files differnew file mode 100644 index 0000000000..7b3cba1965 --- /dev/null +++ b/src/plugins/platforms/windows/images/closedhandcursor_32.png diff --git a/src/plugins/platforms/windows/images/closedhandcursor_48.png b/src/plugins/platforms/windows/images/closedhandcursor_48.png Binary files differnew file mode 100644 index 0000000000..e63031605e --- /dev/null +++ b/src/plugins/platforms/windows/images/closedhandcursor_48.png diff --git a/src/plugins/platforms/windows/images/closedhandcursor_64.png b/src/plugins/platforms/windows/images/closedhandcursor_64.png Binary files differnew file mode 100644 index 0000000000..438680ed4e --- /dev/null +++ b/src/plugins/platforms/windows/images/closedhandcursor_64.png diff --git a/src/plugins/platforms/windows/images/dragcopycursor_32.png b/src/plugins/platforms/windows/images/dragcopycursor_32.png Binary files differnew file mode 100644 index 0000000000..f40ac6a600 --- /dev/null +++ b/src/plugins/platforms/windows/images/dragcopycursor_32.png diff --git a/src/plugins/platforms/windows/images/dragcopycursor_48.png b/src/plugins/platforms/windows/images/dragcopycursor_48.png Binary files differnew file mode 100644 index 0000000000..21ee467f46 --- /dev/null +++ b/src/plugins/platforms/windows/images/dragcopycursor_48.png diff --git a/src/plugins/platforms/windows/images/dragcopycursor_64.png b/src/plugins/platforms/windows/images/dragcopycursor_64.png Binary files differnew file mode 100644 index 0000000000..c49bcf33aa --- /dev/null +++ b/src/plugins/platforms/windows/images/dragcopycursor_64.png diff --git a/src/plugins/platforms/windows/images/draglinkcursor_32.png b/src/plugins/platforms/windows/images/draglinkcursor_32.png Binary files differnew file mode 100644 index 0000000000..5efbce90d3 --- /dev/null +++ b/src/plugins/platforms/windows/images/draglinkcursor_32.png diff --git a/src/plugins/platforms/windows/images/draglinkcursor_48.png b/src/plugins/platforms/windows/images/draglinkcursor_48.png Binary files differnew file mode 100644 index 0000000000..51205101b1 --- /dev/null +++ b/src/plugins/platforms/windows/images/draglinkcursor_48.png diff --git a/src/plugins/platforms/windows/images/draglinkcursor_64.png b/src/plugins/platforms/windows/images/draglinkcursor_64.png Binary files differnew file mode 100644 index 0000000000..55eb0e313a --- /dev/null +++ b/src/plugins/platforms/windows/images/draglinkcursor_64.png diff --git a/src/plugins/platforms/windows/images/dragmovecursor_32.png b/src/plugins/platforms/windows/images/dragmovecursor_32.png Binary files differnew file mode 100644 index 0000000000..32781a15ff --- /dev/null +++ b/src/plugins/platforms/windows/images/dragmovecursor_32.png diff --git a/src/plugins/platforms/windows/images/dragmovecursor_48.png b/src/plugins/platforms/windows/images/dragmovecursor_48.png Binary files differnew file mode 100644 index 0000000000..6b15af6e84 --- /dev/null +++ b/src/plugins/platforms/windows/images/dragmovecursor_48.png diff --git a/src/plugins/platforms/windows/images/dragmovecursor_64.png b/src/plugins/platforms/windows/images/dragmovecursor_64.png Binary files differnew file mode 100644 index 0000000000..e9e4ece29f --- /dev/null +++ b/src/plugins/platforms/windows/images/dragmovecursor_64.png diff --git a/src/plugins/platforms/windows/images/openhandcursor_32.png b/src/plugins/platforms/windows/images/openhandcursor_32.png Binary files differnew file mode 100644 index 0000000000..a6948d48f7 --- /dev/null +++ b/src/plugins/platforms/windows/images/openhandcursor_32.png diff --git a/src/plugins/platforms/windows/images/openhandcursor_48.png b/src/plugins/platforms/windows/images/openhandcursor_48.png Binary files differnew file mode 100644 index 0000000000..e8beb8d29d --- /dev/null +++ b/src/plugins/platforms/windows/images/openhandcursor_48.png diff --git a/src/plugins/platforms/windows/images/openhandcursor_64.png b/src/plugins/platforms/windows/images/openhandcursor_64.png Binary files differnew file mode 100644 index 0000000000..d12e3a7283 --- /dev/null +++ b/src/plugins/platforms/windows/images/openhandcursor_64.png diff --git a/src/plugins/platforms/windows/images/splithcursor_32.png b/src/plugins/platforms/windows/images/splithcursor_32.png Binary files differnew file mode 100644 index 0000000000..1ad479eddf --- /dev/null +++ b/src/plugins/platforms/windows/images/splithcursor_32.png diff --git a/src/plugins/platforms/windows/images/splithcursor_48.png b/src/plugins/platforms/windows/images/splithcursor_48.png Binary files differnew file mode 100644 index 0000000000..bf59b9cdca --- /dev/null +++ b/src/plugins/platforms/windows/images/splithcursor_48.png diff --git a/src/plugins/platforms/windows/images/splithcursor_64.png b/src/plugins/platforms/windows/images/splithcursor_64.png Binary files differnew file mode 100644 index 0000000000..b857458671 --- /dev/null +++ b/src/plugins/platforms/windows/images/splithcursor_64.png diff --git a/src/plugins/platforms/windows/images/splitvcursor_32.png b/src/plugins/platforms/windows/images/splitvcursor_32.png Binary files differnew file mode 100644 index 0000000000..ebb55ae2e1 --- /dev/null +++ b/src/plugins/platforms/windows/images/splitvcursor_32.png diff --git a/src/plugins/platforms/windows/images/splitvcursor_48.png b/src/plugins/platforms/windows/images/splitvcursor_48.png Binary files differnew file mode 100644 index 0000000000..5408920652 --- /dev/null +++ b/src/plugins/platforms/windows/images/splitvcursor_48.png diff --git a/src/plugins/platforms/windows/images/splitvcursor_64.png b/src/plugins/platforms/windows/images/splitvcursor_64.png Binary files differnew file mode 100644 index 0000000000..7f09a40c01 --- /dev/null +++ b/src/plugins/platforms/windows/images/splitvcursor_64.png diff --git a/src/plugins/platforms/windows/qplatformfunctions_wince.h b/src/plugins/platforms/windows/qplatformfunctions_wince.h index 47b03b29cc..17b13ced76 100644 --- a/src/plugins/platforms/windows/qplatformfunctions_wince.h +++ b/src/plugins/platforms/windows/qplatformfunctions_wince.h @@ -75,7 +75,6 @@ #ifndef CWP_SKIPINVISIBLE #define CWP_SKIPINVISIBLE 0x0001 #define CWP_SKIPTRANSPARENT 0x0004 -#define findPlatformWindowAt(a, b, c) findPlatformWindowAt(a, b) #endif #ifndef CS_OWNDC @@ -95,10 +94,6 @@ #define SW_SHOWMINIMIZED SW_MINIMIZE #define SW_SHOWMINNOACTIVE SW_MINIMIZE -#ifndef ChildWindowFromPointEx -#define ChildWindowFromPointEx(a, b, c) ChildWindowFromPoint(a, b) -#endif - #ifndef CF_DIBV5 #define CF_DIBV5 17 #endif diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h index ee640224cf..8c361d72ca 100644 --- a/src/plugins/platforms/windows/qtwindowsglobal.h +++ b/src/plugins/platforms/windows/qtwindowsglobal.h @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch> -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -77,6 +77,7 @@ enum WindowsEventType // Simplify event types LeaveEvent = WindowEventFlag + 5, CloseEvent = WindowEventFlag + 6, ShowEvent = WindowEventFlag + 7, + ShowEventOnParentRestoring = WindowEventFlag + 20, HideEvent = WindowEventFlag + 8, DestroyEvent = WindowEventFlag + 9, MoveEvent = WindowEventFlag + 10, @@ -103,6 +104,7 @@ enum WindowsEventType // Simplify event types AccessibleObjectFromWindowRequest = ApplicationEventFlag + 3, QueryEndSessionApplicationEvent = ApplicationEventFlag + 4, EndSessionApplicationEvent = ApplicationEventFlag + 5, + AppCommandEvent = ApplicationEventFlag + 6, InputMethodStartCompositionEvent = InputMethodEventFlag + 1, InputMethodCompositionEvent = InputMethodEventFlag + 2, InputMethodEndCompositionEvent = InputMethodEventFlag + 3, @@ -117,9 +119,17 @@ enum WindowsEventType // Simplify event types UnknownEvent = 542 }; +// Matches Process_DPI_Awareness (Windows 8.1 onwards), used for SetProcessDpiAwareness() +enum ProcessDpiAwareness +{ + ProcessDpiUnaware, + ProcessSystemDpiAware, + ProcessPerMonitorDpiAware +}; + } // namespace QtWindows -inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamIn) +inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamIn, LPARAM lParamIn) { switch (message) { case WM_PAINT: @@ -147,7 +157,9 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI case WM_MOVE: return QtWindows::MoveEvent; case WM_SHOWWINDOW: - return wParamIn ? QtWindows::ShowEvent : QtWindows::HideEvent; + if (wParamIn) + return lParamIn == SW_PARENTOPENING ? QtWindows::ShowEventOnParentRestoring : QtWindows::ShowEvent; + return QtWindows::HideEvent; case WM_SIZE: return QtWindows::ResizeEvent; case WM_NCCALCSIZE: @@ -234,6 +246,10 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI case WM_ENDSESSION: return QtWindows::EndSessionApplicationEvent; #endif +#if defined(WM_APPCOMMAND) + case WM_APPCOMMAND: + return QtWindows::AppCommandEvent; +#endif default: break; } diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.cpp b/src/plugins/platforms/windows/qwindowsbackingstore.cpp index 34a9c1df5f..40d1108f60 100644 --- a/src/plugins/platforms/windows/qwindowsbackingstore.cpp +++ b/src/plugins/platforms/windows/qwindowsbackingstore.cpp @@ -43,6 +43,7 @@ #include "qwindowswindow.h" #include "qwindowsnativeimage.h" #include "qwindowscontext.h" +#include "qwindowsscaling.h" #include <QtGui/QWindow> #include <QtGui/QPainter> @@ -75,12 +76,10 @@ QPaintDevice *QWindowsBackingStore::paintDevice() return &m_image->image(); } -void QWindowsBackingStore::flush(QWindow *window, const QRegion ®ion, - const QPoint &offset) +void QWindowsBackingStore::flushDp(QWindow *window, const QRect &br, const QPoint &offset) { Q_ASSERT(window); - const QRect br = region.boundingRect(); if (QWindowsContext::verbose > 1) qCDebug(lcQpaBackingStore) << __FUNCTION__ << this << window << offset << br; QWindowsWindow *rw = QWindowsWindow::baseWindowOf(window); @@ -90,8 +89,9 @@ void QWindowsBackingStore::flush(QWindow *window, const QRegion ®ion, const Qt::WindowFlags flags = window->flags(); if ((flags & Qt::FramelessWindowHint) && QWindowsWindow::setWindowLayered(rw->handle(), flags, hasAlpha, rw->opacity()) && hasAlpha) { // Windows with alpha: Use blend function to update. - QRect r = window->frameGeometry(); - QPoint frameOffset(window->frameMargins().left(), window->frameMargins().top()); + const QMargins marginsDP = rw->frameMarginsDp(); + const QRect r = rw->geometryDp() + marginsDP; + const QPoint frameOffset(marginsDP.left(), marginsDP.top()); QRect dirtyRect = br.translated(offset + frameOffset); SIZE size = {r.width(), r.height()}; @@ -135,14 +135,15 @@ void QWindowsBackingStore::flush(QWindow *window, const QRegion ®ion, } } -void QWindowsBackingStore::resize(const QSize &size, const QRegion ®ion) +void QWindowsBackingStore::resize(const QSize &sizeDip, const QRegion ®ionDip) { + const QSize size = sizeDip * QWindowsScaling::factor(); if (m_image.isNull() || m_image->image().size() != size) { #ifndef QT_NO_DEBUG_OUTPUT if (QWindowsContext::verbose && lcQpaBackingStore().isDebugEnabled()) { qCDebug(lcQpaBackingStore) - << __FUNCTION__ << ' ' << window() << ' ' << size << ' ' << region - << " from: " << (m_image.isNull() ? QSize() : m_image->image().size()); + << __FUNCTION__ << ' ' << window() << ' ' << size << ' ' << sizeDip << ' ' + << regionDip << " from: " << (m_image.isNull() ? QSize() : m_image->image().size()); } #endif const QImage::Format format = window()->format().hasAlpha() ? @@ -151,10 +152,10 @@ void QWindowsBackingStore::resize(const QSize &size, const QRegion ®ion) QWindowsNativeImage *oldwni = m_image.data(); QWindowsNativeImage *newwni = new QWindowsNativeImage(size.width(), size.height(), format); - if (oldwni && !region.isEmpty()) { + if (oldwni && !regionDip.isEmpty()) { const QImage &oldimg(oldwni->image()); QImage &newimg(newwni->image()); - QRegion staticRegion(region); + QRegion staticRegion = QWindowsScaling::mapToNative(regionDip); staticRegion &= QRect(0, 0, oldimg.width(), oldimg.height()); staticRegion &= QRect(0, 0, newimg.width(), newimg.height()); QPainter painter(&newimg); @@ -163,35 +164,38 @@ void QWindowsBackingStore::resize(const QSize &size, const QRegion ®ion) painter.drawImage(rect, oldimg, rect); } + if (QWindowsScaling::isActive()) + newwni->setDevicePixelRatio(QWindowsScaling::factor()); m_image.reset(newwni); } } Q_GUI_EXPORT void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset); -bool QWindowsBackingStore::scroll(const QRegion &area, int dx, int dy) +bool QWindowsBackingStore::scroll(const QRegion &areaDip, int dxDip, int dyDip) { if (m_image.isNull() || m_image->image().isNull()) return false; - const QVector<QRect> rects = area.rects(); + const QPoint dp = QPoint(dxDip, dyDip) * QWindowsScaling::factor(); + const QVector<QRect> rects = areaDip.rects(); for (int i = 0; i < rects.size(); ++i) - qt_scrollRectInImage(m_image->image(), rects.at(i), QPoint(dx, dy)); + qt_scrollRectInImage(m_image->image(), QWindowsScaling::mapToNative(rects.at(i)), dp); return true; } -void QWindowsBackingStore::beginPaint(const QRegion ®ion) +void QWindowsBackingStore::beginPaint(const QRegion ®ionDip) { if (QWindowsContext::verbose > 1) - qCDebug(lcQpaBackingStore) <<__FUNCTION__ << region; + qCDebug(lcQpaBackingStore) <<__FUNCTION__ << regionDip; if (m_image->image().hasAlphaChannel()) { QPainter p(&m_image->image()); p.setCompositionMode(QPainter::CompositionMode_Source); const QColor blank = Qt::transparent; - foreach (const QRect &r, region.rects()) - p.fillRect(r, blank); + foreach (const QRect &r, regionDip.rects()) + p.fillRect(QWindowsScaling::mapToNative(r), blank); } } diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.h b/src/plugins/platforms/windows/qwindowsbackingstore.h index 758f6c941f..9c9500dabb 100644 --- a/src/plugins/platforms/windows/qwindowsbackingstore.h +++ b/src/plugins/platforms/windows/qwindowsbackingstore.h @@ -43,6 +43,7 @@ #define QWINDOWSBACKINGSTORE_H #include "qtwindows_additional.h" +#include "qwindowsscaling.h" #include <qpa/qplatformbackingstore.h> #include <QtCore/QScopedPointer> @@ -59,11 +60,16 @@ public: QWindowsBackingStore(QWindow *window); ~QWindowsBackingStore(); - virtual QPaintDevice *paintDevice(); - virtual void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); - virtual void resize(const QSize &size, const QRegion &r); - virtual bool scroll(const QRegion &area, int dx, int dy); - virtual void beginPaint(const QRegion &); + QPaintDevice *paintDevice() Q_DECL_OVERRIDE; + void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE + { + flushDp(window, QWindowsScaling::mapToNative(region.boundingRect()), + offset * QWindowsScaling::factor()); + } + void flushDp(QWindow *window, const QRect &boundingRect, const QPoint &offset); + void resize(const QSize &size, const QRegion &r) Q_DECL_OVERRIDE; + bool scroll(const QRegion &area, int dx, int dy) Q_DECL_OVERRIDE; + void beginPaint(const QRegion &) Q_DECL_OVERRIDE; HDC getDC() const; diff --git a/src/plugins/platforms/windows/qwindowsclipboard.cpp b/src/plugins/platforms/windows/qwindowsclipboard.cpp index dcfeba12fa..e43b524aa8 100644 --- a/src/plugins/platforms/windows/qwindowsclipboard.cpp +++ b/src/plugins/platforms/windows/qwindowsclipboard.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -145,7 +145,7 @@ static void cleanClipboardPostRoutine() QWindowsClipboard *QWindowsClipboard::m_instance = 0; QWindowsClipboard::QWindowsClipboard() : - m_data(0), m_clipboardViewer(0), m_nextClipboardViewer(0) + m_data(0), m_clipboardViewer(0), m_nextClipboardViewer(0), m_formatListenerRegistered(false) { QWindowsClipboard::m_instance = this; qAddPostRoutine(cleanClipboardPostRoutine); @@ -178,20 +178,40 @@ void QWindowsClipboard::registerViewer() m_clipboardViewer = QWindowsContext::instance()-> createDummyWindow(QStringLiteral("Qt5ClipboardView"), L"Qt5ClipboardView", qClipboardViewerWndProc, WS_OVERLAPPED); - m_nextClipboardViewer = SetClipboardViewer(m_clipboardViewer); - qCDebug(lcQpaMime) << __FUNCTION__ << "m_clipboardViewer: " << m_clipboardViewer << "next: " << m_nextClipboardViewer; + // Try format listener API (Vista onwards) first. + if (QWindowsContext::user32dll.addClipboardFormatListener && QWindowsContext::user32dll.removeClipboardFormatListener) { + m_formatListenerRegistered = QWindowsContext::user32dll.addClipboardFormatListener(m_clipboardViewer); + if (!m_formatListenerRegistered) + qErrnoWarning("AddClipboardFormatListener() failed."); + } + + if (!m_formatListenerRegistered) + m_nextClipboardViewer = SetClipboardViewer(m_clipboardViewer); + + qCDebug(lcQpaMime) << __FUNCTION__ << "m_clipboardViewer:" << m_clipboardViewer + << "format listener:" << m_formatListenerRegistered + << "next:" << m_nextClipboardViewer; } void QWindowsClipboard::unregisterViewer() { if (m_clipboardViewer) { - ChangeClipboardChain(m_clipboardViewer, m_nextClipboardViewer); + if (m_formatListenerRegistered) { + QWindowsContext::user32dll.removeClipboardFormatListener(m_clipboardViewer); + m_formatListenerRegistered = false; + } else { + ChangeClipboardChain(m_clipboardViewer, m_nextClipboardViewer); + m_nextClipboardViewer = 0; + } DestroyWindow(m_clipboardViewer); - m_clipboardViewer = m_nextClipboardViewer = 0; + m_clipboardViewer = 0; } } +// ### FIXME: Qt 6: Remove the clipboard chain handling code and make the +// format listener the default. + static bool isProcessBeingDebugged(HWND hwnd) { DWORD pid = 0; @@ -232,6 +252,8 @@ void QWindowsClipboard::propagateClipboardMessage(UINT message, WPARAM wParam, L bool QWindowsClipboard::clipboardViewerWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result) { + enum { wMClipboardUpdate = 0x031D }; + *result = 0; if (QWindowsContext::verbose) qCDebug(lcQpaMime) << __FUNCTION__ << hwnd << message << QWindowsGuiEventDispatcher::windowsMessageName(message); @@ -246,14 +268,16 @@ bool QWindowsClipboard::clipboardViewerWndProc(HWND hwnd, UINT message, WPARAM w } } return true; - case WM_DRAWCLIPBOARD: { + case wMClipboardUpdate: // Clipboard Format listener (Vista onwards) + case WM_DRAWCLIPBOARD: { // Clipboard Viewer Chain handling (up to XP) const bool owned = ownsClipboard(); qCDebug(lcQpaMime) << "Clipboard changed owned " << owned; emitChanged(QClipboard::Clipboard); // clean up the clipboard object if we no longer own the clipboard if (!owned && m_data) releaseIData(); - propagateClipboardMessage(message, wParam, lParam); + if (!m_formatListenerRegistered) + propagateClipboardMessage(message, wParam, lParam); } return true; case WM_DESTROY: diff --git a/src/plugins/platforms/windows/qwindowsclipboard.h b/src/plugins/platforms/windows/qwindowsclipboard.h index 30bc0143f4..a3e9da7f3f 100644 --- a/src/plugins/platforms/windows/qwindowsclipboard.h +++ b/src/plugins/platforms/windows/qwindowsclipboard.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -54,8 +54,8 @@ class QWindowsClipboardRetrievalMimeData : public QWindowsInternalMimeData { public: protected: - virtual IDataObject *retrieveDataObject() const; - virtual void releaseDataObject(IDataObject *) const; + IDataObject *retrieveDataObject() const Q_DECL_OVERRIDE; + void releaseDataObject(IDataObject *) const Q_DECL_OVERRIDE; }; class QWindowsClipboard : public QPlatformClipboard @@ -66,10 +66,10 @@ public: void registerViewer(); // Call in initialization, when context is up. void cleanup(); - virtual QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard); - virtual void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard); - virtual bool supportsMode(QClipboard::Mode mode) const; - virtual bool ownsMode(QClipboard::Mode mode) const; + QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard) Q_DECL_OVERRIDE; + void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard) Q_DECL_OVERRIDE; + bool supportsMode(QClipboard::Mode mode) const Q_DECL_OVERRIDE; + bool ownsMode(QClipboard::Mode mode) const Q_DECL_OVERRIDE; inline bool clipboardViewerWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result); @@ -88,6 +88,7 @@ private: QWindowsOleDataObject *m_data; HWND m_clipboardViewer; HWND m_nextClipboardViewer; + bool m_formatListenerRegistered; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index f2f285f0f6..132f224382 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -59,6 +59,7 @@ #endif #include "qwindowsscreen.h" #include "qwindowstheme.h" +#include "qwindowsscaling.h" #include <QtGui/QWindow> #include <qpa/qwindowsysteminterface.h> @@ -88,9 +89,9 @@ Q_LOGGING_CATEGORY(lcQpaEvents, "qt.qpa.events") Q_LOGGING_CATEGORY(lcQpaFonts, "qt.qpa.fonts") Q_LOGGING_CATEGORY(lcQpaGl, "qt.qpa.gl") Q_LOGGING_CATEGORY(lcQpaMime, "qt.qpa.mime") -Q_LOGGING_CATEGORY(lcQpaInputMethods, "qt.qpa.inputmethods") +Q_LOGGING_CATEGORY(lcQpaInputMethods, "qt.qpa.input.methods") Q_LOGGING_CATEGORY(lcQpaDialogs, "qt.qpa.dialogs") -Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.tabletsupport") +Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") Q_LOGGING_CATEGORY(lcQpaAccessibility, "qt.qpa.accessibility") int QWindowsContext::verbose = 0; @@ -191,7 +192,8 @@ QWindowsUser32DLL::QWindowsUser32DLL() : updateLayeredWindowIndirect(0), isHungAppWindow(0), registerTouchWindow(0), unregisterTouchWindow(0), - getTouchInputInfo(0), closeTouchInputHandle(0), setProcessDPIAware(0) + getTouchInputInfo(0), closeTouchInputHandle(0), setProcessDPIAware(0), + addClipboardFormatListener(0), removeClipboardFormatListener(0) { } @@ -207,6 +209,11 @@ void QWindowsUser32DLL::init() updateLayeredWindowIndirect = (UpdateLayeredWindowIndirect)(library.resolve("UpdateLayeredWindowIndirect")); isHungAppWindow = (IsHungAppWindow)library.resolve("IsHungAppWindow"); setProcessDPIAware = (SetProcessDPIAware)library.resolve("SetProcessDPIAware"); + + if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA) { + addClipboardFormatListener = (AddClipboardFormatListener)library.resolve("AddClipboardFormatListener"); + removeClipboardFormatListener = (RemoveClipboardFormatListener)library.resolve("RemoveClipboardFormatListener"); + } } bool QWindowsUser32DLL::initTouch() @@ -247,8 +254,26 @@ void QWindowsShell32DLL::init() sHGetImageList = (SHGetImageList)library.resolve("SHGetImageList"); } +QWindowsShcoreDLL::QWindowsShcoreDLL() + : getProcessDpiAwareness(0) + , setProcessDpiAwareness(0) + , getDpiForMonitor(0) +{ +} + +void QWindowsShcoreDLL::init() +{ + if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS8_1) + return; + QSystemLibrary library(QStringLiteral("SHCore")); + getProcessDpiAwareness = (GetProcessDpiAwareness)library.resolve("GetProcessDpiAwareness"); + setProcessDpiAwareness = (SetProcessDpiAwareness)library.resolve("SetProcessDpiAwareness"); + getDpiForMonitor = (GetDpiForMonitor)library.resolve("GetDpiForMonitor"); +} + QWindowsUser32DLL QWindowsContext::user32dll; QWindowsShell32DLL QWindowsContext::shell32dll; +QWindowsShcoreDLL QWindowsContext::shcoredll; #endif // !Q_OS_WINCE @@ -299,9 +324,7 @@ QWindowsContextPrivate::QWindowsContextPrivate() #ifndef Q_OS_WINCE QWindowsContext::user32dll.init(); QWindowsContext::shell32dll.init(); - // Ensure metrics functions report correct data, QTBUG-30063. - if (QWindowsContext::user32dll.setProcessDPIAware) - QWindowsContext::user32dll.setProcessDPIAware(); + QWindowsContext::shcoredll.init(); if (hasTouchSupport(ver) && QWindowsContext::user32dll.initTouch()) m_systemInfo |= QWindowsContext::SI_SupportsTouch; @@ -358,6 +381,25 @@ void QWindowsContext::setTabletAbsoluteRange(int a) #endif } +void QWindowsContext::setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiAwareness) +{ +#ifndef Q_OS_WINCE + qCDebug(lcQpaWindows) << __FUNCTION__ << dpiAwareness; + if (QWindowsContext::shcoredll.isValid()) { + const HRESULT hr = QWindowsContext::shcoredll.setProcessDpiAwareness(dpiAwareness); + if (FAILED(hr)) + qWarning() << "SetProcessDpiAwareness failed:" << QWindowsContext::comErrorString(hr); + } else { + if (dpiAwareness != QtWindows::ProcessDpiUnaware && QWindowsContext::user32dll.setProcessDPIAware) { + if (!QWindowsContext::user32dll.setProcessDPIAware()) + qErrnoWarning("SetProcessDPIAware() failed"); + } + } +#else // !Q_OS_WINCE + Q_UNUSED(dpiAwareness) +#endif +} + QWindowsContext *QWindowsContext::instance() { return m_instance; @@ -419,9 +461,17 @@ QString QWindowsContext::registerWindowClass(const QWindow *w, bool isGL) && (type == Qt::Popup || w->property("_q_windowsDropShadow").toBool())) { style |= CS_DROPSHADOW; } - if (type == Qt::Tool || type == Qt::ToolTip || type == Qt::Popup) { + switch (type) { + case Qt::Tool: + case Qt::ToolTip: + case Qt::Popup: style |= CS_SAVEBITS; // Save/restore background icon = false; + break; + case Qt::Dialog: + if (!(flags & Qt::WindowSystemMenuHint)) + icon = false; // QTBUG-2027, dialogs without system menu. + break; } // Create a unique name for the flag combination QString cname = QStringLiteral("Qt5QWindow"); @@ -632,25 +682,54 @@ void QWindowsContext::clearWindowUnderMouse() \a parent is the parent window, pass GetDesktopWindow() for top levels. */ +static inline bool findPlatformWindowHelper(const POINT &screenPoint, unsigned cwexFlags, + const QWindowsContext *context, + HWND *hwnd, QWindowsWindow **result) +{ + POINT point = screenPoint; + ScreenToClient(*hwnd, &point); + // Returns parent if inside & none matched. +#ifndef Q_OS_WINCE + const HWND child = ChildWindowFromPointEx(*hwnd, point, cwexFlags); +#else + Q_UNUSED(cwexFlags) + const HWND child = ChildWindowFromPoint(*hwnd, point); +#endif + if (!child || child == *hwnd) + return false; + if (QWindowsWindow *window = context->findPlatformWindow(child)) { + *result = window; + *hwnd = child; + return true; + } +#ifndef Q_OS_WINCE // Does not have WS_EX_TRANSPARENT . + // QTBUG-40555: despite CWP_SKIPINVISIBLE, it is possible to hit on invisible + // full screen windows of other applications that have WS_EX_TRANSPARENT set + // (for example created by screen sharing applications). In that case, try to + // find a Qt window by searching again with CWP_SKIPTRANSPARENT. + // Note that Qt 5 uses WS_EX_TRANSPARENT for Qt::WindowTransparentForInput + // as well. + if (!(cwexFlags & CWP_SKIPTRANSPARENT) + && (GetWindowLongPtr(child, GWL_EXSTYLE) & WS_EX_TRANSPARENT)) { + const HWND nonTransparentChild = ChildWindowFromPointEx(*hwnd, point, cwexFlags | CWP_SKIPTRANSPARENT); + if (QWindowsWindow *nonTransparentWindow = context->findPlatformWindow(nonTransparentChild)) { + *result = nonTransparentWindow; + *hwnd = nonTransparentChild; + return true; + } + } +#endif // !Q_OS_WINCE + *hwnd = child; + return true; +} + QWindowsWindow *QWindowsContext::findPlatformWindowAt(HWND parent, const QPoint &screenPointIn, unsigned cwex_flags) const { QWindowsWindow *result = 0; const POINT screenPoint = { screenPointIn.x(), screenPointIn.y() }; - while (true) { - POINT point = screenPoint; - ScreenToClient(parent, &point); - // Returns parent if inside & none matched. - const HWND child = ChildWindowFromPointEx(parent, point, cwex_flags); - if (child && child != parent) { - if (QWindowsWindow *window = findPlatformWindow(child)) - result = window; - parent = child; - } else { - break; - } - } + while (findPlatformWindowHelper(screenPoint, cwex_flags, this, &parent, &result)) {} return result; } @@ -913,6 +992,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, case QtWindows::InputMethodKeyEvent: case QtWindows::InputMethodKeyDownEvent: case QtWindows::KeyboardLayoutChangeEvent: + case QtWindows::AppCommandEvent: #if !defined(Q_OS_WINCE) && !defined(QT_NO_SESSIONMANAGER) return platformSessionManager()->isInteractionBlocked() ? true : d->m_keyMapper.translateKeyEvent(platformWindow->window(), hwnd, msg, result); #else @@ -972,6 +1052,12 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, case QtWindows::FocusOutEvent: handleFocusEvent(et, platformWindow); return true; + case QtWindows::ShowEventOnParentRestoring: // QTBUG-40696, prevent Windows from re-showing hidden transient children (dialogs). + if (!platformWindow->window()->isVisible()) { + *result = 0; + return true; + } + break; case QtWindows::HideEvent: platformWindow->handleHidden(); return false;// Indicate transient children should be hidden by windows (SW_PARENTCLOSING) @@ -1133,7 +1219,9 @@ bool QWindowsContext::handleContextMenuEvent(QWindow *window, const MSG &msg) } } - QWindowSystemInterface::handleContextMenuEvent(window, mouseTriggered, pos, globalPos, + QWindowSystemInterface::handleContextMenuEvent(window, mouseTriggered, + pos / QWindowsScaling::factor(), + globalPos / QWindowsScaling::factor(), QWindowsKeyMapper::queryKeyboardModifiers()); return true; } @@ -1161,7 +1249,7 @@ void QWindowsContext::setAsyncExpose(bool value) extern "C" LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { LRESULT result; - const QtWindows::WindowsEventType et = windowsEventType(message, wParam); + const QtWindows::WindowsEventType et = windowsEventType(message, wParam, lParam); const bool handled = QWindowsContext::instance()->windowsProc(hwnd, message, et, wParam, lParam, &result); if (QWindowsContext::verbose > 1 && lcQpaEvents().isDebugEnabled()) { if (const char *eventName = QWindowsGuiEventDispatcher::windowsMessageName(message)) { diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h index f5dbd072c7..086b968255 100644 --- a/src/plugins/platforms/windows/qwindowscontext.h +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -94,6 +94,8 @@ struct QWindowsUser32DLL typedef BOOL (WINAPI *UpdateLayeredWindowIndirect)(HWND, const UPDATELAYEREDWINDOWINFO *); typedef BOOL (WINAPI *IsHungAppWindow)(HWND); typedef BOOL (WINAPI *SetProcessDPIAware)(); + typedef BOOL (WINAPI *AddClipboardFormatListener)(HWND); + typedef BOOL (WINAPI *RemoveClipboardFormatListener)(HWND); // Functions missing in Q_CC_GNU stub libraries. SetLayeredWindowAttributes setLayeredWindowAttributes; @@ -111,6 +113,10 @@ struct QWindowsUser32DLL // Windows Vista onwards SetProcessDPIAware setProcessDPIAware; + + // Clipboard listeners, Windows Vista onwards + AddClipboardFormatListener addClipboardFormatListener; + RemoveClipboardFormatListener removeClipboardFormatListener; }; struct QWindowsShell32DLL @@ -126,6 +132,22 @@ struct QWindowsShell32DLL SHGetStockIconInfo sHGetStockIconInfo; SHGetImageList sHGetImageList; }; + +// Shell scaling library (Windows 8.1 onwards) +struct QWindowsShcoreDLL { + QWindowsShcoreDLL(); + void init(); + inline bool isValid() const { return getProcessDpiAwareness && setProcessDpiAwareness && getDpiForMonitor; } + + typedef HRESULT (WINAPI *GetProcessDpiAwareness)(HANDLE,int); + typedef HRESULT (WINAPI *SetProcessDpiAwareness)(int); + typedef HRESULT (WINAPI *GetDpiForMonitor)(HMONITOR,int,UINT *,UINT *); + + GetProcessDpiAwareness getProcessDpiAwareness; + SetProcessDpiAwareness setProcessDpiAwareness; + GetDpiForMonitor getDpiForMonitor; +}; + #endif // Q_OS_WINCE class QWindowsContext @@ -184,6 +206,7 @@ public: void setWindowCreationContext(const QSharedPointer<QWindowCreationContext> &ctx); void setTabletAbsoluteRange(int a); + void setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiAwareness); // Returns a combination of SystemInfoFlags unsigned systemInfo() const; @@ -197,6 +220,7 @@ public: #ifndef Q_OS_WINCE static QWindowsUser32DLL user32dll; static QWindowsShell32DLL shell32dll; + static QWindowsShcoreDLL shcoredll; #endif static QByteArray comErrorString(HRESULT hr); diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp index d8fb104b3c..eca8a33215 100644 --- a/src/plugins/platforms/windows/qwindowscursor.cpp +++ b/src/plugins/platforms/windows/qwindowscursor.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -44,6 +44,7 @@ #include "qwindowscontext.h" #include "qwindowswindow.h" #include "qwindowsscreen.h" +#include "qwindowsscaling.h" #include <QtGui/QBitmap> #include <QtGui/QImage> @@ -98,7 +99,7 @@ QWindowsCursorCacheKey::QWindowsCursorCacheKey(const QCursor &c) \sa QWindowsWindowCursor */ -HCURSOR QWindowsCursor::createPixmapCursor(const QPixmap &pixmap, int hotX, int hotY) +HCURSOR QWindowsCursor::createPixmapCursor(const QPixmap &pixmap, const QPoint &hotSpot) { HCURSOR cur = 0; QBitmap mask = pixmap.mask(); @@ -112,8 +113,8 @@ HCURSOR QWindowsCursor::createPixmapCursor(const QPixmap &pixmap, int hotX, int ICONINFO ii; ii.fIcon = 0; - ii.xHotspot = hotX; - ii.yHotspot = hotY; + ii.xHotspot = hotSpot.x(); + ii.yHotspot = hotSpot.y(); ii.hbmMask = im; ii.hbmColor = ic; @@ -124,20 +125,120 @@ HCURSOR QWindowsCursor::createPixmapCursor(const QPixmap &pixmap, int hotX, int return cur; } -HCURSOR QWindowsCursor::createSystemCursor(const QCursor &c) +// Create a cursor from image and mask of the format QImage::Format_Mono. +static HCURSOR createBitmapCursor(const QImage &bbits, const QImage &mbits, + QPoint hotSpot = QPoint(), + bool invb = false, bool invm = false) { - int hx = c.hotSpot().x(); - int hy = c.hotSpot().y(); - const Qt::CursorShape cshape = c.shape(); - if (cshape == Qt::BitmapCursor) { - const QPixmap pixmap = c.pixmap(); - if (!pixmap.isNull()) - if (const HCURSOR hc = createPixmapCursor(pixmap, hx, hy)) - return hc; + const int width = bbits.width(); + const int height = bbits.height(); + if (hotSpot.isNull()) + hotSpot = QPoint(width / 2, height / 2); + const int n = qMax(1, width / 8); +#if !defined(Q_OS_WINCE) + QScopedArrayPointer<uchar> xBits(new uchar[height * n]); + QScopedArrayPointer<uchar> xMask(new uchar[height * n]); + int x = 0; + for (int i = 0; i < height; ++i) { + const uchar *bits = bbits.scanLine(i); + const uchar *mask = mbits.scanLine(i); + for (int j = 0; j < n; ++j) { + uchar b = bits[j]; + uchar m = mask[j]; + if (invb) + b ^= 0xff; + if (invm) + m ^= 0xff; + xBits[x] = ~m; + xMask[x] = b ^ m; + ++x; + } + } + return CreateCursor(GetModuleHandle(0), hotSpot.x(), hotSpot.y(), width, height, + xBits.data(), xMask.data()); +#elif defined(GWES_ICONCURS) // Q_OS_WINCE + // Windows CE only supports fixed cursor size. + int sysW = GetSystemMetrics(SM_CXCURSOR); + int sysH = GetSystemMetrics(SM_CYCURSOR); + int sysN = qMax(1, sysW / 8); + uchar* xBits = new uchar[sysH * sysN]; + uchar* xMask = new uchar[sysH * sysN]; + int x = 0; + for (int i = 0; i < sysH; ++i) { + if (i >= height) { + memset(&xBits[x] , 255, sysN); + memset(&xMask[x] , 0, sysN); + x += sysN; + } else { + int fillWidth = n > sysN ? sysN : n; + const uchar *bits = bbits.scanLine(i); + const uchar *mask = mbits.scanLine(i); + for (int j = 0; j < fillWidth; ++j) { + uchar b = bits[j]; + uchar m = mask[j]; + if (invb) + b ^= 0xFF; + if (invm) + m ^= 0xFF; + xBits[x] = ~m; + xMask[x] = b ^ m; + ++x; + } + for (int j = fillWidth; j < sysN; ++j ) { + xBits[x] = 255; + xMask[x] = 0; + ++x; + } + } } - // Non-standard Windows cursors are created from bitmaps + HCURSOR hcurs = CreateCursor(qWinAppInst(), hotSpot.x(), hotSpot.y(), sysW, sysH, + xBits, xMask); + delete [] xBits; + delete [] xMask; + return hcurs; +#else + Q_UNUSED(n); + Q_UNUSED(invm); + Q_UNUSED(invb); + Q_UNUSED(mbits); + return 0; +#endif +} +static inline QSize systemCursorSize() { return QSize(GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR)); } +static inline QSize standardCursorSize() { return QSize(32, 32); } + +#if defined (Q_OS_WINCE) || defined (QT_NO_IMAGEFORMAT_PNG) +// Create pixmap cursors from data and scale the image if the cursor size is +// higher than the standard 32. Note that bitmap cursors as produced by +// createBitmapCursor() only work for standard sizes (32,48,64...), which does +// not work when scaling the 16x16 openhand cursor bitmaps to 150% (resulting +// in a non-standard 24x24 size). +static QCursor createPixmapCursorFromData(const QSize &systemCursorSize, + // The cursor size the bitmap is targeted for + const QSize &bitmapTargetCursorSize, + // The actual size of the bitmap data + int bitmapSize, const uchar *bits, + const uchar *maskBits) +{ + QPixmap rawImage = QPixmap::fromImage(QBitmap::fromData(QSize(bitmapSize, bitmapSize), bits).toImage()); + rawImage.setMask(QBitmap::fromData(QSize(bitmapSize, bitmapSize), maskBits)); + + const qreal factor = qreal(systemCursorSize.width()) / qreal(bitmapTargetCursorSize.width()); + // Scale images if the cursor size is significantly different, starting with 150% where the system cursor + // size is 48. + if (qAbs(factor - 1.0) > 0.4) { + const QTransform transform = QTransform::fromScale(factor, factor); + rawImage = rawImage.transformed(transform, Qt::SmoothTransformation); + } + const QPoint hotSpot(rawImage.width() / 2, rawImage.height() / 2); + return QCursor(rawImage, hotSpot.x(), hotSpot.y()); +} + +QCursor QWindowsCursor::customCursor(Qt::CursorShape cursorShape) +{ + // Non-standard Windows cursors are created from bitmaps static const uchar vsplit_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -203,171 +304,250 @@ HCURSOR QWindowsCursor::createSystemCursor(const QCursor &c) 0xf0,0x7f,0xf8,0x7f,0xfc,0x7f,0xfc,0x3f,0xf8,0x3f,0xf0,0x1f, 0xe0,0x1f,0xe0,0x1f,0x00,0x00,0x00,0x00}; - wchar_t *sh = 0; - switch (c.shape()) { // map to windows cursor - case Qt::ArrowCursor: - sh = IDC_ARROW; - break; - case Qt::UpArrowCursor: - sh = IDC_UPARROW; - break; - case Qt::CrossCursor: - sh = IDC_CROSS; - break; - case Qt::WaitCursor: - sh = IDC_WAIT; - break; - case Qt::IBeamCursor: - sh = IDC_IBEAM; - break; - case Qt::SizeVerCursor: - sh = IDC_SIZENS; - break; - case Qt::SizeHorCursor: - sh = IDC_SIZEWE; - break; - case Qt::SizeBDiagCursor: - sh = IDC_SIZENESW; - break; - case Qt::SizeFDiagCursor: - sh = IDC_SIZENWSE; - break; - case Qt::SizeAllCursor: - sh = IDC_SIZEALL; - break; - case Qt::ForbiddenCursor: - sh = IDC_NO; - break; - case Qt::WhatsThisCursor: - sh = IDC_HELP; - break; - case Qt::BusyCursor: - sh = IDC_APPSTARTING; - break; - case Qt::PointingHandCursor: - sh = IDC_HAND; - break; - case Qt::BlankCursor: + static const char * const moveDragCursorXpmC[] = { + "11 20 3 1", + ". c None", + "a c #FFFFFF", + "X c #000000", // X11 cursor is traditionally black + "aa.........", + "aXa........", + "aXXa.......", + "aXXXa......", + "aXXXXa.....", + "aXXXXXa....", + "aXXXXXXa...", + "aXXXXXXXa..", + "aXXXXXXXXa.", + "aXXXXXXXXXa", + "aXXXXXXaaaa", + "aXXXaXXa...", + "aXXaaXXa...", + "aXa..aXXa..", + "aa...aXXa..", + "a.....aXXa.", + "......aXXa.", + ".......aXXa", + ".......aXXa", + "........aa."}; + + static const char * const copyDragCursorXpmC[] = { + "24 30 3 1", + ". c None", + "a c #000000", + "X c #FFFFFF", + "XX......................", + "XaX.....................", + "XaaX....................", + "XaaaX...................", + "XaaaaX..................", + "XaaaaaX.................", + "XaaaaaaX................", + "XaaaaaaaX...............", + "XaaaaaaaaX..............", + "XaaaaaaaaaX.............", + "XaaaaaaXXXX.............", + "XaaaXaaX................", + "XaaXXaaX................", + "XaX..XaaX...............", + "XX...XaaX...............", + "X.....XaaX..............", + "......XaaX..............", + ".......XaaX.............", + ".......XaaX.............", + "........XX...aaaaaaaaaaa", + ".............aXXXXXXXXXa", + ".............aXXXXXXXXXa", + ".............aXXXXaXXXXa", + ".............aXXXXaXXXXa", + ".............aXXaaaaaXXa", + ".............aXXXXaXXXXa", + ".............aXXXXaXXXXa", + ".............aXXXXXXXXXa", + ".............aXXXXXXXXXa", + ".............aaaaaaaaaaa"}; + + static const char * const linkDragCursorXpmC[] = { + "24 30 3 1", + ". c None", + "a c #000000", + "X c #FFFFFF", + "XX......................", + "XaX.....................", + "XaaX....................", + "XaaaX...................", + "XaaaaX..................", + "XaaaaaX.................", + "XaaaaaaX................", + "XaaaaaaaX...............", + "XaaaaaaaaX..............", + "XaaaaaaaaaX.............", + "XaaaaaaXXXX.............", + "XaaaXaaX................", + "XaaXXaaX................", + "XaX..XaaX...............", + "XX...XaaX...............", + "X.....XaaX..............", + "......XaaX..............", + ".......XaaX.............", + ".......XaaX.............", + "........XX...aaaaaaaaaaa", + ".............aXXXXXXXXXa", + ".............aXXXaaaaXXa", + ".............aXXXXaaaXXa", + ".............aXXXaaaaXXa", + ".............aXXaaaXaXXa", + ".............aXXaaXXXXXa", + ".............aXXaXXXXXXa", + ".............aXXXaXXXXXa", + ".............aXXXXXXXXXa", + ".............aaaaaaaaaaa"}; + + switch (cursorShape) { case Qt::SplitVCursor: + return createPixmapCursorFromData(systemCursorSize(), standardCursorSize(), 32, vsplit_bits, vsplitm_bits); case Qt::SplitHCursor: + return createPixmapCursorFromData(systemCursorSize(), standardCursorSize(), 32, hsplit_bits, hsplitm_bits); case Qt::OpenHandCursor: + return createPixmapCursorFromData(systemCursorSize(), standardCursorSize(), 16, openhand_bits, openhandm_bits); case Qt::ClosedHandCursor: - case Qt::BitmapCursor: { - QImage bbits, mbits; - bool invb, invm; - if (cshape == Qt::BlankCursor) { - bbits = QImage(32, 32, QImage::Format_Mono); - bbits.fill(0); // ignore color table - mbits = bbits.copy(); - hx = hy = 16; - invb = invm = false; - } else if (cshape == Qt::OpenHandCursor || cshape == Qt::ClosedHandCursor) { - bool open = cshape == Qt::OpenHandCursor; - QBitmap cb = QBitmap::fromData(QSize(16, 16), open ? openhand_bits : closedhand_bits); - QBitmap cm = QBitmap::fromData(QSize(16, 16), open ? openhandm_bits : closedhandm_bits); - bbits = cb.toImage().convertToFormat(QImage::Format_Mono); - mbits = cm.toImage().convertToFormat(QImage::Format_Mono); - hx = hy = 8; - invb = invm = false; - } else if (cshape == Qt::BitmapCursor) { - bbits = c.bitmap()->toImage().convertToFormat(QImage::Format_Mono); - mbits = c.mask()->toImage().convertToFormat(QImage::Format_Mono); - invb = bbits.colorCount() > 1 && qGray(bbits.color(0)) < qGray(bbits.color(1)); - invm = mbits.colorCount() > 1 && qGray(mbits.color(0)) < qGray(mbits.color(1)); - } else { // Qt::SplitVCursor, Qt::SplitHCursor - const QBitmap cb = QBitmap::fromData(QSize(32, 32), cshape == Qt::SplitVCursor ? vsplit_bits : hsplit_bits); - const QBitmap cm = QBitmap::fromData(QSize(32, 32), cshape == Qt::SplitVCursor ? vsplitm_bits : hsplitm_bits); - bbits = cb.toImage().convertToFormat(QImage::Format_Mono); - mbits = cm.toImage().convertToFormat(QImage::Format_Mono); - hx = hy = 16; - invb = invm = false; - } - const int n = qMax(1, bbits.width() / 8); - const int h = bbits.height(); -#if !defined(Q_OS_WINCE) - QScopedArrayPointer<uchar> xBits(new uchar[h * n]); - QScopedArrayPointer<uchar> xMask(new uchar[h * n]); - int x = 0; - for (int i = 0; i < h; ++i) { - uchar *bits = bbits.scanLine(i); - uchar *mask = mbits.scanLine(i); - for (int j = 0; j < n; ++j) { - uchar b = bits[j]; - uchar m = mask[j]; - if (invb) - b ^= 0xff; - if (invm) - m ^= 0xff; - xBits[x] = ~m; - xMask[x] = b ^ m; - ++x; - } - } - return CreateCursor(GetModuleHandle(0), hx, hy, bbits.width(), bbits.height(), - xBits.data(), xMask.data()); -#elif defined(GWES_ICONCURS) // Q_WS_WINCE - // Windows CE only supports fixed cursor size. - int sysW = GetSystemMetrics(SM_CXCURSOR); - int sysH = GetSystemMetrics(SM_CYCURSOR); - int sysN = qMax(1, sysW / 8); - uchar* xBits = new uchar[sysH * sysN]; - uchar* xMask = new uchar[sysH * sysN]; - int x = 0; - for (int i = 0; i < sysH; ++i) { - if (i >= h) { - memset(&xBits[x] , 255, sysN); - memset(&xMask[x] , 0, sysN); - x += sysN; - } else { - int fillWidth = n > sysN ? sysN : n; - uchar *bits = bbits.scanLine(i); - uchar *mask = mbits.scanLine(i); - for (int j = 0; j < fillWidth; ++j) { - uchar b = bits[j]; - uchar m = mask[j]; - if (invb) - b ^= 0xFF; - if (invm) - m ^= 0xFF; - xBits[x] = ~m; - xMask[x] = b ^ m; - ++x; - } - for (int j = fillWidth; j < sysN; ++j ) { - xBits[x] = 255; - xMask[x] = 0; - ++x; - } - } + return createPixmapCursorFromData(systemCursorSize(), standardCursorSize(), 16, closedhand_bits, closedhandm_bits); + case Qt::DragCopyCursor: + return QCursor(QPixmap(copyDragCursorXpmC), 0, 0); + case Qt::DragMoveCursor: + return QCursor(QPixmap(moveDragCursorXpmC), 0, 0); + case Qt::DragLinkCursor: + return QCursor(QPixmap(linkDragCursorXpmC), 0, 0); + } + + return QCursor(); +} +#else // Q_OS_WINCE || QT_NO_IMAGEFORMAT_PNG +struct QWindowsCustomPngCursor { + Qt::CursorShape shape; + int size; + const char *fileName; + int hotSpotX; + int hotSpotY; +}; + +QCursor QWindowsCursor::customCursor(Qt::CursorShape cursorShape) +{ + static const QWindowsCustomPngCursor pngCursors[] = { + { Qt::SplitVCursor, 32, "splitvcursor_32.png", 11, 11 }, + { Qt::SplitVCursor, 48, "splitvcursor_48.png", 16, 17 }, + { Qt::SplitVCursor, 64, "splitvcursor_64.png", 22, 22 }, + { Qt::SplitHCursor, 32, "splithcursor_32.png", 11, 11 }, + { Qt::SplitHCursor, 48, "splithcursor_48.png", 16, 17 }, + { Qt::SplitHCursor, 64, "splithcursor_64.png", 22, 22 }, + { Qt::OpenHandCursor, 32, "openhandcursor_32.png", 10, 12 }, + { Qt::OpenHandCursor, 48, "openhandcursor_48.png", 15, 16 }, + { Qt::OpenHandCursor, 64, "openhandcursor_64.png", 20, 24 }, + { Qt::ClosedHandCursor, 32, "closedhandcursor_32.png", 10, 12 }, + { Qt::ClosedHandCursor, 48, "closedhandcursor_48.png", 15, 16 }, + { Qt::ClosedHandCursor, 64, "closedhandcursor_64.png", 20, 24 }, + { Qt::DragCopyCursor, 32, "dragcopycursor_32.png", 0, 0 }, + { Qt::DragCopyCursor, 48, "dragcopycursor_48.png", 0, 0 }, + { Qt::DragCopyCursor, 64, "dragcopycursor_64.png", 0, 0 }, + { Qt::DragMoveCursor, 32, "dragmovecursor_32.png", 0, 0 }, + { Qt::DragMoveCursor, 48, "dragmovecursor_48.png", 0, 0 }, + { Qt::DragMoveCursor, 64, "dragmovecursor_64.png", 0, 0 }, + { Qt::DragLinkCursor, 32, "draglinkcursor_32.png", 0, 0 }, + { Qt::DragLinkCursor, 48, "draglinkcursor_48.png", 0, 0 }, + { Qt::DragLinkCursor, 64, "draglinkcursor_64.png", 0, 0 } + }; + + const int cursorSize = GetSystemMetrics(SM_CXCURSOR); + const QWindowsCustomPngCursor *sEnd = pngCursors + sizeof(pngCursors) / sizeof(pngCursors[0]); + const QWindowsCustomPngCursor *bestFit = 0; + int sizeDelta = INT_MAX; + for (const QWindowsCustomPngCursor *s = pngCursors; s < sEnd; ++s) { + if (s->shape != cursorShape) + continue; + const int currentSizeDelta = qMax(s->size, cursorSize) - qMin(s->size, cursorSize); + if (currentSizeDelta < sizeDelta) { + bestFit = s; + if (currentSizeDelta == 0) + break; // Perfect match found + sizeDelta = currentSizeDelta; } + } - HCURSOR hcurs = CreateCursor(qWinAppInst(), hx, hy, sysW, sysH, - xBits, xMask); - delete [] xBits; - delete [] xMask; - return hcurs; -#else - Q_UNUSED(n); - Q_UNUSED(h); - return 0; -#endif + if (!bestFit) + return QCursor(); + + const QPixmap rawImage(QStringLiteral(":/qt-project.org/windows/cursors/images/") + + QString::fromLatin1(bestFit->fileName)); + return QCursor(rawImage, bestFit->hotSpotX, bestFit->hotSpotY); +} +#endif // Q_OS_WINCE || QT_NO_IMAGEFORMAT_PNG +struct QWindowsStandardCursorMapping { + Qt::CursorShape shape; + LPCWSTR resource; +}; + +HCURSOR QWindowsCursor::createSystemCursor(const QCursor &c) +{ + static const QWindowsStandardCursorMapping standardCursors[] = { + { Qt::ArrowCursor, IDC_ARROW}, + { Qt::UpArrowCursor, IDC_UPARROW }, + { Qt::CrossCursor, IDC_CROSS }, + { Qt::WaitCursor, IDC_WAIT }, + { Qt::IBeamCursor, IDC_IBEAM }, + { Qt::SizeVerCursor, IDC_SIZENS }, + { Qt::SizeHorCursor, IDC_SIZEWE }, + { Qt::SizeBDiagCursor, IDC_SIZENESW }, + { Qt::SizeFDiagCursor, IDC_SIZENWSE }, + { Qt::SizeAllCursor, IDC_SIZEALL }, + { Qt::ForbiddenCursor, IDC_NO }, + { Qt::WhatsThisCursor, IDC_HELP }, + { Qt::BusyCursor, IDC_APPSTARTING }, + { Qt::PointingHandCursor, IDC_HAND } + }; + + const Qt::CursorShape cursorShape = c.shape(); + switch (cursorShape) { + case Qt::BitmapCursor: { + const QPixmap pixmap = c.pixmap(); + if (!pixmap.isNull()) + return QWindowsCursor::createPixmapCursor(pixmap, c.hotSpot()); + const QImage bbits = c.bitmap()->toImage().convertToFormat(QImage::Format_Mono); + const QImage mbits = c.mask()->toImage().convertToFormat(QImage::Format_Mono); + const bool invb = bbits.colorCount() > 1 && qGray(bbits.color(0)) < qGray(bbits.color(1)); + const bool invm = mbits.colorCount() > 1 && qGray(mbits.color(0)) < qGray(mbits.color(1)); + return createBitmapCursor(bbits, mbits, c.hotSpot(), invb, invm); + } + case Qt::BlankCursor: { + QImage blank = QImage(systemCursorSize(), QImage::Format_Mono); + blank.fill(0); // ignore color table + return createBitmapCursor(blank, blank); } + case Qt::SplitVCursor: + case Qt::SplitHCursor: + case Qt::OpenHandCursor: + case Qt::ClosedHandCursor: case Qt::DragCopyCursor: case Qt::DragMoveCursor: - case Qt::DragLinkCursor: { - const QPixmap pixmap = QGuiApplicationPrivate::instance()->getPixmapCursor(cshape); - return createPixmapCursor(pixmap, hx, hy); - } + case Qt::DragLinkCursor: + return createSystemCursor(customCursor(cursorShape)); default: - qWarning("%s: Invalid cursor shape %d", __FUNCTION__, cshape); - return 0; + break; } -#ifdef Q_OS_WINCE - return LoadCursor(0, sh); + + // Load available standard cursors from resources + const QWindowsStandardCursorMapping *sEnd = standardCursors + sizeof(standardCursors) / sizeof(standardCursors[0]); + for (const QWindowsStandardCursorMapping *s = standardCursors; s < sEnd; ++s) { + if (s->shape == cursorShape) { +#ifndef Q_OS_WINCE + return (HCURSOR)LoadImage(0, s->resource, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED); #else - return (HCURSOR)LoadImage(0, sh, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED); + return LoadCursor(0, s->resource); #endif + } + } + + qWarning("%s: Invalid cursor shape %d", __FUNCTION__, cursorShape); + return 0; } /*! @@ -445,9 +625,15 @@ QWindowsCursor::CursorState QWindowsCursor::cursorState() return CursorHidden; } +QPoint QWindowsCursor::pos() const +{ + return mousePosition() / QWindowsScaling::factor(); +} + void QWindowsCursor::setPos(const QPoint &pos) { - SetCursorPos(pos.x(), pos.y()); + const QPoint posDp = pos * QWindowsScaling::factor(); + SetCursorPos(posDp.x() , posDp.y()); } /*! diff --git a/src/plugins/platforms/windows/qwindowscursor.h b/src/plugins/platforms/windows/qwindowscursor.h index 31da4e367d..89214156e8 100644 --- a/src/plugins/platforms/windows/qwindowscursor.h +++ b/src/plugins/platforms/windows/qwindowscursor.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -101,12 +101,13 @@ public: QWindowsCursor() {} - virtual void changeCursor(QCursor * widgetCursor, QWindow * widget); - virtual QPoint pos() const { return mousePosition(); } - virtual void setPos(const QPoint &pos); + void changeCursor(QCursor * widgetCursor, QWindow * widget) Q_DECL_OVERRIDE; + QPoint pos() const Q_DECL_OVERRIDE; + void setPos(const QPoint &pos) Q_DECL_OVERRIDE; - static HCURSOR createPixmapCursor(const QPixmap &pixmap, int hotX, int hotY); + static HCURSOR createPixmapCursor(const QPixmap &pixmap, const QPoint &hotSpot); static HCURSOR createSystemCursor(const QCursor &c); + static QCursor customCursor(Qt::CursorShape cursorShape); static QPoint mousePosition(); static CursorState cursorState(); diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index f70b5b4e2b..1f930822d8 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -1273,7 +1273,6 @@ void QWindowsNativeFileDialogBase::setLabelText(QFileDialogOptions::DialogLabel { wchar_t *wText = const_cast<wchar_t *>(reinterpret_cast<const wchar_t *>(text.utf16())); switch (l) { - break; case QFileDialogOptions::FileName: m_fileDialog->SetFileNameLabel(wText); break; diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.h b/src/plugins/platforms/windows/qwindowsdialoghelpers.h index bcf9f544b5..864c9e40f5 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.h +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.h @@ -71,11 +71,11 @@ public: typedef QSharedPointer<QWindowsNativeDialogBase> QWindowsNativeDialogBasePtr; ~QWindowsDialogHelperBase() { cleanupThread(); } - virtual void exec(); + void exec() Q_DECL_OVERRIDE; virtual bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent); - virtual void hide(); + void hide() Q_DECL_OVERRIDE; virtual bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const { return true; } diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp index 60c3daff23..e1b4aca0c4 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.cpp +++ b/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -41,6 +41,7 @@ #include "qwindowsdrag.h" #include "qwindowscontext.h" +#include "qwindowsscaling.h" #ifndef QT_NO_CLIPBOARD # include "qwindowsclipboard.h" #endif @@ -50,13 +51,12 @@ #include "qwindowswindow.h" #include "qwindowsmousehandler.h" #include "qwindowscursor.h" +#include "qwindowsscaling.h" #include <QtGui/QMouseEvent> #include <QtGui/QPixmap> #include <QtGui/QPainter> -#include <QtGui/QPaintDevice> -#include <QtGui/QBackingStore> -#include <QtGui/QWindow> +#include <QtGui/QRasterWindow> #include <QtGui/QGuiApplication> #include <qpa/qwindowsysteminterface_p.h> #include <QtGui/private/qguiapplication_p.h> @@ -69,146 +69,6 @@ QT_BEGIN_NAMESPACE -// These pixmaps approximate the images in the Windows User Interface Guidelines. -// XPM - -static const char * const moveDragCursorXpmC[] = { -"11 20 3 1", -". c None", -"a c #FFFFFF", -"X c #000000", // X11 cursor is traditionally black -"aa.........", -"aXa........", -"aXXa.......", -"aXXXa......", -"aXXXXa.....", -"aXXXXXa....", -"aXXXXXXa...", -"aXXXXXXXa..", -"aXXXXXXXXa.", -"aXXXXXXXXXa", -"aXXXXXXaaaa", -"aXXXaXXa...", -"aXXaaXXa...", -"aXa..aXXa..", -"aa...aXXa..", -"a.....aXXa.", -"......aXXa.", -".......aXXa", -".......aXXa", -"........aa."}; - - -/* XPM */ -static const char * const copyDragCursorXpmC[] = { -"24 30 3 1", -". c None", -"a c #000000", -"X c #FFFFFF", -"XX......................", -"XaX.....................", -"XaaX....................", -"XaaaX...................", -"XaaaaX..................", -"XaaaaaX.................", -"XaaaaaaX................", -"XaaaaaaaX...............", -"XaaaaaaaaX..............", -"XaaaaaaaaaX.............", -"XaaaaaaXXXX.............", -"XaaaXaaX................", -"XaaXXaaX................", -"XaX..XaaX...............", -"XX...XaaX...............", -"X.....XaaX..............", -"......XaaX..............", -".......XaaX.............", -".......XaaX.............", -"........XX...aaaaaaaaaaa", -".............aXXXXXXXXXa", -".............aXXXXXXXXXa", -".............aXXXXaXXXXa", -".............aXXXXaXXXXa", -".............aXXaaaaaXXa", -".............aXXXXaXXXXa", -".............aXXXXaXXXXa", -".............aXXXXXXXXXa", -".............aXXXXXXXXXa", -".............aaaaaaaaaaa"}; - -/* XPM */ -static const char * const linkDragCursorXpmC[] = { -"24 30 3 1", -". c None", -"a c #000000", -"X c #FFFFFF", -"XX......................", -"XaX.....................", -"XaaX....................", -"XaaaX...................", -"XaaaaX..................", -"XaaaaaX.................", -"XaaaaaaX................", -"XaaaaaaaX...............", -"XaaaaaaaaX..............", -"XaaaaaaaaaX.............", -"XaaaaaaXXXX.............", -"XaaaXaaX................", -"XaaXXaaX................", -"XaX..XaaX...............", -"XX...XaaX...............", -"X.....XaaX..............", -"......XaaX..............", -".......XaaX.............", -".......XaaX.............", -"........XX...aaaaaaaaaaa", -".............aXXXXXXXXXa", -".............aXXXaaaaXXa", -".............aXXXXaaaXXa", -".............aXXXaaaaXXa", -".............aXXaaaXaXXa", -".............aXXaaXXXXXa", -".............aXXaXXXXXXa", -".............aXXXaXXXXXa", -".............aXXXXXXXXXa", -".............aaaaaaaaaaa"}; - -static const char * const ignoreDragCursorXpmC[] = { -"24 30 3 1", -". c None", -"a c #000000", -"X c #FFFFFF", -"aa......................", -"aXa.....................", -"aXXa....................", -"aXXXa...................", -"aXXXXa..................", -"aXXXXXa.................", -"aXXXXXXa................", -"aXXXXXXXa...............", -"aXXXXXXXXa..............", -"aXXXXXXXXXa.............", -"aXXXXXXaaaa.............", -"aXXXaXXa................", -"aXXaaXXa................", -"aXa..aXXa...............", -"aa...aXXa...............", -"a.....aXXa..............", -"......aXXa.....XXXX.....", -".......aXXa..XXaaaaXX...", -".......aXXa.XaaaaaaaaX..", -"........aa.XaaaXXXXaaaX.", -"...........XaaaaX..XaaX.", -"..........XaaXaaaX..XaaX", -"..........XaaXXaaaX.XaaX", -"..........XaaX.XaaaXXaaX", -"..........XaaX..XaaaXaaX", -"...........XaaX..XaaaaX.", -"...........XaaaXXXXaaaX.", -"............XaaaaaaaaX..", -".............XXaaaaXX...", -"...............XXXX....."}; - /*! \class QWindowsDragCursorWindow \brief A toplevel window showing the drag icon in case of touch drag. @@ -218,7 +78,7 @@ static const char * const ignoreDragCursorXpmC[] = { \ingroup qt-lighthouse-win */ -class QWindowsDragCursorWindow : public QWindow +class QWindowsDragCursorWindow : public QRasterWindow { public: explicit QWindowsDragCursorWindow(QWindow *parent = 0); @@ -226,18 +86,18 @@ public: void setPixmap(const QPixmap &p); protected: - void exposeEvent(QExposeEvent *); + void paintEvent(QPaintEvent *) + { + QPainter painter(this); + painter.drawPixmap(0, 0, m_pixmap); + } private: - void render(); - - QBackingStore m_backingStore; QPixmap m_pixmap; }; QWindowsDragCursorWindow::QWindowsDragCursorWindow(QWindow *parent) - : QWindow(parent) - , m_backingStore(this) + : QRasterWindow(parent) { QSurfaceFormat windowFormat = format(); windowFormat.setAlphaBufferSize(8); @@ -253,31 +113,17 @@ void QWindowsDragCursorWindow::setPixmap(const QPixmap &p) if (p.cacheKey() == m_pixmap.cacheKey()) return; const QSize oldSize = m_pixmap.size(); - const QSize newSize = p.size(); + QSize newSize = p.size(); qCDebug(lcQpaMime) << __FUNCTION__ << p.cacheKey() << newSize; m_pixmap = p; if (oldSize != newSize) { + const qreal pixDevicePixelRatio = p.devicePixelRatio(); + if (pixDevicePixelRatio > 1.0 && qFuzzyCompare(pixDevicePixelRatio, devicePixelRatio())) + newSize /= qRound(pixDevicePixelRatio); resize(newSize); - m_backingStore.resize(newSize); } if (isVisible()) - render(); -} - -void QWindowsDragCursorWindow::exposeEvent(QExposeEvent *) -{ - Q_ASSERT(!m_pixmap.isNull()); - render(); -} - -void QWindowsDragCursorWindow::render() -{ - const QRect rect(QPoint(0, 0), m_pixmap.size()); - m_backingStore.beginPaint(rect); - QPainter painter(m_backingStore.paintDevice()); - painter.drawPixmap(0, 0, m_pixmap); - m_backingStore.endPaint(); - m_backingStore.flush(rect); + update(); } /*! @@ -451,12 +297,19 @@ void QWindowsOleDropSource::createCursors() const QDrag *drag = m_drag->currentDrag(); const QPixmap pixmap = drag->pixmap(); const bool hasPixmap = !pixmap.isNull(); + const int scaleFactor = QWindowsScaling::factor(); + const QSize pixmapSizeDp = pixmap.size() * scaleFactor; + const bool scalePixmap = hasPixmap + && m_mode != TouchDrag // Touch drag: pixmap is shown in a separate QWindow, which will be scaled. + && (scaleFactor != 1 && scaleFactor != qRound(pixmap.devicePixelRatio())); + const QPixmap drawPixmap = scalePixmap + ? pixmap.scaled(pixmapSizeDp, Qt::KeepAspectRatio, Qt::SmoothTransformation) : pixmap; Qt::DropAction actions[] = { Qt::MoveAction, Qt::CopyAction, Qt::LinkAction, Qt::IgnoreAction }; int actionCount = int(sizeof(actions) / sizeof(actions[0])); if (!hasPixmap) --actionCount; // No Qt::IgnoreAction unless pixmap - const QPoint hotSpot = drag->hotSpot(); + const QPoint hotSpot = drag->hotSpot() * scaleFactor; for (int cnum = 0; cnum < actionCount; ++cnum) { const Qt::DropAction action = actions[cnum]; QPixmap cursorPixmap = drag->dragCursor(action); @@ -476,21 +329,20 @@ void QWindowsOleDropSource::createCursors() if (hasPixmap) { const int x1 = qMin(-hotSpot.x(), 0); - const int x2 = qMax(pixmap.width() - hotSpot.x(), cursorPixmap.width()); + const int x2 = qMax(pixmapSizeDp.width() - hotSpot.x(), cursorPixmap.width()); const int y1 = qMin(-hotSpot.y(), 0); - const int y2 = qMax(pixmap.height() - hotSpot.y(), cursorPixmap.height()); + const int y2 = qMax(pixmapSizeDp.height() - hotSpot.y(), cursorPixmap.height()); QPixmap newCursor(x2 - x1 + 1, y2 - y1 + 1); newCursor.fill(Qt::transparent); QPainter p(&newCursor); - const QRect srcRect = pixmap.rect(); const QPoint pmDest = QPoint(qMax(0, -hotSpot.x()), qMax(0, -hotSpot.y())); - p.drawPixmap(pmDest, pixmap, srcRect); + p.drawPixmap(pmDest, drawPixmap); p.drawPixmap(qMax(0, hotSpot.x()),qMax(0, hotSpot.y()), cursorPixmap); newPixmap = newCursor; newHotSpot = QPoint(qMax(0, hotSpot.x()), qMax(0, hotSpot.y())); } - if (const HCURSOR sysCursor = QWindowsCursor::createPixmapCursor(newPixmap, newHotSpot.x(), newHotSpot.y())) { + if (const HCURSOR sysCursor = QWindowsCursor::createPixmapCursor(newPixmap, newHotSpot)) { const CursorEntry entry(newPixmap, cacheKey, DragCursorHandlePtr(new DragCursorHandle(sysCursor)), newHotSpot); if (it == m_cursors.end()) m_cursors.insert(action, entry); @@ -610,7 +462,7 @@ QWindowsOleDropSource::GiveFeedback(DWORD dwEffect) if (!m_touchDragWindow) m_touchDragWindow = new QWindowsDragCursorWindow; m_touchDragWindow->setPixmap(e.pixmap); - m_touchDragWindow->setFramePosition(QWindowsCursor::mousePosition() - e.hotSpot); + m_touchDragWindow->setFramePosition((QWindowsCursor::mousePosition() - e.hotSpot) / QWindowsScaling::factor()); if (!m_touchDragWindow->isVisible()) m_touchDragWindow->show(); break; @@ -686,7 +538,9 @@ void QWindowsOleDropTarget::handleDrag(QWindow *window, DWORD grfKeyState, QGuiApplicationPrivate::mouse_buttons = QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState); const QPlatformDragQtResponse response = - QWindowSystemInterface::handleDrag(window, windowsDrag->dropData(), m_lastPoint, actions); + QWindowSystemInterface::handleDrag(window, windowsDrag->dropData(), + m_lastPoint / QWindowsScaling::factor(), + actions); m_answerRect = response.answerRect(); const Qt::DropAction action = response.acceptedAction(); @@ -778,7 +632,8 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState, QWindowsDrag *windowsDrag = QWindowsDrag::instance(); const QPlatformDropQtResponse response = - QWindowSystemInterface::handleDrop(m_window, windowsDrag->dropData(), m_lastPoint, + QWindowSystemInterface::handleDrop(m_window, windowsDrag->dropData(), + m_lastPoint / QWindowsScaling::factor(), translateToQDragDropActions(*pdwEffect)); if (response.isAccepted()) { @@ -864,22 +719,86 @@ QPixmap QWindowsDrag::defaultCursor(Qt::DropAction action) const switch (action) { case Qt::CopyAction: if (m_copyDragCursor.isNull()) - m_copyDragCursor = QPixmap(copyDragCursorXpmC); + m_copyDragCursor = QWindowsCursor::customCursor(Qt::DragCopyCursor).pixmap(); return m_copyDragCursor; case Qt::TargetMoveAction: case Qt::MoveAction: if (m_moveDragCursor.isNull()) - m_moveDragCursor = QPixmap(moveDragCursorXpmC); + m_moveDragCursor = QWindowsCursor::customCursor(Qt::DragMoveCursor).pixmap(); return m_moveDragCursor; case Qt::LinkAction: if (m_linkDragCursor.isNull()) - m_linkDragCursor = QPixmap(linkDragCursorXpmC); + m_linkDragCursor = QWindowsCursor::customCursor(Qt::DragLinkCursor).pixmap(); return m_linkDragCursor; default: break; } - if (m_ignoreDragCursor.isNull()) + + static const char * const ignoreDragCursorXpmC[] = { + "24 30 3 1", + ". c None", + "a c #000000", + "X c #FFFFFF", + "aa......................", + "aXa.....................", + "aXXa....................", + "aXXXa...................", + "aXXXXa..................", + "aXXXXXa.................", + "aXXXXXXa................", + "aXXXXXXXa...............", + "aXXXXXXXXa..............", + "aXXXXXXXXXa.............", + "aXXXXXXaaaa.............", + "aXXXaXXa................", + "aXXaaXXa................", + "aXa..aXXa...............", + "aa...aXXa...............", + "a.....aXXa..............", + "......aXXa.....XXXX.....", + ".......aXXa..XXaaaaXX...", + ".......aXXa.XaaaaaaaaX..", + "........aa.XaaaXXXXaaaX.", + "...........XaaaaX..XaaX.", + "..........XaaXaaaX..XaaX", + "..........XaaXXaaaX.XaaX", + "..........XaaX.XaaaXXaaX", + "..........XaaX..XaaaXaaX", + "...........XaaX..XaaaaX.", + "...........XaaaXXXXaaaX.", + "............XaaaaaaaaX..", + ".............XXaaaaXX...", + "...............XXXX....."}; + + if (m_ignoreDragCursor.isNull()) { +#if !defined (Q_OS_WINCE) + HCURSOR cursor = LoadCursor(NULL, IDC_NO); + ICONINFO iconInfo = {0, 0, 0, 0, 0}; + GetIconInfo(cursor, &iconInfo); + BITMAP bmColor = {0, 0, 0, 0, 0, 0, 0}; + + if (iconInfo.hbmColor + && GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bmColor) + && bmColor.bmWidth == bmColor.bmWidthBytes / 4) { + const int colorBitsLength = bmColor.bmHeight * bmColor.bmWidthBytes; + uchar *colorBits = new uchar[colorBitsLength]; + GetBitmapBits(iconInfo.hbmColor, colorBitsLength, colorBits); + const QImage colorImage(colorBits, bmColor.bmWidth, bmColor.bmHeight, + bmColor.bmWidthBytes, QImage::Format_ARGB32); + + m_ignoreDragCursor = QPixmap::fromImage(colorImage); + delete [] colorBits; + } else { + m_ignoreDragCursor = QPixmap(ignoreDragCursorXpmC); + } + + DeleteObject(iconInfo.hbmMask); + DeleteObject(iconInfo.hbmColor); + DestroyCursor(cursor); +#else // !Q_OS_WINCE m_ignoreDragCursor = QPixmap(ignoreDragCursorXpmC); +#endif // !Q_OS_WINCE + } return m_ignoreDragCursor; } diff --git a/src/plugins/platforms/windows/qwindowsdrag.h b/src/plugins/platforms/windows/qwindowsdrag.h index 4f758fbf3f..b4d303a10f 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.h +++ b/src/plugins/platforms/windows/qwindowsdrag.h @@ -53,7 +53,7 @@ QT_BEGIN_NAMESPACE class QWindowsDropMimeData : public QWindowsInternalMimeData { public: QWindowsDropMimeData() {} - virtual IDataObject *retrieveDataObject() const; + IDataObject *retrieveDataObject() const Q_DECL_OVERRIDE; }; class QWindowsOleDropTarget : public IDropTarget @@ -90,9 +90,9 @@ public: QWindowsDrag(); virtual ~QWindowsDrag(); - virtual QMimeData *platformDropData() { return &m_dropData; } + QMimeData *platformDropData() Q_DECL_OVERRIDE { return &m_dropData; } - virtual Qt::DropAction drag(QDrag *drag); + Qt::DropAction drag(QDrag *drag) Q_DECL_OVERRIDE; static QWindowsDrag *instance(); diff --git a/src/plugins/platforms/windows/qwindowseglcontext.cpp b/src/plugins/platforms/windows/qwindowseglcontext.cpp index d5ca06bb3f..8892fa6daa 100644 --- a/src/plugins/platforms/windows/qwindowseglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowseglcontext.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -46,7 +46,10 @@ #include <QtCore/QDebug> #include <QtGui/QOpenGLContext> -#include <QtPlatformSupport/private/qeglconvenience_p.h> +#if defined(QT_OPENGL_ES_2_ANGLE) || defined(QT_OPENGL_DYNAMIC) +# define EGL_EGLEXT_PROTOTYPES +# include <QtANGLE/EGL/eglext.h> +#endif QT_BEGIN_NAMESPACE @@ -54,15 +57,292 @@ QT_BEGIN_NAMESPACE \class QWindowsEGLStaticContext \brief Static data for QWindowsEGLContext. - Keeps the display. The class is shared via - QSharedPointer in the windows, the contexts - and in QWindowsIntegration. The display will - be closed if the last instance is deleted. + Keeps the display. The class is shared via QSharedPointer in the windows, the + contexts and in QWindowsIntegration. The display will be closed if the last instance + is deleted. + + No EGL or OpenGL functions are called directly. Instead, they are resolved + dynamically. This works even if the plugin links directly to libegl/libglesv2 so + there is no need to differentiate between dynamic or Angle-only builds in here. \internal \ingroup qt-lighthouse-win */ +QWindowsLibEGL QWindowsEGLStaticContext::libEGL; +QWindowsLibGLESv2 QWindowsEGLStaticContext::libGLESv2; + +#ifndef QT_STATIC + +#ifdef Q_CC_MINGW +static void *resolveFunc(HMODULE lib, const char *name) +{ + QString baseNameStr = QString::fromLatin1(name); + QString nameStr; + void *proc = 0; + + // Play nice with 32-bit mingw: Try func first, then func@0, func@4, + // func@8, func@12, ..., func@64. The def file does not provide any aliases + // in libEGL and libGLESv2 in these builds which results in exporting + // function names like eglInitialize@12. This cannot be fixed without + // breaking binary compatibility. So be flexible here instead. + + int argSize = -1; + while (!proc && argSize <= 64) { + nameStr = baseNameStr; + if (argSize >= 0) + nameStr += QLatin1Char('@') + QString::number(argSize); + argSize = argSize < 0 ? 0 : argSize + 4; + proc = (void *) ::GetProcAddress(lib, nameStr.toLatin1().constData()); + } + return proc; +} +#else +static void *resolveFunc(HMODULE lib, const char *name) +{ +# ifndef Q_OS_WINCE + return (void *) ::GetProcAddress(lib, name); +# else + return (void *) ::GetProcAddress(lib, (const wchar_t *) QString::fromLatin1(name).utf16()); +# endif // Q_OS_WINCE +} +#endif // Q_CC_MINGW + +void *QWindowsLibEGL::resolve(const char *name) +{ + void *proc = m_lib ? resolveFunc(m_lib, name) : 0; + if (!proc) + qErrnoWarning(::GetLastError(), "Failed to resolve EGL function %s", name); + + return proc; +} + +#endif // !QT_STATIC + +#ifndef QT_STATIC +# define RESOLVE(signature, name) signature(resolve( #name )); +#else +# define RESOLVE(signature, name) signature(&::name); +#endif + +bool QWindowsLibEGL::init() +{ +#ifdef QT_DEBUG + const char dllName[] = "libEGLd.dll"; +#else + const char dllName[] = "libEGL.dll"; +#endif + + qCDebug(lcQpaGl) << "Qt: Using EGL from" << dllName; + +#ifndef QT_STATIC + m_lib = ::LoadLibraryW((const wchar_t *) QString::fromLatin1(dllName).utf16()); + if (!m_lib) { + qErrnoWarning(::GetLastError(), "Failed to load %s", dllName); + return false; + } +#endif + + eglGetError = RESOLVE((EGLint (EGLAPIENTRY *)(void)), eglGetError); + eglGetDisplay = RESOLVE((EGLDisplay (EGLAPIENTRY *)(EGLNativeDisplayType)), eglGetDisplay); + eglGetPlatformDisplayEXT = RESOLVE((EGLDisplay (EGLAPIENTRY *)(EGLenum platform, void *native_display, const EGLint *attrib_list)), eglGetPlatformDisplayEXT); + eglInitialize = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay, EGLint *, EGLint *)), eglInitialize); + eglTerminate = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay)), eglTerminate); + eglChooseConfig = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay, const EGLint *, EGLConfig *, EGLint, EGLint *)), eglChooseConfig); + eglGetConfigAttrib = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay, EGLConfig, EGLint, EGLint *)), eglGetConfigAttrib); + eglCreateWindowSurface = RESOLVE((EGLSurface (EGLAPIENTRY *)(EGLDisplay, EGLConfig, EGLNativeWindowType, const EGLint *)), eglCreateWindowSurface); + eglCreatePbufferSurface = RESOLVE((EGLSurface (EGLAPIENTRY *)(EGLDisplay , EGLConfig, const EGLint *)), eglCreatePbufferSurface); + eglDestroySurface = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay , EGLSurface )), eglDestroySurface); + eglBindAPI = RESOLVE((EGLBoolean (EGLAPIENTRY * )(EGLenum )), eglBindAPI); + eglSwapInterval = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay , EGLint )), eglSwapInterval); + eglCreateContext = RESOLVE((EGLContext (EGLAPIENTRY *)(EGLDisplay , EGLConfig , EGLContext , const EGLint *)), eglCreateContext); + eglDestroyContext = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay, EGLContext)), eglDestroyContext); + eglMakeCurrent = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay , EGLSurface , EGLSurface , EGLContext )), eglMakeCurrent); + eglGetCurrentContext = RESOLVE((EGLContext (EGLAPIENTRY *)(void)), eglGetCurrentContext); + eglGetCurrentSurface = RESOLVE((EGLSurface (EGLAPIENTRY *)(EGLint )), eglGetCurrentSurface); + eglGetCurrentDisplay = RESOLVE((EGLDisplay (EGLAPIENTRY *)(void)), eglGetCurrentDisplay); + eglSwapBuffers = RESOLVE((EGLBoolean (EGLAPIENTRY *)(EGLDisplay , EGLSurface)), eglSwapBuffers); + eglGetProcAddress = RESOLVE((__eglMustCastToProperFunctionPointerType (EGLAPIENTRY * )(const char *)), eglGetProcAddress); + + return eglGetError && eglGetDisplay && eglInitialize; +} + +#ifndef QT_STATIC +void *QWindowsLibGLESv2::resolve(const char *name) +{ + void *proc = m_lib ? resolveFunc(m_lib, name) : 0; + if (!proc) + qWarning() << "Failed to resolve OpenGL ES function" << name; + + return proc; +} +#endif // !QT_STATIC + +bool QWindowsLibGLESv2::init() +{ +#ifdef QT_DEBUG + const char dllName[] = "libGLESv2d.dll"; +#else + const char dllName[] = "libGLESv2.dll"; +#endif + + qCDebug(lcQpaGl) << "Qt: Using OpenGL ES 2.0 from" << dllName; +#ifndef QT_STATIC + m_lib = ::LoadLibraryW((const wchar_t *) QString::fromLatin1(dllName).utf16()); + if (!m_lib) { + qErrnoWarning(::GetLastError(), "Failed to load %s", dllName); + return false; + } +#endif // !QT_STATIC + + glBindTexture = RESOLVE((void (APIENTRY *)(GLenum , GLuint )), glBindTexture); + glBlendFunc = RESOLVE((void (APIENTRY *)(GLenum , GLenum )), glBlendFunc); + glClear = RESOLVE((void (APIENTRY *)(GLbitfield )), glClear); + glClearColor = RESOLVE((void (APIENTRY *)(GLfloat , GLfloat , GLfloat , GLfloat )), glClearColor); + glClearStencil = RESOLVE((void (APIENTRY *)(GLint )), glClearStencil); + glColorMask = RESOLVE((void (APIENTRY *)(GLboolean , GLboolean , GLboolean , GLboolean )), glColorMask); + glCopyTexImage2D = RESOLVE((void (APIENTRY *)(GLenum , GLint , GLenum , GLint , GLint , GLsizei , GLsizei , GLint )), glCopyTexImage2D); + glCopyTexSubImage2D = RESOLVE((void (APIENTRY *)(GLenum , GLint , GLint , GLint , GLint , GLint , GLsizei , GLsizei )), glCopyTexSubImage2D); + glCullFace = RESOLVE((void (APIENTRY *)(GLenum )), glCullFace); + glDeleteTextures = RESOLVE((void (APIENTRY *)(GLsizei , const GLuint *)), glDeleteTextures); + glDepthFunc = RESOLVE((void (APIENTRY *)(GLenum )), glDepthFunc); + glDepthMask = RESOLVE((void (APIENTRY *)(GLboolean )), glDepthMask); + glDisable = RESOLVE((void (APIENTRY *)(GLenum )), glDisable); + glDrawArrays = RESOLVE((void (APIENTRY *)(GLenum , GLint , GLsizei )), glDrawArrays); + glDrawElements = RESOLVE((void (APIENTRY *)(GLenum , GLsizei , GLenum , const GLvoid *)), glDrawElements); + glEnable = RESOLVE((void (APIENTRY *)(GLenum )), glEnable); + glFinish = RESOLVE((void (APIENTRY *)()), glFinish); + glFlush = RESOLVE((void (APIENTRY *)()), glFlush); + glFrontFace = RESOLVE((void (APIENTRY *)(GLenum )), glFrontFace); + glGenTextures = RESOLVE((void (APIENTRY *)(GLsizei , GLuint *)), glGenTextures); + glGetBooleanv = RESOLVE((void (APIENTRY *)(GLenum , GLboolean *)), glGetBooleanv); + glGetError = RESOLVE((GLenum (APIENTRY *)()), glGetError); + glGetFloatv = RESOLVE((void (APIENTRY *)(GLenum , GLfloat *)), glGetFloatv); + glGetIntegerv = RESOLVE((void (APIENTRY *)(GLenum , GLint *)), glGetIntegerv); + glGetString = RESOLVE((const GLubyte * (APIENTRY *)(GLenum )), glGetString); + glGetTexParameterfv = RESOLVE((void (APIENTRY *)(GLenum , GLenum , GLfloat *)), glGetTexParameterfv); + glGetTexParameteriv = RESOLVE((void (APIENTRY *)(GLenum , GLenum , GLint *)), glGetTexParameteriv); + glHint = RESOLVE((void (APIENTRY *)(GLenum , GLenum )), glHint); + glIsEnabled = RESOLVE((GLboolean (APIENTRY *)(GLenum )), glIsEnabled); + glIsTexture = RESOLVE((GLboolean (APIENTRY *)(GLuint )), glIsTexture); + glLineWidth = RESOLVE((void (APIENTRY *)(GLfloat )), glLineWidth); + glPixelStorei = RESOLVE((void (APIENTRY *)(GLenum , GLint )), glPixelStorei); + glPolygonOffset = RESOLVE((void (APIENTRY *)(GLfloat , GLfloat )), glPolygonOffset); + glReadPixels = RESOLVE((void (APIENTRY *)(GLint , GLint , GLsizei , GLsizei , GLenum , GLenum , GLvoid *)), glReadPixels); + glScissor = RESOLVE((void (APIENTRY *)(GLint , GLint , GLsizei , GLsizei )), glScissor); + glStencilFunc = RESOLVE((void (APIENTRY *)(GLenum , GLint , GLuint )), glStencilFunc); + glStencilMask = RESOLVE((void (APIENTRY *)(GLuint )), glStencilMask); + glStencilOp = RESOLVE((void (APIENTRY *)(GLenum , GLenum , GLenum )), glStencilOp); + glTexImage2D = RESOLVE((void (APIENTRY *)(GLenum , GLint , GLint , GLsizei , GLsizei , GLint , GLenum , GLenum , const GLvoid *)), glTexImage2D); + glTexParameterf = RESOLVE((void (APIENTRY *)(GLenum , GLenum , GLfloat )), glTexParameterf); + glTexParameterfv = RESOLVE((void (APIENTRY *)(GLenum , GLenum , const GLfloat *)), glTexParameterfv); + glTexParameteri = RESOLVE((void (APIENTRY *)(GLenum , GLenum , GLint )), glTexParameteri); + glTexParameteriv = RESOLVE((void (APIENTRY *)(GLenum , GLenum , const GLint *)), glTexParameteriv); + glTexSubImage2D = RESOLVE((void (APIENTRY *)(GLenum , GLint , GLint , GLint , GLsizei , GLsizei , GLenum , GLenum , const GLvoid *)), glTexSubImage2D); + glViewport = RESOLVE((void (APIENTRY *)(GLint , GLint , GLsizei , GLsizei )), glViewport); + + glActiveTexture = RESOLVE((void (APIENTRY *)(GLenum)), glActiveTexture); + glAttachShader = RESOLVE((void (APIENTRY *)(GLuint , GLuint )), glAttachShader); + glBindAttribLocation = RESOLVE((void (APIENTRY *)(GLuint , GLuint , const GLchar* )), glBindAttribLocation); + glBindBuffer = RESOLVE((void (APIENTRY *)(GLenum , GLuint )), glBindBuffer); + glBindFramebuffer = RESOLVE((void (APIENTRY *)(GLenum , GLuint )), glBindFramebuffer); + glBindRenderbuffer = RESOLVE((void (APIENTRY *)(GLenum , GLuint )), glBindRenderbuffer); + glBlendColor = RESOLVE((void (APIENTRY *)(GLclampf , GLclampf , GLclampf , GLclampf )), glBlendColor); + glBlendEquation = RESOLVE((void (APIENTRY *)(GLenum )), glBlendEquation); + glBlendEquationSeparate = RESOLVE((void (APIENTRY *)(GLenum , GLenum )), glBlendEquationSeparate); + glBlendFuncSeparate = RESOLVE((void (APIENTRY *)(GLenum , GLenum , GLenum , GLenum )), glBlendFuncSeparate); + glBufferData = RESOLVE((void (APIENTRY *)(GLenum , qopengl_GLsizeiptr , const GLvoid* , GLenum )), glBufferData); + glBufferSubData = RESOLVE((void (APIENTRY *)(GLenum , qopengl_GLintptr , qopengl_GLsizeiptr , const GLvoid* )), glBufferSubData); + glCheckFramebufferStatus = RESOLVE((GLenum (APIENTRY *)(GLenum )), glCheckFramebufferStatus); + glCompileShader = RESOLVE((void (APIENTRY *)(GLuint )), glCompileShader); + glCompressedTexImage2D = RESOLVE((void (APIENTRY *)(GLenum , GLint , GLenum , GLsizei , GLsizei, GLint, GLsizei, const GLvoid* )), glCompressedTexImage2D); + glCompressedTexSubImage2D = RESOLVE((void (APIENTRY *)(GLenum , GLint , GLint , GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid* )), glCompressedTexSubImage2D); + glCreateProgram = RESOLVE((GLuint (APIENTRY *)(void)), glCreateProgram); + glCreateShader = RESOLVE((GLuint (APIENTRY *)(GLenum )), glCreateShader); + glDeleteBuffers = RESOLVE((void (APIENTRY *)(GLsizei , const GLuint*)), glDeleteBuffers); + glDeleteFramebuffers = RESOLVE((void (APIENTRY *)(GLsizei , const GLuint* )), glDeleteFramebuffers); + glDeleteProgram = RESOLVE((void (APIENTRY *)(GLuint )), glDeleteProgram); + glDeleteRenderbuffers = RESOLVE((void (APIENTRY *)(GLsizei , const GLuint* )), glDeleteRenderbuffers); + glDeleteShader = RESOLVE((void (APIENTRY *)(GLuint )), glDeleteShader); + glDetachShader = RESOLVE((void (APIENTRY *)(GLuint , GLuint )), glDetachShader); + glDisableVertexAttribArray = RESOLVE((void (APIENTRY *)(GLuint )), glDisableVertexAttribArray); + glEnableVertexAttribArray = RESOLVE((void (APIENTRY *)(GLuint )), glEnableVertexAttribArray); + glFramebufferRenderbuffer = RESOLVE((void (APIENTRY *)(GLenum , GLenum , GLenum , GLuint )), glFramebufferRenderbuffer); + glFramebufferTexture2D = RESOLVE((void (APIENTRY *)(GLenum , GLenum , GLenum , GLuint , GLint )), glFramebufferTexture2D); + glGenBuffers = RESOLVE((void (APIENTRY *)(GLsizei , GLuint* )), glGenBuffers); + glGenerateMipmap = RESOLVE((void (APIENTRY *)(GLenum )), glGenerateMipmap); + glGenFramebuffers = RESOLVE((void (APIENTRY *)(GLsizei , GLuint* )), glGenFramebuffers); + glGenRenderbuffers = RESOLVE((void (APIENTRY *)(GLsizei , GLuint* )), glGenRenderbuffers); + glGetActiveAttrib = RESOLVE((void (APIENTRY *)(GLuint , GLuint , GLsizei , GLsizei* , GLint* , GLenum* , GLchar* )), glGetActiveAttrib); + glGetActiveUniform = RESOLVE((void (APIENTRY *)(GLuint , GLuint , GLsizei , GLsizei* , GLint* , GLenum* , GLchar* )), glGetActiveUniform); + glGetAttachedShaders = RESOLVE((void (APIENTRY *)(GLuint , GLsizei , GLsizei*, GLuint* )), glGetAttachedShaders); + glGetAttribLocation = RESOLVE((int (APIENTRY *)(GLuint , const GLchar* )), glGetAttribLocation); + glGetBufferParameteriv = RESOLVE((void (APIENTRY *)(GLenum , GLenum , GLint* )), glGetBufferParameteriv); + glGetFramebufferAttachmentParameteriv = RESOLVE((void (APIENTRY *)(GLenum , GLenum, GLenum , GLint* )), glGetFramebufferAttachmentParameteriv); + glGetProgramiv = RESOLVE((void (APIENTRY *)(GLuint , GLenum , GLint* )), glGetProgramiv); + glGetProgramInfoLog = RESOLVE((void (APIENTRY *)(GLuint , GLsizei , GLsizei* , GLchar* )), glGetProgramInfoLog); + glGetRenderbufferParameteriv = RESOLVE((void (APIENTRY *)(GLenum , GLenum , GLint* )), glGetRenderbufferParameteriv); + glGetShaderiv = RESOLVE((void (APIENTRY *)(GLuint , GLenum , GLint* )), glGetShaderiv); + glGetShaderInfoLog = RESOLVE((void (APIENTRY *)(GLuint , GLsizei , GLsizei*, GLchar*)), glGetShaderInfoLog); + glGetShaderPrecisionFormat = RESOLVE((void (APIENTRY *)(GLenum , GLenum , GLint* , GLint* )), glGetShaderPrecisionFormat); + glGetShaderSource = RESOLVE((void (APIENTRY *)(GLuint , GLsizei , GLsizei* , GLchar* )), glGetShaderSource); + glGetUniformfv = RESOLVE((void (APIENTRY *)(GLuint , GLint , GLfloat*)), glGetUniformfv); + glGetUniformiv = RESOLVE((void (APIENTRY *)(GLuint , GLint , GLint*)), glGetUniformiv); + glGetUniformLocation = RESOLVE((int (APIENTRY *)(GLuint , const GLchar* )), glGetUniformLocation); + glGetVertexAttribfv = RESOLVE((void (APIENTRY *)(GLuint , GLenum , GLfloat* )), glGetVertexAttribfv); + glGetVertexAttribiv = RESOLVE((void (APIENTRY *)(GLuint , GLenum , GLint* )), glGetVertexAttribiv); + glGetVertexAttribPointerv = RESOLVE((void (APIENTRY *)(GLuint , GLenum , GLvoid** pointer)), glGetVertexAttribPointerv); + glIsBuffer = RESOLVE((GLboolean (APIENTRY *)(GLuint )), glIsBuffer); + glIsFramebuffer = RESOLVE((GLboolean (APIENTRY *)(GLuint )), glIsFramebuffer); + glIsProgram = RESOLVE((GLboolean (APIENTRY *)(GLuint )), glIsProgram); + glIsRenderbuffer = RESOLVE((GLboolean (APIENTRY *)(GLuint )), glIsRenderbuffer); + glIsShader = RESOLVE((GLboolean (APIENTRY *)(GLuint )), glIsShader); + glLinkProgram = RESOLVE((void (APIENTRY *)(GLuint )), glLinkProgram); + glReleaseShaderCompiler = RESOLVE((void (APIENTRY *)(void)), glReleaseShaderCompiler); + glRenderbufferStorage = RESOLVE((void (APIENTRY *)(GLenum , GLenum , GLsizei , GLsizei )), glRenderbufferStorage); + glSampleCoverage = RESOLVE((void (APIENTRY *)(GLclampf , GLboolean )), glSampleCoverage); + glShaderBinary = RESOLVE((void (APIENTRY *)(GLsizei , const GLuint*, GLenum , const GLvoid* , GLsizei )), glShaderBinary); + glShaderSource = RESOLVE((void (APIENTRY *)(GLuint , GLsizei , const GLchar* *, const GLint* )), glShaderSource); + glStencilFuncSeparate = RESOLVE((void (APIENTRY *)(GLenum , GLenum , GLint , GLuint )), glStencilFuncSeparate); + glStencilMaskSeparate = RESOLVE((void (APIENTRY *)(GLenum , GLuint )), glStencilMaskSeparate); + glStencilOpSeparate = RESOLVE((void (APIENTRY *)(GLenum , GLenum , GLenum , GLenum )), glStencilOpSeparate); + glUniform1f = RESOLVE((void (APIENTRY *)(GLint , GLfloat )), glUniform1f); + glUniform1fv = RESOLVE((void (APIENTRY *)(GLint , GLsizei , const GLfloat* )), glUniform1fv); + glUniform1i = RESOLVE((void (APIENTRY *)(GLint , GLint )), glUniform1i); + glUniform1iv = RESOLVE((void (APIENTRY *)(GLint , GLsizei , const GLint* )), glUniform1iv); + glUniform2f = RESOLVE((void (APIENTRY *)(GLint , GLfloat , GLfloat )), glUniform2f); + glUniform2fv = RESOLVE((void (APIENTRY *)(GLint , GLsizei , const GLfloat* )), glUniform2fv); + glUniform2i = RESOLVE((void (APIENTRY *)(GLint , GLint , GLint )), glUniform2i); + glUniform2iv = RESOLVE((void (APIENTRY *)(GLint , GLsizei , const GLint* )), glUniform2iv); + glUniform3f = RESOLVE((void (APIENTRY *)(GLint , GLfloat , GLfloat , GLfloat )), glUniform3f); + glUniform3fv = RESOLVE((void (APIENTRY *)(GLint , GLsizei , const GLfloat* )), glUniform3fv); + glUniform3i = RESOLVE((void (APIENTRY *)(GLint , GLint , GLint , GLint )), glUniform3i); + glUniform3iv = RESOLVE((void (APIENTRY *)(GLint , GLsizei , const GLint* )), glUniform3iv); + glUniform4f = RESOLVE((void (APIENTRY *)(GLint , GLfloat , GLfloat , GLfloat , GLfloat )), glUniform4f); + glUniform4fv = RESOLVE((void (APIENTRY *)(GLint , GLsizei , const GLfloat* )), glUniform4fv); + glUniform4i = RESOLVE((void (APIENTRY *)(GLint , GLint , GLint , GLint , GLint )), glUniform4i); + glUniform4iv = RESOLVE((void (APIENTRY *)(GLint , GLsizei , const GLint* )), glUniform4iv); + glUniformMatrix2fv = RESOLVE((void (APIENTRY *)(GLint , GLsizei , GLboolean , const GLfloat* )), glUniformMatrix2fv); + glUniformMatrix3fv = RESOLVE((void (APIENTRY *)(GLint , GLsizei , GLboolean , const GLfloat* )), glUniformMatrix3fv); + glUniformMatrix4fv = RESOLVE((void (APIENTRY *)(GLint , GLsizei , GLboolean , const GLfloat* )), glUniformMatrix4fv); + glUseProgram = RESOLVE((void (APIENTRY *)(GLuint )), glUseProgram); + glValidateProgram = RESOLVE((void (APIENTRY *)(GLuint )), glValidateProgram); + glVertexAttrib1f = RESOLVE((void (APIENTRY *)(GLuint , GLfloat )), glVertexAttrib1f); + glVertexAttrib1fv = RESOLVE((void (APIENTRY *)(GLuint , const GLfloat* )), glVertexAttrib1fv); + glVertexAttrib2f = RESOLVE((void (APIENTRY *)(GLuint , GLfloat , GLfloat )), glVertexAttrib2f); + glVertexAttrib2fv = RESOLVE((void (APIENTRY *)(GLuint , const GLfloat* )), glVertexAttrib2fv); + glVertexAttrib3f = RESOLVE((void (APIENTRY *)(GLuint , GLfloat , GLfloat , GLfloat )), glVertexAttrib3f); + glVertexAttrib3fv = RESOLVE((void (APIENTRY *)(GLuint , const GLfloat* )), glVertexAttrib3fv); + glVertexAttrib4f = RESOLVE((void (APIENTRY *)(GLuint , GLfloat , GLfloat , GLfloat , GLfloat )), glVertexAttrib4f); + glVertexAttrib4fv = RESOLVE((void (APIENTRY *)(GLuint , const GLfloat* )), glVertexAttrib4fv); + glVertexAttribPointer = RESOLVE((void (APIENTRY *)(GLuint , GLint, GLenum, GLboolean, GLsizei, const GLvoid* )), glVertexAttribPointer); + + glClearDepthf = RESOLVE((void (APIENTRY *)(GLclampf )), glClearDepthf); + glDepthRangef = RESOLVE((void (APIENTRY *)(GLclampf , GLclampf )), glDepthRangef); + + return glBindTexture && glCreateShader && glClearDepthf; +} + QWindowsEGLStaticContext::QWindowsEGLStaticContext(EGLDisplay display, int version) : m_display(display), m_version(version) { @@ -76,7 +356,40 @@ QWindowsEGLStaticContext *QWindowsEGLStaticContext::create() return 0; } - EGLDisplay display = eglGetDisplay((EGLNativeDisplayType)dc); + if (!libEGL.init()) { + qWarning("%s: Failed to load and resolve libEGL functions", Q_FUNC_INFO); + return 0; + } + if (!libGLESv2.init()) { + qWarning("%s: Failed to load and resolve libGLESv2 functions", Q_FUNC_INFO); + return 0; + } + + EGLDisplay display = EGL_NO_DISPLAY; +#ifdef EGL_ANGLE_platform_angle_opengl + if (libEGL.eglGetPlatformDisplayEXT && qEnvironmentVariableIsSet("QT_ANGLE_PLATFORM")) { + const EGLint anglePlatformAttributes[][3] = { + { EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_NONE }, + { EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE, EGL_NONE }, + { EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE, EGL_NONE } + }; + const EGLint *attributes = 0; + const QByteArray anglePlatform = qgetenv("QT_ANGLE_PLATFORM"); + if (anglePlatform == "d3d11") + attributes = anglePlatformAttributes[0]; + else if (anglePlatform == "d3d9") + attributes = anglePlatformAttributes[1]; + else if (anglePlatform == "warp") + attributes = anglePlatformAttributes[2]; + else + qCWarning(lcQpaGl) << "Invalid value set for QT_ANGLE_PLATFORM:" << anglePlatform; + + if (attributes) + display = libEGL.eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, dc, attributes); + } +#endif // EGL_ANGLE_platform_angle_opengl + if (display == EGL_NO_DISPLAY) + display = libEGL.eglGetDisplay((EGLNativeDisplayType)dc); if (!display) { qWarning("%s: Could not obtain EGL display", Q_FUNC_INFO); return 0; @@ -84,9 +397,11 @@ QWindowsEGLStaticContext *QWindowsEGLStaticContext::create() EGLint major; EGLint minor; - if (!eglInitialize(display, &major, &minor)) { - qWarning("%s: Could not initialize egl display: error %d\n", - Q_FUNC_INFO, eglGetError()); + if (!libEGL.eglInitialize(display, &major, &minor)) { + int err = libEGL.eglGetError(); + qWarning("%s: Could not initialize EGL display: error 0x%x\n", Q_FUNC_INFO, err); + if (err == 0x3001) + qWarning("%s: When using ANGLE, check if d3dcompiler_4x.dll is available", Q_FUNC_INFO); return 0; } @@ -97,7 +412,70 @@ QWindowsEGLStaticContext *QWindowsEGLStaticContext::create() QWindowsEGLStaticContext::~QWindowsEGLStaticContext() { qCDebug(lcQpaGl) << __FUNCTION__ << "Releasing EGL display " << m_display; - eglTerminate(m_display); + libEGL.eglTerminate(m_display); +} + +QWindowsOpenGLContext *QWindowsEGLStaticContext::createContext(QOpenGLContext *context) +{ + return new QWindowsEGLContext(this, context->format(), context->shareHandle()); +} + +void *QWindowsEGLStaticContext::createWindowSurface(void *nativeWindow, void *nativeConfig) +{ + EGLSurface surface = libEGL.eglCreateWindowSurface(m_display, (EGLConfig) nativeConfig, + (EGLNativeWindowType) nativeWindow, 0); + if (surface == EGL_NO_SURFACE) + qWarning("%s: Could not create the EGL window surface: 0x%x\n", Q_FUNC_INFO, libEGL.eglGetError()); + + return surface; +} + +void QWindowsEGLStaticContext::destroyWindowSurface(void *nativeSurface) +{ + libEGL.eglDestroySurface(m_display, (EGLSurface) nativeSurface); +} + +QSurfaceFormat QWindowsEGLStaticContext::formatFromConfig(EGLDisplay display, EGLConfig config, + const QSurfaceFormat &referenceFormat) +{ + QSurfaceFormat format; + EGLint redSize = 0; + EGLint greenSize = 0; + EGLint blueSize = 0; + EGLint alphaSize = 0; + EGLint depthSize = 0; + EGLint stencilSize = 0; + EGLint sampleCount = 0; + + libEGL.eglGetConfigAttrib(display, config, EGL_RED_SIZE, &redSize); + libEGL.eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &greenSize); + libEGL.eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &blueSize); + libEGL.eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &alphaSize); + libEGL.eglGetConfigAttrib(display, config, EGL_DEPTH_SIZE, &depthSize); + libEGL.eglGetConfigAttrib(display, config, EGL_STENCIL_SIZE, &stencilSize); + libEGL.eglGetConfigAttrib(display, config, EGL_SAMPLES, &sampleCount); + + format.setRenderableType(QSurfaceFormat::OpenGLES); + format.setVersion(referenceFormat.majorVersion(), referenceFormat.minorVersion()); + format.setProfile(referenceFormat.profile()); + format.setOptions(referenceFormat.options()); + + format.setRedBufferSize(redSize); + format.setGreenBufferSize(greenSize); + format.setBlueBufferSize(blueSize); + format.setAlphaBufferSize(alphaSize); + format.setDepthBufferSize(depthSize); + format.setStencilBufferSize(stencilSize); + format.setSamples(sampleCount); + format.setStereo(false); + format.setSwapInterval(referenceFormat.swapInterval()); + + // Clear the EGL error state because some of the above may + // have errored out because the attribute is not applicable + // to the surface type. Such errors don't matter. + libEGL.eglGetError(); + + return format; } /*! @@ -121,40 +499,472 @@ QWindowsEGLStaticContext::~QWindowsEGLStaticContext() \ingroup qt-lighthouse-win */ -QWindowsEGLContext::QWindowsEGLContext(const QWindowsEGLStaticContextPtr &staticContext, +QWindowsEGLContext::QWindowsEGLContext(QWindowsEGLStaticContext *staticContext, const QSurfaceFormat &format, QPlatformOpenGLContext *share) - : QEGLPlatformContext(format, share, staticContext->display()) - , m_staticContext(staticContext) + : m_staticContext(staticContext) + , m_eglDisplay(staticContext->display()) + , m_api(EGL_OPENGL_ES_API) + , m_swapInterval(-1) { + if (!m_staticContext) + return; + + m_eglConfig = chooseConfig(format); + m_format = m_staticContext->formatFromConfig(m_eglDisplay, m_eglConfig, format); + m_shareContext = share ? static_cast<QWindowsEGLContext *>(share)->m_eglContext : 0; + + QVector<EGLint> contextAttrs; + contextAttrs.append(EGL_CONTEXT_CLIENT_VERSION); + contextAttrs.append(m_format.majorVersion()); + contextAttrs.append(EGL_NONE); + + QWindowsEGLStaticContext::libEGL.eglBindAPI(m_api); + m_eglContext = QWindowsEGLStaticContext::libEGL.eglCreateContext(m_eglDisplay, m_eglConfig, m_shareContext, contextAttrs.constData()); + if (m_eglContext == EGL_NO_CONTEXT && m_shareContext != EGL_NO_CONTEXT) { + m_shareContext = 0; + m_eglContext = QWindowsEGLStaticContext::libEGL.eglCreateContext(m_eglDisplay, m_eglConfig, 0, contextAttrs.constData()); + } + + if (m_eglContext == EGL_NO_CONTEXT) { + qWarning("QWindowsEGLContext: eglError: %x, this: %p \n", QWindowsEGLStaticContext::libEGL.eglGetError(), this); + return; + } + + // Make the context current to ensure the GL version query works. This needs a surface too. + const EGLint pbufferAttributes[] = { + EGL_WIDTH, 1, + EGL_HEIGHT, 1, + EGL_LARGEST_PBUFFER, EGL_FALSE, + EGL_NONE + }; + EGLSurface pbuffer = QWindowsEGLStaticContext::libEGL.eglCreatePbufferSurface(m_eglDisplay, m_eglConfig, pbufferAttributes); + if (pbuffer == EGL_NO_SURFACE) + return; + + EGLDisplay prevDisplay = QWindowsEGLStaticContext::libEGL.eglGetCurrentDisplay(); + if (prevDisplay == EGL_NO_DISPLAY) // when no context is current + prevDisplay = m_eglDisplay; + EGLContext prevContext = QWindowsEGLStaticContext::libEGL.eglGetCurrentContext(); + EGLSurface prevSurfaceDraw = QWindowsEGLStaticContext::libEGL.eglGetCurrentSurface(EGL_DRAW); + EGLSurface prevSurfaceRead = QWindowsEGLStaticContext::libEGL.eglGetCurrentSurface(EGL_READ); + + if (QWindowsEGLStaticContext::libEGL.eglMakeCurrent(m_eglDisplay, pbuffer, pbuffer, m_eglContext)) { + const GLubyte *s = QWindowsEGLStaticContext::libGLESv2.glGetString(GL_VERSION); + if (s) { + QByteArray version = QByteArray(reinterpret_cast<const char *>(s)); + int major, minor; + if (QPlatformOpenGLContext::parseOpenGLVersion(version, major, minor)) { + m_format.setMajorVersion(major); + m_format.setMinorVersion(minor); + } + } + m_format.setProfile(QSurfaceFormat::NoProfile); + m_format.setOptions(QSurfaceFormat::FormatOptions()); + QWindowsEGLStaticContext::libEGL.eglMakeCurrent(prevDisplay, prevSurfaceDraw, prevSurfaceRead, prevContext); + } + QWindowsEGLStaticContext::libEGL.eglDestroySurface(m_eglDisplay, pbuffer); } QWindowsEGLContext::~QWindowsEGLContext() { + if (m_eglContext != EGL_NO_CONTEXT) { + QWindowsEGLStaticContext::libEGL.eglDestroyContext(m_eglDisplay, m_eglContext); + m_eglContext = EGL_NO_CONTEXT; + } } -bool QWindowsEGLContext::hasThreadedOpenGLCapability() +bool QWindowsEGLContext::makeCurrent(QPlatformSurface *surface) { - return false; + Q_ASSERT(surface->surface()->supportsOpenGL()); + + QWindowsEGLStaticContext::libEGL.eglBindAPI(m_api); + + QWindowsWindow *window = static_cast<QWindowsWindow *>(surface); + EGLSurface eglSurface = static_cast<EGLSurface>(window->surface(m_eglConfig)); + Q_ASSERT(eglSurface); + + // shortcut: on some GPUs, eglMakeCurrent is not a cheap operation + if (QWindowsEGLStaticContext::libEGL.eglGetCurrentContext() == m_eglContext && + QWindowsEGLStaticContext::libEGL.eglGetCurrentDisplay() == m_eglDisplay && + QWindowsEGLStaticContext::libEGL.eglGetCurrentSurface(EGL_READ) == eglSurface && + QWindowsEGLStaticContext::libEGL.eglGetCurrentSurface(EGL_DRAW) == eglSurface) { + return true; + } + + const bool ok = QWindowsEGLStaticContext::libEGL.eglMakeCurrent(m_eglDisplay, eglSurface, eglSurface, m_eglContext); + if (ok) { + const int requestedSwapInterval = surface->format().swapInterval(); + if (requestedSwapInterval >= 0 && m_swapInterval != requestedSwapInterval) { + m_swapInterval = requestedSwapInterval; + QWindowsEGLStaticContext::libEGL.eglSwapInterval(m_staticContext->display(), m_swapInterval); + } + } else { + qWarning("QWindowsEGLContext::makeCurrent: eglError: %x, this: %p \n", QWindowsEGLStaticContext::libEGL.eglGetError(), this); + } + + return ok; } -EGLSurface QWindowsEGLContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface) +void QWindowsEGLContext::doneCurrent() { - const QWindowsWindow *window = static_cast<const QWindowsWindow *>(surface); - return window->eglSurfaceHandle(); + QWindowsEGLStaticContext::libEGL.eglBindAPI(m_api); + bool ok = QWindowsEGLStaticContext::libEGL.eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (!ok) + qWarning("QWindowsEGLContext::doneCurrent: eglError: %d, this: %p \n", QWindowsEGLStaticContext::libEGL.eglGetError(), this); } -bool QWindowsEGLContext::makeCurrent(QPlatformSurface *surface) +void QWindowsEGLContext::swapBuffers(QPlatformSurface *surface) { - bool ok = false; + QWindowsEGLStaticContext::libEGL.eglBindAPI(m_api); QWindowsWindow *window = static_cast<QWindowsWindow *>(surface); - if (EGLSurface eglSurface = window->ensureEglSurfaceHandle(m_staticContext, eglConfig())) { - ok = eglMakeCurrent(eglDisplay(), eglSurface, eglSurface, eglContext()); - if (!ok) - qWarning("%s: eglMakeCurrent() failed, eglError: 0x%x, this: %p \n", - Q_FUNC_INFO, eglGetError(), this); + EGLSurface eglSurface = static_cast<EGLSurface>(window->surface(m_eglConfig)); + Q_ASSERT(eglSurface); + + bool ok = QWindowsEGLStaticContext::libEGL.eglSwapBuffers(m_eglDisplay, eglSurface); + if (!ok) + qWarning("QWindowsEGLContext::swapBuffers: eglError: %d, this: %p \n", QWindowsEGLStaticContext::libEGL.eglGetError(), this); +} + +QFunctionPointer QWindowsEGLContext::getProcAddress(const QByteArray &procName) +{ + // We support AllGLFunctionsQueryable, which means this function must be able to + // return a function pointer for standard GLES2 functions too. These are not + // guaranteed to be queryable via eglGetProcAddress(). + static struct StdFunc { + const char *name; + void *func; + } standardFuncs[] = { + { "glBindTexture", (void *) QWindowsEGLStaticContext::libGLESv2.glBindTexture }, + { "glBlendFunc", (void *) QWindowsEGLStaticContext::libGLESv2.glBlendFunc }, + { "glClear", (void *) QWindowsEGLStaticContext::libGLESv2.glClear }, + { "glClearColor", (void *) QWindowsEGLStaticContext::libGLESv2.glClearColor }, + { "glClearStencil", (void *) QWindowsEGLStaticContext::libGLESv2.glClearStencil }, + { "glColorMask", (void *) QWindowsEGLStaticContext::libGLESv2.glColorMask }, + { "glCopyTexImage2D", (void *) QWindowsEGLStaticContext::libGLESv2.glCopyTexImage2D }, + { "glCopyTexSubImage2D", (void *) QWindowsEGLStaticContext::libGLESv2.glCopyTexSubImage2D }, + { "glCullFace", (void *) QWindowsEGLStaticContext::libGLESv2.glCullFace }, + { "glDeleteTextures", (void *) QWindowsEGLStaticContext::libGLESv2.glDeleteTextures }, + { "glDepthFunc", (void *) QWindowsEGLStaticContext::libGLESv2.glDepthFunc }, + { "glDepthMask", (void *) QWindowsEGLStaticContext::libGLESv2.glDepthMask }, + { "glDisable", (void *) QWindowsEGLStaticContext::libGLESv2.glDisable }, + { "glDrawArrays", (void *) QWindowsEGLStaticContext::libGLESv2.glDrawArrays }, + { "glDrawElements", (void *) QWindowsEGLStaticContext::libGLESv2.glDrawElements }, + { "glEnable", (void *) QWindowsEGLStaticContext::libGLESv2.glEnable }, + { "glFinish", (void *) QWindowsEGLStaticContext::libGLESv2.glFinish }, + { "glFlush", (void *) QWindowsEGLStaticContext::libGLESv2.glFlush }, + { "glFrontFace", (void *) QWindowsEGLStaticContext::libGLESv2.glFrontFace }, + { "glGenTextures", (void *) QWindowsEGLStaticContext::libGLESv2.glGenTextures }, + { "glGetBooleanv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetBooleanv }, + { "glGetError", (void *) QWindowsEGLStaticContext::libGLESv2.glGetError }, + { "glGetFloatv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetFloatv }, + { "glGetIntegerv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetIntegerv }, + { "glGetString", (void *) QWindowsEGLStaticContext::libGLESv2.glGetString }, + { "glGetTexParameterfv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetTexParameterfv }, + { "glGetTexParameteriv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetTexParameteriv }, + { "glHint", (void *) QWindowsEGLStaticContext::libGLESv2.glHint }, + { "glIsEnabled", (void *) QWindowsEGLStaticContext::libGLESv2.glIsEnabled }, + { "glIsTexture", (void *) QWindowsEGLStaticContext::libGLESv2.glIsTexture }, + { "glLineWidth", (void *) QWindowsEGLStaticContext::libGLESv2.glLineWidth }, + { "glPixelStorei", (void *) QWindowsEGLStaticContext::libGLESv2.glPixelStorei }, + { "glPolygonOffset", (void *) QWindowsEGLStaticContext::libGLESv2.glPolygonOffset }, + { "glReadPixels", (void *) QWindowsEGLStaticContext::libGLESv2.glReadPixels }, + { "glScissor", (void *) QWindowsEGLStaticContext::libGLESv2.glScissor }, + { "glStencilFunc", (void *) QWindowsEGLStaticContext::libGLESv2.glStencilFunc }, + { "glStencilMask", (void *) QWindowsEGLStaticContext::libGLESv2.glStencilMask }, + { "glStencilOp", (void *) QWindowsEGLStaticContext::libGLESv2.glStencilOp }, + { "glTexImage2D", (void *) QWindowsEGLStaticContext::libGLESv2.glTexImage2D }, + { "glTexParameterf", (void *) QWindowsEGLStaticContext::libGLESv2.glTexParameterf }, + { "glTexParameterfv", (void *) QWindowsEGLStaticContext::libGLESv2.glTexParameterfv }, + { "glTexParameteri", (void *) QWindowsEGLStaticContext::libGLESv2.glTexParameteri }, + { "glTexParameteriv", (void *) QWindowsEGLStaticContext::libGLESv2.glTexParameteriv }, + { "glTexSubImage2D", (void *) QWindowsEGLStaticContext::libGLESv2.glTexSubImage2D }, + { "glViewport", (void *) QWindowsEGLStaticContext::libGLESv2.glViewport }, + + { "glActiveTexture", (void *) QWindowsEGLStaticContext::libGLESv2.glActiveTexture }, + { "glAttachShader", (void *) QWindowsEGLStaticContext::libGLESv2.glAttachShader }, + { "glBindAttribLocation", (void *) QWindowsEGLStaticContext::libGLESv2.glBindAttribLocation }, + { "glBindBuffer", (void *) QWindowsEGLStaticContext::libGLESv2.glBindBuffer }, + { "glBindFramebuffer", (void *) QWindowsEGLStaticContext::libGLESv2.glBindFramebuffer }, + { "glBindRenderbuffer", (void *) QWindowsEGLStaticContext::libGLESv2.glBindRenderbuffer }, + { "glBlendColor", (void *) QWindowsEGLStaticContext::libGLESv2.glBlendColor }, + { "glBlendEquation", (void *) QWindowsEGLStaticContext::libGLESv2.glBlendEquation }, + { "glBlendEquationSeparate", (void *) QWindowsEGLStaticContext::libGLESv2.glBlendEquationSeparate }, + { "glBlendFuncSeparate", (void *) QWindowsEGLStaticContext::libGLESv2.glBlendFuncSeparate }, + { "glBufferData", (void *) QWindowsEGLStaticContext::libGLESv2.glBufferData }, + { "glBufferSubData", (void *) QWindowsEGLStaticContext::libGLESv2.glBufferSubData }, + { "glCheckFramebufferStatus", (void *) QWindowsEGLStaticContext::libGLESv2.glCheckFramebufferStatus }, + { "glCompileShader", (void *) QWindowsEGLStaticContext::libGLESv2.glCompileShader }, + { "glCompressedTexImage2D", (void *) QWindowsEGLStaticContext::libGLESv2.glCompressedTexImage2D }, + { "glCompressedTexSubImage2D", (void *) QWindowsEGLStaticContext::libGLESv2.glCompressedTexSubImage2D }, + { "glCreateProgram", (void *) QWindowsEGLStaticContext::libGLESv2.glCreateProgram }, + { "glCreateShader", (void *) QWindowsEGLStaticContext::libGLESv2.glCreateShader }, + { "glDeleteBuffers", (void *) QWindowsEGLStaticContext::libGLESv2.glDeleteBuffers }, + { "glDeleteFramebuffers", (void *) QWindowsEGLStaticContext::libGLESv2.glDeleteFramebuffers }, + { "glDeleteProgram", (void *) QWindowsEGLStaticContext::libGLESv2.glDeleteProgram }, + { "glDeleteRenderbuffers", (void *) QWindowsEGLStaticContext::libGLESv2.glDeleteRenderbuffers }, + { "glDeleteShader", (void *) QWindowsEGLStaticContext::libGLESv2.glDeleteShader }, + { "glDetachShader", (void *) QWindowsEGLStaticContext::libGLESv2.glDetachShader }, + { "glDisableVertexAttribArray", (void *) QWindowsEGLStaticContext::libGLESv2.glDisableVertexAttribArray }, + { "glEnableVertexAttribArray", (void *) QWindowsEGLStaticContext::libGLESv2.glEnableVertexAttribArray }, + { "glFramebufferRenderbuffer", (void *) QWindowsEGLStaticContext::libGLESv2.glFramebufferRenderbuffer }, + { "glFramebufferTexture2D", (void *) QWindowsEGLStaticContext::libGLESv2.glFramebufferTexture2D }, + { "glGenBuffers", (void *) QWindowsEGLStaticContext::libGLESv2.glGenBuffers }, + { "glGenerateMipmap", (void *) QWindowsEGLStaticContext::libGLESv2.glGenerateMipmap }, + { "glGenFramebuffers", (void *) QWindowsEGLStaticContext::libGLESv2.glGenFramebuffers }, + { "glGenRenderbuffers", (void *) QWindowsEGLStaticContext::libGLESv2.glGenRenderbuffers }, + { "glGetActiveAttrib", (void *) QWindowsEGLStaticContext::libGLESv2.glGetActiveAttrib }, + { "glGetActiveUniform", (void *) QWindowsEGLStaticContext::libGLESv2.glGetActiveUniform }, + { "glGetAttachedShaders", (void *) QWindowsEGLStaticContext::libGLESv2.glGetAttachedShaders }, + { "glGetAttribLocation", (void *) QWindowsEGLStaticContext::libGLESv2.glGetAttribLocation }, + { "glGetBufferParameteriv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetBufferParameteriv }, + { "glGetFramebufferAttachmentParameteriv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetFramebufferAttachmentParameteriv }, + { "glGetProgramiv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetProgramiv }, + { "glGetProgramInfoLog", (void *) QWindowsEGLStaticContext::libGLESv2.glGetProgramInfoLog }, + { "glGetRenderbufferParameteriv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetRenderbufferParameteriv }, + { "glGetShaderiv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetShaderiv }, + { "glGetShaderInfoLog", (void *) QWindowsEGLStaticContext::libGLESv2.glGetShaderInfoLog }, + { "glGetShaderPrecisionFormat", (void *) QWindowsEGLStaticContext::libGLESv2.glGetShaderPrecisionFormat }, + { "glGetShaderSource", (void *) QWindowsEGLStaticContext::libGLESv2.glGetShaderSource }, + { "glGetUniformfv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetUniformfv }, + { "glGetUniformiv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetUniformiv }, + { "glGetUniformLocation", (void *) QWindowsEGLStaticContext::libGLESv2.glGetUniformLocation }, + { "glGetVertexAttribfv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetVertexAttribfv }, + { "glGetVertexAttribiv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetVertexAttribiv }, + { "glGetVertexAttribPointerv", (void *) QWindowsEGLStaticContext::libGLESv2.glGetVertexAttribPointerv }, + { "glIsBuffer", (void *) QWindowsEGLStaticContext::libGLESv2.glIsBuffer }, + { "glIsFramebuffer", (void *) QWindowsEGLStaticContext::libGLESv2.glIsFramebuffer }, + { "glIsProgram", (void *) QWindowsEGLStaticContext::libGLESv2.glIsProgram }, + { "glIsRenderbuffer", (void *) QWindowsEGLStaticContext::libGLESv2.glIsRenderbuffer }, + { "glIsShader", (void *) QWindowsEGLStaticContext::libGLESv2.glIsShader }, + { "glLinkProgram", (void *) QWindowsEGLStaticContext::libGLESv2.glLinkProgram }, + { "glReleaseShaderCompiler", (void *) QWindowsEGLStaticContext::libGLESv2.glReleaseShaderCompiler }, + { "glRenderbufferStorage", (void *) QWindowsEGLStaticContext::libGLESv2.glRenderbufferStorage }, + { "glSampleCoverage", (void *) QWindowsEGLStaticContext::libGLESv2.glSampleCoverage }, + { "glShaderBinary", (void *) QWindowsEGLStaticContext::libGLESv2.glShaderBinary }, + { "glShaderSource", (void *) QWindowsEGLStaticContext::libGLESv2.glShaderSource }, + { "glStencilFuncSeparate", (void *) QWindowsEGLStaticContext::libGLESv2.glStencilFuncSeparate }, + { "glStencilMaskSeparate", (void *) QWindowsEGLStaticContext::libGLESv2.glStencilMaskSeparate }, + { "glStencilOpSeparate", (void *) QWindowsEGLStaticContext::libGLESv2.glStencilOpSeparate }, + { "glUniform1f", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform1f }, + { "glUniform1fv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform1fv }, + { "glUniform1i", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform1i }, + { "glUniform1iv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform1iv }, + { "glUniform2f", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform2f }, + { "glUniform2fv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform2fv }, + { "glUniform2i", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform2i }, + { "glUniform2iv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform2iv }, + { "glUniform3f", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform3f }, + { "glUniform3fv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform3fv }, + { "glUniform3i", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform3i }, + { "glUniform3iv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform3iv }, + { "glUniform4f", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform4f }, + { "glUniform4fv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform4fv }, + { "glUniform4i", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform4i }, + { "glUniform4iv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniform4iv }, + { "glUniformMatrix2fv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniformMatrix2fv }, + { "glUniformMatrix3fv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniformMatrix3fv }, + { "glUniformMatrix4fv", (void *) QWindowsEGLStaticContext::libGLESv2.glUniformMatrix4fv }, + { "glUseProgram", (void *) QWindowsEGLStaticContext::libGLESv2.glUseProgram }, + { "glValidateProgram", (void *) QWindowsEGLStaticContext::libGLESv2.glValidateProgram }, + { "glVertexAttrib1f", (void *) QWindowsEGLStaticContext::libGLESv2.glVertexAttrib1f }, + { "glVertexAttrib1fv", (void *) QWindowsEGLStaticContext::libGLESv2.glVertexAttrib1fv }, + { "glVertexAttrib2f", (void *) QWindowsEGLStaticContext::libGLESv2.glVertexAttrib2f }, + { "glVertexAttrib2fv", (void *) QWindowsEGLStaticContext::libGLESv2.glVertexAttrib2fv }, + { "glVertexAttrib3f", (void *) QWindowsEGLStaticContext::libGLESv2.glVertexAttrib3f }, + { "glVertexAttrib3fv", (void *) QWindowsEGLStaticContext::libGLESv2.glVertexAttrib3fv }, + { "glVertexAttrib4f", (void *) QWindowsEGLStaticContext::libGLESv2.glVertexAttrib4f }, + { "glVertexAttrib4fv", (void *) QWindowsEGLStaticContext::libGLESv2.glVertexAttrib4fv }, + { "glVertexAttribPointer", (void *) QWindowsEGLStaticContext::libGLESv2.glVertexAttribPointer }, + + { "glClearDepthf", (void *) QWindowsEGLStaticContext::libGLESv2.glClearDepthf }, + { "glDepthRangef", (void *) QWindowsEGLStaticContext::libGLESv2.glDepthRangef } + }; + for (size_t i = 0; i < sizeof(standardFuncs) / sizeof(StdFunc); ++i) + if (procName == standardFuncs[i].name) + return reinterpret_cast<QFunctionPointer>(standardFuncs[i].func); + + QWindowsEGLStaticContext::libEGL.eglBindAPI(m_api); + QFunctionPointer procAddress = reinterpret_cast<QFunctionPointer>(QWindowsEGLStaticContext::libEGL.eglGetProcAddress(procName.constData())); + if (QWindowsContext::verbose > 1) + qCDebug(lcQpaGl) << __FUNCTION__ << procName << QWindowsEGLStaticContext::libEGL.eglGetCurrentContext() << "returns" << procAddress; + if (!procAddress && QWindowsContext::verbose) + qWarning("%s: Unable to resolve '%s'", __FUNCTION__, procName.constData()); + return procAddress; +} + +static QVector<EGLint> createConfigAttributesFromFormat(const QSurfaceFormat &format) +{ + int redSize = format.redBufferSize(); + int greenSize = format.greenBufferSize(); + int blueSize = format.blueBufferSize(); + int alphaSize = format.alphaBufferSize(); + int depthSize = format.depthBufferSize(); + int stencilSize = format.stencilBufferSize(); + int sampleCount = format.samples(); + + QVector<EGLint> configAttributes; + configAttributes.reserve(16); + + configAttributes.append(EGL_RED_SIZE); + configAttributes.append(redSize > 0 ? redSize : 0); + + configAttributes.append(EGL_GREEN_SIZE); + configAttributes.append(greenSize > 0 ? greenSize : 0); + + configAttributes.append(EGL_BLUE_SIZE); + configAttributes.append(blueSize > 0 ? blueSize : 0); + + configAttributes.append(EGL_ALPHA_SIZE); + configAttributes.append(alphaSize > 0 ? alphaSize : 0); + + configAttributes.append(EGL_DEPTH_SIZE); + configAttributes.append(depthSize > 0 ? depthSize : 0); + + configAttributes.append(EGL_STENCIL_SIZE); + configAttributes.append(stencilSize > 0 ? stencilSize : 0); + + configAttributes.append(EGL_SAMPLES); + configAttributes.append(sampleCount > 0 ? sampleCount : 0); + + configAttributes.append(EGL_SAMPLE_BUFFERS); + configAttributes.append(sampleCount > 0); + + return configAttributes; +} + +static bool reduceConfigAttributes(QVector<EGLint> *configAttributes) +{ + int i = -1; + + i = configAttributes->indexOf(EGL_SWAP_BEHAVIOR); + if (i >= 0) { + configAttributes->remove(i,2); } - return ok; + + i = configAttributes->indexOf(EGL_BUFFER_SIZE); + if (i >= 0) { + if (configAttributes->at(i+1) == 16) { + configAttributes->remove(i,2); + return true; + } + } + + i = configAttributes->indexOf(EGL_SAMPLES); + if (i >= 0) { + EGLint value = configAttributes->value(i+1, 0); + if (value > 1) + configAttributes->replace(i+1, qMin(EGLint(16), value / 2)); + else + configAttributes->remove(i, 2); + return true; + } + + i = configAttributes->indexOf(EGL_SAMPLE_BUFFERS); + if (i >= 0) { + configAttributes->remove(i,2); + return true; + } + + i = configAttributes->indexOf(EGL_ALPHA_SIZE); + if (i >= 0) { + configAttributes->remove(i,2); +#if defined(EGL_BIND_TO_TEXTURE_RGBA) && defined(EGL_BIND_TO_TEXTURE_RGB) + i = configAttributes->indexOf(EGL_BIND_TO_TEXTURE_RGBA); + if (i >= 0) { + configAttributes->replace(i,EGL_BIND_TO_TEXTURE_RGB); + configAttributes->replace(i+1,true); + + } +#endif + return true; + } + + i = configAttributes->indexOf(EGL_STENCIL_SIZE); + if (i >= 0) { + if (configAttributes->at(i + 1) > 1) + configAttributes->replace(i + 1, 1); + else + configAttributes->remove(i, 2); + return true; + } + + i = configAttributes->indexOf(EGL_DEPTH_SIZE); + if (i >= 0) { + if (configAttributes->at(i + 1) > 1) + configAttributes->replace(i + 1, 1); + else + configAttributes->remove(i, 2); + return true; + } +#ifdef EGL_BIND_TO_TEXTURE_RGB + i = configAttributes->indexOf(EGL_BIND_TO_TEXTURE_RGB); + if (i >= 0) { + configAttributes->remove(i,2); + return true; + } +#endif + + return false; +} + +EGLConfig QWindowsEGLContext::chooseConfig(const QSurfaceFormat &format) +{ + QVector<EGLint> configureAttributes = createConfigAttributesFromFormat(format); + configureAttributes.append(EGL_SURFACE_TYPE); + configureAttributes.append(EGL_WINDOW_BIT); + configureAttributes.append(EGL_RENDERABLE_TYPE); + configureAttributes.append(EGL_OPENGL_ES2_BIT); + configureAttributes.append(EGL_NONE); + + EGLDisplay display = m_staticContext->display(); + EGLConfig cfg = 0; + do { + // Get the number of matching configurations for this set of properties. + EGLint matching = 0; + if (!QWindowsEGLStaticContext::libEGL.eglChooseConfig(display, configureAttributes.constData(), 0, 0, &matching) || !matching) + continue; + + // Fetch all of the matching configurations and find the + // first that matches the pixel format we wanted. + int i = configureAttributes.indexOf(EGL_RED_SIZE); + int confAttrRed = configureAttributes.at(i+1); + i = configureAttributes.indexOf(EGL_GREEN_SIZE); + int confAttrGreen = configureAttributes.at(i+1); + i = configureAttributes.indexOf(EGL_BLUE_SIZE); + int confAttrBlue = configureAttributes.at(i+1); + i = configureAttributes.indexOf(EGL_ALPHA_SIZE); + int confAttrAlpha = i == -1 ? 0 : configureAttributes.at(i+1); + + QVector<EGLConfig> configs(matching); + QWindowsEGLStaticContext::libEGL.eglChooseConfig(display, configureAttributes.constData(), configs.data(), configs.size(), &matching); + if (!cfg && matching > 0) + cfg = configs.first(); + + EGLint red = 0; + EGLint green = 0; + EGLint blue = 0; + EGLint alpha = 0; + for (int i = 0; i < configs.size(); ++i) { + if (confAttrRed) + QWindowsEGLStaticContext::libEGL.eglGetConfigAttrib(display, configs[i], EGL_RED_SIZE, &red); + if (confAttrGreen) + QWindowsEGLStaticContext::libEGL.eglGetConfigAttrib(display, configs[i], EGL_GREEN_SIZE, &green); + if (confAttrBlue) + QWindowsEGLStaticContext::libEGL.eglGetConfigAttrib(display, configs[i], EGL_BLUE_SIZE, &blue); + if (confAttrAlpha) + QWindowsEGLStaticContext::libEGL.eglGetConfigAttrib(display, configs[i], EGL_ALPHA_SIZE, &alpha); + + if (red == confAttrRed && green == confAttrGreen + && blue == confAttrBlue && alpha == confAttrAlpha) + return configs[i]; + } + } while (reduceConfigAttributes(&configureAttributes)); + + if (!cfg) + qWarning("Cannot find EGLConfig, returning null config"); + + return cfg; } QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowseglcontext.h b/src/plugins/platforms/windows/qwindowseglcontext.h index 33653b2f2e..a7866516f0 100644 --- a/src/plugins/platforms/windows/qwindowseglcontext.h +++ b/src/plugins/platforms/windows/qwindowseglcontext.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -42,20 +42,238 @@ #ifndef QWINDOWSEGLCONTEXT_H #define QWINDOWSEGLCONTEXT_H -#include <QtPlatformSupport/private/qeglplatformcontext_p.h> -#include <QSharedPointer> +#include "qwindowsopenglcontext.h" +#include <EGL/egl.h> QT_BEGIN_NAMESPACE -class QWindowsEGLStaticContext +struct QWindowsLibEGL +{ + bool init(); + + EGLint (EGLAPIENTRY * eglGetError)(void); + EGLDisplay (EGLAPIENTRY * eglGetDisplay)(EGLNativeDisplayType display_id); + EGLDisplay (EGLAPIENTRY * eglGetPlatformDisplayEXT)(EGLenum platform, void *native_display, const EGLint *attrib_list); + EGLBoolean (EGLAPIENTRY * eglInitialize)(EGLDisplay dpy, EGLint *major, EGLint *minor); + EGLBoolean (EGLAPIENTRY * eglTerminate)(EGLDisplay dpy); + EGLBoolean (EGLAPIENTRY * eglChooseConfig)(EGLDisplay dpy, const EGLint *attrib_list, + EGLConfig *configs, EGLint config_size, + EGLint *num_config); + EGLBoolean (EGLAPIENTRY * eglGetConfigAttrib)(EGLDisplay dpy, EGLConfig config, + EGLint attribute, EGLint *value); + EGLSurface (EGLAPIENTRY * eglCreateWindowSurface)(EGLDisplay dpy, EGLConfig config, + EGLNativeWindowType win, + const EGLint *attrib_list); + EGLSurface (EGLAPIENTRY * eglCreatePbufferSurface)(EGLDisplay dpy, EGLConfig config, + const EGLint *attrib_list); + EGLBoolean (EGLAPIENTRY * eglDestroySurface)(EGLDisplay dpy, EGLSurface surface); + EGLBoolean (EGLAPIENTRY * eglBindAPI)(EGLenum api); + EGLBoolean (EGLAPIENTRY * eglSwapInterval)(EGLDisplay dpy, EGLint interval); + EGLContext (EGLAPIENTRY * eglCreateContext)(EGLDisplay dpy, EGLConfig config, + EGLContext share_context, + const EGLint *attrib_list); + EGLBoolean (EGLAPIENTRY * eglDestroyContext)(EGLDisplay dpy, EGLContext ctx); + EGLBoolean (EGLAPIENTRY * eglMakeCurrent)(EGLDisplay dpy, EGLSurface draw, + EGLSurface read, EGLContext ctx); + EGLContext (EGLAPIENTRY * eglGetCurrentContext)(void); + EGLSurface (EGLAPIENTRY * eglGetCurrentSurface)(EGLint readdraw); + EGLDisplay (EGLAPIENTRY * eglGetCurrentDisplay)(void); + EGLBoolean (EGLAPIENTRY * eglSwapBuffers)(EGLDisplay dpy, EGLSurface surface); + __eglMustCastToProperFunctionPointerType (EGLAPIENTRY * eglGetProcAddress)(const char *procname); + +private: +#ifndef QT_STATIC + void *resolve(const char *name); + HMODULE m_lib; +#endif +}; + +struct QWindowsLibGLESv2 +{ + bool init(); +#ifndef QT_STATIC + void *moduleHandle() const { return m_lib; } +#else + void *moduleHandle() const { return Q_NULLPTR; } +#endif + + // GL1+GLES2 common + void (APIENTRY * glBindTexture)(GLenum target, GLuint texture); + void (APIENTRY * glBlendFunc)(GLenum sfactor, GLenum dfactor); + void (APIENTRY * glClear)(GLbitfield mask); + void (APIENTRY * glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); + void (APIENTRY * glClearStencil)(GLint s); + void (APIENTRY * glColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); + void (APIENTRY * glCopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); + void (APIENTRY * glCopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY * glCullFace)(GLenum mode); + void (APIENTRY * glDeleteTextures)(GLsizei n, const GLuint* textures); + void (APIENTRY * glDepthFunc)(GLenum func); + void (APIENTRY * glDepthMask)(GLboolean flag); + void (APIENTRY * glDisable)(GLenum cap); + void (APIENTRY * glDrawArrays)(GLenum mode, GLint first, GLsizei count); + void (APIENTRY * glDrawElements)(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices); + void (APIENTRY * glEnable)(GLenum cap); + void (APIENTRY * glFinish)(); + void (APIENTRY * glFlush)(); + void (APIENTRY * glFrontFace)(GLenum mode); + void (APIENTRY * glGenTextures)(GLsizei n, GLuint* textures); + void (APIENTRY * glGetBooleanv)(GLenum pname, GLboolean* params); + GLenum (APIENTRY * glGetError)(); + void (APIENTRY * glGetFloatv)(GLenum pname, GLfloat* params); + void (APIENTRY * glGetIntegerv)(GLenum pname, GLint* params); + const GLubyte * (APIENTRY * glGetString)(GLenum name); + void (APIENTRY * glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat* params); + void (APIENTRY * glGetTexParameteriv)(GLenum target, GLenum pname, GLint* params); + void (APIENTRY * glHint)(GLenum target, GLenum mode); + GLboolean (APIENTRY * glIsEnabled)(GLenum cap); + GLboolean (APIENTRY * glIsTexture)(GLuint texture); + void (APIENTRY * glLineWidth)(GLfloat width); + void (APIENTRY * glPixelStorei)(GLenum pname, GLint param); + void (APIENTRY * glPolygonOffset)(GLfloat factor, GLfloat units); + void (APIENTRY * glReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels); + void (APIENTRY * glScissor)(GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY * glStencilFunc)(GLenum func, GLint ref, GLuint mask); + void (APIENTRY * glStencilMask)(GLuint mask); + void (APIENTRY * glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass); + void (APIENTRY * glTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels); + void (APIENTRY * glTexParameterf)(GLenum target, GLenum pname, GLfloat param); + void (APIENTRY * glTexParameterfv)(GLenum target, GLenum pname, const GLfloat* params); + void (APIENTRY * glTexParameteri)(GLenum target, GLenum pname, GLint param); + void (APIENTRY * glTexParameteriv)(GLenum target, GLenum pname, const GLint* params); + void (APIENTRY * glTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels); + void (APIENTRY * glViewport)(GLint x, GLint y, GLsizei width, GLsizei height); + + // GLES2 + void (APIENTRY * glActiveTexture)(GLenum texture); + void (APIENTRY * glAttachShader)(GLuint program, GLuint shader); + void (APIENTRY * glBindAttribLocation)(GLuint program, GLuint index, const char* name); + void (APIENTRY * glBindBuffer)(GLenum target, GLuint buffer); + void (APIENTRY * glBindFramebuffer)(GLenum target, GLuint framebuffer); + void (APIENTRY * glBindRenderbuffer)(GLenum target, GLuint renderbuffer); + void (APIENTRY * glBlendColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); + void (APIENTRY * glBlendEquation)(GLenum mode); + void (APIENTRY * glBlendEquationSeparate)(GLenum modeRGB, GLenum modeAlpha); + void (APIENTRY * glBlendFuncSeparate)(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); + void (APIENTRY * glBufferData)(GLenum target, qopengl_GLsizeiptr size, const void* data, GLenum usage); + void (APIENTRY * glBufferSubData)(GLenum target, qopengl_GLintptr offset, qopengl_GLsizeiptr size, const void* data); + GLenum (APIENTRY * glCheckFramebufferStatus)(GLenum target); + void (APIENTRY * glCompileShader)(GLuint shader); + void (APIENTRY * glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data); + void (APIENTRY * glCompressedTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data); + GLuint (APIENTRY * glCreateProgram)(); + GLuint (APIENTRY * glCreateShader)(GLenum type); + void (APIENTRY * glDeleteBuffers)(GLsizei n, const GLuint* buffers); + void (APIENTRY * glDeleteFramebuffers)(GLsizei n, const GLuint* framebuffers); + void (APIENTRY * glDeleteProgram)(GLuint program); + void (APIENTRY * glDeleteRenderbuffers)(GLsizei n, const GLuint* renderbuffers); + void (APIENTRY * glDeleteShader)(GLuint shader); + void (APIENTRY * glDetachShader)(GLuint program, GLuint shader); + void (APIENTRY * glDisableVertexAttribArray)(GLuint index); + void (APIENTRY * glEnableVertexAttribArray)(GLuint index); + void (APIENTRY * glFramebufferRenderbuffer)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); + void (APIENTRY * glFramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); + void (APIENTRY * glGenBuffers)(GLsizei n, GLuint* buffers); + void (APIENTRY * glGenerateMipmap)(GLenum target); + void (APIENTRY * glGenFramebuffers)(GLsizei n, GLuint* framebuffers); + void (APIENTRY * glGenRenderbuffers)(GLsizei n, GLuint* renderbuffers); + void (APIENTRY * glGetActiveAttrib)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name); + void (APIENTRY * glGetActiveUniform)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name); + void (APIENTRY * glGetAttachedShaders)(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders); + GLint (APIENTRY * glGetAttribLocation)(GLuint program, const char* name); + void (APIENTRY * glGetBufferParameteriv)(GLenum target, GLenum pname, GLint* params); + void (APIENTRY * glGetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint* params); + void (APIENTRY * glGetProgramiv)(GLuint program, GLenum pname, GLint* params); + void (APIENTRY * glGetProgramInfoLog)(GLuint program, GLsizei bufsize, GLsizei* length, char* infolog); + void (APIENTRY * glGetRenderbufferParameteriv)(GLenum target, GLenum pname, GLint* params); + void (APIENTRY * glGetShaderiv)(GLuint shader, GLenum pname, GLint* params); + void (APIENTRY * glGetShaderInfoLog)(GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog); + void (APIENTRY * glGetShaderPrecisionFormat)(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision); + void (APIENTRY * glGetShaderSource)(GLuint shader, GLsizei bufsize, GLsizei* length, char* source); + void (APIENTRY * glGetUniformfv)(GLuint program, GLint location, GLfloat* params); + void (APIENTRY * glGetUniformiv)(GLuint program, GLint location, GLint* params); + GLint (APIENTRY * glGetUniformLocation)(GLuint program, const char* name); + void (APIENTRY * glGetVertexAttribfv)(GLuint index, GLenum pname, GLfloat* params); + void (APIENTRY * glGetVertexAttribiv)(GLuint index, GLenum pname, GLint* params); + void (APIENTRY * glGetVertexAttribPointerv)(GLuint index, GLenum pname, void** pointer); + GLboolean (APIENTRY * glIsBuffer)(GLuint buffer); + GLboolean (APIENTRY * glIsFramebuffer)(GLuint framebuffer); + GLboolean (APIENTRY * glIsProgram)(GLuint program); + GLboolean (APIENTRY * glIsRenderbuffer)(GLuint renderbuffer); + GLboolean (APIENTRY * glIsShader)(GLuint shader); + void (APIENTRY * glLinkProgram)(GLuint program); + void (APIENTRY * glReleaseShaderCompiler)(); + void (APIENTRY * glRenderbufferStorage)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); + void (APIENTRY * glSampleCoverage)(GLclampf value, GLboolean invert); + void (APIENTRY * glShaderBinary)(GLint n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLint length); + void (APIENTRY * glShaderSource)(GLuint shader, GLsizei count, const char** string, const GLint* length); + void (APIENTRY * glStencilFuncSeparate)(GLenum face, GLenum func, GLint ref, GLuint mask); + void (APIENTRY * glStencilMaskSeparate)(GLenum face, GLuint mask); + void (APIENTRY * glStencilOpSeparate)(GLenum face, GLenum fail, GLenum zfail, GLenum zpass); + void (APIENTRY * glUniform1f)(GLint location, GLfloat x); + void (APIENTRY * glUniform1fv)(GLint location, GLsizei count, const GLfloat* v); + void (APIENTRY * glUniform1i)(GLint location, GLint x); + void (APIENTRY * glUniform1iv)(GLint location, GLsizei count, const GLint* v); + void (APIENTRY * glUniform2f)(GLint location, GLfloat x, GLfloat y); + void (APIENTRY * glUniform2fv)(GLint location, GLsizei count, const GLfloat* v); + void (APIENTRY * glUniform2i)(GLint location, GLint x, GLint y); + void (APIENTRY * glUniform2iv)(GLint location, GLsizei count, const GLint* v); + void (APIENTRY * glUniform3f)(GLint location, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY * glUniform3fv)(GLint location, GLsizei count, const GLfloat* v); + void (APIENTRY * glUniform3i)(GLint location, GLint x, GLint y, GLint z); + void (APIENTRY * glUniform3iv)(GLint location, GLsizei count, const GLint* v); + void (APIENTRY * glUniform4f)(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY * glUniform4fv)(GLint location, GLsizei count, const GLfloat* v); + void (APIENTRY * glUniform4i)(GLint location, GLint x, GLint y, GLint z, GLint w); + void (APIENTRY * glUniform4iv)(GLint location, GLsizei count, const GLint* v); + void (APIENTRY * glUniformMatrix2fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + void (APIENTRY * glUniformMatrix3fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + void (APIENTRY * glUniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + void (APIENTRY * glUseProgram)(GLuint program); + void (APIENTRY * glValidateProgram)(GLuint program); + void (APIENTRY * glVertexAttrib1f)(GLuint indx, GLfloat x); + void (APIENTRY * glVertexAttrib1fv)(GLuint indx, const GLfloat* values); + void (APIENTRY * glVertexAttrib2f)(GLuint indx, GLfloat x, GLfloat y); + void (APIENTRY * glVertexAttrib2fv)(GLuint indx, const GLfloat* values); + void (APIENTRY * glVertexAttrib3f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z); + void (APIENTRY * glVertexAttrib3fv)(GLuint indx, const GLfloat* values); + void (APIENTRY * glVertexAttrib4f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (APIENTRY * glVertexAttrib4fv)(GLuint indx, const GLfloat* values); + void (APIENTRY * glVertexAttribPointer)(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr); + + // ES only + void (APIENTRY * glClearDepthf)(GLclampf depth); + void (APIENTRY * glDepthRangef)(GLclampf nearVal, GLclampf farVal); + +private: +#ifndef QT_STATIC + void *resolve(const char *name); + HMODULE m_lib; +#endif +}; + +class QWindowsEGLStaticContext : public QWindowsStaticOpenGLContext { Q_DISABLE_COPY(QWindowsEGLStaticContext) + public: static QWindowsEGLStaticContext *create(); ~QWindowsEGLStaticContext(); EGLDisplay display() const { return m_display; } + QWindowsOpenGLContext *createContext(QOpenGLContext *context); + void *moduleHandle() const { return libGLESv2.moduleHandle(); } + QOpenGLContext::OpenGLModuleType moduleType() const { return QOpenGLContext::LibGLES; } + + void *createWindowSurface(void *nativeWindow, void *nativeConfig) Q_DECL_OVERRIDE; + void destroyWindowSurface(void *nativeSurface) Q_DECL_OVERRIDE; + + QSurfaceFormat formatFromConfig(EGLDisplay display, EGLConfig config, const QSurfaceFormat &referenceFormat); + + static QWindowsLibEGL libEGL; + static QWindowsLibGLESv2 libGLESv2; + private: QWindowsEGLStaticContext(EGLDisplay display, int version); @@ -63,26 +281,38 @@ private: const int m_version; //! majorVersion<<8 + minorVersion }; -class QWindowsEGLContext : public QEGLPlatformContext +class QWindowsEGLContext : public QWindowsOpenGLContext { public: - typedef QSharedPointer<QWindowsEGLStaticContext> QWindowsEGLStaticContextPtr; - - QWindowsEGLContext(const QWindowsEGLStaticContextPtr& staticContext, + QWindowsEGLContext(QWindowsEGLStaticContext *staticContext, const QSurfaceFormat &format, QPlatformOpenGLContext *share); - ~QWindowsEGLContext(); - static bool hasThreadedOpenGLCapability(); + bool makeCurrent(QPlatformSurface *surface) Q_DECL_OVERRIDE; + void doneCurrent() Q_DECL_OVERRIDE; + void swapBuffers(QPlatformSurface *surface) Q_DECL_OVERRIDE; + QFunctionPointer getProcAddress(const QByteArray &procName) Q_DECL_OVERRIDE; - bool makeCurrent(QPlatformSurface *surface); + QSurfaceFormat format() const Q_DECL_OVERRIDE { return m_format; } + bool isSharing() const Q_DECL_OVERRIDE { return m_shareContext != EGL_NO_CONTEXT; } + bool isValid() const Q_DECL_OVERRIDE { return m_eglContext != EGL_NO_CONTEXT; } -protected: - EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface); + void *nativeContext() const Q_DECL_OVERRIDE { return m_eglContext; } + void *nativeDisplay() const Q_DECL_OVERRIDE { return m_eglDisplay; } + void *nativeConfig() const Q_DECL_OVERRIDE { return m_eglConfig; } private: - const QWindowsEGLStaticContextPtr m_staticContext; + EGLConfig chooseConfig(const QSurfaceFormat &format); + + QWindowsEGLStaticContext *m_staticContext; + EGLContext m_eglContext; + EGLContext m_shareContext; + EGLDisplay m_eglDisplay; + EGLConfig m_eglConfig; + QSurfaceFormat m_format; + EGLenum m_api; + int m_swapInterval; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp index f30dcbaa32..7dbca6c089 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp @@ -164,25 +164,24 @@ namespace { { Q_ASSERT(tagName.size() == 4); quint32 tagId = *(reinterpret_cast<const quint32 *>(tagName.constData())); - if (Q_UNLIKELY(m_fontData.size() < sizeof(OffsetSubTable))) + const size_t fontDataSize = m_fontData.size(); + if (Q_UNLIKELY(fontDataSize < sizeof(OffsetSubTable))) return 0; OffsetSubTable *offsetSubTable = reinterpret_cast<OffsetSubTable *>(m_fontData.data()); TableDirectory *tableDirectory = reinterpret_cast<TableDirectory *>(offsetSubTable + 1); - quint16 tableCount = qFromBigEndian<quint16>(offsetSubTable->numTables); - if (Q_UNLIKELY(quint32(m_fontData.size()) < sizeof(OffsetSubTable) + sizeof(TableDirectory) * tableCount)) + const size_t tableCount = qFromBigEndian<quint16>(offsetSubTable->numTables); + if (Q_UNLIKELY(fontDataSize < sizeof(OffsetSubTable) + sizeof(TableDirectory) * tableCount)) return 0; - TableDirectory *nameTableDirectoryEntry = 0; - for (int i = 0; i < tableCount; ++i, ++tableDirectory) { - if (tableDirectory->identifier == tagId) { - nameTableDirectoryEntry = tableDirectory; - break; - } + TableDirectory *tableDirectoryEnd = tableDirectory + tableCount; + for (TableDirectory *entry = tableDirectory; entry < tableDirectoryEnd; ++entry) { + if (entry->identifier == tagId) + return entry; } - return nameTableDirectoryEntry; + return 0; } QString EmbeddedFont::familyName(TableDirectory *nameTableDirectoryEntry) @@ -1064,7 +1063,7 @@ QFontEngineMulti *QWindowsFontDatabase::fontEngineMulti(QFontEngine *fontEngine, if (script == QChar::Script_Common) return new QWindowsMultiFontEngine(fontEngine, script); // ### as long as fallbacksForFamily() does not take script parameter into account, - // prefer QFontEngineMultiQPA's loadEngine() implementation for complex scripts + // prefer QFontEngineMultiBasicImpl's loadEngine() implementation for complex scripts return QPlatformFontDatabase::fontEngineMulti(fontEngine, script); } @@ -1521,13 +1520,15 @@ LOGFONT QWindowsFontDatabase::fontDefToLOGFONT(const QFontDef &request) #endif if (request.styleStrategy & QFont::PreferAntialias) { - if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP) { + if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP && !(request.styleStrategy & QFont::NoSubpixelAntialias)) { qual = CLEARTYPE_QUALITY; } else { qual = ANTIALIASED_QUALITY; } } else if (request.styleStrategy & QFont::NoAntialias) { qual = NONANTIALIASED_QUALITY; + } else if ((request.styleStrategy & QFont::NoSubpixelAntialias) && sharedFontData()->clearTypeEnabled) { + qual = ANTIALIASED_QUALITY; } lf.lfQuality = qual; @@ -1613,37 +1614,36 @@ QStringList QWindowsFontDatabase::extraTryFontsForFamily(const QString &family) return result; } +QString QWindowsFontDatabase::familyForStyleHint(QFont::StyleHint styleHint) +{ + switch (styleHint) { + case QFont::Times: + return QStringLiteral("Times New Roman"); + case QFont::Courier: + return QStringLiteral("Courier New"); + case QFont::Monospace: + return QStringLiteral("Courier New"); + case QFont::Cursive: + return QStringLiteral("Comic Sans MS"); + case QFont::Fantasy: + return QStringLiteral("Impact"); + case QFont::Decorative: + return QStringLiteral("Old English"); + case QFont::Helvetica: + return QStringLiteral("Arial"); + case QFont::System: + default: + break; + } + return QStringLiteral("MS Shell Dlg 2"); +} + QStringList QWindowsFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const { QStringList result = QPlatformFontDatabase::fallbacksForFamily(family, style, styleHint, script); if (!result.isEmpty()) return result; - - switch (styleHint) { - case QFont::Times: - result << QString::fromLatin1("Times New Roman"); - break; - case QFont::Courier: - result << QString::fromLatin1("Courier New"); - break; - case QFont::Monospace: - result << QString::fromLatin1("Courier New"); - break; - case QFont::Cursive: - result << QString::fromLatin1("Comic Sans MS"); - break; - case QFont::Fantasy: - result << QString::fromLatin1("Impact"); - break; - case QFont::Decorative: - result << QString::fromLatin1("Old English"); - break; - case QFont::Helvetica: - case QFont::System: - default: - result << QString::fromLatin1("Arial"); - } - + result.append(QWindowsFontDatabase::familyForStyleHint(styleHint)); result.append(QWindowsFontDatabase::extraTryFontsForFamily(family)); qCDebug(lcQpaFonts) << __FUNCTION__ << family << style << styleHint diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.h b/src/plugins/platforms/windows/qwindowsfontdatabase.h index a2324544d2..1ef346a430 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.h +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.h @@ -77,17 +77,17 @@ public: QWindowsFontDatabase(); ~QWindowsFontDatabase(); - virtual void populateFontDatabase(); - virtual QFontEngineMulti *fontEngineMulti(QFontEngine *fontEngine, QChar::Script script); - virtual QFontEngine *fontEngine(const QFontDef &fontDef, void *handle); - virtual QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference); - virtual QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const; - virtual QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName); - virtual void releaseHandle(void *handle); - virtual QString fontDir() const; - - virtual QFont defaultFont() const { return systemDefaultFont(); } - virtual bool fontsAlwaysScalable() const; + void populateFontDatabase() Q_DECL_OVERRIDE; + QFontEngineMulti *fontEngineMulti(QFontEngine *fontEngine, QChar::Script script) Q_DECL_OVERRIDE; + QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) Q_DECL_OVERRIDE; + QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) Q_DECL_OVERRIDE; + QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const Q_DECL_OVERRIDE; + QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName) Q_DECL_OVERRIDE; + void releaseHandle(void *handle) Q_DECL_OVERRIDE; + QString fontDir() const Q_DECL_OVERRIDE; + + QFont defaultFont() const Q_DECL_OVERRIDE { return systemDefaultFont(); } + bool fontsAlwaysScalable() const Q_DECL_OVERRIDE; void derefUniqueFont(const QString &uniqueFont); void refUniqueFont(const QString &uniqueFont); @@ -104,6 +104,7 @@ public: static LOGFONT fontDefToLOGFONT(const QFontDef &fontDef); static QStringList extraTryFontsForFamily(const QString &family); + static QString familyForStyleHint(QFont::StyleHint styleHint); private: void populate(const QString &family = QString()); diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp index 734f645e65..2f038106de 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp @@ -442,30 +442,7 @@ QStringList QWindowsFontDatabaseFT::fallbacksForFamily(const QString &family, QF if (!result.isEmpty()) return result; - switch (styleHint) { - case QFont::Times: - result << QString::fromLatin1("Times New Roman"); - break; - case QFont::Courier: - result << QString::fromLatin1("Courier New"); - break; - case QFont::Monospace: - result << QString::fromLatin1("Courier New"); - break; - case QFont::Cursive: - result << QString::fromLatin1("Comic Sans MS"); - break; - case QFont::Fantasy: - result << QString::fromLatin1("Impact"); - break; - case QFont::Decorative: - result << QString::fromLatin1("Old English"); - break; - case QFont::Helvetica: - case QFont::System: - default: - result << QString::fromLatin1("Arial"); - } + result.append(QWindowsFontDatabase::familyForStyleHint(styleHint)); #ifdef Q_OS_WINCE QSettings settings(QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\FontLink\\SystemLink"), QSettings::NativeFormat); diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h index bad6c54bf4..cf6108d87a 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h +++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h @@ -57,8 +57,8 @@ public: QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const; - virtual QString fontDir() const; - virtual QFont defaultFont() const; + QString fontDir() const Q_DECL_OVERRIDE; + QFont defaultFont() const Q_DECL_OVERRIDE; private: void populate(const QString &family = QString()); diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp index 4efedb7bc7..d872004846 100644 --- a/src/plugins/platforms/windows/qwindowsfontengine.cpp +++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp @@ -111,11 +111,6 @@ static void resolveGetCharWidthI() ptrGetCharWidthI = (PtrGetCharWidthI)QSystemLibrary::resolve(QStringLiteral("gdi32"), "GetCharWidthI"); } -// defined in qtextengine_win.cpp -typedef void *SCRIPT_CACHE; -typedef HRESULT (WINAPI *fScriptFreeCache)(SCRIPT_CACHE *); -extern fScriptFreeCache ScriptFreeCache; - static inline quint32 getUInt(unsigned char *p) { quint32 val; @@ -805,13 +800,34 @@ static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc, mat.eM11.fract = mat.eM22.fract = 0; mat.eM21.value = mat.eM12.value = 0; mat.eM21.fract = mat.eM12.fract = 0; + + GLYPHMETRICS gMetric; + memset(&gMetric, 0, sizeof(GLYPHMETRICS)); + +#ifndef Q_OS_WINCE + if (metric) { + // If metrics requested, retrieve first using GGO_METRICS, because the returned + // values are incorrect for OpenType PS fonts if obtained at the same time as the + // glyph paths themselves (ie. with GGO_NATIVE as the format). + uint format = GGO_METRICS; + if (ttf) + format |= GGO_GLYPH_INDEX; + int res = GetGlyphOutline(hdc, glyph, format, &gMetric, 0, 0, &mat); + if (res == GDI_ERROR) { + return false; + } + // #### obey scale + *metric = glyph_metrics_t(gMetric.gmptGlyphOrigin.x, -gMetric.gmptGlyphOrigin.y, + (int)gMetric.gmBlackBoxX, (int)gMetric.gmBlackBoxY, + gMetric.gmCellIncX, gMetric.gmCellIncY); + } +#endif + uint glyphFormat = GGO_NATIVE; if (ttf) glyphFormat |= GGO_GLYPH_INDEX; - GLYPHMETRICS gMetric; - memset(&gMetric, 0, sizeof(GLYPHMETRICS)); int bufferSize = GDI_ERROR; bufferSize = GetGlyphOutline(hdc, glyph, glyphFormat, &gMetric, 0, 0, &mat); if ((DWORD)bufferSize == GDI_ERROR) { @@ -826,12 +842,14 @@ static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc, return false; } - if(metric) { +#ifdef Q_OS_WINCE + if (metric) { // #### obey scale *metric = glyph_metrics_t(gMetric.gmptGlyphOrigin.x, -gMetric.gmptGlyphOrigin.y, (int)gMetric.gmBlackBoxX, (int)gMetric.gmBlackBoxY, gMetric.gmCellIncX, gMetric.gmCellIncY); } +#endif int offset = 0; int headerOffset = 0; @@ -1300,7 +1318,7 @@ void QWindowsFontEngine::initFontInfo(const QFontDef &request, Will probably be superseded by a common Free Type font engine in Qt 5.X. */ QWindowsMultiFontEngine::QWindowsMultiFontEngine(QFontEngine *fe, int script) - : QFontEngineMultiQPA(fe, script) + : QFontEngineMultiBasicImpl(fe, script) { } diff --git a/src/plugins/platforms/windows/qwindowsfontengine.h b/src/plugins/platforms/windows/qwindowsfontengine.h index 0ddf778fa0..8fe063121a 100644 --- a/src/plugins/platforms/windows/qwindowsfontengine.h +++ b/src/plugins/platforms/windows/qwindowsfontengine.h @@ -53,7 +53,7 @@ // We mean it. // -#include <QtGui/private/qfontengine_qpa_p.h> +#include <QtGui/private/qfontengine_p.h> #include <QtGui/QImage> #include <QtCore/QSharedPointer> @@ -78,48 +78,48 @@ public: void initFontInfo(const QFontDef &request, HDC fontHdc, int dpi); - virtual QFixed lineThickness() const; - virtual Properties properties() const; - virtual void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics); - virtual FaceId faceId() const; - virtual bool getSfntTableData(uint tag, uchar *buffer, uint *length) const; - virtual int synthesized() const; - virtual QFixed emSquareSize() const; + QFixed lineThickness() const Q_DECL_OVERRIDE; + Properties properties() const Q_DECL_OVERRIDE; + void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics) Q_DECL_OVERRIDE; + FaceId faceId() const Q_DECL_OVERRIDE; + bool getSfntTableData(uint tag, uchar *buffer, uint *length) const Q_DECL_OVERRIDE; + int synthesized() const Q_DECL_OVERRIDE; + QFixed emSquareSize() const Q_DECL_OVERRIDE; - virtual glyph_t glyphIndex(uint ucs4) const; - virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const; - virtual void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags) const; + glyph_t glyphIndex(uint ucs4) const Q_DECL_OVERRIDE; + bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const Q_DECL_OVERRIDE; + void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags) const Q_DECL_OVERRIDE; - virtual void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags); + void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags) Q_DECL_OVERRIDE; virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, QPainterPath *path, QTextItem::RenderFlags flags); HGDIOBJ selectDesignFont() const; - virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs); - virtual glyph_metrics_t boundingBox(glyph_t g) { return boundingBox(g, QTransform()); } - virtual glyph_metrics_t boundingBox(glyph_t g, const QTransform &t); + glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) Q_DECL_OVERRIDE; + glyph_metrics_t boundingBox(glyph_t g) Q_DECL_OVERRIDE { return boundingBox(g, QTransform()); } + glyph_metrics_t boundingBox(glyph_t g, const QTransform &t) Q_DECL_OVERRIDE; - virtual QFixed ascent() const; - virtual QFixed descent() const; - virtual QFixed leading() const; - virtual QFixed xHeight() const; - virtual QFixed averageCharWidth() const; - virtual qreal maxCharWidth() const; - virtual qreal minLeftBearing() const; - virtual qreal minRightBearing() const; + QFixed ascent() const Q_DECL_OVERRIDE; + QFixed descent() const Q_DECL_OVERRIDE; + QFixed leading() const Q_DECL_OVERRIDE; + QFixed xHeight() const Q_DECL_OVERRIDE; + QFixed averageCharWidth() const Q_DECL_OVERRIDE; + qreal maxCharWidth() const Q_DECL_OVERRIDE; + qreal minLeftBearing() const Q_DECL_OVERRIDE; + qreal minRightBearing() const Q_DECL_OVERRIDE; - virtual QImage alphaMapForGlyph(glyph_t t) { return alphaMapForGlyph(t, QTransform()); } - virtual QImage alphaMapForGlyph(glyph_t, const QTransform &xform); - virtual QImage alphaRGBMapForGlyph(glyph_t t, QFixed subPixelPosition, const QTransform &xform); - virtual glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, QFixed, const QTransform &matrix, GlyphFormat); + QImage alphaMapForGlyph(glyph_t t) Q_DECL_OVERRIDE { return alphaMapForGlyph(t, QTransform()); } + QImage alphaMapForGlyph(glyph_t, const QTransform &xform) Q_DECL_OVERRIDE; + QImage alphaRGBMapForGlyph(glyph_t t, QFixed subPixelPosition, const QTransform &xform) Q_DECL_OVERRIDE; + glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, QFixed, const QTransform &matrix, GlyphFormat) Q_DECL_OVERRIDE; - virtual QFontEngine *cloneWithSize(qreal pixelSize) const; - virtual bool supportsTransformation(const QTransform &transform) const; + QFontEngine *cloneWithSize(qreal pixelSize) const Q_DECL_OVERRIDE; + bool supportsTransformation(const QTransform &transform) const Q_DECL_OVERRIDE; #ifndef Q_CC_MINGW - virtual void getGlyphBearings(glyph_t glyph, qreal *leftBearing = 0, qreal *rightBearing = 0); + void getGlyphBearings(glyph_t glyph, qreal *leftBearing = 0, qreal *rightBearing = 0) Q_DECL_OVERRIDE; #endif bool hasUnreliableGlyphOutline() const Q_DECL_OVERRIDE; @@ -172,7 +172,7 @@ private: }; -class QWindowsMultiFontEngine : public QFontEngineMultiQPA +class QWindowsMultiFontEngine : public QFontEngineMultiBasicImpl { public: explicit QWindowsMultiFontEngine(QFontEngine *fe, int script); diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp index 8f55e20536..15b14aff1a 100644 --- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp +++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp @@ -574,7 +574,7 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, int size = width * height * 3; BYTE *alphaValues = new BYTE[size]; - memset(alphaValues, size, 0); + memset(alphaValues, 0, size); hr = glyphAnalysis->CreateAlphaTexture(DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h index 2da014ddc3..9ee074b33e 100644 --- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h +++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h @@ -74,7 +74,7 @@ public: bool getSfntTableData(uint tag, uchar *buffer, uint *length) const; QFixed emSquareSize() const; - virtual glyph_t glyphIndex(uint ucs4) const; + glyph_t glyphIndex(uint ucs4) const Q_DECL_OVERRIDE; bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const; void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags) const; diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp index eaa4eca84e..869df26ef6 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -48,6 +48,7 @@ #include <QtCore/QSysInfo> #include <QtGui/QGuiApplication> #include <qpa/qplatformnativeinterface.h> +#include <QtPlatformHeaders/QWGLNativeContext> #include <algorithm> @@ -144,6 +145,131 @@ QT_BEGIN_NAMESPACE +QWindowsOpengl32DLL QOpenGLStaticContext::opengl32; + +void *QWindowsOpengl32DLL::resolve(const char *name) +{ +#ifndef Q_OS_WINCE + void *proc = m_lib ? (void *) ::GetProcAddress(m_lib, name) : 0; +#else + void *proc = m_lib ? (void *) ::GetProcAddress(m_lib, (const wchar_t *) QString::fromLatin1(name).utf16()) : 0; +#endif + if (!proc) + qErrnoWarning(::GetLastError(), "Failed to resolve OpenGL function %s", name); + + return proc; +} + +bool QWindowsOpengl32DLL::init(bool softwareRendering) +{ + const QByteArray opengl32 = QByteArrayLiteral("opengl32.dll"); + const QByteArray swopengl = QByteArrayLiteral("QtSoftwareOpenGL.dll"); + + QByteArray openglDll = qgetenv("QT_OPENGL_DLL"); + if (openglDll.isEmpty()) + openglDll = softwareRendering ? swopengl : opengl32; + + openglDll = openglDll.toLower(); + m_nonOpengl32 = openglDll != opengl32; + + qCDebug(lcQpaGl) << "Qt: Using WGL and OpenGL from" << openglDll; + + m_lib = ::LoadLibraryA(openglDll.constData()); + if (!m_lib) { + qErrnoWarning(::GetLastError(), "Failed to load %s", openglDll.constData()); + return false; + } + + if (moduleIsNotOpengl32()) { + // Load opengl32.dll always. GDI functions like ChoosePixelFormat do + // GetModuleHandle for opengl32.dll and behave differently (and call back into + // opengl32) when the module is present. This is fine for dummy contexts and windows. + ::LoadLibraryA("opengl32.dll"); + } + + wglCreateContext = reinterpret_cast<HGLRC (WINAPI *)(HDC)>(resolve("wglCreateContext")); + wglDeleteContext = reinterpret_cast<BOOL (WINAPI *)(HGLRC)>(resolve("wglDeleteContext")); + wglGetCurrentContext = reinterpret_cast<HGLRC (WINAPI *)()>(resolve("wglGetCurrentContext")); + wglGetCurrentDC = reinterpret_cast<HDC (WINAPI *)()>(resolve("wglGetCurrentDC")); + wglGetProcAddress = reinterpret_cast<PROC (WINAPI *)(LPCSTR)>(resolve("wglGetProcAddress")); + wglMakeCurrent = reinterpret_cast<BOOL (WINAPI *)(HDC, HGLRC)>(resolve("wglMakeCurrent")); + wglShareLists = reinterpret_cast<BOOL (WINAPI *)(HGLRC, HGLRC)>(resolve("wglShareLists")); + wglSwapBuffers = reinterpret_cast<BOOL (WINAPI *)(HDC)>(resolve("wglSwapBuffers")); + wglSetPixelFormat = reinterpret_cast<BOOL (WINAPI *)(HDC, int, const PIXELFORMATDESCRIPTOR *)>(resolve("wglSetPixelFormat")); + + glBindTexture = reinterpret_cast<void (APIENTRY *)(GLenum , GLuint )>(resolve("glBindTexture")); + glBlendFunc = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum )>(resolve("glBlendFunc")); + glClear = reinterpret_cast<void (APIENTRY *)(GLbitfield )>(resolve("glClear")); + glClearColor = reinterpret_cast<void (APIENTRY *)(GLfloat , GLfloat , GLfloat , GLfloat )>(resolve("glClearColor")); + glClearStencil = reinterpret_cast<void (APIENTRY *)(GLint )>(resolve("glClearStencil")); + glColorMask = reinterpret_cast<void (APIENTRY *)(GLboolean , GLboolean , GLboolean , GLboolean )>(resolve("glColorMask")); + glCopyTexImage2D = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLenum , GLint , GLint , GLsizei , GLsizei , GLint )>(resolve("glCopyTexImage2D")); + glCopyTexSubImage2D = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLint , GLint , GLint , GLint , GLsizei , GLsizei )>(resolve("glCopyTexSubImage2D")); + glCullFace = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolve("glCullFace")); + glDeleteTextures = reinterpret_cast<void (APIENTRY *)(GLsizei , const GLuint *)>(resolve("glDeleteTextures")); + glDepthFunc = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolve("glDepthFunc")); + glDepthMask = reinterpret_cast<void (APIENTRY *)(GLboolean )>(resolve("glDepthMask")); + glDisable = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolve("glDisable")); + glDrawArrays = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLsizei )>(resolve("glDrawArrays")); + glDrawElements = reinterpret_cast<void (APIENTRY *)(GLenum , GLsizei , GLenum , const GLvoid *)>(resolve("glDrawElements")); + glEnable = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolve("glEnable")); + glFinish = reinterpret_cast<void (APIENTRY *)()>(resolve("glFinish")); + glFlush = reinterpret_cast<void (APIENTRY *)()>(resolve("glFlush")); + glFrontFace = reinterpret_cast<void (APIENTRY *)(GLenum )>(resolve("glFrontFace")); + glGenTextures = reinterpret_cast<void (APIENTRY *)(GLsizei , GLuint *)>(resolve("glGenTextures")); + glGetBooleanv = reinterpret_cast<void (APIENTRY *)(GLenum , GLboolean *)>(resolve("glGetBooleanv")); + glGetError = reinterpret_cast<GLenum (APIENTRY *)()>(resolve("glGetError")); + glGetFloatv = reinterpret_cast<void (APIENTRY *)(GLenum , GLfloat *)>(resolve("glGetFloatv")); + glGetIntegerv = reinterpret_cast<void (APIENTRY *)(GLenum , GLint *)>(resolve("glGetIntegerv")); + glGetString = reinterpret_cast<const GLubyte * (APIENTRY *)(GLenum )>(resolve("glGetString")); + glGetTexParameterfv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLfloat *)>(resolve("glGetTexParameterfv")); + glGetTexParameteriv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLint *)>(resolve("glGetTexParameteriv")); + glHint = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum )>(resolve("glHint")); + glIsEnabled = reinterpret_cast<GLboolean (APIENTRY *)(GLenum )>(resolve("glIsEnabled")); + glIsTexture = reinterpret_cast<GLboolean (APIENTRY *)(GLuint )>(resolve("glIsTexture")); + glLineWidth = reinterpret_cast<void (APIENTRY *)(GLfloat )>(resolve("glLineWidth")); + glPixelStorei = reinterpret_cast<void (APIENTRY *)(GLenum , GLint )>(resolve("glPixelStorei")); + glPolygonOffset = reinterpret_cast<void (APIENTRY *)(GLfloat , GLfloat )>(resolve("glPolygonOffset")); + glReadPixels = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLsizei , GLsizei , GLenum , GLenum , GLvoid *)>(resolve("glReadPixels")); + glScissor = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLsizei , GLsizei )>(resolve("glScissor")); + glStencilFunc = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLuint )>(resolve("glStencilFunc")); + glStencilMask = reinterpret_cast<void (APIENTRY *)(GLuint )>(resolve("glStencilMask")); + glStencilOp = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLenum )>(resolve("glStencilOp")); + glTexImage2D = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLint , GLsizei , GLsizei , GLint , GLenum , GLenum , const GLvoid *)>(resolve("glTexImage2D")); + glTexParameterf = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLfloat )>(resolve("glTexParameterf")); + glTexParameterfv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , const GLfloat *)>(resolve("glTexParameterfv")); + glTexParameteri = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , GLint )>(resolve("glTexParameteri")); + glTexParameteriv = reinterpret_cast<void (APIENTRY *)(GLenum , GLenum , const GLint *)>(resolve("glTexParameteriv")); + glTexSubImage2D = reinterpret_cast<void (APIENTRY *)(GLenum , GLint , GLint , GLint , GLsizei , GLsizei , GLenum , GLenum , const GLvoid *)>(resolve("glTexSubImage2D")); + glViewport = reinterpret_cast<void (APIENTRY *)(GLint , GLint , GLsizei , GLsizei )>(resolve("glViewport")); + + glClearDepth = reinterpret_cast<void (APIENTRY *)(GLdouble )>(resolve("glClearDepth")); + glDepthRange = reinterpret_cast<void (APIENTRY *)(GLdouble , GLdouble )>(resolve("glDepthRange")); + + return wglCreateContext && glBindTexture && glClearDepth; +} + +BOOL QWindowsOpengl32DLL::swapBuffers(HDC dc) +{ + if (moduleIsNotOpengl32()) + return wglSwapBuffers(dc); + else + return SwapBuffers(dc); +} + +BOOL QWindowsOpengl32DLL::setPixelFormat(HDC dc, int pf, const PIXELFORMATDESCRIPTOR *pfd) +{ + if (moduleIsNotOpengl32()) + return wglSetPixelFormat(dc, pf, pfd); + else + return SetPixelFormat(dc, pf, pfd); +} + +QWindowsOpenGLContext *QOpenGLStaticContext::createContext(QOpenGLContext *context) +{ + return new QWindowsGLContext(this, context); +} + template <class MaskType, class FlagType> inline bool testFlag(MaskType mask, FlagType flag) { return (mask & MaskType(flag)) != 0; @@ -210,10 +336,11 @@ static inline bool bool ignoreGLSupport = false) // ARB format may not contain it. { const bool pixmapRequested = testFlag(additional.formatFlags, QWindowsGLRenderToPixmap); - return (ignoreGLSupport || testFlag(pfd.dwFlags, PFD_SUPPORT_OPENGL)) - && testFlag(pfd.dwFlags, PFD_DRAW_TO_BITMAP) == pixmapRequested - && hasGLOverlay(pfd) == testFlag(additional.formatFlags, QWindowsGLOverlay) - && (!pixmapRequested || pfd.cColorBits == additional.pixmapDepth); + const bool pixmapOk = !pixmapRequested || testFlag(pfd.dwFlags, PFD_DRAW_TO_BITMAP); + const bool colorOk = !pixmapRequested || pfd.cColorBits == additional.pixmapDepth; + const bool glOk = ignoreGLSupport || testFlag(pfd.dwFlags, PFD_SUPPORT_OPENGL); + const bool overlayOk = hasGLOverlay(pfd) == testFlag(additional.formatFlags, QWindowsGLOverlay); + return pixmapOk && glOk && overlayOk && colorOk; } static void describeFormats(HDC hdc) @@ -299,10 +426,23 @@ static PIXELFORMATDESCRIPTOR // over the available formats to find the best one. // Note: As of Windows 7, it seems direct-rendering is handled, so, // the code might be obsolete? +// +// NB! When using an implementation with a name different than opengl32.dll +// this code path should not be used since it will result in a mess due to GDI +// relying on and possibly calling back into functions in opengl32.dll (and not +// the one we are using). This is not a problem usually since for Mesa, which +// we are most likely to ship with a name other than opengl32.dll, the ARB code +// path should work. Hence the early bail out below. +// static int choosePixelFormat(HDC hdc, const QSurfaceFormat &format, const QWindowsOpenGLAdditionalFormat &additional, PIXELFORMATDESCRIPTOR *obtainedPfd) { + if (QOpenGLStaticContext::opengl32.moduleIsNotOpengl32()) { + qWarning("%s: Attempted to use GDI functions with a non-opengl32.dll library", Q_FUNC_INFO); + return 0; + } + // 1) Try ChoosePixelFormat(). PIXELFORMATDESCRIPTOR requestedPfd = qPixelFormatFromSurfaceFormat(format, QWindowsGLDirectRendering); initPixelFormatDescriptor(obtainedPfd); @@ -352,12 +492,12 @@ static int choosePixelFormat(HDC hdc, const QSurfaceFormat &format, static inline HGLRC createContext(HDC hdc, HGLRC shared) { - HGLRC result = wglCreateContext(hdc); + HGLRC result = QOpenGLStaticContext::opengl32.wglCreateContext(hdc); if (!result) { qErrnoWarning("%s: wglCreateContext failed.", __FUNCTION__); return 0; } - if (shared && !wglShareLists(shared, result)) + if (shared && !QOpenGLStaticContext::opengl32.wglShareLists(shared, result)) qErrnoWarning("%s: wglShareLists() failed.", __FUNCTION__); return result; } @@ -623,7 +763,7 @@ static HGLRC createContext(const QOpenGLStaticContext &staticContext, if (!result) { QString message; QDebug(&message).nospace() << __FUNCTION__ << ": wglCreateContextAttribsARB() failed (GL error code: 0x" - << hex << glGetError() << dec << ") for format: " << format << ", shared context: " << shared; + << hex << staticContext.opengl32.glGetError() << dec << ") for format: " << format << ", shared context: " << shared; qErrnoWarning("%s", qPrintable(message)); } return result; @@ -648,16 +788,17 @@ static inline HGLRC createDummyGLContext(HDC dc) initPixelFormatDescriptor(&pixelFormDescriptor); pixelFormDescriptor.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_GENERIC_FORMAT; pixelFormDescriptor.iPixelType = PFD_TYPE_RGBA; + // Use the GDI variant, for the dummy this is fine, even when using something other than opengl32.dll. const int pixelFormat = ChoosePixelFormat(dc, &pixelFormDescriptor); if (!pixelFormat) { qErrnoWarning("%s: ChoosePixelFormat failed.", __FUNCTION__); return 0; } - if (!SetPixelFormat(dc, pixelFormat, &pixelFormDescriptor)) { + if (!QOpenGLStaticContext::opengl32.setPixelFormat(dc, pixelFormat, &pixelFormDescriptor)) { qErrnoWarning("%s: SetPixelFormat failed.", __FUNCTION__); return 0; } - HGLRC rc = wglCreateContext(dc); + HGLRC rc = QOpenGLStaticContext::opengl32.wglCreateContext(dc); if (!rc) { qErrnoWarning("%s: wglCreateContext failed.", __FUNCTION__); return 0; @@ -668,8 +809,8 @@ static inline HGLRC createDummyGLContext(HDC dc) static inline QOpenGLContextData currentOpenGLContextData() { QOpenGLContextData result; - result.hdc = wglGetCurrentDC(); - result.renderingContext = wglGetCurrentContext(); + result.hdc = QOpenGLStaticContext::opengl32.wglGetCurrentDC(); + result.renderingContext = QOpenGLStaticContext::opengl32.wglGetCurrentContext(); return result; } @@ -721,7 +862,7 @@ QWindowsOpenGLContextFormat QWindowsOpenGLContextFormat::current() } // v3 onwards GLint value = 0; - glGetIntegerv(GL_CONTEXT_FLAGS, &value); + QOpenGLStaticContext::opengl32.glGetIntegerv(GL_CONTEXT_FLAGS, &value); if (!(value & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT)) result.options |= QSurfaceFormat::DeprecatedFunctions; if (value & GL_CONTEXT_FLAG_DEBUG_BIT) @@ -730,7 +871,7 @@ QWindowsOpenGLContextFormat QWindowsOpenGLContextFormat::current() return result; // v3.2 onwards: Profiles value = 0; - glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &value); + QOpenGLStaticContext::opengl32.glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &value); if (value & GL_CONTEXT_CORE_PROFILE_BIT) result.profile = QSurfaceFormat::CoreProfile; else if (value & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) @@ -784,15 +925,15 @@ QOpenGLTemporaryContext::QOpenGLTemporaryContext() : m_previous(currentOpenGLContextData()), m_current(createDummyWindowOpenGLContextData()) { - wglMakeCurrent(m_current.hdc, m_current.renderingContext); + QOpenGLStaticContext::opengl32.wglMakeCurrent(m_current.hdc, m_current.renderingContext); } QOpenGLTemporaryContext::~QOpenGLTemporaryContext() { - wglMakeCurrent(m_previous.hdc, m_previous.renderingContext); + QOpenGLStaticContext::opengl32.wglMakeCurrent(m_previous.hdc, m_previous.renderingContext); ReleaseDC(m_current.hwnd, m_current.hdc); DestroyWindow(m_current.hwnd); - wglDeleteContext(m_current.renderingContext); + QOpenGLStaticContext::opengl32.wglDeleteContext(m_current.renderingContext); } /*! @@ -807,6 +948,11 @@ QOpenGLTemporaryContext::~QOpenGLTemporaryContext() Functions pending integration in the next version of OpenGL are post-fixed ARB. + No WGL or OpenGL functions are called directly from the windows plugin. Instead, the + static context loads opengl32.dll and resolves the necessary functions. This allows + building the plugin without linking to opengl32 and enables QT_OPENGL_DYNAMIC builds + where both the EGL and WGL (this) based implementation of the context are built. + \note Initialization requires an active context (see create()). \sa QWindowsGLContext @@ -822,11 +968,11 @@ QOpenGLStaticContext::QOpenGLStaticContext() : extensionNames(QOpenGLStaticContext::getGlString(GL_EXTENSIONS)), extensions(0), defaultFormat(QWindowsOpenGLContextFormat::current()), - wglGetPixelFormatAttribIVARB((WglGetPixelFormatAttribIVARB)wglGetProcAddress("wglGetPixelFormatAttribivARB")), - wglChoosePixelFormatARB((WglChoosePixelFormatARB)wglGetProcAddress("wglChoosePixelFormatARB")), - wglCreateContextAttribsARB((WglCreateContextAttribsARB)wglGetProcAddress("wglCreateContextAttribsARB")), - wglSwapInternalExt((WglSwapInternalExt)wglGetProcAddress("wglSwapIntervalEXT")), - wglGetSwapInternalExt((WglGetSwapInternalExt)wglGetProcAddress("wglGetSwapIntervalEXT")) + wglGetPixelFormatAttribIVARB((WglGetPixelFormatAttribIVARB)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetPixelFormatAttribivARB")), + wglChoosePixelFormatARB((WglChoosePixelFormatARB)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglChoosePixelFormatARB")), + wglCreateContextAttribsARB((WglCreateContextAttribsARB)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglCreateContextAttribsARB")), + wglSwapInternalExt((WglSwapInternalExt)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglSwapIntervalEXT")), + wglGetSwapInternalExt((WglGetSwapInternalExt)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetSwapIntervalEXT")) { if (extensionNames.startsWith(SAMPLE_BUFFER_EXTENSION " ") || extensionNames.indexOf(" " SAMPLE_BUFFER_EXTENSION " ") != -1) @@ -835,16 +981,21 @@ QOpenGLStaticContext::QOpenGLStaticContext() : QByteArray QOpenGLStaticContext::getGlString(unsigned int which) { - if (const GLubyte *s = glGetString(which)) + if (const GLubyte *s = opengl32.glGetString(which)) return QByteArray((const char*)s); return QByteArray(); } -QOpenGLStaticContext *QOpenGLStaticContext::create() +QOpenGLStaticContext *QOpenGLStaticContext::create(bool softwareRendering) { + if (!opengl32.init(softwareRendering)) { + qWarning("%s: Failed to load and resolve WGL/OpenGL functions", Q_FUNC_INFO); + return 0; + } + // We need a current context for wglGetProcAdress()/getGLString() to work. QScopedPointer<QOpenGLTemporaryContext> temporaryContext; - if (!wglGetCurrentContext()) + if (!QOpenGLStaticContext::opengl32.wglGetCurrentContext()) temporaryContext.reset(new QOpenGLTemporaryContext); QOpenGLStaticContext *result = new QOpenGLStaticContext; qCDebug(lcQpaGl) << __FUNCTION__ << *result; @@ -881,15 +1032,61 @@ QDebug operator<<(QDebug d, const QOpenGLStaticContext &s) \ingroup qt-lighthouse-win */ -QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContext, +QWindowsGLContext::QWindowsGLContext(QOpenGLStaticContext *staticContext, QOpenGLContext *context) : m_staticContext(staticContext), m_context(context), m_renderingContext(0), m_pixelFormat(0), m_extensionsUsed(false), - m_swapInterval(-1) + m_swapInterval(-1), + m_ownsContext(true) { + if (!m_staticContext) // Something went very wrong. Stop here, isValid() will return false. + return; + + QVariant nativeHandle = context->nativeHandle(); + if (!nativeHandle.isNull()) { + // Adopt and existing context. + if (!nativeHandle.canConvert<QWGLNativeContext>()) { + qWarning("QWindowsGLContext: Requires a QWGLNativeContext"); + return; + } + QWGLNativeContext handle = nativeHandle.value<QWGLNativeContext>(); + HGLRC wglcontext = handle.context(); + HWND wnd = handle.window(); + if (!wglcontext || !wnd) { + qWarning("QWindowsGLContext: No context and window given"); + return; + } + + HDC dc = GetDC(wnd); + // A window with an associated pixel format is mandatory. + // When no SetPixelFormat() call has been made, the following will fail. + m_pixelFormat = GetPixelFormat(dc); + bool ok = m_pixelFormat != 0; + if (!ok) + qWarning("QWindowsGLContext: Failed to get pixel format"); + ok = DescribePixelFormat(dc, m_pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &m_obtainedPixelFormatDescriptor); + if (!ok) { + qWarning("QWindowsGLContext: Failed to describe pixel format"); + } else { + QWindowsOpenGLAdditionalFormat obtainedAdditional; + m_obtainedFormat = GDI::qSurfaceFormatFromPixelFormat(m_obtainedPixelFormatDescriptor, &obtainedAdditional); + m_renderingContext = wglcontext; + ok = updateObtainedParams(dc); + } + + ReleaseDC(wnd, dc); + + if (ok) + m_ownsContext = false; + else + m_renderingContext = 0; + + return; + } + QSurfaceFormat format = context->format(); if (format.renderableType() == QSurfaceFormat::DefaultRenderableType) format.setRenderableType(QSurfaceFormat::OpenGL); @@ -901,7 +1098,7 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex static bool opengl32dll = false; if (!opengl32dll) { GLint params; - glGetIntegerv(GL_DEPTH_BITS, ¶ms); + staticContext->opengl32.glGetIntegerv(GL_DEPTH_BITS, ¶ms); opengl32dll = true; } @@ -912,7 +1109,7 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex HWND dummyWindow = 0; HDC hdc = 0; bool tryExtensions = false; - int obtainedSwapInternal = -1; + int obtainedSwapInterval = -1; do { dummyWindow = createDummyGLWindow(); if (!dummyWindow) @@ -954,7 +1151,7 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex qWarning("%s: Unable find a suitable pixel format.", __FUNCTION__); break; } - if (!SetPixelFormat(hdc, m_pixelFormat, &m_obtainedPixelFormatDescriptor)) { + if (!QOpenGLStaticContext::opengl32.setPixelFormat(hdc, m_pixelFormat, &m_obtainedPixelFormatDescriptor)) { qErrnoWarning("SetPixelFormat failed."); break; } @@ -978,18 +1175,16 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex } // Query obtained parameters and apply swap interval. - if (!wglMakeCurrent(hdc, m_renderingContext)) { - qWarning("Failed to make context current."); + if (!updateObtainedParams(hdc, &obtainedSwapInterval)) break; - } - QWindowsOpenGLContextFormat::current().apply(&m_obtainedFormat); + } while (false); - if (m_staticContext->wglGetSwapInternalExt) - obtainedSwapInternal = m_staticContext->wglGetSwapInternalExt(); + // Make the HGLRC retrievable via QOpenGLContext::nativeHandle(). + // Do not provide the window since it is the dummy one and it is about to disappear. + if (m_renderingContext) + context->setNativeHandle(QVariant::fromValue<QWGLNativeContext>(QWGLNativeContext(m_renderingContext, 0))); - wglMakeCurrent(0, 0); - } while (false); if (hdc) ReleaseDC(dummyWindow, hdc); if (dummyWindow) @@ -998,18 +1193,37 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex qCDebug(lcQpaGl) << __FUNCTION__ << this << (tryExtensions ? "ARB" : "GDI") << " requested: " << context->format() << "\n obtained #" << m_pixelFormat << (m_extensionsUsed ? "ARB" : "GDI") << m_obtainedFormat - << "\n " << m_obtainedPixelFormatDescriptor << " swap interval: " << obtainedSwapInternal + << "\n " << m_obtainedPixelFormatDescriptor << " swap interval: " << obtainedSwapInterval << "\n default: " << m_staticContext->defaultFormat << "\n HGLRC=" << m_renderingContext; } QWindowsGLContext::~QWindowsGLContext() { - if (m_renderingContext) - wglDeleteContext(m_renderingContext); + if (m_renderingContext && m_ownsContext) + QOpenGLStaticContext::opengl32.wglDeleteContext(m_renderingContext); releaseDCs(); } +bool QWindowsGLContext::updateObtainedParams(HDC hdc, int *obtainedSwapInterval) +{ + HGLRC prevContext = QOpenGLStaticContext::opengl32.wglGetCurrentContext(); + HDC prevSurface = QOpenGLStaticContext::opengl32.wglGetCurrentDC(); + + if (!QOpenGLStaticContext::opengl32.wglMakeCurrent(hdc, m_renderingContext)) { + qWarning("Failed to make context current."); + return false; + } + + QWindowsOpenGLContextFormat::current().apply(&m_obtainedFormat); + + if (m_staticContext->wglGetSwapInternalExt && obtainedSwapInterval) + *obtainedSwapInterval = m_staticContext->wglGetSwapInternalExt(); + + QOpenGLStaticContext::opengl32.wglMakeCurrent(prevSurface, prevContext); + return true; +} + void QWindowsGLContext::releaseDCs() { const QOpenGLContextData *end = m_windowContexts.end(); @@ -1043,11 +1257,11 @@ void QWindowsGLContext::swapBuffers(QPlatformSurface *surface) { if (QWindowsContext::verbose > 1) qCDebug(lcQpaGl) << __FUNCTION__ << surface; - if (const QOpenGLContextData *contextData = findByHWND(m_windowContexts, handleOf(surface))) { - SwapBuffers(contextData->hdc); - } else { + + if (const QOpenGLContextData *contextData = findByHWND(m_windowContexts, handleOf(surface))) + QOpenGLStaticContext::opengl32.swapBuffers(contextData->hdc); + else qWarning("%s: Cannot find window %p", __FUNCTION__, handleOf(surface)); - } } bool QWindowsGLContext::makeCurrent(QPlatformSurface *surface) @@ -1066,11 +1280,11 @@ bool QWindowsGLContext::makeCurrent(QPlatformSurface *surface) // Repeated calls to wglMakeCurrent when vsync is enabled in the driver will // often result in 100% cpuload. This check is cheap and avoids the problem. // This is reproducable on NVidia cards and Intel onboard chips. - if (wglGetCurrentContext() == contextData->renderingContext - && wglGetCurrentDC() == contextData->hdc) { + if (QOpenGLStaticContext::opengl32.wglGetCurrentContext() == contextData->renderingContext + && QOpenGLStaticContext::opengl32.wglGetCurrentDC() == contextData->hdc) { return true; } - return wglMakeCurrent(contextData->hdc, contextData->renderingContext); + return QOpenGLStaticContext::opengl32.wglMakeCurrent(contextData->hdc, contextData->renderingContext); } // Create a new entry. const QOpenGLContextData newContext(m_renderingContext, hwnd, GetDC(hwnd)); @@ -1079,7 +1293,7 @@ bool QWindowsGLContext::makeCurrent(QPlatformSurface *surface) // Initialize pixel format first time. This will apply to // the HWND as well and must be done only once. if (!window->testFlag(QWindowsWindow::OpenGlPixelFormatInitialized)) { - if (!SetPixelFormat(newContext.hdc, m_pixelFormat, &m_obtainedPixelFormatDescriptor)) { + if (!QOpenGLStaticContext::opengl32.setPixelFormat(newContext.hdc, m_pixelFormat, &m_obtainedPixelFormatDescriptor)) { qErrnoWarning("%s: SetPixelFormat() failed", __FUNCTION__); ReleaseDC(newContext.hwnd, newContext.hdc); return false; @@ -1090,7 +1304,7 @@ bool QWindowsGLContext::makeCurrent(QPlatformSurface *surface) } m_windowContexts.append(newContext); - bool success = wglMakeCurrent(newContext.hdc, newContext.renderingContext); + bool success = QOpenGLStaticContext::opengl32.wglMakeCurrent(newContext.hdc, newContext.renderingContext); // Set the swap interval if (m_staticContext->wglSwapInternalExt) { @@ -1110,17 +1324,83 @@ void QWindowsGLContext::doneCurrent() if (QWindowsContext::verbose > 1) qCDebug(lcQpaGl) << __FUNCTION__ << this << m_windowContexts.size() << "contexts"; #endif // DEBUG_GL - wglMakeCurrent(0, 0); + QOpenGLStaticContext::opengl32.wglMakeCurrent(0, 0); releaseDCs(); } -QWindowsGLContext::GL_Proc QWindowsGLContext::getProcAddress(const QByteArray &procName) +QFunctionPointer QWindowsGLContext::getProcAddress(const QByteArray &procName) { - // TODO: Will that work with the calling conventions? - GL_Proc procAddress = reinterpret_cast<GL_Proc>(wglGetProcAddress(procName.constData())); + // We support AllGLFunctionsQueryable, which means this function must be able to + // return a function pointer even for functions that are in GL.h and exported + // normally from opengl32.dll. wglGetProcAddress() is not guaranteed to work for such + // functions, however in QT_OPENGL_DYNAMIC builds QOpenGLFunctions will just blindly + // call into here for _any_ OpenGL function. Hence the need to handle these specially + // here. The list has to match QOpenGLFunctions. See + // QOpenGLFunctionsPrivate::QOpenGLFunctionsPrivate(QOpenGLContext *). + static struct StdFunc { + const char *name; + void *func; + } standardFuncs[] = { + { "glBindTexture", (void *) QOpenGLStaticContext::opengl32.glBindTexture }, + { "glBlendFunc", (void *) QOpenGLStaticContext::opengl32.glBlendFunc }, + { "glClear", (void *) QOpenGLStaticContext::opengl32.glClear }, + { "glClearColor", (void *) QOpenGLStaticContext::opengl32.glClearColor }, + { "glClearStencil", (void *) QOpenGLStaticContext::opengl32.glClearStencil }, + { "glColorMask", (void *) QOpenGLStaticContext::opengl32.glColorMask }, + { "glCopyTexImage2D", (void *) QOpenGLStaticContext::opengl32.glCopyTexImage2D }, + { "glCopyTexSubImage2D", (void *) QOpenGLStaticContext::opengl32.glCopyTexSubImage2D }, + { "glCullFace", (void *) QOpenGLStaticContext::opengl32.glCullFace }, + { "glDeleteTextures", (void *) QOpenGLStaticContext::opengl32.glDeleteTextures }, + { "glDepthFunc", (void *) QOpenGLStaticContext::opengl32.glDepthFunc }, + { "glDepthMask", (void *) QOpenGLStaticContext::opengl32.glDepthMask }, + { "glDisable", (void *) QOpenGLStaticContext::opengl32.glDisable }, + { "glDrawArrays", (void *) QOpenGLStaticContext::opengl32.glDrawArrays }, + { "glDrawElements", (void *) QOpenGLStaticContext::opengl32.glDrawElements }, + { "glEnable", (void *) QOpenGLStaticContext::opengl32.glEnable }, + { "glFinish", (void *) QOpenGLStaticContext::opengl32.glFinish }, + { "glFlush", (void *) QOpenGLStaticContext::opengl32.glFlush }, + { "glFrontFace", (void *) QOpenGLStaticContext::opengl32.glFrontFace }, + { "glGenTextures", (void *) QOpenGLStaticContext::opengl32.glGenTextures }, + { "glGetBooleanv", (void *) QOpenGLStaticContext::opengl32.glGetBooleanv }, + { "glGetError", (void *) QOpenGLStaticContext::opengl32.glGetError }, + { "glGetFloatv", (void *) QOpenGLStaticContext::opengl32.glGetFloatv }, + { "glGetIntegerv", (void *) QOpenGLStaticContext::opengl32.glGetIntegerv }, + { "glGetString", (void *) QOpenGLStaticContext::opengl32.glGetString }, + { "glGetTexParameterfv", (void *) QOpenGLStaticContext::opengl32.glGetTexParameterfv }, + { "glGetTexParameteriv", (void *) QOpenGLStaticContext::opengl32.glGetTexParameteriv }, + { "glHint", (void *) QOpenGLStaticContext::opengl32.glHint }, + { "glIsEnabled", (void *) QOpenGLStaticContext::opengl32.glIsEnabled }, + { "glIsTexture", (void *) QOpenGLStaticContext::opengl32.glIsTexture }, + { "glLineWidth", (void *) QOpenGLStaticContext::opengl32.glLineWidth }, + { "glPixelStorei", (void *) QOpenGLStaticContext::opengl32.glPixelStorei }, + { "glPolygonOffset", (void *) QOpenGLStaticContext::opengl32.glPolygonOffset }, + { "glReadPixels", (void *) QOpenGLStaticContext::opengl32.glReadPixels }, + { "glScissor", (void *) QOpenGLStaticContext::opengl32.glScissor }, + { "glStencilFunc", (void *) QOpenGLStaticContext::opengl32.glStencilFunc }, + { "glStencilMask", (void *) QOpenGLStaticContext::opengl32.glStencilMask }, + { "glStencilOp", (void *) QOpenGLStaticContext::opengl32.glStencilOp }, + { "glTexImage2D", (void *) QOpenGLStaticContext::opengl32.glTexImage2D }, + { "glTexParameterf", (void *) QOpenGLStaticContext::opengl32.glTexParameterf }, + { "glTexParameterfv", (void *) QOpenGLStaticContext::opengl32.glTexParameterfv }, + { "glTexParameteri", (void *) QOpenGLStaticContext::opengl32.glTexParameteri }, + { "glTexParameteriv", (void *) QOpenGLStaticContext::opengl32.glTexParameteriv }, + { "glTexSubImage2D", (void *) QOpenGLStaticContext::opengl32.glTexSubImage2D }, + { "glViewport", (void *) QOpenGLStaticContext::opengl32.glViewport }, + + { "glClearDepth", (void *) QOpenGLStaticContext::opengl32.glClearDepth }, + { "glDepthRange", (void *) QOpenGLStaticContext::opengl32.glDepthRange }, + }; + for (size_t i = 0; i < sizeof(standardFuncs) / sizeof(StdFunc); ++i) + if (procName == standardFuncs[i].name) + return reinterpret_cast<QFunctionPointer>(standardFuncs[i].func); + + // Even though we use QFunctionPointer, it does not mean the function can be called. + // It will need to be cast to the proper function type with the correct calling + // convention. QFunctionPointer is nothing more than a glorified void* here. + QFunctionPointer procAddress = reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress(procName.constData())); if (QWindowsContext::verbose > 1) - qCDebug(lcQpaGl) << __FUNCTION__ << procName << wglGetCurrentContext() << "returns" << procAddress; - if (!procAddress) + qCDebug(lcQpaGl) << __FUNCTION__ << procName << QOpenGLStaticContext::opengl32.wglGetCurrentContext() << "returns" << procAddress; + if (!procAddress && QWindowsContext::verbose) qWarning("%s: Unable to resolve '%s'", __FUNCTION__, procName.constData()); return procAddress; } diff --git a/src/plugins/platforms/windows/qwindowsglcontext.h b/src/plugins/platforms/windows/qwindowsglcontext.h index c6b477128a..0afeb67a65 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.h +++ b/src/plugins/platforms/windows/qwindowsglcontext.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -44,10 +44,9 @@ #include "array.h" #include "qtwindows_additional.h" +#include "qwindowsopenglcontext.h" -#include <qpa/qplatformopenglcontext.h> #include <QtGui/QOpenGLContext> -#include <QtCore/QSharedPointer> QT_BEGIN_NAMESPACE @@ -81,6 +80,8 @@ struct QOpenGLContextData HDC hdc; }; +class QOpenGLStaticContext; + struct QWindowsOpenGLContextFormat { QWindowsOpenGLContextFormat(); @@ -94,7 +95,87 @@ struct QWindowsOpenGLContextFormat QDebug operator<<(QDebug d, const QWindowsOpenGLContextFormat &); -class QOpenGLStaticContext +struct QWindowsOpengl32DLL +{ + bool init(bool softwareRendering); + void *moduleHandle() const { return m_lib; } + bool moduleIsNotOpengl32() const { return m_nonOpengl32; } + + // Wrappers. Always use these instead of SwapBuffers/wglSwapBuffers/etc. + BOOL swapBuffers(HDC dc); + BOOL setPixelFormat(HDC dc, int pf, const PIXELFORMATDESCRIPTOR *pfd); + + // WGL + HGLRC (WINAPI * wglCreateContext)(HDC dc); + BOOL (WINAPI * wglDeleteContext)(HGLRC context); + HGLRC (WINAPI * wglGetCurrentContext)(); + HDC (WINAPI * wglGetCurrentDC)(); + PROC (WINAPI * wglGetProcAddress)(LPCSTR name); + BOOL (WINAPI * wglMakeCurrent)(HDC dc, HGLRC context); + BOOL (WINAPI * wglShareLists)(HGLRC context1, HGLRC context2); + + // GL1+GLES2 common + void (APIENTRY * glBindTexture)(GLenum target, GLuint texture); + void (APIENTRY * glBlendFunc)(GLenum sfactor, GLenum dfactor); + void (APIENTRY * glClear)(GLbitfield mask); + void (APIENTRY * glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); + void (APIENTRY * glClearStencil)(GLint s); + void (APIENTRY * glColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); + void (APIENTRY * glCopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); + void (APIENTRY * glCopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY * glCullFace)(GLenum mode); + void (APIENTRY * glDeleteTextures)(GLsizei n, const GLuint* textures); + void (APIENTRY * glDepthFunc)(GLenum func); + void (APIENTRY * glDepthMask)(GLboolean flag); + void (APIENTRY * glDisable)(GLenum cap); + void (APIENTRY * glDrawArrays)(GLenum mode, GLint first, GLsizei count); + void (APIENTRY * glDrawElements)(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices); + void (APIENTRY * glEnable)(GLenum cap); + void (APIENTRY * glFinish)(); + void (APIENTRY * glFlush)(); + void (APIENTRY * glFrontFace)(GLenum mode); + void (APIENTRY * glGenTextures)(GLsizei n, GLuint* textures); + void (APIENTRY * glGetBooleanv)(GLenum pname, GLboolean* params); + GLenum (APIENTRY * glGetError)(); + void (APIENTRY * glGetFloatv)(GLenum pname, GLfloat* params); + void (APIENTRY * glGetIntegerv)(GLenum pname, GLint* params); + const GLubyte * (APIENTRY * glGetString)(GLenum name); + void (APIENTRY * glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat* params); + void (APIENTRY * glGetTexParameteriv)(GLenum target, GLenum pname, GLint* params); + void (APIENTRY * glHint)(GLenum target, GLenum mode); + GLboolean (APIENTRY * glIsEnabled)(GLenum cap); + GLboolean (APIENTRY * glIsTexture)(GLuint texture); + void (APIENTRY * glLineWidth)(GLfloat width); + void (APIENTRY * glPixelStorei)(GLenum pname, GLint param); + void (APIENTRY * glPolygonOffset)(GLfloat factor, GLfloat units); + void (APIENTRY * glReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels); + void (APIENTRY * glScissor)(GLint x, GLint y, GLsizei width, GLsizei height); + void (APIENTRY * glStencilFunc)(GLenum func, GLint ref, GLuint mask); + void (APIENTRY * glStencilMask)(GLuint mask); + void (APIENTRY * glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass); + void (APIENTRY * glTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels); + void (APIENTRY * glTexParameterf)(GLenum target, GLenum pname, GLfloat param); + void (APIENTRY * glTexParameterfv)(GLenum target, GLenum pname, const GLfloat* params); + void (APIENTRY * glTexParameteri)(GLenum target, GLenum pname, GLint param); + void (APIENTRY * glTexParameteriv)(GLenum target, GLenum pname, const GLint* params); + void (APIENTRY * glTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels); + void (APIENTRY * glViewport)(GLint x, GLint y, GLsizei width, GLsizei height); + + // GL only + void (APIENTRY * glClearDepth)(GLdouble depth); + void (APIENTRY * glDepthRange)(GLdouble zNear, GLdouble zFar); + +private: + void *resolve(const char *name); + HMODULE m_lib; + bool m_nonOpengl32; + + // For Mesa llvmpipe shipped with a name other than opengl32.dll + BOOL (WINAPI * wglSwapBuffers)(HDC dc); + BOOL (WINAPI * wglSetPixelFormat)(HDC dc, int pf, const PIXELFORMATDESCRIPTOR *pfd); +}; + +class QOpenGLStaticContext : public QWindowsStaticOpenGLContext { Q_DISABLE_COPY(QOpenGLStaticContext) QOpenGLStaticContext(); @@ -125,9 +206,17 @@ public: bool hasExtensions() const { return wglGetPixelFormatAttribIVARB && wglChoosePixelFormatARB && wglCreateContextAttribsARB; } - static QOpenGLStaticContext *create(); + static QOpenGLStaticContext *create(bool softwareRendering = false); static QByteArray getGlString(unsigned int which); + QWindowsOpenGLContext *createContext(QOpenGLContext *context); + void *moduleHandle() const { return opengl32.moduleHandle(); } + QOpenGLContext::OpenGLModuleType moduleType() const { return QOpenGLContext::LibGL; } + + // For a regular opengl32.dll report the ThreadedOpenGL capability. + // For others, which are likely to be software-only, don't. + bool supportsThreadedOpenGL() const { return !opengl32.moduleIsNotOpengl32(); } + const QByteArray vendor; const QByteArray renderer; const QByteArray extensionNames; @@ -139,37 +228,39 @@ public: WglCreateContextAttribsARB wglCreateContextAttribsARB; WglSwapInternalExt wglSwapInternalExt; WglGetSwapInternalExt wglGetSwapInternalExt; + + static QWindowsOpengl32DLL opengl32; }; QDebug operator<<(QDebug d, const QOpenGLStaticContext &); -class QWindowsGLContext : public QPlatformOpenGLContext +class QWindowsGLContext : public QWindowsOpenGLContext { public: - typedef QSharedPointer<QOpenGLStaticContext> QOpenGLStaticContextPtr; - - explicit QWindowsGLContext(const QOpenGLStaticContextPtr &staticContext, - QOpenGLContext *context); - virtual ~QWindowsGLContext(); - bool isSharing() const { return m_context->shareHandle(); } - bool isValid() const { return m_renderingContext; } - virtual QSurfaceFormat format() const { return m_obtainedFormat; } + explicit QWindowsGLContext(QOpenGLStaticContext *staticContext, QOpenGLContext *context); + ~QWindowsGLContext(); + bool isSharing() const Q_DECL_OVERRIDE { return m_context->shareHandle(); } + bool isValid() const Q_DECL_OVERRIDE { return m_renderingContext; } + QSurfaceFormat format() const Q_DECL_OVERRIDE { return m_obtainedFormat; } - virtual void swapBuffers(QPlatformSurface *surface); + void swapBuffers(QPlatformSurface *surface) Q_DECL_OVERRIDE; - virtual bool makeCurrent(QPlatformSurface *surface); - virtual void doneCurrent(); + bool makeCurrent(QPlatformSurface *surface) Q_DECL_OVERRIDE; + void doneCurrent() Q_DECL_OVERRIDE; typedef void (*GL_Proc) (); - virtual GL_Proc getProcAddress(const QByteArray &procName); + QFunctionPointer getProcAddress(const QByteArray &procName) Q_DECL_OVERRIDE; + + HGLRC renderingContext() const { return m_renderingContext; } - HGLRC renderingContext() const { return m_renderingContext; } + void *nativeContext() const Q_DECL_OVERRIDE { return m_renderingContext; } private: inline void releaseDCs(); + bool updateObtainedParams(HDC hdc, int *obtainedSwapInterval = 0); - const QOpenGLStaticContextPtr m_staticContext; + QOpenGLStaticContext *m_staticContext; QOpenGLContext *m_context; QSurfaceFormat m_obtainedFormat; HGLRC m_renderingContext; @@ -178,6 +269,7 @@ private: int m_pixelFormat; bool m_extensionsUsed; int m_swapInterval; + bool m_ownsContext; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp b/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp index 878db7185d..8a8306f01a 100644 --- a/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp +++ b/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp @@ -115,6 +115,9 @@ messageDebugEntries[] = { {WM_SYSCOMMAND, "WM_SYSCOMMAND", true}, {WM_KEYUP, "WM_KEYUP", true}, {WM_SYSKEYUP, "WM_SYSKEYUP", true}, +#if defined(WM_APPCOMMAND) + {WM_APPCOMMAND, "WM_APPCOMMAND", true}, +#endif {WM_IME_CHAR, "WM_IMECHAR", true}, {WM_IME_KEYDOWN, "WM_IMECHAR", true}, {WM_CANCELMODE, "WM_CANCELMODE", true}, diff --git a/src/plugins/platforms/windows/qwindowsguieventdispatcher.h b/src/plugins/platforms/windows/qwindowsguieventdispatcher.h index 65ef912b43..6f67c47279 100644 --- a/src/plugins/platforms/windows/qwindowsguieventdispatcher.h +++ b/src/plugins/platforms/windows/qwindowsguieventdispatcher.h @@ -59,8 +59,8 @@ public: static const char *windowsMessageName(UINT msg); - virtual bool QT_ENSURE_STACK_ALIGNED_FOR_SSE processEvents(QEventLoop::ProcessEventsFlags flags); - virtual void sendPostedEvents(); + bool QT_ENSURE_STACK_ALIGNED_FOR_SSE processEvents(QEventLoop::ProcessEventsFlags flags) Q_DECL_OVERRIDE; + void sendPostedEvents() Q_DECL_OVERRIDE; private: QEventLoop::ProcessEventsFlags m_flags; diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp index 2429e8a4fa..2284c47ed6 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp @@ -44,6 +44,7 @@ #include "qwindowswindow.h" #include "qwindowsintegration.h" #include "qwindowsmousehandler.h" +#include "qwindowsscaling.h" #include <QtCore/QDebug> #include <QtCore/QObject> @@ -83,23 +84,15 @@ static inline QByteArray debugComposition(int lParam) // Cancel current IME composition. static inline void imeNotifyCancelComposition(HWND hwnd) { + if (!hwnd) { + qWarning() << __FUNCTION__ << "called with" << hwnd; + return; + } const HIMC himc = ImmGetContext(hwnd); ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_CANCEL, 0); ImmReleaseContext(hwnd, himc); } -// Query a QObject for an InputMethod-related value -// by sending a QInputMethodQueryEvent. -template <class T> - bool inputMethodQuery(QObject *fo, Qt::InputMethodQuery query, T *result) -{ - QInputMethodQueryEvent queryEvent(query); - if (!QCoreApplication::sendEvent(fo, &queryEvent)) - return false; - *result = qvariant_cast<T>(queryEvent.value(query)); - return true; -} - /*! \class QWindowsInputContext \brief Windows Input context implementation @@ -170,7 +163,7 @@ QWindowsInputContext::QWindowsInputContext() : m_WM_MSIME_MOUSE(RegisterWindowMessage(L"MSIMEMouseOperation")), m_endCompositionRecursionGuard(false) { - connect(qApp->inputMethod(), SIGNAL(cursorRectangleChanged()), + connect(QGuiApplication::inputMethod(), SIGNAL(cursorRectangleChanged()), this, SLOT(cursorRectChanged())); } @@ -187,21 +180,27 @@ void QWindowsInputContext::reset() QPlatformInputContext::reset(); if (!m_compositionContext.hwnd) return; - QObject *fo = qApp->focusObject(); - qCDebug(lcQpaInputMethods) << __FUNCTION__<< fo; - if (!fo) - return; - if (m_compositionContext.isComposing) { + qCDebug(lcQpaInputMethods) << __FUNCTION__; + if (m_compositionContext.isComposing && m_compositionContext.focusObject.isNull()) { QInputMethodEvent event; if (!m_compositionContext.composition.isEmpty()) event.setCommitString(m_compositionContext.composition); - QCoreApplication::sendEvent(fo, &event); + QCoreApplication::sendEvent(m_compositionContext.focusObject, &event); endContextComposition(); } imeNotifyCancelComposition(m_compositionContext.hwnd); doneContext(); } +void QWindowsInputContext::setFocusObject(QObject *) +{ + // ### fixme: On Windows 8.1, it has been observed that the Input context + // remains active when this happens resulting in a lock-up. Consecutive + // key events still have VK_PROCESSKEY set and are thus ignored. + if (m_compositionContext.isComposing) + imeNotifyCancelComposition(m_compositionContext.hwnd); +} + /*! \brief Moves the candidate window along with microfocus of the focus object. */ @@ -215,10 +214,11 @@ void QWindowsInputContext::cursorRectChanged() { if (!m_compositionContext.hwnd) return; - const QInputMethod *inputMethod = qApp->inputMethod(); - QRect cursorRectangle = inputMethod->cursorRectangle().toRect(); - if (!cursorRectangle.isValid()) + const QInputMethod *inputMethod = QGuiApplication::inputMethod(); + const QRect cursorRectangleDip = inputMethod->cursorRectangle().toRect(); + if (!cursorRectangleDip.isValid()) return; + const QRect cursorRectangle = QWindowsScaling::mapToNative(cursorRectangleDip); qCDebug(lcQpaInputMethods) << __FUNCTION__<< cursorRectangle; @@ -329,7 +329,7 @@ static inline QTextFormat standardFormat(StandardFormat format) bool QWindowsInputContext::startComposition(HWND hwnd) { - const QObject *fo = qApp->focusObject(); + QObject *fo = QGuiApplication::focusObject(); if (!fo) return false; // This should always match the object. @@ -339,7 +339,7 @@ bool QWindowsInputContext::startComposition(HWND hwnd) qCDebug(lcQpaInputMethods) << __FUNCTION__ << fo << window; if (!fo || QWindowsWindow::handleOf(window) != hwnd) return false; - initContext(hwnd); + initContext(hwnd, fo); startContextComposition(); return true; } @@ -353,6 +353,7 @@ void QWindowsInputContext::startContextComposition() m_compositionContext.isComposing = true; m_compositionContext.composition.clear(); m_compositionContext.position = 0; + cursorRectChanged(); // position cursor initially. update(Qt::ImQueryAll); } @@ -396,11 +397,10 @@ static inline QList<QInputMethodEvent::Attribute> bool QWindowsInputContext::composition(HWND hwnd, LPARAM lParamIn) { - QObject *fo = qApp->focusObject(); const int lParam = int(lParamIn); - qCDebug(lcQpaInputMethods) << '>' << __FUNCTION__ << fo << debugComposition(lParam) - << " composing=" << m_compositionContext.isComposing; - if (!fo || m_compositionContext.hwnd != hwnd || !lParam) + qCDebug(lcQpaInputMethods) << '>' << __FUNCTION__ << m_compositionContext.focusObject + << debugComposition(lParam) << " composing=" << m_compositionContext.isComposing; + if (m_compositionContext.focusObject.isNull() || m_compositionContext.hwnd != hwnd || !lParam) return false; const HIMC himc = ImmGetContext(m_compositionContext.hwnd); if (!himc) @@ -437,10 +437,10 @@ bool QWindowsInputContext::composition(HWND hwnd, LPARAM lParamIn) event->setCommitString(getCompositionString(himc, GCS_RESULTSTR)); endContextComposition(); } - const bool result = QCoreApplication::sendEvent(fo, event.data()); + const bool result = QCoreApplication::sendEvent(m_compositionContext.focusObject, event.data()); qCDebug(lcQpaInputMethods) << '<' << __FUNCTION__ << "sending markup=" << event->attributes().size() << " commit=" << event->commitString() - << " to " << fo << " returns " << result; + << " to " << m_compositionContext.focusObject << " returns " << result; update(Qt::ImQueryAll); ImmReleaseContext(m_compositionContext.hwnd, himc); return result; @@ -454,8 +454,7 @@ bool QWindowsInputContext::endComposition(HWND hwnd) // against that. if (m_endCompositionRecursionGuard || m_compositionContext.hwnd != hwnd) return false; - QObject *fo = qApp->focusObject(); - if (!fo) + if (m_compositionContext.focusObject.isNull()) return false; m_endCompositionRecursionGuard = true; @@ -463,7 +462,7 @@ bool QWindowsInputContext::endComposition(HWND hwnd) imeNotifyCancelComposition(m_compositionContext.hwnd); if (m_compositionContext.isComposing) { QInputMethodEvent event; - QCoreApplication::sendEvent(fo, &event); + QCoreApplication::sendEvent(m_compositionContext.focusObject, &event); } doneContext(); @@ -471,11 +470,12 @@ bool QWindowsInputContext::endComposition(HWND hwnd) return true; } -void QWindowsInputContext::initContext(HWND hwnd) +void QWindowsInputContext::initContext(HWND hwnd, QObject *focusObject) { if (m_compositionContext.hwnd) doneContext(); m_compositionContext.hwnd = hwnd; + m_compositionContext.focusObject = focusObject; // Create a hidden caret which is kept at the microfocus // position in update(). This is important for some // Chinese input methods. @@ -496,6 +496,7 @@ void QWindowsInputContext::doneContext() m_compositionContext.composition.clear(); m_compositionContext.position = 0; m_compositionContext.isComposing = m_compositionContext.haveCaret = false; + m_compositionContext.focusObject = 0; } bool QWindowsInputContext::handleIME_Request(WPARAM wParam, @@ -536,9 +537,10 @@ int QWindowsInputContext::reconvertString(RECONVERTSTRING *reconv) if (!fo) return false; - QString surroundingText; - if (!inputMethodQuery(fo, Qt::ImSurroundingText, &surroundingText)) + const QVariant surroundingTextV = QInputMethod::queryFocusObject(Qt::ImSurroundingText, QVariant()); + if (!surroundingTextV.isValid()) return -1; + const QString surroundingText = surroundingTextV.toString(); const DWORD memSize = sizeof(RECONVERTSTRING) + (surroundingText.length() + 1) * sizeof(ushort); qCDebug(lcQpaInputMethods) << __FUNCTION__ << " reconv=" << reconv @@ -547,8 +549,8 @@ int QWindowsInputContext::reconvertString(RECONVERTSTRING *reconv) if (!reconv) return surroundingText.isEmpty() ? -1 : int(memSize); - int pos = 0; - inputMethodQuery(fo, Qt::ImCursorPosition, &pos); + const QVariant posV = QInputMethod::queryFocusObject(Qt::ImCursorPosition, QVariant()); + const int pos = posV.isValid() ? posV.toInt() : 0; // Find the word in the surrounding text. QTextBoundaryFinder bounds(QTextBoundaryFinder::Word, surroundingText); bounds.setPosition(pos); diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.h b/src/plugins/platforms/windows/qwindowsinputcontext.h index 31a076cbf8..8ab684b837 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.h +++ b/src/plugins/platforms/windows/qwindowsinputcontext.h @@ -44,6 +44,7 @@ #include "qtwindows_additional.h" +#include <QtCore/QPointer> #include <qpa/qplatforminputcontext.h> QT_BEGIN_NAMESPACE @@ -63,14 +64,16 @@ class QWindowsInputContext : public QPlatformInputContext QString composition; int position; bool isComposing; + QPointer<QObject> focusObject; }; public: explicit QWindowsInputContext(); ~QWindowsInputContext(); - virtual void reset(); - virtual void update(Qt::InputMethodQueries); - virtual void invokeAction(QInputMethod::Action, int cursorPosition); + void reset() Q_DECL_OVERRIDE; + void update(Qt::InputMethodQueries) Q_DECL_OVERRIDE; + void invokeAction(QInputMethod::Action, int cursorPosition) Q_DECL_OVERRIDE; + void setFocusObject(QObject *object) Q_DECL_OVERRIDE; static QWindowsInputContext *instance(); @@ -86,7 +89,7 @@ private slots: void cursorRectChanged(); private: - void initContext(HWND hwnd); + void initContext(HWND hwnd, QObject *focusObject); void doneContext(); void startContextComposition(); void endContextComposition(); diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 78bf833526..7afda853e8 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch> -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -41,21 +41,10 @@ ****************************************************************************/ #include "qwindowsintegration.h" +#include "qwindowsscaling.h" #include "qwindowswindow.h" #include "qwindowscontext.h" - -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) -# include "qwindowseglcontext.h" -# include <QtGui/QOpenGLContext> -#endif - -#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2) -# include "qwindowsglcontext.h" -#endif - -#if !defined(QT_NO_OPENGL) -# include <QtGui/QOpenGLFunctions> -#endif +#include "qwindowsopenglcontext.h" #include "qwindowsscreen.h" #include "qwindowstheme.h" @@ -89,6 +78,19 @@ #include <QtCore/QDebug> #include <QtCore/QVariant> +#include <limits.h> + +#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) +# include "qwindowseglcontext.h" +#endif +#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2) +# include "qwindowsglcontext.h" +#endif + +#ifndef Q_OS_WINCE +# include "qwindowsopengltester.h" +#endif + QT_BEGIN_NAMESPACE /*! @@ -134,15 +136,9 @@ QT_BEGIN_NAMESPACE struct QWindowsIntegrationPrivate { -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - typedef QSharedPointer<QWindowsEGLStaticContext> QEGLStaticContextPtr; -#endif -#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2) - typedef QSharedPointer<QOpenGLStaticContext> QOpenGLStaticContextPtr; -#endif - explicit QWindowsIntegrationPrivate(const QStringList ¶mList); ~QWindowsIntegrationPrivate(); + bool ensureStaticOpenGLContext(); unsigned m_options; QWindowsContext m_context; @@ -153,12 +149,9 @@ struct QWindowsIntegrationPrivate QWindowsDrag m_drag; # endif #endif -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - QEGLStaticContextPtr m_staticEGLContext; -#endif -#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2) - QOpenGLStaticContextPtr m_staticOpenGLContext; -#endif +#ifndef QT_NO_OPENGL + QSharedPointer<QWindowsStaticOpenGLContext> m_staticOpenGLContext; +#endif // QT_NO_OPENGL QScopedPointer<QPlatformInputContext> m_inputContext; #ifndef QT_NO_ACCESSIBILITY QWindowsAccessibility m_accessibility; @@ -166,8 +159,32 @@ struct QWindowsIntegrationPrivate QWindowsServices m_services; }; +template <typename IntType> +bool parseIntOption(const QString ¶meter,const QLatin1String &option, + IntType minimumValue, IntType maximumValue, IntType *target) +{ + const int valueLength = parameter.size() - option.size() - 1; + if (valueLength < 1 || !parameter.startsWith(option) || parameter.at(option.size()) != QLatin1Char('=')) + return false; + bool ok; + const QStringRef valueRef = parameter.rightRef(valueLength); + const int value = valueRef.toInt(&ok); + if (ok) { + if (value >= minimumValue && value <= maximumValue) + *target = static_cast<IntType>(value); + else { + qWarning() << "Value" << value << "for option" << option << "out of range" + << minimumValue << ".." << maximumValue; + } + } else { + qWarning() << "Invalid value" << valueRef << "for option" << option; + } + return true; +} + static inline unsigned parseOptions(const QStringList ¶mList, - int *tabletAbsoluteRange) + int *tabletAbsoluteRange, + QtWindows::ProcessDpiAwareness *dpiAwareness) { unsigned options = 0; foreach (const QString ¶m, paramList) { @@ -187,10 +204,11 @@ static inline unsigned parseOptions(const QStringList ¶mList, options |= QWindowsIntegration::DisableArb; } else if (param == QLatin1String("nomousefromtouch")) { options |= QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch; - } else if (param.startsWith(QLatin1String("verbose="))) { - QWindowsContext::verbose = param.right(param.size() - 8).toInt(); - } else if (param.startsWith(QLatin1String("tabletabsoluterange="))) { - *tabletAbsoluteRange = param.rightRef(param.size() - 20).toInt(); + } else if (parseIntOption(param, QLatin1String("verbose"), 0, INT_MAX, &QWindowsContext::verbose) + || parseIntOption(param, QLatin1String("tabletabsoluterange"), 0, INT_MAX, tabletAbsoluteRange) + || parseIntOption(param, QLatin1String("dpiawareness"), QtWindows::ProcessDpiUnaware, QtWindows::ProcessPerMonitorDpiAware, dpiAwareness)) { + } else { + qWarning() << "Unknown option" << param; } } return options; @@ -200,10 +218,24 @@ QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(const QStringList ¶mL : m_options(0) , m_fontDatabase(0) { + static bool dpiAwarenessSet = false; int tabletAbsoluteRange = -1; - m_options = parseOptions(paramList, &tabletAbsoluteRange); + // Default to per-monitor awareness to avoid being scaled when monitors with different DPI + // are connected to Windows 8.1 + QtWindows::ProcessDpiAwareness dpiAwareness = QtWindows::ProcessPerMonitorDpiAware; + m_options = parseOptions(paramList, &tabletAbsoluteRange, &dpiAwareness); if (tabletAbsoluteRange >= 0) m_context.setTabletAbsoluteRange(tabletAbsoluteRange); + if (!dpiAwarenessSet) { // Set only once in case of repeated instantiations of QGuiApplication. + m_context.setProcessDpiAwareness(dpiAwareness); + dpiAwarenessSet = true; + } + // Determine suitable scale factor, don't mix Windows and Qt scaling + if (dpiAwareness != QtWindows::ProcessDpiUnaware) + QWindowsScaling::setFactor(QWindowsScaling::determineUiScaleFactor()); + qCDebug(lcQpaWindows) + << __FUNCTION__ << "DpiAwareness=" << dpiAwareness <<",Scaling=" + << QWindowsScaling::factor(); } QWindowsIntegrationPrivate::~QWindowsIntegrationPrivate() @@ -242,12 +274,7 @@ bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) co case OpenGL: return true; case ThreadedOpenGL: -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - return QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL - ? QWindowsEGLContext::hasThreadedOpenGLCapability() : true; -# else - return true; -# endif // QT_OPENGL_ES_2 + return d->ensureStaticOpenGLContext() ? d->m_staticOpenGLContext->supportsThreadedOpenGL() : false; #endif // !QT_NO_OPENGL case WindowMasks: return true; @@ -257,6 +284,8 @@ bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) co return true; case RasterGLSurface: return true; + case AllGLFunctionsQueryable: + return true; default: return QPlatformIntegration::hasCapability(cap); } @@ -267,14 +296,13 @@ QWindowsWindowData QWindowsIntegration::createWindowData(QWindow *window) const { QWindowsWindowData requested; requested.flags = window->flags(); - requested.geometry = window->geometry(); + requested.geometry = QWindowsScaling::mapToNative(window->geometry()); // Apply custom margins (see QWindowsWindow::setCustomMargins())). const QVariant customMarginsV = window->property("_q_windowsCustomMargins"); if (customMarginsV.isValid()) requested.customMargins = qvariant_cast<QMargins>(customMarginsV); - const QWindowsWindowData obtained - = QWindowsWindowData::create(window, requested, window->title()); + QWindowsWindowData obtained = QWindowsWindowData::create(window, requested, window->title()); qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << '<' << window << "\n Requested: " << requested.geometry << "frame incl.: " @@ -289,9 +317,14 @@ QWindowsWindowData QWindowsIntegration::createWindowData(QWindow *window) const window->setFlags(obtained.flags); // Trigger geometry change signals of QWindow. if ((obtained.flags & Qt::Desktop) != Qt::Desktop && requested.geometry != obtained.geometry) - QWindowSystemInterface::handleGeometryChange(window, obtained.geometry); + QWindowSystemInterface::handleGeometryChange(window, QWindowsScaling::mapFromNative(obtained.geometry)); } +#ifndef QT_NO_OPENGL + d->ensureStaticOpenGLContext(); + obtained.staticOpenGLContext = d->m_staticOpenGLContext; +#endif // QT_NO_OPENGL + return obtained; } @@ -303,32 +336,80 @@ QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) cons } #ifndef QT_NO_OPENGL -QPlatformOpenGLContext - *QWindowsIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const +static QWindowsStaticOpenGLContext *q_staticOpenGLContext = 0; + +QWindowsStaticOpenGLContext *QWindowsStaticOpenGLContext::create() { - qCDebug(lcQpaGl) << __FUNCTION__ << context->format(); -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - if (QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL) { - if (d->m_staticEGLContext.isNull()) { - QWindowsEGLStaticContext *staticContext = QWindowsEGLStaticContext::create(); - if (!staticContext) - return 0; - d->m_staticEGLContext = QSharedPointer<QWindowsEGLStaticContext>(staticContext); + QWindowsStaticOpenGLContext *ctx = 0; + +#if defined(QT_OPENGL_DYNAMIC) + const QByteArray requested = qgetenv("QT_OPENGL"); // angle, desktop, software + const bool angleRequested = QCoreApplication::testAttribute(Qt::AA_UseOpenGLES) || requested == QByteArrayLiteral("angle"); + const bool desktopRequested = QCoreApplication::testAttribute(Qt::AA_UseDesktopOpenGL) || requested == QByteArrayLiteral("desktop"); + const bool softwareRequested = QCoreApplication::testAttribute(Qt::AA_UseSoftwareOpenGL) || requested == QByteArrayLiteral("software"); + + // If ANGLE is requested, use it, don't try anything else. + if (angleRequested) { + ctx = QWindowsEGLStaticContext::create(); + } else { + // If opengl32.dll seems to be OpenGL 2.x capable, or desktop OpenGL is requested, use it. + if (!softwareRequested && (desktopRequested || QWindowsOpenGLTester::testDesktopGL())) + ctx = QOpenGLStaticContext::create(); + // If failed and desktop OpenGL is not explicitly requested, try ANGLE. + if (!ctx && !desktopRequested && !softwareRequested) + ctx = QWindowsEGLStaticContext::create(); + // Try software. + if (!ctx) { + ctx = QOpenGLStaticContext::create(true); + // If software was explicitly requested but failed, try the regular one. + if (!ctx && softwareRequested && QWindowsOpenGLTester::testDesktopGL()) + ctx = QOpenGLStaticContext::create(); } - return new QWindowsEGLContext(d->m_staticEGLContext, context->format(), context->shareHandle()); } +#elif defined(QT_OPENGL_ES_2) + ctx = QWindowsEGLStaticContext::create(); +#elif !defined(QT_NO_OPENGL) + ctx = QOpenGLStaticContext::create(); #endif -#if !defined(QT_OPENGL_ES_2) - if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) { - if (d->m_staticOpenGLContext.isNull()) - d->m_staticOpenGLContext = - QSharedPointer<QOpenGLStaticContext>(QOpenGLStaticContext::create()); - QScopedPointer<QWindowsGLContext> result(new QWindowsGLContext(d->m_staticOpenGLContext, context)); - return result->isValid() ? result.take() : 0; + + q_staticOpenGLContext = ctx; + + return ctx; +} + +bool QWindowsIntegrationPrivate::ensureStaticOpenGLContext() +{ + if (m_staticOpenGLContext.isNull()) + m_staticOpenGLContext = QSharedPointer<QWindowsStaticOpenGLContext>(QWindowsStaticOpenGLContext::create()); + return !m_staticOpenGLContext.isNull(); +} + +QPlatformOpenGLContext *QWindowsIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const +{ + qCDebug(lcQpaGl) << __FUNCTION__ << context->format(); + if (d->ensureStaticOpenGLContext()) { + QScopedPointer<QWindowsOpenGLContext> result(d->m_staticOpenGLContext->createContext(context)); + if (result->isValid()) + return result.take(); } -#endif // !QT_OPENGL_ES_2 return 0; } + +QOpenGLContext::OpenGLModuleType QWindowsIntegration::openGLModuleType() +{ +#if defined(QT_OPENGL_ES_2) + return QOpenGLContext::LibGLES; +#elif !defined(QT_OPENGL_DYNAMIC) + return QOpenGLContext::LibGL; +#else + return d->ensureStaticOpenGLContext() ? d->m_staticOpenGLContext->moduleType() : QOpenGLContext::LibGL; +#endif +} + +QWindowsStaticOpenGLContext *QWindowsIntegration::staticOpenGLContext() +{ + return q_staticOpenGLContext; +} #endif // !QT_NO_OPENGL /* Workaround for QTBUG-24205: In 'Auto', pick the FreeType engine for diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h index 0f417c8239..cae415ccd9 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.h +++ b/src/plugins/platforms/windows/qwindowsintegration.h @@ -52,6 +52,7 @@ QT_BEGIN_NAMESPACE struct QWindowsIntegrationPrivate; struct QWindowsWindowData; class QWindowsWindow; +class QWindowsStaticOpenGLContext; class QWindowsIntegration : public QPlatformIntegration { @@ -73,28 +74,30 @@ public: QWindowsWindowData createWindowData(QWindow *window) const; QPlatformWindow *createPlatformWindow(QWindow *window) const; #ifndef QT_NO_OPENGL - virtual QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; + QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const Q_DECL_OVERRIDE; + QOpenGLContext::OpenGLModuleType openGLModuleType(); + static QWindowsStaticOpenGLContext *staticOpenGLContext(); #endif - virtual QAbstractEventDispatcher *createEventDispatcher() const; + QAbstractEventDispatcher *createEventDispatcher() const Q_DECL_OVERRIDE; void initialize() Q_DECL_OVERRIDE; #ifndef QT_NO_CLIPBOARD - virtual QPlatformClipboard *clipboard() const; + QPlatformClipboard *clipboard() const Q_DECL_OVERRIDE; # ifndef QT_NO_DRAGANDDROP - virtual QPlatformDrag *drag() const; + QPlatformDrag *drag() const Q_DECL_OVERRIDE; # endif #endif // !QT_NO_CLIPBOARD - virtual QPlatformInputContext *inputContext() const; + QPlatformInputContext *inputContext() const Q_DECL_OVERRIDE; #ifndef QT_NO_ACCESSIBILITY - virtual QPlatformAccessibility *accessibility() const; + QPlatformAccessibility *accessibility() const Q_DECL_OVERRIDE; #endif - virtual QPlatformFontDatabase *fontDatabase() const; - virtual QStringList themeNames() const; - virtual QPlatformTheme *createPlatformTheme(const QString &name) const; + QPlatformFontDatabase *fontDatabase() const Q_DECL_OVERRIDE; + QStringList themeNames() const Q_DECL_OVERRIDE; + QPlatformTheme *createPlatformTheme(const QString &name) const Q_DECL_OVERRIDE; QPlatformServices *services() const; - virtual QVariant styleHint(StyleHint hint) const; + QVariant styleHint(StyleHint hint) const Q_DECL_OVERRIDE; - virtual Qt::KeyboardModifiers queryKeyboardModifiers() const; - virtual QList<int> possibleKeys(const QKeyEvent *e) const; + Qt::KeyboardModifiers queryKeyboardModifiers() const Q_DECL_OVERRIDE; + QList<int> possibleKeys(const QKeyEvent *e) const Q_DECL_OVERRIDE; static QWindowsIntegration *instance(); @@ -103,7 +106,7 @@ public: unsigned options() const; #if !defined(Q_OS_WINCE) && !defined(QT_NO_SESSIONMANAGER) - virtual QPlatformSessionManager *createPlatformSessionManager(const QString &id, const QString &key) const; + QPlatformSessionManager *createPlatformSessionManager(const QString &id, const QString &key) const Q_DECL_OVERRIDE; #endif private: diff --git a/src/plugins/platforms/windows/qwindowsinternalmimedata.h b/src/plugins/platforms/windows/qwindowsinternalmimedata.h index 0c12c662c4..08f2d09534 100644 --- a/src/plugins/platforms/windows/qwindowsinternalmimedata.h +++ b/src/plugins/platforms/windows/qwindowsinternalmimedata.h @@ -54,9 +54,9 @@ class QDebug; // Implementation in qwindowsclipboard.cpp. class QWindowsInternalMimeData : public QInternalMimeData { public: - virtual bool hasFormat_sys(const QString &mimetype) const; - virtual QStringList formats_sys() const; - virtual QVariant retrieveData_sys(const QString &mimetype, QVariant::Type preferredType) const; + bool hasFormat_sys(const QString &mimetype) const Q_DECL_OVERRIDE; + QStringList formats_sys() const Q_DECL_OVERRIDE; + QVariant retrieveData_sys(const QString &mimetype, QVariant::Type preferredType) const Q_DECL_OVERRIDE; protected: virtual IDataObject *retrieveDataObject() const = 0; diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index 6bcfe01a18..540236bda7 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -43,6 +43,7 @@ #include "qwindowscontext.h" #include "qwindowswindow.h" #include "qwindowsguieventdispatcher.h" +#include "qwindowsscaling.h" #include <QtGui/QWindow> #include <qpa/qwindowsysteminterface.h> @@ -428,6 +429,63 @@ static const uint KeyTbl[] = { // Keyboard mapping table 0 }; +static const uint CmdTbl[] = { // Multimedia keys mapping table + // Dec | Hex | AppCommand + Qt::Key_unknown, // 0 0x00 + Qt::Key_Back, // 1 0x01 APPCOMMAND_BROWSER_BACKWARD + Qt::Key_Forward, // 2 0x02 APPCOMMAND_BROWSER_FORWARD + Qt::Key_Refresh, // 3 0x03 APPCOMMAND_BROWSER_REFRESH + Qt::Key_Stop, // 4 0x04 APPCOMMAND_BROWSER_STOP + Qt::Key_Search, // 5 0x05 APPCOMMAND_BROWSER_SEARCH + Qt::Key_Favorites, // 6 0x06 APPCOMMAND_BROWSER_FAVORITES + Qt::Key_Home, // 7 0x07 APPCOMMAND_BROWSER_HOME + Qt::Key_VolumeMute, // 8 0x08 APPCOMMAND_VOLUME_MUTE + Qt::Key_VolumeDown, // 9 0x09 APPCOMMAND_VOLUME_DOWN + Qt::Key_VolumeUp, // 10 0x0a APPCOMMAND_VOLUME_UP + Qt::Key_MediaNext, // 11 0x0b APPCOMMAND_MEDIA_NEXTTRACK + Qt::Key_MediaPrevious, // 12 0x0c APPCOMMAND_MEDIA_PREVIOUSTRACK + Qt::Key_MediaStop, // 13 0x0d APPCOMMAND_MEDIA_STOP + Qt::Key_MediaTogglePlayPause, // 14 0x0e APPCOMMAND_MEDIA_PLAYPAUSE + Qt::Key_LaunchMail, // 15 0x0f APPCOMMAND_LAUNCH_MAIL + Qt::Key_LaunchMedia, // 16 0x10 APPCOMMAND_LAUNCH_MEDIA_SELECT + Qt::Key_Launch0, // 17 0x11 APPCOMMAND_LAUNCH_APP1 + Qt::Key_Launch1, // 18 0x12 APPCOMMAND_LAUNCH_APP2 + Qt::Key_BassDown, // 19 0x13 APPCOMMAND_BASS_DOWN + Qt::Key_BassBoost, // 20 0x14 APPCOMMAND_BASS_BOOST + Qt::Key_BassUp, // 21 0x15 APPCOMMAND_BASS_UP + Qt::Key_TrebleDown, // 22 0x16 APPCOMMAND_TREBLE_DOWN + Qt::Key_TrebleUp, // 23 0x17 APPCOMMAND_TREBLE_UP + Qt::Key_MicMute, // 24 0x18 APPCOMMAND_MICROPHONE_VOLUME_MUTE + Qt::Key_MicVolumeDown, // 25 0x19 APPCOMMAND_MICROPHONE_VOLUME_DOWN + Qt::Key_MicVolumeUp, // 26 0x1a APPCOMMAND_MICROPHONE_VOLUME_UP + Qt::Key_Help, // 27 0x1b APPCOMMAND_HELP + Qt::Key_Find, // 28 0x1c APPCOMMAND_FIND + Qt::Key_New, // 29 0x1d APPCOMMAND_NEW + Qt::Key_Open, // 30 0x1e APPCOMMAND_OPEN + Qt::Key_Close, // 31 0x1f APPCOMMAND_CLOSE + Qt::Key_Save, // 32 0x20 APPCOMMAND_SAVE + Qt::Key_Print, // 33 0x21 APPCOMMAND_PRINT + Qt::Key_Undo, // 34 0x22 APPCOMMAND_UNDO + Qt::Key_Redo, // 35 0x23 APPCOMMAND_REDO + Qt::Key_Copy, // 36 0x24 APPCOMMAND_COPY + Qt::Key_Cut, // 37 0x25 APPCOMMAND_CUT + Qt::Key_Paste, // 38 0x26 APPCOMMAND_PASTE + Qt::Key_Reply, // 39 0x27 APPCOMMAND_REPLY_TO_MAIL + Qt::Key_MailForward, // 40 0x28 APPCOMMAND_FORWARD_MAIL + Qt::Key_Send, // 41 0x29 APPCOMMAND_SEND_MAIL + Qt::Key_Spell, // 42 0x2a APPCOMMAND_SPELL_CHECK + Qt::Key_unknown, // 43 0x2b APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE + Qt::Key_unknown, // 44 0x2c APPCOMMAND_MIC_ON_OFF_TOGGLE + Qt::Key_unknown, // 45 0x2d APPCOMMAND_CORRECTION_LIST + Qt::Key_MediaPlay, // 46 0x2e APPCOMMAND_MEDIA_PLAY + Qt::Key_MediaPause, // 47 0x2f APPCOMMAND_MEDIA_PAUSE + Qt::Key_MediaRecord, // 48 0x30 APPCOMMAND_MEDIA_RECORD + Qt::Key_AudioForward, // 49 0x31 APPCOMMAND_MEDIA_FAST_FORWARD + Qt::Key_AudioRewind, // 50 0x32 APPCOMMAND_MEDIA_REWIND + Qt::Key_ChannelDown, // 51 0x33 APPCOMMAND_MEDIA_CHANNEL_DOWN + Qt::Key_ChannelUp // 52 0x34 APPCOMMAND_MEDIA_CHANNEL_UP +}; + // Possible modifier states. // NOTE: The order of these states match the order in QWindowsKeyMapper::updatePossibleKeyCodes()! static const Qt::KeyboardModifiers ModsTbl[] = { @@ -710,11 +768,10 @@ static void showSystemMenu(QWindow* w) #undef enabled #undef disabled #endif // !Q_OS_WINCE + const QPoint topLeft = topLevel->geometry().topLeft() * QWindowsScaling::factor(); const int ret = TrackPopupMenuEx(menu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD, - topLevel->geometry().x(), topLevel->geometry().y(), - topLevelHwnd, - 0); + topLeft.x(), topLeft.y(), topLevelHwnd, 0); if (ret) qWindowsWndProc(topLevelHwnd, WM_SYSCOMMAND, ret, 0); } @@ -747,6 +804,11 @@ bool QWindowsKeyMapper::translateKeyEvent(QWindow *widget, HWND hwnd, return true; } +#if defined(WM_APPCOMMAND) + if (msg.message == WM_APPCOMMAND) + return translateMultimediaKeyEventInternal(widget, msg); +#endif + // WM_(IME_)CHAR messages already contain the character in question so there is // no need to fiddle with our key map. In any other case add this key to the // keymap if it is not present yet. @@ -761,6 +823,29 @@ bool QWindowsKeyMapper::translateKeyEvent(QWindow *widget, HWND hwnd, return translateKeyEventInternal(widget, msg, false); } +bool QWindowsKeyMapper::translateMultimediaKeyEventInternal(QWindow *window, const MSG &msg) +{ +#if defined(WM_APPCOMMAND) + const int cmd = GET_APPCOMMAND_LPARAM(msg.lParam); + const int dwKeys = GET_KEYSTATE_LPARAM(msg.lParam); + int state = 0; + state |= (dwKeys & MK_SHIFT ? int(Qt::ShiftModifier) : 0); + state |= (dwKeys & MK_CONTROL ? int(Qt::ControlModifier) : 0); + + QWindow *receiver = m_keyGrabber ? m_keyGrabber : window; + + if (cmd < 0 || cmd > 52) + return false; + + const int qtKey = CmdTbl[cmd]; + sendExtendedPressRelease(receiver, qtKey, Qt::KeyboardModifier(state), 0, 0, 0); + return true; +#else + Q_UNREACHABLE(); + return false; +#endif +} + bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &msg, bool /* grab */) { const int msgType = msg.message; diff --git a/src/plugins/platforms/windows/qwindowskeymapper.h b/src/plugins/platforms/windows/qwindowskeymapper.h index f7d33758a0..247a807af7 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.h +++ b/src/plugins/platforms/windows/qwindowskeymapper.h @@ -93,6 +93,7 @@ public: private: bool translateKeyEventInternal(QWindow *receiver, const MSG &msg, bool grab); + bool translateMultimediaKeyEventInternal(QWindow *receiver, const MSG &msg); void updateKeyMap(const MSG &msg); bool m_useRTLExtensions; diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmime.cpp index 3af2cff9a0..37f51e85bd 100644 --- a/src/plugins/platforms/windows/qwindowsmime.cpp +++ b/src/plugins/platforms/windows/qwindowsmime.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -1035,17 +1035,14 @@ bool QWindowsMimeImage::canConvertToMime(const QString &mimeType, IDataObject *p bool QWindowsMimeImage::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const { int cf = getCf(formatetc); - if (mimeData->hasImage()) { - if (cf == CF_DIB) - return true; - else if (cf == CF_DIBV5) { - //support DIBV5 conversion only if the image has alpha channel - QImage image = qvariant_cast<QImage>(mimeData->imageData()); - if (!image.isNull() && image.hasAlphaChannel()) - return true; - } - } - return false; + if (!mimeData->hasImage()) + return false; + const QImage image = qvariant_cast<QImage>(mimeData->imageData()); + if (image.isNull()) + return false; + // QTBUG-11463, deny CF_DIB support for images with alpha to prevent loss of + // transparency in conversion. + return cf == CF_DIBV5 || (cf == CF_DIB && !image.hasAlphaChannel()); } bool QWindowsMimeImage::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const @@ -1442,13 +1439,13 @@ QString QLastResortMimes::mimeForFormat(const FORMATETC &formatetc) const \sa QWindowsMime */ -QWindowsMimeConverter::QWindowsMimeConverter() +QWindowsMimeConverter::QWindowsMimeConverter() : m_internalMimeCount(0) { } QWindowsMimeConverter::~QWindowsMimeConverter() { - qDeleteAll(m_mimes); + qDeleteAll(m_mimes.begin(), m_mimes.begin() + m_internalMimeCount); } QWindowsMime * QWindowsMimeConverter::converterToMime(const QString &mimeType, IDataObject *pDataObj) const @@ -1526,6 +1523,7 @@ void QWindowsMimeConverter::ensureInitialized() const m_mimes << new QWindowsMimeImage << new QLastResortMimes << new QWindowsMimeText << new QWindowsMimeURI << new QWindowsMimeHtml << new QBuiltInMimes; + m_internalMimeCount = m_mimes.size(); } } @@ -1552,4 +1550,10 @@ QVariant QWindowsMimeConverter::convertToMime(const QStringList &mimeTypes, return QVariant(); } +void QWindowsMimeConverter::registerMime(QWindowsMime *mime) +{ + ensureInitialized(); + m_mimes.append(mime); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsmime.h b/src/plugins/platforms/windows/qwindowsmime.h index cd0fb4d8b3..e2818422bf 100644 --- a/src/plugins/platforms/windows/qwindowsmime.h +++ b/src/plugins/platforms/windows/qwindowsmime.h @@ -89,12 +89,14 @@ public: QVariant convertToMime(const QStringList &mimeTypes, IDataObject *pDataObj, QVariant::Type preferredType, QString *format = 0) const; -private: - typedef QSharedPointer<QWindowsMime> MimePtr; + void registerMime(QWindowsMime *mime); + void unregisterMime(QWindowsMime *mime) { m_mimes.removeOne(mime); } +private: void ensureInitialized() const; mutable QList<QWindowsMime *> m_mimes; + mutable int m_internalMimeCount; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp index 4633378342..96c4a8bb78 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp +++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp @@ -191,8 +191,10 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, const QPoint globalPosition = winEventPosition; const QPoint clientPosition = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPosition); const Qt::MouseButtons buttons = QWindowsMouseHandler::queryMouseButtons(); - QWindowSystemInterface::handleFrameStrutMouseEvent(window, clientPosition, - globalPosition, buttons, + QWindowSystemInterface::handleFrameStrutMouseEvent(window, + clientPosition / QWindowsScaling::factor(), + globalPosition / QWindowsScaling::factor(), + buttons, QWindowsKeyMapper::queryKeyboardModifiers(), source); return false; // Allow further event processing (dragging of windows). @@ -334,7 +336,10 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, m_windowUnderMouse = currentWindowUnderMouse; } - QWindowSystemInterface::handleMouseEvent(window, winEventPosition, globalPosition, buttons, + QWindowSystemInterface::handleMouseEvent(window, + winEventPosition / QWindowsScaling::factor(), + globalPosition / QWindowsScaling::factor(), + buttons, QWindowsKeyMapper::queryKeyboardModifiers(), source); m_previousCaptureWindow = hasCapture ? window : 0; @@ -379,7 +384,7 @@ bool QWindowsMouseHandler::translateMouseWheelEvent(QWindow *window, HWND, // 2) The window receiving the event // If a window is blocked by modality, it can't get the event. const QPoint globalPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam)); - QWindow *receiver = QWindowsScreen::windowAt(globalPos); + QWindow *receiver = QWindowsScreen::windowAt(globalPos, CWP_SKIPINVISIBLE); bool handleEvent = true; if (!isValidWheelReceiver(receiver)) { receiver = window; @@ -388,10 +393,11 @@ bool QWindowsMouseHandler::translateMouseWheelEvent(QWindow *window, HWND, } if (handleEvent) { + const QPoint posDip = QWindowsGeometryHint::mapFromGlobal(receiver, globalPos) / QWindowsScaling::factor(); QWindowSystemInterface::handleWheelEvent(receiver, - QWindowsGeometryHint::mapFromGlobal(receiver, globalPos), - globalPos, - delta, orientation, mods); + posDip, globalPos / QWindowsScaling::factor(), + delta / QWindowsScaling::factor(), + orientation, mods); } return true; @@ -419,6 +425,7 @@ bool QWindowsMouseHandler::translateTouchEvent(QWindow *window, HWND, Q_ASSERT(QWindowsContext::user32dll.getTouchInputInfo); QWindowsContext::user32dll.getTouchInputInfo((HANDLE) msg.lParam, msg.wParam, winTouchInputs.data(), sizeof(TOUCHINPUT)); + const qreal screenPosFactor = 0.01 / qreal(QWindowsScaling::factor()); for (int i = 0; i < winTouchPointCount; ++i) { const TOUCHINPUT &winTouchInput = winTouchInputs[i]; int id = m_touchInputIDToTouchPointID.value(winTouchInput.dwID, -1); @@ -432,10 +439,9 @@ bool QWindowsMouseHandler::translateTouchEvent(QWindow *window, HWND, if (m_lastTouchPositions.contains(id)) touchPoint.normalPosition = m_lastTouchPositions.value(id); - QPointF screenPos = QPointF(qreal(winTouchInput.x) / qreal(100.), qreal(winTouchInput.y) / qreal(100.)); + const QPointF screenPos = QPointF(winTouchInput.x, winTouchInput.y) * screenPosFactor; if (winTouchInput.dwMask & TOUCHINPUTMASKF_CONTACTAREA) - touchPoint.area.setSize(QSizeF(qreal(winTouchInput.cxContact) / qreal(100.), - qreal(winTouchInput.cyContact) / qreal(100.))); + touchPoint.area.setSize(QSizeF(winTouchInput.cxContact, winTouchInput.cyContact) * screenPosFactor); touchPoint.area.moveCenter(screenPos); QPointF normalPosition = QPointF(screenPos.x() / screenGeometry.width(), screenPos.y() / screenGeometry.height()); diff --git a/src/plugins/platforms/windows/qwindowsnativeimage.h b/src/plugins/platforms/windows/qwindowsnativeimage.h index 399bead323..98b7fc9bc5 100644 --- a/src/plugins/platforms/windows/qwindowsnativeimage.h +++ b/src/plugins/platforms/windows/qwindowsnativeimage.h @@ -67,6 +67,8 @@ public: HDC hdc() const { return m_hdc; } + void setDevicePixelRatio(qreal scaleFactor) { m_image.setDevicePixelRatio(scaleFactor); } + static QImage::Format systemFormat(); private: diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp index 06c0122bbb..06f9f709c9 100644 --- a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp +++ b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -42,24 +42,45 @@ #include "qwindowsnativeinterface.h" #include "qwindowswindow.h" #include "qwindowscontext.h" - -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) -# include "qwindowseglcontext.h" -# include <QtGui/QOpenGLContext> -#endif - -#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2) -# include "qwindowsglcontext.h" -#endif - -#if !defined(QT_NO_OPENGL) -# include <QtGui/QOpenGLFunctions> -#endif +#include "qwindowsopenglcontext.h" +#include "qwindowsintegration.h" +#include "qwindowsmime.h" #include <QtGui/QWindow> +#include <QtGui/QOpenGLContext> QT_BEGIN_NAMESPACE +enum ResourceType { + RenderingContextType, + EglContextType, + EglDisplayType, + EglConfigType, + HandleType, + GlHandleType, + GetDCType, + ReleaseDCType +}; + +static int resourceType(const QByteArray &key) +{ + static const char *names[] = { // match ResourceType + "renderingcontext", + "eglcontext", + "egldisplay", + "eglconfig", + "handle", + "glhandle", + "getdc", + "releasedc" + }; + const char ** const end = names + sizeof(names) / sizeof(names[0]); + const char **result = std::find(names, end, key); + if (result == end) + result = std::find(names, end, key.toLower()); + return int(result - names); +} + void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resource, QWindow *window) { if (!window || !window->handle()) { @@ -67,14 +88,15 @@ void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resourc return 0; } QWindowsWindow *bw = static_cast<QWindowsWindow *>(window->handle()); - if (resource == "handle") + int type = resourceType(resource); + if (type == HandleType) return bw->handle(); switch (window->surfaceType()) { case QWindow::RasterSurface: case QWindow::RasterGLSurface: - if (resource == "getDC") + if (type == GetDCType) return bw->getDC(); - if (resource == "releaseDC") { + if (type == ReleaseDCType) { bw->releaseDC(); return 0; } @@ -117,6 +139,16 @@ QVariantMap QWindowsNativeInterface::windowProperties(QPlatformWindow *window) c return result; } +void *QWindowsNativeInterface::nativeResourceForIntegration(const QByteArray &resource) +{ +#ifndef QT_NO_OPENGL + if (resourceType(resource) == GlHandleType) + return QWindowsIntegration::staticOpenGLContext()->moduleHandle(); +#endif + + return 0; +} + #ifndef QT_NO_OPENGL void *QWindowsNativeInterface::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) { @@ -124,24 +156,19 @@ void *QWindowsNativeInterface::nativeResourceForContext(const QByteArray &resour qWarning("%s: '%s' requested for null context or context without handle.", __FUNCTION__, resource.constData()); return 0; } -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - if (QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL) { - QWindowsEGLContext *windowsEglContext = static_cast<QWindowsEGLContext *>(context->handle()); - if (resource == QByteArrayLiteral("eglDisplay")) - return windowsEglContext->eglDisplay(); - if (resource == QByteArrayLiteral("eglContext")) - return windowsEglContext->eglContext(); - if (resource == QByteArrayLiteral("eglConfig")) - return windowsEglContext->eglConfig(); - } -#endif // QT_OPENGL_ES_2 || QT_OPENGL_DYNAMIC -#if !defined(QT_OPENGL_ES_2) - if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) { - QWindowsGLContext *windowsContext = static_cast<QWindowsGLContext *>(context->handle()); - if (resource == QByteArrayLiteral("renderingContext")) - return windowsContext->renderingContext(); + + QWindowsOpenGLContext *glcontext = static_cast<QWindowsOpenGLContext *>(context->handle()); + switch (resourceType(resource)) { + case RenderingContextType: // Fall through. + case EglContextType: + return glcontext->nativeContext(); + case EglDisplayType: + return glcontext->nativeDisplay(); + case EglConfigType: + return glcontext->nativeConfig(); + default: + break; } -#endif // QT_OPENGL_ES_2 || QT_OPENGL_DYNAMIC qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData()); return 0; @@ -182,4 +209,19 @@ void QWindowsNativeInterface::setAsyncExpose(bool value) QWindowsContext::instance()->setAsyncExpose(value); } +void QWindowsNativeInterface::registerWindowsMime(void *mimeIn) +{ + QWindowsContext::instance()->mimeConverter().registerMime(reinterpret_cast<QWindowsMime *>(mimeIn)); +} + +void QWindowsNativeInterface::unregisterWindowsMime(void *mimeIn) +{ + QWindowsContext::instance()->mimeConverter().unregisterMime(reinterpret_cast<QWindowsMime *>(mimeIn)); +} + +int QWindowsNativeInterface::registerMimeType(const QString &mimeType) +{ + return QWindowsMime::registerMimeType(mimeType); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.h b/src/plugins/platforms/windows/qwindowsnativeinterface.h index 20100d0f49..1afa0571a0 100644 --- a/src/plugins/platforms/windows/qwindowsnativeinterface.h +++ b/src/plugins/platforms/windows/qwindowsnativeinterface.h @@ -66,11 +66,13 @@ class QWindowsNativeInterface : public QPlatformNativeInterface { Q_OBJECT Q_PROPERTY(bool asyncExpose READ asyncExpose WRITE setAsyncExpose) + public: + void *nativeResourceForIntegration(const QByteArray &resource) Q_DECL_OVERRIDE; #ifndef QT_NO_OPENGL - virtual void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context); + void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) Q_DECL_OVERRIDE; #endif - virtual void *nativeResourceForWindow(const QByteArray &resource, QWindow *window); + void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) Q_DECL_OVERRIDE; Q_INVOKABLE void *createMessageWindow(const QString &classNameTemplate, const QString &windowName, @@ -80,13 +82,17 @@ public: Q_INVOKABLE void beep() { MessageBeep(MB_OK); } // For QApplication + Q_INVOKABLE void registerWindowsMime(void *mimeIn); + Q_INVOKABLE void unregisterWindowsMime(void *mime); + Q_INVOKABLE int registerMimeType(const QString &mimeType); + bool asyncExpose() const; void setAsyncExpose(bool value); - QVariantMap windowProperties(QPlatformWindow *window) const; - QVariant windowProperty(QPlatformWindow *window, const QString &name) const; - QVariant windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const; - void setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value); + QVariantMap windowProperties(QPlatformWindow *window) const Q_DECL_OVERRIDE; + QVariant windowProperty(QPlatformWindow *window, const QString &name) const Q_DECL_OVERRIDE; + QVariant windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const Q_DECL_OVERRIDE; + void setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value) Q_DECL_OVERRIDE; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsopenglcontext.h b/src/plugins/platforms/windows/qwindowsopenglcontext.h new file mode 100644 index 0000000000..555af72f37 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsopenglcontext.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSOPENGLCONTEXT_H +#define QWINDOWSOPENGLCONTEXT_H + +#include <QtGui/QOpenGLContext> +#include <qpa/qplatformopenglcontext.h> + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_OPENGL + +class QWindowsOpenGLContext; + +class QWindowsStaticOpenGLContext +{ +public: + static QWindowsStaticOpenGLContext *create(); + virtual ~QWindowsStaticOpenGLContext() { } + + virtual QWindowsOpenGLContext *createContext(QOpenGLContext *context) = 0; + virtual void *moduleHandle() const = 0; + virtual QOpenGLContext::OpenGLModuleType moduleType() const = 0; + virtual bool supportsThreadedOpenGL() const { return false; } + + // If the windowing system interface needs explicitly created window surfaces (like EGL), + // reimplement these. + virtual void *createWindowSurface(void * /*nativeWindow*/, void * /*nativeConfig*/) { return 0; } + virtual void destroyWindowSurface(void * /*nativeSurface*/) { } +}; + +class QWindowsOpenGLContext : public QPlatformOpenGLContext +{ +public: + virtual ~QWindowsOpenGLContext() { } + + // Returns the native context handle (e.g. HGLRC for WGL, EGLContext for EGL). + virtual void *nativeContext() const = 0; + + // These should be implemented only for some winsys interfaces, for example EGL. + // For others, like WGL, they are not relevant. + virtual void *nativeDisplay() const { return 0; } + virtual void *nativeConfig() const { return 0; } +}; + +#endif // QT_NO_OPENGL + +QT_END_NAMESPACE + +#endif // QWINDOWSOPENGLCONTEXT_H diff --git a/src/plugins/platforms/windows/qwindowsopengltester.cpp b/src/plugins/platforms/windows/qwindowsopengltester.cpp new file mode 100644 index 0000000000..9ee62e6d56 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsopengltester.cpp @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowsopengltester.h" +#include "qt_windows.h" +#include "qwindowscontext.h" + +QT_BEGIN_NAMESPACE + +bool QWindowsOpenGLTester::testDesktopGL() +{ + HMODULE lib = 0; + HWND wnd = 0; + HDC dc = 0; + HGLRC context = 0; + LPCTSTR className = L"qtopengltest"; + + HGLRC (WINAPI * CreateContext)(HDC dc) = 0; + BOOL (WINAPI * DeleteContext)(HGLRC context) = 0; + BOOL (WINAPI * MakeCurrent)(HDC dc, HGLRC context) = 0; + PROC (WINAPI * WGL_GetProcAddress)(LPCSTR name) = 0; + + bool result = false; + + // Test #1: Load opengl32.dll and try to resolve an OpenGL 2 function. + // This will typically fail on systems that do not have a real OpenGL driver. + lib = LoadLibraryA("opengl32.dll"); + if (lib) { + CreateContext = reinterpret_cast<HGLRC (WINAPI *)(HDC)>(::GetProcAddress(lib, "wglCreateContext")); + if (!CreateContext) + goto cleanup; + DeleteContext = reinterpret_cast<BOOL (WINAPI *)(HGLRC)>(::GetProcAddress(lib, "wglDeleteContext")); + if (!DeleteContext) + goto cleanup; + MakeCurrent = reinterpret_cast<BOOL (WINAPI *)(HDC, HGLRC)>(::GetProcAddress(lib, "wglMakeCurrent")); + if (!MakeCurrent) + goto cleanup; + WGL_GetProcAddress = reinterpret_cast<PROC (WINAPI *)(LPCSTR)>(::GetProcAddress(lib, "wglGetProcAddress")); + if (!WGL_GetProcAddress) + goto cleanup; + + WNDCLASS wclass; + wclass.cbClsExtra = 0; + wclass.cbWndExtra = 0; + wclass.hInstance = (HINSTANCE) GetModuleHandle(0); + wclass.hIcon = 0; + wclass.hCursor = 0; + wclass.hbrBackground = (HBRUSH) (COLOR_BACKGROUND); + wclass.lpszMenuName = 0; + wclass.lpfnWndProc = DefWindowProc; + wclass.lpszClassName = className; + wclass.style = CS_OWNDC; + if (!RegisterClass(&wclass)) + goto cleanup; + wnd = CreateWindow(className, L"qtopenglproxytest", WS_OVERLAPPED, + 0, 0, 640, 480, 0, 0, wclass.hInstance, 0); + if (!wnd) + goto cleanup; + dc = GetDC(wnd); + if (!dc) + goto cleanup; + + PIXELFORMATDESCRIPTOR pfd; + memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR)); + pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); + pfd.nVersion = 1; + pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_GENERIC_FORMAT; + pfd.iPixelType = PFD_TYPE_RGBA; + // Use the GDI functions. Under the hood this will call the wgl variants in opengl32.dll. + int pixelFormat = ChoosePixelFormat(dc, &pfd); + if (!pixelFormat) + goto cleanup; + if (!SetPixelFormat(dc, pixelFormat, &pfd)) + goto cleanup; + context = CreateContext(dc); + if (!context) + goto cleanup; + if (!MakeCurrent(dc, context)) + goto cleanup; + + // Now that there is finally a context current, try doing something useful. + if (WGL_GetProcAddress("glCreateShader")) { + result = true; + qCDebug(lcQpaGl, "OpenGL 2.0 entry points available"); + } else { + qCDebug(lcQpaGl, "OpenGL 2.0 entry points not found"); + } + } else { + qCDebug(lcQpaGl, "Failed to load opengl32.dll"); + } + +cleanup: + if (MakeCurrent) + MakeCurrent(0, 0); + if (context) + DeleteContext(context); + if (dc && wnd) + ReleaseDC(wnd, dc); + if (wnd) { + DestroyWindow(wnd); + UnregisterClass(className, GetModuleHandle(0)); + } + // No FreeLibrary. Some implementations, Mesa in particular, deadlock when trying to unload. + + return result; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsopengltester.h b/src/plugins/platforms/windows/qwindowsopengltester.h new file mode 100644 index 0000000000..f7cd7e3005 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsopengltester.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qtwindowsglobal.h> + +QT_BEGIN_NAMESPACE + +class QWindowsOpenGLTester +{ +public: + static bool testDesktopGL(); +}; + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsscaling.cpp b/src/plugins/platforms/windows/qwindowsscaling.cpp new file mode 100644 index 0000000000..fcc3440b42 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsscaling.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowsscaling.h" +#include "qwindowsscreen.h" + +#include <QtCore/QDebug> +#include <QtCore/QCoreApplication> + +QT_BEGIN_NAMESPACE + +/*! + \class QWindowsScaling + \brief Windows scaling utilities + + \internal + \ingroup qt-lighthouse-win +*/ + +int QWindowsScaling::m_factor = 1; + +static const char devicePixelRatioEnvVar[] = "QT_DEVICE_PIXEL_RATIO"; + +// Suggest a scale factor by checking monitor sizes. +int QWindowsScaling::determineUiScaleFactor() +{ + if (!qEnvironmentVariableIsSet(devicePixelRatioEnvVar)) + return 1; + const QByteArray envDevicePixelRatioEnv = qgetenv(devicePixelRatioEnvVar); + // Auto: Suggest a scale factor by checking monitor resolution. + if (envDevicePixelRatioEnv == QByteArrayLiteral("auto")) { + const int maxResolution = QWindowsScreen::maxMonitorHorizResolution(); + return maxResolution > 180 ? maxResolution / 96 : 1; + } + // Get factor from environment + bool ok = false; + const int envFactor = envDevicePixelRatioEnv.toInt(&ok); + return ok && envFactor > 0 ? envFactor : 1; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsscaling.h b/src/plugins/platforms/windows/qwindowsscaling.h new file mode 100644 index 0000000000..99fec7c810 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsscaling.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSSCALING_H +#define QWINDOWSSCALING_H + +#include <QtGui/QRegion> +#include <QtCore/QVector> +#include <QtCore/QRect> + +QT_BEGIN_NAMESPACE + +enum +#if defined(Q_COMPILER_CLASS_ENUM) || defined(Q_CC_MSVC) + : int +#endif +{ QWINDOWSIZE_MAX = 16777215 }; + +class QWindowsScaling { +public: + static bool isActive() { return m_factor > 1; } + static int factor() { return m_factor; } + static void setFactor(int factor) { m_factor = factor; } + static int determineUiScaleFactor(); + + // Scaling helpers for size constraints. + static int mapToNativeConstrained(int qt) + { return m_factor != 1 && qt > 0 && qt < QWINDOWSIZE_MAX ? qt * m_factor : qt; } + + static int mapFromNativeConstrained(int dp) + { return m_factor != 1 && dp > 0 && dp < QWINDOWSIZE_MAX ? dp / m_factor : dp; } + + static QSize mapToNativeConstrained(const QSize &qt) + { return QSize(mapToNativeConstrained(qt.width()), mapToNativeConstrained(qt.height())); } + + static QRect mapToNative(const QRect &qRect) + { + return QRect(qRect.x() * m_factor, qRect.y() * m_factor, qRect.width() * m_factor, qRect.height() * m_factor); + } + + static QRect mapFromNative(const QRect &dp) + { + return isActive() ? + QRect(dp.x() / m_factor, dp.y() / m_factor, (dp.width() + 1) / m_factor, (dp.height() + 1) / m_factor) : + dp; + } + + static QRegion mapToNative(const QRegion ®ionQt) + { + if (!QWindowsScaling::isActive() || regionQt.isEmpty()) + return regionQt; + + QRegion result; + foreach (const QRect &rectQt, regionQt.rects()) + result += QWindowsScaling::mapToNative(rectQt); + return result; + } + + static QRegion mapFromNative(const QRegion ®ionDp) + { + if (!QWindowsScaling::isActive() || regionDp.isEmpty()) + return regionDp; + + QRegion result; + foreach (const QRect &rectDp, regionDp.rects()) + result += QWindowsScaling::mapFromNative(rectDp); + return result; + } + +private: + static int m_factor; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSSCALING_H diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index a6e2aabaf0..8d8505ea05 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -68,6 +68,21 @@ static inline QDpi deviceDPI(HDC hdc) return QDpi(GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY)); } +#ifndef Q_OS_WINCE + +static inline QDpi monitorDPI(HMONITOR hMonitor) +{ + if (QWindowsContext::shcoredll.isValid()) { + UINT dpiX; + UINT dpiY; + if (SUCCEEDED(QWindowsContext::shcoredll.getDpiForMonitor(hMonitor, 0, &dpiX, &dpiY))) + return QDpi(dpiX, dpiY); + } + return QDpi(0, 0); +} + +#endif // !Q_OS_WINCE + static inline QSizeF deviceSizeMM(const QSize &pixels, const QDpi &dpi) { const qreal inchToMM = 25.4; @@ -86,21 +101,19 @@ static inline QDpi deviceDPI(const QSize &pixels, const QSizeF &physicalSizeMM) typedef QList<QWindowsScreenData> WindowsScreenDataList; -// from QDesktopWidget, taking WindowsScreenDataList as LPARAM -BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM p) +static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data) { MONITORINFOEX info; memset(&info, 0, sizeof(MONITORINFOEX)); info.cbSize = sizeof(MONITORINFOEX); if (GetMonitorInfo(hMonitor, &info) == FALSE) - return TRUE; + return false; - WindowsScreenDataList *result = reinterpret_cast<WindowsScreenDataList *>(p); - QWindowsScreenData data; - data.geometry = QRect(QPoint(info.rcMonitor.left, info.rcMonitor.top), QPoint(info.rcMonitor.right - 1, info.rcMonitor.bottom - 1)); - data.name = QString::fromWCharArray(info.szDevice); - if (data.name == QLatin1String("WinDisc")) { - data.flags |= QWindowsScreenData::LockScreen; + data->geometry = QRect(QPoint(info.rcMonitor.left, info.rcMonitor.top), QPoint(info.rcMonitor.right - 1, info.rcMonitor.bottom - 1)); + data->availableGeometry = QRect(QPoint(info.rcWork.left, info.rcWork.top), QPoint(info.rcWork.right - 1, info.rcWork.bottom - 1)); + data->name = QString::fromWCharArray(info.szDevice); + if (data->name == QLatin1String("WinDisc")) { + data->flags |= QWindowsScreenData::LockScreen; } else { #ifdef Q_OS_WINCE //Windows CE, just supports one Display and expects to get only DISPLAY, @@ -110,37 +123,50 @@ BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM HDC hdc = CreateDC(info.szDevice, NULL, NULL, NULL); #endif if (hdc) { - data.dpi = deviceDPI(hdc); - data.depth = GetDeviceCaps(hdc, BITSPIXEL); - data.format = data.depth == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32; - data.physicalSizeMM = QSizeF(GetDeviceCaps(hdc, HORZSIZE), GetDeviceCaps(hdc, VERTSIZE)); +#ifndef Q_OS_WINCE + const QDpi dpi = monitorDPI(hMonitor); + data->dpi = dpi.first ? dpi : deviceDPI(hdc); +#else + data->dpi = deviceDPI(hdc); +#endif + data->depth = GetDeviceCaps(hdc, BITSPIXEL); + data->format = data->depth == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32; + data->physicalSizeMM = QSizeF(GetDeviceCaps(hdc, HORZSIZE), GetDeviceCaps(hdc, VERTSIZE)); const int refreshRate = GetDeviceCaps(hdc, VREFRESH); if (refreshRate > 1) // 0,1 means hardware default. - data.refreshRateHz = refreshRate; + data->refreshRateHz = refreshRate; DeleteDC(hdc); } else { qWarning("%s: Unable to obtain handle for monitor '%s', defaulting to %g DPI.", __FUNCTION__, qPrintable(QString::fromWCharArray(info.szDevice)), - data.dpi.first); + data->dpi.first); } // CreateDC() failed } // not lock screen - data.geometry = QRect(QPoint(info.rcMonitor.left, info.rcMonitor.top), QPoint(info.rcMonitor.right - 1, info.rcMonitor.bottom - 1)); - data.availableGeometry = QRect(QPoint(info.rcWork.left, info.rcWork.top), QPoint(info.rcWork.right - 1, info.rcWork.bottom - 1)); - data.orientation = data.geometry.height() > data.geometry.width() ? + data->orientation = data->geometry.height() > data->geometry.width() ? Qt::PortraitOrientation : Qt::LandscapeOrientation; // EnumDisplayMonitors (as opposed to EnumDisplayDevices) enumerates only // virtual desktop screens. - data.flags |= QWindowsScreenData::VirtualDesktop; - if (info.dwFlags & MONITORINFOF_PRIMARY) { - data.flags |= QWindowsScreenData::PrimaryScreen; + data->flags |= QWindowsScreenData::VirtualDesktop; + if (info.dwFlags & MONITORINFOF_PRIMARY) + data->flags |= QWindowsScreenData::PrimaryScreen; + return true; +} + +// from QDesktopWidget, taking WindowsScreenDataList as LPARAM +BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM p) +{ + QWindowsScreenData data; + if (monitorData(hMonitor, &data)) { + WindowsScreenDataList *result = reinterpret_cast<WindowsScreenDataList *>(p); // QPlatformIntegration::screenAdded() documentation specifies that first // added screen will be the primary screen, so order accordingly. // Note that the side effect of this policy is that there is no way to change primary // screen reported by Qt, unless we want to delete all existing screens and add them // again whenever primary screen changes. - result->prepend(data); - } else { - result->append(data); + if (data.flags & QWindowsScreenData::PrimaryScreen) + result->prepend(data); + else + result->append(data); } return TRUE; } @@ -197,14 +223,36 @@ QWindowsScreen::QWindowsScreen(const QWindowsScreenData &data) : { } +BOOL QT_WIN_CALLBACK monitorResolutionEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM p) +{ + QWindowsScreenData data; + if (monitorData(hMonitor, &data)) { + int *maxHorizResolution = reinterpret_cast<int *>(p); + const int horizResolution = qRound(data.dpi.first); + if (horizResolution > *maxHorizResolution) + *maxHorizResolution = horizResolution; + } + return TRUE; +} + +int QWindowsScreen::maxMonitorHorizResolution() +{ + int result = 0; + EnumDisplayMonitors(0, 0, monitorResolutionEnumCallback, (LPARAM)&result); + return result; +} + Q_GUI_EXPORT QPixmap qt_pixmapFromWinHBITMAP(HBITMAP bitmap, int hbitmapFormat = 0); -QPixmap QWindowsScreen::grabWindow(WId window, int x, int y, int width, int height) const +QPixmap QWindowsScreen::grabWindow(WId window, int qX, int qY, int qWidth, int qHeight) const { RECT r; HWND hwnd = window ? (HWND)window : GetDesktopWindow(); GetClientRect(hwnd, &r); - + const int x = qX * QWindowsScaling::factor(); + const int y = qY * QWindowsScaling::factor(); + int width = qWidth * QWindowsScaling::factor(); + int height = qHeight * QWindowsScaling::factor(); if (width < 0) width = r.right - r.left; if (height < 0) height = r.bottom - r.top; @@ -228,6 +276,10 @@ QPixmap QWindowsScreen::grabWindow(WId window, int x, int y, int width, int heig DeleteObject(bitmap); ReleaseDC(0, display_dc); + if (QWindowsScaling::isActive()) { + const qreal factor = 1.0 / qreal(QWindowsScaling::factor()); + return pixmap.transformed(QTransform::fromScale(factor, factor)); + } return pixmap; } @@ -235,13 +287,12 @@ QPixmap QWindowsScreen::grabWindow(WId window, int x, int y, int width, int heig \brief Find a top level window taking the flags of ChildWindowFromPointEx. */ -QWindow *QWindowsScreen::findTopLevelAt(const QPoint &point, unsigned flags) +QWindow *QWindowsScreen::topLevelAt(const QPoint &point) const { - QWindow* result = 0; - if (QPlatformWindow *bw = QWindowsContext::instance()-> - findPlatformWindowAt(GetDesktopWindow(), point, flags)) - result = QWindowsWindow::topLevelOf(bw->window()); - qCDebug(lcQpaWindows) <<__FUNCTION__ << point << flags << result; + QWindow *result = 0; + if (QWindow *child = QWindowsScreen::windowAt(point * QWindowsScaling::factor(), CWP_SKIPINVISIBLE)) + result = QWindowsWindow::topLevelOf(child); + qCDebug(lcQpaWindows) <<__FUNCTION__ << point << result; return result; } @@ -255,15 +306,6 @@ QWindow *QWindowsScreen::windowAt(const QPoint &screenPoint, unsigned flags) return result; } -QWindow *QWindowsScreen::windowUnderMouse(unsigned flags) -{ -#ifndef QT_NO_CURSOR - return QWindowsScreen::windowAt(QWindowsCursor::mousePosition(), flags); -#else - return 0; -#endif -} - QWindowsScreen *QWindowsScreen::screenOf(const QWindow *w) { if (w) @@ -304,15 +346,11 @@ void QWindowsScreen::handleChanges(const QWindowsScreenData &newData) { m_data.physicalSizeMM = newData.physicalSizeMM; - if (m_data.geometry != newData.geometry) { + if (m_data.geometry != newData.geometry || m_data.availableGeometry != newData.availableGeometry) { m_data.geometry = newData.geometry; - QWindowSystemInterface::handleScreenGeometryChange(screen(), - newData.geometry); - } - if (m_data.availableGeometry != newData.availableGeometry) { m_data.availableGeometry = newData.availableGeometry; - QWindowSystemInterface::handleScreenAvailableGeometryChange(screen(), - newData.availableGeometry); + QWindowSystemInterface::handleScreenGeometryChange(screen(), + newData.geometry, newData.availableGeometry); } if (!qFuzzyCompare(m_data.dpi.first, newData.dpi.first) || !qFuzzyCompare(m_data.dpi.second, newData.dpi.second)) { @@ -387,6 +425,54 @@ static inline int indexOfMonitor(const QList<QWindowsScreenData> &screenData, return -1; } +// Move a window to a new virtual screen, accounting for varying sizes. +static void moveToVirtualScreen(QWindow *w, const QScreen *newScreen) +{ + QRect geometry = w->geometry(); + const QRect oldScreenGeometry = w->screen()->geometry(); + const QRect newScreenGeometry = newScreen->geometry(); + QPoint relativePosition = geometry.topLeft() - oldScreenGeometry.topLeft(); + if (oldScreenGeometry.size() != newScreenGeometry.size()) { + const qreal factor = + qreal(QPoint(newScreenGeometry.width(), newScreenGeometry.height()).manhattanLength()) / + qreal(QPoint(oldScreenGeometry.width(), oldScreenGeometry.height()).manhattanLength()); + relativePosition = (QPointF(relativePosition) * factor).toPoint(); + } + geometry.moveTopLeft(relativePosition); + w->setGeometry(geometry); +} + +void QWindowsScreenManager::removeScreen(int index) +{ + qCDebug(lcQpaWindows) << "Removing Monitor:" << m_screens.at(index)->data(); + QScreen *screen = m_screens.at(index)->screen(); + QScreen *primaryScreen = QGuiApplication::primaryScreen(); + // QTBUG-38650: When a screen is disconnected, Windows will automatically + // move the Window to another screen. This will trigger a geometry change + // event, but unfortunately after the screen destruction signal. To prevent + // QtGui from automatically hiding the QWindow, pretend all Windows move to + // the primary screen first (which is likely the correct, final screen). + // QTBUG-39320: Windows does not automatically move WS_EX_TOOLWINDOW (dock) windows; + // move those manually. + if (screen != primaryScreen) { + unsigned movedWindowCount = 0; + foreach (QWindow *w, QGuiApplication::topLevelWindows()) { + if (w->screen() == screen && w->handle() && w->type() != Qt::Desktop) { + if (w->isVisible() && w->windowState() != Qt::WindowMinimized + && (QWindowsWindow::baseWindowOf(w)->exStyle() & WS_EX_TOOLWINDOW)) { + moveToVirtualScreen(w, primaryScreen); + } else { + QWindowSystemInterface::handleWindowScreenChanged(w, primaryScreen); + } + ++movedWindowCount; + } + } + if (movedWindowCount) + QWindowSystemInterface::flushWindowSystemEvents(); + } + delete m_screens.takeAt(index); +} + /*! \brief Synchronizes the screen list, adds new screens, removes deleted ones and propagates resolution changes to QWindowSystemInterface. @@ -412,10 +498,8 @@ bool QWindowsScreenManager::handleScreenChanges() // temporary lock screen to avoid window recreation (QTBUG-33062). if (!lockScreen) { for (int i = m_screens.size() - 1; i >= 0; --i) { - if (indexOfMonitor(newDataList, m_screens.at(i)->data().name) == -1) { - qCDebug(lcQpaWindows) << "Removing Monitor: " << m_screens.at(i) ->data(); - delete m_screens.takeAt(i); - } // not found + if (indexOfMonitor(newDataList, m_screens.at(i)->data().name) == -1) + removeScreen(i); } // for existing screens } // not lock screen return true; diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h index 930814a17d..44638bcbe0 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.h +++ b/src/plugins/platforms/windows/qwindowsscreen.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -43,11 +43,13 @@ #define QWINDOWSSCREEN_H #include "qwindowscursor.h" +#include "qwindowsscaling.h" #ifdef Q_OS_WINCE # include "qplatformfunctions_wince.h" #endif #include <QtCore/QList> +#include <QtCore/QVector> #include <QtCore/QPair> #include <QtCore/QSharedPointer> #include <qpa/qplatformscreen.h> @@ -88,24 +90,24 @@ public: static QWindowsScreen *screenOf(const QWindow *w = 0); - virtual QRect geometry() const { return m_data.geometry; } - virtual QRect availableGeometry() const { return m_data.availableGeometry; } - virtual int depth() const { return m_data.depth; } - virtual QImage::Format format() const { return m_data.format; } - virtual QSizeF physicalSize() const { return m_data.physicalSizeMM; } - virtual QDpi logicalDpi() const { return m_data.dpi; } - virtual qreal refreshRate() const { return m_data.refreshRateHz; } - virtual QString name() const { return m_data.name; } - virtual Qt::ScreenOrientation primaryOrientation() { return m_data.orientation; } - virtual QList<QPlatformScreen *> virtualSiblings() const; - virtual QWindow *topLevelAt(const QPoint &point) const - { return QWindowsScreen::findTopLevelAt(point, CWP_SKIPINVISIBLE); } - - static QWindow *findTopLevelAt(const QPoint &point, unsigned flags); - static QWindow *windowAt(const QPoint &point, unsigned flags = CWP_SKIPINVISIBLE); - static QWindow *windowUnderMouse(unsigned flags = CWP_SKIPINVISIBLE); - - virtual QPixmap grabWindow(WId window, int x, int y, int width, int height) const; + QRect geometryDp() const { return m_data.geometry; } + QRect geometry() const Q_DECL_OVERRIDE { return QWindowsScaling::mapFromNative(geometryDp()); } + QRect availableGeometryDp() const { return m_data.availableGeometry; } + QRect availableGeometry() const Q_DECL_OVERRIDE { return QWindowsScaling::mapFromNative(availableGeometryDp()); } + int depth() const Q_DECL_OVERRIDE { return m_data.depth; } + QImage::Format format() const Q_DECL_OVERRIDE { return m_data.format; } + QSizeF physicalSize() const Q_DECL_OVERRIDE { return m_data.physicalSizeMM; } + QDpi logicalDpi() const Q_DECL_OVERRIDE + { return QDpi(m_data.dpi.first / QWindowsScaling::factor(), m_data.dpi.second / QWindowsScaling::factor()); } + qreal devicePixelRatio() const Q_DECL_OVERRIDE { return QWindowsScaling::factor(); } + qreal refreshRate() const Q_DECL_OVERRIDE { return m_data.refreshRateHz; } + QString name() const Q_DECL_OVERRIDE { return m_data.name; } + Qt::ScreenOrientation orientation() const Q_DECL_OVERRIDE { return m_data.orientation; } + QList<QPlatformScreen *> virtualSiblings() const Q_DECL_OVERRIDE; + QWindow *topLevelAt(const QPoint &point) const Q_DECL_OVERRIDE; + static QWindow *windowAt(const QPoint &point, unsigned flags); + + QPixmap grabWindow(WId window, int qX, int qY, int qWidth, int qHeight) const Q_DECL_OVERRIDE; inline void handleChanges(const QWindowsScreenData &newData); @@ -117,6 +119,7 @@ public: #endif // !QT_NO_CURSOR const QWindowsScreenData &data() const { return m_data; } + static int maxMonitorHorizResolution(); private: QWindowsScreenData m_data; @@ -143,6 +146,8 @@ public: const WindowsScreenList &screens() const { return m_screens; } private: + void removeScreen(int index); + WindowsScreenList m_screens; int m_lastDepth; WORD m_lastHorizontalResolution; diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.cpp b/src/plugins/platforms/windows/qwindowstabletsupport.cpp index 8ceab02311..b6940e6850 100644 --- a/src/plugins/platforms/windows/qwindowstabletsupport.cpp +++ b/src/plugins/platforms/windows/qwindowstabletsupport.cpp @@ -40,12 +40,14 @@ ****************************************************************************/ #include "qwindowstabletsupport.h" +#include "qwindowsscaling.h" #ifndef QT_NO_TABLETEVENT #include "qwindowscontext.h" #include "qwindowskeymapper.h" #include "qwindowswindow.h" +#include "qwindowsscreen.h" #include <qpa/qwindowsysteminterface.h> @@ -275,6 +277,8 @@ static inline QTabletEvent::TabletDevice deviceType(const UINT cursorType) { if (((cursorType & 0x0006) == 0x0002) && ((cursorType & CursorTypeBitMask) != 0x0902)) return QTabletEvent::Stylus; + if (cursorType == 0x4020) // Surface Pro 2 tablet device + return QTabletEvent::Stylus; switch (cursorType & CursorTypeBitMask) { case 0x0802: return QTabletEvent::Stylus; @@ -403,7 +407,8 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() // in which case we snap the position to the mouse position. // It seems there is no way to find out the mode programmatically, the LOGCONTEXT orgX/Y/Ext // area is always the virtual desktop. - const QRect virtualDesktopArea = QGuiApplication::primaryScreen()->virtualGeometry(); + const QRect virtualDesktopArea + = QWindowsScaling::mapToNative(QGuiApplication::primaryScreen()->virtualGeometry()); qCDebug(lcQpaTablet) << __FUNCTION__ << "processing " << packetCount << "target:" << QGuiApplicationPrivate::tabletPressTarget; @@ -423,7 +428,7 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() QPoint globalPos = globalPosF.toPoint(); // Get Mouse Position and compare to tablet info - const QPoint mouseLocation = QWindowsCursor::mousePosition(); + QPoint mouseLocation = QWindowsCursor::mousePosition(); // Positions should be almost the same if we are in absolute // mode. If they are not, use the mouse location. @@ -433,8 +438,7 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() } if (!target) - if (QPlatformWindow *pw = QWindowsContext::instance()->findPlatformWindowAt(GetDesktopWindow(), globalPos, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT)) - target = pw->window(); + target = QWindowsScreen::windowAt(globalPos, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT); if (!target) continue; @@ -465,7 +469,9 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() const double degY = atan(cos(radAzim) / tanAlt); tiltX = int(degX * (180 / M_PI)); tiltY = int(-degY * (180 / M_PI)); - rotation = packet.pkOrientation.orTwist; + rotation = 360.0 - (packet.pkOrientation.orTwist / 10.0); + if (rotation > 180.0) + rotation -= 360.0; } if (QWindowsContext::verbose > 1) { @@ -477,8 +483,11 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() << tiltY << "tanP:" << tangentialPressure << "rotation:" << rotation; } - QWindowSystemInterface::handleTabletEvent(target, packet.pkButtons, localPos, globalPosF, + const QPointF localPosDip = QPointF(localPos / QWindowsScaling::factor()); + const QPointF globalPosDip = globalPosF / qreal(QWindowsScaling::factor()); + QWindowSystemInterface::handleTabletEvent(target, localPosDip, globalPosDip, currentDevice, currentPointer, + static_cast<Qt::MouseButtons>(packet.pkButtons), pressureNew, tiltX, tiltY, tangentialPressure, rotation, z, m_devices.at(m_currentDevice).uniqueId, diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h index 9346621d59..4414c71bc0 100644 --- a/src/plugins/platforms/windows/qwindowstheme.h +++ b/src/plugins/platforms/windows/qwindowstheme.h @@ -59,17 +59,17 @@ public: static QWindowsTheme *instance() { return m_instance; } - virtual bool usePlatformNativeDialog(DialogType type) const; - virtual QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const; - virtual QVariant themeHint(ThemeHint) const; + bool usePlatformNativeDialog(DialogType type) const Q_DECL_OVERRIDE; + QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const Q_DECL_OVERRIDE; + QVariant themeHint(ThemeHint) const Q_DECL_OVERRIDE; virtual const QPalette *palette(Palette type = SystemPalette) const { return m_palettes[type]; } virtual const QFont *font(Font type = SystemFont) const { return m_fonts[type]; } - virtual QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const; - virtual QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size, - QPlatformTheme::IconOptions iconOptions = 0) const; + QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const Q_DECL_OVERRIDE; + QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size, + QPlatformTheme::IconOptions iconOptions = 0) const Q_DECL_OVERRIDE; void windowsThemeChanged(QWindow *window); diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 0382144cbe..06b566629b 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -44,19 +44,16 @@ #include "qwindowscontext.h" #include "qwindowsdrag.h" #include "qwindowsscreen.h" +#include "qwindowsscaling.h" #ifdef QT_NO_CURSOR # include "qwindowscursor.h" #endif -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) -# include "qwindowseglcontext.h" -# include <QtGui/QOpenGLFunctions> -#endif - #include <QtGui/QGuiApplication> #include <QtGui/QScreen> #include <QtGui/QWindow> #include <QtGui/QRegion> +#include <QtGui/QOpenGLContext> #include <private/qsystemlibrary_p.h> #include <private/qwindow_p.h> #include <private/qguiapplication_p.h> @@ -110,6 +107,8 @@ static QByteArray debugWinExStyle(DWORD exStyle) rc += " WS_EX_CONTEXTHELP"; if (exStyle & WS_EX_LAYERED) rc += " WS_EX_LAYERED"; + if (exStyle & WS_EX_DLGMODALFRAME) + rc += " WS_EX_DLGMODALFRAME"; return rc; } @@ -183,6 +182,15 @@ QDebug operator<<(QDebug d, const NCCALCSIZE_PARAMS &p) static inline QRect frameGeometry(HWND hwnd, bool topLevel) { RECT rect = { 0, 0, 0, 0 }; +#ifndef Q_OS_WINCE + if (topLevel) { + WINDOWPLACEMENT windowPlacement; + windowPlacement.length = sizeof(WINDOWPLACEMENT); + GetWindowPlacement(hwnd, &windowPlacement); + if (windowPlacement.showCmd == SW_SHOWMINIMIZED) + return qrectFromRECT(windowPlacement.rcNormalPosition); + } +#endif // !Q_OS_WINCE GetWindowRect(hwnd, &rect); // Screen coordinates. const HWND parent = GetParent(hwnd); if (parent && !topLevel) { @@ -513,6 +521,10 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag } if (flags & Qt::WindowSystemMenuHint) style |= WS_SYSMENU; + else if (dialog) { + style |= WS_SYSMENU | WS_BORDER; // QTBUG-2027, dialogs without system menu. + exStyle |= WS_EX_DLGMODALFRAME; + } if (flags & Qt::WindowMinimizeButtonHint) style |= WS_MINIMIZEBOX; if (shouldShowMaximizeButton(w, flags)) @@ -566,7 +578,9 @@ QWindowsWindowData const QString windowClassName = QWindowsContext::instance()->registerWindowClass(w, isGL); - QRect rect = QPlatformWindow::initialGeometry(w, data.geometry, defaultWindowWidth, defaultWindowHeight); + const QRect geometryDip = QWindowsScaling::mapFromNative(data.geometry); + QRect fixedGeometryDip = QPlatformWindow::initialGeometry(w, geometryDip, defaultWindowWidth, defaultWindowHeight); + const QRect rect = fixedGeometryDip != geometryDip ? QWindowsScaling::mapToNative(fixedGeometryDip) : data.geometry; if (title.isEmpty() && (result.flags & Qt::WindowTitleHint)) title = topLevel ? qAppName() : w->objectName(); @@ -673,11 +687,9 @@ void WindowCreationData::initialize(HWND hwnd, bool frameChange, qreal opacityLe \ingroup qt-lighthouse-win */ -#define QWINDOWSIZE_MAX ((1<<24)-1) - QWindowsGeometryHint::QWindowsGeometryHint(const QWindow *w, const QMargins &cm) : - minimumSize(w->minimumSize()), - maximumSize(w->maximumSize()), + minimumSize(QWindowsScaling::mapToNativeConstrained(w->minimumSize())), + maximumSize(QWindowsScaling::mapToNativeConstrained(w->maximumSize())), customMargins(cm) { } @@ -758,9 +770,8 @@ void QWindowsGeometryHint::applyToMinMaxInfo(DWORD style, DWORD exStyle, MINMAXI const int maximumHeight = qMax(maximumSize.height(), minimumSize.height()); if (maximumWidth < QWINDOWSIZE_MAX) mmi->ptMaxTrackSize.x = maximumWidth + frameWidth; - // windows with title bar have an implicit size limit of 112 pixels if (maximumHeight < QWINDOWSIZE_MAX) - mmi->ptMaxTrackSize.y = qMax(maximumHeight + frameHeight, 112); + mmi->ptMaxTrackSize.y = maximumHeight + frameHeight; qCDebug(lcQpaWindows).nospace() << '<' << __FUNCTION__ << " frame=" << margins << ' ' << frameWidth << ',' << frameHeight << " out " << *mmi; @@ -861,15 +872,13 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) m_opacity(1.0), m_dropTarget(0), m_savedStyle(0), - m_format(aWindow->format()), -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - m_eglSurface(0), -#endif + m_format(aWindow->requestedFormat()), #ifdef Q_OS_WINCE m_previouslyHidden(false), #endif m_iconSmall(0), - m_iconBig(0) + m_iconBig(0), + m_surface(0) { // Clear the creation context as the window can be found in QWindowsContext's map. QWindowsContext::instance()->setWindowCreationContext(QSharedPointer<QWindowCreationContext>()); @@ -877,13 +886,14 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) const Qt::WindowType type = aWindow->type(); if (type == Qt::Desktop) return; // No further handling for Qt::Desktop +#ifndef QT_NO_OPENGL if (aWindow->surfaceType() == QWindow::OpenGLSurface) { - setFlag(OpenGLSurface); -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - if (QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL) + if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) + setFlag(OpenGLSurface); + else setFlag(OpenGL_ES2); -#endif } +#endif // QT_NO_OPENGL updateDropSite(); #ifndef Q_OS_WINCE @@ -921,7 +931,8 @@ void QWindowsWindow::fireExpose(const QRegion ®ion, bool force) clearFlag(Exposed); else setFlag(Exposed); - QWindowSystemInterface::handleExposeEvent(window(), region); + QWindowSystemInterface::handleExposeEvent(window(), + QWindowsScaling::mapFromNative(region)); } static inline QWindow *findTransientChild(const QWindow *parent) @@ -947,11 +958,10 @@ void QWindowsWindow::destroyWindow() if (hasMouseCapture()) setMouseGrabEnabled(false); setDropSiteEnabled(false); -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - if (m_eglSurface) { - qCDebug(lcQpaGl) << __FUNCTION__ << "Freeing EGL surface " << m_eglSurface << window(); - eglDestroySurface(m_staticEglContext->display(), m_eglSurface); - m_eglSurface = 0; +#ifndef QT_NO_OPENGL + if (m_surface) { + m_data.staticOpenGLContext->destroyWindowSurface(m_surface); + m_surface = 0; } #endif #ifdef Q_OS_WINCE @@ -1098,7 +1108,7 @@ bool QWindowsWindow::isEmbedded(const QPlatformWindow *parentWindow) const return m_data.embedded; } -QPoint QWindowsWindow::mapToGlobal(const QPoint &pos) const +QPoint QWindowsWindow::mapToGlobalDp(const QPoint &pos) const { if (m_data.hwnd) return QWindowsGeometryHint::mapToGlobal(m_data.hwnd, pos); @@ -1106,7 +1116,7 @@ QPoint QWindowsWindow::mapToGlobal(const QPoint &pos) const return pos; } -QPoint QWindowsWindow::mapFromGlobal(const QPoint &pos) const +QPoint QWindowsWindow::mapFromGlobalDp(const QPoint &pos) const { if (m_data.hwnd) return QWindowsGeometryHint::mapFromGlobal(m_data.hwnd, pos); @@ -1278,22 +1288,22 @@ static QRect normalFrameGeometry(HWND hwnd) return QRect(); } -QRect QWindowsWindow::normalGeometry() const +QRect QWindowsWindow::normalGeometryDp() const { // Check for fake 'fullscreen' mode. const bool fakeFullScreen = m_savedFrameGeometry.isValid() && window()->windowState() == Qt::WindowFullScreen; const QRect frame = fakeFullScreen ? m_savedFrameGeometry : normalFrameGeometry(m_data.hwnd); - const QMargins margins = fakeFullScreen ? QWindowsGeometryHint::frame(m_savedStyle, 0) : frameMargins(); + const QMargins margins = fakeFullScreen ? QWindowsGeometryHint::frame(m_savedStyle, 0) : frameMarginsDp(); return frame.isValid() ? frame.marginsRemoved(margins) : frame; } -void QWindowsWindow::setGeometry(const QRect &rectIn) +void QWindowsWindow::setGeometryDp(const QRect &rectIn) { QRect rect = rectIn; // This means it is a call from QWindow::setFramePosition() and // the coordinates include the frame (size is still the contents rectangle). if (QWindowsGeometryHint::positionIncludesFrame(window())) { - const QMargins margins = frameMargins(); + const QMargins margins = frameMarginsDp(); rect.moveTopLeft(rect.topLeft() + QPoint(margins.left(), margins.top())); } const QSize oldSize = m_data.geometry.size(); @@ -1375,13 +1385,19 @@ void QWindowsWindow::handleGeometryChange() return; const QRect previousGeometry = m_data.geometry; m_data.geometry = geometry_sys(); - QPlatformWindow::setGeometry(m_data.geometry); - QWindowSystemInterface::handleGeometryChange(window(), m_data.geometry); + const QRect geometryDip = QWindowsScaling::mapFromNative(m_data.geometry); + QPlatformWindow::setGeometry(geometryDip); + QWindowSystemInterface::handleGeometryChange(window(), geometryDip); // QTBUG-32121: OpenGL/normal windows (with exception of ANGLE) do not receive // expose events when shrinking, synthesize. if (!testFlag(OpenGL_ES2) && isExposed() && !(m_data.geometry.width() > previousGeometry.width() || m_data.geometry.height() > previousGeometry.height())) { - fireExpose(QRegion(m_data.geometry), true); + fireExpose(QRect(QPoint(0, 0), m_data.geometry.size()), true); + } + if (previousGeometry.topLeft() != m_data.geometry.topLeft()) { + QPlatformScreen *newScreen = screenForGeometry(m_data.geometry); + if (newScreen != screen()) + QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); } if (testFlag(SynchronousGeometryChangeEvent)) QWindowSystemInterface::flushWindowSystemEvents(); @@ -1391,7 +1407,7 @@ void QWindowsWindow::handleGeometryChange() void QWindowsWindow::setGeometry_sys(const QRect &rect) const { - const QMargins margins = frameMargins(); + const QMargins margins = frameMarginsDp(); const QRect frameGeometry = rect + margins; qCDebug(lcQpaWindows) << '>' << __FUNCTION__ << this << window() @@ -1399,22 +1415,37 @@ void QWindowsWindow::setGeometry_sys(const QRect &rect) const << margins << " to " <<rect << " new frame: " << frameGeometry; - const bool rc = MoveWindow(m_data.hwnd, frameGeometry.x(), frameGeometry.y(), - frameGeometry.width(), frameGeometry.height(), true); + bool result = false; +#ifndef Q_OS_WINCE + WINDOWPLACEMENT windowPlacement; + windowPlacement.length = sizeof(WINDOWPLACEMENT); + GetWindowPlacement(m_data.hwnd, &windowPlacement); + // If the window is hidden and in maximized state or minimized, instead of moving the + // window, set the normal position of the window. + if ((windowPlacement.showCmd == SW_MAXIMIZE && !IsWindowVisible(m_data.hwnd)) + || windowPlacement.showCmd == SW_SHOWMINIMIZED) { + windowPlacement.rcNormalPosition = RECTfromQRect(frameGeometry); + windowPlacement.showCmd = windowPlacement.showCmd == SW_SHOWMINIMIZED ? SW_SHOWMINIMIZED : SW_HIDE; + result = SetWindowPlacement(m_data.hwnd, &windowPlacement); + } else +#endif // !Q_OS_WINCE + { + result = MoveWindow(m_data.hwnd, frameGeometry.x(), frameGeometry.y(), + frameGeometry.width(), frameGeometry.height(), true); + } qCDebug(lcQpaWindows) << '<' << __FUNCTION__ << this << window() - << " \n resulting " << rc << geometry_sys(); + << " \n resulting " << result << geometry_sys(); } QRect QWindowsWindow::frameGeometry_sys() const { - // Warning: Returns bogus values when minimized. bool isRealTopLevel = window()->isTopLevel() && !m_data.embedded; return frameGeometry(m_data.hwnd, isRealTopLevel); } QRect QWindowsWindow::geometry_sys() const { - return frameGeometry_sys().marginsRemoved(frameMargins()); + return frameGeometry_sys().marginsRemoved(frameMarginsDp()); } /*! @@ -1487,7 +1518,7 @@ void QWindowsWindow::setWindowFlags(Qt::WindowFlags flags) qCDebug(lcQpaWindows) << '>' << __FUNCTION__ << this << window() << "\n from: " << QWindowsWindow::debugWindowFlags(m_data.flags) << "\n to: " << QWindowsWindow::debugWindowFlags(flags); - const QRect oldGeometry = geometry(); + const QRect oldGeometry = geometryDp(); if (m_data.flags != flags) { m_data.flags = flags; if (m_data.hwnd) { @@ -1573,23 +1604,10 @@ void QWindowsWindow::setWindowState(Qt::WindowState state) } } -// Return the effective screen for full screen mode in a virtual desktop. -static const QScreen *effectiveScreen(const QWindow *w) -{ - QPoint center = w->geometry().center(); - if (!w->isTopLevel()) - center = w->mapToGlobal(center); - const QScreen *screen = w->screen(); - if (!screen->geometry().contains(center)) - foreach (const QScreen *sibling, screen->virtualSiblings()) - if (sibling->geometry().contains(center)) - return sibling; - return screen; -} - bool QWindowsWindow::isFullScreen_sys() const { - return window()->isTopLevel() && geometry_sys() == effectiveScreen(window())->geometry(); + return window()->isTopLevel() + && geometry_sys() == QWindowsScaling::mapToNative(window()->screen()->geometry()); } /*! @@ -1669,15 +1687,16 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) setStyle(newStyle); // Use geometry of QWindow::screen() within creation or the virtual screen the // window is in (QTBUG-31166, QTBUG-30724). - const QScreen *screen = testFlag(WithinCreate) ? window()->screen() : effectiveScreen(window()); - const QRect r = screen->geometry(); + const QScreen *screen = window()->screen(); + const QRect rDip = screen->geometry(); + const QRect r = QWindowsScaling::mapToNative(rDip); 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::handleGeometryChange(window(), rDip); QWindowSystemInterface::flushWindowSystemEvents(); } else if (newState != Qt::WindowMinimized) { // Restore saved state. @@ -1765,7 +1784,7 @@ void QWindowsWindow::propagateSizeHints() qCDebug(lcQpaWindows) << __FUNCTION__ << this << window(); } -QMargins QWindowsWindow::frameMargins() const +QMargins QWindowsWindow::frameMarginsDp() const { // Frames are invalidated by style changes (window state, flags). // As they are also required for geometry calculations in resize @@ -1807,17 +1826,17 @@ static inline void addRectToWinRegion(const QRect &rect, HRGN *winRegion) } } -static HRGN qRegionToWinRegion(const QRegion ®ion) +static HRGN qRegionToWinRegion(const QRegion ®ionDip) { - const QVector<QRect> rects = region.rects(); + const QVector<QRect> rects = regionDip.rects(); if (rects.isEmpty()) return NULL; const int rectCount = rects.size(); if (rectCount == 1) - return createRectRegion(region.boundingRect()); + return createRectRegion(QWindowsScaling::mapToNative(regionDip.boundingRect())); HRGN hRegion = createRectRegion(rects.front()); for (int i = 1; i < rectCount; ++i) - addRectToWinRegion(rects.at(i), &hRegion); + addRectToWinRegion(QWindowsScaling::mapToNative(rects.at(i)), &hRegion); return hRegion; } @@ -1831,7 +1850,7 @@ void QWindowsWindow::setMask(const QRegion ®ion) // Mask is in client area coordinates, so offset it in case we have a frame if (window()->isTopLevel()) { - const QMargins margins = frameMargins(); + const QMargins margins = frameMarginsDp(); OffsetRgn(winRegion, margins.left(), margins.top()); } @@ -1939,7 +1958,7 @@ void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const && (m_data.flags & Qt::FramelessWindowHint)) { // This block fixes QTBUG-8361: Frameless windows shouldn't cover the // taskbar when maximized - const QScreen *screen = effectiveScreen(window()); + const QScreen *screen = window()->screen(); // Documentation of MINMAXINFO states that it will only work for the primary screen if (screen && screen == QGuiApplication::primaryScreen()) { @@ -1968,23 +1987,23 @@ bool QWindowsWindow::handleNonClientHitTest(const QPoint &globalPos, LRESULT *re || (m_data.flags & Qt::FramelessWindowHint)) { return false; } - const QSize minimumSize = w->minimumSize(); + const QSize minimumSize = QWindowsScaling::mapToNativeConstrained(w->minimumSize()); if (minimumSize.isEmpty()) return false; - const QSize maximumSize = w->maximumSize(); + const QSize maximumSize = QWindowsScaling::mapToNativeConstrained(w->maximumSize()); const bool fixedWidth = minimumSize.width() == maximumSize.width(); const bool fixedHeight = minimumSize.height() == maximumSize.height(); if (!fixedWidth && !fixedHeight) return false; - const QPoint localPos = w->mapFromGlobal(globalPos); - const QSize size = w->size(); + const QPoint localPos = mapFromGlobalDp(globalPos); + const QSize size = w->size() * QWindowsScaling::factor(); if (fixedHeight) { if (localPos.y() >= size.height()) { *result = HTBORDER; // Unspecified border, no resize cursor. return true; } if (localPos.y() < 0) { - const QMargins margins = frameMargins(); + const QMargins margins = frameMarginsDp(); const int topResizeBarPos = margins.left() - margins.top(); if (localPos.y() < topResizeBarPos) { *result = HTCAPTION; // Extend caption over top resize bar, let's user move the window. @@ -2065,26 +2084,6 @@ void QWindowsWindow::setCursor(const QWindowsWindowCursor &c) #endif } -/*! - \brief Find a child window using flags from ChildWindowFromPointEx. -*/ - -QWindowsWindow *QWindowsWindow::childAtScreenPoint(const QPoint &screenPoint, - unsigned cwexflags) const -{ - if (m_data.hwnd) - return QWindowsContext::instance()->findPlatformWindowAt(m_data.hwnd, screenPoint, cwexflags); - return 0; -} - -QWindowsWindow *QWindowsWindow::childAt(const QPoint &clientPoint, unsigned cwexflags) const -{ - if (m_data.hwnd) - return childAtScreenPoint(QWindowsGeometryHint::mapToGlobal(m_data.hwnd, clientPoint), - cwexflags); - return 0; -} - #ifndef Q_OS_WINCE void QWindowsWindow::setAlertState(bool enabled) { @@ -2144,23 +2143,6 @@ void QWindowsWindow::setEnabled(bool enabled) setStyle(newStyle); } -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) -EGLSurface QWindowsWindow::ensureEglSurfaceHandle(const QWindowsWindow::QWindowsEGLStaticContextPtr &staticContext, EGLConfig config) -{ - if (!m_eglSurface) { - m_staticEglContext = staticContext; - m_eglSurface = eglCreateWindowSurface(staticContext->display(), config, (EGLNativeWindowType)m_data.hwnd, NULL); - if (m_eglSurface == EGL_NO_SURFACE) - qWarning("%s: Could not create the egl surface for %s/'%s' (eglCreateWindowSurface failed): error = 0x%x\n", - Q_FUNC_INFO, window()->metaObject()->className(), - qPrintable(window()->objectName()), eglGetError()); - - qCDebug(lcQpaGl) << __FUNCTION__<<"Created EGL surface "<< m_eglSurface <<window(); - } - return m_eglSurface; -} -#endif // QT_OPENGL_ES_2 - QByteArray QWindowsWindow::debugWindowFlags(Qt::WindowFlags wf) { const int iwf = int(wf); @@ -2253,6 +2235,10 @@ void QWindowsWindow::setWindowIcon(const QIcon &icon) The property can be set using QPlatformNativeInterface::setWindowProperty() or, before platform window creation, by setting a dynamic property on the QWindow (see QWindowsIntegration::createPlatformWindow()). + + Note: The function uses (unscaled) device pixels since the QWizard also + uses AdjustWindowRect() and using device independent pixels would introduce + rounding errors. */ void QWindowsWindow::setCustomMargins(const QMargins &newCustomMargins) @@ -2272,4 +2258,16 @@ void QWindowsWindow::setCustomMargins(const QMargins &newCustomMargins) } } +void *QWindowsWindow::surface(void *nativeConfig) +{ +#ifdef QT_NO_OPENGL + return 0; +#else + if (!m_surface) + m_surface = m_data.staticOpenGLContext->createWindowSurface(m_data.hwnd, nativeConfig); + + return m_surface; +#endif +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index cb437b76d0..03c71351bd 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -46,24 +46,17 @@ #ifdef Q_OS_WINCE # include "qplatformfunctions_wince.h" #endif +#include "qwindowsscaling.h" #include "qwindowscursor.h" +#include "qwindowsopenglcontext.h" #include <qpa/qplatformwindow.h> -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) -# include <QtCore/QSharedPointer> -# include <EGL/egl.h> -#endif - QT_BEGIN_NAMESPACE class QWindowsOleDropTarget; class QDebug; -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) -class QWindowsEGLStaticContext; -#endif - struct QWindowsGeometryHint { QWindowsGeometryHint() {} @@ -121,6 +114,9 @@ struct QWindowsWindowData QMargins customMargins; // User-defined, additional frame for NCCALCSIZE HWND hwnd; bool embedded; +#ifndef QT_NO_OPENGL + QSharedPointer<QWindowsStaticOpenGLContext> staticOpenGLContext; +#endif // QT_NO_OPENGL static QWindowsWindowData create(const QWindow *w, const QWindowsWindowData ¶meters, @@ -130,10 +126,6 @@ struct QWindowsWindowData class QWindowsWindow : public QPlatformWindow { public: -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - typedef QSharedPointer<QWindowsEGLStaticContext> QWindowsEGLStaticContextPtr; -#endif - enum Flags { AutoMouseCapture = 0x1, //! Automatic mouse capture on button press. @@ -160,46 +152,57 @@ public: QWindowsWindow(QWindow *window, const QWindowsWindowData &data); ~QWindowsWindow(); - virtual QSurfaceFormat format() const { return m_format; } - virtual void setGeometry(const QRect &rect); - virtual QRect geometry() const { return m_data.geometry; } - QRect normalGeometry() const Q_DECL_OVERRIDE; - - virtual void setVisible(bool visible); + QSurfaceFormat format() const Q_DECL_OVERRIDE { return m_format; } + void setGeometryDp(const QRect &rectIn); + void setGeometry(const QRect &rect) Q_DECL_OVERRIDE + { setGeometryDp(QWindowsScaling::mapToNative(rect)); } + QRect geometryDp() const { return m_data.geometry; } + QRect geometry() const Q_DECL_OVERRIDE + { return QWindowsScaling::mapFromNative(geometryDp()); } + QRect normalGeometryDp() const; + QRect normalGeometry() const Q_DECL_OVERRIDE + { return QWindowsScaling::mapFromNative(normalGeometryDp()); } + qreal devicePixelRatio() const Q_DECL_OVERRIDE + { return qreal(QWindowsScaling::factor()); } + void setVisible(bool visible) Q_DECL_OVERRIDE; bool isVisible() const; - virtual bool isExposed() const { return testFlag(Exposed); } - virtual bool isActive() const; - virtual bool isEmbedded(const QPlatformWindow *parentWindow) const; - virtual QPoint mapToGlobal(const QPoint &pos) const; - virtual QPoint mapFromGlobal(const QPoint &pos) const; - - virtual void setWindowFlags(Qt::WindowFlags flags); - virtual void setWindowState(Qt::WindowState state); + bool isExposed() const Q_DECL_OVERRIDE { return testFlag(Exposed); } + bool isActive() const Q_DECL_OVERRIDE; + bool isEmbedded(const QPlatformWindow *parentWindow) const Q_DECL_OVERRIDE; + QPoint mapToGlobalDp(const QPoint &pos) const; + QPoint mapToGlobal(const QPoint &pos) const Q_DECL_OVERRIDE + { return mapToGlobalDp(pos * QWindowsScaling::factor()) / QWindowsScaling::factor(); } + QPoint mapFromGlobalDp(const QPoint &pos) const; + QPoint mapFromGlobal(const QPoint &pos) const Q_DECL_OVERRIDE + { return mapFromGlobalDp(pos * QWindowsScaling::factor()) / QWindowsScaling::factor(); } + void setWindowFlags(Qt::WindowFlags flags) Q_DECL_OVERRIDE; + void setWindowState(Qt::WindowState state) Q_DECL_OVERRIDE; HWND handle() const { return m_data.hwnd; } - virtual WId winId() const { return WId(m_data.hwnd); } - virtual void setParent(const QPlatformWindow *window); + WId winId() const Q_DECL_OVERRIDE { return WId(m_data.hwnd); } + void setParent(const QPlatformWindow *window) Q_DECL_OVERRIDE; - virtual void setWindowTitle(const QString &title); - virtual void raise(); - virtual void lower(); + void setWindowTitle(const QString &title) Q_DECL_OVERRIDE; + void raise() Q_DECL_OVERRIDE; + void lower() Q_DECL_OVERRIDE; void windowEvent(QEvent *event); - virtual void propagateSizeHints(); - virtual QMargins frameMargins() const; + void propagateSizeHints() Q_DECL_OVERRIDE; + QMargins frameMarginsDp() const; + QMargins frameMargins() const Q_DECL_OVERRIDE { return frameMarginsDp() / QWindowsScaling::factor(); } - virtual void setOpacity(qreal level); - virtual void setMask(const QRegion ®ion); + void setOpacity(qreal level) Q_DECL_OVERRIDE; + void setMask(const QRegion ®ion) Q_DECL_OVERRIDE; qreal opacity() const { return m_opacity; } - virtual void requestActivateWindow(); + void requestActivateWindow() Q_DECL_OVERRIDE; - virtual bool setKeyboardGrabEnabled(bool grab); - virtual bool setMouseGrabEnabled(bool grab); + bool setKeyboardGrabEnabled(bool grab) Q_DECL_OVERRIDE; + bool setMouseGrabEnabled(bool grab) Q_DECL_OVERRIDE; inline bool hasMouseCapture() const { return GetCapture() == m_data.hwnd; } - virtual bool startSystemResize(const QPoint &pos, Qt::Corner corner); + bool startSystemResize(const QPoint &, Qt::Corner corner) Q_DECL_OVERRIDE; void setFrameStrutEventsEnabled(bool enabled); bool frameStrutEventsEnabled() const { return testFlag(FrameStrutEventsEnabled); } @@ -207,11 +210,6 @@ public: QMargins customMargins() const { return m_data.customMargins; } void setCustomMargins(const QMargins &m); -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - EGLSurface eglSurfaceHandle() const { return m_eglSurface;} - EGLSurface ensureEglSurfaceHandle(const QWindowsEGLStaticContextPtr &staticContext, EGLConfig config); -#endif - inline unsigned style() const { return GetWindowLongPtr(m_data.hwnd, GWL_STYLE); } void setStyle(unsigned s) const; @@ -248,11 +246,6 @@ public: void setCursor(const QWindowsWindowCursor &c); void applyCursor(); - QWindowsWindow *childAt(const QPoint &clientPoint, - unsigned cwexflags = CWP_SKIPINVISIBLE) const; - QWindowsWindow *childAtScreenPoint(const QPoint &screenPoint, - unsigned cwexflags = CWP_SKIPINVISIBLE) const; - static QByteArray debugWindowFlags(Qt::WindowFlags wf); inline bool testFlag(unsigned f) const { return (m_flags & f) != 0; } @@ -263,6 +256,8 @@ public: bool isEnabled() const; void setWindowIcon(const QIcon &icon); + void *surface(void *nativeConfig); + #ifndef Q_OS_WINCE void setAlertState(bool enabled); bool isAlertState() const { return testFlag(AlertState); } @@ -302,15 +297,12 @@ private: unsigned m_savedStyle; QRect m_savedFrameGeometry; const QSurfaceFormat m_format; -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - EGLSurface m_eglSurface; - QSharedPointer<QWindowsEGLStaticContext> m_staticEglContext; -#endif #ifdef Q_OS_WINCE bool m_previouslyHidden; #endif HICON m_iconSmall; HICON m_iconBig; + void *m_surface; }; // Debug diff --git a/src/plugins/platforms/windows/windows.pri b/src/plugins/platforms/windows/windows.pri index 13799ba1ba..8e5f35d293 100644 --- a/src/plugins/platforms/windows/windows.pri +++ b/src/plugins/platforms/windows/windows.pri @@ -39,7 +39,8 @@ SOURCES += \ $$PWD/qwindowsdialoghelpers.cpp \ $$PWD/qwindowsservices.cpp \ $$PWD/qwindowsnativeimage.cpp \ - $$PWD/qwindowsnativeinterface.cpp + $$PWD/qwindowsnativeinterface.cpp \ + $$PWD/qwindowsscaling.cpp HEADERS += \ $$PWD/qwindowswindow.h \ @@ -64,10 +65,15 @@ HEADERS += \ $$PWD/qwindowsservices.h \ $$PWD/qplatformfunctions_wince.h \ $$PWD/qwindowsnativeimage.h \ - $$PWD/qwindowsnativeinterface.h + $$PWD/qwindowsnativeinterface.h \ + $$PWD/qwindowsscaling.h + +!wince: HEADERS += $$PWD/qwindowsopengltester.h INCLUDEPATH += $$PWD +contains(QT_CONFIG,opengl): HEADERS += $$PWD/qwindowsopenglcontext.h + contains(QT_CONFIG, opengles2) { SOURCES += $$PWD/qwindowseglcontext.cpp HEADERS += $$PWD/qwindowseglcontext.h @@ -78,7 +84,8 @@ contains(QT_CONFIG, opengles2) { # Dynamic GL needs both WGL and EGL contains(QT_CONFIG,dynamicgl) { - SOURCES += $$PWD/qwindowseglcontext.cpp + SOURCES += $$PWD/qwindowseglcontext.cpp \ + $$PWD/qwindowsopengltester.cpp HEADERS += $$PWD/qwindowseglcontext.h } @@ -108,6 +115,10 @@ contains(QT_CONFIG,dynamicgl) { HEADERS += $$PWD/qwindowssessionmanager.h } +!wince*:!contains( DEFINES, QT_NO_IMAGEFORMAT_PNG ) { + RESOURCES += $$PWD/cursors.qrc +} + contains(QT_CONFIG, freetype) { DEFINES *= QT_NO_FONTCONFIG QT_FREETYPE_DIR = $$QT_SOURCE_TREE/src/3rdparty/freetype |