소스 검색

Add new window setting: always on top

Implemented for Windows and Linux.
Pedro J. Estébanez 7 년 전
부모
커밋
554ffdcde7
8개의 변경된 파일108개의 추가작업 그리고 3개의 파일을 삭제
  1. 10 0
      core/bind/core_bind.cpp
  2. 2 0
      core/bind/core_bind.h
  3. 5 1
      core/os/os.h
  4. 11 1
      main/main.cpp
  5. 19 0
      platform/windows/os_windows.cpp
  6. 2 0
      platform/windows/os_windows.h
  7. 56 1
      platform/x11/os_x11.cpp
  8. 3 0
      platform/x11/os_x11.h

+ 10 - 0
core/bind/core_bind.cpp

@@ -297,6 +297,14 @@ bool _OS::is_window_maximized() const {
 	return OS::get_singleton()->is_window_maximized();
 }
 
+void _OS::set_window_always_on_top(bool p_enabled) {
+	OS::get_singleton()->set_window_always_on_top(p_enabled);
+}
+
+bool _OS::is_window_always_on_top() const {
+	return OS::get_singleton()->is_window_always_on_top();
+}
+
 void _OS::set_borderless_window(bool p_borderless) {
 	OS::get_singleton()->set_borderless_window(p_borderless);
 }
@@ -1031,6 +1039,8 @@ void _OS::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("is_window_minimized"), &_OS::is_window_minimized);
 	ObjectTypeDB::bind_method(_MD("set_window_maximized", "enabled"), &_OS::set_window_maximized);
 	ObjectTypeDB::bind_method(_MD("is_window_maximized"), &_OS::is_window_maximized);
+	ObjectTypeDB::bind_method(_MD("set_window_always_on_top", "enabled"), &_OS::set_window_always_on_top);
+	ObjectTypeDB::bind_method(_MD("is_window_always_on_top"), &_OS::is_window_always_on_top);
 	ObjectTypeDB::bind_method(_MD("request_attention"), &_OS::request_attention);
 
 	ObjectTypeDB::bind_method(_MD("set_borderless_window", "borderless"), &_OS::set_borderless_window);

+ 2 - 0
core/bind/core_bind.h

@@ -151,6 +151,8 @@ public:
 	virtual bool is_window_minimized() const;
 	virtual void set_window_maximized(bool p_enabled);
 	virtual bool is_window_maximized() const;
+	virtual void set_window_always_on_top(bool p_enabled);
+	virtual bool is_window_always_on_top() const;
 	virtual void request_attention();
 
 	virtual void set_borderless_window(bool p_borderless);

+ 5 - 1
core/os/os.h

@@ -78,13 +78,15 @@ public:
 		bool fullscreen;
 		bool resizable;
 		bool borderless_window;
+		bool always_on_top;
 		float get_aspect() const { return (float)width / (float)height; }
-		VideoMode(int p_width = 1024, int p_height = 600, bool p_fullscreen = false, bool p_resizable = true, bool p_borderless_window = false) {
+		VideoMode(int p_width = 1024, int p_height = 600, bool p_fullscreen = false, bool p_resizable = true, bool p_borderless_window = false, bool p_always_on_top = false) {
 			width = p_width;
 			height = p_height;
 			fullscreen = p_fullscreen;
 			resizable = p_resizable;
 			borderless_window = p_borderless_window;
+			always_on_top = p_always_on_top;
 		}
 	};
 
@@ -177,6 +179,8 @@ public:
 	virtual bool is_window_minimized() const { return false; }
 	virtual void set_window_maximized(bool p_enabled) {}
 	virtual bool is_window_maximized() const { return true; }
+	virtual void set_window_always_on_top(bool p_enabled) {}
+	virtual bool is_window_always_on_top() const { return false; }
 	virtual void request_attention() {}
 
 	virtual void set_borderless_window(int p_borderless) {}

+ 11 - 1
main/main.cpp

@@ -93,6 +93,7 @@ static OS::VideoMode video_mode;
 static bool init_maximized = false;
 static bool init_windowed = false;
 static bool init_fullscreen = false;
