Browse Source

[Linux/X11] Split fullscreen mode into `WINDOW_MODE_EXCLUSIVE_FULLSCREEN` and `WINDOW_MODE_FULLSCREEN` to improve multi-window handling.

bruvzg 2 years ago
parent
commit
ad0f6ff85b

+ 9 - 6
doc/classes/DisplayServer.xml

@@ -1634,14 +1634,17 @@
 			Maximized window mode, i.e. [Window] will occupy whole screen area except task bar and still display its borders. Normally happens when the minimize button is pressed.
 		</constant>
 		<constant name="WINDOW_MODE_FULLSCREEN" value="3" enum="WindowMode">
-			Full screen window mode. Note that this is not [i]exclusive[/i] full screen. On Windows and Linux (X11), a borderless window is used to emulate full screen. On macOS, a new desktop is used to display the running project.
-			Regardless of the platform, enabling full screen 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 full screen mode.
+			Full screen mode with full multi-window support.
+			Full screen window cover the entire display area of a screen, have no border or decorations. Display video mode is not changed.
+			[b]Note:[/b] Regardless of the platform, enabling full screen 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 full screen mode.
 		</constant>
 		<constant name="WINDOW_MODE_EXCLUSIVE_FULLSCREEN" value="4" enum="WindowMode">
-			Exclusive full screen window mode. This mode is implemented on Windows and macOS only. On other platforms, it is equivalent to [constant WINDOW_MODE_FULLSCREEN].
-			[b]On Windows:[/b] Only one window in exclusive full screen mode can be visible on a given screen at a time. If multiple windows are in exclusive full screen mode for the same screen, the last one being set to this mode takes precedence.
-			[b]On macOS:[/b] Exclusive full-screen mode prevents Dock and Menu from showing up when the mouse pointer is hovering the edge of the screen.
-			Regardless of the platform, enabling full screen 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 full screen mode.
+			A single window full screen mode. This mode has less overhead, but only one window can be open on a given screen at a time (opening a child window or application switching will trigger a full screen transition).
+			Full screen window cover the entire display area of a screen, have no border or decorations. Display video mode is not changed.
+			[b]On Windows:[/b] Depending on video driver, full screen transition might cause screens to go black for a moment.
+			[b]On macOS:[/b] Exclusive full screen mode prevents Dock and Menu from showing up when the mouse pointer is hovering the edge of the screen.
+			[b]On Linux (X11):[/b] Exclusive full screen mode bypasses compositor.
+			[b]Note:[/b] Regardless of the platform, enabling full screen 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 full screen mode.
 		</constant>
 		<constant name="WINDOW_FLAG_RESIZE_DISABLED" value="0" enum="WindowFlags">
 			The window can't be resizing by dragging its resize grip. It's still possible to resize the window using [method window_set_size]. This flag is ignored for full screen windows.

+ 25 - 7
platform/linuxbsd/x11/display_server_x11.cpp

