浏览代码

Fixes to X11, still pretty broken

Juan Linietsky 5 年之前
父节点
当前提交
197cb4e771

+ 110 - 27
platform/linuxbsd/display_server_x11.cpp

@@ -862,11 +862,10 @@ Point2i DisplayServerX11::window_get_position(WindowID p_window) const {
 
 	ERR_FAIL_COND_V(!windows.has(p_window), Point2i());
 	const WindowData &wd = windows[p_window];
-	int x, y;
-	Window child;
-	XTranslateCoordinates(x11_display, wd.x11_window, DefaultRootWindow(x11_display), 0, 0, &x, &y, &child);
-	return Point2i(x, y);
+
+	return wd.position;
 }
+
 void DisplayServerX11::window_set_position(const Point2i &p_position, WindowID p_window) {
 
 	_THREAD_SAFE_METHOD_
@@ -991,9 +990,14 @@ void DisplayServerX11::window_set_size(const Size2i p_size, WindowID p_window) {
 	_THREAD_SAFE_METHOD_
 
 	ERR_FAIL_COND(!windows.has(p_window));
+
+	Size2i size = p_size;
+	size.x = MAX(1, size.x);
+	size.y = MAX(1, size.y);
+
 	WindowData &wd = windows[p_window];
 
-	if (wd.size.width == p_size.width && wd.size.height == p_size.height)
+	if (wd.size.width == size.width && wd.size.height == size.height)
 		return;
 
 	XWindowAttributes xwa;
@@ -1007,10 +1011,10 @@ void DisplayServerX11::window_set_size(const Size2i p_size, WindowID p_window) {
 	xsh = XAllocSizeHints();
 	if (!window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) {
 		xsh->flags = PMinSize | PMaxSize;
-		xsh->min_width = p_size.x;
-		xsh->max_width = p_size.x;
-		xsh->min_height = p_size.y;
-		xsh->max_height = p_size.y;
+		xsh->min_width = size.x;
+		xsh->max_width = size.x;
+		xsh->min_height = size.y;
+		xsh->max_height = size.y;
 	} else {
 		xsh->flags = 0L;
 		if (wd.min_size != Size2i()) {
@@ -1028,10 +1032,10 @@ void DisplayServerX11::window_set_size(const Size2i p_size, WindowID p_window) {
 	XFree(xsh);
 
 	// Resize the window
-	XResizeWindow(x11_display, wd.x11_window, p_size.x, p_size.y);
+	XResizeWindow(x11_display, wd.x11_window, size.x, size.y);
 
 	// Update our videomode width and height
-	wd.size = p_size;
+	wd.size = size;
 
 	for (int timeout = 0; timeout < 50; ++timeout) {
 		XSync(x11_display, False);
@@ -1348,7 +1352,7 @@ void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) {
 			XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
 		} break;
 		case WINDOW_MODE_FULLSCREEN: {
-			wd.last_position_before_fs = window_get_position(p_window);
+			wd.last_position_before_fs = wd.position;
 			if (window_get_flag(WINDOW_FLAG_ALWAYS_ON_TOP, p_window)) {
 				_set_wm_maximized(p_window, true);
 			}
@@ -2229,22 +2233,35 @@ void DisplayServerX11::_window_changed(XEvent *event) {
 		}
 	}
 
+	Rect2i new_rect;
+
 	WindowData &wd = windows[window_id];
-	if (wd.x11_window != event->xany.window) { // Check if the correct window
+	if (wd.x11_window != event->xany.window) { // Check if the correct window, in case it was not main window or anything else
 		return;
 	}
 
+	{
+		//the position in xconfigure is not useful here, obtain it manually
+		int x, y;
+		Window child;
+		XTranslateCoordinates(x11_display, wd.x11_window, DefaultRootWindow(x11_display), 0, 0, &x, &y, &child);
+		new_rect.position.x = x;
+		new_rect.position.y = y;
+
+		new_rect.size.width = event->xconfigure.width;
+		new_rect.size.height = event->xconfigure.height;
+	}
+
+	if (new_rect == Rect2i(wd.position, wd.size)) {
+		return;
+	}
 	if (wd.xic) {
 		//  Not portable.
 		window_set_ime_position(Point2(0, 1));
 	}
 
-	if ((event->xconfigure.width == wd.size.width) &&
-			(event->xconfigure.height == wd.size.height))
-		return;
-
-	wd.size.width = event->xconfigure.width;
-	wd.size.height = event->xconfigure.height;
+	wd.position = new_rect.position;
+	wd.size = new_rect.size;
 
 #if defined(VULKAN_ENABLED)
 	if (rendering_driver == "vulkan") {
@@ -2252,8 +2269,12 @@ void DisplayServerX11::_window_changed(XEvent *event) {
 	}
 #endif
 
+	print_line("DisplayServer::_window_changed: " + itos(window_id) + " rect: " + new_rect);
 	if (!wd.rect_changed_callback.is_null()) {
-		Variant rect = Rect2i(wd.im_position, wd.size);
+		Rect2i r = new_rect;
+
+		Variant rect = r;
+
 		Variant *rectp = &rect;
 		Variant ret;
 		Callable::CallError ce;
@@ -3122,7 +3143,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u
 	WindowID id;
 	{
 		WindowData wd;
-		wd.x11_window = XCreateWindow(x11_display, RootWindow(x11_display, visualInfo->screen), p_rect.position.x, p_rect.position.y, p_rect.size.width, p_rect.size.height, 0, visualInfo->depth, InputOutput, visualInfo->visual, valuemask, &windowAttributes);
+		wd.x11_window = XCreateWindow(x11_display, RootWindow(x11_display, visualInfo->screen), p_rect.position.x, p_rect.position.y, p_rect.size.width > 0 ? p_rect.size.width : 1, p_rect.size.height > 0 ? p_rect.size.height : 1, 0, visualInfo->depth, InputOutput, visualInfo->visual, valuemask, &windowAttributes);
 
 		XMapWindow(x11_display, wd.x11_window);
 
@@ -3206,13 +3227,73 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u
 
 		windows[id] = wd;
 
-		if (id != MAIN_WINDOW_ID) {
-			//this is a sub window, don't let the window manager put it wherever it wants
-			for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
-				if (p_flags & (1 << i)) {
-					window_set_flag(WindowFlags(i), true, id);
+		{
+
+			if (p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT) {
+
+				XSizeHints *xsh;
+				xsh = XAllocSizeHints();
+
+				xsh->flags = PMinSize | PMaxSize;
+				xsh->min_width = p_rect.size.width;
+				xsh->max_width = p_rect.size.width;
+				xsh->min_height = p_rect.size.height;
+				xsh->max_height = p_rect.size.height;
+
+				XSetWMNormalHints(x11_display, wd.x11_window, xsh);
+				XFree(xsh);
+			}
+
+			bool make_utility = false;
+
+			if (p_flags & WINDOW_FLAG_BORDERLESS_BIT) {
+				Hints hints;
+				Atom property;
+				hints.flags = 2;
+				hints.decorations = 0;
+				property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
+				XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
+
+				make_utility = true;
+			}
+			if (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) {
+				make_utility = true;
+			}
+
+			if (make_utility) {
+				//this one seems to disable the fade animations for regular windows
+				//but has the drawback that will not get focus by default, so
+				//we need fo force it, unless no focus requested
+
+				Atom type_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_UTILITY", False);
+				Atom wt_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", False);
+
+				XChangeProperty(x11_display, wd.x11_window, wt_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&type_atom, 1);
+
+				if (!(p_flags & WINDOW_FLAG_NO_FOCUS_BIT)) {
+					//but as utility appears unfocused, it needs to be forcefuly focused, unless no focus requested
+					XEvent xev;
+					Atom net_active_window = XInternAtom(x11_display, "_NET_ACTIVE_WINDOW", False);
+
+					memset(&xev, 0, sizeof(xev));
+					xev.type = ClientMessage;
+					xev.xclient.window = wd.x11_window;
+					xev.xclient.message_type = net_active_window;
+					xev.xclient.format = 32;
+					xev.xclient.data.l[0] = 1;
+					xev.xclient.data.l[1] = CurrentTime;
+
+					XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
 				}
+			} else {
+				Atom type_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_NORMAL", False);
+				Atom wt_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", False);
+
+				XChangeProperty(x11_display, wd.x11_window, wt_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&type_atom, 1);
 			}
+		}
+
+		if (id != MAIN_WINDOW_ID) {
 
 			XSizeHints my_hints = XSizeHints();
 
@@ -3253,10 +3334,12 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u
 		XSync(x11_display, False);
 		XGetWindowAttributes(x11_display, wd.x11_window, &xwa);
 
+		wd.position.x = xwa.x;
+		wd.position.y = xwa.y;
 		wd.size.width = xwa.width;
 		wd.size.height = xwa.height;
 
-		print_line("created at rect: " + p_rect + " but at rect " + Rect2i(xwa.x, xwa.y, xwa.width, xwa.height));
+		print_line("DisplayServer::_create_window " + itos(id) + " want rect: " + p_rect + " got rect " + Rect2i(xwa.x, xwa.y, xwa.width, xwa.height));
 	}
 
 	//set cursor

+ 1 - 0
platform/linuxbsd/display_server_x11.h

@@ -118,6 +118,7 @@ class DisplayServerX11 : public DisplayServer {
 
 		Size2i min_size;
 		Size2i max_size;
+		Point2i position;
 		Size2i size;
 		Point2i im_position;
 		bool im_active = false;

+ 7 - 0
scene/gui/menu_button.cpp

@@ -53,10 +53,17 @@ void MenuButton::_unhandled_key_input(Ref<InputEvent> p_event) {
 
 void MenuButton::pressed() {
 
+	{
+		Window *w = Object::cast_to<Window>(get_viewport());
+		if (w && !w->is_embedding_subwindows()) {
+			print_line("windowpos: " + w->get_position());
+		}
+	}
 	Size2 size = get_size();
 
 	Point2 gp = get_screen_position();
 
+	print_line("screenpos: " + gp);
 	gp.y += get_size().y;
 
 	popup->set_position(gp);

+ 13 - 13
scene/main/window.cpp

@@ -932,7 +932,7 @@ Window *Window::get_parent_visible_window() const {
 	return window;
 }
 
-void Window::popup_on_parent(const Rect2 &p_parent_rect) {
+void Window::popup_on_parent(const Rect2i &p_parent_rect) {
 
 	ERR_FAIL_COND(!is_inside_tree());
 	ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window.");
@@ -943,14 +943,14 @@ void Window::popup_on_parent(const Rect2 &p_parent_rect) {
 		if (!window) {
 			popup(p_parent_rect);
 		} else {
-			popup(Rect2(window->get_position() + p_parent_rect.position, p_parent_rect.size));
+			popup(Rect2i(window->get_position() + p_parent_rect.position, p_parent_rect.size));
 		}
 	} else {
 		popup(p_parent_rect);
 	}
 }
 
-void Window::popup_centered_clamped(const Size2 &p_size, float p_fallback_ratio) {
+void Window::popup_centered_clamped(const Size2i &p_size, float p_fallback_ratio) {
 
 	ERR_FAIL_COND(!is_inside_tree());
 	ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window.");
@@ -966,16 +966,16 @@ void Window::popup_centered_clamped(const Size2 &p_size, float p_fallback_ratio)
 		parent_rect.size = DisplayServer::get_singleton()->screen_get_size(parent_screen);
 	}
 
-	Vector2 size_ratio = parent_rect.size * p_fallback_ratio;
+	Vector2i size_ratio = parent_rect.size * p_fallback_ratio;
 
-	Rect2 popup_rect;
-	popup_rect.size = Vector2(MIN(size_ratio.x, p_size.x), MIN(size_ratio.y, p_size.y));
+	Rect2i popup_rect;
+	popup_rect.size = Vector2i(MIN(size_ratio.x, p_size.x), MIN(size_ratio.y, p_size.y));
 	popup_rect.position = (parent_rect.size - popup_rect.size) / 2;
 
 	popup(popup_rect);
 }
 
-void Window::popup_centered(const Size2 &p_minsize) {
+void Window::popup_centered(const Size2i &p_minsize) {
 	ERR_FAIL_COND(!is_inside_tree());
 	ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window.");
 
@@ -990,8 +990,8 @@ void Window::popup_centered(const Size2 &p_minsize) {
 		parent_rect.size = DisplayServer::get_singleton()->screen_get_size(parent_screen);
 	}
 
-	Rect2 popup_rect;
-	if (p_minsize == Size2()) {
+	Rect2i popup_rect;
+	if (p_minsize == Size2i()) {
 		popup_rect.size = _get_contents_minimum_size();
 	} else {
 		popup_rect.size = p_minsize;
@@ -1006,7 +1006,7 @@ void Window::popup_centered_ratio(float p_ratio) {
 	ERR_FAIL_COND(!is_inside_tree());
 	ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window.");
 
-	Rect2 parent_rect;
+	Rect2i parent_rect;
 
 	if (is_embedded()) {
 		parent_rect = get_parent_viewport()->get_visible_rect();
@@ -1017,18 +1017,18 @@ void Window::popup_centered_ratio(float p_ratio) {
 		parent_rect.size = DisplayServer::get_singleton()->screen_get_size(parent_screen);
 	}
 
-	Rect2 popup_rect;
+	Rect2i popup_rect;
 	popup_rect.size = parent_rect.size * p_ratio;
 	popup_rect.position = (parent_rect.size - popup_rect.size) / 2;
 
 	popup(popup_rect);
 }
 
-void Window::popup(const Rect2 &p_screen_rect) {
+void Window::popup(const Rect2i &p_screen_rect) {
 
 	emit_signal("about_to_popup");
 
-	if (p_screen_rect != Rect2()) {
+	if (p_screen_rect != Rect2i()) {
 		set_position(p_screen_rect.position);
 		set_size(p_screen_rect.size);
 	}

+ 4 - 4
scene/main/window.h

@@ -221,11 +221,11 @@ public:
 
 	Window *get_parent_visible_window() const;
 	Viewport *get_parent_viewport() const;
-	void popup(const Rect2 &p_rect = Rect2());
-	void popup_on_parent(const Rect2 &p_parent_rect);
+	void popup(const Rect2i &p_rect = Rect2i());
+	void popup_on_parent(const Rect2i &p_parent_rect);
 	void popup_centered_ratio(float p_ratio = 0.8);
-	void popup_centered(const Size2 &p_minsize = Size2());
-	void popup_centered_clamped(const Size2 &p_size = Size2(), float p_fallback_ratio = 0.75);
+	void popup_centered(const Size2i &p_minsize = Size2i());
+	void popup_centered_clamped(const Size2i &p_size = Size2i(), float p_fallback_ratio = 0.75);
 
 	void set_theme(const Ref<Theme> &p_theme);
 	Ref<Theme> get_theme() const;

+ 2 - 2
servers/display_server.cpp

@@ -284,8 +284,8 @@ void DisplayServer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("window_set_input_text_callback", "callback", "window_id"), &DisplayServer::window_set_input_text_callback, DEFVAL(MAIN_WINDOW_ID));
 	ClassDB::bind_method(D_METHOD("window_set_drop_files_callback", "callback", "window_id"), &DisplayServer::window_set_drop_files_callback, DEFVAL(MAIN_WINDOW_ID));
 
-	ClassDB::bind_method(D_METHOD("window_attach_instance_id", "instance_id", "window_id"), &DisplayServer::window_get_max_size, DEFVAL(MAIN_WINDOW_ID));
-	ClassDB::bind_method(D_METHOD("window_get_attached_instance_id", "window_id"), &DisplayServer::window_get_max_size, DEFVAL(MAIN_WINDOW_ID));
+	ClassDB::bind_method(D_METHOD("window_attach_instance_id", "instance_id", "window_id"), &DisplayServer::window_attach_instance_id, DEFVAL(MAIN_WINDOW_ID));
+	ClassDB::bind_method(D_METHOD("window_get_attached_instance_id", "window_id"), &DisplayServer::window_get_attached_instance_id, DEFVAL(MAIN_WINDOW_ID));
 
 	ClassDB::bind_method(D_METHOD("window_get_max_size", "window_id"), &DisplayServer::window_get_max_size, DEFVAL(MAIN_WINDOW_ID));
 	ClassDB::bind_method(D_METHOD("window_set_max_size", "max_size", "window_id"), &DisplayServer::window_set_max_size, DEFVAL(MAIN_WINDOW_ID));