From 641893104ae28392c3b5c1502370982d060d67b7 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 12 May 2019 21:32:02 +0200 Subject: [PATCH] WindowServer: Add a maximize/unmaximize button to windows. --- Servers/WindowServer/WSButton.cpp | 4 +- Servers/WindowServer/WSButton.h | 6 ++- Servers/WindowServer/WSWindow.cpp | 15 ++++++++ Servers/WindowServer/WSWindow.h | 5 +++ Servers/WindowServer/WSWindowFrame.cpp | 47 +++++++++++++++++++++++- Servers/WindowServer/WSWindowFrame.h | 2 +- Servers/WindowServer/WSWindowManager.cpp | 21 +++++++++++ Servers/WindowServer/WSWindowManager.h | 2 + 8 files changed, 95 insertions(+), 7 deletions(-) diff --git a/Servers/WindowServer/WSButton.cpp b/Servers/WindowServer/WSButton.cpp index 24e639164f..bf26ffb552 100644 --- a/Servers/WindowServer/WSButton.cpp +++ b/Servers/WindowServer/WSButton.cpp @@ -5,7 +5,7 @@ #include #include -WSButton::WSButton(WSWindowFrame& frame, Retained&& bitmap, Function&& on_click_handler) +WSButton::WSButton(WSWindowFrame& frame, Retained&& bitmap, Function&& on_click_handler) : on_click(move(on_click_handler)) , m_frame(frame) , m_bitmap(move(bitmap)) @@ -47,7 +47,7 @@ void WSButton::on_mouse_event(const WSMouseEvent& event) m_pressed = false; if (rect().contains(event.position())) { if (on_click) - on_click(); + on_click(*this); } if (old_pressed != m_pressed) wm.invalidate(screen_rect()); diff --git a/Servers/WindowServer/WSButton.h b/Servers/WindowServer/WSButton.h index 5ceeff41e4..bd87932e6f 100644 --- a/Servers/WindowServer/WSButton.h +++ b/Servers/WindowServer/WSButton.h @@ -12,7 +12,7 @@ class WSWindowFrame; class WSButton : public Weakable { public: - WSButton(WSWindowFrame&, Retained&&, Function&& on_click_handler); + WSButton(WSWindowFrame&, Retained&&, Function&& on_click_handler); ~WSButton(); Rect relative_rect() const { return m_relative_rect; } @@ -25,10 +25,12 @@ public: void on_mouse_event(const WSMouseEvent&); - Function on_click; + Function on_click; bool is_visible() const { return m_visible; } + void set_bitmap(const CharacterBitmap& bitmap) { m_bitmap = bitmap; } + private: WSWindowFrame& m_frame; Rect m_relative_rect; diff --git a/Servers/WindowServer/WSWindow.cpp b/Servers/WindowServer/WSWindow.cpp index 20e50ac467..5c81654e7e 100644 --- a/Servers/WindowServer/WSWindow.cpp +++ b/Servers/WindowServer/WSWindow.cpp @@ -134,6 +134,21 @@ void WSWindow::set_minimized(bool minimized) WSWindowManager::the().notify_minimization_state_changed(*this); } +void WSWindow::set_maximized(bool maximized) +{ + if (m_maximized == maximized) + return; + m_maximized = maximized; + auto old_rect = m_rect; + if (maximized) { + m_unmaximized_rect = m_rect; + set_rect(WSWindowManager::the().maximized_window_rect(*this)); + } else { + set_rect(m_unmaximized_rect); + } + WSEventLoop::the().post_event(*this, make(old_rect, m_rect)); +} + void WSWindow::event(CEvent& event) { if (m_internal_owner) diff --git a/Servers/WindowServer/WSWindow.h b/Servers/WindowServer/WSWindow.h index 072e64fca2..7b4d15af1f 100644 --- a/Servers/WindowServer/WSWindow.h +++ b/Servers/WindowServer/WSWindow.h @@ -29,6 +29,9 @@ public: bool is_minimized() const { return m_minimized; } void set_minimized(bool); + bool is_maximized() const { return m_maximized; } + void set_maximized(bool); + WSWindowFrame& frame() { return m_frame; } const WSWindowFrame& frame() const { return m_frame; } @@ -152,6 +155,7 @@ private: bool m_resizable { false }; bool m_listens_to_wm_events { false }; bool m_minimized { false }; + bool m_maximized { false }; RetainPtr m_backing_store; RetainPtr m_last_backing_store; int m_window_id { -1 }; @@ -165,4 +169,5 @@ private: Color m_background_color { Color::LightGray }; unsigned m_wm_event_mask { 0 }; DisjointRectSet m_pending_paint_rects; + Rect m_unmaximized_rect; }; diff --git a/Servers/WindowServer/WSWindowFrame.cpp b/Servers/WindowServer/WSWindowFrame.cpp index 1b93161a14..32b0539d4e 100644 --- a/Servers/WindowServer/WSWindowFrame.cpp +++ b/Servers/WindowServer/WSWindowFrame.cpp @@ -42,6 +42,38 @@ static CharacterBitmap* s_minimize_button_bitmap; static const int s_minimize_button_bitmap_width = 8; static const int s_minimize_button_bitmap_height = 9; +static const char* s_maximize_button_bitmap_data = { + " " + " " + " " + " ## " + " #### " + " ###### " + " " + " " + " " +}; + +static CharacterBitmap* s_maximize_button_bitmap; +static const int s_maximize_button_bitmap_width = 8; +static const int s_maximize_button_bitmap_height = 9; + +static const char* s_unmaximize_button_bitmap_data = { + " " + " ## " + " #### " + " ###### " + " " + " ###### " + " #### " + " ## " + " " +}; + +static CharacterBitmap* s_unmaximize_button_bitmap; +static const int s_unmaximize_button_bitmap_width = 8; +static const int s_unmaximize_button_bitmap_height = 9; + WSWindowFrame::WSWindowFrame(WSWindow& window) : m_window(window) { @@ -51,14 +83,25 @@ WSWindowFrame::WSWindowFrame(WSWindow& window) if (!s_minimize_button_bitmap) s_minimize_button_bitmap = &CharacterBitmap::create_from_ascii(s_minimize_button_bitmap_data, s_minimize_button_bitmap_width, s_minimize_button_bitmap_height).leak_ref(); - m_buttons.append(make(*this, *s_close_button_bitmap, [this] { + if (!s_maximize_button_bitmap) + s_maximize_button_bitmap = &CharacterBitmap::create_from_ascii(s_maximize_button_bitmap_data, s_maximize_button_bitmap_width, s_maximize_button_bitmap_height).leak_ref(); + + if (!s_unmaximize_button_bitmap) + s_unmaximize_button_bitmap = &CharacterBitmap::create_from_ascii(s_unmaximize_button_bitmap_data, s_unmaximize_button_bitmap_width, s_unmaximize_button_bitmap_height).leak_ref(); + + m_buttons.append(make(*this, *s_close_button_bitmap, [this] (auto&) { WSEvent close_request(WSEvent::WindowCloseRequest); m_window.event(close_request); })); - m_buttons.append(make(*this, *s_minimize_button_bitmap, [this] { + m_buttons.append(make(*this, *s_minimize_button_bitmap, [this] (auto&) { m_window.set_minimized(true); })); + + m_buttons.append(make(*this, *s_maximize_button_bitmap, [this] (auto& button) { + m_window.set_maximized(!m_window.is_maximized()); + button.set_bitmap(m_window.is_maximized() ? *s_unmaximize_button_bitmap : *s_maximize_button_bitmap); + })); } WSWindowFrame::~WSWindowFrame() diff --git a/Servers/WindowServer/WSWindowFrame.h b/Servers/WindowServer/WSWindowFrame.h index 3e7852c531..c004446870 100644 --- a/Servers/WindowServer/WSWindowFrame.h +++ b/Servers/WindowServer/WSWindowFrame.h @@ -20,11 +20,11 @@ public: void notify_window_rect_changed(const Rect& old_rect, const Rect& new_rect); void invalidate_title_bar(); -private: Rect title_bar_rect() const; Rect title_bar_icon_rect() const; Rect title_bar_text_rect() const; +private: WSWindow& m_window; Vector> m_buttons; }; diff --git a/Servers/WindowServer/WSWindowManager.cpp b/Servers/WindowServer/WSWindowManager.cpp index 957015f359..0a7116c755 100644 --- a/Servers/WindowServer/WSWindowManager.cpp +++ b/Servers/WindowServer/WSWindowManager.cpp @@ -1218,3 +1218,24 @@ void WSWindowManager::set_resize_candidate(WSWindow& window, ResizeDirection dir m_resize_candidate = window.make_weak_ptr(); m_resize_direction = direction; } + +Rect WSWindowManager::maximized_window_rect(const WSWindow& window) const +{ + Rect rect = m_screen_rect; + + // Subtract window title bar (leaving the border) + rect.set_y(rect.y() + window.frame().title_bar_rect().height()); + rect.set_height(rect.height() - window.frame().title_bar_rect().height()); + + // Subtract menu bar + rect.set_y(rect.y() + menubar_rect().height()); + rect.set_height(rect.height() - menubar_rect().height()); + + // Subtract taskbar window height if present + const_cast(this)->for_each_visible_window_of_type_from_back_to_front(WSWindowType::Taskbar, [&rect] (WSWindow& taskbar_window) { + rect.set_height(rect.height() - taskbar_window.height()); + return IterationDecision::Abort; + }); + + return rect; +} diff --git a/Servers/WindowServer/WSWindowManager.h b/Servers/WindowServer/WSWindowManager.h index 7d607f9d11..634427233c 100644 --- a/Servers/WindowServer/WSWindowManager.h +++ b/Servers/WindowServer/WSWindowManager.h @@ -46,6 +46,8 @@ public: void notify_minimization_state_changed(WSWindow&); void notify_client_changed_app_menubar(WSClientConnection&); + Rect maximized_window_rect(const WSWindow&) const; + WSWindow* active_window() { return m_active_window.ptr(); } const WSClientConnection* active_client() const;