From ede6314cb65d23dc47a85f09c33a94e9bf283ea4 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Tue, 16 Sep 2025 12:55:37 -0400 Subject: [PATCH] LibWebView+UI/AppKit: Display icons in the macOS UI on Tahoe On macOS Tahoe, it is now recommended to show menu item icons. We use system symbols for this now. Symbols do not have constant variable names and must be found via the SF Symbols app. The symbols chosen here were to match Safari as close as possible. --- Libraries/LibWebView/Menu.h | 3 +- Libraries/LibWebView/ViewImplementation.cpp | 12 +++- Libraries/LibWebView/ViewImplementation.h | 3 +- UI/AppKit/Interface/Menu.h | 4 +- UI/AppKit/Interface/Menu.mm | 79 +++++++++++++++++++-- UI/AppKit/Interface/TabController.mm | 8 +-- 6 files changed, 95 insertions(+), 14 deletions(-) diff --git a/Libraries/LibWebView/Menu.h b/Libraries/LibWebView/Menu.h index e5c55f78da7..13d6c081a7c 100644 --- a/Libraries/LibWebView/Menu.h +++ b/Libraries/LibWebView/Menu.h @@ -50,7 +50,8 @@ enum class ActionID { PauseMedia, MuteMedia, UnmuteMedia, - ToggleMediaControlsState, + ShowControls, + HideControls, ToggleMediaLoopState, ZoomIn, diff --git a/Libraries/LibWebView/ViewImplementation.cpp b/Libraries/LibWebView/ViewImplementation.cpp index bd02967e49f..ff6fa5c5c21 100644 --- a/Libraries/LibWebView/ViewImplementation.cpp +++ b/Libraries/LibWebView/ViewImplementation.cpp @@ -908,7 +908,10 @@ void ViewImplementation::initialize_context_menus() m_media_unmute_action = Action::create("Unmute"sv, ActionID::UnmuteMedia, [this]() { client().async_toggle_media_mute_state(page_id()); }); - m_media_controls_action = Action::create_checkable("Show Controls"sv, ActionID::ToggleMediaControlsState, [this]() { + m_media_show_controls_action = Action::create("Show Controls"sv, ActionID::ShowControls, [this]() { + client().async_toggle_media_controls_state(page_id()); + }); + m_media_hide_controls_action = Action::create("Hide Controls"sv, ActionID::HideControls, [this]() { client().async_toggle_media_controls_state(page_id()); }); m_media_loop_action = Action::create_checkable("Loop"sv, ActionID::ToggleMediaLoopState, [this]() { @@ -947,7 +950,8 @@ void ViewImplementation::initialize_context_menus() m_media_context_menu->add_action(*m_media_pause_action); m_media_context_menu->add_action(*m_media_mute_action); m_media_context_menu->add_action(*m_media_unmute_action); - m_media_context_menu->add_action(*m_media_controls_action); + m_media_context_menu->add_action(*m_media_show_controls_action); + m_media_context_menu->add_action(*m_media_hide_controls_action); m_media_context_menu->add_action(*m_media_loop_action); m_media_context_menu->add_separator(); m_media_context_menu->add_action(*m_open_audio_action); @@ -1027,7 +1031,9 @@ void ViewImplementation::did_request_media_context_menu(Badge, m_media_mute_action->set_visible(!menu.is_muted); m_media_unmute_action->set_visible(menu.is_muted); - m_media_controls_action->set_checked(menu.has_user_agent_controls); + m_media_show_controls_action->set_visible(!menu.has_user_agent_controls); + m_media_hide_controls_action->set_visible(menu.has_user_agent_controls); + m_media_loop_action->set_checked(menu.is_looping); if (m_media_context_menu->on_activation) diff --git a/Libraries/LibWebView/ViewImplementation.h b/Libraries/LibWebView/ViewImplementation.h index bf7eaa7e36c..be362bd7bc4 100644 --- a/Libraries/LibWebView/ViewImplementation.h +++ b/Libraries/LibWebView/ViewImplementation.h @@ -331,7 +331,8 @@ protected: RefPtr m_media_pause_action; RefPtr m_media_mute_action; RefPtr m_media_unmute_action; - RefPtr m_media_controls_action; + RefPtr m_media_show_controls_action; + RefPtr m_media_hide_controls_action; RefPtr m_media_loop_action; Queue m_pending_input_events; diff --git a/UI/AppKit/Interface/Menu.h b/UI/AppKit/Interface/Menu.h index f27b847d93d..5447fcbcdb9 100644 --- a/UI/AppKit/Interface/Menu.h +++ b/UI/AppKit/Interface/Menu.h @@ -19,6 +19,8 @@ NSMenu* create_application_menu(WebView::Menu&); NSMenu* create_context_menu(LadybirdWebView*, WebView::Menu&); NSMenuItem* create_application_menu_item(WebView::Action&); -NSButton* create_application_button(WebView::Action&, NSImageName); +NSButton* create_application_button(WebView::Action&); + +void set_control_image(id control, NSString*); } diff --git a/UI/AppKit/Interface/Menu.mm b/UI/AppKit/Interface/Menu.mm index edc60f983be..6f0a08ad22a 100644 --- a/UI/AppKit/Interface/Menu.mm +++ b/UI/AppKit/Interface/Menu.mm @@ -115,29 +115,87 @@ static void initialize_native_control(WebView::Action& action, id control) { switch (action.id()) { case WebView::ActionID::NavigateBack: + set_control_image(control, @"chevron.left"); [control setKeyEquivalent:@"["]; break; case WebView::ActionID::NavigateForward: + set_control_image(control, @"chevron.right"); [control setKeyEquivalent:@"]"]; break; case WebView::ActionID::Reload: + set_control_image(control, @"arrow.clockwise"); [control setKeyEquivalent:@"r"]; break; case WebView::ActionID::CopySelection: + set_control_image(control, @"document.on.document"); [control setKeyEquivalent:@"c"]; break; case WebView::ActionID::Paste: + set_control_image(control, @"document.on.clipboard"); [control setKeyEquivalent:@"v"]; break; case WebView::ActionID::SelectAll: + set_control_image(control, @"character.textbox"); [control setKeyEquivalent:@"a"]; break; + case WebView::ActionID::SearchSelectedText: + set_control_image(control, @"magnifyingglass"); + break; + case WebView::ActionID::ViewSource: + set_control_image(control, @"text.document"); [control setKeyEquivalent:@"u"]; break; + case WebView::ActionID::TakeVisibleScreenshot: + case WebView::ActionID::TakeFullScreenshot: + set_control_image(control, @"photo"); + break; + + case WebView::ActionID::OpenInNewTab: + set_control_image(control, @"plus.square.on.square"); + break; + case WebView::ActionID::CopyURL: + set_control_image(control, @"document.on.document"); + break; + + case WebView::ActionID::OpenImage: + set_control_image(control, @"photo"); + break; + case WebView::ActionID::CopyImage: + set_control_image(control, @"document.on.document"); + break; + + case WebView::ActionID::OpenAudio: + set_control_image(control, @"speaker.wave.1"); + break; + case WebView::ActionID::OpenVideo: + set_control_image(control, @"video"); + break; + case WebView::ActionID::PlayMedia: + set_control_image(control, @"play"); + break; + case WebView::ActionID::PauseMedia: + set_control_image(control, @"pause"); + break; + case WebView::ActionID::MuteMedia: + set_control_image(control, @"speaker.slash"); + break; + case WebView::ActionID::UnmuteMedia: + set_control_image(control, @"speaker.wave.2"); + break; + case WebView::ActionID::ShowControls: + set_control_image(control, @"eye"); + break; + case WebView::ActionID::HideControls: + set_control_image(control, @"eye.slash"); + break; + case WebView::ActionID::ToggleMediaLoopState: + set_control_image(control, @"arrow.clockwise"); + break; + case WebView::ActionID::ZoomIn: [control setKeyEquivalent:@"+"]; break; @@ -213,14 +271,27 @@ NSMenuItem* create_application_menu_item(WebView::Action& action) return item; } -NSButton* create_application_button(WebView::Action& action, NSImageName image) +NSButton* create_application_button(WebView::Action& action) { auto* button = [[NSButton alloc] init]; - if (image) - [button setImage:[NSImage imageNamed:image]]; - initialize_native_control(action, button); return button; } +void set_control_image(id control, NSString* image) +{ + // System symbols are distributed with the San Fransisco (SF) Symbols font. To see all SF Symbols and their names, + // you will have to install the SF Symbols app: https://developer.apple.com/sf-symbols/ + auto set_image = [&]() { + [control setImage:[NSImage imageWithSystemSymbolName:image accessibilityDescription:@""]]; + }; + + if (@available(macOS 26, *)) { + set_image(); + } else { + if ([control isKindOfClass:[NSButton class]]) + set_image(); + } +} + } diff --git a/UI/AppKit/Interface/TabController.mm b/UI/AppKit/Interface/TabController.mm index 2f8f44a8b29..d3173f2d885 100644 --- a/UI/AppKit/Interface/TabController.mm +++ b/UI/AppKit/Interface/TabController.mm @@ -260,7 +260,7 @@ static NSString* const TOOLBAR_TAB_OVERVIEW_IDENTIFIER = @"ToolbarTabOverviewIde - (NSToolbarItem*)navigate_back_toolbar_item { if (!_navigate_back_toolbar_item) { - auto* button = Ladybird::create_application_button([[[self tab] web_view] view].navigate_back_action(), NSImageNameGoBackTemplate); + auto* button = Ladybird::create_application_button([[[self tab] web_view] view].navigate_back_action()); _navigate_back_toolbar_item = [[NSToolbarItem alloc] initWithItemIdentifier:TOOLBAR_NAVIGATE_BACK_IDENTIFIER]; [_navigate_back_toolbar_item setView:button]; @@ -272,7 +272,7 @@ static NSString* const TOOLBAR_TAB_OVERVIEW_IDENTIFIER = @"ToolbarTabOverviewIde - (NSToolbarItem*)navigate_forward_toolbar_item { if (!_navigate_forward_toolbar_item) { - auto* button = Ladybird::create_application_button([[[self tab] web_view] view].navigate_forward_action(), NSImageNameGoForwardTemplate); + auto* button = Ladybird::create_application_button([[[self tab] web_view] view].navigate_forward_action()); _navigate_forward_toolbar_item = [[NSToolbarItem alloc] initWithItemIdentifier:TOOLBAR_NAVIGATE_FORWARD_IDENTIFIER]; [_navigate_forward_toolbar_item setView:button]; @@ -284,7 +284,7 @@ static NSString* const TOOLBAR_TAB_OVERVIEW_IDENTIFIER = @"ToolbarTabOverviewIde - (NSToolbarItem*)reload_toolbar_item { if (!_reload_toolbar_item) { - auto* button = Ladybird::create_application_button(WebView::Application::the().reload_action(), NSImageNameRefreshTemplate); + auto* button = Ladybird::create_application_button(WebView::Application::the().reload_action()); _reload_toolbar_item = [[NSToolbarItem alloc] initWithItemIdentifier:TOOLBAR_RELOAD_IDENTIFIER]; [_reload_toolbar_item setView:button]; @@ -315,7 +315,7 @@ static NSString* const TOOLBAR_TAB_OVERVIEW_IDENTIFIER = @"ToolbarTabOverviewIde - (NSToolbarItem*)zoom_toolbar_item { if (!_zoom_toolbar_item) { - auto* button = Ladybird::create_application_button([[[self tab] web_view] view].reset_zoom_action(), nil); + auto* button = Ladybird::create_application_button([[[self tab] web_view] view].reset_zoom_action()); _zoom_toolbar_item = [[NSToolbarItem alloc] initWithItemIdentifier:TOOLBAR_ZOOM_IDENTIFIER]; [_zoom_toolbar_item setView:button];