mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 15:32:46 +00:00 
			
		
		
		
	WindowServer: Add basic menu applet concept
It's now possible to create a little applet window that sits inside the system's menubar. This is done using the new CreateMenuApplet IPC call. So far, it's possible to assign a backing store ID, and to invalidate rects for repaint. There is no way to get the events from inside the applet just yet. This will allow us to move the CPU graph and audio thingy to separate applet processes. :^)
This commit is contained in:
		
							parent
							
								
									2d18fc8052
								
							
						
					
					
						commit
						44d5388e78
					
				
					 8 changed files with 174 additions and 0 deletions
				
			
		|  | @ -17,6 +17,7 @@ OBJS = \ | |||
|     WSCPUMonitor.o \
 | ||||
|     WSCompositor.o \
 | ||||
|     WSMenuManager.o \
 | ||||
|     WSMenuApplet.o \
 | ||||
|     main.o | ||||
| 
 | ||||
| APP = WindowServer | ||||
|  |  | |||
|  | @ -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>(); | ||||
| } | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
							
								
								
									
										25
									
								
								Servers/WindowServer/WSMenuApplet.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								Servers/WindowServer/WSMenuApplet.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -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); | ||||
| } | ||||
							
								
								
									
										33
									
								
								Servers/WindowServer/WSMenuApplet.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								Servers/WindowServer/WSMenuApplet.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||
| }; | ||||
|  | @ -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(); | ||||
| } | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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, | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling