Add support for the custom initial screen for the main window, fix primary screen detection.

This commit is contained in:
bruvzg 2023-01-05 00:00:02 +02:00
parent 163f6f5fe8
commit 2718a7b7d3
No known key found for this signature in database
GPG key ID: 7960FCF39844EC38
27 changed files with 506 additions and 205 deletions

View file

@ -1240,6 +1240,14 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF_BASIC("display/window/size/mode", 0); GLOBAL_DEF_BASIC("display/window/size/mode", 0);
custom_prop_info["display/window/size/mode"] = PropertyInfo(Variant::INT, "display/window/size/mode", PROPERTY_HINT_ENUM, "Windowed,Minimized,Maximized,Fullscreen,Exclusive Fullscreen"); custom_prop_info["display/window/size/mode"] = PropertyInfo(Variant::INT, "display/window/size/mode", PROPERTY_HINT_ENUM, "Windowed,Minimized,Maximized,Fullscreen,Exclusive Fullscreen");
// Keep the enum values in sync with the `DisplayServer::SCREEN_` enum.
GLOBAL_DEF_BASIC("display/window/size/initial_screen", -2);
String screen_hints = "Primary Monitor:-2"; // Note: Main Window Monitor:-1 is not used for the main window, skip it.
for (int i = 0; i < 64; i++) {
screen_hints += ",Monitor " + itos(i + 1) + ":" + itos(i);
}
custom_prop_info["display/window/size/initial_screen"] = PropertyInfo(Variant::INT, "display/window/size/initial_screen", PROPERTY_HINT_ENUM, screen_hints);
GLOBAL_DEF_BASIC("display/window/size/resizable", true); GLOBAL_DEF_BASIC("display/window/size/resizable", true);
GLOBAL_DEF_BASIC("display/window/size/borderless", false); GLOBAL_DEF_BASIC("display/window/size/borderless", false);
GLOBAL_DEF("display/window/size/always_on_top", false); GLOBAL_DEF("display/window/size/always_on_top", false);

View file

@ -130,12 +130,25 @@
The names of built-in display servers are [code]Windows[/code], [code]macOS[/code], [code]X11[/code] (Linux), [code]Android[/code], [code]iOS[/code], [code]web[/code] (HTML5) and [code]headless[/code] (when started with the [code]--headless[/code] [url=$DOCS_URL/tutorials/editor/command_line_tutorial.html]command line argument[/url]). The names of built-in display servers are [code]Windows[/code], [code]macOS[/code], [code]X11[/code] (Linux), [code]Android[/code], [code]iOS[/code], [code]web[/code] (HTML5) and [code]headless[/code] (when started with the [code]--headless[/code] [url=$DOCS_URL/tutorials/editor/command_line_tutorial.html]command line argument[/url]).
</description> </description>
</method> </method>
<method name="get_primary_screen" qualifiers="const">
<return type="int" />
<description>
Returns index of the primary screen.
</description>
</method>
<method name="get_screen_count" qualifiers="const"> <method name="get_screen_count" qualifiers="const">
<return type="int" /> <return type="int" />
<description> <description>
Returns the number of displays available. Returns the number of displays available.
</description> </description>
</method> </method>
<method name="get_screen_from_rect" qualifiers="const">
<return type="int" />
<param index="0" name="rect" type="Rect2" />
<description>
Returns index of the screen which contains specified rectangle.
</description>
</method>
<method name="get_swap_cancel_ok"> <method name="get_swap_cancel_ok">
<return type="bool" /> <return type="bool" />
<description> <description>
@ -1521,6 +1534,9 @@
<constant name="MOUSE_MODE_CONFINED_HIDDEN" value="4" enum="MouseMode"> <constant name="MOUSE_MODE_CONFINED_HIDDEN" value="4" enum="MouseMode">
Confines the mouse cursor to the game window, and make it hidden. Confines the mouse cursor to the game window, and make it hidden.
</constant> </constant>
<constant name="SCREEN_PRIMARY" value="-2">
Represents the primary screen.
</constant>
<constant name="SCREEN_OF_MAIN_WINDOW" value="-1"> <constant name="SCREEN_OF_MAIN_WINDOW" value="-1">
Represents the screen where the main window is located. This is usually the default value in functions that allow specifying one of several screens. Represents the screen where the main window is located. This is usually the default value in functions that allow specifying one of several screens.
</constant> </constant>

View file

@ -596,6 +596,9 @@
Main window content is expanded to the full size of the window. Unlike a borderless window, the frame is left intact and can be used to resize the window, and the title bar is transparent, but has minimize/maximize/close buttons. Main window content is expanded to the full size of the window. Unlike a borderless window, the frame is left intact and can be used to resize the window, and the title bar is transparent, but has minimize/maximize/close buttons.
[b]Note:[/b] This setting is implemented only on macOS. [b]Note:[/b] This setting is implemented only on macOS.
</member> </member>
<member name="display/window/size/initial_screen" type="int" setter="" getter="" default="-2">
Main window initial screen.
</member>
<member name="display/window/size/mode" type="int" setter="" getter="" default="0"> <member name="display/window/size/mode" type="int" setter="" getter="" default="0">
Main window mode. See [enum DisplayServer.WindowMode] for possible values and how each mode behaves. Main window mode. See [enum DisplayServer.WindowMode] for possible values and how each mode behaves.
</member> </member>

View file

@ -503,7 +503,7 @@
<member name="content_scale_size" type="Vector2i" setter="set_content_scale_size" getter="get_content_scale_size" default="Vector2i(0, 0)"> <member name="content_scale_size" type="Vector2i" setter="set_content_scale_size" getter="get_content_scale_size" default="Vector2i(0, 0)">
Base size of the content (i.e. nodes that are drawn inside the window). If non-zero, [Window]'s content will be scaled when the window is resized to a different size. Base size of the content (i.e. nodes that are drawn inside the window). If non-zero, [Window]'s content will be scaled when the window is resized to a different size.
</member> </member>
<member name="current_screen" type="int" setter="set_current_screen" getter="get_current_screen" default="0"> <member name="current_screen" type="int" setter="set_current_screen" getter="get_current_screen">
The screen the window is currently on. The screen the window is currently on.
</member> </member>
<member name="exclusive" type="bool" setter="set_exclusive" getter="is_exclusive" default="false"> <member name="exclusive" type="bool" setter="set_exclusive" getter="is_exclusive" default="false">
@ -513,6 +513,8 @@
<member name="extend_to_title" type="bool" setter="set_flag" getter="get_flag" default="false"> <member name="extend_to_title" type="bool" setter="set_flag" getter="get_flag" default="false">
If [code]true[/code], the [Window] contents is expanded to the full size of the window, window title bar is transparent. If [code]true[/code], the [Window] contents is expanded to the full size of the window, window title bar is transparent.
</member> </member>
<member name="initial_position" type="int" setter="set_initial_position" getter="get_initial_position" enum="Window.WindowInitialPosition" default="0">
</member>
<member name="max_size" type="Vector2i" setter="set_max_size" getter="get_max_size" default="Vector2i(0, 0)"> <member name="max_size" type="Vector2i" setter="set_max_size" getter="get_max_size" default="Vector2i(0, 0)">
If non-zero, the [Window] can't be resized to be bigger than this size. If non-zero, the [Window] can't be resized to be bigger than this size.
[b]Note:[/b] This property will be ignored if the value is lower than [member min_size]. [b]Note:[/b] This property will be ignored if the value is lower than [member min_size].
@ -732,6 +734,10 @@
<constant name="LAYOUT_DIRECTION_RTL" value="3" enum="LayoutDirection"> <constant name="LAYOUT_DIRECTION_RTL" value="3" enum="LayoutDirection">
Right-to-left layout direction. Right-to-left layout direction.
</constant> </constant>
<constant name="WINDOW_INITIAL_POSITION_ABSOLUTE" value="0" enum="WindowInitialPosition">
</constant>
<constant name="WINDOW_INITIAL_POSITION_CENTER_SCREEN" value="1" enum="WindowInitialPosition">
</constant>
</constants> </constants>
<theme_items> <theme_items>
<theme_item name="title_color" data_type="color" type="Color" default="Color(0.875, 0.875, 0.875, 1)"> <theme_item name="title_color" data_type="color" type="Color" default="Color(0.875, 0.875, 0.875, 1)">

View file

@ -93,30 +93,24 @@ Error EditorRun::run(const String &p_scene, const String &p_write_movie) {
} }
int screen = EDITOR_GET("run/window_placement/screen"); int screen = EDITOR_GET("run/window_placement/screen");
if (screen == 0) { if (screen == -5) {
// Same as editor // Same as editor
screen = DisplayServer::get_singleton()->window_get_current_screen(); screen = DisplayServer::get_singleton()->window_get_current_screen();
} else if (screen == 1) { } else if (screen == -4) {
// Previous monitor (wrap to the other end if needed) // Previous monitor (wrap to the other end if needed)
screen = Math::wrapi( screen = Math::wrapi(
DisplayServer::get_singleton()->window_get_current_screen() - 1, DisplayServer::get_singleton()->window_get_current_screen() - 1,
0, 0,
DisplayServer::get_singleton()->get_screen_count()); DisplayServer::get_singleton()->get_screen_count());
} else if (screen == 2) { } else if (screen == -3) {
// Next monitor (wrap to the other end if needed) // Next monitor (wrap to the other end if needed)
screen = Math::wrapi( screen = Math::wrapi(
DisplayServer::get_singleton()->window_get_current_screen() + 1, DisplayServer::get_singleton()->window_get_current_screen() + 1,
0, 0,
DisplayServer::get_singleton()->get_screen_count()); DisplayServer::get_singleton()->get_screen_count());
} else {
// Fixed monitor ID
// There are 3 special options, so decrement the option ID by 3 to get the monitor ID
screen -= 3;
} }
Rect2 screen_rect; Rect2 screen_rect = DisplayServer::get_singleton()->screen_get_usable_rect(screen);
screen_rect.position = DisplayServer::get_singleton()->screen_get_position(screen);
screen_rect.size = DisplayServer::get_singleton()->screen_get_size(screen);
int window_placement = EDITOR_GET("run/window_placement/rect"); int window_placement = EDITOR_GET("run/window_placement/rect");
if (screen_rect != Rect2()) { if (screen_rect != Rect2()) {
@ -169,13 +163,13 @@ Error EditorRun::run(const String &p_scene, const String &p_write_movie) {
args.push_back(itos(pos.x) + "," + itos(pos.y)); args.push_back(itos(pos.x) + "," + itos(pos.y));
} break; } break;
case 3: { // force maximized case 3: { // force maximized
Vector2 pos = screen_rect.position; Vector2 pos = screen_rect.position + screen_rect.size / 2;
args.push_back("--position"); args.push_back("--position");
args.push_back(itos(pos.x) + "," + itos(pos.y)); args.push_back(itos(pos.x) + "," + itos(pos.y));
args.push_back("--maximized"); args.push_back("--maximized");
} break; } break;
case 4: { // force fullscreen case 4: { // force fullscreen
Vector2 pos = screen_rect.position; Vector2 pos = screen_rect.position + screen_rect.size / 2;
args.push_back("--position"); args.push_back("--position");
args.push_back(itos(pos.x) + "," + itos(pos.y)); args.push_back(itos(pos.x) + "," + itos(pos.y));
args.push_back("--fullscreen"); args.push_back("--fullscreen");

View file

@ -697,12 +697,13 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
// Window placement // Window placement
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "run/window_placement/rect", 1, "Top Left,Centered,Custom Position,Force Maximized,Force Fullscreen") EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "run/window_placement/rect", 1, "Top Left,Centered,Custom Position,Force Maximized,Force Fullscreen")
String screen_hints = "Same as Editor,Previous Monitor,Next Monitor"; // Keep the enum values in sync with the `DisplayServer::SCREEN_` enum.
String screen_hints = "Same as Editor:-5,Previous Monitor:-4,Next Monitor:-3,Primary Monitor:-2"; // Note: Main Window Screen:-1 is not used for the main window.
for (int i = 0; i < DisplayServer::get_singleton()->get_screen_count(); i++) { for (int i = 0; i < DisplayServer::get_singleton()->get_screen_count(); i++) {
screen_hints += ",Monitor " + itos(i + 1); screen_hints += ",Monitor " + itos(i + 1) + ":" + itos(i);
} }
_initial_set("run/window_placement/rect_custom_position", Vector2()); _initial_set("run/window_placement/rect_custom_position", Vector2());
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "run/window_placement/screen", 0, screen_hints) EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "run/window_placement/screen", -5, screen_hints)
// Auto save // Auto save
_initial_set("run/auto_save/save_before_running", true); _initial_set("run/auto_save/save_before_running", true);

