[Windows] Add WS_BORDER flag to windows in WINDOW_MODE_FULLSCREEN mode to allow multi-window interface in full-screen.

[Windows] Add WINDOW_MODE_EXCLUSIVE_FULLSCREEN without WS_BORDER flag enabled (no multi-window support).
This commit is contained in:
bruvzg 2022-01-28 11:19:53 +02:00
parent 29c4644890
commit f4ea9cd9f3
No known key found for this signature in database
GPG key ID: 7960FCF39844EC38
12 changed files with 49 additions and 13 deletions

View file

@ -900,6 +900,11 @@
Fullscreen window mode. Note that this is not [i]exclusive[/i] fullscreen. On Windows and Linux, a borderless window is used to emulate fullscreen. On macOS, a new desktop is used to display the running project. Fullscreen window mode. Note that this is not [i]exclusive[/i] fullscreen. On Windows and Linux, a borderless window is used to emulate fullscreen. On macOS, a new desktop is used to display the running project.
Regardless of the platform, enabling fullscreen will change the window size to match the monitor's size. Therefore, make sure your project supports [url=$DOCS_URL/tutorials/rendering/multiple_resolutions.html]multiple resolutions[/url] when enabling fullscreen mode. Regardless of the platform, enabling fullscreen will change the window size to match the monitor's size. Therefore, make sure your project supports [url=$DOCS_URL/tutorials/rendering/multiple_resolutions.html]multiple resolutions[/url] when enabling fullscreen mode.
</constant> </constant>
<constant name="WINDOW_MODE_EXCLUSIVE_FULLSCREEN" value="4" enum="WindowMode">
Exclusive fullscreen window mode. This mode is implemented on Windows only. On other platforms, it is equivalent to [constant WINDOW_MODE_FULLSCREEN].
Only one window in exclusive fullscreen mode can be visible on a given screen at a time. If multiple windows are in exclusive fullscreen mode for the same screen, the last one being set to this mode takes precedence.
Regardless of the platform, enabling fullscreen will change the window size to match the monitor's size. Therefore, make sure your project supports [url=$DOCS_URL/tutorials/rendering/multiple_resolutions.html]multiple resolutions[/url] when enabling fullscreen mode.
</constant>
<constant name="WINDOW_FLAG_RESIZE_DISABLED" value="0" enum="WindowFlags"> <constant name="WINDOW_FLAG_RESIZE_DISABLED" value="0" enum="WindowFlags">
</constant> </constant>
<constant name="WINDOW_FLAG_BORDERLESS" value="1" enum="WindowFlags"> <constant name="WINDOW_FLAG_BORDERLESS" value="1" enum="WindowFlags">

View file

@ -398,6 +398,11 @@
Fullscreen window mode. Note that this is not [i]exclusive[/i] fullscreen. On Windows and Linux, a borderless window is used to emulate fullscreen. On macOS, a new desktop is used to display the running project. Fullscreen window mode. Note that this is not [i]exclusive[/i] fullscreen. On Windows and Linux, a borderless window is used to emulate fullscreen. On macOS, a new desktop is used to display the running project.
Regardless of the platform, enabling fullscreen will change the window size to match the monitor's size. Therefore, make sure your project supports [url=$DOCS_URL/tutorials/rendering/multiple_resolutions.html]multiple resolutions[/url] when enabling fullscreen mode. Regardless of the platform, enabling fullscreen will change the window size to match the monitor's size. Therefore, make sure your project supports [url=$DOCS_URL/tutorials/rendering/multiple_resolutions.html]multiple resolutions[/url] when enabling fullscreen mode.
</constant> </constant>
<constant name="MODE_EXCLUSIVE_FULLSCREEN" value="4" enum="Mode">
Exclusive fullscreen window mode. This mode is implemented on Windows only. On other platforms, it is equivalent to [constant MODE_FULLSCREEN].
Only one window in exclusive fullscreen mode can be visible on a given screen at a time. If multiple windows are in exclusive fullscreen mode for the same screen, the last one being set to this mode takes precedence.
Regardless of the platform, enabling fullscreen will change the window size to match the monitor's size. Therefore, make sure your project supports [url=$DOCS_URL/tutorials/rendering/multiple_resolutions.html]multiple resolutions[/url] when enabling fullscreen mode.
</constant>
<constant name="FLAG_RESIZE_DISABLED" value="0" enum="Flags"> <constant name="FLAG_RESIZE_DISABLED" value="0" enum="Flags">
The window's ability to be resized. The window's ability to be resized.
</constant> </constant>

