diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index c328332387d..9dc43497596 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -1513,6 +1513,8 @@ ProjectSettings::ProjectSettings() { 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("display/window/size/minimize_disabled", false); + GLOBAL_DEF("display/window/size/maximize_disabled", 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/AcceptDialog.xml b/doc/classes/AcceptDialog.xml index 198429831ea..ccbe2ddd555 100644 --- a/doc/classes/AcceptDialog.xml +++ b/doc/classes/AcceptDialog.xml @@ -73,6 +73,8 @@ + + The text displayed by the OK button (see [method get_ok_button]). If empty, a default text will be used. diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index 0103cff1df4..93cf2994e5e 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -2195,7 +2195,15 @@ Signals the window manager that this window is supposed to be an implementation-defined "popup" (usually a floating, borderless, untileable and immovable child window). - + + Window minimize button is disabled. + [b]Note:[/b] This flag is implemented on macOS and Windows. + + + Window maximize button is disabled. + [b]Note:[/b] This flag is implemented on macOS and Windows. + + Max value of the [enum WindowFlags]. diff --git a/doc/classes/Popup.xml b/doc/classes/Popup.xml index a7ca692aa0d..e31184112df 100644 --- a/doc/classes/Popup.xml +++ b/doc/classes/Popup.xml @@ -10,6 +10,8 @@ + + diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index a156c0ad275..257cbb8fd0f 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -948,6 +948,12 @@ Main window initial screen, this setting is used only if [member display/window/size/initial_position_type] is set to "Other Screen Center" ([code]2[/code]). [b]Note:[/b] This setting only affects the exported project, or when the project is run from the command line. In the editor, the value of [member EditorSettings.run/window_placement/screen] is used instead. + + If [code]true[/code], the main window's maximize button is disabled. + + + If [code]true[/code], the main window's minimize button is disabled. + Main window mode. See [enum DisplayServer.WindowMode] for possible values and how each mode behaves. [b]Note:[/b] Game embedding is available only in the "Windowed" mode. diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml index 4016f05628f..b8c3d580696 100644 --- a/doc/classes/Window.xml +++ b/doc/classes/Window.xml @@ -626,10 +626,20 @@ 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]. + + If [code]true[/code], the [Window]'s maximize button is disabled. + [b]Note:[/b] If both minimize and maximize buttons are disabled, buttons are fully hidden, and only close button is visible. + [b]Note:[/b] This property is implemented only on macOS and Windows. + If non-zero, the [Window] can't be resized to be smaller than this size. [b]Note:[/b] This property will be ignored in favor of [method get_contents_minimum_size] if [member wrap_controls] is enabled and if its size is bigger. + + If [code]true[/code], the [Window]'s minimize button is disabled. + [b]Note:[/b] If both minimize and maximize buttons are disabled, buttons are fully hidden, and only close button is visible. + [b]Note:[/b] This property is implemented only on macOS and Windows. + Set's the window's current mode. [b]Note:[/b] Fullscreen mode is not exclusive full screen on Windows and Linux. @@ -714,7 +724,7 @@ If [code]true[/code], the [Window] can't be focused nor interacted with. It can still be visible. - If [code]true[/code], the window can't be resized. Minimize and maximize buttons are disabled. + If [code]true[/code], the window can't be resized. If [code]true[/code], the window is visible. @@ -887,7 +897,15 @@ Signals the window manager that this window is supposed to be an implementation-defined "popup" (usually a floating, borderless, untileable and immovable child window). - + + Window minimize button is disabled. + [b]Note:[/b] This flag is implemented on macOS and Windows. + + + Window maximize button is disabled. + [b]Note:[/b] This flag is implemented on macOS and Windows. + + Max value of the [enum Flags]. diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index aa886d9a864..158a8c00297 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -1946,6 +1946,8 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { delete_window = memnew(ConfirmationDialog); delete_window->set_flag(Window::FLAG_RESIZE_DISABLED, true); + delete_window->set_flag(Window::FLAG_MINIMIZE_DISABLED, true); + delete_window->set_flag(Window::FLAG_MAXIMIZE_DISABLED, true); add_child(delete_window); delete_tree = memnew(Tree); diff --git a/main/main.cpp b/main/main.cpp index 0cea51cacf9..339a3029744 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -2542,6 +2542,12 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph if (!bool(GLOBAL_GET("display/window/size/resizable"))) { window_flags |= DisplayServer::WINDOW_FLAG_RESIZE_DISABLED_BIT; } + if (bool(GLOBAL_GET("display/window/size/minimize_disabled"))) { + window_flags |= DisplayServer::WINDOW_FLAG_MINIMIZE_DISABLED_BIT; + } + if (bool(GLOBAL_GET("display/window/size/maximize_disabled"))) { + window_flags |= DisplayServer::WINDOW_FLAG_MAXIMIZE_DISABLED_BIT; + } if (bool(GLOBAL_GET("display/window/size/borderless"))) { window_flags |= DisplayServer::WINDOW_FLAG_BORDERLESS_BIT; } diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index 5f2850c83c5..ee035dfd92b 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -2315,6 +2315,40 @@ void DisplayServerX11::_update_size_hints(WindowID p_window) { XFree(xsh); } +void DisplayServerX11::_update_actions_hints(WindowID p_window) { + WindowData &wd = windows[p_window]; + + Atom prop = XInternAtom(x11_display, "_NET_WM_ALLOWED_ACTIONS", False); + if (prop != None) { + Atom wm_act_max_horz = XInternAtom(x11_display, "_NET_WM_ACTION_MAXIMIZE_HORZ", False); + Atom wm_act_max_vert = XInternAtom(x11_display, "_NET_WM_ACTION_MAXIMIZE_VERT", False); + Atom wm_act_min = XInternAtom(x11_display, "_NET_WM_ACTION_MINIMIZE", False); + Atom type; + int format; + unsigned long len; + unsigned long remaining; + unsigned char *data = nullptr; + if (XGetWindowProperty(x11_display, wd.x11_window, prop, 0, 1024, False, XA_ATOM, &type, &format, &len, &remaining, &data) == Success) { + Atom *atoms = (Atom *)data; + Vector new_atoms; + for (uint64_t i = 0; i < len; i++) { + if (atoms[i] != wm_act_max_horz && atoms[i] != wm_act_max_vert && atoms[i] != wm_act_min) { + new_atoms.push_back(atoms[i]); + } + } + if (!wd.no_max_btn) { + new_atoms.push_back(wm_act_max_horz); + new_atoms.push_back(wm_act_max_vert); + } + if (!wd.no_min_btn) { + new_atoms.push_back(wm_act_min); + } + XChangeProperty(x11_display, wd.x11_window, prop, XA_ATOM, 32, PropModeReplace, (unsigned char *)new_atoms.ptrw(), new_atoms.size()); + XFree(data); + } + } +} + Point2i DisplayServerX11::window_get_position(WindowID p_window) const { _THREAD_SAFE_METHOD_ @@ -3001,6 +3035,18 @@ void DisplayServerX11::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo WindowData &wd = windows[p_window]; switch (p_flag) { + case WINDOW_FLAG_MAXIMIZE_DISABLED: { + wd.no_max_btn = p_enabled; + _update_actions_hints(p_window); + + XFlush(x11_display); + } break; + case WINDOW_FLAG_MINIMIZE_DISABLED: { + wd.no_min_btn = p_enabled; + _update_actions_hints(p_window); + + XFlush(x11_display); + } break; case WINDOW_FLAG_RESIZE_DISABLED: { if (p_enabled && wd.embed_parent) { print_line("Embedded window resize can't be disabled."); @@ -3009,6 +3055,7 @@ void DisplayServerX11::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo wd.resize_disabled = p_enabled; _update_size_hints(p_window); + _update_actions_hints(p_window); XFlush(x11_display); } break; @@ -3095,6 +3142,12 @@ bool DisplayServerX11::window_get_flag(WindowFlags p_flag, WindowID p_window) co const WindowData &wd = windows[p_window]; switch (p_flag) { + case WINDOW_FLAG_MAXIMIZE_DISABLED: { + return wd.no_max_btn; + } break; + case WINDOW_FLAG_MINIMIZE_DISABLED: { + return wd.no_min_btn; + } break; case WINDOW_FLAG_RESIZE_DISABLED: { return wd.resize_disabled; } break; @@ -4842,6 +4895,9 @@ void DisplayServerX11::process_events() { XSync(x11_display, False); XGetWindowAttributes(x11_display, wd.x11_window, &xwa); + _update_actions_hints(window_id); + XFlush(x11_display); + // Set focus when menu window is started. // RevertToPointerRoot is used to make sure we don't lose all focus in case // a subwindow and its parent are both destroyed. diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h index 25bf3111dc2..28334b80850 100644 --- a/platform/linuxbsd/x11/display_server_x11.h +++ b/platform/linuxbsd/x11/display_server_x11.h @@ -199,6 +199,8 @@ class DisplayServerX11 : public DisplayServer { bool on_top = false; bool borderless = false; bool resize_disabled = false; + bool no_min_btn = false; + bool no_max_btn = false; Vector2i last_position_before_fs; bool focused = true; bool minimized = false; @@ -352,6 +354,7 @@ class DisplayServerX11 : public DisplayServer { bool _window_minimize_check(WindowID p_window) const; void _validate_mode_on_map(WindowID p_window); void _update_size_hints(WindowID p_window); + void _update_actions_hints(WindowID p_window); void _set_wm_fullscreen(WindowID p_window, bool p_enabled, bool p_exclusive); void _set_wm_maximized(WindowID p_window, bool p_enabled); void _set_wm_minimized(WindowID p_window, bool p_enabled); diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h index e6cfd976ae4..18f41676b16 100644 --- a/platform/macos/display_server_macos.h +++ b/platform/macos/display_server_macos.h @@ -123,6 +123,8 @@ public: bool on_top = false; bool borderless = false; bool resize_disabled = false; + bool no_min_btn = false; + bool no_max_btn = false; bool no_focus = false; bool is_popup = false; bool mpass = false; diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm index 942d3a27e3e..91482d2aa2f 100644 --- a/platform/macos/display_server_macos.mm +++ b/platform/macos/display_server_macos.mm @@ -2454,6 +2454,10 @@ void DisplayServerMacOS::window_set_mode(WindowMode p_mode, WindowID p_window) { if (wd.resize_disabled) { // Restore resize disabled. [wd.window_object setStyleMask:[wd.window_object styleMask] & ~NSWindowStyleMaskResizable]; } + [[wd.window_object standardWindowButton:NSWindowMiniaturizeButton] setEnabled:!wd.no_min_btn]; + [[wd.window_object standardWindowButton:NSWindowZoomButton] setEnabled:!wd.no_max_btn]; + [[wd.window_object standardWindowButton:NSWindowMiniaturizeButton] setHidden:(wd.no_min_btn && wd.no_max_btn)]; + [[wd.window_object standardWindowButton:NSWindowZoomButton] setHidden:(wd.no_min_btn && wd.no_max_btn)]; if (wd.min_size != Size2i()) { Size2i size = wd.min_size / screen_get_max_scale(); [wd.window_object setContentMinSize:NSMakeSize(size.x, size.y)]; @@ -2539,7 +2543,10 @@ DisplayServer::WindowMode DisplayServerMacOS::window_get_mode(WindowID p_window) } bool DisplayServerMacOS::window_is_maximize_allowed(WindowID p_window) const { - return true; + ERR_FAIL_COND_V(!windows.has(p_window), false); + const WindowData &wd = windows[p_window]; + + return [wd.window_object standardWindowButton:NSWindowZoomButton].enabled; } bool DisplayServerMacOS::window_maximize_on_title_dbl_click() const { @@ -2632,11 +2639,14 @@ void DisplayServerMacOS::window_set_custom_window_buttons(WindowData &p_wd, bool p_wd.window_button_view = [[GodotButtonView alloc] initWithFrame:NSZeroRect]; [p_wd.window_button_view initButtons:window_buttons_spacing offset:NSMakePoint(p_wd.wb_offset.x, p_wd.wb_offset.y) rtl:is_rtl]; [p_wd.window_view addSubview:p_wd.window_button_view]; + + [[p_wd.window_object standardWindowButton:NSWindowMiniaturizeButton] setHidden:(p_wd.no_min_btn && p_wd.no_max_btn)]; + [[p_wd.window_object standardWindowButton:NSWindowZoomButton] setHidden:(p_wd.no_min_btn && p_wd.no_max_btn)]; } else { [p_wd.window_object setTitleVisibility:NSWindowTitleVisible]; [[p_wd.window_object standardWindowButton:NSWindowZoomButton] setHidden:NO]; - [[p_wd.window_object standardWindowButton:NSWindowMiniaturizeButton] setHidden:NO]; - [[p_wd.window_object standardWindowButton:NSWindowCloseButton] setHidden:NO]; + [[p_wd.window_object standardWindowButton:NSWindowMiniaturizeButton] setHidden:(p_wd.no_min_btn && p_wd.no_max_btn)]; + [[p_wd.window_object standardWindowButton:NSWindowZoomButton] setHidden:(p_wd.no_min_btn && p_wd.no_max_btn)]; } } @@ -2647,6 +2657,18 @@ void DisplayServerMacOS::window_set_flag(WindowFlags p_flag, bool p_enabled, Win WindowData &wd = windows[p_window]; switch (p_flag) { + case WINDOW_FLAG_MINIMIZE_DISABLED: { + wd.no_min_btn = p_enabled; + [[wd.window_object standardWindowButton:NSWindowMiniaturizeButton] setEnabled:!p_enabled]; + [[wd.window_object standardWindowButton:NSWindowMiniaturizeButton] setHidden:(wd.no_min_btn && wd.no_max_btn)]; + [[wd.window_object standardWindowButton:NSWindowZoomButton] setHidden:(wd.no_min_btn && wd.no_max_btn)]; + } break; + case WINDOW_FLAG_MAXIMIZE_DISABLED: { + wd.no_max_btn = p_enabled; + [[wd.window_object standardWindowButton:NSWindowZoomButton] setEnabled:!p_enabled]; + [[wd.window_object standardWindowButton:NSWindowMiniaturizeButton] setHidden:(wd.no_min_btn && wd.no_max_btn)]; + [[wd.window_object standardWindowButton:NSWindowZoomButton] setHidden:(wd.no_min_btn && wd.no_max_btn)]; + } break; case WINDOW_FLAG_RESIZE_DISABLED: { wd.resize_disabled = p_enabled; if (wd.fullscreen) { // Fullscreen window should be resizable, style will be applied on exiting fullscreen. @@ -2654,11 +2676,13 @@ void DisplayServerMacOS::window_set_flag(WindowFlags p_flag, bool p_enabled, Win } if (p_enabled) { [wd.window_object setStyleMask:[wd.window_object styleMask] & ~NSWindowStyleMaskResizable]; - [[wd.window_object standardWindowButton:NSWindowZoomButton] setEnabled:NO]; } else { [wd.window_object setStyleMask:[wd.window_object styleMask] | NSWindowStyleMaskResizable]; - [[wd.window_object standardWindowButton:NSWindowZoomButton] setEnabled:YES]; } + [[wd.window_object standardWindowButton:NSWindowMiniaturizeButton] setEnabled:!wd.no_min_btn]; + [[wd.window_object standardWindowButton:NSWindowZoomButton] setEnabled:!wd.no_max_btn]; + [[wd.window_object standardWindowButton:NSWindowMiniaturizeButton] setHidden:(wd.no_min_btn && wd.no_max_btn)]; + [[wd.window_object standardWindowButton:NSWindowZoomButton] setHidden:(wd.no_min_btn && wd.no_max_btn)]; } break; case WINDOW_FLAG_EXTEND_TO_TITLE: { NSRect rect = [wd.window_object frame]; @@ -2700,6 +2724,8 @@ void DisplayServerMacOS::window_set_flag(WindowFlags p_flag, bool p_enabled, Win } } else { [wd.window_object setStyleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | (wd.extend_to_title ? NSWindowStyleMaskFullSizeContentView : 0) | (wd.resize_disabled ? 0 : NSWindowStyleMaskResizable)]; + [[wd.window_object standardWindowButton:NSWindowMiniaturizeButton] setEnabled:!wd.no_min_btn]; + [[wd.window_object standardWindowButton:NSWindowZoomButton] setEnabled:!wd.no_max_btn]; [wd.window_object setHasShadow:YES]; if (wd.layered_window) { // Note: transparent and not borderless - set alpha to non-zero value to ensure window shadow is rendered correctly. @@ -2780,6 +2806,12 @@ bool DisplayServerMacOS::window_get_flag(WindowFlags p_flag, WindowID p_window) const WindowData &wd = windows[p_window]; switch (p_flag) { + case WINDOW_FLAG_MAXIMIZE_DISABLED: { + return wd.no_max_btn; + } break; + case WINDOW_FLAG_MINIMIZE_DISABLED: { + return wd.no_min_btn; + } break; case WINDOW_FLAG_RESIZE_DISABLED: { return wd.resize_disabled; } break; diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 5d3fe5aa113..6fbb89b98cf 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -1622,6 +1622,12 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod if (p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT) { wd.resizable = false; } + if (p_flags & WINDOW_FLAG_MINIMIZE_DISABLED_BIT) { + wd.no_min_btn = true; + } + if (p_flags & WINDOW_FLAG_MAXIMIZE_DISABLED_BIT) { + wd.no_max_btn = true; + } if (p_flags & WINDOW_FLAG_BORDERLESS_BIT) { wd.borderless = true; } @@ -2303,7 +2309,7 @@ Size2i DisplayServerWindows::window_get_size_with_decorations(WindowID p_window) return Size2(); } -void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_initialized, bool p_fullscreen, bool p_multiwindow_fs, bool p_borderless, bool p_resizable, bool p_minimized, bool p_maximized, bool p_maximized_fs, bool p_no_activate_focus, bool p_embed_child, DWORD &r_style, DWORD &r_style_ex) { +void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_initialized, bool p_fullscreen, bool p_multiwindow_fs, bool p_borderless, bool p_resizable, bool p_no_min_btn, bool p_no_max_btn, bool p_minimized, bool p_maximized, bool p_maximized_fs, bool p_no_activate_focus, bool p_embed_child, 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 @@ -2331,9 +2337,11 @@ void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_initiali r_style |= WS_MAXIMIZE; } if (!p_fullscreen) { - r_style |= WS_SYSMENU | WS_MINIMIZEBOX; - - if (p_resizable) { + r_style |= WS_SYSMENU; + if (!p_no_min_btn) { + r_style |= WS_MINIMIZEBOX; + } + if (!p_no_max_btn) { r_style |= WS_MAXIMIZEBOX; } } @@ -2346,11 +2354,23 @@ void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_initiali } else { r_style = WS_OVERLAPPEDWINDOW; } + if (p_no_min_btn) { + r_style &= ~WS_MINIMIZEBOX; + } + if (p_no_max_btn) { + r_style &= ~WS_MAXIMIZEBOX; + } } else { if (p_minimized) { - r_style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MINIMIZE; + r_style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZE; } else { - r_style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; + r_style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU; + } + if (!p_no_min_btn) { + r_style |= WS_MINIMIZEBOX; + } + if (!p_no_max_btn) { + r_style |= WS_MAXIMIZEBOX; } } } @@ -2380,7 +2400,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.initialized, wd.fullscreen, wd.multiwindow_fs, wd.borderless, wd.resizable, wd.minimized, wd.maximized, wd.maximized_fs, wd.no_focus || wd.is_popup, wd.parent_hwnd, style, style_ex); + _get_window_style(p_window == MAIN_WINDOW_ID, wd.initialized, wd.fullscreen, wd.multiwindow_fs, wd.borderless, wd.resizable, wd.no_min_btn, wd.no_max_btn, wd.minimized, wd.maximized, wd.maximized_fs, wd.no_focus || wd.is_popup, wd.parent_hwnd, style, style_ex); SetWindowLongPtr(wd.hWnd, GWL_STYLE, style); SetWindowLongPtr(wd.hWnd, GWL_EXSTYLE, style_ex); @@ -2535,10 +2555,10 @@ bool DisplayServerWindows::window_is_maximize_allowed(WindowID p_window) const { _THREAD_SAFE_METHOD_ ERR_FAIL_COND_V(!windows.has(p_window), false); + const WindowData &wd = windows[p_window]; - // FIXME: Implement this, or confirm that it should always be true. - - return true; + const DWORD style = GetWindowLongPtr(wd.hWnd, GWL_STYLE); + return (style & WS_MAXIMIZEBOX) == WS_MAXIMIZEBOX; } void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) { @@ -2547,6 +2567,14 @@ void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, W ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd = windows[p_window]; switch (p_flag) { + case WINDOW_FLAG_MINIMIZE_DISABLED: { + wd.no_min_btn = p_enabled; + _update_window_style(p_window); + } break; + case WINDOW_FLAG_MAXIMIZE_DISABLED: { + wd.no_max_btn = p_enabled; + _update_window_style(p_window); + } break; case WINDOW_FLAG_RESIZE_DISABLED: { if (p_enabled && wd.parent_hwnd) { print_line("Embedded window resize can't be disabled."); @@ -2642,6 +2670,12 @@ bool DisplayServerWindows::window_get_flag(WindowFlags p_flag, WindowID p_window ERR_FAIL_COND_V(!windows.has(p_window), false); const WindowData &wd = windows[p_window]; switch (p_flag) { + case WINDOW_FLAG_MAXIMIZE_DISABLED: { + return wd.no_max_btn; + } break; + case WINDOW_FLAG_MINIMIZE_DISABLED: { + return wd.no_min_btn; + } break; case WINDOW_FLAG_RESIZE_DISABLED: { return !wd.resizable; } break; @@ -6153,7 +6187,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, DWORD dwExStyle; DWORD dwStyle; - _get_window_style(window_id_counter == MAIN_WINDOW_ID, false, (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_MINIMIZED, p_mode == WINDOW_MODE_MAXIMIZED, false, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) | (p_flags & WINDOW_FLAG_POPUP_BIT), p_parent_hwnd, dwStyle, dwExStyle); + _get_window_style(window_id_counter == MAIN_WINDOW_ID, false, (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_flags & WINDOW_FLAG_MINIMIZE_DISABLED_BIT, p_flags & WINDOW_FLAG_MAXIMIZE_DISABLED_BIT, p_mode == WINDOW_MODE_MINIMIZED, p_mode == WINDOW_MODE_MAXIMIZED, false, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) | (p_flags & WINDOW_FLAG_POPUP_BIT), p_parent_hwnd, dwStyle, dwExStyle); int rq_screen = get_screen_from_rect(p_rect); if (rq_screen < 0) { diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index cf50408f760..4365fdcd364 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -479,6 +479,8 @@ class DisplayServerWindows : public DisplayServer { bool multiwindow_fs = false; bool borderless = false; bool resizable = true; + bool no_min_btn = false; + bool no_max_btn = false; bool window_focused = false; int activate_state = 0; bool was_maximized_pre_fs = false; @@ -617,7 +619,7 @@ class DisplayServerWindows : public DisplayServer { HashMap pointer_last_pos; void _send_window_event(const WindowData &wd, WindowEvent p_event); - void _get_window_style(bool p_main_window, bool p_initialized, bool p_fullscreen, bool p_multiwindow_fs, bool p_borderless, bool p_resizable, bool p_minimized, bool p_maximized, bool p_maximized_fs, bool p_no_activate_focus, bool p_embed_child, DWORD &r_style, DWORD &r_style_ex); + void _get_window_style(bool p_main_window, bool p_initialized, bool p_fullscreen, bool p_multiwindow_fs, bool p_borderless, bool p_resizable, bool p_no_min_btn, bool p_no_max_btn, bool p_minimized, bool p_maximized, bool p_maximized_fs, bool p_no_activate_focus, bool p_embed_child, DWORD &r_style, DWORD &r_style_ex); MouseMode mouse_mode; MouseMode mouse_mode_base = MOUSE_MODE_VISIBLE; diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index feea863e5ae..43aead7c41b 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -448,6 +448,9 @@ AcceptDialog::AcceptDialog() { set_clamp_to_embedder(true); set_keep_title_visible(true); + set_flag(FLAG_MINIMIZE_DISABLED, true); + set_flag(FLAG_MAXIMIZE_DISABLED, true); + bg_panel = memnew(Panel); add_child(bg_panel, false, INTERNAL_MODE_FRONT); diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp index cb88492d2c3..11d74e04065 100644 --- a/scene/gui/popup.cpp +++ b/scene/gui/popup.cpp @@ -223,6 +223,8 @@ Popup::Popup() { set_transient(true); set_flag(FLAG_BORDERLESS, true); set_flag(FLAG_RESIZE_DISABLED, true); + set_flag(FLAG_MINIMIZE_DISABLED, true); + set_flag(FLAG_MAXIMIZE_DISABLED, true); set_flag(FLAG_POPUP, true); set_flag(FLAG_POPUP_WM_HINT, true); } diff --git a/scene/main/window.cpp b/scene/main/window.cpp index f5e19d2eef7..50368ed10c4 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -3106,6 +3106,8 @@ void Window::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "sharp_corners"), "set_flag", "get_flag", FLAG_SHARP_CORNERS); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "exclude_from_capture"), "set_flag", "get_flag", FLAG_EXCLUDE_FROM_CAPTURE); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "popup_wm_hint"), "set_flag", "get_flag", FLAG_POPUP_WM_HINT); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "minimize_disabled"), "set_flag", "get_flag", FLAG_MINIMIZE_DISABLED); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "maximize_disabled"), "set_flag", "get_flag", FLAG_MAXIMIZE_DISABLED); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "force_native"), "set_force_native", "get_force_native"); ADD_GROUP("Limits", ""); @@ -3163,6 +3165,8 @@ void Window::_bind_methods() { BIND_ENUM_CONSTANT(FLAG_SHARP_CORNERS); BIND_ENUM_CONSTANT(FLAG_EXCLUDE_FROM_CAPTURE); BIND_ENUM_CONSTANT(FLAG_POPUP_WM_HINT); + BIND_ENUM_CONSTANT(FLAG_MINIMIZE_DISABLED); + BIND_ENUM_CONSTANT(FLAG_MAXIMIZE_DISABLED); 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 abce073bc51..505582bfa47 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -65,6 +65,8 @@ public: FLAG_SHARP_CORNERS = DisplayServer::WINDOW_FLAG_SHARP_CORNERS, FLAG_EXCLUDE_FROM_CAPTURE = DisplayServer::WINDOW_FLAG_EXCLUDE_FROM_CAPTURE, FLAG_POPUP_WM_HINT = DisplayServer::WINDOW_FLAG_POPUP_WM_HINT, + FLAG_MINIMIZE_DISABLED = DisplayServer::WINDOW_FLAG_MINIMIZE_DISABLED, + FLAG_MAXIMIZE_DISABLED = DisplayServer::WINDOW_FLAG_MAXIMIZE_DISABLED, FLAG_MAX = DisplayServer::WINDOW_FLAG_MAX, }; diff --git a/servers/display_server.cpp b/servers/display_server.cpp index 32fdc36cbe4..0403f2f0eec 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -1198,6 +1198,8 @@ void DisplayServer::_bind_methods() { BIND_ENUM_CONSTANT(WINDOW_FLAG_SHARP_CORNERS); BIND_ENUM_CONSTANT(WINDOW_FLAG_EXCLUDE_FROM_CAPTURE); BIND_ENUM_CONSTANT(WINDOW_FLAG_POPUP_WM_HINT); + BIND_ENUM_CONSTANT(WINDOW_FLAG_MINIMIZE_DISABLED); + BIND_ENUM_CONSTANT(WINDOW_FLAG_MAXIMIZE_DISABLED); 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 345d0752bdb..fcad959008c 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -409,6 +409,8 @@ public: WINDOW_FLAG_SHARP_CORNERS, WINDOW_FLAG_EXCLUDE_FROM_CAPTURE, WINDOW_FLAG_POPUP_WM_HINT, + WINDOW_FLAG_MINIMIZE_DISABLED, + WINDOW_FLAG_MAXIMIZE_DISABLED, WINDOW_FLAG_MAX, }; @@ -425,6 +427,8 @@ public: WINDOW_FLAG_SHARP_CORNERS_BIT = (1 << WINDOW_FLAG_SHARP_CORNERS), WINDOW_FLAG_EXCLUDE_FROM_CAPTURE_BIT = (1 << WINDOW_FLAG_EXCLUDE_FROM_CAPTURE), WINDOW_FLAG_POPUP_WM_HINT_BIT = (1 << WINDOW_FLAG_POPUP_WM_HINT), + WINDOW_FLAG_MINIMIZE_DISABLED_BIT = (1 << WINDOW_FLAG_MINIMIZE_DISABLED), + WINDOW_FLAG_MAXIMIZE_DISABLED_BIT = (1 << WINDOW_FLAG_MAXIMIZE_DISABLED), }; 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);