+static bool init_always_on_top = false;
 static bool init_use_custom_pos = false;
 #ifdef DEBUG_ENABLED
 static bool debug_collisions = false;
@@ -153,6 +154,7 @@ void Main::print_help(const char *p_binary) {
 	OS::get_singleton()->print("\t-f : Request fullscreen.\n");
 	OS::get_singleton()->print("\t-mx : Request maximized.\n");
 	OS::get_singleton()->print("\t-w : Request windowed.\n");
+	OS::get_singleton()->print("\t-t : Request always-on-top.\n");
 	OS::get_singleton()->print("\t-vd <driver> : Video driver (");
 	for (int i = 0; i < OS::get_singleton()->get_video_driver_count(); i++) {
 
@@ -425,8 +427,10 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
 
 		} else if (I->get() == "-f") { // fullscreen
 
-			//video_mode.fullscreen=false;
 			init_fullscreen = true;
+		} else if (I->get() == "-t") { // always-on-top
+
+			init_always_on_top = true;
 		} else if (I->get() == "-e" || I->get() == "-editor") { // fonud editor
 
 			editor = true;
@@ -690,6 +694,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
 		video_mode.resizable = globals->get("display/resizable");
 	if (use_custom_res && globals->has("display/borderless_window"))
 		video_mode.borderless_window = globals->get("display/borderless_window");
+	if (use_custom_res && globals->has("display/always_on_top"))
+		video_mode.always_on_top = globals->get("display/always_on_top");
 
 	if (!force_res && use_custom_res && globals->has("display/test_width") && globals->has("display/test_height")) {
 		int tw = globals->get("display/test_width");
@@ -706,6 +712,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
 	GLOBAL_DEF("display/fullscreen", video_mode.fullscreen);
 	GLOBAL_DEF("display/resizable", video_mode.resizable);
 	GLOBAL_DEF("display/borderless_window", video_mode.borderless_window);
+	GLOBAL_DEF("display/always_on_top", video_mode.always_on_top);
 	use_vsync = GLOBAL_DEF("display/use_vsync", use_vsync);
 	GLOBAL_DEF("display/test_width", 0);
 	GLOBAL_DEF("display/test_height", 0);
@@ -882,6 +889,9 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
 	} else if (init_fullscreen) {
 		OS::get_singleton()->set_window_fullscreen(true);
 	}
+	if (init_always_on_top) {
+		OS::get_singleton()->set_window_always_on_top(true);
+	}
 	MAIN_PRINT("Main: Load Remaps");
 
 	path_remap->load_remaps();

+ 19 - 0
platform/windows/os_windows.cpp

@@ -1040,6 +1040,10 @@ void OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int
 		}
 	};
 
