diff --git a/README.md b/README.md index 481b2979..f819804b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -This is Qt 6.6.1 backport that runs on Windows 7 (what?). The repository contains patched source files from the qtbase module. +This is Qt 6.6.2 backport that runs on Windows 7 (what?). The repository contains patched source files from the qtbase module. Approach is based on this [forum thread](https://forum.qt.io/topic/133002/qt-creator-6-0-1-and-qt-6-2-2-running-on-windows-7/60) but better: many improvements amongst important fallbacks to default Qt 6 behaviour when running on newer Windows. -You can use [our prebuild binaries](https://github.com/crystalidea/qt6windows7/releases) (we used Visual C++ 2019 with OpenSSL 1.1.1k statically linked, see [compile_win.pl](https://github.com/crystalidea/qt-build-tools/tree/master/6.6.1) script) or compile Qt yourself. +You can use [our prebuild binaries](https://github.com/crystalidea/qt6windows7/releases) (we used Visual C++ 2019 with OpenSSL 3.0.13 statically linked, see [compile_win.pl](https://github.com/crystalidea/qt-build-tools/tree/master/6.6.2) script) or compile Qt yourself. Known issues: diff --git a/qt6_x86_to_run_on_windows7.7z b/qt6_x86_to_run_on_windows7.7z new file mode 100644 index 00000000..64d374d4 Binary files /dev/null and b/qt6_x86_to_run_on_windows7.7z differ diff --git a/qtbase/src/gui/rhi/qrhid3d12.cpp b/qtbase/src/gui/rhi/qrhid3d12.cpp index 561e6db4..8edf734d 100644 --- a/qtbase/src/gui/rhi/qrhid3d12.cpp +++ b/qtbase/src/gui/rhi/qrhid3d12.cpp @@ -192,9 +192,20 @@ bool QRhiD3D12::create(QRhi::Flags flags) factoryFlags |= DXGI_CREATE_FACTORY_DEBUG; HRESULT hr = myCreateDXGIFactory2(factoryFlags, __uuidof(IDXGIFactory2), reinterpret_cast(&dxgiFactory)); if (FAILED(hr)) { - qWarning("CreateDXGIFactory2() failed to create DXGI factory: %s", - qPrintable(QSystemError::windowsComString(hr))); - return false; + // retry without debug, if it was requested (to match D3D11 backend behavior) + if (debugLayer) { + qCDebug(QRHI_LOG_INFO, "Debug layer was requested but is not available. " + "Attempting to create DXGIFactory2 without it."); + factoryFlags &= ~DXGI_CREATE_FACTORY_DEBUG; + hr = myCreateDXGIFactory2(factoryFlags, __uuidof(IDXGIFactory2), reinterpret_cast(&dxgiFactory)); + } + if (SUCCEEDED(hr)) { + debugLayer = false; + } else { + qWarning("CreateDXGIFactory2() failed to create DXGI factory: %s", + qPrintable(QSystemError::windowsComString(hr))); + return false; + } } supportsAllowTearing = false; diff --git a/qtbase/src/plugins/platforms/windows/qwindowscontext.cpp b/qtbase/src/plugins/platforms/windows/qwindowscontext.cpp index 9447fcfc..0b510475 100644 --- a/qtbase/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/qtbase/src/plugins/platforms/windows/qwindowscontext.cpp @@ -1222,7 +1222,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, d->m_creationContext->applyToMinMaxInfo(reinterpret_cast(lParam)); return true; case QtWindows::ResizeEvent: - d->m_creationContext->obtainedSize = QSize(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + d->m_creationContext->obtainedSize = QSize(LOWORD(lParam), HIWORD(lParam)); return true; case QtWindows::MoveEvent: d->m_creationContext->obtainedPos = QPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); diff --git a/qtbase/src/plugins/platforms/windows/qwindowsdrag.cpp b/qtbase/src/plugins/platforms/windows/qwindowsdrag.cpp index ea2439e9..b91608de 100644 --- a/qtbase/src/plugins/platforms/windows/qwindowsdrag.cpp +++ b/qtbase/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -649,7 +649,8 @@ IDropTargetHelper* QWindowsDrag::dropHelper() { static HRESULT startDoDragDrop(LPDATAOBJECT pDataObj, LPDROPSOURCE pDropSource, DWORD dwOKEffects, LPDWORD pdwEffect) { QWindow *underMouse = QWindowsContext::instance()->windowUnderMouse(); - const HWND hwnd = underMouse ? reinterpret_cast(underMouse->winId()) : ::GetFocus(); + const bool hasMouseCapture = underMouse && static_cast(underMouse->handle())->hasMouseCapture(); + const HWND hwnd = hasMouseCapture ? reinterpret_cast(underMouse->winId()) : ::GetFocus(); bool starting = false; for (;;) { diff --git a/qtbase/src/plugins/platforms/windows/qwindowskeymapper.cpp b/qtbase/src/plugins/platforms/windows/qwindowskeymapper.cpp index 4b219c34..319b8ab3 100644 --- a/qtbase/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/qtbase/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -990,7 +990,7 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg, // A multi-character key or a Input method character // not found by our look-ahead if (msgType == WM_CHAR || msgType == WM_IME_CHAR) { - sendExtendedPressRelease(receiver, 0, Qt::KeyboardModifier(state), scancode, vk_key, nModifiers, messageKeyText(msg), false); + sendExtendedPressRelease(receiver, 0, Qt::KeyboardModifier(state), scancode, 0, nModifiers, messageKeyText(msg), false); return true; } diff --git a/qtbase/src/plugins/platforms/windows/qwindowsscreen.cpp b/qtbase/src/plugins/platforms/windows/qwindowsscreen.cpp index b78b6d54..a8f65209 100644 --- a/qtbase/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/qtbase/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -118,16 +119,22 @@ static float getMonitorSDRWhiteLevel(DISPLAYCONFIG_PATH_TARGET_INFO *targetInfo) using WindowsScreenDataList = QList; -struct RegistryHandleDeleter +namespace { + +struct DiRegKeyHandleTraits { - void operator()(HKEY handle) const noexcept + using Type = HKEY; + static Type invalidValue() { - if (handle != nullptr && handle != INVALID_HANDLE_VALUE) - RegCloseKey(handle); + // The setupapi.h functions return INVALID_HANDLE_VALUE when failing to open a registry key + return reinterpret_cast(INVALID_HANDLE_VALUE); } + static bool close(Type handle) { return RegCloseKey(handle) == ERROR_SUCCESS; } }; -using RegistryHandlePtr = std::unique_ptr, RegistryHandleDeleter>; +using DiRegKeyHandle = QUniqueHandle; + +} static void setMonitorDataFromSetupApi(QWindowsScreenData &data, const std::vector &pathGroup) @@ -209,10 +216,10 @@ static void setMonitorDataFromSetupApi(QWindowsScreenData &data, continue; } - const RegistryHandlePtr edidRegistryKey{ SetupDiOpenDevRegKey( + const DiRegKeyHandle edidRegistryKey{ SetupDiOpenDevRegKey( devInfo, &deviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ) }; - if (!edidRegistryKey || edidRegistryKey.get() == INVALID_HANDLE_VALUE) + if (!edidRegistryKey.isValid()) continue; DWORD edidDataSize{ 0 }; diff --git a/qtbase/src/plugins/platforms/windows/qwindowswindow.cpp b/qtbase/src/plugins/platforms/windows/qwindowswindow.cpp index de71c5c3..7f29c7ff 100644 --- a/qtbase/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/qtbase/src/plugins/platforms/windows/qwindowswindow.cpp @@ -1025,6 +1025,21 @@ static QSize toNativeSizeConstrained(QSize dip, const QScreen *s) return dip; } +// Helper for checking if frame adjustment needs to be skipped +// NOTE: Unmaximized frameless windows will skip margins calculation +static bool shouldOmitFrameAdjustment(const Qt::WindowFlags flags, DWORD style) +{ + return flags.testFlag(Qt::FramelessWindowHint) && !(style & WS_MAXIMIZE); +} + +// Helper for checking if frame adjustment needs to be skipped +// NOTE: Unmaximized frameless windows will skip margins calculation +static bool shouldOmitFrameAdjustment(const Qt::WindowFlags flags, HWND hwnd) +{ + DWORD style = hwnd != nullptr ? DWORD(GetWindowLongPtr(hwnd, GWL_STYLE)) : 0; + return flags.testFlag(Qt::FramelessWindowHint) && !(style & WS_MAXIMIZE); +} + /*! \class QWindowsGeometryHint \brief Stores geometry constraints and provides utility functions. @@ -1037,7 +1052,7 @@ static QSize toNativeSizeConstrained(QSize dip, const QScreen *s) QMargins QWindowsGeometryHint::frameOnPrimaryScreen(const QWindow *w, DWORD style, DWORD exStyle) { - if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint)) + if (!w->isTopLevel() || shouldOmitFrameAdjustment(w->flags(), style)) return {}; RECT rect = {0,0,0,0}; style &= ~DWORD(WS_OVERLAPPED); // Not permitted, see docs. @@ -1053,15 +1068,13 @@ QMargins QWindowsGeometryHint::frameOnPrimaryScreen(const QWindow *w, DWORD styl QMargins QWindowsGeometryHint::frameOnPrimaryScreen(const QWindow *w, HWND hwnd) { - if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint)) - return {}; return frameOnPrimaryScreen(w, DWORD(GetWindowLongPtr(hwnd, GWL_STYLE)), DWORD(GetWindowLongPtr(hwnd, GWL_EXSTYLE))); } QMargins QWindowsGeometryHint::frame(const QWindow *w, DWORD style, DWORD exStyle, qreal dpi) { - if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint)) + if (!w->isTopLevel() || shouldOmitFrameAdjustment(w->flags(), style)) return {}; RECT rect = {0,0,0,0}; style &= ~DWORD(WS_OVERLAPPED); // Not permitted, see docs. @@ -1080,7 +1093,7 @@ QMargins QWindowsGeometryHint::frame(const QWindow *w, DWORD style, DWORD exStyl QMargins QWindowsGeometryHint::frame(const QWindow *w, HWND hwnd, DWORD style, DWORD exStyle) { - if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint)) + if (!w->isTopLevel() || shouldOmitFrameAdjustment(w->flags(), style)) return {}; if (QWindowsScreenManager::isSingleScreen()) return frameOnPrimaryScreen(w, style, exStyle); @@ -1094,8 +1107,6 @@ QMargins QWindowsGeometryHint::frame(const QWindow *w, HWND hwnd, DWORD style, D QMargins QWindowsGeometryHint::frame(const QWindow *w, HWND hwnd) { - if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint)) - return {}; return frame(w, hwnd, DWORD(GetWindowLongPtr(hwnd, GWL_STYLE)), DWORD(GetWindowLongPtr(hwnd, GWL_EXSTYLE))); } @@ -1104,7 +1115,7 @@ QMargins QWindowsGeometryHint::frame(const QWindow *w, HWND hwnd) QMargins QWindowsGeometryHint::frame(const QWindow *w, const QRect &geometry, DWORD style, DWORD exStyle) { - if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint)) + if (!w->isTopLevel() || shouldOmitFrameAdjustment(w->flags(), style)) return {}; if (QWindowsScreenManager::isSingleScreen() || !QWindowsContext::shouldHaveNonClientDpiScaling(w)) { @@ -2042,7 +2053,7 @@ void QWindowsWindow::handleDpiChanged(HWND hwnd, WPARAM wParam, LPARAM lParam) // If the window does not have a frame, WM_MOVE and WM_SIZE won't be // called which prevents the content from being scaled appropriately // after a DPI change. - if (m_data.flags & Qt::FramelessWindowHint) + if (shouldOmitFrameAdjustment(m_data.flags, m_data.hwnd)) handleGeometryChange(); } @@ -2575,26 +2586,26 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowStates newState) if (testFlag(HasBorderInFullScreen)) newStyle |= WS_BORDER; setStyle(newStyle); - // Use geometry of QWindow::screen() within creation or the virtual screen the - // window is in (QTBUG-31166, QTBUG-30724). - const QScreen *screen = window()->screen(); - if (!screen) - screen = QGuiApplication::primaryScreen(); - const QRect r = screen ? QHighDpi::toNativePixels(screen->geometry(), window()) : m_savedFrameGeometry; - + const HMONITOR monitor = MonitorFromWindow(m_data.hwnd, MONITOR_DEFAULTTONEAREST); + MONITORINFO monitorInfo = {}; + monitorInfo.cbSize = sizeof(MONITORINFO); + GetMonitorInfoW(monitor, &monitorInfo); + const QRect screenGeometry(monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top, + monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left, + monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top); if (newState & Qt::WindowMinimized) { - setMinimizedGeometry(m_data.hwnd, r); + setMinimizedGeometry(m_data.hwnd, screenGeometry); if (stateChange & Qt::WindowMaximized) setRestoreMaximizedFlag(m_data.hwnd, newState & Qt::WindowMaximized); } else { const UINT swpf = SWP_FRAMECHANGED | SWP_NOACTIVATE; const bool wasSync = testFlag(SynchronousGeometryChangeEvent); setFlag(SynchronousGeometryChangeEvent); - SetWindowPos(m_data.hwnd, HWND_TOP, r.left(), r.top(), r.width(), r.height(), swpf); + SetWindowPos(m_data.hwnd, HWND_TOP, screenGeometry.left(), screenGeometry.top(), screenGeometry.width(), screenGeometry.height(), swpf); if (!wasSync) clearFlag(SynchronousGeometryChangeEvent); clearFlag(MaximizeToFullScreen); - QWindowSystemInterface::handleGeometryChange(window(), r); + QWindowSystemInterface::handleGeometryChange(window(), screenGeometry); QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); } } else { @@ -2761,7 +2772,7 @@ bool QWindowsWindow::handleGeometryChanging(MSG *message) const void QWindowsWindow::setFullFrameMargins(const QMargins &newMargins) { - if (m_data.flags & Qt::FramelessWindowHint) + if (shouldOmitFrameAdjustment(m_data.flags, m_data.hwnd)) return; if (m_data.fullFrameMargins != newMargins) { qCDebug(lcQpaWindow) << __FUNCTION__ << window() << m_data.fullFrameMargins << "->" << newMargins; @@ -2780,13 +2791,8 @@ void QWindowsWindow::updateFullFrameMargins() void QWindowsWindow::calculateFullFrameMargins() { - if (m_data.flags & Qt::FramelessWindowHint) + if (shouldOmitFrameAdjustment(m_data.flags, m_data.hwnd)) return; - // Normally obtained from WM_NCCALCSIZE. This calculation only works - // when no native menu is present. - const auto systemMargins = testFlag(DisableNonClientScaling) - ? QWindowsGeometryHint::frameOnPrimaryScreen(window(), m_data.hwnd) - : frameMargins_sys(); // QTBUG-113736: systemMargins depends on AdjustWindowRectExForDpi. This doesn't take into // account possible external modifications to the titlebar, as with ExtendsContentIntoTitleBar() @@ -2800,6 +2806,20 @@ void QWindowsWindow::calculateFullFrameMargins() RECT clientRect{}; GetWindowRect(handle(), &windowRect); GetClientRect(handle(), &clientRect); + + // QTBUG-117704 It is also possible that the user has manually removed the frame (for example + // by handling WM_NCCALCSIZE). If that is the case, i.e., the client area and the window area + // have identical sizes, we don't want to override the user-defined margins. + + if (qrectFromRECT(windowRect).size() == qrectFromRECT(clientRect).size()) + return; + + // Normally obtained from WM_NCCALCSIZE. This calculation only works + // when no native menu is present. + const auto systemMargins = testFlag(DisableNonClientScaling) + ? QWindowsGeometryHint::frameOnPrimaryScreen(window(), m_data.hwnd) + : frameMargins_sys(); + const int yDiff = (windowRect.bottom - windowRect.top) - (clientRect.bottom - clientRect.top); const bool typicalFrame = (systemMargins.left() == systemMargins.right()) && (systemMargins.right() == systemMargins.bottom()); @@ -2822,7 +2842,7 @@ QMargins QWindowsWindow::frameMargins() const QMargins QWindowsWindow::fullFrameMargins() const { - if (m_data.flags & Qt::FramelessWindowHint) + if (shouldOmitFrameAdjustment(m_data.flags, m_data.hwnd)) return {}; return m_data.fullFrameMargins; }