diff options
Diffstat (limited to 'platform')
-rw-r--r-- | platform/android/display_server_android.cpp | 10 | ||||
-rw-r--r-- | platform/android/display_server_android.h | 1 | ||||
-rw-r--r-- | platform/android/export/export_plugin.cpp | 10 | ||||
-rw-r--r-- | platform/android/java/lib/src/org/godotengine/godot/GodotIO.java | 8 | ||||
-rw-r--r-- | platform/android/java_godot_io_wrapper.cpp | 14 | ||||
-rw-r--r-- | platform/android/java_godot_io_wrapper.h | 2 | ||||
-rw-r--r-- | platform/iphone/display_server_iphone.h | 1 | ||||
-rw-r--r-- | platform/iphone/display_server_iphone.mm | 4 | ||||
-rw-r--r-- | platform/iphone/export/export_plugin.h | 2 | ||||
-rw-r--r-- | platform/javascript/display_server_javascript.cpp | 7 | ||||
-rw-r--r-- | platform/javascript/display_server_javascript.h | 1 | ||||
-rw-r--r-- | platform/linuxbsd/display_server_x11.cpp | 64 | ||||
-rw-r--r-- | platform/linuxbsd/display_server_x11.h | 1 | ||||
-rw-r--r-- | platform/osx/display_server_osx.h | 1 | ||||
-rw-r--r-- | platform/osx/display_server_osx.mm | 20 | ||||
-rw-r--r-- | platform/osx/export/export_plugin.h | 2 | ||||
-rw-r--r-- | platform/windows/display_server_windows.cpp | 201 | ||||
-rw-r--r-- | platform/windows/display_server_windows.h | 5 |
18 files changed, 254 insertions, 100 deletions
diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp index 3d0dabc56e..b0f16337ed 100644 --- a/platform/android/display_server_android.cpp +++ b/platform/android/display_server_android.cpp @@ -161,6 +161,16 @@ int DisplayServerAndroid::screen_get_dpi(int p_screen) const { return godot_io_java->get_screen_dpi(); } +float DisplayServerAndroid::screen_get_refresh_rate(int p_screen) const { + GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java(); + if (!godot_io_java) { + ERR_PRINT("An error occured while trying to get the screen refresh rate."); + return SCREEN_REFRESH_RATE_FALLBACK; + } + + return godot_io_java->get_screen_refresh_rate(SCREEN_REFRESH_RATE_FALLBACK); +} + bool DisplayServerAndroid::screen_is_touchscreen(int p_screen) const { return true; } diff --git a/platform/android/display_server_android.h b/platform/android/display_server_android.h index e52e07bf1a..23077a6529 100644 --- a/platform/android/display_server_android.h +++ b/platform/android/display_server_android.h @@ -106,6 +106,7 @@ public: 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 int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; + virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), bool p_multiline = false, int p_max_length = -1, int p_cursor_start = -1, int p_cursor_end = -1) override; diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index 61d2f897ef..df2d32e152 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -416,10 +416,10 @@ String EditorExportPlatformAndroid::get_package_name(const String &p_package) co bool first = true; for (int i = 0; i < basename.length(); i++) { char32_t c = basename[i]; - if (c >= '0' && c <= '9' && first) { + if (is_digit(c) && first) { continue; } - if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) { + if (is_ascii_alphanumeric_char(c)) { name += String::chr(c); first = false; } @@ -462,19 +462,19 @@ bool EditorExportPlatformAndroid::is_package_name_valid(const String &p_package, first = true; continue; } - if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_')) { + if (!is_ascii_identifier_char(c)) { if (r_error) { *r_error = vformat(TTR("The character '%s' is not allowed in Android application package names."), String::chr(c)); } return false; } - if (first && (c >= '0' && c <= '9')) { + if (first && is_digit(c)) { if (r_error) { *r_error = TTR("A digit cannot be the first character in a package segment."); } return false; } - if (first && c == '_') { + if (first && is_underscore(c)) { if (r_error) { *r_error = vformat(TTR("The character '%s' cannot be the first character in a package segment."), String::chr(c)); } diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java index d679fd92c0..b151e7eec1 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java @@ -226,6 +226,14 @@ public class GodotIO { return (int)(metrics.density * 160f); } + public double getScreenRefreshRate(double fallback) { + Display display = activity.getWindowManager().getDefaultDisplay(); + if (display != null) { + return display.getRefreshRate(); + } + return fallback; + } + public int[] screenGetUsableRect() { DisplayMetrics metrics = activity.getResources().getDisplayMetrics(); Display display = activity.getWindowManager().getDefaultDisplay(); diff --git a/platform/android/java_godot_io_wrapper.cpp b/platform/android/java_godot_io_wrapper.cpp index e0a535f16e..8a2788e848 100644 --- a/platform/android/java_godot_io_wrapper.cpp +++ b/platform/android/java_godot_io_wrapper.cpp @@ -53,6 +53,7 @@ GodotIOJavaWrapper::GodotIOJavaWrapper(JNIEnv *p_env, jobject p_godot_io_instanc _get_locale = p_env->GetMethodID(cls, "getLocale", "()Ljava/lang/String;"); _get_model = p_env->GetMethodID(cls, "getModel", "()Ljava/lang/String;"); _get_screen_DPI = p_env->GetMethodID(cls, "getScreenDPI", "()I"); + _get_screen_refresh_rate = p_env->GetMethodID(cls, "getScreenRefreshRate", "(D)D"); _screen_get_usable_rect = p_env->GetMethodID(cls, "screenGetUsableRect", "()[I"), _get_unique_id = p_env->GetMethodID(cls, "getUniqueID", "()Ljava/lang/String;"); _show_keyboard = p_env->GetMethodID(cls, "showKeyboard", "(Ljava/lang/String;ZIII)V"); @@ -136,6 +137,19 @@ int GodotIOJavaWrapper::get_screen_dpi() { } } +float GodotIOJavaWrapper::get_screen_refresh_rate(float fallback) { + if (_get_screen_refresh_rate) { + JNIEnv *env = get_jni_env(); + if (env == nullptr) { + ERR_PRINT("An error occured while trying to get screen refresh rate."); + return fallback; + } + return (float)env->CallDoubleMethod(godot_io_instance, _get_screen_refresh_rate, (double)fallback); + } + ERR_PRINT("An error occured while trying to get the screen refresh rate."); + return fallback; +} + void GodotIOJavaWrapper::screen_get_usable_rect(int (&p_rect_xywh)[4]) { if (_screen_get_usable_rect) { JNIEnv *env = get_jni_env(); diff --git a/platform/android/java_godot_io_wrapper.h b/platform/android/java_godot_io_wrapper.h index c96abf1101..38a2b710a9 100644 --- a/platform/android/java_godot_io_wrapper.h +++ b/platform/android/java_godot_io_wrapper.h @@ -51,6 +51,7 @@ private: jmethodID _get_locale = 0; jmethodID _get_model = 0; jmethodID _get_screen_DPI = 0; + jmethodID _get_screen_refresh_rate = 0; jmethodID _screen_get_usable_rect = 0; jmethodID _get_unique_id = 0; jmethodID _show_keyboard = 0; @@ -71,6 +72,7 @@ public: String get_locale(); String get_model(); int get_screen_dpi(); + float get_screen_refresh_rate(float fallback); void screen_get_usable_rect(int (&p_rect_xywh)[4]); String get_unique_id(); bool has_vk(); diff --git a/platform/iphone/display_server_iphone.h b/platform/iphone/display_server_iphone.h index 6434483641..7441550f67 100644 --- a/platform/iphone/display_server_iphone.h +++ b/platform/iphone/display_server_iphone.h @@ -129,6 +129,7 @@ public: virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual float screen_get_scale(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; + virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual Vector<DisplayServer::WindowID> get_window_list() const override; diff --git a/platform/iphone/display_server_iphone.mm b/platform/iphone/display_server_iphone.mm index 48bda89fc3..9491c9cf90 100644 --- a/platform/iphone/display_server_iphone.mm +++ b/platform/iphone/display_server_iphone.mm @@ -393,6 +393,10 @@ int DisplayServerIPhone::screen_get_dpi(int p_screen) const { } } +float DisplayServerIPhone::screen_get_refresh_rate(int p_screen) const { + return [UIScreen mainScreen].maximumFramesPerSecond; +} + float DisplayServerIPhone::screen_get_scale(int p_screen) const { return [UIScreen mainScreen].nativeScale; } diff --git a/platform/iphone/export/export_plugin.h b/platform/iphone/export/export_plugin.h index 756bca14dd..93b23f7ee2 100644 --- a/platform/iphone/export/export_plugin.h +++ b/platform/iphone/export/export_plugin.h @@ -130,7 +130,7 @@ class EditorExportPlatformIOS : public EditorExportPlatform { for (int i = 0; i < pname.length(); i++) { char32_t c = pname[i]; - if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-' || c == '.')) { + if (!(is_ascii_alphanumeric_char(c) || c == '-' || c == '.')) { if (r_error) { *r_error = vformat(TTR("The character '%s' is not allowed in Identifier."), String::chr(c)); } diff --git a/platform/javascript/display_server_javascript.cpp b/platform/javascript/display_server_javascript.cpp index 2842fc2f5e..a0e1246c55 100644 --- a/platform/javascript/display_server_javascript.cpp +++ b/platform/javascript/display_server_javascript.cpp @@ -663,7 +663,7 @@ DisplayServerJavaScript::DisplayServerJavaScript(const String &p_rendering_drive godot_js_config_canvas_id_get(canvas_id, 256); // Handle contextmenu, webglcontextlost - godot_js_display_setup_canvas(p_resolution.x, p_resolution.y, p_window_mode == WINDOW_MODE_FULLSCREEN, OS::get_singleton()->is_hidpi_allowed() ? 1 : 0); + godot_js_display_setup_canvas(p_resolution.x, p_resolution.y, (p_window_mode == WINDOW_MODE_FULLSCREEN || p_window_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN), OS::get_singleton()->is_hidpi_allowed() ? 1 : 0); // Check if it's windows. swap_cancel_ok = godot_js_display_is_swap_ok_cancel() == 1; @@ -794,6 +794,10 @@ float DisplayServerJavaScript::screen_get_scale(int p_screen) const { return godot_js_display_pixel_ratio_get(); } +float DisplayServerJavaScript::screen_get_refresh_rate(int p_screen) const { + return SCREEN_REFRESH_RATE_FALLBACK; // Javascript doesn't have much of a need for the screen refresh rate, and there's no native way to do so. +} + Vector<DisplayServer::WindowID> DisplayServerJavaScript::get_window_list() const { Vector<WindowID> ret; ret.push_back(MAIN_WINDOW_ID); @@ -897,6 +901,7 @@ void DisplayServerJavaScript::window_set_mode(WindowMode p_mode, WindowID p_wind } window_mode = WINDOW_MODE_WINDOWED; } break; + case WINDOW_MODE_EXCLUSIVE_FULLSCREEN: case WINDOW_MODE_FULLSCREEN: { int result = godot_js_display_fullscreen_request(); ERR_FAIL_COND_MSG(result, "The request was denied. Remember that enabling fullscreen is only possible from an input callback for the HTML5 platform."); diff --git a/platform/javascript/display_server_javascript.h b/platform/javascript/display_server_javascript.h index 1ae5d68787..b50956d91c 100644 --- a/platform/javascript/display_server_javascript.h +++ b/platform/javascript/display_server_javascript.h @@ -139,6 +139,7 @@ public: virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual float screen_get_scale(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; + virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), bool p_multiline = false, int p_max_input_length = -1, int p_cursor_start = -1, int p_cursor_end = -1) override; virtual void virtual_keyboard_hide() override; diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp index 198eacd1f3..844b5616c4 100644 --- a/platform/linuxbsd/display_server_x11.cpp +++ b/platform/linuxbsd/display_server_x11.cpp @@ -1054,6 +1054,66 @@ int DisplayServerX11::screen_get_dpi(int p_screen) const { return 96; } +float DisplayServerX11::screen_get_refresh_rate(int p_screen) const { + _THREAD_SAFE_METHOD_ + + if (p_screen == SCREEN_OF_MAIN_WINDOW) { + p_screen = window_get_current_screen(); + } + + //invalid screen? + ERR_FAIL_INDEX_V(p_screen, get_screen_count(), SCREEN_REFRESH_RATE_FALLBACK); + + //Use xrandr to get screen refresh rate. + if (xrandr_ext_ok) { + XRRScreenResources *screen_info = XRRGetScreenResources(x11_display, windows[MAIN_WINDOW_ID].x11_window); + if (screen_info) { + RRMode current_mode = 0; + xrr_monitor_info *monitors = nullptr; + + if (xrr_get_monitors) { + int count = 0; + monitors = xrr_get_monitors(x11_display, windows[MAIN_WINDOW_ID].x11_window, true, &count); + ERR_FAIL_INDEX_V(p_screen, count, SCREEN_REFRESH_RATE_FALLBACK); + } else { + ERR_PRINT("An error occured while trying to get the screen refresh rate."); + return SCREEN_REFRESH_RATE_FALLBACK; + } + + bool found_active_mode = false; + for (int crtc = 0; crtc < screen_info->ncrtc; crtc++) { // Loop through outputs to find which one is currently outputting. + XRRCrtcInfo *monitor_info = XRRGetCrtcInfo(x11_display, screen_info, screen_info->crtcs[crtc]); + if (monitor_info->x != monitors[p_screen].x || monitor_info->y != monitors[p_screen].y) { // If X and Y aren't the same as the monitor we're looking for, this isn't the right monitor. Continue. + continue; + } + + if (monitor_info->mode != None) { + current_mode = monitor_info->mode; + found_active_mode = true; + break; + } + } + + if (found_active_mode) { + for (int mode = 0; mode < screen_info->nmode; mode++) { + XRRModeInfo m_info = screen_info->modes[mode]; + if (m_info.id == current_mode) { + return (float)m_info.dotClock / ((float)m_info.hTotal * (float)m_info.vTotal); + } + } + } + + ERR_PRINT("An error occured while trying to get the screen refresh rate."); // We should have returned the refresh rate by now. An error must have occured. + return SCREEN_REFRESH_RATE_FALLBACK; + } else { + ERR_PRINT("An error occured while trying to get the screen refresh rate."); + return SCREEN_REFRESH_RATE_FALLBACK; + } + } + ERR_PRINT("An error occured while trying to get the screen refresh rate."); + return SCREEN_REFRESH_RATE_FALLBACK; +} + bool DisplayServerX11::screen_is_touchscreen(int p_screen) const { _THREAD_SAFE_METHOD_ @@ -1825,6 +1885,7 @@ void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) { XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); } break; + case WINDOW_MODE_EXCLUSIVE_FULLSCREEN: case WINDOW_MODE_FULLSCREEN: { //Remove full-screen wd.fullscreen = false; @@ -1877,6 +1938,7 @@ void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) { XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); } break; + case WINDOW_MODE_EXCLUSIVE_FULLSCREEN: case WINDOW_MODE_FULLSCREEN: { wd.last_position_before_fs = wd.position; @@ -2417,7 +2479,7 @@ Key DisplayServerX11::keyboard_get_keycode_from_physical(Key p_keycode) const { Key keycode_no_mod = p_keycode & KeyModifierMask::CODE_MASK; unsigned int xkeycode = KeyMappingX11::get_xlibcode(keycode_no_mod); KeySym xkeysym = XkbKeycodeToKeysym(x11_display, xkeycode, 0, 0); - if (xkeysym >= 'a' && xkeysym <= 'z') { + if (is_ascii_lower_case(xkeysym)) { xkeysym -= ('a' - 'A'); } diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h index c17e120db5..2d07361deb 100644 --- a/platform/linuxbsd/display_server_x11.h +++ b/platform/linuxbsd/display_server_x11.h @@ -303,6 +303,7 @@ public: 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 int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; + virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; #if defined(DBUS_ENABLED) diff --git a/platform/osx/display_server_osx.h b/platform/osx/display_server_osx.h index 719a45c2a8..4fc733fe2c 100644 --- a/platform/osx/display_server_osx.h +++ b/platform/osx/display_server_osx.h @@ -230,6 +230,7 @@ public: virtual float screen_get_scale(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual float screen_get_max_scale() const override; virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; + virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual Vector<int> get_window_list() const override; diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm index f7add5b688..000be79852 100644 --- a/platform/osx/display_server_osx.mm +++ b/platform/osx/display_server_osx.mm @@ -2203,6 +2203,24 @@ Rect2i DisplayServerOSX::screen_get_usable_rect(int p_screen) const { return Rect2i(); } +float DisplayServerOSX::screen_get_refresh_rate(int p_screen) const { + _THREAD_SAFE_METHOD_ + + if (p_screen == SCREEN_OF_MAIN_WINDOW) { + p_screen = window_get_current_screen(); + } + + NSArray *screenArray = [NSScreen screens]; + if ((NSUInteger)p_screen < [screenArray count]) { + NSDictionary *description = [[screenArray objectAtIndex:p_screen] deviceDescription]; + const CGDisplayModeRef displayMode = CGDisplayCopyDisplayMode([[description objectForKey:@"NSScreenNumber"] unsignedIntValue]); + const double displayRefreshRate = CGDisplayModeGetRefreshRate(displayMode); + return (float)displayRefreshRate; + } + ERR_PRINT("An error occured while trying to get the screen refresh rate."); + return SCREEN_REFRESH_RATE_FALLBACK; +} + Vector<DisplayServer::WindowID> DisplayServerOSX::get_window_list() const { _THREAD_SAFE_METHOD_ @@ -2652,6 +2670,7 @@ void DisplayServerOSX::window_set_mode(WindowMode p_mode, WindowID p_window) { case WINDOW_MODE_MINIMIZED: { [wd.window_object deminiaturize:nil]; } break; + case WINDOW_MODE_EXCLUSIVE_FULLSCREEN: case WINDOW_MODE_FULLSCREEN: { [wd.window_object setLevel:NSNormalWindowLevel]; if (wd.layered_window) { @@ -2685,6 +2704,7 @@ void DisplayServerOSX::window_set_mode(WindowMode p_mode, WindowID p_window) { case WINDOW_MODE_MINIMIZED: { [wd.window_object performMiniaturize:nil]; } break; + case WINDOW_MODE_EXCLUSIVE_FULLSCREEN: case WINDOW_MODE_FULLSCREEN: { if (wd.layered_window) _set_window_per_pixel_transparency_enabled(false, p_window); diff --git a/platform/osx/export/export_plugin.h b/platform/osx/export/export_plugin.h index 0c2ac90206..931ce7e41a 100644 --- a/platform/osx/export/export_plugin.h +++ b/platform/osx/export/export_plugin.h @@ -87,7 +87,7 @@ class EditorExportPlatformOSX : public EditorExportPlatform { for (int i = 0; i < pname.length(); i++) { char32_t c = pname[i]; - if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-' || c == '.')) { + if (!(is_ascii_alphanumeric_char(c) || c == '-' || c == '.')) { if (r_error) { *r_error = vformat(TTR("The character '%s' is not allowed in Identifier."), String::chr(c)); } diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index d288c27016..b340129a16 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -326,6 +326,12 @@ typedef struct { Rect2i rect; } EnumRectData; +typedef struct { + int count; + int screen; + float rate; +} EnumRefreshRateData; + static BOOL CALLBACK _MonitorEnumProcSize(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) { EnumSizeData *data = (EnumSizeData *)dwData; if (data->count == data->screen) { @@ -363,6 +369,26 @@ static BOOL CALLBACK _MonitorEnumProcUsableSize(HMONITOR hMonitor, HDC hdcMonito return TRUE; } +static BOOL CALLBACK _MonitorEnumProcRefreshRate(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) { + EnumRefreshRateData *data = (EnumRefreshRateData *)dwData; + if (data->count == data->screen) { + MONITORINFOEXW minfo; + memset(&minfo, 0, sizeof(minfo)); + minfo.cbSize = sizeof(minfo); + GetMonitorInfoW(hMonitor, &minfo); + + DEVMODEW dm; + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + EnumDisplaySettingsW(minfo.szDevice, ENUM_CURRENT_SETTINGS, &dm); + + data->rate = dm.dmDisplayFrequency; + } + + data->count++; + return TRUE; +} + Rect2i DisplayServerWindows::screen_get_usable_rect(int p_screen) const { _THREAD_SAFE_METHOD_ @@ -446,6 +472,13 @@ int DisplayServerWindows::screen_get_dpi(int p_screen) const { EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcDpi, (LPARAM)&data); return data.dpi; } +float DisplayServerWindows::screen_get_refresh_rate(int p_screen) const { + _THREAD_SAFE_METHOD_ + + EnumRefreshRateData data = { 0, p_screen == SCREEN_OF_MAIN_WINDOW ? window_get_current_screen() : p_screen, SCREEN_REFRESH_RATE_FALLBACK }; + EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcRefreshRate, (LPARAM)&data); + return data.rate; +} bool DisplayServerWindows::screen_is_touchscreen(int p_screen) const { #ifndef _MSC_VER @@ -506,7 +539,7 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod if (p_flags & WINDOW_FLAG_BORDERLESS_BIT) { wd.borderless = true; } - if (p_flags & WINDOW_FLAG_ALWAYS_ON_TOP_BIT && p_mode != WINDOW_MODE_FULLSCREEN) { + if (p_flags & WINDOW_FLAG_ALWAYS_ON_TOP_BIT && p_mode != WINDOW_MODE_FULLSCREEN && p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN) { wd.always_on_top = true; } if (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) { @@ -946,7 +979,7 @@ Size2i DisplayServerWindows::window_get_real_size(WindowID p_window) const { return Size2(); } -void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscreen, bool p_borderless, bool p_resizable, bool p_maximized, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex) { +void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscreen, bool p_multiwindow_fs, bool p_borderless, bool p_resizable, bool p_maximized, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex) { // Windows docs for window styles: // https://docs.microsoft.com/en-us/windows/win32/winmsg/window-styles // https://docs.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles @@ -959,6 +992,9 @@ void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscre if (p_fullscreen || p_borderless) { r_style |= WS_POPUP; // p_borderless was WS_EX_TOOLWINDOW in the past. + if (p_fullscreen && p_multiwindow_fs) { + r_style |= WS_BORDER; // Allows child windows to be displayed on top of full screen. + } } else { if (p_resizable) { if (p_maximized) { @@ -989,7 +1025,7 @@ void DisplayServerWindows::_update_window_style(WindowID p_window, bool p_repain DWORD style = 0; DWORD style_ex = 0; - _get_window_style(p_window == MAIN_WINDOW_ID, wd.fullscreen, wd.borderless, wd.resizable, wd.maximized, wd.no_focus, style, style_ex); + _get_window_style(p_window == MAIN_WINDOW_ID, wd.fullscreen, wd.multiwindow_fs, wd.borderless, wd.resizable, wd.maximized, wd.no_focus, style, style_ex); SetWindowLongPtr(wd.hWnd, GWL_STYLE, style); SetWindowLongPtr(wd.hWnd, GWL_EXSTYLE, style_ex); @@ -1009,10 +1045,11 @@ void DisplayServerWindows::window_set_mode(WindowMode p_mode, WindowID p_window) ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd = windows[p_window]; - if (wd.fullscreen && p_mode != WINDOW_MODE_FULLSCREEN) { + if (wd.fullscreen && p_mode != WINDOW_MODE_FULLSCREEN && p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN) { RECT rect; wd.fullscreen = false; + wd.multiwindow_fs = false; wd.maximized = wd.was_maximized; if (wd.pre_fs_valid) { @@ -1051,7 +1088,15 @@ void DisplayServerWindows::window_set_mode(WindowMode p_mode, WindowID p_window) wd.minimized = true; } - if (p_mode == WINDOW_MODE_FULLSCREEN && !wd.fullscreen) { + if (p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) { + wd.multiwindow_fs = false; + _update_window_style(false); + } else { + wd.multiwindow_fs = true; + _update_window_style(false); + } + + if ((p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) && !wd.fullscreen) { if (wd.minimized) { ShowWindow(wd.hWnd, SW_RESTORE); } @@ -1098,7 +1143,11 @@ DisplayServer::WindowMode DisplayServerWindows::window_get_mode(WindowID p_windo const WindowData &wd = windows[p_window]; if (wd.fullscreen) { - return WINDOW_MODE_FULLSCREEN; + if (wd.multiwindow_fs) { + return WINDOW_MODE_FULLSCREEN; + } else { + return WINDOW_MODE_EXCLUSIVE_FULLSCREEN; + } } else if (wd.minimized) { return WINDOW_MODE_MINIMIZED; } else if (wd.maximized) { @@ -2649,98 +2698,72 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } } break; - case WM_MOVE: { - if (!IsIconic(windows[window_id].hWnd)) { - int x = int16_t(LOWORD(lParam)); - int y = int16_t(HIWORD(lParam)); - windows[window_id].last_pos = Point2(x, y); - - if (!windows[window_id].rect_changed_callback.is_null()) { - Variant size = Rect2i(windows[window_id].last_pos.x, windows[window_id].last_pos.y, windows[window_id].width, windows[window_id].height); - Variant *sizep = &size; - Variant ret; - Callable::CallError ce; - windows[window_id].rect_changed_callback.call((const Variant **)&sizep, 1, ret, ce); + + case WM_WINDOWPOSCHANGED: { + Rect2i window_client_rect; + { + RECT rect; + GetClientRect(hWnd, &rect); + ClientToScreen(hWnd, (POINT *)&rect.left); + ClientToScreen(hWnd, (POINT *)&rect.right); + window_client_rect = Rect2i(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); + } + + WINDOWPOS *window_pos_params = (WINDOWPOS *)lParam; + WindowData &window = windows[window_id]; + + bool rect_changed = false; + if (!(window_pos_params->flags & SWP_NOSIZE) || window_pos_params->flags & SWP_FRAMECHANGED) { + int screen_id = window_get_current_screen(window_id); + Size2i screen_size = screen_get_size(screen_id); + Point2i screen_position = screen_get_position(screen_id); + + window.maximized = false; + window.minimized = false; + window.fullscreen = false; + + if (IsIconic(hWnd)) { + window.minimized = true; + } else if (IsZoomed(hWnd)) { + window.maximized = true; + } else if (window_client_rect.position == screen_position && window_client_rect.size == screen_size) { + window.fullscreen = true; } - } - } break; - case WM_SIZE: { - // Ignore window size change when a SIZE_MINIMIZED event is triggered. - if (wParam != SIZE_MINIMIZED) { - // The new width and height of the client area. - int window_w = LOWORD(lParam); - int window_h = HIWORD(lParam); - - // Set new value to the size if it isn't preserved. - if (window_w > 0 && window_h > 0 && !windows[window_id].preserve_window_size) { - windows[window_id].width = window_w; - windows[window_id].height = window_h; + + if (!window.minimized) { + window.width = window_client_rect.size.width; + window.height = window_client_rect.size.height; #if defined(VULKAN_ENABLED) if (context_vulkan && window_created) { - context_vulkan->window_resize(window_id, windows[window_id].width, windows[window_id].height); + context_vulkan->window_resize(window_id, window.width, window.height); } #endif + rect_changed = true; + } + } - } else { // If the size is preserved. - windows[window_id].preserve_window_size = false; + if (!window.minimized && (!(window_pos_params->flags & SWP_NOMOVE) || window_pos_params->flags & SWP_FRAMECHANGED)) { + window.last_pos = window_client_rect.position; + rect_changed = true; + } - // Restore the old size. - window_set_size(Size2(windows[window_id].width, windows[window_id].height), window_id); + if (rect_changed) { + if (!window.rect_changed_callback.is_null()) { + Variant size = Rect2i(window.last_pos.x, window.last_pos.y, window.width, window.height); + const Variant *args[] = { &size }; + Variant ret; + Callable::CallError ce; + window.rect_changed_callback.call(args, 1, ret, ce); } - } else { // When the window has been minimized, preserve its size. - windows[window_id].preserve_window_size = true; } - // Call windows rect change callback. - if (!windows[window_id].rect_changed_callback.is_null()) { - Variant size = Rect2i(windows[window_id].last_pos.x, windows[window_id].last_pos.y, windows[window_id].width, windows[window_id].height); - Variant *size_ptr = &size; - Variant ret; - Callable::CallError ce; - windows[window_id].rect_changed_callback.call((const Variant **)&size_ptr, 1, ret, ce); - } - - // The window has been maximized. - if (wParam == SIZE_MAXIMIZED) { - windows[window_id].maximized = true; - windows[window_id].minimized = false; - } - // The window has been minimized. - else if (wParam == SIZE_MINIMIZED) { - windows[window_id].maximized = false; - windows[window_id].minimized = true; - windows[window_id].preserve_window_size = false; - } - // The window has been resized, but neither the SIZE_MINIMIZED nor SIZE_MAXIMIZED value applies. - else if (wParam == SIZE_RESTORED) { - windows[window_id].maximized = false; - windows[window_id].minimized = false; - } -#if 0 - if (is_layered_allowed() && layered_window) { - DeleteObject(hBitmap); - - RECT r; - GetWindowRect(hWnd, &r); - dib_size = Size2i(r.right - r.left, r.bottom - r.top); - - BITMAPINFO bmi; - ZeroMemory(&bmi, sizeof(BITMAPINFO)); - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biWidth = dib_size.x; - bmi.bmiHeader.biHeight = dib_size.y; - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = 32; - bmi.bmiHeader.biCompression = BI_RGB; - bmi.bmiHeader.biSizeImage = dib_size.x * dib_size.y * 4; - hBitmap = CreateDIBSection(hDC_dib, &bmi, DIB_RGB_COLORS, (void **)&dib_data, nullptr, 0x0); - SelectObject(hDC_dib, hBitmap); - - ZeroMemory(dib_data, dib_size.x * dib_size.y * 4); - } -#endif + // Return here to prevent WM_MOVE and WM_SIZE from being sent + // See: https://docs.microsoft.com/en-us/windows/win32/winmsg/wm-windowposchanged#remarks + return 0; + } break; + case WM_ENTERSIZEMOVE: { Input::get_singleton()->release_pressed_events(); windows[window_id].move_timer_id = SetTimer(windows[window_id].hWnd, 1, USER_TIMER_MINIMUM, (TIMERPROC) nullptr); @@ -3088,7 +3111,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, DWORD dwExStyle; DWORD dwStyle; - _get_window_style(window_id_counter == MAIN_WINDOW_ID, p_mode == WINDOW_MODE_FULLSCREEN, p_flags & WINDOW_FLAG_BORDERLESS_BIT, !(p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT), p_mode == WINDOW_MODE_MAXIMIZED, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT), dwStyle, dwExStyle); + _get_window_style(window_id_counter == MAIN_WINDOW_ID, (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN), p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN, p_flags & WINDOW_FLAG_BORDERLESS_BIT, !(p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT), p_mode == WINDOW_MODE_MAXIMIZED, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT), dwStyle, dwExStyle); RECT WindowRect; @@ -3097,7 +3120,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, WindowRect.top = p_rect.position.y; WindowRect.bottom = p_rect.position.y + p_rect.size.y; - if (p_mode == WINDOW_MODE_FULLSCREEN) { + if (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN) { int nearest_area = 0; Rect2i screen_rect; for (int i = 0; i < get_screen_count(); i++) { @@ -3140,7 +3163,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, windows.erase(id); return INVALID_WINDOW_ID; } - if (p_mode != WINDOW_MODE_FULLSCREEN) { + if (p_mode != WINDOW_MODE_FULLSCREEN && p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN) { wd.pre_fs_valid = true; } diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 803c2d4836..d36ca97ebe 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -326,12 +326,12 @@ class DisplayServerWindows : public DisplayServer { Vector<Vector2> mpath; - bool preserve_window_size = false; bool pre_fs_valid = false; RECT pre_fs_rect; bool maximized = false; bool minimized = false; bool fullscreen = false; + bool multiwindow_fs = false; bool borderless = false; bool resizable = true; bool window_focused = false; @@ -401,7 +401,7 @@ class DisplayServerWindows : public DisplayServer { WNDPROC user_proc = nullptr; void _send_window_event(const WindowData &wd, WindowEvent p_event); - void _get_window_style(bool p_main_window, bool p_fullscreen, bool p_borderless, bool p_resizable, bool p_maximized, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex); + void _get_window_style(bool p_main_window, bool p_fullscreen, bool p_multiwindow_fs, bool p_borderless, bool p_resizable, bool p_maximized, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex); MouseMode mouse_mode; int restore_mouse_trails = 0; @@ -458,6 +458,7 @@ public: 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 int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; + virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual void screen_set_orientation(ScreenOrientation p_orientation, int p_screen = SCREEN_OF_MAIN_WINDOW) override; |