diff --git a/Userland/Services/WindowServer/WMClientConnection.cpp b/Userland/Services/WindowServer/WMClientConnection.cpp index e1ca5d2b17..b7a4ec57e3 100644 --- a/Userland/Services/WindowServer/WMClientConnection.cpp +++ b/Userland/Services/WindowServer/WMClientConnection.cpp @@ -115,6 +115,34 @@ void WMClientConnection::set_window_minimized(i32 client_id, i32 window_id, bool WindowManager::the().minimize_windows(window, minimized); } +void WMClientConnection::toggle_show_desktop() +{ + bool should_hide = false; + WindowServer::ClientConnection::for_each_client([&should_hide](auto& client) { + client.for_each_window([&should_hide](Window& window) { + if (window.type() == WindowType::Normal && window.is_minimizable()) { + if (!window.is_hidden() && !window.is_minimized()) { + should_hide = true; + return IterationDecision::Break; + } + } + return IterationDecision::Continue; + }); + }); + + WindowServer::ClientConnection::for_each_client([should_hide](auto& client) { + client.for_each_window([should_hide](Window& window) { + if (window.type() == WindowType::Normal && window.is_minimizable()) { + auto state = window.minimized_state(); + if (state == WindowMinimizedState::None || state == WindowMinimizedState::Hidden) { + WindowManager::the().hide_windows(window, should_hide); + } + } + return IterationDecision::Continue; + }); + }); +} + void WMClientConnection::set_event_mask(u32 event_mask) { m_event_mask = event_mask; diff --git a/Userland/Services/WindowServer/WMClientConnection.h b/Userland/Services/WindowServer/WMClientConnection.h index e29ac25760..dfa4389201 100644 --- a/Userland/Services/WindowServer/WMClientConnection.h +++ b/Userland/Services/WindowServer/WMClientConnection.h @@ -23,6 +23,7 @@ public: virtual void set_active_window(i32, i32) override; virtual void set_window_minimized(i32, i32, bool) override; + virtual void toggle_show_desktop() override; virtual void start_window_resize(i32, i32) override; virtual void popup_window_menu(i32, i32, Gfx::IntPoint const&) override; virtual void set_window_taskbar_rect(i32, i32, Gfx::IntRect const&) override; diff --git a/Userland/Services/WindowServer/Window.cpp b/Userland/Services/WindowServer/Window.cpp index 1cd62b4c6b..f59091d099 100644 --- a/Userland/Services/WindowServer/Window.cpp +++ b/Userland/Services/WindowServer/Window.cpp @@ -267,22 +267,22 @@ void Window::update_window_menu_items() if (!m_window_menu) return; - m_window_menu_minimize_item->set_text(m_minimized ? "&Unminimize" : "Mi&nimize"); + m_window_menu_minimize_item->set_text(m_minimized_state != WindowMinimizedState::None ? "&Unminimize" : "Mi&nimize"); m_window_menu_minimize_item->set_enabled(m_minimizable); m_window_menu_maximize_item->set_text(m_maximized ? "&Restore" : "Ma&ximize"); m_window_menu_maximize_item->set_enabled(m_resizable); - m_window_menu_move_item->set_enabled(!m_minimized && !m_maximized && !m_fullscreen); + m_window_menu_move_item->set_enabled(m_minimized_state == WindowMinimizedState::None && !m_maximized && !m_fullscreen); } void Window::set_minimized(bool minimized) { - if (m_minimized == minimized) + if ((m_minimized_state != WindowMinimizedState::None) == minimized) return; if (minimized && !m_minimizable) return; - m_minimized = minimized; + m_minimized_state = minimized ? WindowMinimizedState::Minimized : WindowMinimizedState::None; update_window_menu_items(); Compositor::the().invalidate_occlusions(); Compositor::the().invalidate_screen(frame().render_rect()); @@ -293,6 +293,23 @@ void Window::set_minimized(bool minimized) WindowManager::the().notify_minimization_state_changed(*this); } +void Window::set_hidden(bool hidden) +{ + if ((m_minimized_state != WindowMinimizedState::None) == hidden) + return; + if (hidden && !m_minimizable) + return; + m_minimized_state = hidden ? WindowMinimizedState::Hidden : WindowMinimizedState::None; + update_window_menu_items(); + Compositor::the().invalidate_occlusions(); + Compositor::the().invalidate_screen(frame().render_rect()); + if (!blocking_modal_window()) + start_minimize_animation(); + if (!hidden) + request_update({ {}, size() }); + WindowManager::the().notify_minimization_state_changed(*this); +} + void Window::set_minimizable(bool minimizable) { if (m_minimizable == minimizable) @@ -750,8 +767,8 @@ void Window::handle_window_menu_action(WindowMenuAction action) { switch (action) { case WindowMenuAction::MinimizeOrUnminimize: - WindowManager::the().minimize_windows(*this, !m_minimized); - if (!m_minimized) + WindowManager::the().minimize_windows(*this, m_minimized_state == WindowMinimizedState::None); + if (m_minimized_state == WindowMinimizedState::None) WindowManager::the().move_to_front_and_make_active(*this); break; case WindowMenuAction::MaximizeOrRestore: @@ -791,7 +808,7 @@ void Window::popup_window_menu(const Gfx::IntPoint& position, WindowMenuDefaultA default_action = WindowMenuDefaultAction::Minimize; } m_window_menu_minimize_item->set_default(default_action == WindowMenuDefaultAction::Minimize || default_action == WindowMenuDefaultAction::Unminimize); - m_window_menu_minimize_item->set_icon(m_minimized ? nullptr : &minimize_icon()); + m_window_menu_minimize_item->set_icon(m_minimized_state != WindowMinimizedState::None ? nullptr : &minimize_icon()); m_window_menu_maximize_item->set_default(default_action == WindowMenuDefaultAction::Maximize || default_action == WindowMenuDefaultAction::Restore); m_window_menu_maximize_item->set_icon(m_maximized ? &restore_icon() : &maximize_icon()); m_window_menu_close_item->set_default(default_action == WindowMenuDefaultAction::Close); diff --git a/Userland/Services/WindowServer/Window.h b/Userland/Services/WindowServer/Window.h index 3d75b77d55..a6db32a04d 100644 --- a/Userland/Services/WindowServer/Window.h +++ b/Userland/Services/WindowServer/Window.h @@ -68,6 +68,12 @@ enum class WindowMenuDefaultAction { Restore }; +enum class WindowMinimizedState : u32 { + None = 0, + Minimized, + Hidden, +}; + class Window final : public Core::Object { C_OBJECT(Window); @@ -82,8 +88,11 @@ public: void window_menu_activate_default(); void request_close(); - bool is_minimized() const { return m_minimized; } + bool is_minimized() const { return m_minimized_state != WindowMinimizedState::None; } void set_minimized(bool); + bool is_hidden() const { return m_minimized_state == WindowMinimizedState::Hidden; } + void set_hidden(bool); + WindowMinimizedState minimized_state() const { return m_minimized_state; } bool is_minimizable() const { return m_type == WindowType::Normal && m_minimizable; } void set_minimizable(bool); @@ -383,7 +392,7 @@ private: bool m_frameless { false }; bool m_resizable { false }; Optional m_resize_aspect_ratio {}; - bool m_minimized { false }; + WindowMinimizedState m_minimized_state { WindowMinimizedState::None }; bool m_maximized { false }; bool m_fullscreen { false }; bool m_accessory { false }; diff --git a/Userland/Services/WindowServer/WindowManager.cpp b/Userland/Services/WindowServer/WindowManager.cpp index 146ef50cba..3b15ac4242 100644 --- a/Userland/Services/WindowServer/WindowManager.cpp +++ b/Userland/Services/WindowServer/WindowManager.cpp @@ -1981,6 +1981,18 @@ void WindowManager::minimize_windows(Window& window, bool minimized) }); } +void WindowManager::hide_windows(Window& window, bool hidden) +{ + for_each_window_in_modal_stack(window, [&](auto& w, bool) { + w.set_hidden(hidden); + + if (!hidden) + pick_new_active_window(&window); + + return IterationDecision::Continue; + }); +} + void WindowManager::maximize_windows(Window& window, bool maximized) { for_each_window_in_modal_stack(window, [&](auto& w, bool stack_top) { diff --git a/Userland/Services/WindowServer/WindowManager.h b/Userland/Services/WindowServer/WindowManager.h index 803657f205..179b5e944e 100644 --- a/Userland/Services/WindowServer/WindowManager.h +++ b/Userland/Services/WindowServer/WindowManager.h @@ -221,6 +221,7 @@ public: bool is_menu_doubleclick(Window& window, MouseEvent const& event) const; void minimize_windows(Window&, bool); + void hide_windows(Window&, bool); void maximize_windows(Window&, bool); template diff --git a/Userland/Services/WindowServer/WindowManagerServer.ipc b/Userland/Services/WindowServer/WindowManagerServer.ipc index d01dcb8736..b572e390e3 100644 --- a/Userland/Services/WindowServer/WindowManagerServer.ipc +++ b/Userland/Services/WindowServer/WindowManagerServer.ipc @@ -7,6 +7,7 @@ endpoint WindowManagerServer set_active_window(i32 client_id, i32 window_id) =| set_window_minimized(i32 client_id, i32 window_id, bool minimized) =| + toggle_show_desktop() =| start_window_resize(i32 client_id, i32 window_id) =| popup_window_menu(i32 client_id, i32 window_id, Gfx::IntPoint screen_position) =| set_window_taskbar_rect(i32 client_id, i32 window_id, Gfx::IntRect rect) =|