Browse Source

Wayland: Implement native sub-windows

The backend is now mature enough to not explode with multiple windows
but the `DisplayServer` API still cannot meet some guarantees required
by the various Wayland protocols we use. To meet those guarantees this
patch adds three new elements to the DisplayServer API, with relative
handling logic for `Window` and `Popup` nodes:

 - `WINDOW_EVENT_FORCE_CLOSE`, which tells a window to *forcefully*
close itself and ensure a proper cleanup of its references, as Wayland
enforces this behavior;

 - `WINDOW_FLAG_POPUP_WM_HINT`, which explicitly declares a window as a
"popup", as Wayland enforces this distinction and heuristics are not
reliable enough;

 - `FEATURE_SELF_FITTING_WINDOWS`, which signals that the compositor can
fit windows to the screen automatically and that nodes should not do
that themselves.

Given the size of this feature, this patch also includes various
`WaylandThread` reworks and fixes including:

 - Improvements to frame wait logic, with fixes to various stalls and a
configurable (through a `#define`) timeout amount;

 - A proper implementation of `window_can_draw`;

 - Complete overhaul of pointer and tablet handling. Now everything is
always accumulated and handled only on each respective `frame` event.
This makes their logic simpler and more robust.

 - Better handling of pointer leaving and pointer enter/exit event
sending;

 - Keyboard focus tracking;

 - More solid window references using IDs instead of raw pointers as
windows can be deleted at any time;

 - More aggressive messaging to window nodes to enforce rects imposed by
the compositor.
Riteo 1 year ago
parent
commit
84d3adcf2f

+ 11 - 1
doc/classes/DisplayServer.xml

@@ -1958,6 +1958,9 @@
 		<constant name="FEATURE_NATIVE_COLOR_PICKER" value="32" enum="Feature">
 			Display server supports native color picker. [b]Linux (X11/Wayland)[/b]
 		</constant>
+		<constant name="FEATURE_SELF_FITTING_WINDOWS" value="33" enum="Feature">
+			Display server automatically fits popups according to the screen boundaries. Window nodes should not attempt to do that themselves.
+		</constant>
 		<constant name="MOUSE_MODE_VISIBLE" value="0" enum="MouseMode">
 			Makes the mouse cursor visible if it is hidden.
 		</constant>
@@ -2181,7 +2184,10 @@
 			[b]Note:[/b] This flag is implemented on macOS and Windows.
 			[b]Note:[/b] Setting this flag will [b]NOT[/b] prevent other apps from capturing an image, it should not be used as a security measure.
 		</constant>
-		<constant name="WINDOW_FLAG_MAX" value="10" enum="WindowFlags">
+		<constant name="WINDOW_FLAG_POPUP_WM_HINT" value="10" enum="WindowFlags">
+			Signals the window manager that this window is supposed to be an implementation-defined "popup" (usually a floating, borderless, untileable and immovable child window).
+		</constant>
+		<constant name="WINDOW_FLAG_MAX" value="11" enum="WindowFlags">
 			Max value of the [enum WindowFlags].
 		</constant>
 		<constant name="WINDOW_EVENT_MOUSE_ENTER" value="0" enum="WindowEvent">
@@ -2211,6 +2217,10 @@
 			Sent when the window title bar decoration is changed (e.g. [constant WINDOW_FLAG_EXTEND_TO_TITLE] is set or window entered/exited full screen mode).
 			[b]Note:[/b] This flag is implemented only on macOS.
 		</constant>
+		<constant name="WINDOW_EVENT_FORCE_CLOSE" value="8" enum="WindowEvent">
+			Sent when the window has been forcibly closed by the Display Server. The window shall immediately hide and clean any internal rendering references.
+			[b]Note:[/b] This flag is implemented only on Linux (Wayland).
+		</constant>
 		<constant name="WINDOW_EDGE_TOP_LEFT" value="0" enum="WindowResizeEdge">
 			Top-left edge of a window.
 		</constant>

+ 1 - 0
doc/classes/Popup.xml

@@ -11,6 +11,7 @@
 	<members>
 		<member name="borderless" type="bool" setter="set_flag" getter="get_flag" overrides="Window" default="true" />
 		<member name="popup_window" type="bool" setter="set_flag" getter="get_flag" overrides="Window" default="true" />
