diff options
-rw-r--r-- | Servers/WindowServer/Makefile | 1 | ||||
-rw-r--r-- | Servers/WindowServer/WSClientConnection.cpp | 51 | ||||
-rw-r--r-- | Servers/WindowServer/WSClientConnection.h | 6 | ||||
-rw-r--r-- | Servers/WindowServer/WSMenuApplet.cpp | 25 | ||||
-rw-r--r-- | Servers/WindowServer/WSMenuApplet.h | 33 | ||||
-rw-r--r-- | Servers/WindowServer/WSMenuManager.cpp | 45 | ||||
-rw-r--r-- | Servers/WindowServer/WSMenuManager.h | 8 | ||||
-rw-r--r-- | Servers/WindowServer/WindowServer.ipc | 5 |
8 files changed, 174 insertions, 0 deletions
diff --git a/Servers/WindowServer/Makefile b/Servers/WindowServer/Makefile index 411ec11953..9d407aa26f 100644 --- a/Servers/WindowServer/Makefile +++ b/Servers/WindowServer/Makefile @@ -17,6 +17,7 @@ OBJS = \ WSCPUMonitor.o \ WSCompositor.o \ WSMenuManager.o \ + WSMenuApplet.o \ main.o APP = WindowServer diff --git a/Servers/WindowServer/WSClientConnection.cpp b/Servers/WindowServer/WSClientConnection.cpp index 3d365d3682..0e23387706 100644 --- a/Servers/WindowServer/WSClientConnection.cpp +++ b/Servers/WindowServer/WSClientConnection.cpp @@ -1,6 +1,7 @@ #include <LibC/SharedBuffer.h> #include <LibDraw/GraphicsBitmap.h> #include <SharedBuffer.h> +#include <WindowServer/WSMenuApplet.h> #include <WindowServer/WSClientConnection.h> #include <WindowServer/WSClipboard.h> #include <WindowServer/WSCompositor.h> @@ -628,3 +629,53 @@ void WSClientConnection::handle(const WindowServer::WM_SetWindowTaskbarRect& mes auto& window = *(*it).value; 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>(); +} diff --git a/Servers/WindowServer/WSClientConnection.h b/Servers/WindowServer/WSClientConnection.h index 9f50a0c901..b7d3bc4987 100644 --- a/Servers/WindowServer/WSClientConnection.h +++ b/Servers/WindowServer/WSClientConnection.h @@ -10,6 +10,7 @@ #include <WindowServer/WSEvent.h> #include <WindowServer/WindowServerEndpoint.h> +class WSMenuApplet; class WSWindow; class WSMenu; class WSMenuBar; @@ -87,7 +88,12 @@ 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; + 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; diff --git a/Servers/WindowServer/WSMenuApplet.cpp b/Servers/WindowServer/WSMenuApplet.cpp new file mode 100644 index 0000000000..765c4f23dd --- /dev/null +++ b/Servers/WindowServer/WSMenuApplet.cpp @@ -0,0 +1,25 @@ +#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); +} diff --git a/Servers/WindowServer/WSMenuApplet.h b/Servers/WindowServer/WSMenuApplet.h new file mode 100644 index 0000000000..f51402775b --- /dev/null +++ b/Servers/WindowServer/WSMenuApplet.h @@ -0,0 +1,33 @@ +#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; +}; diff --git a/Servers/WindowServer/WSMenuManager.cpp b/Servers/WindowServer/WSMenuManager.cpp index 5be1a6c5a1..7712bedaf6 100644 --- a/Servers/WindowServer/WSMenuManager.cpp +++ b/Servers/WindowServer/WSMenuManager.cpp @@ -129,6 +129,12 @@ void WSMenuManager::draw() auto& audio_bitmap = m_audio_muted ? *m_muted_bitmap : *m_unmuted_bitmap; painter.blit(m_audio_rect.location(), audio_bitmap, audio_bitmap.rect()); + + for (auto& applet : m_applets) { + if (!applet) + continue; + draw_applet(*applet); + } } void WSMenuManager::tick_clock() @@ -282,3 +288,42 @@ void WSMenuManager::close_bar() close_everyone(); m_bar_open = false; } + +void WSMenuManager::add_applet(WSMenuApplet& applet) +{ + int right_edge_x = m_audio_rect.x() - 4; + for (auto& existing_applet : m_applets) { + if (existing_applet) + right_edge_x = existing_applet->rect_in_menubar().x() - 4; + } + + Rect new_applet_rect(right_edge_x - applet.size().width(), 0, applet.size().width(), applet.size().height()); + Rect dummy_menubar_rect(0, 0, 0, 18); + new_applet_rect.center_vertically_within(dummy_menubar_rect); + + applet.set_rect_in_menubar(new_applet_rect); + m_applets.append(applet.make_weak_ptr()); +} + +void WSMenuManager::remove_applet(WSMenuApplet& applet) +{ + m_applets.remove_first_matching([&](auto& entry) { + return &applet == entry.ptr(); + }); +} + +void WSMenuManager::draw_applet(const WSMenuApplet& applet) +{ + if (!applet.bitmap()) + return; + Painter painter(*window().backing_store()); + painter.blit(applet.rect_in_menubar().location(), *applet.bitmap(), applet.bitmap()->rect()); +} + +void WSMenuManager::invalidate_applet(WSMenuApplet& applet, const Rect& rect) +{ + // FIXME: This should only invalidate the applet's own rect, not the whole menubar. + (void)rect; + draw_applet(applet); + window().invalidate(); +} diff --git a/Servers/WindowServer/WSMenuManager.h b/Servers/WindowServer/WSMenuManager.h index 4c65d85402..69a33b7793 100644 --- a/Servers/WindowServer/WSMenuManager.h +++ b/Servers/WindowServer/WSMenuManager.h @@ -3,6 +3,7 @@ #include "WSMenu.h" #include <LibCore/CObject.h> #include <LibCore/CTimer.h> +#include <WindowServer/WSMenuApplet.h> #include <WindowServer/WSCPUMonitor.h> #include <WindowServer/WSWindow.h> @@ -33,6 +34,10 @@ 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&); + private: void close_menus(const Vector<WSMenu*>&); @@ -42,6 +47,7 @@ private: void handle_menu_mouse_event(WSMenu&, const WSMouseEvent&); void draw(); + void draw_applet(const WSMenuApplet&); void tick_clock(); RefPtr<WSWindow> m_window; @@ -55,6 +61,8 @@ private: RefPtr<GraphicsBitmap> m_muted_bitmap; RefPtr<GraphicsBitmap> m_unmuted_bitmap; + Vector<WeakPtr<WSMenuApplet>> m_applets; + OwnPtr<AClientConnection> m_audio_client; Rect m_audio_rect; diff --git a/Servers/WindowServer/WindowServer.ipc b/Servers/WindowServer/WindowServer.ipc index 883d820219..3f78821d37 100644 --- a/Servers/WindowServer/WindowServer.ipc +++ b/Servers/WindowServer/WindowServer.ipc @@ -16,6 +16,11 @@ 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, |