diff options
-rw-r--r-- | Libraries/LibGUI/GAction.h | 1 | ||||
-rw-r--r-- | Libraries/LibGUI/GMenu.cpp | 16 | ||||
-rw-r--r-- | Servers/WindowServer/WSAPITypes.h | 1 | ||||
-rw-r--r-- | Servers/WindowServer/WSClientConnection.cpp | 16 | ||||
-rw-r--r-- | Servers/WindowServer/WSEvent.h | 5 | ||||
-rw-r--r-- | Servers/WindowServer/WSMenu.cpp | 23 | ||||
-rw-r--r-- | Servers/WindowServer/WSMenu.h | 2 | ||||
-rw-r--r-- | Servers/WindowServer/WSMenuBar.cpp | 1 | ||||
-rw-r--r-- | Servers/WindowServer/WSMenuItem.cpp | 1 | ||||
-rw-r--r-- | Servers/WindowServer/WSMenuItem.h | 5 | ||||
-rw-r--r-- | Servers/WindowServer/WSWindowSwitcher.cpp | 1 |
11 files changed, 61 insertions, 11 deletions
diff --git a/Libraries/LibGUI/GAction.h b/Libraries/LibGUI/GAction.h index eedb597d61..c294d65de9 100644 --- a/Libraries/LibGUI/GAction.h +++ b/Libraries/LibGUI/GAction.h @@ -48,6 +48,7 @@ public: String text() const { return m_text; } GShortcut shortcut() const { return m_shortcut; } const GraphicsBitmap* icon() const { return m_icon.ptr(); } + void set_icon(const GraphicsBitmap* icon) { m_icon = icon; } Function<void(GAction&)> on_activation; diff --git a/Libraries/LibGUI/GMenu.cpp b/Libraries/LibGUI/GMenu.cpp index b6d0da5a8e..b2940768f5 100644 --- a/Libraries/LibGUI/GMenu.cpp +++ b/Libraries/LibGUI/GMenu.cpp @@ -98,6 +98,22 @@ int GMenu::realize_menu() request.menu.identifier = i; request.menu.enabled = action.is_enabled(); request.menu.checkable = action.is_checkable(); + if (action.icon()) { + ASSERT(action.icon()->format() == GraphicsBitmap::Format::RGBA32); + ASSERT(action.icon()->size() == Size(16, 16)); + if (action.icon()->shared_buffer_id() == -1) { + auto shared_buffer = SharedBuffer::create_with_size(action.icon()->size_in_bytes()); + ASSERT(shared_buffer); + auto shared_icon = GraphicsBitmap::create_with_shared_buffer(GraphicsBitmap::Format::RGBA32, *shared_buffer, action.icon()->size()); + memcpy(shared_buffer->data(), action.icon()->bits(0), action.icon()->size_in_bytes()); + shared_buffer->seal(); + shared_buffer->share_with(GWindowServerConnection::the().server_pid()); + action.set_icon(shared_icon); + } + request.menu.icon_buffer_id = action.icon()->shared_buffer_id(); + } else { + request.menu.icon_buffer_id = -1; + } if (action.is_checkable()) request.menu.checked = action.is_checked(); ASSERT(action.text().length() < (ssize_t)sizeof(request.text)); diff --git a/Servers/WindowServer/WSAPITypes.h b/Servers/WindowServer/WSAPITypes.h index ab1d6ee363..be7eb0ef43 100644 --- a/Servers/WindowServer/WSAPITypes.h +++ b/Servers/WindowServer/WSAPITypes.h @@ -263,6 +263,7 @@ struct WSAPI_ClientMessage { struct { int menubar_id; int menu_id; + int icon_buffer_id; unsigned identifier; char shortcut_text[32]; int shortcut_text_length; diff --git a/Servers/WindowServer/WSClientConnection.cpp b/Servers/WindowServer/WSClientConnection.cpp index 6f79207a4e..154fdc015b 100644 --- a/Servers/WindowServer/WSClientConnection.cpp +++ b/Servers/WindowServer/WSClientConnection.cpp @@ -1,4 +1,5 @@ #include <LibC/SharedBuffer.h> +#include <LibDraw/GraphicsBitmap.h> #include <SharedBuffer.h> #include <WindowServer/WSAPITypes.h> #include <WindowServer/WSClientConnection.h> @@ -158,7 +159,7 @@ bool WSClientConnection::handle_message(const WSAPI_ClientMessage& message, cons did_misbehave(); return false; } - CEventLoop::current().post_event(*this, make<WSAPIAddMenuItemRequest>(client_id(), message.menu.menu_id, message.menu.identifier, String(message.text, message.text_length), String(message.menu.shortcut_text, message.menu.shortcut_text_length), message.menu.enabled, message.menu.checkable, message.menu.checked)); + CEventLoop::current().post_event(*this, make<WSAPIAddMenuItemRequest>(client_id(), message.menu.menu_id, message.menu.identifier, String(message.text, message.text_length), String(message.menu.shortcut_text, message.menu.shortcut_text_length), message.menu.enabled, message.menu.checkable, message.menu.checked, message.menu.icon_buffer_id)); break; case WSAPI_ClientMessage::Type::UpdateMenuItem: if (message.text_length > (int)sizeof(message.text)) { @@ -422,7 +423,18 @@ void WSClientConnection::handle_request(const WSAPIAddMenuItemRequest& request) return; } auto& menu = *(*it).value; - menu.add_item(make<WSMenuItem>(menu, identifier, request.text(), request.shortcut_text(), request.is_enabled(), request.is_checkable(), request.is_checked())); + auto menu_item = make<WSMenuItem>(menu, identifier, request.text(), request.shortcut_text(), request.is_enabled(), request.is_checkable(), request.is_checked()); + if (request.icon_buffer_id() != -1) { + auto icon_buffer = SharedBuffer::create_from_shared_buffer_id(request.icon_buffer_id()); + if (!icon_buffer) { + did_misbehave(); + return; + } + // FIXME: Verify that the icon buffer can accomodate a 16x16 bitmap view. + auto shared_icon = GraphicsBitmap::create_with_shared_buffer(GraphicsBitmap::Format::RGBA32, icon_buffer.release_nonnull(), { 16, 16 }); + menu_item->set_icon(shared_icon); + } + menu.add_item(move(menu_item)); WSAPI_ServerMessage response; response.type = WSAPI_ServerMessage::Type::DidAddMenuItem; response.menu.menu_id = menu_id; diff --git a/Servers/WindowServer/WSEvent.h b/Servers/WindowServer/WSEvent.h index f2a1c7f290..215bc00fec 100644 --- a/Servers/WindowServer/WSEvent.h +++ b/Servers/WindowServer/WSEvent.h @@ -303,7 +303,7 @@ private: class WSAPIAddMenuItemRequest : public WSAPIClientRequest { public: - WSAPIAddMenuItemRequest(int client_id, int menu_id, unsigned identifier, const String& text, const String& shortcut_text, bool enabled, bool checkable, bool checked) + WSAPIAddMenuItemRequest(int client_id, int menu_id, unsigned identifier, const String& text, const String& shortcut_text, bool enabled, bool checkable, bool checked, int icon_buffer_id) : WSAPIClientRequest(WSEvent::APIAddMenuItemRequest, client_id) , m_menu_id(menu_id) , m_identifier(identifier) @@ -312,6 +312,7 @@ public: , m_enabled(enabled) , m_checkable(checkable) , m_checked(checked) + , m_icon_buffer_id(icon_buffer_id) { } @@ -322,6 +323,7 @@ public: bool is_enabled() const { return m_enabled; } bool is_checkable() const { return m_checkable; } bool is_checked() const { return m_checked; } + int icon_buffer_id() const { return m_icon_buffer_id; } private: int m_menu_id { 0 }; @@ -331,6 +333,7 @@ private: bool m_enabled; bool m_checkable; bool m_checked; + int m_icon_buffer_id { 0 }; }; class WSAPIUpdateMenuItemRequest : public WSAPIClientRequest { diff --git a/Servers/WindowServer/WSMenu.cpp b/Servers/WindowServer/WSMenu.cpp index cc9bb91e19..2a8c983578 100644 --- a/Servers/WindowServer/WSMenu.cpp +++ b/Servers/WindowServer/WSMenu.cpp @@ -7,6 +7,7 @@ #include "WSWindowManager.h" #include <LibDraw/CharacterBitmap.h> #include <LibDraw/Font.h> +#include <LibDraw/GraphicsBitmap.h> #include <LibDraw/Painter.h> #include <LibDraw/StylePainter.h> #include <WindowServer/WSAPITypes.h> @@ -44,7 +45,8 @@ static const char* s_checked_bitmap_data = { static CharacterBitmap* s_checked_bitmap; static const int s_checked_bitmap_width = 9; static const int s_checked_bitmap_height = 9; -static const int s_checked_bitmap_padding = 6; +static const int s_item_icon_width = 16; +static const int s_checkbox_or_icon_padding = 6; int WSMenu::width() const { @@ -58,8 +60,8 @@ int WSMenu::width() const int shortcut_width = font().width(item.shortcut_text()); widest_shortcut = max(shortcut_width, widest_shortcut); } - if (item.is_checkable()) - text_width += s_checked_bitmap_width + s_checked_bitmap_padding; + if (item.is_checkable() || item.icon()) + text_width += s_item_icon_width + s_checkbox_or_icon_padding; widest_text = max(widest_text, text_width); } @@ -125,8 +127,11 @@ void WSMenu::draw() s_checked_bitmap = &CharacterBitmap::create_from_ascii(s_checked_bitmap_data, s_checked_bitmap_width, s_checked_bitmap_height).leak_ref(); bool has_checkable_items = false; - for (auto& item : m_items) + bool has_items_with_icon = false; + for (auto& item : m_items) { has_checkable_items = has_checkable_items | item.is_checkable(); + has_items_with_icon = has_items_with_icon | !!item.icon(); + } for (auto& item : m_items) { if (item.type() == WSMenuItem::Text) { @@ -139,7 +144,7 @@ void WSMenu::draw() text_color = Color::MidGray; Rect text_rect = item.rect().translated(left_padding(), 0); if (item.is_checkable()) { - Rect checkmark_rect { text_rect.location().x(), 0, s_checked_bitmap_width, s_checked_bitmap_height }; + Rect checkmark_rect { text_rect.location().x() + 2, 0, s_checked_bitmap_width, s_checked_bitmap_height }; checkmark_rect.center_vertically_within(text_rect); Rect checkbox_rect = checkmark_rect.inflated(4, 4); painter.fill_rect(checkbox_rect, Color::White); @@ -147,9 +152,13 @@ void WSMenu::draw() if (item.is_checked()) { painter.draw_bitmap(checkmark_rect.location(), *s_checked_bitmap, Color::Black); } + } else if (item.icon()) { + Rect icon_rect { text_rect.location().x() - 2, 0, s_item_icon_width, s_item_icon_width }; + icon_rect.center_vertically_within(text_rect); + painter.blit(icon_rect.location(), *item.icon(), item.icon()->rect()); } - if (has_checkable_items) - text_rect.move_by(s_checked_bitmap_width + s_checked_bitmap_padding, 0); + if (has_checkable_items || has_items_with_icon) + text_rect.move_by(s_item_icon_width + s_checkbox_or_icon_padding, 0); painter.draw_text(text_rect, item.text(), TextAlignment::CenterLeft, text_color); if (!item.shortcut_text().is_empty()) { painter.draw_text(item.rect().translated(-right_padding(), 0), item.shortcut_text(), TextAlignment::CenterRight, text_color); diff --git a/Servers/WindowServer/WSMenu.h b/Servers/WindowServer/WSMenu.h index c6f24a2f95..8b0d437775 100644 --- a/Servers/WindowServer/WSMenu.h +++ b/Servers/WindowServer/WSMenu.h @@ -53,7 +53,7 @@ public: int width() const; int height() const; - int item_height() const { return 16; } + int item_height() const { return 20; } int frame_thickness() const { return 3; } int horizontal_padding() const { return left_padding() + right_padding(); } int left_padding() const { return 14; } diff --git a/Servers/WindowServer/WSMenuBar.cpp b/Servers/WindowServer/WSMenuBar.cpp index 5893a6b83d..5d7e3f934c 100644 --- a/Servers/WindowServer/WSMenuBar.cpp +++ b/Servers/WindowServer/WSMenuBar.cpp @@ -1,6 +1,7 @@ #include "WSMenuBar.h" #include "WSMenu.h" #include "WSMenuItem.h" +#include <LibDraw/GraphicsBitmap.h> WSMenuBar::WSMenuBar(WSClientConnection& client, int menubar_id) : m_client(client) diff --git a/Servers/WindowServer/WSMenuItem.cpp b/Servers/WindowServer/WSMenuItem.cpp index 94db473dec..745d494c16 100644 --- a/Servers/WindowServer/WSMenuItem.cpp +++ b/Servers/WindowServer/WSMenuItem.cpp @@ -1,5 +1,6 @@ #include "WSMenuItem.h" #include "WSMenu.h" +#include <LibDraw/GraphicsBitmap.h> WSMenuItem::WSMenuItem(WSMenu& menu, unsigned identifier, const String& text, const String& shortcut_text, bool enabled, bool checkable, bool checked) : m_menu(menu) diff --git a/Servers/WindowServer/WSMenuItem.h b/Servers/WindowServer/WSMenuItem.h index 4489e332d2..36c5d46f9c 100644 --- a/Servers/WindowServer/WSMenuItem.h +++ b/Servers/WindowServer/WSMenuItem.h @@ -4,6 +4,7 @@ #include <AK/Function.h> #include <LibDraw/Rect.h> +class GraphicsBitmap; class WSMenu; class WSMenuItem { @@ -40,6 +41,9 @@ public: unsigned identifier() const { return m_identifier; } + const GraphicsBitmap* icon() const { return m_icon; } + void set_icon(const GraphicsBitmap* icon) { m_icon = icon; } + private: WSMenu& m_menu; Type m_type { None }; @@ -50,4 +54,5 @@ private: String m_text; String m_shortcut_text; Rect m_rect; + RefPtr<GraphicsBitmap> m_icon; }; diff --git a/Servers/WindowServer/WSWindowSwitcher.cpp b/Servers/WindowServer/WSWindowSwitcher.cpp index 8123027f9b..090d6c8aa2 100644 --- a/Servers/WindowServer/WSWindowSwitcher.cpp +++ b/Servers/WindowServer/WSWindowSwitcher.cpp @@ -1,4 +1,5 @@ #include <LibDraw/Font.h> +#include <LibDraw/GraphicsBitmap.h> #include <LibDraw/StylePainter.h> #include <WindowServer/WSEvent.h> #include <WindowServer/WSScreen.h> |