+		<member name="popup_wm_hint" type="bool" setter="set_flag" getter="get_flag" overrides="Window" default="true" />
 		<member name="transient" type="bool" setter="set_transient" getter="is_transient" overrides="Window" default="true" />
 		<member name="unresizable" type="bool" setter="set_flag" getter="get_flag" overrides="Window" default="true" />
 		<member name="visible" type="bool" setter="set_visible" getter="is_visible" overrides="Window" default="false" />

+ 7 - 1
doc/classes/Window.xml

@@ -670,6 +670,9 @@
 		<member name="popup_window" type="bool" setter="set_flag" getter="get_flag" default="false">
 			If [code]true[/code], the [Window] will be considered a popup. Popups are sub-windows that don't show as separate windows in system's window manager's window list and will send close request when anything is clicked outside of them (unless [member exclusive] is enabled).
 		</member>
+		<member name="popup_wm_hint" type="bool" setter="set_flag" getter="get_flag" default="false">
+			If [code]true[/code], the [Window] will signal to the window manager that it is supposed to be an implementation-defined "popup" (usually a floating, borderless, untileable and immovable child window).
+		</member>
 		<member name="position" type="Vector2i" setter="set_position" getter="get_position" default="Vector2i(0, 0)">
 			The window's position in pixels.
 			If [member ProjectSettings.display/window/subwindows/embed_subwindows] is [code]false[/code], the position is in absolute screen coordinates. This typically applies to editor plugins. If the setting is [code]true[/code], the window's position is in the coordinates of its parent [Viewport].
@@ -879,7 +882,10 @@
 			[b]Note:[/b] This flag is implemented on macOS and Windows.
 			[b]Note:[/b] Setting this flag will [b]NOT[/b] prevent other apps from capturing an image, it should not be used as a security measure.
 		</constant>
-		<constant name="FLAG_MAX" value="10" enum="Flags">
+		<constant name="FLAG_POPUP_WM_HINT" value="10" enum="Flags">
+			Signals the window manager that this window is supposed to be an implementation-defined "popup" (usually a floating, borderless, untileable and immovable child window).
+		</constant>
+		<constant name="FLAG_MAX" value="11" enum="Flags">
 			Max value of the [enum Flags].
 		</constant>
 		<constant name="CONTENT_SCALE_MODE_DISABLED" value="0" enum="ContentScaleMode">

File diff suppressed because it is too large
+ 487 - 137
platform/linuxbsd/wayland/display_server_wayland.cpp


+ 31 - 7
platform/linuxbsd/wayland/display_server_wayland.h