View file

@ -3014,16 +3014,15 @@ ProjectManager::ProjectManager() {
float scale_factor = MAX(1, EDSCALE); float scale_factor = MAX(1, EDSCALE);
if (scale_factor > 1.0) { if (scale_factor > 1.0) {
Vector2i window_size = DisplayServer::get_singleton()->window_get_size(); Vector2i window_size = DisplayServer::get_singleton()->window_get_size();
Vector2i screen_size = DisplayServer::get_singleton()->screen_get_size(); Rect2i screen_rect = DisplayServer::get_singleton()->screen_get_usable_rect(DisplayServer::get_singleton()->window_get_current_screen());
Vector2i screen_position = DisplayServer::get_singleton()->screen_get_position();
window_size *= scale_factor; window_size *= scale_factor;
DisplayServer::get_singleton()->window_set_size(window_size); DisplayServer::get_singleton()->window_set_size(window_size);
if (screen_size != Vector2i()) { if (screen_rect.size != Vector2i()) {
Vector2i window_position; Vector2i window_position;
window_position.x = screen_position.x + (screen_size.x - window_size.x) / 2; window_position.x = screen_rect.position.x + (screen_rect.size.x - window_size.x) / 2;
window_position.y = screen_position.y + (screen_size.y - window_size.y) / 2; window_position.y = screen_rect.position.y + (screen_rect.size.y - window_size.y) / 2;
DisplayServer::get_singleton()->window_set_position(window_position); DisplayServer::get_singleton()->window_set_position(window_position);
} }
} }

View file

@ -179,7 +179,7 @@ static DisplayServer::VSyncMode window_vsync_mode = DisplayServer::VSYNC_ENABLED
static uint32_t window_flags = 0; static uint32_t window_flags = 0;
static Size2i window_size = Size2i(1152, 648); static Size2i window_size = Size2i(1152, 648);
static int init_screen = -1; static int init_screen = DisplayServer::SCREEN_PRIMARY;
static bool init_fullscreen = false; static bool init_fullscreen = false;
static bool init_maximized = false; static bool init_maximized = false;
static bool init_windowed = false; static bool init_windowed = false;
@ -377,7 +377,8 @@ void Main::print_help(const char *p_binary) {
OS::get_singleton()->print(" -w, --windowed Request windowed mode.\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(" -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(" --resolution <W>x<H> Request window resolution.\n");
OS::get_singleton()->print(" --position <X>,<Y> Request window position.\n"); OS::get_singleton()->print(" --position <X>,<Y> Request window position (if set, screen argument is ignored).\n");
OS::get_singleton()->print(" --screen <N> Request window screen.\n");
OS::get_singleton()->print(" --single-window Use a single window (no separate subwindows).\n"); OS::get_singleton()->print(" --single-window Use a single window (no separate subwindows).\n");
OS::get_singleton()->print(" --xr-mode <mode> Select XR (Extended Reality) mode ['default', 'off', 'on'].\n"); OS::get_singleton()->print(" --xr-mode <mode> Select XR (Extended Reality) mode ['default', 'off', 'on'].\n");
OS::get_singleton()->print("\n"); OS::get_singleton()->print("\n");
@ -959,6 +960,17 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
goto error; goto error;
} }
} else if (I->get() == "--screen") { // set window screen
if (I->next()) {
init_screen = I->next()->get().to_int();
N = I->next()->next();
} else {
OS::get_singleton()->print("Missing screen argument, aborting.\n");
goto error;
}
} else if (I->get() == "--position") { // set window position } else if (I->get() == "--position") { // set window position
if (I->next()) { if (I->next()) {
@ -1658,6 +1670,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
window_flags |= DisplayServer::WINDOW_FLAG_NO_FOCUS_BIT; window_flags |= DisplayServer::WINDOW_FLAG_NO_FOCUS_BIT;
} }
window_mode = (DisplayServer::WindowMode)(GLOBAL_GET("display/window/size/mode").operator int()); window_mode = (DisplayServer::WindowMode)(GLOBAL_GET("display/window/size/mode").operator int());
init_screen = GLOBAL_GET("display/window/size/initial_screen").operator int();
} }
GLOBAL_DEF("internationalization/locale/include_text_server_data", false); GLOBAL_DEF("internationalization/locale/include_text_server_data", false);
@ -1909,7 +1922,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
// rendering_driver now held in static global String in main and initialized in setup() // rendering_driver now held in static global String in main and initialized in setup()
Error err; Error err;
display_server = DisplayServer::create(display_driver_idx, rendering_driver, window_mode, window_vsync_mode, window_flags, window_position, window_size, err); display_server = DisplayServer::create(display_driver_idx, rendering_driver, window_mode, window_vsync_mode, window_flags, window_position, window_size, init_screen, err);
if (err != OK || display_server == nullptr) { if (err != OK || display_server == nullptr) {
// We can't use this display server, try other ones as fallback. // We can't use this display server, try other ones as fallback.
// Skip headless (always last registered) because that's not what users // Skip headless (always last registered) because that's not what users
@ -1918,7 +1931,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
if (i == display_driver_idx) { if (i == display_driver_idx) {
continue; // Don't try the same twice. continue; // Don't try the same twice.
} }
display_server = DisplayServer::create(i, rendering_driver, window_mode, window_vsync_mode, window_flags, window_position, window_size, err); display_server = DisplayServer::create(i, rendering_driver, window_mode, window_vsync_mode, window_flags, window_position, window_size, init_screen, err);
if (err == OK && display_server != nullptr) { if (err == OK && display_server != nullptr) {
break; break;
} }
@ -2015,10 +2028,6 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
print_line(" "); //add a blank line for readability print_line(" "); //add a blank line for readability
if (init_use_custom_pos) {
display_server->window_set_position(init_custom_pos);
}
// right moment to create and initialize the audio server // right moment to create and initialize the audio server
audio_server = memnew(AudioServer); audio_server = memnew(AudioServer);
@ -2037,9 +2046,6 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
bool show_logo = true; bool show_logo = true;
#endif #endif
if (init_screen != -1) {
DisplayServer::get_singleton()->window_set_current_screen(init_screen);
}
if (init_windowed) { if (init_windowed) {
//do none.. //do none..
} else if (init_maximized) { } else if (init_maximized) {

View file

@ -184,6 +184,10 @@ int DisplayServerAndroid::get_screen_count() const {
return 1; return 1;
} }
int DisplayServerAndroid::get_primary_screen() const {
return 0;
}
Point2i DisplayServerAndroid::screen_get_position(int p_screen) const { Point2i DisplayServerAndroid::screen_get_position(int p_screen) const {
return Point2i(0, 0); return Point2i(0, 0);
} }
@ -459,8 +463,8 @@ Vector<String> DisplayServerAndroid::get_rendering_drivers_func() {
return drivers; return drivers;
} }
DisplayServer *DisplayServerAndroid::create_func(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) { DisplayServer *DisplayServerAndroid::create_func(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error) {
DisplayServer *ds = memnew(DisplayServerAndroid(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, r_error)); DisplayServer *ds = memnew(DisplayServerAndroid(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, r_error));
if (r_error != OK) { if (r_error != OK) {
OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan versions.", "Unable to initialize Video driver"); OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan versions.", "Unable to initialize Video driver");
if (p_rendering_driver == "vulkan") { if (p_rendering_driver == "vulkan") {
@ -512,7 +516,7 @@ void DisplayServerAndroid::notify_surface_changed(int p_width, int p_height) {
rect_changed_callback.callp(reinterpret_cast<const Variant **>(&sizep), 1, ret, ce); rect_changed_callback.callp(reinterpret_cast<const Variant **>(&sizep), 1, ret, ce);
} }
DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) { DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error) {
rendering_driver = p_rendering_driver; rendering_driver = p_rendering_driver;
keep_screen_on = GLOBAL_GET("display/window/energy_saving/keep_screen_on"); keep_screen_on = GLOBAL_GET("display/window/energy_saving/keep_screen_on");

View file

@ -115,6 +115,7 @@ public:
virtual ScreenOrientation screen_get_orientation(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual ScreenOrientation screen_get_orientation(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual int get_screen_count() const override; virtual int get_screen_count() const override;
virtual int get_primary_screen() const override;
virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
@ -198,7 +199,7 @@ public:
virtual void mouse_set_mode(MouseMode p_mode) override; virtual void mouse_set_mode(MouseMode p_mode) override;
virtual MouseMode mouse_get_mode() const override; virtual MouseMode mouse_get_mode() const override;
static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error); static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error);
static Vector<String> get_rendering_drivers_func(); static Vector<String> get_rendering_drivers_func();
static void register_android_driver(); static void register_android_driver();
@ -215,7 +216,7 @@ public:
virtual void set_native_icon(const String &p_filename) override; virtual void set_native_icon(const String &p_filename) override;
virtual void set_icon(const Ref<Image> &p_icon) override; virtual void set_icon(const Ref<Image> &p_icon) override;
DisplayServerAndroid(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error); DisplayServerAndroid(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error);
~DisplayServerAndroid(); ~DisplayServerAndroid();
}; };

View file

@ -75,7 +75,7 @@ class DisplayServerIOS : public DisplayServer {
void perform_event(const Ref<InputEvent> &p_event); void perform_event(const Ref<InputEvent> &p_event);
DisplayServerIOS(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error); DisplayServerIOS(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error);
~DisplayServerIOS(); ~DisplayServerIOS();
public: public:
@ -84,7 +84,7 @@ public:
static DisplayServerIOS *get_singleton(); static DisplayServerIOS *get_singleton();
static void register_ios_driver(); static void register_ios_driver();
static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error); static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error);
static Vector<String> get_rendering_drivers_func(); static Vector<String> get_rendering_drivers_func();
// MARK: - Events // MARK: - Events
@ -139,6 +139,7 @@ public:
virtual Rect2i get_display_safe_area() const override; virtual Rect2i get_display_safe_area() const override;
virtual int get_screen_count() const override; virtual int get_screen_count() const override;
virtual int get_primary_screen() const override;
virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;

View file

@ -49,7 +49,7 @@ DisplayServerIOS *DisplayServerIOS::get_singleton() {
return (DisplayServerIOS *)DisplayServer::get_singleton(); return (DisplayServerIOS *)DisplayServer::get_singleton();
} }
DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) { DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error) {
rendering_driver = p_rendering_driver; rendering_driver = p_rendering_driver;
// Init TTS // Init TTS
@ -151,8 +151,8 @@ DisplayServerIOS::~DisplayServerIOS() {
#endif #endif
} }
DisplayServer *DisplayServerIOS::create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) { DisplayServer *DisplayServerIOS::create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error) {
return memnew(DisplayServerIOS(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, r_error)); return memnew(DisplayServerIOS(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, r_error));
} }
Vector<String> DisplayServerIOS::get_rendering_drivers_func() { Vector<String> DisplayServerIOS::get_rendering_drivers_func() {
@ -379,6 +379,10 @@ int DisplayServerIOS::get_screen_count() const {
return 1; return 1;
} }
int DisplayServerIOS::get_primary_screen() const {
return 0;
}
Point2i DisplayServerIOS::screen_get_position(int p_screen) const { Point2i DisplayServerIOS::screen_get_position(int p_screen) const {
return Size2i(); return Size2i();
} }

View file

@ -751,11 +751,22 @@ int DisplayServerX11::get_screen_count() const {
return count; return count;
} }
int DisplayServerX11::get_primary_screen() const {
return XDefaultScreen(x11_display);
}
Rect2i DisplayServerX11::_screen_get_rect(int p_screen) const { Rect2i DisplayServerX11::_screen_get_rect(int p_screen) const {
Rect2i rect(0, 0, 0, 0); Rect2i rect(0, 0, 0, 0);
if (p_screen == SCREEN_OF_MAIN_WINDOW) { switch (p_screen) {
p_screen = window_get_current_screen(); case SCREEN_PRIMARY: {
p_screen = get_primary_screen();
} break;
case SCREEN_OF_MAIN_WINDOW: {
p_screen = window_get_current_screen(MAIN_WINDOW_ID);
} break;
default:
break;
} }
ERR_FAIL_COND_V(p_screen < 0, rect); ERR_FAIL_COND_V(p_screen < 0, rect);
@ -822,8 +833,15 @@ int bad_window_error_handler(Display *display, XErrorEvent *error) {
Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const { Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const {
_THREAD_SAFE_METHOD_ _THREAD_SAFE_METHOD_
if (p_screen == SCREEN_OF_MAIN_WINDOW) { switch (p_screen) {
p_screen = window_get_current_screen(); case SCREEN_PRIMARY: {
p_screen = get_primary_screen();
} break;
case SCREEN_OF_MAIN_WINDOW: {
p_screen = window_get_current_screen(MAIN_WINDOW_ID);
} break;
default:
break;
} }
int screen_count = get_screen_count(); int screen_count = get_screen_count();
@ -1102,8 +1120,15 @@ Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const {
int DisplayServerX11::screen_get_dpi(int p_screen) const { int DisplayServerX11::screen_get_dpi(int p_screen) const {
_THREAD_SAFE_METHOD_ _THREAD_SAFE_METHOD_
if (p_screen == SCREEN_OF_MAIN_WINDOW) { switch (p_screen) {
p_screen = window_get_current_screen(); case SCREEN_PRIMARY: {
p_screen = get_primary_screen();
} break;
case SCREEN_OF_MAIN_WINDOW: {
p_screen = window_get_current_screen(MAIN_WINDOW_ID);
} break;
default:
break;
} }
//invalid screen? //invalid screen?
@ -1147,8 +1172,15 @@ int DisplayServerX11::screen_get_dpi(int p_screen) const {
float DisplayServerX11::screen_get_refresh_rate(int p_screen) const { float DisplayServerX11::screen_get_refresh_rate(int p_screen) const {
_THREAD_SAFE_METHOD_ _THREAD_SAFE_METHOD_
if (p_screen == SCREEN_OF_MAIN_WINDOW) { switch (p_screen) {
p_screen = window_get_current_screen(); case SCREEN_PRIMARY: {
p_screen = get_primary_screen();
} break;
case SCREEN_OF_MAIN_WINDOW: {
p_screen = window_get_current_screen(MAIN_WINDOW_ID);
} break;
default:
break;
} }
//invalid screen? //invalid screen?
@ -1235,10 +1267,10 @@ Vector<DisplayServer::WindowID> DisplayServerX11::get_window_list() const {
return ret; return ret;
} }
DisplayServer::WindowID DisplayServerX11::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, int p_screen) { DisplayServer::WindowID DisplayServerX11::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) {
_THREAD_SAFE_METHOD_ _THREAD_SAFE_METHOD_
WindowID id = _create_window(p_mode, p_vsync_mode, p_flags, p_rect, p_screen); WindowID id = _create_window(p_mode, p_vsync_mode, p_flags, p_rect);
for (int i = 0; i < WINDOW_FLAG_MAX; i++) { for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
if (p_flags & (1 << i)) { if (p_flags & (1 << i)) {
window_set_flag(WindowFlags(i), true, id); window_set_flag(WindowFlags(i), true, id);
@ -1500,8 +1532,15 @@ void DisplayServerX11::window_set_current_screen(int p_screen, WindowID p_window
ERR_FAIL_COND(!windows.has(p_window)); ERR_FAIL_COND(!windows.has(p_window));
WindowData &wd = windows[p_window]; WindowData &wd = windows[p_window];
if (p_screen == SCREEN_OF_MAIN_WINDOW) { switch (p_screen) {
p_screen = window_get_current_screen(); case SCREEN_PRIMARY: {
p_screen = get_primary_screen();
} break;
case SCREEN_OF_MAIN_WINDOW: {
p_screen = window_get_current_screen(MAIN_WINDOW_ID);
} break;
default:
break;
} }
// Check if screen is valid // Check if screen is valid
@ -1521,9 +1560,10 @@ void DisplayServerX11::window_set_current_screen(int p_screen, WindowID p_window
Point2i wpos = window_get_position(p_window) - screen_get_position(window_get_current_screen(p_window)); Point2i wpos = window_get_position(p_window) - screen_get_position(window_get_current_screen(p_window));
Size2i wsize = window_get_size(p_window); Size2i wsize = window_get_size(p_window);
wpos += srect.position; wpos += srect.position;
if (srect != Rect2i()) {
wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - wsize.width / 3); wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - wsize.width / 3);
wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - wsize.height / 3); wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - wsize.height / 3);
}
window_set_position(wpos, p_window); window_set_position(wpos, p_window);
} }
} }
@ -4519,8 +4559,8 @@ Vector<String> DisplayServerX11::get_rendering_drivers_func() {
return drivers; return drivers;
} }
DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) { DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error) {
DisplayServer *ds = memnew(DisplayServerX11(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, r_error)); DisplayServer *ds = memnew(DisplayServerX11(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, r_error));
if (r_error != OK) { if (r_error != OK) {
if (p_rendering_driver == "vulkan") { if (p_rendering_driver == "vulkan") {
String executable_name = OS::get_singleton()->get_executable_path().get_file(); String executable_name = OS::get_singleton()->get_executable_path().get_file();
@ -4541,7 +4581,7 @@ DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, W
return ds; return ds;
} }
DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, int p_screen) { DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) {
//Create window //Create window
XVisualInfo visualInfo; XVisualInfo visualInfo;
@ -4617,30 +4657,19 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
valuemask |= CWOverrideRedirect | CWSaveUnder; valuemask |= CWOverrideRedirect | CWSaveUnder;
} }
int rq_screen = get_screen_from_rect(p_rect);
if (rq_screen < 0) {
rq_screen = get_primary_screen(); // Requested window rect is outside any screen bounds.
}
Rect2i win_rect = p_rect; Rect2i win_rect = p_rect;
if (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) { if (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
Rect2i screen_rect = Rect2i(screen_get_position(p_screen), screen_get_size(p_screen)); Rect2i screen_rect = Rect2i(screen_get_position(rq_screen), screen_get_size(rq_screen));
win_rect = screen_rect; win_rect = screen_rect;
} else { } else {
int nearest_area = 0; Rect2i srect = screen_get_usable_rect(rq_screen);
int pos_screen = -1; Point2i wpos = p_rect.position;
for (int i = 0; i < get_screen_count(); i++) {
Rect2i r;
r.position = screen_get_position(i);
r.size = screen_get_size(i);
Rect2 inters = r.intersection(p_rect);
int area = inters.size.width * inters.size.height;
if (area > nearest_area) {
pos_screen = i;
nearest_area = area;
}
}
Rect2i srect = screen_get_usable_rect(p_screen);
Point2i wpos = p_rect.position - ((pos_screen >= 0) ? screen_get_position(pos_screen) : Vector2i());
wpos += srect.position;
wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - p_rect.size.width / 3); wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - p_rect.size.width / 3);
wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - p_rect.size.height / 3); wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - p_rect.size.height / 3);
@ -4811,7 +4840,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
return id; return id;
} }
DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) { DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error) {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
int dylibloader_verbose = 1; int dylibloader_verbose = 1;
#else #else
@ -5075,16 +5104,17 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
ERR_FAIL_MSG("Video driver not found"); ERR_FAIL_MSG("Video driver not found");
} }
Point2i window_position( Point2i window_position;
(screen_get_size(0).width - p_resolution.width) / 2,
(screen_get_size(0).height - p_resolution.height) / 2);
window_position += screen_get_position(0);
if (p_position != nullptr) { if (p_position != nullptr) {
window_position = *p_position; window_position = *p_position;
} else {
if (p_screen == SCREEN_OF_MAIN_WINDOW) {
p_screen = SCREEN_PRIMARY;
}
window_position = screen_get_position(p_screen) + (screen_get_size(p_screen) - p_resolution) / 2;
} }
WindowID main_window = _create_window(p_mode, p_vsync_mode, p_flags, Rect2i(window_position, p_resolution), 0); WindowID main_window = _create_window(p_mode, p_vsync_mode, p_flags, Rect2i(window_position, p_resolution));
if (main_window == INVALID_WINDOW_ID) { if (main_window == INVALID_WINDOW_ID) {
r_error = ERR_CANT_CREATE; r_error = ERR_CANT_CREATE;
return; return;

View file

@ -185,7 +185,7 @@ class DisplayServerX11 : public DisplayServer {
WindowID last_focused_window = INVALID_WINDOW_ID; WindowID last_focused_window = INVALID_WINDOW_ID;
WindowID window_id_counter = MAIN_WINDOW_ID; WindowID window_id_counter = MAIN_WINDOW_ID;
WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, int p_screen); WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect);
String internal_clipboard; String internal_clipboard;
String internal_clipboard_primary; String internal_clipboard_primary;
@ -352,6 +352,7 @@ public:
virtual String clipboard_get_primary() const override; virtual String clipboard_get_primary() const override;
virtual int get_screen_count() const override; virtual int get_screen_count() const override;
virtual int get_primary_screen() const override;
virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
@ -365,7 +366,7 @@ public:
virtual Vector<DisplayServer::WindowID> get_window_list() const override; 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(), int p_screen = 0) override; virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()) override;
virtual void show_window(WindowID p_id) override; virtual void show_window(WindowID p_id) override;
virtual void delete_sub_window(WindowID p_id) override; virtual void delete_sub_window(WindowID p_id) override;
@ -453,12 +454,12 @@ public:
virtual void set_native_icon(const String &p_filename) override; virtual void set_native_icon(const String &p_filename) override;
virtual void set_icon(const Ref<Image> &p_icon) override; virtual void set_icon(const Ref<Image> &p_icon) override;
static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error); static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error);
static Vector<String> get_rendering_drivers_func(); static Vector<String> get_rendering_drivers_func();
static void register_x11_driver(); static void register_x11_driver();
DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error); DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error);
~DisplayServerX11(); ~DisplayServerX11();
}; };

