Browse Source

WindowServer: Let the window switcher render itself as a WSWindow.

Much better than drawing directly into the back buffer.
Andreas Kling 6 năm trước cách đây
mục cha
commit
b85fe0bd07

+ 2 - 2
WindowServer/WSMenu.cpp

@@ -69,7 +69,7 @@ WSWindow& WSMenu::ensure_menu_window()
             next_item_location.move_by(0, height);
         }
 
-        auto window = make<WSWindow>(*this);
+        auto window = make<WSWindow>(*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) {

+ 6 - 4
WindowServer/WSMenu.h

@@ -4,7 +4,8 @@
 #include <AK/Vector.h>
 #include <AK/WeakPtr.h>
 #include <SharedGraphics/Rect.h>
-#include "WSMenuItem.h"
+#include <WindowServer/WSMenuItem.h>
+#include <WindowServer/WSMessageReceiver.h>
 
 class WSClientConnection;
 class WSMenuBar;
@@ -12,10 +13,10 @@ class WSMessage;
 class WSWindow;
 class Font;
 
-class WSMenu : public Weakable<WSMenu> {
+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 };

+ 6 - 9
WindowServer/WSWindow.cpp

@@ -5,9 +5,9 @@
 #include <WindowServer/WSAPITypes.h>
 #include <WindowServer/WSClientConnection.h>
 
-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();

+ 2 - 2
WindowServer/WSWindow.h

@@ -13,7 +13,7 @@ class WSMenu;
 class WSWindow final : public WSMessageReceiver, public InlineLinkedListNode<WSWindow> {
 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<GraphicsBitmap> m_backing_store;
     int m_window_id { -1 };
     float m_opacity { 1 };

+ 44 - 25
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);
     }
 }

+ 17 - 11
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<WSWindow>(*this, WSWindowType::WindowSwitcher);
+    m_switcher_window->set_rect(m_rect);
+    draw();
+}
+
+void WSWindowSwitcher::on_message(WSMessage& message)
+{
+
 }

+ 9 - 4
WindowServer/WSWindowSwitcher.h

@@ -3,15 +3,16 @@
 #include <SharedGraphics/Rect.h>
 #include <AK/Vector.h>
 #include <AK/WeakPtr.h>
+#include <WindowServer/WSMessageReceiver.h>
 
 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();
 
+    WSWindow* switcher_window() { return m_switcher_window.ptr(); }
+
 private:
+    virtual void on_message(WSMessage&) override;
 
+    OwnPtr<WSWindow> m_switcher_window;
     Rect m_rect;
     bool m_visible { false };
     Vector<WeakPtr<WSWindow>> m_windows;

+ 2 - 1
WindowServer/WSWindowType.h

@@ -3,5 +3,6 @@
 enum class WSWindowType {
     Invalid = 0,
     Normal,
-    Menu
+    Menu,
+    WindowSwitcher,
 };