@@ -68,7 +68,15 @@
 class DisplayServerWayland : public DisplayServer {
 	// No need to register with GDCLASS, it's platform-specific and nothing is added.
 	struct WindowData {
-		WindowID id;
+		WindowID id = INVALID_WINDOW_ID;
+
+		WindowID parent_id = INVALID_WINDOW_ID;
+
+		// For popups.
+		WindowID root_id = INVALID_WINDOW_ID;
+
+		// For toplevels.
+		List<WindowID> popup_stack;
 
 		Rect2i rect;
 		Size2i max_size;
@@ -76,6 +84,8 @@ class DisplayServerWayland : public DisplayServer {
 
 		Rect2i safe_rect;
 
+		bool emulate_vsync = false;
+
 #ifdef GLES3_ENABLED
 		struct wl_egl_window *wl_egl_window = nullptr;
 #endif
@@ -119,17 +129,25 @@ class DisplayServerWayland : public DisplayServer {
 
 	HashMap<CursorShape, CustomCursor> custom_cursors;
 
-	WindowData main_window;
+	HashMap<WindowID, WindowData> windows;
+	WindowID window_id_counter = MAIN_WINDOW_ID;
+
 	WaylandThread wayland_thread;
 
 	Context context;
 	bool swap_cancel_ok = false;
 
+	// NOTE: These are the based on WINDOW_FLAG_POPUP, which does NOT imply what it
+	// seems. It's particularly confusing for our usecase, but just know that these
+	// are the "take all input thx" windows while the `popup_stack` variable keeps
+	// track of all the generic floating window concept.
+	List<WindowID> popup_menu_list;
+	BitField<MouseButtonMask> last_mouse_monitor_mask;
+
 	String ime_text;
 	Vector2i ime_selection;
 
 	SuspendState suspend_state = SuspendState::NONE;
-	bool emulate_vsync = false;
 
 	String rendering_driver;
 
@@ -155,14 +173,12 @@ class DisplayServerWayland : public DisplayServer {
 #endif
 	static String _get_app_id_from_context(Context p_context);
 
-	void _send_window_event(WindowEvent p_event);
+	void _send_window_event(WindowEvent p_event, WindowID p_window_id = MAIN_WINDOW_ID);
 
 	static void dispatch_input_events(const Ref<InputEvent> &p_event);
 	void _dispatch_input_event(const Ref<InputEvent> &p_event);
 
-	void _resize_window(const Size2i &p_size);
-
-	virtual void _show_window();
+	void _update_window_rect(const Rect2i &p_rect, WindowID p_window_id = MAIN_WINDOW_ID);
 
 	void try_suspend();
 
@@ -227,6 +243,14 @@ public:
 
 	virtual Vector<DisplayServer::WindowID> get_window_list() const override;
 
+	virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i(), bool p_exclusive = false, WindowID p_transient_parent = INVALID_WINDOW_ID) override;
+	virtual void show_window(WindowID p_id) override;
+	virtual void delete_sub_window(WindowID p_id) override;
+
+	virtual WindowID window_get_active_popup() const override;
+	virtual void window_set_popup_safe_rect(WindowID p_window, const Rect2i &p_rect) override;
+	virtual Rect2i window_get_popup_safe_rect(WindowID p_window) const override;
+
 	virtual int64_t window_get_native_handle(HandleType p_handle_type, WindowID p_window = MAIN_WINDOW_ID) const override;
 
 	virtual WindowID get_window_at_screen_position(const Point2i &p_position) const override;

File diff suppressed because it is too large
+ 320 - 208
platform/linuxbsd/wayland/wayland_thread.cpp


+ 46 - 15
platform/linuxbsd/wayland/wayland_thread.h

@@ -95,8 +95,15 @@ public:
 		virtual ~Message() = default;
 	};
 
+	class WindowMessage : public Message {
+		GDSOFTCLASS(WindowMessage, Message);
+
+	public:
+		DisplayServer::WindowID id = DisplayServer::INVALID_WINDOW_ID;
+	};
+
 	// Message data for window rect changes.
-	class WindowRectMessage : public Message {
+	class WindowRectMessage : public WindowMessage {
 		GDSOFTCLASS(WindowRectMessage, Message);
 
 	public:
@@ -105,7 +112,7 @@ public:
 		Rect2i rect;
 	};
 
-	class WindowEventMessage : public Message {
+	class WindowEventMessage : public WindowMessage {
 		GDSOFTCLASS(WindowEventMessage, Message);
 
 	public:
@@ -119,14 +126,14 @@ public:
 		Ref<InputEvent> event;
 	};
 
-	class DropFilesEventMessage : public Message {
+	class DropFilesEventMessage : public WindowMessage {
 		GDSOFTCLASS(DropFilesEventMessage, Message);
 
 	public:
 		Vector<String> files;
 	};
 
-	class IMEUpdateEventMessage : public Message {
+	class IMEUpdateEventMessage : public WindowMessage {
 		GDSOFTCLASS(IMEUpdateEventMessage, Message);
 
 	public:
@@ -134,7 +141,7 @@ public:
 		Vector2i selection;
 	};
 
-	class IMECommitEventMessage : public Message {
+	class IMECommitEventMessage : public WindowMessage {
 		GDSOFTCLASS(IMECommitEventMessage, Message);
 
 	public:
@@ -215,7 +222,8 @@ public:
 	// TODO: Make private?
 
 	struct WindowState {
-		DisplayServer::WindowID id;
+		DisplayServer::WindowID id = DisplayServer::INVALID_WINDOW_ID;
+		DisplayServer::WindowID parent_id = DisplayServer::INVALID_WINDOW_ID;
 
 		Rect2i rect;
 		DisplayServer::WindowMode mode = DisplayServer::WINDOW_MODE_WINDOWED;
@@ -237,6 +245,7 @@ public:
 		// be called even after being destroyed, pointing to probably invalid window
 		// data by then and segfaulting hard.
 		struct wl_callback *frame_callback = nullptr;
+		uint64_t last_frame_time = 0;
 
 		struct wl_surface *wl_surface = nullptr;
 		struct xdg_surface *xdg_surface = nullptr;
@@ -250,6 +259,8 @@ public:
 
 		struct zxdg_exported_v2 *xdg_exported_v2 = nullptr;
 
+		struct xdg_popup *xdg_popup = nullptr;
+
 		String exported_handle;
 
 		// Currently applied buffer scale.
@@ -335,6 +346,9 @@ public:
 		MouseButton last_button_pressed = MouseButton::NONE;
 		Point2 last_pressed_position;
 
+		DisplayServer::WindowID pointed_id = DisplayServer::INVALID_WINDOW_ID;
+		DisplayServer::WindowID last_pointed_id = DisplayServer::INVALID_WINDOW_ID;
+
 		// This is needed to check for a new double click every time.
 		bool double_click_begun = false;
 
@@ -364,20 +378,17 @@ public:
 
 		bool double_click_begun = false;
 
-		// Note: the protocol doesn't have it (I guess that this isn't really meant to
-		// be used as a mouse...), but we'll hack one in with the current ticks.
 		uint64_t button_time = 0;
-
 		uint64_t motion_time = 0;
 
+		DisplayServer::WindowID proximal_id = DisplayServer::INVALID_WINDOW_ID;
+		DisplayServer::WindowID last_proximal_id = DisplayServer::INVALID_WINDOW_ID;
 		uint32_t proximity_serial = 0;
-		struct wl_surface *proximal_surface = nullptr;
 	};
 
 	struct TabletToolState {
 		struct wl_seat *wl_seat = nullptr;
 
-		struct wl_surface *last_surface = nullptr;
 		bool is_eraser = false;
 
 		TabletToolData data_pending;
@@ -401,9 +412,6 @@ public:
 
 		uint32_t pointer_enter_serial = 0;
 
-		struct wl_surface *pointed_surface = nullptr;
-		struct wl_surface *last_pointed_surface = nullptr;
-
 		struct zwp_relative_pointer_v1 *wp_relative_pointer = nullptr;
 		struct zwp_locked_pointer_v1 *wp_locked_pointer = nullptr;
 		struct zwp_confined_pointer_v1 *wp_confined_pointer = nullptr;
@@ -434,6 +442,9 @@ public:
 		// Keyboard.
 		struct wl_keyboard *wl_keyboard = nullptr;
 
+		// For key events.
+		DisplayServer::WindowID focused_id = DisplayServer::INVALID_WINDOW_ID;
+
 		struct xkb_context *xkb_context = nullptr;
 		struct xkb_keymap *xkb_keymap = nullptr;
 		struct xkb_state *xkb_state = nullptr;
@@ -462,6 +473,7 @@ public:
 		struct wl_data_device *wl_data_device = nullptr;
 
 		// Drag and drop.
+		DisplayServer::WindowID dnd_id = DisplayServer::INVALID_WINDOW_ID;
 		struct wl_data_offer *wl_data_offer_dnd = nullptr;
 		uint32_t dnd_enter_serial = 0;
 
@@ -486,6 +498,7 @@ public:
 
 		// IME.
 		struct zwp_text_input_v3 *wp_text_input = nullptr;
+		DisplayServer::WindowID ime_window_id = DisplayServer::INVALID_WINDOW_ID;
 		bool ime_enabled = false;
 		bool ime_active = false;
 		String ime_text;
@@ -516,7 +529,7 @@ private:
 	Thread events_thread;
 	ThreadData thread_data;
 
-	WindowState main_window;
+	HashMap<DisplayServer::WindowID, WindowState> windows;
 
 	List<Ref<Message>> messages;
 
@@ -628,6 +641,10 @@ private:
 	static void _xdg_toplevel_on_configure_bounds(void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height);
 	static void _xdg_toplevel_on_wm_capabilities(void *data, struct xdg_toplevel *xdg_toplevel, struct wl_array *capabilities);
 
+	static void _xdg_popup_on_configure(void *data, struct xdg_popup *xdg_popup, int32_t x, int32_t y, int32_t width, int32_t height);
+	static void _xdg_popup_on_popup_done(void *data, struct xdg_popup *xdg_popup);
+	static void _xdg_popup_on_repositioned(void *data, struct xdg_popup *xdg_popup, uint32_t token);
+
 	// wayland-protocols event handlers.
 	static void _wp_fractional_scale_on_preferred_scale(void *data, struct wp_fractional_scale_v1 *wp_fractional_scale_v1, uint32_t scale);
 
@@ -783,6 +800,12 @@ private:
 		.wm_capabilities = _xdg_toplevel_on_wm_capabilities,
 	};
 
+	static constexpr struct xdg_popup_listener xdg_popup_listener = {
+		.configure = _xdg_popup_on_configure,
+		.popup_done = _xdg_popup_on_popup_done,
+		.repositioned = _xdg_popup_on_repositioned,
+	};
+
 	// wayland-protocols event listeners.
 	static constexpr struct wp_fractional_scale_v1_listener wp_fractional_scale_listener = {
 		.preferred_scale = _wp_fractional_scale_on_preferred_scale,
@@ -968,8 +991,13 @@ public:
 	void beep() const;
 
 	void window_create(DisplayServer::WindowID p_window_id, int p_width, int p_height);
+	void window_create_popup(DisplayServer::WindowID p_window_id, DisplayServer::WindowID p_parent_id, Rect2i p_rect);
+	void window_destroy(DisplayServer::WindowID p_window_Id);
+
+	void window_set_parent(DisplayServer::WindowID p_window_id, DisplayServer::WindowID p_parent_id);
 
 	struct wl_surface *window_get_wl_surface(DisplayServer::WindowID p_window_id) const;
+	WindowState *window_get_state(DisplayServer::WindowID p_window_id);
 
 	void window_start_resize(DisplayServer::WindowResizeEdge p_edge, DisplayServer::WindowID p_window);
 
@@ -1002,6 +1030,7 @@ public:
 	void pointer_set_hint(const Point2i &p_hint);
 	PointerConstraint pointer_get_constraint() const;
 	DisplayServer::WindowID pointer_get_pointed_window_id() const;
+	DisplayServer::WindowID pointer_get_last_pointed_window_id() const;
 	BitField<MouseButtonMask> pointer_get_button_mask() const;
 
 	void cursor_set_visible(bool p_visible);
@@ -1040,6 +1069,8 @@ public:
 	bool get_reset_frame();
 	bool wait_frame_suspend_ms(int p_timeout);
 
+	uint64_t window_get_last_frame_time(DisplayServer::WindowID p_window_id) const;
+	bool window_is_suspended(DisplayServer::WindowID p_window_id) const;
 	bool is_suspended() const;
 
 	Error init();

+ 6 - 0
scene/gui/popup.cpp

@@ -167,6 +167,11 @@ Rect2i Popup::_popup_adjust_rect() const {
 
 	Rect2i current(get_position(), get_size());
 
+	if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_SELF_FITTING_WINDOWS)) {
+		// We're fine as is, the Display Server will take care of that for us.
+		return current;
+	}
+
 	if (current.position.x + current.size.x > parent_rect.position.x + parent_rect.size.x) {
 		current.position.x = parent_rect.position.x + parent_rect.size.x - current.size.x;
 	}
@@ -219,6 +224,7 @@ Popup::Popup() {
 	set_flag(FLAG_BORDERLESS, true);
 	set_flag(FLAG_RESIZE_DISABLED, true);
 	set_flag(FLAG_POPUP, true);
+	set_flag(FLAG_POPUP_WM_HINT, true);
 }
 
 Popup::~Popup() {

+ 17 - 5
scene/main/window.cpp

@@ -835,6 +835,9 @@ void Window::_event_callback(DisplayServer::WindowEvent p_event) {
 		case DisplayServer::WINDOW_EVENT_TITLEBAR_CHANGE: {
 			emit_signal(SNAME("titlebar_changed"));
 		} break;
+		case DisplayServer::WINDOW_EVENT_FORCE_CLOSE: {
+			hide();
+		} break;
 	}
 }
 
@@ -1859,12 +1862,19 @@ void Window::popup(const Rect2i &p_screen_rect) {
 	// Update window size to calculate the actual window size based on contents minimum size and minimum size.
 	_update_window_size();
 
+	bool should_fit = !DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_SELF_FITTING_WINDOWS);
+
 	if (p_screen_rect != Rect2i()) {
 		set_position(p_screen_rect.position);
-		int screen_id = DisplayServer::get_singleton()->get_screen_from_rect(p_screen_rect);
-		Size2i screen_size = DisplayServer::get_singleton()->screen_get_usable_rect(screen_id).size;
-		Size2i new_size = p_screen_rect.size.min(screen_size);
-		set_size(new_size);
+
+		if (should_fit) {
+			int screen_id = DisplayServer::get_singleton()->get_screen_from_rect(p_screen_rect);
+			Size2i screen_size = DisplayServer::get_singleton()->screen_get_usable_rect(screen_id).size;
+			Size2i new_size = p_screen_rect.size.min(screen_size);
+			set_size(new_size);
+		} else {
+			set_size(p_screen_rect.size);
+		}
 	}
 
 	Rect2i adjust = _popup_adjust_rect();
@@ -1892,7 +1902,7 @@ void Window::popup(const Rect2i &p_screen_rect) {
 		int screen_id = DisplayServer::get_singleton()->window_get_current_screen(get_window_id());
 		parent_rect = DisplayServer::get_singleton()->screen_get_usable_rect(screen_id);
 	}
-	if (parent_rect != Rect2i() && !parent_rect.intersects(Rect2i(position, size))) {
+	if (should_fit && parent_rect != Rect2i() && !parent_rect.intersects(Rect2i(position, size))) {
 		ERR_PRINT(vformat("Window %d spawned at invalid position: %s.", get_window_id(), position));
 		set_position((parent_rect.size - size) / 2);
 	}
@@ -3095,6 +3105,7 @@ void Window::_bind_methods() {
 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "mouse_passthrough"), "set_flag", "get_flag", FLAG_MOUSE_PASSTHROUGH);
 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "sharp_corners"), "set_flag", "get_flag", FLAG_SHARP_CORNERS);
 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "exclude_from_capture"), "set_flag", "get_flag", FLAG_EXCLUDE_FROM_CAPTURE);
+	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "popup_wm_hint"), "set_flag", "get_flag", FLAG_POPUP_WM_HINT);
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "force_native"), "set_force_native", "get_force_native");
 
 	ADD_GROUP("Limits", "");
@@ -3151,6 +3162,7 @@ void Window::_bind_methods() {
 	BIND_ENUM_CONSTANT(FLAG_MOUSE_PASSTHROUGH);
 	BIND_ENUM_CONSTANT(FLAG_SHARP_CORNERS);
 	BIND_ENUM_CONSTANT(FLAG_EXCLUDE_FROM_CAPTURE);
+	BIND_ENUM_CONSTANT(FLAG_POPUP_WM_HINT);
 	BIND_ENUM_CONSTANT(FLAG_MAX);
 
 	BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_DISABLED);

+ 1 - 0
scene/main/window.h

@@ -64,6 +64,7 @@ public:
 		FLAG_MOUSE_PASSTHROUGH = DisplayServer::WINDOW_FLAG_MOUSE_PASSTHROUGH,
 		FLAG_SHARP_CORNERS = DisplayServer::WINDOW_FLAG_SHARP_CORNERS,
 		FLAG_EXCLUDE_FROM_CAPTURE = DisplayServer::WINDOW_FLAG_EXCLUDE_FROM_CAPTURE,
+		FLAG_POPUP_WM_HINT = DisplayServer::WINDOW_FLAG_POPUP_WM_HINT,
 		FLAG_MAX = DisplayServer::WINDOW_FLAG_MAX,
 	};
 