View file

@ -191,7 +191,7 @@ private:
const NSMenu *_get_menu_root(const String &p_menu_root) const; const NSMenu *_get_menu_root(const String &p_menu_root) const;
NSMenu *_get_menu_root(const String &p_menu_root); NSMenu *_get_menu_root(const String &p_menu_root);
WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, const Rect2i &p_rect, int p_screen); WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, const Rect2i &p_rect);
void _update_window_style(WindowData p_wd); void _update_window_style(WindowData p_wd);
void _set_window_per_pixel_transparency_enabled(bool p_enabled, WindowID p_window); void _set_window_per_pixel_transparency_enabled(bool p_enabled, WindowID p_window);
@ -324,6 +324,7 @@ public:
virtual String clipboard_get() const override; virtual String clipboard_get() const override;
virtual int get_screen_count() const override; virtual int get_screen_count() const override;
virtual int get_primary_screen() const override;
virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
@ -336,7 +337,7 @@ public:
virtual Vector<int> get_window_list() const override; virtual Vector<int> 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(), int p_screen = 0) override; virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()) override;
virtual void show_window(WindowID p_id) override; virtual void show_window(WindowID p_id) override;
virtual void delete_sub_window(WindowID p_id) override; virtual void delete_sub_window(WindowID p_id) override;
@ -435,12 +436,12 @@ public:
virtual void set_native_icon(const String &p_filename) override; virtual void set_native_icon(const String &p_filename) override;
virtual void set_icon(const Ref<Image> &p_icon) override; virtual void set_icon(const Ref<Image> &p_icon) override;
static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error); static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error);
static Vector<String> get_rendering_drivers_func(); static Vector<String> get_rendering_drivers_func();
static void register_macos_driver(); static void register_macos_driver();
DisplayServerMacOS(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error); DisplayServerMacOS(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error);
~DisplayServerMacOS(); ~DisplayServerMacOS();
}; };

