From b85fe0bd076e4c5f4e353ad2d9fe6ed003d818d1 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Wed, 6 Mar 2019 10:03:10 +0100 Subject: [PATCH] WindowServer: Let the window switcher render itself as a WSWindow. Much better than drawing directly into the back buffer. --- WindowServer/WSMenu.cpp | 4 +- WindowServer/WSMenu.h | 10 +++-- WindowServer/WSWindow.cpp | 15 +++---- WindowServer/WSWindow.h | 4 +- WindowServer/WSWindowManager.cpp | 69 ++++++++++++++++++++----------- WindowServer/WSWindowSwitcher.cpp | 28 ++++++++----- WindowServer/WSWindowSwitcher.h | 15 ++++--- WindowServer/WSWindowType.h | 3 +- 8 files changed, 89 insertions(+), 59 deletions(-) diff --git a/WindowServer/WSMenu.cpp b/WindowServer/WSMenu.cpp index 383cde2472..b8b457122f 100644 --- a/WindowServer/WSMenu.cpp +++ b/WindowServer/WSMenu.cpp @@ -69,7 +69,7 @@ WSWindow& WSMenu::ensure_menu_window() next_item_location.move_by(0, height); } - auto window = make(*this); + auto window = make(*this, WSWindowType::Menu); window->set_opacity(0.95f); window->set_rect(0, 0, width(), height()); m_menu_window = move(window); @@ -107,7 +107,7 @@ void WSMenu::draw() } } -void WSMenu::on_window_message(WSMessage& message) +void WSMenu::on_message(WSMessage& message) { ASSERT(menu_window()); if (message.type() == WSMessage::MouseMove) { diff --git a/WindowServer/WSMenu.h b/WindowServer/WSMenu.h index 107d6fc78f..e7e6c34ef0 100644 --- a/WindowServer/WSMenu.h +++ b/WindowServer/WSMenu.h @@ -4,7 +4,8 @@ #include #include #include -#include "WSMenuItem.h" +#include +#include class WSClientConnection; class WSMenuBar; @@ -12,10 +13,10 @@ class WSMessage; class WSWindow; class Font; -class WSMenu : public Weakable { +class WSMenu final : public WSMessageReceiver { public: WSMenu(WSClientConnection*, int menu_id, String&& name); - ~WSMenu(); + virtual ~WSMenu() override; WSClientConnection* client() { return m_client; } const WSClientConnection* client() const { return m_client; } @@ -58,7 +59,6 @@ public: int left_padding() const { return 14; } int right_padding() const { return 14; } - void on_window_message(WSMessage&); void draw(); const Font& font() const; @@ -73,6 +73,8 @@ public: void close(); private: + virtual void on_message(WSMessage&) override; + int padding_between_text_and_shortcut() const { return 50; } void did_activate(WSMenuItem&); WSClientConnection* m_client { nullptr }; diff --git a/WindowServer/WSWindow.cpp b/WindowServer/WSWindow.cpp index 6105721fd8..7cfbc4b6e2 100644 --- a/WindowServer/WSWindow.cpp +++ b/WindowServer/WSWindow.cpp @@ -5,9 +5,9 @@ #include #include -WSWindow::WSWindow(WSMenu& menu) - : m_type(WSWindowType::Menu) - , m_menu(&menu) +WSWindow::WSWindow(WSMessageReceiver& internal_owner, WSWindowType type) + : m_internal_owner(&internal_owner) + , m_type(type) { WSWindowManager::the().add_window(*this); } @@ -36,12 +36,11 @@ void WSWindow::set_title(String&& title) void WSWindow::set_rect(const Rect& rect) { Rect old_rect; - ASSERT(m_client || m_menu); if (m_rect == rect) return; old_rect = m_rect; m_rect = rect; - if (m_menu && (!m_backing_store || old_rect.size() != rect.size())) { + if (!m_client && (!m_backing_store || old_rect.size() != rect.size())) { m_backing_store = GraphicsBitmap::create(GraphicsBitmap::Format::RGB32, m_rect.size()); } WSWindowManager::the().notify_rect_changed(*this, old_rect, rect); @@ -61,10 +60,8 @@ static WSAPI_MouseButton to_api(MouseButton button) void WSWindow::on_message(WSMessage& message) { - if (m_menu) { - m_menu->on_window_message(message); - return; - } + if (m_internal_owner) + return m_internal_owner->on_message(message); WSAPI_ServerMessage server_message; server_message.window_id = window_id(); diff --git a/WindowServer/WSWindow.h b/WindowServer/WSWindow.h index 9f506fed24..26c4a41bef 100644 --- a/WindowServer/WSWindow.h +++ b/WindowServer/WSWindow.h @@ -13,7 +13,7 @@ class WSMenu; class WSWindow final : public WSMessageReceiver, public InlineLinkedListNode { public: WSWindow(WSClientConnection&, int window_id); - explicit WSWindow(WSMenu&); + WSWindow(WSMessageReceiver&, WSWindowType); virtual ~WSWindow() override; WSClientConnection* client() { return m_client; } @@ -85,6 +85,7 @@ public: private: WSClientConnection* m_client { nullptr }; + WSMessageReceiver* m_internal_owner { nullptr }; String m_title; Rect m_rect; WSWindowType m_type { WSWindowType::Normal }; @@ -92,7 +93,6 @@ private: bool m_visible { true }; bool m_has_alpha_channel { false }; bool m_has_painted_since_last_resize { false }; - WSMenu* m_menu { nullptr }; RetainPtr m_backing_store; int m_window_id { -1 }; float m_opacity { 1 }; diff --git a/WindowServer/WSWindowManager.cpp b/WindowServer/WSWindowManager.cpp index 8c9aead44e..479cf5b47e 100644 --- a/WindowServer/WSWindowManager.cpp +++ b/WindowServer/WSWindowManager.cpp @@ -82,6 +82,16 @@ static inline Rect outer_window_rect(const Rect& window) return rect; } +static inline Rect outer_window_rect(const WSWindow& window) +{ + if (window.type() == WSWindowType::Menu) + return menu_window_rect(window.rect()); + if (window.type() == WSWindowType::WindowSwitcher) + return window.rect(); + ASSERT(window.type() == WSWindowType::Normal); + return outer_window_rect(window.rect()); +} + static WSWindowManager* s_the; WSWindowManager& WSWindowManager::the() @@ -384,9 +394,12 @@ void WSWindowManager::paint_window_frame(WSWindow& window) return; } + if (window.type() == WSWindowType::WindowSwitcher) + return; + auto titlebar_rect = title_bar_rect(window.rect()); auto titlebar_inner_rect = title_bar_text_rect(window.rect()); - auto outer_rect = outer_window_rect(window.rect()); + auto outer_rect = outer_window_rect(window); auto border_rect = border_window_rect(window.rect()); auto close_button_rect = close_button_rect_for_window(window.rect()); @@ -466,8 +479,8 @@ void WSWindowManager::add_window(WSWindow& window) m_windows_in_order.append(&window); if (!active_window()) set_active_window(&window); - if (m_switcher.is_visible()) - m_switcher.invalidate(); + if (m_switcher.is_visible() && window.type() != WSWindowType::WindowSwitcher) + m_switcher.refresh(); } void WSWindowManager::move_to_front(WSWindow& window) @@ -488,25 +501,25 @@ void WSWindowManager::remove_window(WSWindow& window) m_windows_in_order.remove(&window); if (!active_window() && !m_windows.is_empty()) set_active_window(*m_windows.begin()); - if (m_switcher.is_visible()) - m_switcher.invalidate(); + if (m_switcher.is_visible() && window.type() != WSWindowType::WindowSwitcher) + m_switcher.refresh(); } void WSWindowManager::notify_title_changed(WSWindow& window) { - printf("[WM] WSWindow{%p} title set to '%s'\n", &window, window.title().characters()); - invalidate(outer_window_rect(window.rect())); + dbgprintf("[WM] WSWindow{%p} title set to '%s'\n", &window, window.title().characters()); + invalidate(outer_window_rect(window)); if (m_switcher.is_visible()) - m_switcher.invalidate(); + m_switcher.refresh(); } void WSWindowManager::notify_rect_changed(WSWindow& window, const Rect& old_rect, const Rect& new_rect) { - printf("[WM] WSWindow %p rect changed (%d,%d %dx%d) -> (%d,%d %dx%d)\n", &window, old_rect.x(), old_rect.y(), old_rect.width(), old_rect.height(), new_rect.x(), new_rect.y(), new_rect.width(), new_rect.height()); + dbgprintf("[WM] WSWindow %p rect changed (%d,%d %dx%d) -> (%d,%d %dx%d)\n", &window, old_rect.x(), old_rect.y(), old_rect.width(), old_rect.height(), new_rect.x(), new_rect.y(), new_rect.width(), new_rect.height()); invalidate(outer_window_rect(old_rect)); invalidate(outer_window_rect(new_rect)); - if (m_switcher.is_visible()) - m_switcher.invalidate(); + if (m_switcher.is_visible() && window.type() != WSWindowType::WindowSwitcher) + m_switcher.refresh(); } void WSWindowManager::handle_menu_mouse_event(WSMenu& menu, WSMouseEvent& event) @@ -578,7 +591,7 @@ void WSWindowManager::start_window_resize(WSWindow& window, WSMouseEvent& event) { ResizeDirection::Left, ResizeDirection::None, ResizeDirection::Right }, { ResizeDirection::DownLeft, ResizeDirection::Down, ResizeDirection::DownRight }, }; - Rect outer_rect = outer_window_rect(window.rect()); + Rect outer_rect = outer_window_rect(window); ASSERT(outer_rect.contains(event.position())); int window_relative_x = event.x() - outer_rect.x(); int window_relative_y = event.y() - outer_rect.y(); @@ -752,7 +765,7 @@ void WSWindowManager::process_mouse_event(WSMouseEvent& event, WSWindow*& event_ } for_each_visible_window_from_front_to_back([&] (WSWindow& window) { - if (window.type() != WSWindowType::Menu && outer_window_rect(window.rect()).contains(event.position())) { + if (window.type() == WSWindowType::Normal && outer_window_rect(window).contains(event.position())) { if (m_keyboard_modifiers == Mod_Logo && event.type() == WSMessage::MouseDown && event.button() == MouseButton::Left) { start_window_drag(window, event); return IterationDecision::Abort; @@ -762,7 +775,7 @@ void WSWindowManager::process_mouse_event(WSMouseEvent& event, WSWindow*& event_ return IterationDecision::Abort; } } - if (window.type() != WSWindowType::Menu && title_bar_rect(window.rect()).contains(event.position())) { + if (window.type() == WSWindowType::Normal && title_bar_rect(window.rect()).contains(event.position())) { if (event.type() == WSMessage::MouseDown) { move_to_front(window); set_active_window(&window); @@ -777,7 +790,7 @@ void WSWindowManager::process_mouse_event(WSMouseEvent& event, WSWindow*& event_ } if (window.rect().contains(event.position())) { - if (window.type() != WSWindowType::Menu && event.type() == WSMessage::MouseDown) { + if (window.type() == WSWindowType::Normal && event.type() == WSMessage::MouseDown) { move_to_front(window); set_active_window(&window); } @@ -815,14 +828,14 @@ void WSWindowManager::compose() // Maybe there's some way we could know this? continue; } - if (outer_window_rect(window->rect()).contains(r)) + if (outer_window_rect(*window).contains(r)) return true; } return false; }; auto any_dirty_rect_intersects_window = [&dirty_rects] (const WSWindow& window) { - auto window_rect = outer_window_rect(window.rect()); + auto window_rect = outer_window_rect(window); for (auto& dirty_rect : dirty_rects.rects()) { if (dirty_rect.intersects(window_rect)) return true; @@ -876,7 +889,9 @@ void WSWindowManager::compose() compose_window(*m_highlight_window); draw_menubar(); - draw_window_switcher(); + if (m_switcher.is_visible()) + compose_window(*m_switcher.switcher_window()); + draw_cursor(); if (m_flash_flush) { @@ -949,7 +964,7 @@ void WSWindowManager::draw_menubar() void WSWindowManager::draw_window_switcher() { if (m_switcher.is_visible()) - m_switcher.draw(*m_back_painter); + m_switcher.draw(); } void WSWindowManager::draw_cursor() @@ -1009,8 +1024,8 @@ void WSWindowManager::set_highlight_window(WSWindow* window) void WSWindowManager::set_active_window(WSWindow* window) { - if (window->type() == WSWindowType::Menu) { - dbgprintf("WSWindowManager: Attempted to make a menu window active.\n"); + if (window->type() != WSWindowType::Normal) { + dbgprintf("WSWindowManager: Attempted to make a non-normal window active.\n"); return; } @@ -1079,7 +1094,11 @@ void WSWindowManager::invalidate(const WSWindow& window) return; } if (window.type() == WSWindowType::Normal) { - invalidate(outer_window_rect(window.rect())); + invalidate(outer_window_rect(window)); + return; + } + if (window.type() == WSWindowType::WindowSwitcher) { + invalidate(window.rect()); return; } ASSERT_NOT_REACHED(); @@ -1091,7 +1110,7 @@ void WSWindowManager::invalidate(const WSWindow& window, const Rect& rect) invalidate(window); return; } - auto outer_rect = outer_window_rect(window.rect()); + auto outer_rect = outer_window_rect(window); auto inner_rect = rect; inner_rect.move_by(window.position()); // FIXME: This seems slightly wrong; the inner rect shouldn't intersect the border part of the outer rect. @@ -1107,13 +1126,13 @@ void WSWindowManager::flush(const Rect& a_rect) dbgprintf("[WM] flush #%u (%d,%d %dx%d)\n", ++m_flush_count, rect.x(), rect.y(), rect.width(), rect.height()); #endif - RGBA32* front_ptr = m_front_bitmap->scanline(rect.y()) + rect.x(); + const RGBA32* front_ptr = m_front_bitmap->scanline(rect.y()) + rect.x(); RGBA32* back_ptr = m_back_bitmap->scanline(rect.y()) + rect.x(); size_t pitch = m_back_bitmap->pitch(); for (int y = 0; y < rect.height(); ++y) { fast_dword_copy(back_ptr, front_ptr, rect.width()); - front_ptr = (RGBA32*)((byte*)front_ptr + pitch); + front_ptr = (const RGBA32*)((const byte*)front_ptr + pitch); back_ptr = (RGBA32*)((byte*)back_ptr + pitch); } } diff --git a/WindowServer/WSWindowSwitcher.cpp b/WindowServer/WSWindowSwitcher.cpp index 1a8f320811..9f7118f27b 100644 --- a/WindowServer/WSWindowSwitcher.cpp +++ b/WindowServer/WSWindowSwitcher.cpp @@ -16,11 +16,11 @@ void WSWindowSwitcher::set_visible(bool visible) if (m_visible == visible) return; m_visible = visible; - if (!m_visible) { - WSWindowManager::the().invalidate(m_rect); + if (m_switcher_window) + m_switcher_window->set_visible(visible); + if (!m_visible) return; - } - invalidate(); + refresh(); } WSWindow* WSWindowSwitcher::selected_window() @@ -53,15 +53,15 @@ void WSWindowSwitcher::on_key_event(const WSKeyEvent& event) auto* highlight_window = m_windows.at(m_selected_index).ptr(); ASSERT(highlight_window); WSWindowManager::the().set_highlight_window(highlight_window); + draw(); WSWindowManager::the().invalidate(m_rect); } -void WSWindowSwitcher::draw(Painter& painter) +void WSWindowSwitcher::draw() { - painter.translate(m_rect.location()); + Painter painter(*m_switcher_window->backing_store()); painter.fill_rect({ { }, m_rect.size() }, Color::LightGray); painter.draw_rect({ { }, m_rect.size() }, Color::DarkGray); - for (int index = 0; index < m_windows.size(); ++index) { auto& window = *m_windows.at(index); Rect item_rect { @@ -80,16 +80,14 @@ void WSWindowSwitcher::draw(Painter& painter) text_color = Color::Black; rect_text_color = Color::DarkGray; } - painter.set_font(Font::default_bold_font()); painter.draw_text(item_rect, window.title(), TextAlignment::CenterLeft, text_color); painter.set_font(WSWindowManager::the().font()); painter.draw_text(item_rect, window.rect().to_string(), TextAlignment::CenterRight, rect_text_color); } - painter.translate(-m_rect.x(), -m_rect.y()); } -void WSWindowSwitcher::invalidate() +void WSWindowSwitcher::refresh() { WSWindow* selected_window = nullptr; if (m_selected_index > 0 && m_windows[m_selected_index]) @@ -114,5 +112,13 @@ void WSWindowSwitcher::invalidate() m_rect.set_width(longest_title * WSWindowManager::the().font().glyph_width() + space_for_window_rect + padding() * 2); m_rect.set_height(window_count * item_height() + padding() * 2); m_rect.center_within(WSWindowManager::the().m_screen_rect); - WSWindowManager::the().invalidate(m_rect); + if (!m_switcher_window) + m_switcher_window = make(*this, WSWindowType::WindowSwitcher); + m_switcher_window->set_rect(m_rect); + draw(); +} + +void WSWindowSwitcher::on_message(WSMessage& message) +{ + } diff --git a/WindowServer/WSWindowSwitcher.h b/WindowServer/WSWindowSwitcher.h index 81c4c2d830..418cb4481d 100644 --- a/WindowServer/WSWindowSwitcher.h +++ b/WindowServer/WSWindowSwitcher.h @@ -3,15 +3,16 @@ #include #include #include +#include class Painter; class WSKeyEvent; class WSWindow; -class WSWindowSwitcher { +class WSWindowSwitcher : public WSMessageReceiver { public: WSWindowSwitcher(); - ~WSWindowSwitcher(); + virtual ~WSWindowSwitcher() override; bool is_visible() const { return m_visible; } void set_visible(bool); @@ -20,17 +21,21 @@ public: void hide() { set_visible(false); } void on_key_event(const WSKeyEvent&); - void invalidate(); + void refresh(); - void draw(Painter&); + void draw(); int item_height() { return 20; } int padding() { return 8; } WSWindow* selected_window(); -private: + WSWindow* switcher_window() { return m_switcher_window.ptr(); } +private: + virtual void on_message(WSMessage&) override; + + OwnPtr m_switcher_window; Rect m_rect; bool m_visible { false }; Vector> m_windows; diff --git a/WindowServer/WSWindowType.h b/WindowServer/WSWindowType.h index afd2b8a13f..7713495e0d 100644 --- a/WindowServer/WSWindowType.h +++ b/WindowServer/WSWindowType.h @@ -3,5 +3,6 @@ enum class WSWindowType { Invalid = 0, Normal, - Menu + Menu, + WindowSwitcher, };