-
-
Notifications
You must be signed in to change notification settings - Fork 21.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Windows: Add support for enabling Alt+Space menu and fix borderless maximize #88329
Conversation
Good question. I don't think there's a good place for it. |
Why does this not work in the project manager though? I have no idea how to enable that. |
The project manager doesn't use the settings of any specific project so it defaults to |
I was able to make it work with borderless mode, but it requires modifications to this line (adding godot/platform/windows/display_server_windows.cpp Line 1869 in 907db8e
This might break other stuff. So, should I make these changes? I did some testing with borderless mode 😊:
I've pushed changes (for now) to allow testing. |
The above listed issues must be fixed now. Also fixed an issue with window mode getting stuck. I tested with the following code: func _input(event: InputEvent) -> void:
if event is InputEventKey:
if event.keycode == KEY_C and event.pressed:
print("Mode: ", get_window().mode)
print("Position: ", get_window().position)
print("Size: ", get_window().size)
if event.keycode == KEY_Q and event.pressed:
get_tree().quit()
if event.keycode == KEY_B and event.pressed:
get_window().borderless = !get_window().borderless
if event.keycode == KEY_F and event.pressed:
get_window().mode = Window.MODE_FULLSCREEN
if event.keycode == KEY_E and event.pressed:
get_window().mode = Window.MODE_EXCLUSIVE_FULLSCREEN
if event.keycode == KEY_W and event.pressed:
get_window().mode = Window.MODE_WINDOWED
if event.keycode == KEY_M and event.pressed:
get_window().mode = Window.MODE_MAXIMIZED
if event.keycode == KEY_N and event.pressed:
get_window().mode = Window.MODE_MINIMIZED |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested locally on Windows 11 22H2, it works but I can't use keyboard shortcuts in the editor such as F5 after using Alt + Space then dismissing the popup. I need to unfocus the editor window then focus it again to be able to do that. This occurs regardless of how the popup is dismissed (by pressing Escape or clicking outside the popup).
The behavior regarding where it's enabled is good still. (It's enabled in the editor and project manager and disabled by default in projects.)
@Calinou Thanks for testing this. I'm trying to figure out a fix for this 👍. |
I noticed that SC_KEYMENU is received even when alt alone is pressed and released. This also sends SC_ENTERMENULOOP, and does not even display the menu 🤦♂️ (my bad). The menu loop is exited only after alt is pressed and released again. This is fixed ✅. The issue that @Calinou described should also be fixed ✅. This does change the keyboard events that gdscript will receive:
with menu disabled:
The following code was used: func _input(event: InputEvent) -> void:
if event is InputEventKey:
print("KEY ", "PRESSED: " if event.pressed else "RELEASED: ", event.as_text_keycode()) |
One issue introduced by this PR is with the animations that are played (in bordered mode)
This behavior is a result of fixing an issue where transitioning |
Coincidentally I found this PR while writing about how wacky and nonsensical Godot's borderless fullscreen is on Windows I tried this PR on my MRP for fullscreen modes (you can find it on that comment) and while this PR does technically fix a bug, it also unknowingly removes the only band-aid solution for having a borderless fullscreen mode on Windows without a 1px border. I know fixing that is not in the scope of this PR but by fixing maximized borderless windowed mode, this technically breaks compatibility for a workaround people are using until someone fixes borderless fullscreen. ¯\_(ツ)_/¯ |
I wonder if it's worth to revert borderless-related changes and only keeping the Alt-Space menu in most cases (for now), or just addressing everything all at once. This relatively simple addition is turning into quite the rabbit hole... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exclusive Fullscreen : While the alt+tab menu is displayed the visible region changes size to same as what it was in windowed mode and the rest of the region appears black.
That's how it should be, exclusive fs disables composition and only one window can be displayed, if it's not like this with your change, you broke exclusive fs.
@@ -3473,6 +3480,14 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA | |||
min_max_info->ptMaxTrackSize.x = windows[window_id].max_size.x + decor.x; | |||
min_max_info->ptMaxTrackSize.y = windows[window_id].max_size.y + decor.y; | |||
} | |||
if (windows[window_id].borderless) { | |||
Rect2i screen_rect = screen_get_usable_rect(window_get_current_screen(window_id)); | |||
int border = ((screen_get_size(window_get_current_screen(window_id)) == screen_rect.size) ? 1 : 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's that supposed to do? If you are trying to make window bigger to hide border in non-exclusive fullscreen, it will not work on many GPUs (depends on a driver, some account only for client area) and will break mulitwindow apps like Godot editor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here actually, I am trying to add the border instead in maximized mode (when the taskbar and other panels are hidden), this border is not needed when the taskbar is present already (is it needed? 😅).
The border was previously being added within the if block
at line 1870.
Now it is only added if maximized size == screen size
, to prevent automatically switching to exclusive fs (no border is added, actually the window size is made 1px smaller in all directions😅)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code seems problematic.. right?
Making the window smaller shouldn't be the right way.
should we undo this? we will have to disable maximization support (through the menu) in borderless mode, if we decide to undo this.
Or is there a better solution to allow maximization in borderless mode when the taskbar is hidden?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changing window size is not a good option, that's why WS_BORDER
was applied to maximized window (to keep window size and reduce client area), but I'm not sure if it would work with WS_MAXIMIZE
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would always disable Alt+Space for borderless and full-screen if someone is using borderless window, it's not expected to be maximizable (and if it is, a custom decorations and Alt+Space menu should be implemented).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WS_BORDER
does work with WS_MAXIMIZE
just fine (I tried just now). But the problem then becomes how do we update the style when maximization is done through the menu. Because our _update_window_style
is not called (I think) when maximization happens through the menu.
The common part that runs in both cases (through code and through menu) is here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problematic border has been removed, now we use WS_BORDER
if the maximized window covers the entire screen👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi 😊
if someone is using borderless window, it's not expected to be maximizable
I think it is expected to be borderless maximizable, as on linux, godot does support borderless maximization, and window menu also works with borderless windows.
For fullscreen, the menu has been disabled ✅
I had to make these changes because the maximizing behavior through the menu and through code was different. See: #88329 (comment) .
I've removed the ability to use the window menu in fullscreen and exclusive fs modes. ✅
You are right 😅
I wish we don't have to. 🥲 |
I'm curious about why the workaround by @popcar2 is effective, considering the window size is larger than the screen size. Wouldn't it be expected for some GPUs to switch to exclusive fullscreen mode since there's no border? @bruvzg @popcar2 as a workaround this can be used (for now), I hope it is good enough: var curr_screen := DisplayServer.window_get_current_screen(get_window().get_window_id())
var screen_size := DisplayServer.screen_get_size(curr_screen)
var screen_pos := DisplayServer.screen_get_position(curr_screen)
get_window().mode = Window.MODE_FULLSCREEN
get_window().mode = Window.MODE_WINDOWED
get_window().size = screen_size + Vector2i(2, 2)
get_window().position = screen_pos - Vector2i(1, 1) To check if the window is in fullscreen mode: get_window().size == screen_size + Vector2i(1, 1) and get_window().position == screen_pos - Vector2i(1, 1) Also, you'll need to save the original window size in case it needs to be restored. |
Exclusive fs is triggered by client area size, making it bigger or smaller (by adding border like we do) will prevent it. But if it's bigger it will stick to the other displays, and might cause GPU driver to bug out and fullscreen it on the wrong screen. |
Thanks for clarifying 👍. I noticed, @popcar2 's workaround (this one): get_window().mode = Window.MODE_MAXIMIZED
get_window().borderless = true
get_window().mode = Window.MODE_MAXIMIZED actually switches to (this one): get_window().mode = Window.MODE_MAXIMIZED
get_window().borderless = true
get_window().mode = Window.MODE_MAXIMIZED
get_window().borderless = true makes the window size 2px bigger than the screen size. The mode reported is
Test project (The background color is set to white make the border easily noticeable, and the script is attached with the appropriate keybindings for changing window modes): |
(BUG) Also exists in get_window().mode = Window.MODE_MAXIMIZED
get_window().borderless = true This code sets the window position offscreen, (-7, -7) in my case. I believe it would be beneficial to create a separate issue for this. This should undo the effect: get_window().mode = Window.MODE_WINDOWED
get_window().mode = Window.MODE_MAXIMIZED |
I was about to undo the maximization stuff, but then I figured it out a better solution (I think). |
@@ -4742,7 +4781,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, | |||
DWORD dwExStyle; | |||
DWORD dwStyle; | |||
|
|||
_get_window_style(window_id_counter == MAIN_WINDOW_ID, (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN), p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN, p_flags & WINDOW_FLAG_BORDERLESS_BIT, !(p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT), p_mode == WINDOW_MODE_MAXIMIZED, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) | (p_flags & WINDOW_FLAG_POPUP), dwStyle, dwExStyle); | |||
_get_window_style(window_id_counter == MAIN_WINDOW_ID, (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN), p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN, p_flags & WINDOW_FLAG_BORDERLESS_BIT, !(p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT), p_mode == WINDOW_MODE_MAXIMIZED, false, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) | (p_flags & WINDOW_FLAG_POPUP), dwStyle, dwExStyle); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maximized_fs
is handled inside WM_WINDOWPOSCHANGED
[This is required because maximization could occur through external means (via the menu) which bypasses our state management logic at window_set_mode
👍].
In case needed the following can be used here instead of false
(not needed for now because it is handled at WM_WINDOWPOSCHANGED
):
bool is_maximized_fs = (p_mode == WINDOW_MODE_MAXIMIZED) && (p_flags & WINDOW_FLAG_BORDERLESS_BIT) && (screen_get_size(rq_screen) == screen_get_usable_rect(rq_screen).size) && (screen_get_position(rq_screen) == screen_get_usable_rect(rq_screen).position);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested locally (rebased on top of master
655e93d), it works as expected.
I've tested the following scenarios:
- Window (resizable)
- Window (non-resizable)
- Fullscreen (Alt + Space is ineffective in this mode, as expected)
- Exclusive Fullscreen (Alt + Space is ineffective in this mode, as expected)
Please squash your commits into one, see here |
adf503b
to
c7cea04
Compare
Please remove all the unnecessary text from the commit message, just keep the title |
c7cea04
to
6319d38
Compare
Looks great! |
There seems to be a remaining style issue: https://github.com/godotengine/godot/actions/runs/8580514699/job/23516655245?pr=88329 You can fix it with |
6319d38
to
329d04d
Compare
Thanks! And congrats for your first merged Godot contribution 🎉 |
Thanks everyone!! 🎉🎉 |
Fixes #88277
For now, I have added the option indisplay/window/size/
. Where would be the best place for it?borderlesswindow might get stuck in a given modeborderless maximized
(does not cover taskbar) from modeborderless fullscreen