View file

@ -109,7 +109,7 @@ NSMenu *DisplayServerMacOS::_get_menu_root(const String &p_menu_root) {
return menu; return menu;
} }
DisplayServerMacOS::WindowID DisplayServerMacOS::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, const Rect2i &p_rect, int p_screen) { DisplayServerMacOS::WindowID DisplayServerMacOS::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, const Rect2i &p_rect) {
WindowID id; WindowID id;
const float scale = screen_get_max_scale(); const float scale = screen_get_max_scale();
{ {
@ -119,36 +119,30 @@ DisplayServerMacOS::WindowID DisplayServerMacOS::_create_window(WindowMode p_mod
ERR_FAIL_COND_V_MSG(wd.window_delegate == nil, INVALID_WINDOW_ID, "Can't create a window delegate"); ERR_FAIL_COND_V_MSG(wd.window_delegate == nil, INVALID_WINDOW_ID, "Can't create a window delegate");
[wd.window_delegate setWindowID:window_id_counter]; [wd.window_delegate setWindowID:window_id_counter];
int nearest_area = 0; int rq_screen = get_screen_from_rect(p_rect);
int pos_screen = -1; if (rq_screen < 0) {
for (int i = 0; i < get_screen_count(); i++) { rq_screen = get_primary_screen(); // Requested window rect is outside any screen bounds.
Rect2i r = screen_get_usable_rect(i);
Rect2 inters = r.intersection(p_rect);
int area = inters.size.width * inters.size.height;
if (area > nearest_area && area > 0) {
pos_screen = i;
nearest_area = area;
}
} }
Rect2i srect = screen_get_usable_rect(p_screen); Rect2i srect = screen_get_usable_rect(rq_screen);
Point2i wpos = p_rect.position - ((pos_screen >= 0) ? screen_get_position(pos_screen) : Vector2i()); Point2i wpos = p_rect.position;
wpos += srect.position; if (srect != Rect2i()) {
wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - p_rect.size.width / 3); wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - p_rect.size.width / 3);
wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - p_rect.size.height / 3); wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - p_rect.size.height / 3);
}
// OS X native y-coordinate relative to _get_screens_origin() is negative, // OS X native y-coordinate relative to _get_screens_origin() is negative,
// Godot passes a positive value. // Godot passes a positive value.
wpos.y *= -1; wpos.y *= -1;
wpos += _get_screens_origin(); wpos += _get_screens_origin();
wpos /= scale;
// initWithContentRect uses bottom-left corner of the windows frame as origin. // initWithContentRect uses bottom-left corner of the windows frame as origin.
wd.window_object = [[GodotWindow alloc] wd.window_object = [[GodotWindow alloc]
initWithContentRect:NSMakeRect(0, 0, p_rect.size.width / scale, p_rect.size.height / scale) initWithContentRect:NSMakeRect(100, 100, p_rect.size.width / scale, p_rect.size.height / scale)
styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable
backing:NSBackingStoreBuffered backing:NSBackingStoreBuffered
defer:NO]; defer:NO];
ERR_FAIL_COND_V_MSG(wd.window_object == nil, INVALID_WINDOW_ID, "Can't create a window"); ERR_FAIL_COND_V_MSG(wd.window_object == nil, INVALID_WINDOW_ID, "Can't create a window");
[wd.window_object setFrameTopLeftPoint:NSMakePoint(wpos.x / scale, wpos.y / scale)];
[wd.window_object setWindowID:window_id_counter]; [wd.window_object setWindowID:window_id_counter];
wd.window_view = [[GodotContentView alloc] init]; wd.window_view = [[GodotContentView alloc] init];
@ -186,6 +180,16 @@ DisplayServerMacOS::WindowID DisplayServerMacOS::_create_window(WindowMode p_mod
window_set_vsync_mode(p_vsync_mode, window_id_counter); window_set_vsync_mode(p_vsync_mode, window_id_counter);
#endif #endif
[wd.window_view updateLayerDelegate]; [wd.window_view updateLayerDelegate];
const NSRect contentRect = [wd.window_view frame];
const NSRect windowRect = [wd.window_object frame];
const NSRect nsrect = [wd.window_object convertRectToScreen:contentRect];
Point2i offset;
offset.x = (nsrect.origin.x - windowRect.origin.x);
offset.y = (nsrect.origin.y + nsrect.size.height);
offset.y -= (windowRect.origin.y + windowRect.size.height);
[wd.window_object setFrameTopLeftPoint:NSMakePoint(wpos.x - offset.x, wpos.y - offset.y)];
id = window_id_counter++; id = window_id_counter++;
windows[id] = wd; windows[id] = wd;
} }
@ -2077,11 +2081,22 @@ int DisplayServerMacOS::get_screen_count() const {
return [screenArray count]; return [screenArray count];
} }
int DisplayServerMacOS::get_primary_screen() const {
return 0;
}
Point2i DisplayServerMacOS::screen_get_position(int p_screen) const { Point2i DisplayServerMacOS::screen_get_position(int p_screen) const {
_THREAD_SAFE_METHOD_ _THREAD_SAFE_METHOD_
if (p_screen == SCREEN_OF_MAIN_WINDOW) { switch (p_screen) {
p_screen = window_get_current_screen(); case SCREEN_PRIMARY: {
p_screen = get_primary_screen();
} break;
case SCREEN_OF_MAIN_WINDOW: {
p_screen = window_get_current_screen(MAIN_WINDOW_ID);
} break;
default:
break;
} }
Point2i position = _get_native_screen_position(p_screen) - _get_screens_origin(); Point2i position = _get_native_screen_position(p_screen) - _get_screens_origin();
@ -2094,8 +2109,15 @@ Point2i DisplayServerMacOS::screen_get_position(int p_screen) const {
Size2i DisplayServerMacOS::screen_get_size(int p_screen) const { Size2i DisplayServerMacOS::screen_get_size(int p_screen) const {
_THREAD_SAFE_METHOD_ _THREAD_SAFE_METHOD_
if (p_screen == SCREEN_OF_MAIN_WINDOW) { switch (p_screen) {
p_screen = window_get_current_screen(); case SCREEN_PRIMARY: {
p_screen = get_primary_screen();
} break;
case SCREEN_OF_MAIN_WINDOW: {
p_screen = window_get_current_screen(MAIN_WINDOW_ID);
} break;
default:
break;
} }
NSArray *screenArray = [NSScreen screens]; NSArray *screenArray = [NSScreen screens];
@ -2111,8 +2133,15 @@ Size2i DisplayServerMacOS::screen_get_size(int p_screen) const {
int DisplayServerMacOS::screen_get_dpi(int p_screen) const { int DisplayServerMacOS::screen_get_dpi(int p_screen) const {
_THREAD_SAFE_METHOD_ _THREAD_SAFE_METHOD_
if (p_screen == SCREEN_OF_MAIN_WINDOW) { switch (p_screen) {
p_screen = window_get_current_screen(); case SCREEN_PRIMARY: {
p_screen = get_primary_screen();
} break;
case SCREEN_OF_MAIN_WINDOW: {
p_screen = window_get_current_screen(MAIN_WINDOW_ID);
} break;
default:
break;
} }
NSArray *screenArray = [NSScreen screens]; NSArray *screenArray = [NSScreen screens];
@ -2135,9 +2164,17 @@ int DisplayServerMacOS::screen_get_dpi(int p_screen) const {
float DisplayServerMacOS::screen_get_scale(int p_screen) const { float DisplayServerMacOS::screen_get_scale(int p_screen) const {
_THREAD_SAFE_METHOD_ _THREAD_SAFE_METHOD_
if (p_screen == SCREEN_OF_MAIN_WINDOW) { switch (p_screen) {
p_screen = window_get_current_screen(); case SCREEN_PRIMARY: {
p_screen = get_primary_screen();
} break;
case SCREEN_OF_MAIN_WINDOW: {
p_screen = window_get_current_screen(MAIN_WINDOW_ID);
} break;
default:
break;
} }
if (OS::get_singleton()->is_hidpi_allowed()) { if (OS::get_singleton()->is_hidpi_allowed()) {
NSArray *screenArray = [NSScreen screens]; NSArray *screenArray = [NSScreen screens];
if ((NSUInteger)p_screen < [screenArray count]) { if ((NSUInteger)p_screen < [screenArray count]) {
@ -2160,8 +2197,15 @@ float DisplayServerMacOS::screen_get_max_scale() const {
Rect2i DisplayServerMacOS::screen_get_usable_rect(int p_screen) const { Rect2i DisplayServerMacOS::screen_get_usable_rect(int p_screen) const {
_THREAD_SAFE_METHOD_ _THREAD_SAFE_METHOD_
if (p_screen == SCREEN_OF_MAIN_WINDOW) { switch (p_screen) {
p_screen = window_get_current_screen(); case SCREEN_PRIMARY: {
p_screen = get_primary_screen();
} break;
case SCREEN_OF_MAIN_WINDOW: {
p_screen = window_get_current_screen(MAIN_WINDOW_ID);
} break;
default:
break;
} }
NSArray *screenArray = [NSScreen screens]; NSArray *screenArray = [NSScreen screens];
@ -2182,8 +2226,15 @@ Rect2i DisplayServerMacOS::screen_get_usable_rect(int p_screen) const {
float DisplayServerMacOS::screen_get_refresh_rate(int p_screen) const { float DisplayServerMacOS::screen_get_refresh_rate(int p_screen) const {
_THREAD_SAFE_METHOD_ _THREAD_SAFE_METHOD_
if (p_screen == SCREEN_OF_MAIN_WINDOW) { switch (p_screen) {
p_screen = window_get_current_screen(); case SCREEN_PRIMARY: {
p_screen = get_primary_screen();
} break;
case SCREEN_OF_MAIN_WINDOW: {
p_screen = window_get_current_screen(MAIN_WINDOW_ID);
} break;
default:
break;
} }
NSArray *screenArray = [NSScreen screens]; NSArray *screenArray = [NSScreen screens];
@ -2225,10 +2276,10 @@ Vector<DisplayServer::WindowID> DisplayServerMacOS::get_window_list() const {
return ret; return ret;
} }
DisplayServer::WindowID DisplayServerMacOS::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, int p_screen) { DisplayServer::WindowID DisplayServerMacOS::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) {
_THREAD_SAFE_METHOD_ _THREAD_SAFE_METHOD_
WindowID id = _create_window(p_mode, p_vsync_mode, p_rect, p_screen); WindowID id = _create_window(p_mode, p_vsync_mode, p_rect);
for (int i = 0; i < WINDOW_FLAG_MAX; i++) { for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
if (p_flags & (1 << i)) { if (p_flags & (1 << i)) {
window_set_flag(WindowFlags(i), true, id); window_set_flag(WindowFlags(i), true, id);
@ -3520,8 +3571,8 @@ void DisplayServerMacOS::set_icon(const Ref<Image> &p_icon) {
[NSApp setApplicationIconImage:nsimg]; [NSApp setApplicationIconImage:nsimg];
} }
DisplayServer *DisplayServerMacOS::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) { DisplayServer *DisplayServerMacOS::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error) {
DisplayServer *ds = memnew(DisplayServerMacOS(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, r_error)); DisplayServer *ds = memnew(DisplayServerMacOS(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, r_error));
if (r_error != OK) { if (r_error != OK) {
if (p_rendering_driver == "vulkan") { if (p_rendering_driver == "vulkan") {
String executable_command; String executable_command;
@ -3690,7 +3741,7 @@ bool DisplayServerMacOS::mouse_process_popups(bool p_close) {
return closed; return closed;
} }
DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) { DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error) {
Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events); Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events);
r_error = OK; r_error = OK;
@ -3796,15 +3847,17 @@ DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowM
} }
#endif #endif
Point2i window_position( Point2i window_position;
screen_get_position(0).x + (screen_get_size(0).width - p_resolution.width) / 2,
screen_get_position(0).y + (screen_get_size(0).height - p_resolution.height) / 2);
if (p_position != nullptr) { if (p_position != nullptr) {
window_position = *p_position; window_position = *p_position;
} else {
if (p_screen == SCREEN_OF_MAIN_WINDOW) {
p_screen = SCREEN_PRIMARY;
}
window_position = screen_get_position(p_screen) + (screen_get_size(p_screen) - p_resolution) / 2;
} }
WindowID main_window = _create_window(p_mode, p_vsync_mode, Rect2i(window_position, p_resolution), 0); WindowID main_window = _create_window(p_mode, p_vsync_mode, Rect2i(window_position, p_resolution));
ERR_FAIL_COND(main_window == INVALID_WINDOW_ID); ERR_FAIL_COND(main_window == INVALID_WINDOW_ID);
for (int i = 0; i < WINDOW_FLAG_MAX; i++) { for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
if (p_flags & (1 << i)) { if (p_flags & (1 << i)) {

View file

@ -746,11 +746,11 @@ void DisplayServerWeb::_dispatch_input_event(const Ref<InputEvent> &p_event) {
} }
} }
DisplayServer *DisplayServerWeb::create_func(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Point2i *p_position, const Size2i &p_resolution, Error &r_error) { DisplayServer *DisplayServerWeb::create_func(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Point2i *p_position, const Size2i &p_resolution, int p_screen, Error &r_error) {
return memnew(DisplayServerWeb(p_rendering_driver, p_window_mode, p_vsync_mode, p_flags, p_position, p_resolution, r_error)); return memnew(DisplayServerWeb(p_rendering_driver, p_window_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, r_error));
} }
DisplayServerWeb::DisplayServerWeb(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Point2i *p_position, const Size2i &p_resolution, Error &r_error) { DisplayServerWeb::DisplayServerWeb(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Point2i *p_position, const Size2i &p_resolution, int p_screen, Error &r_error) {
r_error = OK; // Always succeeds for now. r_error = OK; // Always succeeds for now.
// Ensure the canvas ID. // Ensure the canvas ID.
@ -864,6 +864,10 @@ int DisplayServerWeb::get_screen_count() const {
return 1; return 1;
} }
int DisplayServerWeb::get_primary_screen() const {
return 0;
}
Point2i DisplayServerWeb::screen_get_position(int p_screen) const { Point2i DisplayServerWeb::screen_get_position(int p_screen) const {
return Point2i(); // TODO offsetX/Y? return Point2i(); // TODO offsetX/Y?
} }

View file

@ -97,7 +97,7 @@ private:
static void _js_utterance_callback(int p_event, int p_id, int p_pos); static void _js_utterance_callback(int p_event, int p_id, int p_pos);
static Vector<String> get_rendering_drivers_func(); static Vector<String> get_rendering_drivers_func();
static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error); static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error);
static void _dispatch_input_event(const Ref<InputEvent> &p_event); static void _dispatch_input_event(const Ref<InputEvent> &p_event);
@ -151,6 +151,7 @@ public:
// screen // screen
virtual int get_screen_count() const override; virtual int get_screen_count() const override;
virtual int get_primary_screen() const override;
virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
@ -223,7 +224,7 @@ public:
virtual void swap_buffers() override; virtual void swap_buffers() override;
static void register_web_driver(); static void register_web_driver();
DisplayServerWeb(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Point2i *p_position, const Size2i &p_resolution, Error &r_error); DisplayServerWeb(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Point2i *p_position, const Size2i &p_resolution, int p_screen, Error &r_error);
~DisplayServerWeb(); ~DisplayServerWeb();
}; };

View file

@ -254,7 +254,7 @@ void DisplayServerWindows::warp_mouse(const Point2i &p_position) {
Point2i DisplayServerWindows::mouse_get_position() const { Point2i DisplayServerWindows::mouse_get_position() const {
POINT p; POINT p;
GetCursorPos(&p); GetCursorPos(&p);
return Point2i(p.x, p.y); return Point2i(p.x, p.y) - _get_screens_origin();
} }
MouseButton DisplayServerWindows::mouse_get_button_state() const { MouseButton DisplayServerWindows::mouse_get_button_state() const {
@ -346,6 +346,19 @@ typedef struct {
HMONITOR monitor; HMONITOR monitor;
} EnumScreenData; } EnumScreenData;
static BOOL CALLBACK _MonitorEnumProcPrim(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
EnumScreenData *data = (EnumScreenData *)dwData;
if (data->monitor == hMonitor) {
if ((lprcMonitor->left == 0) && (lprcMonitor->top == 0)) {
data->screen = data->count;
return FALSE;
}
}
data->count++;
return TRUE;
}
static BOOL CALLBACK _MonitorEnumProcScreen(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) { static BOOL CALLBACK _MonitorEnumProcScreen(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
EnumScreenData *data = (EnumScreenData *)dwData; EnumScreenData *data = (EnumScreenData *)dwData;
if (data->monitor == hMonitor) { if (data->monitor == hMonitor) {
@ -370,6 +383,12 @@ int DisplayServerWindows::get_screen_count() const {
return data; return data;
} }
int DisplayServerWindows::get_primary_screen() const {
EnumScreenData data = { 0, 0, 0 };
EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcPrim, (LPARAM)&data);
return data.screen;
}
typedef struct { typedef struct {
int count; int count;
int screen; int screen;
@ -387,12 +406,39 @@ static BOOL CALLBACK _MonitorEnumProcPos(HMONITOR hMonitor, HDC hdcMonitor, LPRE
return TRUE; return TRUE;
} }
static BOOL CALLBACK _MonitorEnumProcOrigin(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
EnumPosData *data = (EnumPosData *)dwData;
data->pos.x = MIN(data->pos.x, lprcMonitor->left);
data->pos.y = MIN(data->pos.y, lprcMonitor->top);
return TRUE;
}
Point2i DisplayServerWindows::_get_screens_origin() const {
_THREAD_SAFE_METHOD_
EnumPosData data = { 0, 0, Point2() };
EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcOrigin, (LPARAM)&data);
return data.pos;
}
Point2i DisplayServerWindows::screen_get_position(int p_screen) const { Point2i DisplayServerWindows::screen_get_position(int p_screen) const {
_THREAD_SAFE_METHOD_ _THREAD_SAFE_METHOD_
EnumPosData data = { 0, p_screen == SCREEN_OF_MAIN_WINDOW ? window_get_current_screen() : p_screen, Point2() }; switch (p_screen) {
case SCREEN_PRIMARY: {
p_screen = get_primary_screen();
} break;
case SCREEN_OF_MAIN_WINDOW: {
p_screen = window_get_current_screen(MAIN_WINDOW_ID);
} break;
default:
break;
}
EnumPosData data = { 0, p_screen, Point2() };
EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcPos, (LPARAM)&data); EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcPos, (LPARAM)&data);
return data.pos; return data.pos - _get_screens_origin();
} }
typedef struct { typedef struct {
@ -427,7 +473,18 @@ static BOOL CALLBACK _MonitorEnumProcSize(HMONITOR hMonitor, HDC hdcMonitor, LPR
Size2i DisplayServerWindows::screen_get_size(int p_screen) const { Size2i DisplayServerWindows::screen_get_size(int p_screen) const {
_THREAD_SAFE_METHOD_ _THREAD_SAFE_METHOD_
EnumSizeData data = { 0, p_screen == SCREEN_OF_MAIN_WINDOW ? window_get_current_screen() : p_screen, Size2() }; switch (p_screen) {
case SCREEN_PRIMARY: {
p_screen = get_primary_screen();
} break;
case SCREEN_OF_MAIN_WINDOW: {
p_screen = window_get_current_screen(MAIN_WINDOW_ID);
} break;
default:
break;
}
EnumSizeData data = { 0, p_screen, Size2() };
EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcSize, (LPARAM)&data); EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcSize, (LPARAM)&data);
return data.size; return data.size;
} }
@ -473,8 +530,20 @@ static BOOL CALLBACK _MonitorEnumProcRefreshRate(HMONITOR hMonitor, HDC hdcMonit
Rect2i DisplayServerWindows::screen_get_usable_rect(int p_screen) const { Rect2i DisplayServerWindows::screen_get_usable_rect(int p_screen) const {
_THREAD_SAFE_METHOD_ _THREAD_SAFE_METHOD_
EnumRectData data = { 0, p_screen == SCREEN_OF_MAIN_WINDOW ? window_get_current_screen() : p_screen, Rect2i() }; switch (p_screen) {
case SCREEN_PRIMARY: {
p_screen = get_primary_screen();
} break;
case SCREEN_OF_MAIN_WINDOW: {
p_screen = window_get_current_screen(MAIN_WINDOW_ID);
} break;
default:
break;
}
EnumRectData data = { 0, p_screen, Rect2i() };
EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcUsableSize, (LPARAM)&data); EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcUsableSize, (LPARAM)&data);
data.rect.position -= _get_screens_origin();
return data.rect; return data.rect;
} }
@ -549,14 +618,36 @@ static BOOL CALLBACK _MonitorEnumProcDpi(HMONITOR hMonitor, HDC hdcMonitor, LPRE
int DisplayServerWindows::screen_get_dpi(int p_screen) const { int DisplayServerWindows::screen_get_dpi(int p_screen) const {
_THREAD_SAFE_METHOD_ _THREAD_SAFE_METHOD_
EnumDpiData data = { 0, p_screen == SCREEN_OF_MAIN_WINDOW ? window_get_current_screen() : p_screen, 72 }; switch (p_screen) {
case SCREEN_PRIMARY: {
p_screen = get_primary_screen();
} break;
case SCREEN_OF_MAIN_WINDOW: {
p_screen = window_get_current_screen(MAIN_WINDOW_ID);
} break;
default:
break;
}
EnumDpiData data = { 0, p_screen, 72 };
EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcDpi, (LPARAM)&data); EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcDpi, (LPARAM)&data);
return data.dpi; return data.dpi;
} }
float DisplayServerWindows::screen_get_refresh_rate(int p_screen) const { float DisplayServerWindows::screen_get_refresh_rate(int p_screen) const {
_THREAD_SAFE_METHOD_ _THREAD_SAFE_METHOD_
EnumRefreshRateData data = { 0, p_screen == SCREEN_OF_MAIN_WINDOW ? window_get_current_screen() : p_screen, SCREEN_REFRESH_RATE_FALLBACK }; switch (p_screen) {
case SCREEN_PRIMARY: {
p_screen = get_primary_screen();
} break;
case SCREEN_OF_MAIN_WINDOW: {
p_screen = window_get_current_screen(MAIN_WINDOW_ID);
} break;
default:
break;
}
EnumRefreshRateData data = { 0, p_screen, SCREEN_REFRESH_RATE_FALLBACK };
EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcRefreshRate, (LPARAM)&data); EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcRefreshRate, (LPARAM)&data);
return data.rate; return data.rate;
} }
@ -612,9 +703,10 @@ Vector<DisplayServer::WindowID> DisplayServerWindows::get_window_list() const {
} }
DisplayServer::WindowID DisplayServerWindows::get_window_at_screen_position(const Point2i &p_position) const { DisplayServer::WindowID DisplayServerWindows::get_window_at_screen_position(const Point2i &p_position) const {
Point2i offset = _get_screens_origin();
POINT p; POINT p;
p.x = p_position.x; p.x = p_position.x + offset.x;
p.y = p_position.y; p.y = p_position.y + offset.y;
HWND hwnd = WindowFromPoint(p); HWND hwnd = WindowFromPoint(p);
for (const KeyValue<WindowID, WindowData> &E : windows) { for (const KeyValue<WindowID, WindowData> &E : windows) {
if (E.value.hWnd == hwnd) { if (E.value.hWnd == hwnd) {
@ -625,10 +717,10 @@ DisplayServer::WindowID DisplayServerWindows::get_window_at_screen_position(cons
return INVALID_WINDOW_ID; return INVALID_WINDOW_ID;
} }
DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, int p_screen) { DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) {
_THREAD_SAFE_METHOD_ _THREAD_SAFE_METHOD_
WindowID window_id = _create_window(p_mode, p_vsync_mode, p_flags, p_rect, p_screen); WindowID window_id = _create_window(p_mode, p_vsync_mode, p_flags, p_rect);
ERR_FAIL_COND_V_MSG(window_id == INVALID_WINDOW_ID, INVALID_WINDOW_ID, "Failed to create sub window."); ERR_FAIL_COND_V_MSG(window_id == INVALID_WINDOW_ID, INVALID_WINDOW_ID, "Failed to create sub window.");
WindowData &wd = windows[window_id]; WindowData &wd = windows[window_id];
@ -870,7 +962,7 @@ void DisplayServerWindows::window_set_current_screen(int p_screen, WindowID p_wi
} }
const WindowData &wd = windows[p_window]; const WindowData &wd = windows[p_window];
if (wd.fullscreen) { if (wd.fullscreen) {
Point2 pos = screen_get_position(p_screen); Point2 pos = screen_get_position(p_screen) + _get_screens_origin();
Size2 size = screen_get_size(p_screen); Size2 size = screen_get_size(p_screen);
MoveWindow(wd.hWnd, pos.x, pos.y, size.width, size.height, TRUE); MoveWindow(wd.hWnd, pos.x, pos.y, size.width, size.height, TRUE);
@ -911,7 +1003,7 @@ Point2i DisplayServerWindows::window_get_position(WindowID p_window) const {
ClientToScreen(wd.hWnd, &point); ClientToScreen(wd.hWnd, &point);
return Point2i(point.x, point.y); return Point2i(point.x, point.y) - _get_screens_origin();
} }
Point2i DisplayServerWindows::window_get_position_with_decorations(WindowID p_window) const { Point2i DisplayServerWindows::window_get_position_with_decorations(WindowID p_window) const {
@ -926,7 +1018,7 @@ Point2i DisplayServerWindows::window_get_position_with_decorations(WindowID p_wi
RECT r; RECT r;
if (GetWindowRect(wd.hWnd, &r)) { if (GetWindowRect(wd.hWnd, &r)) {
return Point2i(r.left, r.top); return Point2i(r.left, r.top) - _get_screens_origin();
} }
return Point2i(); return Point2i();
@ -956,11 +1048,13 @@ void DisplayServerWindows::window_set_position(const Point2i &p_position, Window
return; return;
} }
Point2i offset = _get_screens_origin();
RECT rc; RECT rc;
rc.left = p_position.x; rc.left = p_position.x + offset.x;
rc.right = p_position.x + wd.width; rc.right = p_position.x + wd.width + offset.x;
rc.bottom = p_position.y + wd.height; rc.bottom = p_position.y + wd.height + offset.y;
rc.top = p_position.y; rc.top = p_position.y + offset.y;
const DWORD style = GetWindowLongPtr(wd.hWnd, GWL_STYLE); const DWORD style = GetWindowLongPtr(wd.hWnd, GWL_STYLE);
const DWORD exStyle = GetWindowLongPtr(wd.hWnd, GWL_EXSTYLE); const DWORD exStyle = GetWindowLongPtr(wd.hWnd, GWL_EXSTYLE);
@ -1296,7 +1390,7 @@ void DisplayServerWindows::window_set_mode(WindowMode p_mode, WindowID p_window)
} }
int cs = window_get_current_screen(p_window); int cs = window_get_current_screen(p_window);
Point2 pos = screen_get_position(cs); Point2 pos = screen_get_position(cs) + _get_screens_origin();
Size2 size = screen_get_size(cs); Size2 size = screen_get_size(cs);
wd.fullscreen = true; wd.fullscreen = true;
@ -2277,7 +2371,7 @@ LRESULT DisplayServerWindows::MouseProc(int code, WPARAM wParam, LPARAM lParam)
case WM_RBUTTONDOWN: case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN: { case WM_MBUTTONDOWN: {
MOUSEHOOKSTRUCT *ms = (MOUSEHOOKSTRUCT *)lParam; MOUSEHOOKSTRUCT *ms = (MOUSEHOOKSTRUCT *)lParam;
Point2i pos = Point2i(ms->pt.x, ms->pt.y); Point2i pos = Point2i(ms->pt.x, ms->pt.y) - _get_screens_origin();
List<WindowID>::Element *C = nullptr; List<WindowID>::Element *C = nullptr;
List<WindowID>::Element *E = popup_list.back(); List<WindowID>::Element *E = popup_list.back();
// Find top popup to close. // Find top popup to close.
@ -3130,10 +3224,12 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
ClientToScreen(hWnd, (POINT *)&rect.left); ClientToScreen(hWnd, (POINT *)&rect.left);
ClientToScreen(hWnd, (POINT *)&rect.right); ClientToScreen(hWnd, (POINT *)&rect.right);
window_client_rect = Rect2i(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); window_client_rect = Rect2i(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
window_client_rect.position -= _get_screens_origin();
RECT wrect; RECT wrect;
GetWindowRect(hWnd, &wrect); GetWindowRect(hWnd, &wrect);
window_rect = Rect2i(wrect.left, wrect.top, wrect.right - wrect.left, wrect.bottom - wrect.top); window_rect = Rect2i(wrect.left, wrect.top, wrect.right - wrect.left, wrect.bottom - wrect.top);
window_rect.position -= _get_screens_origin();
} }
WINDOWPOS *window_pos_params = (WINDOWPOS *)lParam; WINDOWPOS *window_pos_params = (WINDOWPOS *)lParam;
@ -3539,7 +3635,7 @@ void DisplayServerWindows::_update_tablet_ctx(const String &p_old_driver, const
} }
} }
DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, int p_screen) { DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) {
DWORD dwExStyle; DWORD dwExStyle;
DWORD dwStyle; DWORD dwStyle;
@ -3552,40 +3648,38 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
WindowRect.top = p_rect.position.y; WindowRect.top = p_rect.position.y;
WindowRect.bottom = p_rect.position.y + p_rect.size.y; WindowRect.bottom = p_rect.position.y + p_rect.size.y;
int rq_screen = get_screen_from_rect(p_rect);
if (rq_screen < 0) {
rq_screen = get_primary_screen(); // Requested window rect is outside any screen bounds.
}
if (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) { if (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
Rect2i screen_rect = Rect2i(screen_get_position(p_screen), screen_get_size(p_screen)); Rect2i screen_rect = Rect2i(screen_get_position(rq_screen), screen_get_size(rq_screen));
WindowRect.left = screen_rect.position.x; WindowRect.left = screen_rect.position.x;
WindowRect.right = screen_rect.position.x + screen_rect.size.x; WindowRect.right = screen_rect.position.x + screen_rect.size.x;
WindowRect.top = screen_rect.position.y; WindowRect.top = screen_rect.position.y;
WindowRect.bottom = screen_rect.position.y + screen_rect.size.y; WindowRect.bottom = screen_rect.position.y + screen_rect.size.y;
} else { } else {
int nearest_area = 0; Rect2i srect = screen_get_usable_rect(rq_screen);
int pos_screen = -1; Point2i wpos = p_rect.position;
for (int i = 0; i < get_screen_count(); i++) { if (srect != Rect2i()) {
Rect2i r; wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - p_rect.size.width / 3);
r.position = screen_get_position(i); wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - p_rect.size.height / 3);
r.size = screen_get_size(i);
Rect2 inters = r.intersection(p_rect);
int area = inters.size.width * inters.size.height;
if (area > nearest_area) {
pos_screen = i;
nearest_area = area;
}
} }
Rect2i srect = screen_get_usable_rect(p_screen);
Point2i wpos = p_rect.position - ((pos_screen >= 0) ? screen_get_position(pos_screen) : Vector2i());
wpos += srect.position;
wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - p_rect.size.width / 3);
wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - p_rect.size.height / 3);
WindowRect.left = wpos.x; WindowRect.left = wpos.x;
WindowRect.right = wpos.x + p_rect.size.x; WindowRect.right = wpos.x + p_rect.size.x;
WindowRect.top = wpos.y; WindowRect.top = wpos.y;
WindowRect.bottom = wpos.y + p_rect.size.y; WindowRect.bottom = wpos.y + p_rect.size.y;
} }
Point2i offset = _get_screens_origin();
WindowRect.left += offset.x;
WindowRect.right += offset.x;
WindowRect.top += offset.y;
WindowRect.bottom += offset.y;
AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle); AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);
WindowID id = window_id_counter; WindowID id = window_id_counter;
@ -3794,7 +3888,7 @@ void DisplayServerWindows::tablet_set_current_driver(const String &p_driver) {
} }
} }
DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) { DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error) {
drop_events = false; drop_events = false;
key_event_pos = 0; key_event_pos = 0;
@ -3941,15 +4035,17 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
mouse_monitor = SetWindowsHookEx(WH_MOUSE, ::MouseProc, nullptr, GetCurrentThreadId()); mouse_monitor = SetWindowsHookEx(WH_MOUSE, ::MouseProc, nullptr, GetCurrentThreadId());
Point2i window_position( Point2i window_position;
(screen_get_size(0).width - p_resolution.width) / 2,
(screen_get_size(0).height - p_resolution.height) / 2);
if (p_position != nullptr) { if (p_position != nullptr) {
window_position = *p_position; window_position = *p_position;
} else {
if (p_screen == SCREEN_OF_MAIN_WINDOW) {
p_screen = SCREEN_PRIMARY;
}
window_position = screen_get_position(p_screen) + (screen_get_size(p_screen) - p_resolution) / 2;
} }
WindowID main_window = _create_window(p_mode, p_vsync_mode, 0, Rect2i(window_position, p_resolution), 0); WindowID main_window = _create_window(p_mode, p_vsync_mode, 0, Rect2i(window_position, p_resolution));
ERR_FAIL_COND_MSG(main_window == INVALID_WINDOW_ID, "Failed to create main window."); ERR_FAIL_COND_MSG(main_window == INVALID_WINDOW_ID, "Failed to create main window.");
joypad = new JoypadWindows(&windows[MAIN_WINDOW_ID].hWnd); joypad = new JoypadWindows(&windows[MAIN_WINDOW_ID].hWnd);
@ -4012,8 +4108,8 @@ Vector<String> DisplayServerWindows::get_rendering_drivers_func() {
return drivers; return drivers;
} }
DisplayServer *DisplayServerWindows::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) { DisplayServer *DisplayServerWindows::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error) {
DisplayServer *ds = memnew(DisplayServerWindows(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, r_error)); DisplayServer *ds = memnew(DisplayServerWindows(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, r_error));
if (r_error != OK) { if (r_error != OK) {
if (p_rendering_driver == "vulkan") { if (p_rendering_driver == "vulkan") {
String executable_name = OS::get_singleton()->get_executable_path().get_file(); String executable_name = OS::get_singleton()->get_executable_path().get_file();

View file

@ -426,7 +426,7 @@ class DisplayServerWindows : public DisplayServer {
uint64_t time_since_popup = 0; uint64_t time_since_popup = 0;
Ref<Image> icon; Ref<Image> icon;
WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, int p_screen); WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect);
WindowID window_id_counter = MAIN_WINDOW_ID; WindowID window_id_counter = MAIN_WINDOW_ID;
RBMap<WindowID, WindowData> windows; RBMap<WindowID, WindowData> windows;
@ -476,6 +476,7 @@ class DisplayServerWindows : public DisplayServer {
void _dispatch_input_event(const Ref<InputEvent> &p_event); void _dispatch_input_event(const Ref<InputEvent> &p_event);
LRESULT _handle_early_window_message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); LRESULT _handle_early_window_message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
Point2i _get_screens_origin() const;
public: public:
LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
@ -511,6 +512,7 @@ public:
virtual String clipboard_get() const override; virtual String clipboard_get() const override;
virtual int get_screen_count() const override; virtual int get_screen_count() const override;
virtual int get_primary_screen() const override;
virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
@ -522,7 +524,7 @@ public:
virtual Vector<DisplayServer::WindowID> get_window_list() const override; 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(), int p_screen = 0) override; virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()) override;
virtual void show_window(WindowID p_window) override; virtual void show_window(WindowID p_window) override;
virtual void delete_sub_window(WindowID p_window) override; virtual void delete_sub_window(WindowID p_window) override;
@ -623,11 +625,11 @@ public:
virtual void set_context(Context p_context) override; virtual void set_context(Context p_context) override;
static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error); static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error);
static Vector<String> get_rendering_drivers_func(); static Vector<String> get_rendering_drivers_func();
static void register_windows_driver(); static void register_windows_driver();
DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error); DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error);
~DisplayServerWindows(); ~DisplayServerWindows();
}; };

View file

@ -1298,7 +1298,6 @@ void Viewport::_gui_show_tooltip() {
r.position.y = vr.position.y; r.position.y = vr.position.y;
} }
gui.tooltip_popup->set_current_screen(window->get_current_screen());
gui.tooltip_popup->set_position(r.position); gui.tooltip_popup->set_position(r.position);
gui.tooltip_popup->set_size(r.size); gui.tooltip_popup->set_size(r.size);

View file

@ -223,6 +223,14 @@ void Window::_get_property_list(List<PropertyInfo> *p_list) const {
} }
void Window::_validate_property(PropertyInfo &p_property) const { void Window::_validate_property(PropertyInfo &p_property) const {
if (p_property.name == "position" && initial_position != WINDOW_INITIAL_POSITION_ABSOLUTE) {
p_property.usage = PROPERTY_USAGE_NONE;
}
if (p_property.name == "current_screen" && initial_position != WINDOW_INITIAL_POSITION_CENTER_SCREEN) {
p_property.usage = PROPERTY_USAGE_NONE;
}
if (p_property.name == "theme_type_variation") { if (p_property.name == "theme_type_variation") {
List<StringName> names; List<StringName> names;
@ -275,6 +283,15 @@ String Window::get_title() const {
return title; return title;
} }
void Window::set_initial_position(Window::WindowInitialPosition p_initial_position) {
initial_position = p_initial_position;
notify_property_list_changed();
}
Window::WindowInitialPosition Window::get_initial_position() const {
return initial_position;
}
void Window::set_current_screen(int p_screen) { void Window::set_current_screen(int p_screen) {
current_screen = p_screen; current_screen = p_screen;
if (window_id == DisplayServer::INVALID_WINDOW_ID) { if (window_id == DisplayServer::INVALID_WINDOW_ID) {
@ -462,7 +479,13 @@ void Window::_make_window() {
} }
DisplayServer::VSyncMode vsync_mode = DisplayServer::get_singleton()->window_get_vsync_mode(DisplayServer::MAIN_WINDOW_ID); DisplayServer::VSyncMode vsync_mode = DisplayServer::get_singleton()->window_get_vsync_mode(DisplayServer::MAIN_WINDOW_ID);
window_id = DisplayServer::get_singleton()->create_sub_window(DisplayServer::WindowMode(mode), vsync_mode, f, Rect2i(position, size), current_screen); Rect2i window_rect;
if (initial_position == WINDOW_INITIAL_POSITION_ABSOLUTE) {
window_rect = Rect2i(position, size);
} else if (initial_position == WINDOW_INITIAL_POSITION_CENTER_SCREEN) {
window_rect = Rect2i(DisplayServer::get_singleton()->screen_get_position(current_screen) + (DisplayServer::get_singleton()->screen_get_size(current_screen) - size) / 2, size);
}
window_id = DisplayServer::get_singleton()->create_sub_window(DisplayServer::WindowMode(mode), vsync_mode, f, window_rect);
ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID); ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID);
DisplayServer::get_singleton()->window_set_max_size(Size2i(), window_id); DisplayServer::get_singleton()->window_set_max_size(Size2i(), window_id);
DisplayServer::get_singleton()->window_set_min_size(Size2i(), window_id); DisplayServer::get_singleton()->window_set_min_size(Size2i(), window_id);
@ -2068,6 +2091,9 @@ void Window::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_title", "title"), &Window::set_title); ClassDB::bind_method(D_METHOD("set_title", "title"), &Window::set_title);
ClassDB::bind_method(D_METHOD("get_title"), &Window::get_title); ClassDB::bind_method(D_METHOD("get_title"), &Window::get_title);
ClassDB::bind_method(D_METHOD("set_initial_position", "initial_position"), &Window::set_initial_position);
ClassDB::bind_method(D_METHOD("get_initial_position"), &Window::get_initial_position);
ClassDB::bind_method(D_METHOD("set_current_screen", "index"), &Window::set_current_screen); ClassDB::bind_method(D_METHOD("set_current_screen", "index"), &Window::set_current_screen);
ClassDB::bind_method(D_METHOD("get_current_screen"), &Window::get_current_screen); ClassDB::bind_method(D_METHOD("get_current_screen"), &Window::get_current_screen);
@ -2204,11 +2230,18 @@ void Window::_bind_methods() {
ClassDB::bind_method(D_METHOD("popup_centered", "minsize"), &Window::popup_centered, DEFVAL(Size2i())); ClassDB::bind_method(D_METHOD("popup_centered", "minsize"), &Window::popup_centered, DEFVAL(Size2i()));
ClassDB::bind_method(D_METHOD("popup_centered_clamped", "minsize", "fallback_ratio"), &Window::popup_centered_clamped, DEFVAL(Size2i()), DEFVAL(0.75)); ClassDB::bind_method(D_METHOD("popup_centered_clamped", "minsize", "fallback_ratio"), &Window::popup_centered_clamped, DEFVAL(Size2i()), DEFVAL(0.75));
ADD_PROPERTY(PropertyInfo(Variant::INT, "initial_position", PROPERTY_HINT_ENUM, "Absolute,Screen Center"), "set_initial_position", "get_initial_position");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "title"), "set_title", "get_title"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "title"), "set_title", "get_title");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "position", PROPERTY_HINT_NONE, "suffix:px"), "set_position", "get_position"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "position", PROPERTY_HINT_NONE, "suffix:px"), "set_position", "get_position");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "size", PROPERTY_HINT_NONE, "suffix:px"), "set_size", "get_size"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "size", PROPERTY_HINT_NONE, "suffix:px"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Windowed,Minimized,Maximized,Fullscreen"), "set_mode", "get_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Windowed,Minimized,Maximized,Fullscreen"), "set_mode", "get_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "current_screen"), "set_current_screen", "get_current_screen");
// Keep the enum values in sync with the `DisplayServer::SCREEN_` enum.
String screen_hints = "Primary Monitor:-2,Main Window Monitor:-1";
for (int i = 0; i < 64; i++) {
screen_hints += ",Monitor " + itos(i + 1) + ":" + itos(i);
}
ADD_PROPERTY(PropertyInfo(Variant::INT, "current_screen", PROPERTY_HINT_ENUM, screen_hints), "set_current_screen", "get_current_screen");
ADD_GROUP("Flags", ""); ADD_GROUP("Flags", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
@ -2285,6 +2318,9 @@ void Window::_bind_methods() {
BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_LOCALE); BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_LOCALE);
BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_LTR); BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_LTR);
BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_RTL); BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_RTL);
BIND_ENUM_CONSTANT(WINDOW_INITIAL_POSITION_ABSOLUTE);
BIND_ENUM_CONSTANT(WINDOW_INITIAL_POSITION_CENTER_SCREEN);
} }
Window::Window() { Window::Window() {

View file

@ -87,11 +87,16 @@ public:
DEFAULT_WINDOW_SIZE = 100, DEFAULT_WINDOW_SIZE = 100,
}; };
enum WindowInitialPosition {
WINDOW_INITIAL_POSITION_ABSOLUTE,
WINDOW_INITIAL_POSITION_CENTER_SCREEN,
};
private: private:
DisplayServer::WindowID window_id = DisplayServer::INVALID_WINDOW_ID; DisplayServer::WindowID window_id = DisplayServer::INVALID_WINDOW_ID;
String title; String title;
mutable int current_screen = 0; mutable int current_screen = DisplayServer::SCREEN_PRIMARY;
mutable Vector2i position; mutable Vector2i position;
mutable Size2i size = Size2i(DEFAULT_WINDOW_SIZE, DEFAULT_WINDOW_SIZE); mutable Size2i size = Size2i(DEFAULT_WINDOW_SIZE, DEFAULT_WINDOW_SIZE);
mutable Size2i min_size; mutable Size2i min_size;
@ -100,6 +105,7 @@ private:
mutable bool flags[FLAG_MAX] = {}; mutable bool flags[FLAG_MAX] = {};
bool visible = true; bool visible = true;
bool focused = false; bool focused = false;
WindowInitialPosition initial_position = WINDOW_INITIAL_POSITION_ABSOLUTE;
bool use_font_oversampling = false; bool use_font_oversampling = false;
bool transient = false; bool transient = false;
@ -201,6 +207,9 @@ public:
void set_title(const String &p_title); void set_title(const String &p_title);
String get_title() const; String get_title() const;
void set_initial_position(WindowInitialPosition p_initial_position);
WindowInitialPosition get_initial_position() const;
void set_current_screen(int p_screen); void set_current_screen(int p_screen);
int get_current_screen() const; int get_current_screen() const;
@ -369,5 +378,6 @@ VARIANT_ENUM_CAST(Window::Flags);
VARIANT_ENUM_CAST(Window::ContentScaleMode); VARIANT_ENUM_CAST(Window::ContentScaleMode);
VARIANT_ENUM_CAST(Window::ContentScaleAspect); VARIANT_ENUM_CAST(Window::ContentScaleAspect);
VARIANT_ENUM_CAST(Window::LayoutDirection); VARIANT_ENUM_CAST(Window::LayoutDirection);
VARIANT_ENUM_CAST(Window::WindowInitialPosition);
#endif // WINDOW_H #endif // WINDOW_H

