diff --git a/Libraries/LibGUI/GWindowType.h b/Libraries/LibGUI/GWindowType.h index 0bdb3d46d3a..b46bed009e5 100644 --- a/Libraries/LibGUI/GWindowType.h +++ b/Libraries/LibGUI/GWindowType.h @@ -9,4 +9,5 @@ enum class GWindowType { Taskbar, Tooltip, Menubar, + MenuApplet, }; diff --git a/MenuApplets/CPUGraph/main.cpp b/MenuApplets/CPUGraph/main.cpp index 8190c9aec00..ed6744bdfde 100644 --- a/MenuApplets/CPUGraph/main.cpp +++ b/MenuApplets/CPUGraph/main.cpp @@ -1,87 +1,83 @@ #include #include -#include -#include #include #include -#include +#include +#include -NonnullRefPtr 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); -} +class GraphWidget final : public GWidget { + C_OBJECT(GraphWidget) +public: + GraphWidget() + : GWidget(nullptr) + { + start_timer(1000); + } -static void get_cpu_usage(unsigned& busy, unsigned& idle) -{ - busy = 0; - idle = 0; + virtual ~GraphWidget() override {} - auto all_processes = CProcessStatisticsReader::get_all(); +private: + virtual void timer_event(CTimerEvent&) override + { + unsigned busy; + unsigned idle; + get_cpu_usage(busy, 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); + m_cpu_history.enqueue(cpu); + update(); + } - 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; + 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( + { 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; + + 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; + } + } + } + + CircularQueue m_cpu_history; + unsigned m_last_busy { 0 }; + unsigned m_last_idle { 0 }; +}; int main(int argc, char** argv) { GApplication app(argc, argv); - Size applet_size(30, 16); - Rect applet_rect({}, applet_size); - - CircularQueue cpu_history; - - i32 applet_id = GWindowServerConnection::the().send_sync(applet_size)->applet_id(); - auto bitmap = create_shared_bitmap(applet_size); - - GWindowServerConnection::the().send_sync(applet_id, bitmap->shared_buffer_id()); - - unsigned last_busy = 0; - unsigned last_idle = 0; - - auto repaint = [&] { - 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; - float cpu = (float)busy_diff / (float)(busy_diff + idle_diff); - cpu_history.enqueue(cpu); - - GPainter painter(*bitmap); - painter.fill_rect(applet_rect, Color::Black); - int i = cpu_history.capacity() - cpu_history.size(); - for (auto cpu_usage : 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()))) }, - Color::from_rgb(0xaa6d4b)); - ++i; - } - - GWindowServerConnection::the().send_sync(applet_id, applet_rect); - }; - - repaint(); - - 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(); } diff --git a/Servers/WindowServer/Makefile b/Servers/WindowServer/Makefile index 3a068a7bf84..b5f6d06e064 100644 --- a/Servers/WindowServer/Makefile +++ b/Servers/WindowServer/Makefile @@ -16,7 +16,6 @@ OBJS = \ WSButton.o \ WSCompositor.o \ WSMenuManager.o \ - WSMenuApplet.o \ main.o APP = WindowServer diff --git a/Servers/WindowServer/WSClientConnection.cpp b/Servers/WindowServer/WSClientConnection.cpp index 6c684267428..8de0727d243 100644 --- a/Servers/WindowServer/WSClientConnection.cpp +++ b/Servers/WindowServer/WSClientConnection.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -407,6 +406,8 @@ OwnPtr 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(window_id); } @@ -419,6 +420,10 @@ OwnPtr 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 WSClientConnection::handle(const WindowServer::CreateMenuApplet& message) -{ - auto applet = make(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(applet_id); -} - -OwnPtr 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(); -} - -OwnPtr 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(); -} - -OwnPtr 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(); -} - OwnPtr WSClientConnection::handle(const WindowServer::StartDrag& message) { auto& wm = WSWindowManager::the(); diff --git a/Servers/WindowServer/WSClientConnection.h b/Servers/WindowServer/WSClientConnection.h index 707c882d2f5..3d2e0a8d9c0 100644 --- a/Servers/WindowServer/WSClientConnection.h +++ b/Servers/WindowServer/WSClientConnection.h @@ -10,7 +10,6 @@ #include #include -class WSMenuApplet; class WSWindow; class WSMenu; class WSMenuBar; @@ -88,13 +87,8 @@ private: virtual OwnPtr handle(const WindowServer::DismissMenu&) override; virtual OwnPtr handle(const WindowServer::SetWindowIconBitmap&) override; virtual void handle(const WindowServer::WM_SetWindowTaskbarRect&) override; - virtual OwnPtr handle(const WindowServer::CreateMenuApplet&) override; - virtual OwnPtr handle(const WindowServer::DestroyMenuApplet&) override; - virtual OwnPtr handle(const WindowServer::SetMenuAppletBackingStore&) override; - virtual OwnPtr handle(const WindowServer::InvalidateMenuAppletRect&) override; virtual OwnPtr handle(const WindowServer::StartDrag&) override; - HashMap> m_menu_applets; HashMap> m_windows; HashMap> m_menubars; HashMap> m_menus; diff --git a/Servers/WindowServer/WSMenuApplet.cpp b/Servers/WindowServer/WSMenuApplet.cpp deleted file mode 100644 index 765c4f23ddb..00000000000 --- a/Servers/WindowServer/WSMenuApplet.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include -#include - -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); -} diff --git a/Servers/WindowServer/WSMenuApplet.h b/Servers/WindowServer/WSMenuApplet.h deleted file mode 100644 index f51402775b5..00000000000 --- a/Servers/WindowServer/WSMenuApplet.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -class GraphicsBitmap; - -class WSMenuApplet : public Weakable { - 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 m_bitmap; -}; diff --git a/Servers/WindowServer/WSMenuManager.cpp b/Servers/WindowServer/WSMenuManager.cpp index 83642bfc5e1..730c7e841bc 100644 --- a/Servers/WindowServer/WSMenuManager.cpp +++ b/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; diff --git a/Servers/WindowServer/WSMenuManager.h b/Servers/WindowServer/WSMenuManager.h index 706c0fcc968..740cd3be1a4 100644 --- a/Servers/WindowServer/WSMenuManager.h +++ b/Servers/WindowServer/WSMenuManager.h @@ -3,7 +3,6 @@ #include "WSMenu.h" #include #include -#include #include 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&); @@ -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 m_window; @@ -62,7 +61,7 @@ private: RefPtr m_muted_bitmap; RefPtr m_unmuted_bitmap; - Vector> m_applets; + Vector> m_applets; OwnPtr m_audio_client; diff --git a/Servers/WindowServer/WSWindow.h b/Servers/WindowServer/WSWindow.h index 9276a6a192d..b89cf4541aa 100644 --- a/Servers/WindowServer/WSWindow.h +++ b/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&& 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 m_window_menu; int m_minimize_animation_step { -1 }; }; diff --git a/Servers/WindowServer/WSWindowManager.cpp b/Servers/WindowServer/WSWindowManager.cpp index 451acb46896..ea750907d9f 100644 --- a/Servers/WindowServer/WSWindowManager.cpp +++ b/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; diff --git a/Servers/WindowServer/WSWindowType.h b/Servers/WindowServer/WSWindowType.h index 2d853a014c4..07c93f32c6d 100644 --- a/Servers/WindowServer/WSWindowType.h +++ b/Servers/WindowServer/WSWindowType.h @@ -9,4 +9,5 @@ enum class WSWindowType { Taskbar, Tooltip, Menubar, + MenuApplet, }; diff --git a/Servers/WindowServer/WindowServer.ipc b/Servers/WindowServer/WindowServer.ipc index cafa36fee3c..58c3da272b6 100644 --- a/Servers/WindowServer/WindowServer.ipc +++ b/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,