summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/windows/qwindowswindow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/windows/qwindowswindow.cpp')
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp195
1 files changed, 151 insertions, 44 deletions
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index ca87f1b6a4..9c31409644 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -58,23 +58,25 @@
#else
# include "qwindowsopenglcontext.h"
#endif
+#include "qwindowsopengltester.h"
#ifdef QT_NO_CURSOR
# include "qwindowscursor.h"
#endif
-#include <QtGui/QGuiApplication>
-#include <QtGui/QScreen>
-#include <QtGui/QWindow>
-#include <QtGui/QRegion>
-#include <QtGui/QOpenGLContext>
+#include <QtGui/qguiapplication.h>
+#include <QtGui/qscreen.h>
+#include <QtGui/qwindow.h>
+#include <QtGui/qregion.h>
+#include <QtGui/qopenglcontext.h>
#include <private/qsystemlibrary_p.h>
#include <private/qwindow_p.h> // QWINDOWSIZE_MAX
#include <private/qguiapplication_p.h>
#include <private/qhighdpiscaling_p.h>
#include <qpa/qwindowsysteminterface.h>
-#include <QtCore/QDebug>
-#include <QtCore/QLibraryInfo>
+#include <QtCore/qdebug.h>
+#include <QtCore/qlibraryinfo.h>
+#include <QtCore/qoperatingsystemversion.h>
#include <dwmapi.h>
@@ -422,6 +424,31 @@ static inline void updateGLWindowSettings(const QWindow *w, HWND hwnd, Qt::Windo
}
/*!
+ Calculates the dimensions of the invisible borders within the
+ window frames in Windows 10, using an empirical expression that
+ reproduces the measured values for standard DPI settings.
+*/
+
+static QMargins invisibleMargins(QPoint screenPoint)
+{
+ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10) {
+ POINT pt = {screenPoint.x(), screenPoint.y()};
+ if (HMONITOR hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL)) {
+ if (QWindowsContext::shcoredll.isValid()) {
+ UINT dpiX;
+ UINT dpiY;
+ if (SUCCEEDED(QWindowsContext::shcoredll.getDpiForMonitor(hMonitor, 0, &dpiX, &dpiY))) {
+ const qreal sc = (dpiX - 96) / 96.0;
+ const int gap = 7 + qRound(5*sc) - int(sc);
+ return QMargins(gap, 0, gap, gap);
+ }
+ }
+ }
+ }
+ return QMargins();
+}
+
+/*!
\class WindowCreationData
\brief Window creation code.
@@ -515,6 +542,84 @@ static inline void fixTopLevelWindowFlags(Qt::WindowFlags &flags)
flags |= Qt::FramelessWindowHint;
}
+static QScreen *screenForName(const QWindow *w, const QString &name)
+{
+ QScreen *winScreen = w ? w->screen() : QGuiApplication::primaryScreen();
+ if (winScreen && winScreen->name() != name) {
+ const auto screens = winScreen->virtualSiblings();
+ for (QScreen *screen : screens) {
+ if (screen->name() == name)
+ return screen;
+ }
+ }
+ return winScreen;
+}
+
+static QScreen *forcedScreenForGLWindow(const QWindow *w)
+{
+ const QString forceToScreen = GpuDescription::detect().gpuSuitableScreen;
+ return forceToScreen.isEmpty() ? nullptr : screenForName(w, forceToScreen);
+}
+
+static QPoint calcPosition(const QWindow *w, const QWindowCreationContextPtr &context, const QMargins &invMargins)
+{
+ const QPoint orgPos(context->frameX - invMargins.left(), context->frameY - invMargins.top());
+
+ if (!w || (!w->isTopLevel() && w->surfaceType() != QWindow::OpenGLSurface))
+ return orgPos;
+
+ // Workaround for QTBUG-50371
+ const QScreen *screenForGL = forcedScreenForGLWindow(w);
+ if (!screenForGL)
+ return orgPos;
+
+ const QPoint posFrame(context->frameX, context->frameY);
+ const QMargins margins = context->margins;
+ const QRect scrGeo = screenForGL->handle()->availableGeometry();
+
+ // Point is already in the required screen.
+ if (scrGeo.contains(orgPos))
+ return orgPos;
+
+ // If the visible part of the window is already in the
+ // required screen, just ignore the invisible offset.
+ if (scrGeo.contains(posFrame))
+ return posFrame;
+
+ // Find the original screen containing the coordinates.
+ const QList<QScreen *> screens = screenForGL->virtualSiblings();
+ const QScreen *orgScreen = nullptr;
+ for (QScreen *screen : screens) {
+ if (screen->handle()->availableGeometry().contains(posFrame)) {
+ orgScreen = screen;
+ break;
+ }
+ }
+ const QPoint ctPos = QPoint(qMax(scrGeo.left(), scrGeo.center().x()
+ + (margins.right() - margins.left() - context->frameWidth)/2),
+ qMax(scrGeo.top(), scrGeo.center().y()
+ + (margins.bottom() - margins.top() - context->frameHeight)/2));
+
+ // If initial coordinates were outside all screens, center the window on the required screen.
+ if (!orgScreen)
+ return ctPos;
+
+ const QRect orgGeo = orgScreen->handle()->availableGeometry();
+ const QRect orgFrame(QPoint(context->frameX, context->frameY),
+ QSize(context->frameWidth, context->frameHeight));
+
+ // Window would be centered on orgScreen. Center it on the required screen.
+ if (orgGeo.center() == (orgFrame - margins).center())
+ return ctPos;
+
+ // Transform the coordinates to map them into the required screen.
+ const QPoint newPos(scrGeo.left() + ((posFrame.x() - orgGeo.left()) * scrGeo.width()) / orgGeo.width(),
+ scrGeo.top() + ((posFrame.y() - orgGeo.top()) * scrGeo.height()) / orgGeo.height());
+ const QPoint newPosNoMargin(newPos.x() - invMargins.left(), newPos.y() - invMargins.top());
+
+ return scrGeo.contains(newPosNoMargin) ? newPosNoMargin : newPos;
+}
+
void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flagsIn,
unsigned creationFlags)
{
@@ -634,7 +739,7 @@ QWindowsWindowData
WindowData result;
result.flags = flags;
- const HINSTANCE appinst = (HINSTANCE)GetModuleHandle(0);
+ const auto appinst = reinterpret_cast<HINSTANCE>(GetModuleHandle(nullptr));
const QString windowClassName = QWindowsContext::instance()->registerWindowClass(w);
@@ -651,16 +756,23 @@ QWindowsWindowData
const QWindowCreationContextPtr context(new QWindowCreationContext(w, data.geometry, rect, data.customMargins, style, exStyle));
QWindowsContext::instance()->setWindowCreationContext(context);
+ QMargins invMargins = topLevel && !(result.flags & Qt::FramelessWindowHint) && QWindowsGeometryHint::positionIncludesFrame(w)
+ ? invisibleMargins(QPoint(context->frameX, context->frameY)) : QMargins();
+
qCDebug(lcQpaWindows).nospace()
<< "CreateWindowEx: " << w << " class=" << windowClassName << " title=" << title
<< '\n' << *this << "\nrequested: " << rect << ": "
<< context->frameWidth << 'x' << context->frameHeight
<< '+' << context->frameX << '+' << context->frameY
- << " custom margins: " << context->customMargins;
+ << " custom margins: " << context->customMargins
+ << " invisible margins: " << invMargins;
+
+
+ QPoint pos = calcPosition(w, context, invMargins);
result.hwnd = CreateWindowEx(exStyle, classNameUtf16, titleUtf16,
style,
- context->frameX, context->frameY,
+ pos.x(), pos.y(),
context->frameWidth, context->frameHeight,
parentHandle, NULL, appinst, NULL);
qCDebug(lcQpaWindows).nospace()
@@ -673,7 +785,7 @@ QWindowsWindowData
}
result.geometry = context->obtainedGeometry;
- result.frame = context->margins;
+ result.fullFrameMargins = context->margins;
result.embedded = embedded;
result.customMargins = context->customMargins;
@@ -887,7 +999,7 @@ QRect QWindowsBaseWindow::frameGeometry_sys() const
QRect QWindowsBaseWindow::geometry_sys() const
{
- return frameGeometry_sys().marginsRemoved(frameMargins());
+ return frameGeometry_sys().marginsRemoved(fullFrameMargins());
}
QMargins QWindowsBaseWindow::frameMargins_sys() const
@@ -1344,28 +1456,12 @@ bool QWindowsWindow::isEmbedded() const
QPoint QWindowsWindow::mapToGlobal(const QPoint &pos) const
{
- if (m_data.hwnd)
- return QWindowsGeometryHint::mapToGlobal(m_data.hwnd, pos);
- else
- return pos;
+ return m_data.hwnd ? QWindowsGeometryHint::mapToGlobal(m_data.hwnd, pos) : pos;
}
QPoint QWindowsWindow::mapFromGlobal(const QPoint &pos) const
{
- if (m_data.hwnd)
- return QWindowsGeometryHint::mapFromGlobal(m_data.hwnd, pos);
- else
- return pos;
-}
-
-static inline HWND transientParentHwnd(HWND hwnd)
-{
- if (GetAncestor(hwnd, GA_PARENT) == GetDesktopWindow()) {
- const HWND rootOwnerHwnd = GetAncestor(hwnd, GA_ROOTOWNER);
- if (rootOwnerHwnd != hwnd) // May return itself for toplevels.
- return rootOwnerHwnd;
- }
- return 0;
+ return m_data.hwnd ? QWindowsGeometryHint::mapFromGlobal(m_data.hwnd, pos) : pos;
}
// Update the transient parent for a toplevel window. The concept does not
@@ -1382,7 +1478,7 @@ void QWindowsWindow::updateTransientParent() const
if (window()->type() == Qt::Popup)
return; // QTBUG-34503, // a popup stays on top, no parent, see also WindowCreationData::fromWindow().
// Update transient parent.
- const HWND oldTransientParent = transientParentHwnd(m_data.hwnd);
+ const HWND oldTransientParent = GetWindow(m_data.hwnd, GW_OWNER);
HWND newTransientParent = 0;
if (const QWindow *tp = window()->transientParent())
if (const QWindowsWindow *tw = QWindowsWindow::windowsWindowOf(tp))
@@ -1560,7 +1656,7 @@ QRect QWindowsWindow::normalGeometry() const
const bool fakeFullScreen =
m_savedFrameGeometry.isValid() && (window()->windowStates() & Qt::WindowFullScreen);
const QRect frame = fakeFullScreen ? m_savedFrameGeometry : normalFrameGeometry(m_data.hwnd);
- const QMargins margins = fakeFullScreen ? QWindowsGeometryHint::frame(m_savedStyle, 0) : frameMargins();
+ const QMargins margins = fakeFullScreen ? QWindowsGeometryHint::frame(m_savedStyle, 0) : fullFrameMargins();
return frame.isValid() ? frame.marginsRemoved(margins) : frame;
}
@@ -1592,8 +1688,8 @@ void QWindowsWindow::setGeometry(const QRect &rectIn)
window()->metaObject()->className(), qPrintable(window()->objectName()),
m_data.geometry.width(), m_data.geometry.height(),
m_data.geometry.x(), m_data.geometry.y(),
- m_data.frame.left(), m_data.frame.top(),
- m_data.frame.right(), m_data.frame.bottom(),
+ m_data.fullFrameMargins.left(), m_data.fullFrameMargins.top(),
+ m_data.fullFrameMargins.right(), m_data.fullFrameMargins.bottom(),
m_data.customMargins.left(), m_data.customMargins.top(),
m_data.customMargins.right(), m_data.customMargins.bottom(),
window()->minimumWidth(), window()->minimumHeight(),
@@ -1685,7 +1781,7 @@ void QWindowsWindow::handleGeometryChange()
void QWindowsBaseWindow::setGeometry_sys(const QRect &rect) const
{
- const QMargins margins = frameMargins();
+ const QMargins margins = fullFrameMargins();
const QRect frameGeometry = rect + margins;
qCDebug(lcQpaWindows) << '>' << __FUNCTION__ << window()
@@ -1856,7 +1952,8 @@ void QWindowsWindow::handleWindowStateChange(Qt::WindowStates state)
fireExpose(QRegion(0, 0, w->width(), w->height()));
exposeEventsSent = true;
}
- foreach (QWindow *child, QGuiApplication::allWindows()) {
+ const QWindowList allWindows = QGuiApplication::allWindows();
+ for (QWindow *child : allWindows) {
if (child != w && child->isVisible() && child->transientParent() == w) {
QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(child);
if (platformWindow && platformWindow->isLayered()) {
@@ -2048,7 +2145,7 @@ void QWindowsWindow::setExStyle(unsigned s) const
SetWindowLongPtr(m_data.hwnd, GWL_EXSTYLE, s);
}
-void QWindowsWindow::windowEvent(QEvent *event)
+bool QWindowsWindow::windowEvent(QEvent *event)
{
switch (event->type()) {
case QEvent::WindowBlocked: // Blocked by another modal window.
@@ -2064,6 +2161,8 @@ void QWindowsWindow::windowEvent(QEvent *event)
default:
break;
}
+
+ return QPlatformWindow::windowEvent(event);
}
void QWindowsWindow::propagateSizeHints()
@@ -2106,21 +2205,29 @@ bool QWindowsWindow::handleGeometryChangingMessage(MSG *message, const QWindow *
bool QWindowsWindow::handleGeometryChanging(MSG *message) const
{
- const QMargins margins = window()->isTopLevel() ? frameMargins() : QMargins();
+ const QMargins margins = window()->isTopLevel() ? fullFrameMargins() : QMargins();
return QWindowsWindow::handleGeometryChangingMessage(message, window(), margins);
}
-void QWindowsWindow::setFrameMargins(const QMargins &newMargins)
+void QWindowsWindow::setFullFrameMargins(const QMargins &newMargins)
{
- if (m_data.frame != newMargins) {
- qCDebug(lcQpaWindows) << __FUNCTION__ << window() << m_data.frame << "->" << newMargins;
- m_data.frame = newMargins;
+ if (m_data.fullFrameMargins != newMargins) {
+ qCDebug(lcQpaWindows) << __FUNCTION__ << window() << m_data.fullFrameMargins << "->" << newMargins;
+ m_data.fullFrameMargins = newMargins;
}
}
QMargins QWindowsWindow::frameMargins() const
{
- return m_data.frame;
+ QMargins result = fullFrameMargins();
+ if (isTopLevel() && !(m_data.flags & Qt::FramelessWindowHint))
+ result -= invisibleMargins(geometry().topLeft());
+ return result;
+}
+
+QMargins QWindowsWindow::fullFrameMargins() const
+{
+ return m_data.fullFrameMargins;
}
void QWindowsWindow::setOpacity(qreal level)
@@ -2174,7 +2281,7 @@ void QWindowsWindow::setMask(const QRegion &region)
// 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 = fullFrameMargins();
OffsetRgn(winRegion, margins.left(), margins.top());
}