View file

@ -663,7 +663,7 @@ DisplayServerJavaScript::DisplayServerJavaScript(const String &p_rendering_drive
godot_js_config_canvas_id_get(canvas_id, 256); godot_js_config_canvas_id_get(canvas_id, 256);
// Handle contextmenu, webglcontextlost // Handle contextmenu, webglcontextlost
godot_js_display_setup_canvas(p_resolution.x, p_resolution.y, p_window_mode == WINDOW_MODE_FULLSCREEN, OS::get_singleton()->is_hidpi_allowed() ? 1 : 0); godot_js_display_setup_canvas(p_resolution.x, p_resolution.y, (p_window_mode == WINDOW_MODE_FULLSCREEN || p_window_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN), OS::get_singleton()->is_hidpi_allowed() ? 1 : 0);
// Check if it's windows. // Check if it's windows.
swap_cancel_ok = godot_js_display_is_swap_ok_cancel() == 1; swap_cancel_ok = godot_js_display_is_swap_ok_cancel() == 1;
@ -897,6 +897,7 @@ void DisplayServerJavaScript::window_set_mode(WindowMode p_mode, WindowID p_wind
} }
window_mode = WINDOW_MODE_WINDOWED; window_mode = WINDOW_MODE_WINDOWED;
} break; } break;
case WINDOW_MODE_EXCLUSIVE_FULLSCREEN:
case WINDOW_MODE_FULLSCREEN: { case WINDOW_MODE_FULLSCREEN: {
int result = godot_js_display_fullscreen_request(); int result = godot_js_display_fullscreen_request();
ERR_FAIL_COND_MSG(result, "The request was denied. Remember that enabling fullscreen is only possible from an input callback for the HTML5 platform."); ERR_FAIL_COND_MSG(result, "The request was denied. Remember that enabling fullscreen is only possible from an input callback for the HTML5 platform.");

View file

@ -1825,6 +1825,7 @@ void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) {
XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
} break; } break;
case WINDOW_MODE_EXCLUSIVE_FULLSCREEN:
case WINDOW_MODE_FULLSCREEN: { case WINDOW_MODE_FULLSCREEN: {
//Remove full-screen //Remove full-screen
wd.fullscreen = false; wd.fullscreen = false;
@ -1877,6 +1878,7 @@ void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) {
XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
} break; } break;
case WINDOW_MODE_EXCLUSIVE_FULLSCREEN:
case WINDOW_MODE_FULLSCREEN: { case WINDOW_MODE_FULLSCREEN: {
wd.last_position_before_fs = wd.position; wd.last_position_before_fs = wd.position;

View file

@ -2652,6 +2652,7 @@ void DisplayServerOSX::window_set_mode(WindowMode p_mode, WindowID p_window) {
case WINDOW_MODE_MINIMIZED: { case WINDOW_MODE_MINIMIZED: {
[wd.window_object deminiaturize:nil]; [wd.window_object deminiaturize:nil];
} break; } break;
case WINDOW_MODE_EXCLUSIVE_FULLSCREEN:
case WINDOW_MODE_FULLSCREEN: { case WINDOW_MODE_FULLSCREEN: {
[wd.window_object setLevel:NSNormalWindowLevel]; [wd.window_object setLevel:NSNormalWindowLevel];
if (wd.layered_window) { if (wd.layered_window) {
@ -2685,6 +2686,7 @@ void DisplayServerOSX::window_set_mode(WindowMode p_mode, WindowID p_window) {
case WINDOW_MODE_MINIMIZED: { case WINDOW_MODE_MINIMIZED: {
[wd.window_object performMiniaturize:nil]; [wd.window_object performMiniaturize:nil];
} break; } break;
case WINDOW_MODE_EXCLUSIVE_FULLSCREEN:
case WINDOW_MODE_FULLSCREEN: { case WINDOW_MODE_FULLSCREEN: {
if (wd.layered_window) if (wd.layered_window)
_set_window_per_pixel_transparency_enabled(false, p_window); _set_window_per_pixel_transparency_enabled(false, p_window);

View file

@ -506,7 +506,7 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod
if (p_flags & WINDOW_FLAG_BORDERLESS_BIT) { if (p_flags & WINDOW_FLAG_BORDERLESS_BIT) {
wd.borderless = true; wd.borderless = true;
} }
if (p_flags & WINDOW_FLAG_ALWAYS_ON_TOP_BIT && p_mode != WINDOW_MODE_FULLSCREEN) { if (p_flags & WINDOW_FLAG_ALWAYS_ON_TOP_BIT && p_mode != WINDOW_MODE_FULLSCREEN && p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
wd.always_on_top = true; wd.always_on_top = true;
} }
if (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) { if (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) {
@ -946,7 +946,7 @@ Size2i DisplayServerWindows::window_get_real_size(WindowID p_window) const {
return Size2(); return Size2();
} }
void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscreen, bool p_borderless, bool p_resizable, bool p_maximized, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex) { void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscreen, bool p_multiwindow_fs, bool p_borderless, bool p_resizable, bool p_maximized, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex) {
// Windows docs for window styles: // Windows docs for window styles:
// https://docs.microsoft.com/en-us/windows/win32/winmsg/window-styles // https://docs.microsoft.com/en-us/windows/win32/winmsg/window-styles
// https://docs.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles // https://docs.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles
@ -959,6 +959,9 @@ void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscre
if (p_fullscreen || p_borderless) { if (p_fullscreen || p_borderless) {
r_style |= WS_POPUP; // p_borderless was WS_EX_TOOLWINDOW in the past. r_style |= WS_POPUP; // p_borderless was WS_EX_TOOLWINDOW in the past.
if (p_fullscreen && p_multiwindow_fs) {
r_style |= WS_BORDER; // Allows child windows to be displayed on top of full screen.
}
} else { } else {
if (p_resizable) { if (p_resizable) {
if (p_maximized) { if (p_maximized) {
@ -989,7 +992,7 @@ void DisplayServerWindows::_update_window_style(WindowID p_window, bool p_repain
DWORD style = 0; DWORD style = 0;
DWORD style_ex = 0; DWORD style_ex = 0;
_get_window_style(p_window == MAIN_WINDOW_ID, wd.fullscreen, wd.borderless, wd.resizable, wd.maximized, wd.no_focus, style, style_ex); _get_window_style(p_window == MAIN_WINDOW_ID, wd.fullscreen, wd.multiwindow_fs, wd.borderless, wd.resizable, wd.maximized, wd.no_focus, style, style_ex);
SetWindowLongPtr(wd.hWnd, GWL_STYLE, style); SetWindowLongPtr(wd.hWnd, GWL_STYLE, style);
SetWindowLongPtr(wd.hWnd, GWL_EXSTYLE, style_ex); SetWindowLongPtr(wd.hWnd, GWL_EXSTYLE, style_ex);
@ -1009,10 +1012,11 @@ void DisplayServerWindows::window_set_mode(WindowMode p_mode, WindowID p_window)
ERR_FAIL_COND(!windows.has(p_window)); ERR_FAIL_COND(!windows.has(p_window));
WindowData &wd = windows[p_window]; WindowData &wd = windows[p_window];
if (wd.fullscreen && p_mode != WINDOW_MODE_FULLSCREEN) { if (wd.fullscreen && p_mode != WINDOW_MODE_FULLSCREEN && p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
RECT rect; RECT rect;
wd.fullscreen = false; wd.fullscreen = false;
wd.multiwindow_fs = false;
wd.maximized = wd.was_maximized; wd.maximized = wd.was_maximized;
if (wd.pre_fs_valid) { if (wd.pre_fs_valid) {
@ -1051,7 +1055,15 @@ void DisplayServerWindows::window_set_mode(WindowMode p_mode, WindowID p_window)
wd.minimized = true; wd.minimized = true;
} }
if (p_mode == WINDOW_MODE_FULLSCREEN && !wd.fullscreen) { if (p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
wd.multiwindow_fs = false;
_update_window_style(false);
} else {
wd.multiwindow_fs = true;
_update_window_style(false);
}
if ((p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) && !wd.fullscreen) {
if (wd.minimized) { if (wd.minimized) {
ShowWindow(wd.hWnd, SW_RESTORE); ShowWindow(wd.hWnd, SW_RESTORE);
} }
@ -1098,7 +1110,11 @@ DisplayServer::WindowMode DisplayServerWindows::window_get_mode(WindowID p_windo
const WindowData &wd = windows[p_window]; const WindowData &wd = windows[p_window];
if (wd.fullscreen) { if (wd.fullscreen) {
return WINDOW_MODE_FULLSCREEN; if (wd.multiwindow_fs) {
return WINDOW_MODE_FULLSCREEN;
} else {
return WINDOW_MODE_EXCLUSIVE_FULLSCREEN;
}
} else if (wd.minimized) { } else if (wd.minimized) {
return WINDOW_MODE_MINIMIZED; return WINDOW_MODE_MINIMIZED;
} else if (wd.maximized) { } else if (wd.maximized) {
@ -3088,7 +3104,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
DWORD dwExStyle; DWORD dwExStyle;
DWORD dwStyle; DWORD dwStyle;
_get_window_style(window_id_counter == MAIN_WINDOW_ID, p_mode == WINDOW_MODE_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), 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, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT), dwStyle, dwExStyle);
RECT WindowRect; RECT WindowRect;
@ -3097,7 +3113,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
WindowRect.top = p_rect.position.y; 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;
if (p_mode == WINDOW_MODE_FULLSCREEN) { if (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
int nearest_area = 0; int nearest_area = 0;
Rect2i screen_rect; Rect2i screen_rect;
for (int i = 0; i < get_screen_count(); i++) { for (int i = 0; i < get_screen_count(); i++) {
@ -3140,7 +3156,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
windows.erase(id); windows.erase(id);
return INVALID_WINDOW_ID; return INVALID_WINDOW_ID;
} }
if (p_mode != WINDOW_MODE_FULLSCREEN) { if (p_mode != WINDOW_MODE_FULLSCREEN && p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
wd.pre_fs_valid = true; wd.pre_fs_valid = true;
} }

View file

@ -332,6 +332,7 @@ class DisplayServerWindows : public DisplayServer {
bool maximized = false; bool maximized = false;
bool minimized = false; bool minimized = false;
bool fullscreen = false; bool fullscreen = false;
bool multiwindow_fs = false;
bool borderless = false; bool borderless = false;
bool resizable = true; bool resizable = true;
bool window_focused = false; bool window_focused = false;
@ -401,7 +402,7 @@ class DisplayServerWindows : public DisplayServer {
WNDPROC user_proc = nullptr; WNDPROC user_proc = nullptr;
void _send_window_event(const WindowData &wd, WindowEvent p_event); void _send_window_event(const WindowData &wd, WindowEvent p_event);
void _get_window_style(bool p_main_window, bool p_fullscreen, bool p_borderless, bool p_resizable, bool p_maximized, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex); void _get_window_style(bool p_main_window, bool p_fullscreen, bool p_multiwindow_fs, bool p_borderless, bool p_resizable, bool p_maximized, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex);
MouseMode mouse_mode; MouseMode mouse_mode;
int restore_mouse_trails = 0; int restore_mouse_trails = 0;

View file

@ -1231,7 +1231,7 @@ void Viewport::_gui_show_tooltip() {
base_tooltip->set_anchors_and_offsets_preset(Control::PRESET_WIDE); base_tooltip->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
panel->set_transient(false); panel->set_transient(true);
panel->set_flag(Window::FLAG_NO_FOCUS, true); panel->set_flag(Window::FLAG_NO_FOCUS, true);
panel->set_wrap_controls(true); panel->set_wrap_controls(true);
panel->add_child(base_tooltip); panel->add_child(base_tooltip);

View file

@ -1614,6 +1614,7 @@ void Window::_bind_methods() {
BIND_ENUM_CONSTANT(MODE_MINIMIZED); BIND_ENUM_CONSTANT(MODE_MINIMIZED);
BIND_ENUM_CONSTANT(MODE_MAXIMIZED); BIND_ENUM_CONSTANT(MODE_MAXIMIZED);
BIND_ENUM_CONSTANT(MODE_FULLSCREEN); BIND_ENUM_CONSTANT(MODE_FULLSCREEN);
BIND_ENUM_CONSTANT(MODE_EXCLUSIVE_FULLSCREEN);
BIND_ENUM_CONSTANT(FLAG_RESIZE_DISABLED); BIND_ENUM_CONSTANT(FLAG_RESIZE_DISABLED);
BIND_ENUM_CONSTANT(FLAG_BORDERLESS); BIND_ENUM_CONSTANT(FLAG_BORDERLESS);

View file

@ -46,6 +46,7 @@ public:
MODE_MINIMIZED = DisplayServer::WINDOW_MODE_MINIMIZED, MODE_MINIMIZED = DisplayServer::WINDOW_MODE_MINIMIZED,
MODE_MAXIMIZED = DisplayServer::WINDOW_MODE_MAXIMIZED, MODE_MAXIMIZED = DisplayServer::WINDOW_MODE_MAXIMIZED,
MODE_FULLSCREEN = DisplayServer::WINDOW_MODE_FULLSCREEN, MODE_FULLSCREEN = DisplayServer::WINDOW_MODE_FULLSCREEN,
MODE_EXCLUSIVE_FULLSCREEN = DisplayServer::WINDOW_MODE_EXCLUSIVE_FULLSCREEN,
}; };
enum Flags { enum Flags {

View file

@ -539,6 +539,7 @@ void DisplayServer::_bind_methods() {
BIND_ENUM_CONSTANT(WINDOW_MODE_MINIMIZED); BIND_ENUM_CONSTANT(WINDOW_MODE_MINIMIZED);
BIND_ENUM_CONSTANT(WINDOW_MODE_MAXIMIZED); BIND_ENUM_CONSTANT(WINDOW_MODE_MAXIMIZED);
BIND_ENUM_CONSTANT(WINDOW_MODE_FULLSCREEN); BIND_ENUM_CONSTANT(WINDOW_MODE_FULLSCREEN);
BIND_ENUM_CONSTANT(WINDOW_MODE_EXCLUSIVE_FULLSCREEN);
BIND_ENUM_CONSTANT(WINDOW_FLAG_RESIZE_DISABLED); BIND_ENUM_CONSTANT(WINDOW_FLAG_RESIZE_DISABLED);
BIND_ENUM_CONSTANT(WINDOW_FLAG_BORDERLESS); BIND_ENUM_CONSTANT(WINDOW_FLAG_BORDERLESS);

View file

@ -53,7 +53,8 @@ public:
WINDOW_MODE_WINDOWED, WINDOW_MODE_WINDOWED,
WINDOW_MODE_MINIMIZED, WINDOW_MODE_MINIMIZED,
WINDOW_MODE_MAXIMIZED, WINDOW_MODE_MAXIMIZED,
WINDOW_MODE_FULLSCREEN WINDOW_MODE_FULLSCREEN,
WINDOW_MODE_EXCLUSIVE_FULLSCREEN,
}; };
// Keep the VSyncMode enum values in sync with the `display/window/vsync/vsync_mode` // Keep the VSyncMode enum values in sync with the `display/window/vsync/vsync_mode`