فهرست منبع

WindowServer+CPUGraph: Make menu applets be "regular" windows

Instead of implementing menu applets as their own thing, they are now
WSWindows of WSWindowType::MenuApplet.

This makes it much easier to work with them on the client side, since
you can just create a GWindow with the right type and you're in the
menubar doing applet stuff :^)
Andreas Kling 5 سال پیش
والد
کامیت
df129bbe0e

+ 1 - 0
Libraries/LibGUI/GWindowType.h

@@ -9,4 +9,5 @@ enum class GWindowType {
     Taskbar,
     Tooltip,
     Menubar,
+    MenuApplet,
 };

+ 61 - 65
MenuApplets/CPUGraph/main.cpp

@@ -1,87 +1,83 @@
 #include <AK/CircularQueue.h>
 #include <LibCore/CProcessStatisticsReader.h>
-#include <LibCore/CTimer.h>
-#include <LibDraw/GraphicsBitmap.h>
 #include <LibGUI/GApplication.h>
 #include <LibGUI/GPainter.h>
-#include <LibGUI/GWindowServerConnection.h>
-
-NonnullRefPtr<GraphicsBitmap> create_shared_bitmap(const Size& size)
-{
-    ASSERT(GWindowServerConnection::the().server_pid());
-    ASSERT(!size.is_empty());
-    size_t pitch = round_up_to_power_of_two(size.width() * sizeof(RGBA32), 16);
-    size_t size_in_bytes = size.height() * pitch;
-    auto shared_buffer = SharedBuffer::create_with_size(size_in_bytes);
-    ASSERT(shared_buffer);
-    shared_buffer->share_with(GWindowServerConnection::the().server_pid());
-    return GraphicsBitmap::create_with_shared_buffer(GraphicsBitmap::Format::RGBA32, *shared_buffer, size);
-}
-
-static void get_cpu_usage(unsigned& busy, unsigned& idle)
-{
-    busy = 0;
-    idle = 0;
-
-    auto all_processes = CProcessStatisticsReader::get_all();
-
-    for (auto& it : all_processes) {
-        for (auto& jt : it.value.threads) {
-            if (it.value.pid == 0)
-                idle += jt.times_scheduled;
-            else
-                busy += jt.times_scheduled;
-        }
+#include <LibGUI/GWidget.h>
+#include <LibGUI/GWindow.h>
+
+class GraphWidget final : public GWidget {
+    C_OBJECT(GraphWidget)
+public:
+    GraphWidget()
+        : GWidget(nullptr)
+    {
+        start_timer(1000);
     }
-}
-
-int main(int argc, char** argv)
-{
-    GApplication app(argc, argv);
-
-    Size applet_size(30, 16);
-    Rect applet_rect({}, applet_size);
 
-    CircularQueue<float, 30> cpu_history;
+    virtual ~GraphWidget() override {}
 
-    i32 applet_id = GWindowServerConnection::the().send_sync<WindowServer::CreateMenuApplet>(applet_size)->applet_id();
-    auto bitmap = create_shared_bitmap(applet_size);
-
-    GWindowServerConnection::the().send_sync<WindowServer::SetMenuAppletBackingStore>(applet_id, bitmap->shared_buffer_id());
-
-    unsigned last_busy = 0;
-    unsigned last_idle = 0;
-
-    auto repaint = [&] {
+private:
+    virtual void timer_event(CTimerEvent&) override
+    {
         unsigned busy;
         unsigned idle;
         get_cpu_usage(busy, idle);
-        unsigned busy_diff = busy - last_busy;
-        unsigned idle_diff = idle - last_idle;
-        last_busy = busy;
-        last_idle = idle;
+        unsigned busy_diff = busy - m_last_busy;
+        unsigned idle_diff = idle - m_last_idle;
+        m_last_busy = busy;
+        m_last_idle = idle;
         float cpu = (float)busy_diff / (float)(busy_diff + idle_diff);
-        cpu_history.enqueue(cpu);
+        m_cpu_history.enqueue(cpu);
+        update();
+    }
 
-        GPainter painter(*bitmap);
-        painter.fill_rect(applet_rect, Color::Black);
-        int i = cpu_history.capacity() - cpu_history.size();
-        for (auto cpu_usage : cpu_history) {
+    virtual void paint_event(GPaintEvent& event) override
+    {
+        GPainter painter(*this);
+        painter.add_clip_rect(event.rect());
+        painter.fill_rect(event.rect(), Color::Black);
+        int i = m_cpu_history.capacity() - m_cpu_history.size();
+        for (auto cpu_usage : m_cpu_history) {
             painter.draw_line(
-                { applet_rect.x() + i, applet_rect.bottom() },
-                { applet_rect.x() + i, (int)(applet_rect.y() + (applet_rect.height() - (cpu_usage * (float)applet_rect.height()))) },
+                { i, rect().bottom() },
+                { i, (int)(height() - (cpu_usage * (float)height())) },
                 Color::from_rgb(0xaa6d4b));
             ++i;
         }
+    }
+
+    static void get_cpu_usage(unsigned& busy, unsigned& idle)
+    {
+        busy = 0;
+        idle = 0;
 
-        GWindowServerConnection::the().send_sync<WindowServer::InvalidateMenuAppletRect>(applet_id, applet_rect);
-    };
+        auto all_processes = CProcessStatisticsReader::get_all();
 
-    repaint();
+        for (auto& it : all_processes) {
+            for (auto& jt : it.value.threads) {
+                if (it.value.pid == 0)
+                    idle += jt.times_scheduled;
+                else
+                    busy += jt.times_scheduled;
+            }
+        }
+    }
+
+    CircularQueue<float, 30> m_cpu_history;
+    unsigned m_last_busy { 0 };
+    unsigned m_last_idle { 0 };
+};
+
+int main(int argc, char** argv)
+{
+    GApplication app(argc, argv);
 
-    auto timer = CTimer::construct(1000, [&] {
-        repaint();
-    });
+    auto window = GWindow::construct();
+    window->set_window_type(GWindowType::MenuApplet);
+    window->resize(30, 16);
 
+    auto widget = GraphWidget::construct();
+    window->set_main_widget(widget);
+    window->show();
     return app.exec();
 }

+ 0 - 1
Servers/WindowServer/Makefile

@@ -16,7 +16,6 @@ OBJS = \
     WSButton.o \
     WSCompositor.o \
     WSMenuManager.o \
-    WSMenuApplet.o \
     main.o
 
 APP = WindowServer

+ 6 - 51
Servers/WindowServer/WSClientConnection.cpp

@@ -6,7 +6,6 @@
 #include <WindowServer/WSCompositor.h>
 #include <WindowServer/WSEventLoop.h>
 #include <WindowServer/WSMenu.h>
-#include <WindowServer/WSMenuApplet.h>
 #include <WindowServer/WSMenuBar.h>
 #include <WindowServer/WSMenuItem.h>
 #include <WindowServer/WSScreen.h>
@@ -407,6 +406,8 @@ OwnPtr<WindowServer::CreateWindowResponse> WSClientConnection::handle(const Wind
     window->set_size_increment(message.size_increment());
     window->set_base_size(message.base_size());
     window->invalidate();
+    if (window->type() == WSWindowType::MenuApplet)
+        WSWindowManager::the().menu_manager().add_applet(*window);
     m_windows.set(window_id, move(window));
     return make<WindowServer::CreateWindowResponse>(window_id);
 }
@@ -419,6 +420,10 @@ OwnPtr<WindowServer::DestroyWindowResponse> WSClientConnection::handle(const Win
         return nullptr;
     }
     auto& window = *(*it).value;
+
+    if (window.type() == WSWindowType::MenuApplet)
+        WSWindowManager::the().menu_manager().remove_applet(window);
+
     WSWindowManager::the().invalidate(window);
     remove_child(window);
     ASSERT(it->value.ptr() == &window);
@@ -629,56 +634,6 @@ void WSClientConnection::handle(const WindowServer::WM_SetWindowTaskbarRect& mes
     window.set_taskbar_rect(message.rect());
 }
 
-OwnPtr<WindowServer::CreateMenuAppletResponse> WSClientConnection::handle(const WindowServer::CreateMenuApplet& message)
-{
-    auto applet = make<WSMenuApplet>(message.size());
-    auto applet_id = applet->applet_id();
-    WSWindowManager::the().menu_manager().add_applet(*applet);
-    m_menu_applets.set(applet_id, move(applet));
-    return make<WindowServer::CreateMenuAppletResponse>(applet_id);
-}
-
-OwnPtr<WindowServer::DestroyMenuAppletResponse> WSClientConnection::handle(const WindowServer::DestroyMenuApplet& message)
-{
-    auto it = m_menu_applets.find(message.applet_id());
-    if (it == m_menu_applets.end()) {
-        did_misbehave("DestroyApplet: Invalid applet ID");
-        return nullptr;
-    }
-    WSWindowManager::the().menu_manager().remove_applet(*it->value);
-    m_menu_applets.remove(message.applet_id());
-    return make<WindowServer::DestroyMenuAppletResponse>();
-}
-
-OwnPtr<WindowServer::SetMenuAppletBackingStoreResponse> WSClientConnection::handle(const WindowServer::SetMenuAppletBackingStore& message)
-{
-    auto it = m_menu_applets.find(message.applet_id());
-    if (it == m_menu_applets.end()) {
-        did_misbehave("SetAppletBackingStore: Invalid applet ID");
-        return nullptr;
-    }
-    auto shared_buffer = SharedBuffer::create_from_shared_buffer_id(message.shared_buffer_id());
-    ssize_t size_in_bytes = it->value->size().area() * sizeof(RGBA32);
-    if (size_in_bytes > shared_buffer->size()) {
-        did_misbehave("SetAppletBackingStore: Shared buffer is too small for applet size");
-        return nullptr;
-    }
-    auto bitmap = GraphicsBitmap::create_with_shared_buffer(GraphicsBitmap::Format::RGBA32, *shared_buffer, it->value->size());
-    it->value->set_bitmap(bitmap);
-    return make<WindowServer::SetMenuAppletBackingStoreResponse>();
-}
-
-OwnPtr<WindowServer::InvalidateMenuAppletRectResponse> WSClientConnection::handle(const WindowServer::InvalidateMenuAppletRect& message)
-{
-    auto it = m_menu_applets.find(message.applet_id());
-    if (it == m_menu_applets.end()) {
-        did_misbehave("InvalidateAppletRect: Invalid applet ID");
-        return nullptr;
-    }
-    it->value->invalidate(message.rect());
-    return make<WindowServer::InvalidateMenuAppletRectResponse>();
-}
-
 OwnPtr<WindowServer::StartDragResponse> WSClientConnection::handle(const WindowServer::StartDrag& message)
 {
     auto& wm = WSWindowManager::the();

+ 0 - 6
Servers/WindowServer/WSClientConnection.h

@@ -10,7 +10,6 @@
 #include <WindowServer/WSEvent.h>
 #include <WindowServer/WindowServerEndpoint.h>
 
-class WSMenuApplet;
 class WSWindow;
 class WSMenu;
 class WSMenuBar;
@@ -88,13 +87,8 @@ private:
     virtual OwnPtr<WindowServer::DismissMenuResponse> handle(const WindowServer::DismissMenu&) override;
     virtual OwnPtr<WindowServer::SetWindowIconBitmapResponse> handle(const WindowServer::SetWindowIconBitmap&) override;
     virtual void handle(const WindowServer::WM_SetWindowTaskbarRect&) override;
-    virtual OwnPtr<WindowServer::CreateMenuAppletResponse> handle(const WindowServer::CreateMenuApplet&) override;
-    virtual OwnPtr<WindowServer::DestroyMenuAppletResponse> handle(const WindowServer::DestroyMenuApplet&) override;
-    virtual OwnPtr<WindowServer::SetMenuAppletBackingStoreResponse> handle(const WindowServer::SetMenuAppletBackingStore&) override;
-    virtual OwnPtr<WindowServer::InvalidateMenuAppletRectResponse> handle(const WindowServer::InvalidateMenuAppletRect&) override;
     virtual OwnPtr<WindowServer::StartDragResponse> handle(const WindowServer::StartDrag&) override;
 
-    HashMap<i32, NonnullOwnPtr<WSMenuApplet>> m_menu_applets;
     HashMap<int, NonnullRefPtr<WSWindow>> m_windows;
     HashMap<int, NonnullOwnPtr<WSMenuBar>> m_menubars;
     HashMap<int, NonnullRefPtr<WSMenu>> m_menus;

+ 0 - 25
Servers/WindowServer/WSMenuApplet.cpp

@@ -1,25 +0,0 @@
-#include <WindowServer/WSMenuApplet.h>
-#include <WindowServer/WSMenuManager.h>
-#include <WindowServer/WSWindowManager.h>
-
-static i32 s_next_applet_id = 1;
-
-WSMenuApplet::WSMenuApplet(const Size& size)
-    : m_applet_id(s_next_applet_id++)
-    , m_size(size)
-{
-}
-
-WSMenuApplet::~WSMenuApplet()
-{
-}
-
-void WSMenuApplet::set_bitmap(GraphicsBitmap* bitmap)
-{
-    m_bitmap = bitmap;
-}
-
-void WSMenuApplet::invalidate(const Rect& rect)
-{
-    WSWindowManager::the().menu_manager().invalidate_applet(*this, rect);
-}

+ 0 - 33
Servers/WindowServer/WSMenuApplet.h

@@ -1,33 +0,0 @@
-#pragma once
-
-#include <AK/Noncopyable.h>
-#include <AK/Weakable.h>
-#include <LibDraw/Rect.h>
-#include <LibDraw/Size.h>
-
-class GraphicsBitmap;
-
-class WSMenuApplet : public Weakable<WSMenuApplet> {
-    AK_MAKE_NONCOPYABLE(WSMenuApplet)
-    AK_MAKE_NONMOVABLE(WSMenuApplet)
-public:
-    explicit WSMenuApplet(const Size&);
-    ~WSMenuApplet();
-
-    i32 applet_id() const { return m_applet_id; }
-    Size size() const { return m_size; }
-
-    void set_bitmap(GraphicsBitmap*);
-    const GraphicsBitmap* bitmap() const { return m_bitmap; }
-
-    void invalidate(const Rect&);
-
-    const Rect& rect_in_menubar() const { return m_rect_in_menubar; }
-    void set_rect_in_menubar(const Rect& rect) { m_rect_in_menubar = rect; }
-
-private:
-    i32 m_applet_id { -1 };
-    Size m_size;
-    Rect m_rect_in_menubar;
-    RefPtr<GraphicsBitmap> m_bitmap;
-};

+ 6 - 6
Servers/WindowServer/WSMenuManager.cpp

@@ -298,7 +298,7 @@ void WSMenuManager::close_bar()
     m_bar_open = false;
 }
 
-void WSMenuManager::add_applet(WSMenuApplet& applet)
+void WSMenuManager::add_applet(WSWindow& applet)
 {
     int right_edge_x = m_audio_rect.x() - 4;
     for (auto& existing_applet : m_applets) {
@@ -314,22 +314,22 @@ void WSMenuManager::add_applet(WSMenuApplet& applet)
     m_applets.append(applet.make_weak_ptr());
 }
 
-void WSMenuManager::remove_applet(WSMenuApplet& applet)
+void WSMenuManager::remove_applet(WSWindow& applet)
 {
     m_applets.remove_first_matching([&](auto& entry) {
         return &applet == entry.ptr();
     });
 }
 
-void WSMenuManager::draw_applet(const WSMenuApplet& applet)
+void WSMenuManager::draw_applet(const WSWindow& applet)
 {
-    if (!applet.bitmap())
+    if (!applet.backing_store())
         return;
     Painter painter(*window().backing_store());
-    painter.blit(applet.rect_in_menubar().location(), *applet.bitmap(), applet.bitmap()->rect());
+    painter.blit(applet.rect_in_menubar().location(), *applet.backing_store(), applet.backing_store()->rect());
 }
 
-void WSMenuManager::invalidate_applet(WSMenuApplet& applet, const Rect& rect)
+void WSMenuManager::invalidate_applet(const WSWindow& applet, const Rect& rect)
 {
     // FIXME: This should only invalidate the applet's own rect, not the whole menubar.
     (void)rect;

+ 5 - 6
Servers/WindowServer/WSMenuManager.h

@@ -3,7 +3,6 @@
 #include "WSMenu.h"
 #include <LibCore/CObject.h>
 #include <LibCore/CTimer.h>
-#include <WindowServer/WSMenuApplet.h>
 #include <WindowServer/WSWindow.h>
 
 class AClientConnection;
@@ -36,9 +35,9 @@ public:
     void close_everyone_not_in_lineage(WSMenu&);
     void close_menu_and_descendants(WSMenu&);
 
-    void add_applet(WSMenuApplet&);
-    void remove_applet(WSMenuApplet&);
-    void invalidate_applet(WSMenuApplet&, const Rect&);
+    void add_applet(WSWindow&);
+    void remove_applet(WSWindow&);
+    void invalidate_applet(const WSWindow&, const Rect&);
 
 private:
     void close_menus(const Vector<WSMenu*>&);
@@ -49,7 +48,7 @@ private:
     void handle_menu_mouse_event(WSMenu&, const WSMouseEvent&);
 
     void draw();
-    void draw_applet(const WSMenuApplet&);
+    void draw_applet(const WSWindow&);
     void tick_clock();
 
     RefPtr<WSWindow> m_window;
@@ -62,7 +61,7 @@ private:
     RefPtr<GraphicsBitmap> m_muted_bitmap;
     RefPtr<GraphicsBitmap> m_unmuted_bitmap;
 
-    Vector<WeakPtr<WSMenuApplet>> m_applets;
+    Vector<WeakPtr<WSWindow>> m_applets;
 
     OwnPtr<AClientConnection> m_audio_client;
 

+ 8 - 0
Servers/WindowServer/WSWindow.h

@@ -118,12 +118,19 @@ public:
 
     virtual void event(CEvent&) override;
 
+    // Only used by WSWindowType::MenuApplet. Perhaps it could be a WSWindow subclass? I don't know.
+    void set_rect_in_menubar(const Rect& rect) { m_rect_in_menubar = rect; }
+    const Rect& rect_in_menubar() const { return m_rect_in_menubar; }
+
+    const GraphicsBitmap* backing_store() const { return m_backing_store.ptr(); }
     GraphicsBitmap* backing_store() { return m_backing_store.ptr(); }
+
     void set_backing_store(RefPtr<GraphicsBitmap>&& backing_store)
     {
         m_last_backing_store = move(m_backing_store);
         m_backing_store = move(backing_store);
     }
+
     void swap_backing_stores()
     {
         swap(m_backing_store, m_last_backing_store);
@@ -200,6 +207,7 @@ private:
     unsigned m_wm_event_mask { 0 };
     DisjointRectSet m_pending_paint_rects;
     Rect m_unmaximized_rect;
+    Rect m_rect_in_menubar;
     RefPtr<WSMenu> m_window_menu;
     int m_minimize_animation_step { -1 };
 };

+ 5 - 0
Servers/WindowServer/WSWindowManager.cpp

@@ -1072,6 +1072,11 @@ void WSWindowManager::invalidate(const WSWindow& window)
 
 void WSWindowManager::invalidate(const WSWindow& window, const Rect& rect)
 {
+    if (window.type() == WSWindowType::MenuApplet) {
+        menu_manager().invalidate_applet(window, rect);
+        return;
+    }
+
     if (rect.is_empty()) {
         invalidate(window);
         return;

+ 1 - 0
Servers/WindowServer/WSWindowType.h

@@ -9,4 +9,5 @@ enum class WSWindowType {
     Taskbar,
     Tooltip,
     Menubar,
+    MenuApplet,
 };

+ 0 - 5
Servers/WindowServer/WindowServer.ipc

@@ -16,11 +16,6 @@ endpoint WindowServer = 2
 
     UpdateMenuItem(i32 menu_id, i32 identifier, i32 submenu_id, String text, bool enabled, bool checkable, bool checked, String shortcut) => ()
 
-    CreateMenuApplet(Size size) => (i32 applet_id)
-    DestroyMenuApplet(i32 applet_id) => ()
-    SetMenuAppletBackingStore(i32 applet_id, i32 shared_buffer_id) => ()
-    InvalidateMenuAppletRect(i32 applet_id, Rect rect) => ()
-
     CreateWindow(
         Rect rect,
         bool has_alpha_channel,