From 9ebe07e28062ce08cfa083ee4029d34408a4a863 Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Wed, 10 Sep 2025 09:43:02 +0300 Subject: [PATCH] [Windows] Expand full screen border in the direction with no adjacent display, or display with min refresh rate difference. --- platform/windows/display_server_windows.cpp | 113 ++++++++++++++------ platform/windows/display_server_windows.h | 2 + 2 files changed, 80 insertions(+), 35 deletions(-) diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 8653ee43123..6b048790472 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -97,8 +97,6 @@ #define WM_INDICATOR_CALLBACK_MESSAGE (WM_USER + 1) -int constexpr FS_TRANSP_BORDER = 2; - static String format_error_message(DWORD id) { LPWSTR messageBuffer = nullptr; size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, @@ -170,6 +168,49 @@ String DisplayServerWindows::get_name() const { return "Windows"; } +Vector2i _logical_to_physical(const Vector2i &p_point) { + POINT p1; + p1.x = p_point.x; + p1.y = p_point.y; + LogicalToPhysicalPointForPerMonitorDPI(nullptr, &p1); + return Vector2i(p1.x, p1.y); +} + +Vector2i DisplayServerWindows::_get_screen_expand_offset(int p_screen) const { + Vector2i p1 = _logical_to_physical(screen_get_position(p_screen)); + Vector2i p2 = _logical_to_physical(screen_get_position(p_screen) + screen_get_size(p_screen)); + + int screen_down = -1; + int screen_right = -1; + for (int i = 0; i < get_screen_count(); i++) { + if (i == p_screen) { + continue; + } + Vector2i sp1 = _logical_to_physical(screen_get_position(i)); + Vector2i sp2 = _logical_to_physical(screen_get_position(i) + screen_get_size(i)); + if (sp1.y >= p2.y - 5 && sp1.y <= p2.y + 5 && sp1.x <= p2.x && p1.x <= sp2.x) { + screen_down = i; + } + if (sp1.x >= p2.x - 5 && sp1.x <= p2.x + 5 && sp1.y <= p2.y && p1.y <= sp2.y) { + screen_right = i; + } + } + + if (screen_down == -1) { + return Vector2i(0, 2); + } else if (screen_right == -1) { + return Vector2i(2, 0); + } else { + int diff_d = screen_get_refresh_rate(p_screen) - screen_get_refresh_rate(screen_down); + int diff_r = screen_get_refresh_rate(p_screen) - screen_get_refresh_rate(screen_right); + if (diff_d < diff_r) { + return Vector2i(0, 2); + } else { + return Vector2i(2, 0); + } + } +} + void DisplayServerWindows::_set_mouse_mode_impl(MouseMode p_mode) { if (p_mode == MOUSE_MODE_HIDDEN || p_mode == MOUSE_MODE_CAPTURED || p_mode == MOUSE_MODE_CONFINED_HIDDEN) { // Hide cursor before moving. @@ -189,11 +230,12 @@ void DisplayServerWindows::_set_mouse_mode_impl(MouseMode p_mode) { WindowData &wd = windows[window_id]; - int off_x = (wd.multiwindow_fs || (!wd.fullscreen && wd.borderless && wd.maximized)) ? FS_TRANSP_BORDER : 0; + Vector2i off = (wd.multiwindow_fs || (!wd.fullscreen && wd.borderless && wd.maximized)) ? _get_screen_expand_offset(window_get_current_screen(window_id)) : Vector2i(); RECT clipRect; GetClientRect(wd.hWnd, &clipRect); - clipRect.right -= off_x; + clipRect.right -= off.x; + clipRect.bottom -= off.y; ClientToScreen(wd.hWnd, (POINT *)&clipRect.left); ClientToScreen(wd.hWnd, (POINT *)&clipRect.right); ClipCursor(&clipRect); @@ -2030,16 +2072,16 @@ void DisplayServerWindows::window_set_current_screen(int p_screen, WindowID p_wi if (wd.fullscreen) { Point2 pos = screen_get_position(p_screen) + _get_screens_origin(); Size2 size = screen_get_size(p_screen); - int off_x = (wd.multiwindow_fs || (!wd.fullscreen && wd.borderless && wd.maximized)) ? FS_TRANSP_BORDER : 0; + Vector2i off = (wd.multiwindow_fs || (!wd.fullscreen && wd.borderless && wd.maximized)) ? _get_screen_expand_offset(p_screen) : Vector2i(); - MoveWindow(wd.hWnd, pos.x, pos.y, size.width + off_x, size.height, TRUE); + MoveWindow(wd.hWnd, pos.x, pos.y, size.width + off.x, size.height + off.y, TRUE); } else if (wd.maximized) { Point2 pos = screen_get_position(p_screen) + _get_screens_origin(); Size2 size = screen_get_size(p_screen); - int off_x = (wd.multiwindow_fs || (!wd.fullscreen && wd.borderless && wd.maximized)) ? FS_TRANSP_BORDER : 0; + Vector2i off = (wd.multiwindow_fs || (!wd.fullscreen && wd.borderless && wd.maximized)) ? _get_screen_expand_offset(p_screen) : Vector2i(); ShowWindow(wd.hWnd, SW_RESTORE); - MoveWindow(wd.hWnd, pos.x, pos.y, size.width + off_x, size.height, TRUE); + MoveWindow(wd.hWnd, pos.x, pos.y, size.width + off.x, size.height + off.y, TRUE); ShowWindow(wd.hWnd, SW_MAXIMIZE); } else { Rect2i srect = screen_get_usable_rect(p_screen); @@ -2288,8 +2330,8 @@ Size2i DisplayServerWindows::window_get_size(WindowID p_window) const { RECT r; if (GetClientRect(wd.hWnd, &r)) { // Retrieves area inside of window border, including decoration. - int off_x = (wd.multiwindow_fs || (!wd.fullscreen && wd.borderless && wd.maximized)) ? FS_TRANSP_BORDER : 0; - return Size2(r.right - r.left - off_x, r.bottom - r.top); + Vector2i off = (wd.multiwindow_fs || (!wd.fullscreen && wd.borderless && wd.maximized)) ? _get_screen_expand_offset(window_get_current_screen(p_window)) : Vector2i(); + return Size2(r.right - r.left - off.x, r.bottom - r.top - off.y); } return Size2(); } @@ -2307,8 +2349,8 @@ Size2i DisplayServerWindows::window_get_size_with_decorations(WindowID p_window) RECT r; if (GetWindowRect(wd.hWnd, &r)) { // Retrieves area inside of window border, including decoration. - int off_x = (wd.multiwindow_fs || (!wd.fullscreen && wd.borderless && wd.maximized)) ? FS_TRANSP_BORDER : 0; - return Size2(r.right - r.left - off_x, r.bottom - r.top); + Vector2i off = (wd.multiwindow_fs || (!wd.fullscreen && wd.borderless && wd.maximized)) ? _get_screen_expand_offset(window_get_current_screen(p_window)) : Vector2i(); + return Size2(r.right - r.left - off.x, r.bottom - r.top - off.y); } return Size2(); } @@ -2418,8 +2460,8 @@ void DisplayServerWindows::_update_window_style(WindowID p_window, bool p_repain if (p_repaint) { RECT rect; GetWindowRect(wd.hWnd, &rect); - int off_x = (wd.multiwindow_fs || (!wd.fullscreen && wd.borderless && wd.maximized)) ? FS_TRANSP_BORDER : 0; - MoveWindow(wd.hWnd, rect.left, rect.top, rect.right - rect.left + off_x, rect.bottom - rect.top, TRUE); + Vector2i off = (wd.multiwindow_fs || (!wd.fullscreen && wd.borderless && wd.maximized)) ? _get_screen_expand_offset(window_get_current_screen(p_window)) : Vector2i(); + MoveWindow(wd.hWnd, rect.left, rect.top, rect.right - rect.left + off.x, rect.bottom - rect.top - off.y, TRUE); } } @@ -2558,8 +2600,8 @@ void DisplayServerWindows::window_set_mode(WindowMode p_mode, WindowID p_window) _update_window_style(p_window, false); - int off_x = (wd.multiwindow_fs || (!wd.fullscreen && wd.borderless && wd.maximized)) ? FS_TRANSP_BORDER : 0; - MoveWindow(wd.hWnd, pos.x, pos.y, size.width + off_x, size.height, TRUE); + Vector2i off = (wd.multiwindow_fs || (!wd.fullscreen && wd.borderless && wd.maximized)) ? _get_screen_expand_offset(cs) : Vector2i(); + MoveWindow(wd.hWnd, pos.x, pos.y, size.width + off.x, size.height + off.y, TRUE); // If the user has mouse trails enabled in windows, then sometimes the cursor disappears in fullscreen mode. // Save number of trails so we can restore when exiting, then turn off mouse trails @@ -5750,7 +5792,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA case WM_WINDOWPOSCHANGED: { WindowData &window = windows[window_id]; - int off_x = (window.multiwindow_fs || (!window.fullscreen && window.borderless && IsZoomed(hWnd))) ? FS_TRANSP_BORDER : 0; + Vector2i off = (window.multiwindow_fs || (!window.fullscreen && window.borderless && window.maximized)) ? _get_screen_expand_offset(window_get_current_screen(window_id)) : Vector2i(); Rect2i window_client_rect; Rect2i window_rect; { @@ -5758,12 +5800,12 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA GetClientRect(hWnd, &rect); ClientToScreen(hWnd, (POINT *)&rect.left); ClientToScreen(hWnd, (POINT *)&rect.right); - window_client_rect = Rect2i(rect.left, rect.top, rect.right - rect.left - off_x, rect.bottom - rect.top); + window_client_rect = Rect2i(rect.left, rect.top, rect.right - rect.left - off.x, rect.bottom - rect.top - off.y); window_client_rect.position -= _get_screens_origin(); RECT wrect; GetWindowRect(hWnd, &wrect); - window_rect = Rect2i(wrect.left, wrect.top, wrect.right - wrect.left - off_x, wrect.bottom - wrect.top); + window_rect = Rect2i(wrect.left, wrect.top, wrect.right - wrect.left - off.x, wrect.bottom - wrect.top - off.y); window_rect.position -= _get_screens_origin(); } @@ -5819,15 +5861,15 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA #if defined(RD_ENABLED) if (window.create_completed && rendering_context && window.rendering_context_window_created) { // Note: Trigger resize event to update swapchains when window is minimized/restored, even if size is not changed. - rendering_context->window_set_size(window_id, window.width + off_x, window.height); + rendering_context->window_set_size(window_id, window.width + off.x, window.height + off.y); } #endif #if defined(GLES3_ENABLED) if (window.create_completed && gl_manager_native && window.gl_native_window_created) { - gl_manager_native->window_resize(window_id, window.width + off_x, window.height); + gl_manager_native->window_resize(window_id, window.width + off.x, window.height + off.y); } if (window.create_completed && gl_manager_angle && window.gl_angle_window_created) { - gl_manager_angle->window_resize(window_id, window.width + off_x, window.height); + gl_manager_angle->window_resize(window_id, window.width + off.x, window.height + off.y); } #endif } @@ -5846,7 +5888,8 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN) { RECT crect; GetClientRect(window.hWnd, &crect); - crect.right -= off_x; + crect.right -= off.x; + crect.bottom -= off.y; ClientToScreen(window.hWnd, (POINT *)&crect.left); ClientToScreen(window.hWnd, (POINT *)&crect.right); ClipCursor(&crect); @@ -6343,21 +6386,21 @@ Error DisplayServerWindows::_create_window(WindowID p_window_id, WindowMode p_mo RECT WindowRect; - int off_x = (p_mode == WINDOW_MODE_FULLSCREEN || ((p_flags & WINDOW_FLAG_BORDERLESS_BIT) && p_mode == WINDOW_MODE_MAXIMIZED)) ? FS_TRANSP_BORDER : 0; + Vector2i off = (p_mode == WINDOW_MODE_FULLSCREEN || ((p_flags & WINDOW_FLAG_BORDERLESS_BIT) && p_mode == WINDOW_MODE_MAXIMIZED)) ? _get_screen_expand_offset(rq_screen) : Vector2i(); WindowRect.left = p_rect.position.x; - WindowRect.right = p_rect.position.x + p_rect.size.x + off_x; + WindowRect.right = p_rect.position.x + p_rect.size.x + off.x; WindowRect.top = p_rect.position.y; - WindowRect.bottom = p_rect.position.y + p_rect.size.y; + WindowRect.bottom = p_rect.position.y + p_rect.size.y + off.y; if (!p_parent_hwnd) { if (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) { Rect2i screen_rect = Rect2i(screen_get_position(rq_screen), screen_get_size(rq_screen)); WindowRect.left = screen_rect.position.x; - WindowRect.right = screen_rect.position.x + screen_rect.size.x + off_x; + WindowRect.right = screen_rect.position.x + screen_rect.size.x + off.x; WindowRect.top = screen_rect.position.y; - WindowRect.bottom = screen_rect.position.y + screen_rect.size.y; + WindowRect.bottom = screen_rect.position.y + screen_rect.size.y + off.y; } else { Rect2i srect = screen_get_usable_rect(rq_screen); Point2i wpos = p_rect.position; @@ -6366,9 +6409,9 @@ Error DisplayServerWindows::_create_window(WindowID p_window_id, WindowMode p_mo } WindowRect.left = wpos.x; - WindowRect.right = wpos.x + p_rect.size.x + off_x; + WindowRect.right = wpos.x + p_rect.size.x + off.x; WindowRect.top = wpos.y; - WindowRect.bottom = wpos.y + p_rect.size.y; + WindowRect.bottom = wpos.y + p_rect.size.y + off.y; } } @@ -6558,8 +6601,8 @@ Error DisplayServerWindows::_create_window(WindowID p_window_id, WindowMode p_mo ClientToScreen(wd.hWnd, (POINT *)&r.left); ClientToScreen(wd.hWnd, (POINT *)&r.right); wd.last_pos = Point2i(r.left, r.top) - _get_screens_origin(); - wd.width = r.right - r.left - off_x; - wd.height = r.bottom - r.top; + wd.width = r.right - r.left - off.x; + wd.height = r.bottom - r.top - off.y; } else { wd.last_pos = p_rect.position; wd.width = p_rect.size.width; @@ -6571,7 +6614,7 @@ Error DisplayServerWindows::_create_window(WindowID p_window_id, WindowMode p_mo wd.create_completed = true; // Set size of maximized borderless window (by default it covers the entire screen). if (!p_parent_hwnd && p_mode == WINDOW_MODE_MAXIMIZED && (p_flags & WINDOW_FLAG_BORDERLESS_BIT)) { - SetWindowPos(wd.hWnd, HWND_TOP, usable_rect.position.x - off_x, usable_rect.position.y, usable_rect.size.width + off_x, usable_rect.size.height, SWP_NOZORDER | SWP_NOACTIVATE); + SetWindowPos(wd.hWnd, HWND_TOP, usable_rect.position.x - off.x, usable_rect.position.y - off.y, usable_rect.size.width + off.x, usable_rect.size.height + off.y, SWP_NOZORDER | SWP_NOACTIVATE); } _update_window_mouse_passthrough(id); } @@ -6634,8 +6677,8 @@ Error DisplayServerWindows::_create_rendering_context_window(WindowID p_window_i Error err = rendering_context->window_create(p_window_id, &wpd); ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Failed to create %s window.", p_rendering_driver)); - int off_x = (wd.multiwindow_fs || (!wd.fullscreen && wd.borderless && wd.maximized)) ? FS_TRANSP_BORDER : 0; - rendering_context->window_set_size(p_window_id, wd.width + off_x, wd.height); + Vector2i off = (wd.multiwindow_fs || (!wd.fullscreen && wd.borderless && wd.maximized)) ? _get_screen_expand_offset(window_get_current_screen(p_window_id)) : Vector2i(); + rendering_context->window_set_size(p_window_id, wd.width + off.x, wd.height + off.y); wd.rendering_context_window_created = true; return OK; diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 201a834cadb..ea7fc02dfa4 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -506,6 +506,8 @@ class DisplayServerWindows : public DisplayServer { LRESULT _handle_early_window_message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); Point2i _get_screens_origin() const; + Vector2i _get_screen_expand_offset(int p_screen) const; + enum class WinKeyModifierMask { ALT_GR = (1 << 1), SHIFT = (1 << 2),