+	if (video_mode.always_on_top) {
+		SetWindowPos(hWnd, video_mode.always_on_top ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+	}
+
 #if defined(OPENGL_ENABLED) || defined(GLES2_ENABLED) || defined(LEGACYGL_ENABLED)
 	gl_context = memnew(ContextGL_Win(hWnd, false));
 	gl_context->initialize();
@@ -1644,6 +1648,19 @@ bool OS_Windows::is_window_maximized() const {
 	return maximized;
 }
 
+void OS_Windows::set_window_always_on_top(bool p_enabled) {
+	if (video_mode.always_on_top == p_enabled)
+		return;
+
+	video_mode.always_on_top = p_enabled;
+
+	_update_window_style();
+}
+
+bool OS_Windows::is_window_always_on_top() const {
+	return video_mode.always_on_top;
+}
+
 void OS_Windows::set_borderless_window(int p_borderless) {
 	if (video_mode.borderless_window == p_borderless)
 		return;
@@ -1668,6 +1685,8 @@ void OS_Windows::_update_window_style(bool repaint) {
 		}
 	}
 
+	SetWindowPos(hWnd, video_mode.always_on_top ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+
 	if (repaint) {
 		RECT rect;
 		GetWindowRect(hWnd, &rect);

+ 2 - 0
platform/windows/os_windows.h

@@ -224,6 +224,8 @@ public:
 	virtual bool is_window_minimized() const;
 	virtual void set_window_maximized(bool p_enabled);
 	virtual bool is_window_maximized() const;
+	virtual void set_window_always_on_top(bool p_enabled);
+	virtual bool is_window_always_on_top() const;
 	virtual void request_attention();
 
 	virtual void set_borderless_window(int p_borderless);

+ 56 - 1
platform/x11/os_x11.cpp

@@ -263,7 +263,13 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
 
 	// borderless fullscreen window mode
 	if (current_videomode.fullscreen) {
-		set_wm_fullscreen(true);
+		current_videomode.fullscreen = false;
+		set_window_fullscreen(true);
+	}
+
+	if (current_videomode.always_on_top) {
+		current_videomode.always_on_top = false;
+		set_window_always_on_top(true);
 	}
 
 	// disable resizable window
@@ -723,6 +729,22 @@ void OS_X11::set_wm_fullscreen(bool p_enabled) {
 	}
 }
 
+void OS_X11::set_wm_above(bool p_enabled) {
+
+	Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
+	Atom wm_above = XInternAtom(x11_display, "_NET_WM_STATE_ABOVE", False);
+
+	XClientMessageEvent xev;
+	memset(&xev, 0, sizeof(xev));
+	xev.type = ClientMessage;
+	xev.window = x11_window;
+	xev.message_type = wm_state;
+	xev.format = 32;
+	xev.data.l[0] = p_enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
+	xev.data.l[1] = wm_above;
+	XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&xev);
+}
+
 int OS_X11::get_screen_count() const {
 	// Using Xinerama Extension
 	int event_base, error_base;
@@ -886,7 +908,19 @@ void OS_X11::set_window_size(const Size2 p_size) {
 }
 
 void OS_X11::set_window_fullscreen(bool p_enabled) {
+	if (p_enabled == current_videomode.fullscreen)
+		return;
+
+	if (p_enabled && current_videomode.always_on_top) {
+		// Fullscreen + Always-on-top requires a maximized window on some window managers (Metacity)
+		set_window_maximized(true);
+	}
 	set_wm_fullscreen(p_enabled);
+	if (!p_enabled && !current_videomode.always_on_top) {
+		// Restore
+		set_window_maximized(false);
+	}
+
 	current_videomode.fullscreen = p_enabled;
 }
 
@@ -1040,6 +1074,27 @@ bool OS_X11::is_window_maximized() const {
 	return false;
 }
 
+void OS_X11::set_window_always_on_top(bool p_enabled) {
+	if (current_videomode.always_on_top == p_enabled)
+		return;
+
+	if (p_enabled && current_videomode.fullscreen) {
+		// Fullscreen + Always-on-top requires a maximized window on some window managers (Metacity)
+		set_window_maximized(true);
+	}
+	set_wm_above(p_enabled);
+	if (!p_enabled && !current_videomode.fullscreen) {
+		// Restore
+		set_window_maximized(false);
+	}
+
+	current_videomode.always_on_top = p_enabled;
+}
+
+bool OS_X11::is_window_always_on_top() const {
+	return current_videomode.always_on_top;
+}
+
 void OS_X11::request_attention() {
 	// Using EWMH -- Extended Window Manager Hints
 	//

+ 3 - 0
platform/x11/os_x11.h

@@ -192,6 +192,7 @@ class OS_X11 : public OS_Unix {
 	bool maximized;
 	//void set_wm_border(bool p_enabled);
 	void set_wm_fullscreen(bool p_enabled);
+	void set_wm_above(bool p_enabled);
 
 	typedef xrr_monitor_info *(*xrr_get_monitors_t)(Display *dpy, Window window, Bool get_active, int *nmonitors);
 	typedef void (*xrr_free_monitors_t)(xrr_monitor_info *monitors);
@@ -267,6 +268,8 @@ public:
 	virtual bool is_window_minimized() const;
 	virtual void set_window_maximized(bool p_enabled);
 	virtual bool is_window_maximized() const;
+	virtual void set_window_always_on_top(bool p_enabled);
+	virtual bool is_window_always_on_top() const;
 	virtual void request_attention();
 
 	virtual void move_window_to_foreground();