| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ui/views/frame/dbus_appmenu.h" |
| |
| #include <dlfcn.h> |
| #include <stddef.h> |
| |
| #include <limits> |
| #include <memory> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/bind.h" |
| #include "base/check_op.h" |
| #include "base/containers/contains.h" |
| #include "base/feature_list.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "build/branding_buildflags.h" |
| #include "chrome/app/chrome_command_ids.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/history/top_sites_factory.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/profiles/profile_manager.h" |
| #include "chrome/browser/profiles/profile_metrics.h" |
| #include "chrome/browser/profiles/profile_window.h" |
| #include "chrome/browser/sessions/tab_restore_service_factory.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_commands.h" |
| #include "chrome/browser/ui/browser_list.h" |
| #include "chrome/browser/ui/browser_live_tab_context.h" |
| #include "chrome/browser/ui/profile_picker.h" |
| #include "chrome/browser/ui/ui_features.h" |
| #include "chrome/browser/ui/views/frame/browser_view.h" |
| #include "chrome/browser/ui/views/frame/dbus_appmenu_registrar.h" |
| #include "chrome/grit/generated_resources.h" |
| #include "components/bookmarks/common/bookmark_pref_names.h" |
| #include "components/history/core/browser/top_sites.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/sessions/core/tab_restore_service.h" |
| #include "components/strings/grit/components_strings.h" |
| #include "dbus/object_path.h" |
| #include "ui/base/accelerators/menu_label_accelerator_util_linux.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/base/models/menu_model.h" |
| #include "ui/base/models/menu_separator_types.h" |
| #include "ui/events/keycodes/keyboard_code_conversion_x.h" |
| #include "ui/gfx/text_elider.h" |
| |
| // A line in the static menu definitions. |
| struct DbusAppmenuCommand { |
| int command; |
| int str_id; |
| }; |
| |
| namespace { |
| |
| // The maximum number of most visited items to display. |
| const unsigned int kMostVisitedCount = 8; |
| |
| // The number of recently closed items to get. |
| const unsigned int kRecentlyClosedCount = 8; |
| |
| // Menus more than this many chars long will get trimmed. |
| const size_t kMaximumMenuWidthInChars = 50; |
| |
| // Constants used in menu definitions. The first non-Chrome command is at |
| // IDC_FIRST_UNBOUNDED_MENU. |
| enum ReservedCommandId { |
| kLastChromeCommand = IDC_FIRST_UNBOUNDED_MENU - 1, |
| kMenuEnd, |
| kSeparator, |
| kSubmenu, |
| kTagRecentlyClosed, |
| kTagMostVisited, |
| kTagProfileEdit, |
| kTagProfileCreate, |
| kFirstUnreservedCommandId |
| }; |
| |
| constexpr DbusAppmenuCommand kFileMenu[] = { |
| {IDC_NEW_TAB, IDS_NEW_TAB}, |
| {IDC_NEW_WINDOW, IDS_NEW_WINDOW}, |
| {IDC_NEW_INCOGNITO_WINDOW, IDS_NEW_INCOGNITO_WINDOW}, |
| {IDC_RESTORE_TAB, IDS_REOPEN_CLOSED_TABS_LINUX}, |
| {IDC_OPEN_FILE, IDS_OPEN_FILE_LINUX}, |
| {IDC_FOCUS_LOCATION, IDS_OPEN_LOCATION_LINUX}, |
| {kSeparator}, |
| {IDC_CLOSE_WINDOW, IDS_CLOSE_WINDOW_LINUX}, |
| {IDC_CLOSE_TAB, IDS_CLOSE_TAB_LINUX}, |
| {IDC_SAVE_PAGE, IDS_SAVE_PAGE}, |
| {kSeparator}, |
| {IDC_PRINT, IDS_PRINT}, |
| {kMenuEnd}}; |
| |
| constexpr DbusAppmenuCommand kEditMenu[] = {{IDC_CUT, IDS_CUT}, |
| {IDC_COPY, IDS_COPY}, |
| {IDC_PASTE, IDS_PASTE}, |
| {kSeparator}, |
| {IDC_FIND, IDS_FIND}, |
| {kSeparator}, |
| {IDC_OPTIONS, IDS_PREFERENCES}, |
| {kMenuEnd}}; |
| |
| constexpr DbusAppmenuCommand kViewMenu[] = { |
| {IDC_SHOW_BOOKMARK_BAR, IDS_SHOW_BOOKMARK_BAR}, |
| {kSeparator}, |
| {IDC_STOP, IDS_STOP_MENU_LINUX}, |
| {IDC_RELOAD, IDS_RELOAD_MENU_LINUX}, |
| {kSeparator}, |
| {IDC_FULLSCREEN, IDS_FULLSCREEN}, |
| {IDC_ZOOM_NORMAL, IDS_TEXT_DEFAULT_LINUX}, |
| {IDC_ZOOM_PLUS, IDS_TEXT_BIGGER_LINUX}, |
| {IDC_ZOOM_MINUS, IDS_TEXT_SMALLER_LINUX}, |
| {kMenuEnd}}; |
| |
| constexpr DbusAppmenuCommand kHistoryMenu[] = { |
| {IDC_HOME, IDS_HISTORY_HOME_LINUX}, |
| {IDC_BACK, IDS_HISTORY_BACK_LINUX}, |
| {IDC_FORWARD, IDS_HISTORY_FORWARD_LINUX}, |
| {kSeparator}, |
| {kTagRecentlyClosed, IDS_HISTORY_CLOSED_LINUX}, |
| {kSeparator}, |
| {kTagMostVisited, IDS_HISTORY_VISITED_LINUX}, |
| {kSeparator}, |
| {IDC_SHOW_HISTORY, IDS_HISTORY_SHOWFULLHISTORY_LINK}, |
| {kMenuEnd}}; |
| |
| constexpr DbusAppmenuCommand kToolsMenu[] = { |
| {IDC_SHOW_DOWNLOADS, IDS_SHOW_DOWNLOADS}, |
| {IDC_SHOW_HISTORY, IDS_HISTORY_SHOW_HISTORY}, |
| {IDC_MANAGE_EXTENSIONS, IDS_SHOW_EXTENSIONS}, |
| {kSeparator}, |
| {IDC_TASK_MANAGER, IDS_TASK_MANAGER}, |
| {IDC_CLEAR_BROWSING_DATA, IDS_CLEAR_BROWSING_DATA}, |
| {kSeparator}, |
| {IDC_VIEW_SOURCE, IDS_VIEW_SOURCE}, |
| {IDC_DEV_TOOLS, IDS_DEV_TOOLS}, |
| {IDC_DEV_TOOLS_INSPECT, IDS_DEV_TOOLS_ELEMENTS}, |
| {IDC_DEV_TOOLS_CONSOLE, IDS_DEV_TOOLS_CONSOLE}, |
| {IDC_DEV_TOOLS_DEVICES, IDS_DEV_TOOLS_DEVICES}, |
| {kMenuEnd}}; |
| |
| constexpr DbusAppmenuCommand kProfilesMenu[] = { |
| {kSeparator}, |
| {kTagProfileEdit, IDS_PROFILES_MANAGE_BUTTON_LABEL}, |
| {kTagProfileCreate, IDS_PROFILES_ADD_PROFILE_LABEL}, |
| {kMenuEnd}}; |
| |
| constexpr DbusAppmenuCommand kHelpMenu[] = { |
| #if BUILDFLAG(GOOGLE_CHROME_BRANDING) |
| {IDC_FEEDBACK, IDS_FEEDBACK}, |
| #endif |
| {IDC_HELP_PAGE_VIA_MENU, IDS_HELP_PAGE}, |
| {kMenuEnd}}; |
| |
| void FindMenuItemsForCommandAux( |
| ui::MenuModel* menu, |
| int command, |
| std::vector<std::pair<ui::MenuModel*, size_t>>* menu_items) { |
| for (size_t i = 0; i < menu->GetItemCount(); ++i) { |
| if (menu->GetCommandIdAt(i) == command) |
| menu_items->push_back({menu, i}); |
| if (menu->GetTypeAt(i) == ui::SimpleMenuModel::ItemType::TYPE_SUBMENU) { |
| FindMenuItemsForCommandAux(menu->GetSubmenuModelAt(i), command, |
| menu_items); |
| } |
| } |
| } |
| |
| std::vector<std::pair<ui::MenuModel*, size_t>> FindMenuItemsForCommand( |
| ui::MenuModel* menu, |
| int command) { |
| std::vector<std::pair<ui::MenuModel*, size_t>> menu_items; |
| FindMenuItemsForCommandAux(menu, command, &menu_items); |
| return menu_items; |
| } |
| |
| } // namespace |
| |
| struct DbusAppmenu::HistoryItem { |
| HistoryItem() : session_id(SessionID::InvalidValue()) {} |
| |
| HistoryItem(const HistoryItem&) = delete; |
| HistoryItem& operator=(const HistoryItem&) = delete; |
| |
| // The title for the menu item. |
| std::u16string title; |
| // The URL that will be navigated to if the user selects this item. |
| GURL url; |
| |
| // This ID is unique for a browser session and can be passed to the |
| // TabRestoreService to re-open the closed window or tab that this |
| // references. A valid session ID indicates that this is an entry can be |
| // restored that way. Otherwise, the URL will be used to open the item and |
| // this ID will be invalid. |
| SessionID session_id; |
| |
| // If the HistoryItem is a window, this will be the vector of tabs. Note |
| // that this is a list of weak references. DbusAppmenu::history_items_ |
| // is the owner of all items. If it is not a window, then the entry is a |
| // single page and the vector will be empty. |
| std::vector<HistoryItem*> tabs; |
| }; |
| |
| DbusAppmenu::DbusAppmenu(BrowserView* browser_view, uint32_t browser_frame_id) |
| : browser_(browser_view->browser()), |
| profile_(browser_->profile()), |
| browser_view_(browser_view), |
| browser_frame_id_(browser_frame_id), |
| tab_restore_service_(nullptr), |
| last_command_id_(kFirstUnreservedCommandId - 1) { |
| DbusAppmenuRegistrar::GetInstance()->OnMenuBarCreated(this); |
| } |
| |
| DbusAppmenu::~DbusAppmenu() { |
| auto* registrar = DbusAppmenuRegistrar::GetInstance(); |
| registrar->OnMenuBarDestroyed(this); |
| |
| if (!initialized_) |
| return; |
| |
| registrar->bus()->UnregisterExportedObject(dbus::ObjectPath(GetPath())); |
| |
| for (int command : observed_commands_) |
| chrome::RemoveCommandObserver(browser_, command, this); |
| |
| pref_change_registrar_.RemoveAll(); |
| |
| if (tab_restore_service_) |
| tab_restore_service_->RemoveObserver(this); |
| |
| BrowserList::RemoveObserver(this); |
| } |
| |
| void DbusAppmenu::Initialize(DbusMenu::InitializedCallback callback) { |
| DCHECK(!initialized_); |
| initialized_ = true; |
| |
| // First build static menu content. |
| root_menu_ = std::make_unique<ui::SimpleMenuModel>(this); |
| |
| BuildStaticMenu(IDS_FILE_MENU_LINUX, kFileMenu); |
| BuildStaticMenu(IDS_EDIT_MENU_LINUX, kEditMenu); |
| BuildStaticMenu(IDS_VIEW_MENU_LINUX, kViewMenu); |
| history_menu_ = BuildStaticMenu(IDS_HISTORY_MENU_LINUX, kHistoryMenu); |
| BuildStaticMenu(IDS_TOOLS_MENU_LINUX, kToolsMenu); |
| profiles_menu_ = BuildStaticMenu(IDS_PROFILES_MENU_NAME, kProfilesMenu); |
| BuildStaticMenu(IDS_HELP_MENU_LINUX, kHelpMenu); |
| |
| pref_change_registrar_.Init(browser_->profile()->GetPrefs()); |
| pref_change_registrar_.Add( |
| bookmarks::prefs::kShowBookmarkBar, |
| base::BindRepeating(&DbusAppmenu::OnBookmarkBarVisibilityChanged, |
| base::Unretained(this))); |
| |
| top_sites_ = TopSitesFactory::GetForProfile(profile_); |
| if (top_sites_) { |
| GetTopSitesData(); |
| |
| // Register as TopSitesObserver so that we can update ourselves when the |
| // TopSites changes. |
| scoped_observation_.Observe(top_sites_.get()); |
| } |
| |
| ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| DCHECK(profile_manager); |
| avatar_menu_ = std::make_unique<AvatarMenu>( |
| &profile_manager->GetProfileAttributesStorage(), this, |
| BrowserList::GetInstance()->GetLastActive()); |
| avatar_menu_->RebuildMenu(); |
| BrowserList::AddObserver(this); |
| |
| RebuildProfilesMenu(); |
| |
| menu_service_ = std::make_unique<DbusMenu>( |
| DbusAppmenuRegistrar::GetInstance()->bus()->GetExportedObject( |
| dbus::ObjectPath(GetPath())), |
| std::move(callback)); |
| menu_service_->SetModel(root_menu_.get(), false); |
| } |
| |
| std::string DbusAppmenu::GetPath() const { |
| return base::StringPrintf("/com/canonical/menu/%X", browser_frame_id_); |
| } |
| |
| ui::SimpleMenuModel* DbusAppmenu::BuildStaticMenu( |
| int string_id, |
| const DbusAppmenuCommand* commands) { |
| toplevel_menus_.push_back(std::make_unique<ui::SimpleMenuModel>(this)); |
| ui::SimpleMenuModel* menu = toplevel_menus_.back().get(); |
| for (; commands->command != kMenuEnd; commands++) { |
| int command_id = commands->command; |
| if (command_id == kSeparator) { |
| // Use InsertSeparatorAt() instead of AddSeparator() because the latter |
| // refuses to add a separator to an empty menu. |
| size_t old_item_count = menu->GetItemCount(); |
| menu->InsertSeparatorAt(old_item_count, |
| ui::MenuSeparatorType::SPACING_SEPARATOR); |
| |
| // Make extra sure the separator got added in case the behavior |
| // InsertSeparatorAt() changes. |
| CHECK_EQ(old_item_count + 1, menu->GetItemCount()); |
| continue; |
| } |
| |
| int string_id = commands->str_id; |
| if (command_id == IDC_SHOW_BOOKMARK_BAR) |
| menu->AddCheckItemWithStringId(command_id, string_id); |
| else |
| menu->AddItemWithStringId(command_id, string_id); |
| if (command_id < kLastChromeCommand) |
| RegisterCommandObserver(command_id); |
| } |
| root_menu_->AddSubMenu(kSubmenu, l10n_util::GetStringUTF16(string_id), menu); |
| return menu; |
| } |
| |
| std::unique_ptr<DbusAppmenu::HistoryItem> DbusAppmenu::HistoryItemForTab( |
| const sessions::TabRestoreService::Tab& entry) { |
| const sessions::SerializedNavigationEntry& current_navigation = |
| entry.navigations.at(entry.current_navigation_index); |
| auto item = std::make_unique<HistoryItem>(); |
| item->title = current_navigation.title(); |
| item->url = current_navigation.virtual_url(); |
| item->session_id = entry.id; |
| return item; |
| } |
| |
| void DbusAppmenu::AddHistoryItemToMenu(std::unique_ptr<HistoryItem> item, |
| ui::SimpleMenuModel* menu, |
| int index) { |
| std::u16string title = item->title; |
| std::string url_string = item->url.possibly_invalid_spec(); |
| |
| if (title.empty()) |
| title = base::UTF8ToUTF16(url_string); |
| gfx::ElideString(title, kMaximumMenuWidthInChars, &title); |
| |
| int command_id = NextCommandId(); |
| menu->InsertItemAt(index, command_id, title); |
| history_items_[command_id] = std::move(item); |
| } |
| |
| void DbusAppmenu::AddEntryToHistoryMenu( |
| SessionID id, |
| std::u16string title, |
| int index, |
| const std::vector<std::unique_ptr<sessions::TabRestoreService::Tab>>& |
| tabs) { |
| // Create the item for the parent/window. |
| auto item = std::make_unique<HistoryItem>(); |
| item->session_id = id; |
| |
| auto parent_menu = std::make_unique<ui::SimpleMenuModel>(this); |
| int command = NextCommandId(); |
| history_menu_->InsertSubMenuAt(index, command, title, parent_menu.get()); |
| parent_menu->AddItemWithStringId(command, |
| IDS_HISTORY_CLOSED_RESTORE_WINDOW_LINUX); |
| parent_menu->AddSeparator(ui::MenuSeparatorType::NORMAL_SEPARATOR); |
| |
| // Loop over the tabs and add them to the submenu. |
| int subindex = 2; |
| for (const auto& tab : tabs) { |
| std::unique_ptr<HistoryItem> tab_item = HistoryItemForTab(*tab); |
| item->tabs.push_back(tab_item.get()); |
| AddHistoryItemToMenu(std::move(tab_item), parent_menu.get(), subindex++); |
| } |
| |
| history_items_[command] = std::move(item); |
| recently_closed_window_menus_.push_back(std::move(parent_menu)); |
| } |
| |
| void DbusAppmenu::GetTopSitesData() { |
| DCHECK(top_sites_); |
| |
| top_sites_->GetMostVisitedURLs(base::BindOnce( |
| &DbusAppmenu::OnTopSitesReceived, weak_ptr_factory_.GetWeakPtr())); |
| } |
| |
| void DbusAppmenu::OnTopSitesReceived( |
| const history::MostVisitedURLList& visited_list) { |
| int index = ClearHistoryMenuSection(kTagMostVisited); |
| |
| for (size_t i = 0; i < visited_list.size() && i < kMostVisitedCount; ++i) { |
| const history::MostVisitedURL& visited = visited_list[i]; |
| if (visited.url.spec().empty()) |
| break; // This is the signal that there are no more real visited sites. |
| |
| auto item = std::make_unique<HistoryItem>(); |
| item->title = visited.title; |
| item->url = visited.url; |
| |
| AddHistoryItemToMenu(std::move(item), history_menu_, index++); |
| } |
| |
| if (menu_service_) |
| menu_service_->MenuLayoutUpdated(history_menu_); |
| } |
| |
| void DbusAppmenu::OnBookmarkBarVisibilityChanged() { |
| menu_service_->MenuItemsPropertiesUpdated( |
| FindMenuItemsForCommand(root_menu_.get(), IDC_SHOW_BOOKMARK_BAR)); |
| } |
| |
| void DbusAppmenu::RebuildProfilesMenu() { |
| while (profiles_menu_->GetTypeAt(0) != ui::MenuModel::TYPE_SEPARATOR) |
| profiles_menu_->RemoveItemAt(0); |
| profile_commands_.clear(); |
| |
| // Don't call avatar_menu_->GetActiveProfileIndex() as the as the index might |
| // be incorrect if RebuildProfilesMenu() is called while we deleting the |
| // active profile and closing all its browser windows. |
| active_profile_index_ = -1; |
| for (size_t i = 0; i < avatar_menu_->GetNumberOfItems(); ++i) { |
| const AvatarMenu::Item& item = avatar_menu_->GetItemAt(i); |
| std::u16string title = item.name; |
| gfx::ElideString(title, kMaximumMenuWidthInChars, &title); |
| |
| if (item.active) |
| active_profile_index_ = i; |
| |
| int command = NextCommandId(); |
| profile_commands_[command] = i; |
| profiles_menu_->InsertCheckItemAt(i, command, title); |
| } |
| |
| if (menu_service_) |
| menu_service_->MenuLayoutUpdated(profiles_menu_); |
| } |
| |
| int DbusAppmenu::ClearHistoryMenuSection(int header_command_id) { |
| int index = 0; |
| while (history_menu_->GetCommandIdAt(index++) != header_command_id) { |
| } |
| while (history_menu_->GetTypeAt(index) != ui::MenuModel::TYPE_SEPARATOR) { |
| history_items_.erase(history_menu_->GetCommandIdAt(index)); |
| history_menu_->RemoveItemAt(index); |
| } |
| return index; |
| } |
| |
| void DbusAppmenu::RegisterCommandObserver(int command) { |
| if (command > kLastChromeCommand) |
| return; |
| |
| // Keep track of which commands are already registered to avoid |
| // registering them twice. |
| const bool inserted = observed_commands_.insert(command).second; |
| if (!inserted) |
| return; |
| |
| chrome::AddCommandObserver(browser_, command, this); |
| } |
| |
| int DbusAppmenu::NextCommandId() { |
| do { |
| if (last_command_id_ == std::numeric_limits<int>::max()) |
| last_command_id_ = kFirstUnreservedCommandId; |
| else |
| last_command_id_++; |
| } while (base::Contains(history_items_, last_command_id_) || |
| base::Contains(profile_commands_, last_command_id_)); |
| return last_command_id_; |
| } |
| |
| void DbusAppmenu::OnAvatarMenuChanged(AvatarMenu* avatar_menu) { |
| RebuildProfilesMenu(); |
| } |
| |
| void DbusAppmenu::OnBrowserSetLastActive(Browser* browser) { |
| // Notify the avatar menu of the change and rebuild the menu. Note: The |
| // ActiveBrowserChanged() call needs to happen first to update the state. |
| avatar_menu_->ActiveBrowserChanged(browser); |
| avatar_menu_->RebuildMenu(); |
| RebuildProfilesMenu(); |
| } |
| |
| void DbusAppmenu::EnabledStateChangedForCommand(int id, bool enabled) { |
| menu_service_->MenuItemsPropertiesUpdated( |
| FindMenuItemsForCommand(root_menu_.get(), id)); |
| } |
| |
| void DbusAppmenu::TopSitesLoaded(history::TopSites* top_sites) {} |
| |
| void DbusAppmenu::TopSitesChanged(history::TopSites* top_sites, |
| ChangeReason change_reason) { |
| GetTopSitesData(); |
| } |
| |
| void DbusAppmenu::TabRestoreServiceChanged( |
| sessions::TabRestoreService* service) { |
| const sessions::TabRestoreService::Entries& entries = service->entries(); |
| |
| int index = ClearHistoryMenuSection(kTagRecentlyClosed); |
| recently_closed_window_menus_.clear(); |
| |
| unsigned int added_count = 0; |
| for (auto it = entries.begin(); |
| it != entries.end() && added_count < kRecentlyClosedCount; ++it) { |
| sessions::TabRestoreService::Entry* entry = it->get(); |
| |
| if (entry->type == sessions::TabRestoreService::WINDOW) { |
| sessions::TabRestoreService::Window* window = |
| static_cast<sessions::TabRestoreService::Window*>(entry); |
| |
| auto& tabs = window->tabs; |
| if (tabs.empty()) |
| continue; |
| |
| std::u16string title = l10n_util::GetPluralStringFUTF16( |
| IDS_RECENTLY_CLOSED_WINDOW, tabs.size()); |
| |
| AddEntryToHistoryMenu(window->id, title, index++, tabs); |
| ++added_count; |
| } else if (entry->type == sessions::TabRestoreService::TAB) { |
| sessions::TabRestoreService::Tab* tab = |
| static_cast<sessions::TabRestoreService::Tab*>(entry); |
| AddHistoryItemToMenu(HistoryItemForTab(*tab), history_menu_, index++); |
| ++added_count; |
| } else if (entry->type == sessions::TabRestoreService::GROUP) { |
| sessions::TabRestoreService::Group* group = |
| static_cast<sessions::TabRestoreService::Group*>(entry); |
| |
| auto& tabs = group->tabs; |
| if (tabs.empty()) |
| continue; |
| |
| std::u16string title; |
| if (group->visual_data.title().empty()) { |
| title = l10n_util::GetPluralStringFUTF16( |
| IDS_RECENTLY_CLOSED_GROUP_UNNAMED, tabs.size()); |
| } else { |
| title = l10n_util::GetPluralStringFUTF16(IDS_RECENTLY_CLOSED_GROUP, |
| tabs.size()); |
| title = base::ReplaceStringPlaceholders( |
| title, {group->visual_data.title()}, nullptr); |
| } |
| |
| AddEntryToHistoryMenu(group->id, title, index++, tabs); |
| ++added_count; |
| } |
| } |
| |
| menu_service_->MenuLayoutUpdated(history_menu_); |
| } |
| |
| void DbusAppmenu::TabRestoreServiceDestroyed( |
| sessions::TabRestoreService* service) { |
| tab_restore_service_ = nullptr; |
| } |
| |
| bool DbusAppmenu::IsCommandIdChecked(int command_id) const { |
| if (command_id == IDC_SHOW_BOOKMARK_BAR) { |
| return browser_->profile()->GetPrefs()->GetBoolean( |
| bookmarks::prefs::kShowBookmarkBar); |
| } |
| |
| auto it = profile_commands_.find(command_id); |
| return it != profile_commands_.end() && it->second == active_profile_index_; |
| } |
| |
| bool DbusAppmenu::IsCommandIdEnabled(int command_id) const { |
| if (command_id <= kLastChromeCommand) |
| return chrome::IsCommandEnabled(browser_, command_id); |
| // There is no active profile in Guest mode, in which case the action |
| // buttons should be disabled. |
| if (command_id == kTagProfileEdit || command_id == kTagProfileCreate) |
| return active_profile_index_ >= 0; |
| return command_id != kTagRecentlyClosed && command_id != kTagMostVisited; |
| } |
| |
| void DbusAppmenu::ExecuteCommand(int command_id, int event_flags) { |
| if (command_id <= kLastChromeCommand) { |
| chrome::ExecuteCommand(browser_, command_id); |
| } else if (command_id == kTagProfileEdit) { |
| avatar_menu_->EditProfile(active_profile_index_); |
| } else if (command_id == kTagProfileCreate) { |
| ProfilePicker::Show(ProfilePicker::Params::FromEntryPoint( |
| ProfilePicker::EntryPoint::kProfileMenuAddNewProfile)); |
| } else if (base::Contains(history_items_, command_id)) { |
| HistoryItem* item = history_items_[command_id].get(); |
| // If this item can be restored using TabRestoreService, do so. |
| // Otherwise, just load the URL. |
| sessions::TabRestoreService* service = |
| TabRestoreServiceFactory::GetForProfile(profile_); |
| if (item->session_id.is_valid() && service) { |
| service->RestoreEntryById(browser_->live_tab_context(), item->session_id, |
| WindowOpenDisposition::UNKNOWN); |
| } else { |
| DCHECK(item->url.is_valid()); |
| browser_->OpenURL( |
| content::OpenURLParams(item->url, content::Referrer(), |
| WindowOpenDisposition::NEW_FOREGROUND_TAB, |
| ui::PAGE_TRANSITION_AUTO_BOOKMARK, false)); |
| } |
| } else if (base::Contains(profile_commands_, command_id)) { |
| avatar_menu_->SwitchToProfile(profile_commands_[command_id], false); |
| } |
| } |
| |
| void DbusAppmenu::OnMenuWillShow(ui::SimpleMenuModel* source) { |
| if (source != history_menu_ || tab_restore_service_) |
| return; |
| |
| tab_restore_service_ = TabRestoreServiceFactory::GetForProfile(profile_); |
| if (!tab_restore_service_) |
| return; |
| |
| tab_restore_service_->LoadTabsFromLastSession(); |
| tab_restore_service_->AddObserver(this); |
| |
| // If LoadTabsFromLastSession doesn't load tabs, it won't call |
| // TabRestoreServiceChanged(). This ensures that all new windows after |
| // the first one will have their menus populated correctly. |
| TabRestoreServiceChanged(tab_restore_service_); |
| } |
| |
| bool DbusAppmenu::GetAcceleratorForCommandId( |
| int command_id, |
| ui::Accelerator* accelerator) const { |
| return browser_view_->GetAccelerator(command_id, accelerator); |
| } |