View file

@ -379,7 +379,24 @@ bool DisplayServer::screen_is_kept_on() const {
return false; return false;
} }
DisplayServer::WindowID DisplayServer::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, int p_screen) { int DisplayServer::get_screen_from_rect(const Rect2 &p_rect) const {
int nearest_area = 0;
int pos_screen = -1;
for (int i = 0; i < get_screen_count(); i++) {
Rect2i r;
r.position = screen_get_position(i);
r.size = screen_get_size(i);
Rect2 inters = r.intersection(p_rect);
int area = inters.size.width * inters.size.height;
if (area > nearest_area) {
pos_screen = i;
nearest_area = area;
}
}
return pos_screen;
}
DisplayServer::WindowID DisplayServer::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) {
ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Sub-windows not supported by this display server."); ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Sub-windows not supported by this display server.");
} }
@ -612,6 +629,8 @@ void DisplayServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_display_safe_area"), &DisplayServer::get_display_safe_area); ClassDB::bind_method(D_METHOD("get_display_safe_area"), &DisplayServer::get_display_safe_area);
ClassDB::bind_method(D_METHOD("get_screen_count"), &DisplayServer::get_screen_count); ClassDB::bind_method(D_METHOD("get_screen_count"), &DisplayServer::get_screen_count);
ClassDB::bind_method(D_METHOD("get_primary_screen"), &DisplayServer::get_primary_screen);
ClassDB::bind_method(D_METHOD("get_screen_from_rect", "rect"), &DisplayServer::get_screen_from_rect);
ClassDB::bind_method(D_METHOD("screen_get_position", "screen"), &DisplayServer::screen_get_position, DEFVAL(SCREEN_OF_MAIN_WINDOW)); ClassDB::bind_method(D_METHOD("screen_get_position", "screen"), &DisplayServer::screen_get_position, DEFVAL(SCREEN_OF_MAIN_WINDOW));
ClassDB::bind_method(D_METHOD("screen_get_size", "screen"), &DisplayServer::screen_get_size, DEFVAL(SCREEN_OF_MAIN_WINDOW)); ClassDB::bind_method(D_METHOD("screen_get_size", "screen"), &DisplayServer::screen_get_size, DEFVAL(SCREEN_OF_MAIN_WINDOW));
ClassDB::bind_method(D_METHOD("screen_get_usable_rect", "screen"), &DisplayServer::screen_get_usable_rect, DEFVAL(SCREEN_OF_MAIN_WINDOW)); ClassDB::bind_method(D_METHOD("screen_get_usable_rect", "screen"), &DisplayServer::screen_get_usable_rect, DEFVAL(SCREEN_OF_MAIN_WINDOW));
@ -754,7 +773,9 @@ void DisplayServer::_bind_methods() {
BIND_ENUM_CONSTANT(MOUSE_MODE_CONFINED); BIND_ENUM_CONSTANT(MOUSE_MODE_CONFINED);
BIND_ENUM_CONSTANT(MOUSE_MODE_CONFINED_HIDDEN); BIND_ENUM_CONSTANT(MOUSE_MODE_CONFINED_HIDDEN);
BIND_CONSTANT(SCREEN_PRIMARY);
BIND_CONSTANT(SCREEN_OF_MAIN_WINDOW); BIND_CONSTANT(SCREEN_OF_MAIN_WINDOW);
BIND_CONSTANT(MAIN_WINDOW_ID); BIND_CONSTANT(MAIN_WINDOW_ID);
BIND_CONSTANT(INVALID_WINDOW_ID); BIND_CONSTANT(INVALID_WINDOW_ID);
@ -858,9 +879,9 @@ Vector<String> DisplayServer::get_create_function_rendering_drivers(int p_index)
return server_create_functions[p_index].get_rendering_drivers_function(); return server_create_functions[p_index].get_rendering_drivers_function();
} }
DisplayServer *DisplayServer::create(int p_index, const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) { DisplayServer *DisplayServer::create(int p_index, const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error) {
ERR_FAIL_INDEX_V(p_index, server_create_count, nullptr); ERR_FAIL_INDEX_V(p_index, server_create_count, nullptr);
return server_create_functions[p_index].create_function(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, r_error); return server_create_functions[p_index].create_function(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, r_error);
} }
void DisplayServer::_input_set_mouse_mode(Input::MouseMode p_mode) { void DisplayServer::_input_set_mouse_mode(Input::MouseMode p_mode) {

View file

@ -73,7 +73,7 @@ public:
OPENGL_CONTEXT, OPENGL_CONTEXT,
}; };
typedef DisplayServer *(*CreateFunction)(const String &, WindowMode, VSyncMode, uint32_t, const Point2i *, const Size2i &, Error &r_error); typedef DisplayServer *(*CreateFunction)(const String &, WindowMode, VSyncMode, uint32_t, const Point2i *, const Size2i &, int p_screen, Error &r_error);
typedef Vector<String> (*GetRenderingDriversFunction)(); typedef Vector<String> (*GetRenderingDriversFunction)();
private: private:
@ -242,12 +242,15 @@ public:
virtual Rect2i get_display_safe_area() const { return screen_get_usable_rect(); } virtual Rect2i get_display_safe_area() const { return screen_get_usable_rect(); }
enum { enum {
SCREEN_OF_MAIN_WINDOW = -1 SCREEN_PRIMARY = -2,
SCREEN_OF_MAIN_WINDOW = -1, // Note: for the main window, determine screen from position.
}; };
const float SCREEN_REFRESH_RATE_FALLBACK = -1.0; // Returned by screen_get_refresh_rate if the method fails. const float SCREEN_REFRESH_RATE_FALLBACK = -1.0; // Returned by screen_get_refresh_rate if the method fails.
virtual int get_screen_count() const = 0; virtual int get_screen_count() const = 0;
virtual int get_primary_screen() const = 0;
virtual int get_screen_from_rect(const Rect2 &p_rect) const;
virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0; virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0;
virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0; virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0;
virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0; virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0;
@ -312,7 +315,7 @@ public:
WINDOW_FLAG_EXTEND_TO_TITLE_BIT = (1 << WINDOW_FLAG_EXTEND_TO_TITLE), WINDOW_FLAG_EXTEND_TO_TITLE_BIT = (1 << WINDOW_FLAG_EXTEND_TO_TITLE),
}; };
virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i(), int p_screen = 0); virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i());
virtual void show_window(WindowID p_id); virtual void show_window(WindowID p_id);
virtual void delete_sub_window(WindowID p_id); virtual void delete_sub_window(WindowID p_id);
@ -485,7 +488,7 @@ public:
static int get_create_function_count(); static int get_create_function_count();
static const char *get_create_function_name(int p_index); static const char *get_create_function_name(int p_index);
static Vector<String> get_create_function_rendering_drivers(int p_index); static Vector<String> get_create_function_rendering_drivers(int p_index);
static DisplayServer *create(int p_index, const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error); static DisplayServer *create(int p_index, const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error);
DisplayServer(); DisplayServer();
~DisplayServer(); ~DisplayServer();