@@ -1582,7 +1582,7 @@ void DisplayServerX11::_update_size_hints(WindowID p_window) {
 	xsh->width = wd.size.width;
 	xsh->height = wd.size.height;
 
-	if (window_mode == WINDOW_MODE_FULLSCREEN) {
+	if (window_mode == WINDOW_MODE_FULLSCREEN || window_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
 		// Do not set any other hints to prevent the window manager from ignoring the fullscreen flags
 	} else if (window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) {
 		// If resizing is disabled, use the forced size
@@ -1949,7 +1949,7 @@ void DisplayServerX11::_validate_mode_on_map(WindowID p_window) {
 	// Check if we applied any window modes that didn't take effect while unmapped
 	const WindowData &wd = windows[p_window];
 	if (wd.fullscreen && !_window_fullscreen_check(p_window)) {
-		_set_wm_fullscreen(p_window, true);
+		_set_wm_fullscreen(p_window, true, wd.exclusive_fullscreen);
 	} else if (wd.maximized && !_window_maximize_check(p_window, "_NET_WM_STATE")) {
 		_set_wm_maximized(p_window, true);
 	} else if (wd.minimized && !_window_minimize_check(p_window)) {
@@ -2024,7 +2024,7 @@ void DisplayServerX11::_set_wm_minimized(WindowID p_window, bool p_enabled) {
 	wd.minimized = p_enabled;
 }
 
-void DisplayServerX11::_set_wm_fullscreen(WindowID p_window, bool p_enabled) {
+void DisplayServerX11::_set_wm_fullscreen(WindowID p_window, bool p_enabled, bool p_exclusive) {
 	ERR_FAIL_COND(!windows.has(p_window));
 	WindowData &wd = windows[p_window];
 
@@ -2063,7 +2063,14 @@ void DisplayServerX11::_set_wm_fullscreen(WindowID p_window, bool p_enabled) {
 
 	// set bypass compositor hint
 	Atom bypass_compositor = XInternAtom(x11_display, "_NET_WM_BYPASS_COMPOSITOR", False);
-	unsigned long compositing_disable_on = p_enabled ? 1 : 0;
+	unsigned long compositing_disable_on = 0; // Use default.
+	if (p_enabled) {
+		if (p_exclusive) {
+			compositing_disable_on = 1; // Force composition OFF to reduce overhead.
+		} else {
+			compositing_disable_on = 2; // Force composition ON to allow popup windows.
+		}
+	}
 	if (bypass_compositor != None) {
 		XChangeProperty(x11_display, wd.x11_window, bypass_compositor, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&compositing_disable_on, 1);
 	}
@@ -2109,8 +2116,9 @@ void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) {
 		case WINDOW_MODE_FULLSCREEN: {
 			//Remove full-screen
 			wd.fullscreen = false;
+			wd.exclusive_fullscreen = false;
 
-			_set_wm_fullscreen(p_window, false);
+			_set_wm_fullscreen(p_window, false, false);
 
 			//un-maximize required for always on top
 			bool on_top = window_get_flag(WINDOW_FLAG_ALWAYS_ON_TOP, p_window);
@@ -2143,7 +2151,13 @@ void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) {
 			}
 
 			wd.fullscreen = true;
-			_set_wm_fullscreen(p_window, true);
+			if (p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
+				wd.exclusive_fullscreen = true;
+				_set_wm_fullscreen(p_window, true, true);
+			} else {
+				wd.exclusive_fullscreen = false;
+				_set_wm_fullscreen(p_window, true, false);
+			}
 		} break;
 		case WINDOW_MODE_MAXIMIZED: {
 			_set_wm_maximized(p_window, true);
@@ -2158,7 +2172,11 @@ DisplayServer::WindowMode DisplayServerX11::window_get_mode(WindowID p_window) c
 	const WindowData &wd = windows[p_window];
 
 	if (wd.fullscreen) { //if fullscreen, it's not in another mode
-		return WINDOW_MODE_FULLSCREEN;
+		if (wd.exclusive_fullscreen) {
+			return WINDOW_MODE_EXCLUSIVE_FULLSCREEN;
+		} else {
+			return WINDOW_MODE_FULLSCREEN;
+		}
 	}
 
 	// Test maximized.

+ 2 - 1
platform/linuxbsd/x11/display_server_x11.h

@@ -159,6 +159,7 @@ class DisplayServerX11 : public DisplayServer {
 		//better to guess on the fly, given WM can change it
 		//WindowMode mode;
 		bool fullscreen = false; //OS can't exit from this mode
+		bool exclusive_fullscreen = false;
 		bool on_top = false;
 		bool borderless = false;
 		bool resize_disabled = false;
@@ -283,7 +284,7 @@ class DisplayServerX11 : public DisplayServer {
 	bool _window_minimize_check(WindowID p_window) const;
 	void _validate_mode_on_map(WindowID p_window);
 	void _update_size_hints(WindowID p_window);
-	void _set_wm_fullscreen(WindowID p_window, bool p_enabled);
+	void _set_wm_fullscreen(WindowID p_window, bool p_enabled, bool p_exclusive);
 	void _set_wm_maximized(WindowID p_window, bool p_enabled);
 	void _set_wm_minimized(WindowID p_window, bool p_enabled);