Browse Source

Merge pull request #101774 from Riteo/wayland-multiwindow-for-real-this-time

Wayland: Implement native sub-windows
Thaddeus Crews 5 months ago
parent
commit
f4c7a5ae1d

+ 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