diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index d9cf65b63c4..52677e80c32 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -1477,6 +1477,7 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF("display/window/size/transparent", false); GLOBAL_DEF("display/window/size/extend_to_title", false); GLOBAL_DEF("display/window/size/no_focus", false); + GLOBAL_DEF("display/window/size/sharp_corners", false); GLOBAL_DEF(PropertyInfo(Variant::INT, "display/window/size/window_width_override", PROPERTY_HINT_RANGE, "0,7680,1,or_greater"), 0); // 8K resolution GLOBAL_DEF(PropertyInfo(Variant::INT, "display/window/size/window_height_override", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"), 0); // 8K resolution diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index 37bf265d20c..91151ae8695 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -2099,7 +2099,11 @@ All mouse events are passed to the underlying window of the same application. - + + Window style is overridden, forcing sharp corners. + [b]Note:[/b] This flag is implemented only on Windows (11). + + Max value of the [enum WindowFlags]. diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 1684edb9b88..1e571e58a17 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -875,6 +875,10 @@ [b]Note:[/b] Certain window managers can be configured to ignore the non-resizable status of a window. Do not rely on this setting as a guarantee that the window will [i]never[/i] be resizable. [b]Note:[/b] This setting is ignored on iOS. + + If [code]true[/code], the main window uses sharp corners by default. + [b]Note:[/b] This property is implemented only on Windows (11). + If [code]true[/code], enables a window manager hint that the main window background [i]can[/i] be transparent. This does not make the background actually transparent. For the background to be transparent, the root viewport must also be made transparent by enabling [member rendering/viewport/transparent_background]. [b]Note:[/b] To use a transparent splash screen, set [member application/boot_splash/bg_color] to [code]Color(0, 0, 0, 0)[/code]. diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml index a37e64ee129..02110f01628 100644 --- a/doc/classes/Window.xml +++ b/doc/classes/Window.xml @@ -659,6 +659,11 @@ If [member ProjectSettings.display/window/subwindows/embed_subwindows] is [code]false[/code], the position is in absolute screen coordinates. This typically applies to editor plugins. If the setting is [code]true[/code], the window's position is in the coordinates of its parent [Viewport]. [b]Note:[/b] This property only works if [member initial_position] is set to [constant WINDOW_INITIAL_POSITION_ABSOLUTE]. + + If [code]true[/code], the [Window] will override the OS window style to display sharp corners. + [b]Note:[/b] This property is implemented only on Windows (11). + [b]Note:[/b] This property only works with native windows. + The window's size in pixels. @@ -842,7 +847,12 @@ All mouse events are passed to the underlying window of the same application. [b]Note:[/b] This flag has no effect in embedded windows. - + + Window style is overridden, forcing sharp corners. + [b]Note:[/b] This flag has no effect in embedded windows. + [b]Note:[/b] This flag is implemented only on Windows (11). + + Max value of the [enum Flags]. diff --git a/main/main.cpp b/main/main.cpp index f7ec817bea3..cd2370ff3e8 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -2413,6 +2413,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph if (bool(GLOBAL_GET("display/window/size/no_focus"))) { window_flags |= DisplayServer::WINDOW_FLAG_NO_FOCUS_BIT; } + if (bool(GLOBAL_GET("display/window/size/sharp_corners"))) { + window_flags |= DisplayServer::WINDOW_FLAG_SHARP_CORNERS_BIT; + } window_mode = (DisplayServer::WindowMode)(GLOBAL_GET("display/window/size/mode").operator int()); int initial_position_type = GLOBAL_GET("display/window/size/initial_position_type").operator int(); if (initial_position_type == 0) { // Absolute. diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index ffa3840181b..21b318ee4dd 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -67,6 +67,18 @@ #define DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 19 #endif +#ifndef DWMWA_WINDOW_CORNER_PREFERENCE +#define DWMWA_WINDOW_CORNER_PREFERENCE 33 +#endif + +#ifndef DWMWCP_DEFAULT +#define DWMWCP_DEFAULT 0 +#endif + +#ifndef DWMWCP_DONOTROUND +#define DWMWCP_DONOTROUND 1 +#endif + #define WM_INDICATOR_CALLBACK_MESSAGE (WM_USER + 1) #if defined(__GNUC__) @@ -1483,6 +1495,9 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod 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_SHARP_CORNERS_BIT) { + wd.sharp_corners = true; + } if (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) { wd.no_focus = true; } @@ -2297,6 +2312,12 @@ void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, W wd.always_on_top = p_enabled; _update_window_style(p_window); } break; + case WINDOW_FLAG_SHARP_CORNERS: { + wd.sharp_corners = p_enabled; + DWORD value = wd.sharp_corners ? DWMWCP_DONOTROUND : DWMWCP_DEFAULT; + ::DwmSetWindowAttribute(wd.hWnd, DWMWA_WINDOW_CORNER_PREFERENCE, &value, sizeof(value)); + _update_window_style(p_window); + } break; case WINDOW_FLAG_TRANSPARENT: { if (p_enabled) { // Enable per-pixel alpha. @@ -3994,6 +4015,10 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA native_menu->_menu_activate(HMENU(lParam), (int)wParam); } break; case WM_CREATE: { + { + DWORD value = windows[window_id].sharp_corners ? DWMWCP_DONOTROUND : DWMWCP_DEFAULT; + ::DwmSetWindowAttribute(windows[window_id].hWnd, DWMWA_WINDOW_CORNER_PREFERENCE, &value, sizeof(value)); + } if (is_dark_mode_supported() && dark_title_available) { BOOL value = is_dark_mode(); @@ -5645,6 +5670,12 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, wd_transient_parent->transient_children.insert(id); } + wd.sharp_corners = p_flags & WINDOW_FLAG_SHARP_CORNERS_BIT; + { + DWORD value = wd.sharp_corners ? DWMWCP_DONOTROUND : DWMWCP_DEFAULT; + ::DwmSetWindowAttribute(wd.hWnd, DWMWA_WINDOW_CORNER_PREFERENCE, &value, sizeof(value)); + } + if (is_dark_mode_supported() && dark_title_available) { BOOL value = is_dark_mode(); ::DwmSetWindowAttribute(wd.hWnd, use_legacy_dark_mode_before_20H1 ? DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 : DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value)); diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 0f0faf892c6..fc72e05b1d6 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -474,6 +474,7 @@ class DisplayServerWindows : public DisplayServer { bool exclusive = false; bool context_created = false; bool mpass = false; + bool sharp_corners = false; // Used to transfer data between events using timer. WPARAM saved_wparam; diff --git a/scene/main/window.cpp b/scene/main/window.cpp index 1b2025ca78e..045c3ae02d8 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -3008,6 +3008,7 @@ void Window::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "popup_window"), "set_flag", "get_flag", FLAG_POPUP); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "extend_to_title"), "set_flag", "get_flag", FLAG_EXTEND_TO_TITLE); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "mouse_passthrough"), "set_flag", "get_flag", FLAG_MOUSE_PASSTHROUGH); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "sharp_corners"), "set_flag", "get_flag", FLAG_SHARP_CORNERS); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "force_native"), "set_force_native", "get_force_native"); ADD_GROUP("Limits", ""); @@ -3061,6 +3062,7 @@ void Window::_bind_methods() { BIND_ENUM_CONSTANT(FLAG_POPUP); BIND_ENUM_CONSTANT(FLAG_EXTEND_TO_TITLE); BIND_ENUM_CONSTANT(FLAG_MOUSE_PASSTHROUGH); + BIND_ENUM_CONSTANT(FLAG_SHARP_CORNERS); BIND_ENUM_CONSTANT(FLAG_MAX); BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_DISABLED); diff --git a/scene/main/window.h b/scene/main/window.h index c2937d61681..6517350b78c 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -62,6 +62,7 @@ public: FLAG_POPUP = DisplayServer::WINDOW_FLAG_POPUP, FLAG_EXTEND_TO_TITLE = DisplayServer::WINDOW_FLAG_EXTEND_TO_TITLE, FLAG_MOUSE_PASSTHROUGH = DisplayServer::WINDOW_FLAG_MOUSE_PASSTHROUGH, + FLAG_SHARP_CORNERS = DisplayServer::WINDOW_FLAG_SHARP_CORNERS, FLAG_MAX = DisplayServer::WINDOW_FLAG_MAX, }; diff --git a/servers/display_server.cpp b/servers/display_server.cpp index ce0d6cb9960..8bfe95aa766 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -1128,6 +1128,7 @@ void DisplayServer::_bind_methods() { BIND_ENUM_CONSTANT(WINDOW_FLAG_POPUP); BIND_ENUM_CONSTANT(WINDOW_FLAG_EXTEND_TO_TITLE); BIND_ENUM_CONSTANT(WINDOW_FLAG_MOUSE_PASSTHROUGH); + BIND_ENUM_CONSTANT(WINDOW_FLAG_SHARP_CORNERS); BIND_ENUM_CONSTANT(WINDOW_FLAG_MAX); BIND_ENUM_CONSTANT(WINDOW_EVENT_MOUSE_ENTER); diff --git a/servers/display_server.h b/servers/display_server.h index f4057c18a89..f25bf334a48 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -381,6 +381,7 @@ public: WINDOW_FLAG_POPUP, WINDOW_FLAG_EXTEND_TO_TITLE, WINDOW_FLAG_MOUSE_PASSTHROUGH, + WINDOW_FLAG_SHARP_CORNERS, WINDOW_FLAG_MAX, }; @@ -394,6 +395,7 @@ public: WINDOW_FLAG_POPUP_BIT = (1 << WINDOW_FLAG_POPUP), WINDOW_FLAG_EXTEND_TO_TITLE_BIT = (1 << WINDOW_FLAG_EXTEND_TO_TITLE), WINDOW_FLAG_MOUSE_PASSTHROUGH_BIT = (1 << WINDOW_FLAG_MOUSE_PASSTHROUGH), + WINDOW_FLAG_SHARP_CORNERS_BIT = (1 << WINDOW_FLAG_SHARP_CORNERS), }; virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i(), bool p_exclusive = false, WindowID p_transient_parent = INVALID_WINDOW_ID);