Add new window setting: always on top
Implemented for Windows and Linux.
This commit is contained in:
parent
db49f35ab8
commit
ee2c31d306
8 changed files with 105 additions and 4 deletions
|
@ -294,6 +294,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);
|
||||
}
|
||||
|
@ -1010,6 +1018,8 @@ void _OS::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("is_window_minimized"), &_OS::is_window_minimized);
|
||||
ClassDB::bind_method(D_METHOD("set_window_maximized", "enabled"), &_OS::set_window_maximized);
|
||||
ClassDB::bind_method(D_METHOD("is_window_maximized"), &_OS::is_window_maximized);
|
||||
ClassDB::bind_method(D_METHOD("set_window_always_on_top", "enabled"), &_OS::set_window_always_on_top);
|
||||
ClassDB::bind_method(D_METHOD("is_window_always_on_top"), &_OS::is_window_always_on_top);
|
||||
ClassDB::bind_method(D_METHOD("request_attention"), &_OS::request_attention);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_borderless_window", "borderless"), &_OS::set_borderless_window);
|
||||
|
|
|
@ -164,6 +164,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);
|
||||
|
|
|
@ -94,15 +94,17 @@ public:
|
|||
bool resizable;
|
||||
bool borderless_window;
|
||||
bool maximized;
|
||||
bool always_on_top;
|
||||
bool use_vsync;
|
||||
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, bool p_maximized = false, bool p_use_vsync = 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_maximized = false, bool p_always_on_top = false, bool p_use_vsync = false) {
|
||||
width = p_width;
|
||||
height = p_height;
|
||||
fullscreen = p_fullscreen;
|
||||
resizable = p_resizable;
|
||||
borderless_window = p_borderless_window;
|
||||
maximized = p_maximized;
|
||||
always_on_top = p_always_on_top;
|
||||
use_vsync = p_use_vsync;
|
||||
}
|
||||
};
|
||||
|
@ -191,6 +193,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(bool p_borderless) {}
|
||||
|
|
|
@ -106,6 +106,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;
|
||||
|
@ -224,6 +225,7 @@ void Main::print_help(const char *p_binary) {
|
|||
OS::get_singleton()->print(" -f, --fullscreen Request fullscreen mode.\n");
|
||||
OS::get_singleton()->print(" -m, --maximized Request a maximized window.\n");
|
||||
OS::get_singleton()->print(" -w, --windowed Request windowed mode.\n");
|
||||
OS::get_singleton()->print(" -t, --always-on-top Request an always-on-top window.\n");
|
||||
OS::get_singleton()->print(" --resolution <W>x<H> Request window resolution.\n");
|
||||
OS::get_singleton()->print(" --position <X>,<Y> Request window position.\n");
|
||||
OS::get_singleton()->print(" --low-dpi Force low-DPI mode (macOS and Windows only).\n");
|
||||
|
@ -430,6 +432,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||
} else if (I->get() == "-w" || I->get() == "--windowed") { // force windowed window
|
||||
|
||||
init_windowed = true;
|
||||
} else if (I->get() == "-t" || I->get() == "--always-on-top") { // force always-on-top window
|
||||
|
||||
init_always_on_top = true;
|
||||
} else if (I->get() == "--profiling") { // enable profiling
|
||||
|
||||
use_debug_profiler = true;
|
||||
|
@ -795,6 +800,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||
GLOBAL_DEF("display/window/size/resizable", true);
|
||||
GLOBAL_DEF("display/window/size/borderless", false);
|
||||
GLOBAL_DEF("display/window/size/fullscreen", false);
|
||||
GLOBAL_DEF("display/window/size/always_on_top", false);
|
||||
GLOBAL_DEF("display/window/size/test_width", 0);
|
||||
GLOBAL_DEF("display/window/size/test_height", 0);
|
||||
|
||||
|
@ -817,6 +823,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||
video_mode.resizable = GLOBAL_GET("display/window/size/resizable");
|
||||
video_mode.borderless_window = GLOBAL_GET("display/window/size/borderless");
|
||||
video_mode.fullscreen = GLOBAL_GET("display/window/size/fullscreen");
|
||||
video_mode.always_on_top = GLOBAL_GET("display/window/size/always_on_top");
|
||||
}
|
||||
|
||||
if (!force_lowdpi) {
|
||||
|
@ -1020,6 +1027,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);
|
||||
}
|
||||
|
||||
register_server_types();
|
||||
|
||||
|
|
|
@ -1068,6 +1068,10 @@ Error 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)
|
||||
gl_context = memnew(ContextGL_Win(hWnd, true));
|
||||
gl_context->initialize();
|
||||
|
@ -1601,6 +1605,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(bool p_borderless) {
|
||||
if (video_mode.borderless_window == p_borderless)
|
||||
return;
|
||||
|
@ -1625,6 +1642,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);
|
||||
|
|
|
@ -210,6 +210,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);
|
||||
|
|
|
@ -333,6 +333,11 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
|
|||
XFree(xsh);
|
||||
}
|
||||
|
||||
if (current_videomode.always_on_top) {
|
||||
current_videomode.always_on_top = false;
|
||||
set_window_always_on_top(true);
|
||||
}
|
||||
|
||||
AudioDriverManager::initialize(p_audio_driver);
|
||||
|
||||
ERR_FAIL_COND_V(!visual_server, ERR_UNAVAILABLE);
|
||||
|
@ -710,9 +715,6 @@ void OS_X11::get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen) con
|
|||
}
|
||||
|
||||
void OS_X11::set_wm_fullscreen(bool p_enabled) {
|
||||
if (current_videomode.fullscreen == p_enabled)
|
||||
return;
|
||||
|
||||
if (p_enabled && !is_window_resizable()) {
|
||||
// Set the window as resizable to prevent window managers to ignore the fullscreen state flag.
|
||||
XSizeHints *xsh;
|
||||
|
@ -773,6 +775,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;
|
||||
xev.data.l[3] = 1;
|
||||
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;
|
||||
|
@ -947,7 +965,19 @@ void OS_X11::set_window_size(const Size2 p_size) {
|
|||
}
|
||||
|
||||
void OS_X11::set_window_fullscreen(bool p_enabled) {
|
||||
if (current_videomode.fullscreen == p_enabled)
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1154,6 +1184,27 @@ bool OS_X11::is_window_maximized() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
void OS_X11::set_window_always_on_top(bool p_enabled) {
|
||||
if (is_window_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::set_borderless_window(bool p_borderless) {
|
||||
|
||||
if (current_videomode.borderless_window == p_borderless)
|
||||
|
|
|
@ -178,6 +178,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);
|
||||
|
@ -260,6 +261,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);
|
||||
|
|
Loading…
Reference in a new issue