View file

@ -45,7 +45,7 @@ private:
return drivers; return drivers;
} }
static DisplayServer *create_func(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) { static DisplayServer *create_func(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error) {
r_error = OK; r_error = OK;
RasterizerDummy::make_current(); RasterizerDummy::make_current();
return memnew(DisplayServerHeadless()); return memnew(DisplayServerHeadless());
@ -56,6 +56,7 @@ public:
String get_name() const override { return "headless"; } String get_name() const override { return "headless"; }
int get_screen_count() const override { return 0; } int get_screen_count() const override { return 0; }
int get_primary_screen() const override { return 0; };
Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override { return Point2i(); } Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override { return Point2i(); }
Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override { return Size2i(); } Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override { return Size2i(); }
Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override { return Rect2i(); } Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override { return Rect2i(); }
@ -66,7 +67,7 @@ public:
Vector<DisplayServer::WindowID> get_window_list() const override { return Vector<DisplayServer::WindowID>(); } Vector<DisplayServer::WindowID> get_window_list() const override { return Vector<DisplayServer::WindowID>(); }
WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i(), int p_screen = 0) override { return 0; } WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()) override { return 0; }
void show_window(WindowID p_id) override {} void show_window(WindowID p_id) override {}
void delete_sub_window(WindowID p_id) override {} void delete_sub_window(WindowID p_id) override {}

View file

@ -203,7 +203,7 @@ struct GodotTestCaseListener : public doctest::IReporter {
OS::get_singleton()->set_has_server_feature_callback(nullptr); OS::get_singleton()->set_has_server_feature_callback(nullptr);
for (int i = 0; i < DisplayServer::get_create_function_count(); i++) { for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
if (String("headless") == DisplayServer::get_create_function_name(i)) { if (String("headless") == DisplayServer::get_create_function_name(i)) {
DisplayServer::create(i, "", DisplayServer::WindowMode::WINDOW_MODE_MINIMIZED, DisplayServer::VSyncMode::VSYNC_ENABLED, 0, nullptr, Vector2i(0, 0), err); DisplayServer::create(i, "", DisplayServer::WindowMode::WINDOW_MODE_MINIMIZED, DisplayServer::VSyncMode::VSYNC_ENABLED, 0, nullptr, Vector2i(0, 0), DisplayServer::SCREEN_PRIMARY, err);
break; break;
} }
} }