summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Servers/WindowServer/Makefile1
-rw-r--r--Servers/WindowServer/WSClientConnection.cpp51
-rw-r--r--Servers/WindowServer/WSClientConnection.h6
-rw-r--r--Servers/WindowServer/WSMenuApplet.cpp25
-rw-r--r--Servers/WindowServer/WSMenuApplet.h33
-rw-r--r--Servers/WindowServer/WSMenuManager.cpp45
-rw-r--r--Servers/WindowServer/WSMenuManager.h8
-rw-r--r--Servers/WindowServer/WindowServer.ipc5
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,