+ 3 - 0
servers/display_server.cpp

@@ -1120,6 +1120,7 @@ void DisplayServer::_bind_methods() {
 	BIND_ENUM_CONSTANT(FEATURE_NATIVE_DIALOG_FILE_MIME);
 	BIND_ENUM_CONSTANT(FEATURE_EMOJI_AND_SYMBOL_PICKER);
 	BIND_ENUM_CONSTANT(FEATURE_NATIVE_COLOR_PICKER);
+	BIND_ENUM_CONSTANT(FEATURE_SELF_FITTING_WINDOWS);
 
 	BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE);
 	BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN);
@@ -1195,6 +1196,7 @@ void DisplayServer::_bind_methods() {
 	BIND_ENUM_CONSTANT(WINDOW_FLAG_MOUSE_PASSTHROUGH);
 	BIND_ENUM_CONSTANT(WINDOW_FLAG_SHARP_CORNERS);
 	BIND_ENUM_CONSTANT(WINDOW_FLAG_EXCLUDE_FROM_CAPTURE);
+	BIND_ENUM_CONSTANT(WINDOW_FLAG_POPUP_WM_HINT);
 	BIND_ENUM_CONSTANT(WINDOW_FLAG_MAX);
 
 	BIND_ENUM_CONSTANT(WINDOW_EVENT_MOUSE_ENTER);
@@ -1205,6 +1207,7 @@ void DisplayServer::_bind_methods() {
 	BIND_ENUM_CONSTANT(WINDOW_EVENT_GO_BACK_REQUEST);
 	BIND_ENUM_CONSTANT(WINDOW_EVENT_DPI_CHANGE);
 	BIND_ENUM_CONSTANT(WINDOW_EVENT_TITLEBAR_CHANGE);
+	BIND_ENUM_CONSTANT(WINDOW_EVENT_FORCE_CLOSE);
 
 	BIND_ENUM_CONSTANT(WINDOW_EDGE_TOP_LEFT);
 	BIND_ENUM_CONSTANT(WINDOW_EDGE_TOP);

+ 4 - 0
servers/display_server.h

@@ -166,6 +166,7 @@ public:
 		FEATURE_NATIVE_DIALOG_FILE_MIME,
 		FEATURE_EMOJI_AND_SYMBOL_PICKER,
 		FEATURE_NATIVE_COLOR_PICKER,
+		FEATURE_SELF_FITTING_WINDOWS,
 	};
 
 	virtual bool has_feature(Feature p_feature) const = 0;
@@ -406,6 +407,7 @@ public:
 		WINDOW_FLAG_MOUSE_PASSTHROUGH,
 		WINDOW_FLAG_SHARP_CORNERS,
 		WINDOW_FLAG_EXCLUDE_FROM_CAPTURE,
+		WINDOW_FLAG_POPUP_WM_HINT,
 		WINDOW_FLAG_MAX,
 	};
 
@@ -421,6 +423,7 @@ public:
 		WINDOW_FLAG_MOUSE_PASSTHROUGH_BIT = (1 << WINDOW_FLAG_MOUSE_PASSTHROUGH),
 		WINDOW_FLAG_SHARP_CORNERS_BIT = (1 << WINDOW_FLAG_SHARP_CORNERS),
 		WINDOW_FLAG_EXCLUDE_FROM_CAPTURE_BIT = (1 << WINDOW_FLAG_EXCLUDE_FROM_CAPTURE),
+		WINDOW_FLAG_POPUP_WM_HINT_BIT = (1 << WINDOW_FLAG_POPUP_WM_HINT),
 	};
 
 	virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i(), bool p_exclusive = false, WindowID p_transient_parent = INVALID_WINDOW_ID);
@@ -449,6 +452,7 @@ public:
 		WINDOW_EVENT_GO_BACK_REQUEST,
 		WINDOW_EVENT_DPI_CHANGE,
 		WINDOW_EVENT_TITLEBAR_CHANGE,
+		WINDOW_EVENT_FORCE_CLOSE,
 	};
 	virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) = 0;
 	virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) = 0;

Some files were not shown because too many files changed in this diff