| | |
| | | #include <QtCore/QHash> |
| | | #include <QtCore/QScopeGuard> |
| | | #include <QtCore/QTimer> |
| | | #include <QtCore/QDateTime> |
| | | #include <QtGui/QGuiApplication> |
| | | #include <QtGui/QPainter> |
| | | #include <QtGui/QPalette> |
| | |
| | | |
| | | // Original Qt window proc function |
| | | static WNDPROC g_qtWindowProc = nullptr; |
| | | |
| | | static inline bool |
| | | #if !QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER) |
| | | constexpr |
| | | #endif |
| | | |
| | | isSystemBorderEnabled() { |
| | | return |
| | | #if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER) |
| | | isWin10OrGreater() |
| | | #else |
| | | false |
| | | #endif |
| | | ; |
| | | } |
| | | |
| | | static inline void triggerFrameChange(HWND hwnd) { |
| | | ::SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, |
| | |
| | | static inline void addManagedWindow(QWindow *window, HWND hWnd, Win32WindowContext *ctx) { |
| | | const auto margins = [hWnd]() -> QMargins { |
| | | const auto titleBarHeight = int(getTitleBarHeight(hWnd)); |
| | | if (isWin10OrGreater()) { |
| | | if (isSystemBorderEnabled()) { |
| | | return {0, -titleBarHeight, 0, 0}; |
| | | } else { |
| | | const auto frameSize = int(getResizeBorderThickness(hWnd)); |
| | |
| | | } |
| | | |
| | | case DrawWindows10BorderHook: { |
| | | #if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER) |
| | | if (!windowId) |
| | | return; |
| | | |
| | |
| | | const auto hwnd = reinterpret_cast<HWND>(windowId); |
| | | |
| | | QPen pen; |
| | | pen.setWidth(getWindowFrameBorderThickness(hwnd) * 2); |
| | | pen.setWidth(int(getWindowFrameBorderThickness(hwnd)) * 2); |
| | | |
| | | const bool dark = isDarkThemeActive() && isDarkWindowFrameEnabled(hwnd); |
| | | if (m_delegate->isWindowActive(m_host)) { |
| | |
| | | } |
| | | painter.save(); |
| | | |
| | | // We needs anti-aliasing to give us better result. |
| | | // We need antialiasing to give us better result. |
| | | painter.setRenderHint(QPainter::Antialiasing); |
| | | |
| | | painter.setPen(pen); |
| | |
| | | QPoint{m_windowHandle->width(), 0} |
| | | }); |
| | | painter.restore(); |
| | | return; |
| | | #endif |
| | | } |
| | | |
| | | case DrawWindows10BorderHook2: { |
| | | #if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER) |
| | | if (!m_windowHandle) |
| | | return; |
| | | |
| | | // https://github.com/microsoft/terminal/blob/71a6f26e6ece656084e87de1a528c4a8072eeabd/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp#L1025 |
| | | // https://docs.microsoft.com/en-us/windows/win32/dwm/customframe#extending-the-client-frame |
| | | // Draw a black rectangle to make Windows native top border show |
| | | |
| | | auto hWnd = reinterpret_cast<HWND>(windowId); |
| | | HDC hdc = ::GetDC(hWnd); |
| | | RECT windowRect{}; |
| | | ::GetClientRect(hWnd, &windowRect); |
| | | RECT rcTopBorder = { |
| | | 0, |
| | | 0, |
| | | RECT_WIDTH(windowRect), |
| | | int(getWindowFrameBorderThickness(hWnd)), |
| | | }; |
| | | ::FillRect(hdc, &rcTopBorder, |
| | | reinterpret_cast<HBRUSH>(::GetStockObject(BLACK_BRUSH))); |
| | | ::ReleaseDC(hWnd, hdc); |
| | | #endif |
| | | return; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | bool Win32WindowContext::needBorderPainter() const { |
| | | return isWin10OrGreater() && !isWin11OrGreater(); |
| | | Q_UNUSED(this) |
| | | return isSystemBorderEnabled() && !isWin11OrGreater(); |
| | | } |
| | | |
| | | int Win32WindowContext::borderThickness() const { |
| | | return getWindowFrameBorderThickness(reinterpret_cast<HWND>(windowId)); |
| | | return int(getWindowFrameBorderThickness(reinterpret_cast<HWND>(windowId))); |
| | | } |
| | | |
| | | void Win32WindowContext::resume(const QByteArray &eventType, void *message, |
| | | QT_NATIVE_EVENT_RESULT_TYPE *result) { |
| | | const auto msg = static_cast<const MSG *>(message); |
| | | LRESULT res = |
| | | ::CallWindowProcW(g_qtWindowProc, msg->hwnd, msg->message, msg->wParam, msg->lParam); |
| | | *result = decltype(*result)(res); |
| | | } |
| | | |
| | | void Win32WindowContext::winIdChanged() { |
| | |
| | | auto winId = m_windowHandle->winId(); |
| | | auto hWnd = reinterpret_cast<HWND>(winId); |
| | | |
| | | #if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER) |
| | | if (!isWin10OrGreater()) { |
| | | if (!isSystemBorderEnabled()) { |
| | | static constexpr const MARGINS margins = {1, 1, 1, 1}; |
| | | DynamicApis::instance().pDwmExtendFrameIntoClientArea(hWnd, &margins); |
| | | } |
| | | #else |
| | | { |
| | | static const MARGINS margins = |
| | | isWin10OrGreater() ? MARGINS{0, 0, 0, 0} : MARGINS{1, 1, 1, 1}; |
| | | } else if (isWin10OrGreater() && !isWin11OrGreater()) { |
| | | // https://github.com/microsoft/terminal/blob/71a6f26e6ece656084e87de1a528c4a8072eeabd/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp#L940 |
| | | // Must call DWM API to extend top frame to client area |
| | | static constexpr const MARGINS margins = {0, 0, 1, 0}; |
| | | DynamicApis::instance().pDwmExtendFrameIntoClientArea(hWnd, &margins); |
| | | } |
| | | #endif |
| | | |
| | | |
| | | { |
| | | auto style = ::GetWindowLongPtrW(hWnd, GWL_STYLE); |
| | |
| | | const DynamicApis &apis = DynamicApis::instance(); |
| | | static constexpr const MARGINS extendMargins = {-1, -1, -1, -1}; |
| | | static const auto defaultMargins = |
| | | isWin10OrGreater() ? MARGINS{0, 0, 0, 0} : MARGINS{1, 1, 1, 1}; |
| | | isSystemBorderEnabled() ? MARGINS{0, 0, 0, 0} : MARGINS{1, 1, 1, 1}; |
| | | if (key == QStringLiteral("mica")) { |
| | | if (!isWin11OrGreater()) { |
| | | return false; |
| | |
| | | } |
| | | |
| | | BOOL enable = attribute.toBool(); |
| | | |
| | | if (isWin101903OrGreater()) { |
| | | apis.pSetPreferredAppMode(enable ? PAM_AUTO : PAM_DEFAULT); |
| | | } else { |
| | | apis.pAllowDarkModeForApp(enable); |
| | | } |
| | | |
| | | for (const auto attr : { |
| | | _DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1, |
| | | _DWMWA_USE_IMMERSIVE_DARK_MODE, |
| | |
| | | } |
| | | |
| | | apis.pFlushMenuThemes(); |
| | | |
| | | return true; |
| | | } |
| | | return false; |
| | |
| | | int frameSize = getResizeBorderThickness(hWnd); |
| | | bool isTop = (nativeLocalPos.y < frameSize); |
| | | |
| | | #if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER) |
| | | if (isWin10OrGreater()) { |
| | | if (isSystemBorderEnabled()) { |
| | | // This will handle the left, right and bottom parts of the frame |
| | | // because we didn't change them. |
| | | LRESULT originalHitTestResult = ::DefWindowProcW(hWnd, WM_NCHITTEST, 0, lParam); |
| | |
| | | } |
| | | *result = HTCLIENT; |
| | | return true; |
| | | } else |
| | | #endif |
| | | { |
| | | } else { |
| | | if (full) { |
| | | *result = HTCLIENT; |
| | | return true; |
| | |
| | | break; |
| | | } |
| | | |
| | | if (!isWin10OrGreater()) { |
| | | if (!isSystemBorderEnabled()) { |
| | | switch (message) { |
| | | case WM_NCUAHDRAWCAPTION: |
| | | case WM_NCUAHDRAWFRAME: { |
| | |
| | | // and align it with the upper-left corner of our new client area". |
| | | const auto clientRect = wParam ? &(reinterpret_cast<LPNCCALCSIZE_PARAMS>(lParam))->rgrc[0] |
| | | : reinterpret_cast<LPRECT>(lParam); |
| | | #if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER) |
| | | if (isWin10OrGreater()) { |
| | | if (isSystemBorderEnabled()) { |
| | | // Store the original top margin before the default window procedure applies the |
| | | // default frame. |
| | | const LONG originalTop = clientRect->top; |
| | |
| | | // technique to bring the top border back. |
| | | clientRect->top = originalTop; |
| | | } |
| | | #endif |
| | | |
| | | const bool max = IsMaximized(hWnd); |
| | | const bool full = isFullScreen(hWnd); |
| | | // We don't need this correction when we're fullscreen. We will |
| | |
| | | // a window when it's maximized unless you restore it). |
| | | const quint32 frameSize = getResizeBorderThickness(hWnd); |
| | | clientRect->top += frameSize; |
| | | |
| | | #if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER) |
| | | if (!isWin10OrGreater()) { |
| | | #endif |
| | | if (!isSystemBorderEnabled()) { |
| | | clientRect->bottom -= frameSize; |
| | | clientRect->left += frameSize; |
| | | clientRect->right -= frameSize; |
| | | #if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER) |
| | | } |
| | | #endif |
| | | } |
| | | // Attempt to detect if there's an autohide taskbar, and if |
| | | // there is, reduce our size a bit on the side with the taskbar, |
| | |
| | | const auto getNativeGlobalPosFromKeyboard = [hWnd]() -> POINT { |
| | | const bool maxOrFull = IsMaximized(hWnd) || isFullScreen(hWnd); |
| | | const quint32 frameSize = getResizeBorderThickness(hWnd); |
| | | const quint32 horizontalOffset = ((maxOrFull || !isWin10OrGreater()) ? 0 : frameSize); |
| | | const quint32 horizontalOffset = |
| | | ((maxOrFull || !isSystemBorderEnabled()) ? 0 : frameSize); |
| | | const auto verticalOffset = [hWnd, maxOrFull, frameSize]() -> quint32 { |
| | | const quint32 titleBarHeight = getTitleBarHeight(hWnd); |
| | | if (!isWin10OrGreater()) { |
| | | if (!isSystemBorderEnabled()) { |
| | | return titleBarHeight; |
| | | } |
| | | if (isWin11OrGreater()) { |