Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2785)

Unified Diff: chrome/browser/ui/views/frame/global_menu_bar_x11.cc

Issue 22562005: linux_aura: Implement the dynamic History menu in the dbusmenu. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Redo how HistoryItems are stored. Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/ui/views/frame/global_menu_bar_x11.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/ui/views/frame/global_menu_bar_x11.cc
diff --git a/chrome/browser/ui/views/frame/global_menu_bar_x11.cc b/chrome/browser/ui/views/frame/global_menu_bar_x11.cc
index e6ccb3ef863168f060f1dc4ee070b0e836cf8c69..9b0f1a743c0b0f2d9f4e66262a6bca5e15e2708e 100644
--- a/chrome/browser/ui/views/frame/global_menu_bar_x11.cc
+++ b/chrome/browser/ui/views/frame/global_menu_bar_x11.cc
@@ -9,27 +9,45 @@
#include "base/logging.h"
#include "base/prefs/pref_service.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/history/top_sites.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/sessions/tab_restore_service.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_tab_restore_service_delegate.h"
#include "chrome/browser/ui/views/frame/browser_desktop_root_window_host_x11.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h"
#include "chrome/common/pref_names.h"
+#include "content/public/browser/notification_source.h"
#include "grit/generated_resources.h"
#include "ui/base/accelerators/menu_label_accelerator_util_linux.h"
#include "ui/base/keycodes/keyboard_code_conversion_x.h"
#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/text/text_elider.h"
// libdbusmenu-glib types
typedef struct _DbusmenuMenuitem DbusmenuMenuitem;
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_new_func)();
-typedef DbusmenuMenuitem* (*dbusmenu_menuitem_new_with_id_func)(int id);
-
-typedef int (*dbusmenu_menuitem_get_id_func)(DbusmenuMenuitem* item);
+typedef bool (*dbusmenu_menuitem_child_add_position_func)(
+ DbusmenuMenuitem* parent,
+ DbusmenuMenuitem* child,
+ unsigned int position);
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_child_append_func)(
DbusmenuMenuitem* parent,
DbusmenuMenuitem* child);
+typedef bool (*dbusmenu_menuitem_child_delete_func)(
+ DbusmenuMenuitem* parent,
+ DbusmenuMenuitem* child);
+typedef GList* (*dbusmenu_menuitem_get_children_func)(
+ DbusmenuMenuitem* item);
typedef DbusmenuMenuitem* (*dbusmenu_menuitem_property_set_func)(
DbusmenuMenuitem* item,
const char* property,
@@ -65,9 +83,10 @@ namespace {
// DbusmenuMenuItem methods:
dbusmenu_menuitem_new_func menuitem_new = NULL;
-dbusmenu_menuitem_new_with_id_func menuitem_new_with_id = NULL;
-dbusmenu_menuitem_get_id_func menuitem_get_id = NULL;
+dbusmenu_menuitem_get_children_func menuitem_get_children = NULL;
+dbusmenu_menuitem_child_add_position_func menuitem_child_add_position = NULL;
dbusmenu_menuitem_child_append_func menuitem_child_append = NULL;
+dbusmenu_menuitem_child_delete_func menuitem_child_delete = NULL;
dbusmenu_menuitem_property_set_func menuitem_property_set = NULL;
dbusmenu_menuitem_property_set_variant_func menuitem_property_set_variant =
NULL;
@@ -90,10 +109,30 @@ const char kPropertyVisible[] = "visible";
const char kTypeCheckmark[] = "checkmark";
const char kTypeSeparator[] = "separator";
-// Constants used in menu definitions
+// Data set on GObjectgs.
+const char kTypeTag[] = "type-tag";
+const char kHistoryItem[] = "history-item";
+
+// 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 int kMaximumMenuWidthInChars = 50;
+
+// Constants used in menu definitions.
const int MENU_SEPARATOR =-1;
const int MENU_END = -2;
-const int MENU_DISABLED_LABEL = -3;
+const int MENU_DISABLED_ID = -3;
+
+// These tag values are used to refer to menu itesm.
+const int TAG_NORMAL = 0;
+const int TAG_MOST_VISITED = 1;
+const int TAG_RECENTLY_CLOSED = 2;
+const int TAG_MOST_VISITED_HEADER = 3;
+const int TAG_RECENTLY_CLOSED_HEADER = 4;
GlobalMenuBarCommand file_menu[] = {
{ IDS_NEW_TAB, IDC_NEW_TAB },
@@ -136,7 +175,6 @@ GlobalMenuBarCommand edit_menu[] = {
{ MENU_END, MENU_END }
};
-
GlobalMenuBarCommand view_menu[] = {
{ IDS_SHOW_BOOKMARK_BAR, IDC_SHOW_BOOKMARK_BAR },
@@ -155,7 +193,25 @@ GlobalMenuBarCommand view_menu[] = {
{ MENU_END, MENU_END }
};
-// TODO(erg): History menu.
+GlobalMenuBarCommand history_menu[] = {
+ { IDS_HISTORY_HOME_LINUX, IDC_HOME },
+ { IDS_HISTORY_BACK_LINUX, IDC_BACK },
+ { IDS_HISTORY_FORWARD_LINUX, IDC_FORWARD },
+
+ { MENU_SEPARATOR, MENU_SEPARATOR },
+
+ { IDS_HISTORY_VISITED_LINUX, MENU_DISABLED_ID, TAG_MOST_VISITED_HEADER },
+
+ { MENU_SEPARATOR, MENU_SEPARATOR },
+
+ { IDS_HISTORY_CLOSED_LINUX, MENU_DISABLED_ID, TAG_RECENTLY_CLOSED_HEADER },
+
+ { MENU_SEPARATOR, MENU_SEPARATOR },
+
+ { IDS_SHOWFULLHISTORY_LINK, IDC_SHOW_HISTORY },
+
+ { MENU_END, MENU_END }
+};
GlobalMenuBarCommand tools_menu[] = {
{ IDS_SHOW_DOWNLOADS, IDC_SHOW_DOWNLOADS },
@@ -182,7 +238,6 @@ GlobalMenuBarCommand help_menu[] = {
{ MENU_END, MENU_END }
};
-
void EnsureMethodsLoaded() {
static bool attempted_load = false;
if (attempted_load)
@@ -196,12 +251,15 @@ void EnsureMethodsLoaded() {
// DbusmenuMenuItem methods.
menuitem_new = reinterpret_cast<dbusmenu_menuitem_new_func>(
dlsym(dbusmenu_lib, "dbusmenu_menuitem_new"));
- menuitem_new_with_id = reinterpret_cast<dbusmenu_menuitem_new_with_id_func>(
- dlsym(dbusmenu_lib, "dbusmenu_menuitem_new_with_id"));
- menuitem_get_id = reinterpret_cast<dbusmenu_menuitem_get_id_func>(
- dlsym(dbusmenu_lib, "dbusmenu_menuitem_get_id"));
+ menuitem_child_add_position =
+ reinterpret_cast<dbusmenu_menuitem_child_add_position_func>(
+ dlsym(dbusmenu_lib, "dbusmenu_menuitem_child_add_position"));
menuitem_child_append = reinterpret_cast<dbusmenu_menuitem_child_append_func>(
dlsym(dbusmenu_lib, "dbusmenu_menuitem_child_append"));
+ menuitem_child_delete = reinterpret_cast<dbusmenu_menuitem_child_delete_func>(
+ dlsym(dbusmenu_lib, "dbusmenu_menuitem_child_delete"));
+ menuitem_get_children = reinterpret_cast<dbusmenu_menuitem_get_children_func>(
+ dlsym(dbusmenu_lib, "dbusmenu_menuitem_get_children"));
menuitem_property_set = reinterpret_cast<dbusmenu_menuitem_property_set_func>(
dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set"));
menuitem_property_set_variant =
@@ -223,13 +281,43 @@ void EnsureMethodsLoaded() {
} // namespace
+struct GlobalMenuBarX11::HistoryItem {
+ HistoryItem() : session_id(0) {}
+
+ // The title for the menu item.
+ string16 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 non-0 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 0.
+ SessionID::id_type session_id;
+
+ // If the HistoryItem is a window, this will be the vector of tabs. Note
+ // that this is a list of weak references. The |menu_item_map_| 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;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HistoryItem);
+};
+
GlobalMenuBarX11::GlobalMenuBarX11(BrowserView* browser_view,
BrowserDesktopRootWindowHostX11* host)
: browser_(browser_view->browser()),
+ profile_(browser_->profile()),
browser_view_(browser_view),
host_(host),
server_(NULL),
- root_item_(NULL) {
+ root_item_(NULL),
+ history_menu_(NULL),
+ top_sites_(NULL),
+ tab_restore_service_(NULL),
+ weak_ptr_factory_(this) {
EnsureMethodsLoaded();
if (server_new)
@@ -239,6 +327,10 @@ GlobalMenuBarX11::GlobalMenuBarX11(BrowserView* browser_view,
GlobalMenuBarX11::~GlobalMenuBarX11() {
if (server_) {
Disable();
+
+ if (tab_restore_service_)
+ tab_restore_service_->RemoveObserver(this);
+
g_object_unref(server_);
host_->RemoveObserver(this);
}
@@ -249,6 +341,26 @@ std::string GlobalMenuBarX11::GetPathForWindow(unsigned long xid) {
return base::StringPrintf("/com/canonical/menu/%lX", xid);
}
+DbusmenuMenuitem* GlobalMenuBarX11::BuildSeparator() {
+ DbusmenuMenuitem* item = menuitem_new();
+ menuitem_property_set(item, kPropertyType, kTypeSeparator);
+ menuitem_property_set_bool(item, kPropertyVisible, true);
+ return item;
+}
+
+DbusmenuMenuitem* GlobalMenuBarX11::BuildMenuItem(
+ const std::string& label,
+ int tag_id) {
+ DbusmenuMenuitem* item = menuitem_new();
+ menuitem_property_set(item, kPropertyLabel, label.c_str());
+ menuitem_property_set_bool(item, kPropertyVisible, true);
+
+ if (tag_id)
+ g_object_set_data(G_OBJECT(item), kTypeTag, GINT_TO_POINTER(tag_id));
+
+ return item;
+}
+
void GlobalMenuBarX11::InitServer(unsigned long xid) {
std::string path = GetPathForWindow(xid);
server_ = server_new(path.c_str());
@@ -257,13 +369,20 @@ void GlobalMenuBarX11::InitServer(unsigned long xid) {
menuitem_property_set(root_item_, kPropertyLabel, "Root");
menuitem_property_set_bool(root_item_, kPropertyVisible, true);
- BuildMenuFrom(root_item_, IDS_FILE_MENU_LINUX, &id_to_menu_item_, file_menu);
- BuildMenuFrom(root_item_, IDS_EDIT_MENU_LINUX, &id_to_menu_item_, edit_menu);
- BuildMenuFrom(root_item_, IDS_VIEW_MENU_LINUX, &id_to_menu_item_, view_menu);
- // TODO(erg): History menu.
- BuildMenuFrom(root_item_, IDS_TOOLS_MENU_LINUX, &id_to_menu_item_,
- tools_menu);
- BuildMenuFrom(root_item_, IDS_HELP_MENU_LINUX, &id_to_menu_item_, help_menu);
+ // First build static menu content.
+ BuildStaticMenu(root_item_, IDS_FILE_MENU_LINUX, file_menu);
+ BuildStaticMenu(root_item_, IDS_EDIT_MENU_LINUX, edit_menu);
+ BuildStaticMenu(root_item_, IDS_VIEW_MENU_LINUX, view_menu);
+ history_menu_ = BuildStaticMenu(
+ root_item_, IDS_HISTORY_MENU_LINUX, history_menu);
+ BuildStaticMenu(root_item_, IDS_TOOLS_MENU_LINUX, tools_menu);
+ BuildStaticMenu(root_item_, IDS_HELP_MENU_LINUX, help_menu);
+
+ // We have to connect to |history_menu_item|'s "activate" signal instead of
+ // |history_menu|'s "show" signal because we are not supposed to modify the
+ // menu during "show"
+ g_signal_connect(history_menu_, "about-to-show",
+ G_CALLBACK(OnHistoryMenuAboutToShowThunk), this);
for (CommandIDMenuItemMap::const_iterator it = id_to_menu_item_.begin();
it != id_to_menu_item_.end(); ++it) {
@@ -284,6 +403,16 @@ void GlobalMenuBarX11::InitServer(unsigned long xid) {
base::Unretained(this)));
OnBookmarkBarVisibilityChanged();
+ top_sites_ = profile_->GetTopSites();
+ if (top_sites_) {
+ GetTopSitesData();
+
+ // Register for notification when TopSites changes so that we can update
+ // ourself.
+ registrar_.Add(this, chrome::NOTIFICATION_TOP_SITES_CHANGED,
+ content::Source<history::TopSites>(top_sites_));
+ }
+
server_set_root(server_, root_item_);
}
@@ -297,10 +426,9 @@ void GlobalMenuBarX11::Disable() {
pref_change_registrar_.RemoveAll();
}
-void GlobalMenuBarX11::BuildMenuFrom(
+DbusmenuMenuitem* GlobalMenuBarX11::BuildStaticMenu(
DbusmenuMenuitem* parent,
int menu_str_id,
- std::map<int, DbusmenuMenuitem*>* id_to_menu_item,
GlobalMenuBarCommand* commands) {
DbusmenuMenuitem* top = menuitem_new();
menuitem_property_set(
@@ -310,48 +438,37 @@ void GlobalMenuBarX11::BuildMenuFrom(
menuitem_property_set_bool(top, kPropertyVisible, true);
for (int i = 0; commands[i].str_id != MENU_END; ++i) {
- DbusmenuMenuitem* menu_item = BuildMenuItem(
- commands[i].str_id, commands[i].command, commands[i].tag,
- id_to_menu_item);
- menuitem_child_append(top, menu_item);
- }
-
- menuitem_child_append(parent, top);
-}
-
-DbusmenuMenuitem* GlobalMenuBarX11::BuildMenuItem(
- int string_id,
- int command_id,
- int tag_id,
- std::map<int, DbusmenuMenuitem*>* id_to_menu_item) {
- DbusmenuMenuitem* item = menuitem_new();
-
- if (string_id == MENU_SEPARATOR) {
- menuitem_property_set(item, kPropertyType, kTypeSeparator);
- } else {
- std::string label = ui::ConvertAcceleratorsFromWindowsStyle(
- l10n_util::GetStringUTF8(string_id));
- menuitem_property_set(item, kPropertyLabel, label.c_str());
-
- if (command_id == IDC_SHOW_BOOKMARK_BAR)
- menuitem_property_set(item, kPropertyToggleType, kTypeCheckmark);
-
- if (tag_id)
- g_object_set_data(G_OBJECT(item), "type-tag", GINT_TO_POINTER(tag_id));
-
- if (command_id == MENU_DISABLED_LABEL) {
- menuitem_property_set_bool(item, kPropertyEnabled, false);
+ DbusmenuMenuitem* menu_item = NULL;
+ int command_id = commands[i].command;
+ if (commands[i].str_id == MENU_SEPARATOR) {
+ menu_item = BuildSeparator();
} else {
- id_to_menu_item->insert(std::make_pair(command_id, item));
- g_object_set_data(G_OBJECT(item), "command-id",
- GINT_TO_POINTER(command_id));
- g_signal_connect(item, "item-activated",
- G_CALLBACK(OnItemActivatedThunk), this);
+ std::string label = ui::ConvertAcceleratorsFromWindowsStyle(
+ l10n_util::GetStringUTF8(commands[i].str_id));
+
+ menu_item = BuildMenuItem(label, commands[i].tag);
+
+ if (command_id == MENU_DISABLED_ID) {
+ menuitem_property_set_bool(menu_item, kPropertyEnabled, false);
+ } else {
+ if (command_id == IDC_SHOW_BOOKMARK_BAR)
+ menuitem_property_set(menu_item, kPropertyToggleType, kTypeCheckmark);
+
+ id_to_menu_item_.insert(std::make_pair(command_id, menu_item));
+ g_object_set_data(G_OBJECT(menu_item), "command-id",
+ GINT_TO_POINTER(command_id));
+ g_signal_connect(menu_item, "item-activated",
+ G_CALLBACK(OnItemActivatedThunk), this);
+ }
}
+
+ menuitem_child_append(top, menu_item);
+ g_object_unref(menu_item);
sadrul 2013/08/09 20:31:34 Ah, this is interesting. I wonder if BuildSeperato
}
- menuitem_property_set_bool(item, kPropertyVisible, true);
- return item;
+ menuitem_child_append(parent, top);
+ g_object_unref(top);
+ return top;
}
void GlobalMenuBarX11::RegisterAccelerator(DbusmenuMenuitem* item,
@@ -384,6 +501,70 @@ void GlobalMenuBarX11::RegisterAccelerator(DbusmenuMenuitem* item,
menuitem_property_set_variant(item, kPropertyShortcut, outside_array);
}
+GlobalMenuBarX11::HistoryItem* GlobalMenuBarX11::HistoryItemForTab(
+ const TabRestoreService::Tab& entry) {
+ const sessions::SerializedNavigationEntry& current_navigation =
+ entry.navigations.at(entry.current_navigation_index);
+ HistoryItem* item = new HistoryItem();
+ item->title = current_navigation.title();
+ item->url = current_navigation.virtual_url();
+ item->session_id = entry.id;
+
+ return item;
+}
+
+void GlobalMenuBarX11::AddHistoryItemToMenu(HistoryItem* item,
+ DbusmenuMenuitem* menu,
+ int tag,
+ int index) {
+ string16 title = item->title;
+ std::string url_string = item->url.possibly_invalid_spec();
+
+ if (title.empty())
+ title = UTF8ToUTF16(url_string);
+ ui::ElideString(title, kMaximumMenuWidthInChars, &title);
+
+ DbusmenuMenuitem* menu_item = BuildMenuItem(UTF16ToUTF8(title), tag);
+ g_signal_connect(menu_item, "item-activated",
+ G_CALLBACK(OnHistoryItemActivatedThunk), this);
+
+ g_object_set_data_full(G_OBJECT(menu_item), kHistoryItem, item,
+ DeleteHistoryItem);
sadrul 2013/08/09 20:31:34 Is it possible to use base::DeletePointer? (althou
Elliot Glaysher 2013/08/09 20:45:32 At some point I have to put the reinterpret cast.
+ menuitem_child_add_position(menu, menu_item, index);
+ g_object_unref(menu_item);
+}
+
+void GlobalMenuBarX11::GetTopSitesData() {
+ DCHECK(top_sites_);
+
+ top_sites_->GetMostVisitedURLs(
+ base::Bind(&GlobalMenuBarX11::OnTopSitesReceived,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void GlobalMenuBarX11::OnTopSitesReceived(
+ const history::MostVisitedURLList& visited_list) {
+ ClearMenuSection(history_menu_, TAG_MOST_VISITED);
+
+ int index = GetIndexOfMenuItemWithTag(history_menu_,
+ TAG_MOST_VISITED_HEADER) + 1;
+
+ 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.
+
+ HistoryItem* item = new HistoryItem();
+ item->title = visited.title;
+ item->url = visited.url;
+
+ AddHistoryItemToMenu(item,
+ history_menu_,
+ TAG_MOST_VISITED,
+ index++);
+ }
+}
+
void GlobalMenuBarX11::OnBookmarkBarVisibilityChanged() {
CommandIDMenuItemMap::iterator it =
id_to_menu_item_.find(IDC_SHOW_BOOKMARK_BAR);
@@ -396,12 +577,152 @@ void GlobalMenuBarX11::OnBookmarkBarVisibilityChanged() {
}
}
+int GlobalMenuBarX11::GetIndexOfMenuItemWithTag(DbusmenuMenuitem* menu,
+ int tag_id) {
+ GList* childs = menuitem_get_children(menu);
+ int i = 0;
+ for (; childs != NULL; childs = childs->next, i++) {
+ int tag =
+ GPOINTER_TO_INT(g_object_get_data(G_OBJECT(childs->data), kTypeTag));
+ if (tag == tag_id)
+ return i;
+ }
+
+ NOTREACHED();
+ return -1;
+}
+
+void GlobalMenuBarX11::ClearMenuSection(DbusmenuMenuitem* menu, int tag_id) {
+ std::vector<DbusmenuMenuitem*> menuitems_to_delete;
+
+ GList* childs = menuitem_get_children(menu);
+ for (; childs != NULL; childs = childs->next) {
+ DbusmenuMenuitem* current_item = reinterpret_cast<DbusmenuMenuitem*>(
+ childs->data);
+ ClearMenuSection(current_item, tag_id);
+
+ int tag =
+ GPOINTER_TO_INT(g_object_get_data(G_OBJECT(childs->data), kTypeTag));
+ if (tag == tag_id)
+ menuitems_to_delete.push_back(current_item);
+ }
+
+ for (std::vector<DbusmenuMenuitem*>::const_iterator it =
+ menuitems_to_delete.begin(); it != menuitems_to_delete.end(); ++it) {
+ menuitem_child_delete(menu, *it);
+ }
+}
+
+// static
+void GlobalMenuBarX11::DeleteHistoryItem(void* void_item) {
+ HistoryItem* item =
+ reinterpret_cast<GlobalMenuBarX11::HistoryItem*>(void_item);
+ delete item;
+}
+
void GlobalMenuBarX11::EnabledStateChangedForCommand(int id, bool enabled) {
CommandIDMenuItemMap::iterator it = id_to_menu_item_.find(id);
if (it != id_to_menu_item_.end())
menuitem_property_set_bool(it->second, kPropertyEnabled, enabled);
}
+void GlobalMenuBarX11::Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ if (type == chrome::NOTIFICATION_TOP_SITES_CHANGED) {
+ GetTopSitesData();
+ } else {
+ NOTREACHED();
+ }
+}
+
+void GlobalMenuBarX11::TabRestoreServiceChanged(TabRestoreService* service) {
+ const TabRestoreService::Entries& entries = service->entries();
+
+ ClearMenuSection(history_menu_, TAG_RECENTLY_CLOSED);
+
+ // We'll get the index the "Recently Closed" header. (This can vary depending
+ // on the number of "Most Visited" items.
+ int index = GetIndexOfMenuItemWithTag(history_menu_,
+ TAG_RECENTLY_CLOSED_HEADER) + 1;
+
+ unsigned int added_count = 0;
+ for (TabRestoreService::Entries::const_iterator it = entries.begin();
+ it != entries.end() && added_count < kRecentlyClosedCount; ++it) {
+ TabRestoreService::Entry* entry = *it;
+
+ if (entry->type == TabRestoreService::WINDOW) {
+ TabRestoreService::Window* entry_win =
+ static_cast<TabRestoreService::Window*>(entry);
+ std::vector<TabRestoreService::Tab>& tabs = entry_win->tabs;
+ if (tabs.empty())
+ continue;
+
+ // Create the item for the parent/window.
+ HistoryItem* item = new HistoryItem();
+ item->session_id = entry_win->id;
+
+ std::string title = item->tabs.size() == 1 ?
+ l10n_util::GetStringUTF8(
+ IDS_NEW_TAB_RECENTLY_CLOSED_WINDOW_SINGLE) :
+ l10n_util::GetStringFUTF8(
+ IDS_NEW_TAB_RECENTLY_CLOSED_WINDOW_MULTIPLE,
+ base::IntToString16(item->tabs.size()));
+ DbusmenuMenuitem* parent_item = BuildMenuItem(
+ title, TAG_RECENTLY_CLOSED);
+ menuitem_child_add_position(history_menu_, parent_item, index++);
+ g_object_unref(parent_item);
+
+ // The mac version of this code allows the user to click on the parent
+ // menu item to have the same effect as clicking the restore window
+ // submenu item. GTK+ helpfully activates a menu item when it shows a
+ // submenu so toss that feature out.
+ DbusmenuMenuitem* restore_item = BuildMenuItem(
+ l10n_util::GetStringUTF8(
+ IDS_HISTORY_CLOSED_RESTORE_WINDOW_LINUX).c_str(),
+ TAG_RECENTLY_CLOSED);
+ g_signal_connect(restore_item, "item-activated",
+ G_CALLBACK(OnHistoryItemActivatedThunk), this);
+ g_object_set_data_full(G_OBJECT(restore_item), kHistoryItem, item,
+ DeleteHistoryItem);
+ menuitem_child_append(parent_item, restore_item);
+ g_object_unref(restore_item);
+
+ DbusmenuMenuitem* separator = BuildSeparator();
+ menuitem_child_append(parent_item, separator);
+ g_object_unref(separator);
+
+ // Loop over the window's tabs and add them to the submenu.
+ int subindex = 2;
+ std::vector<TabRestoreService::Tab>::const_iterator iter;
+ for (iter = tabs.begin(); iter != tabs.end(); ++iter) {
+ TabRestoreService::Tab tab = *iter;
+ HistoryItem* tab_item = HistoryItemForTab(tab);
+ item->tabs.push_back(tab_item);
+ AddHistoryItemToMenu(tab_item,
+ parent_item,
+ TAG_RECENTLY_CLOSED,
+ subindex++);
+ }
+
+ ++added_count;
+ } else if (entry->type == TabRestoreService::TAB) {
+ TabRestoreService::Tab* tab = static_cast<TabRestoreService::Tab*>(entry);
+ HistoryItem* item = HistoryItemForTab(*tab);
+ AddHistoryItemToMenu(item,
+ history_menu_,
+ TAG_RECENTLY_CLOSED,
+ index++);
+ ++added_count;
+ }
+ }
+}
+
+void GlobalMenuBarX11::TabRestoreServiceDestroyed(
+ TabRestoreService* service) {
+ tab_restore_service_ = NULL;
+}
+
void GlobalMenuBarX11::OnWindowMapped(unsigned long xid) {
if (!server_)
InitServer(xid);
@@ -418,3 +739,44 @@ void GlobalMenuBarX11::OnItemActivated(DbusmenuMenuitem* item,
int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(item), "command-id"));
chrome::ExecuteCommand(browser_, id);
}
+
+void GlobalMenuBarX11::OnHistoryItemActivated(DbusmenuMenuitem* sender,
+ unsigned int timestamp) {
+ // Note: We don't have access to the event modifiers used to click the menu
+ // item since that happens in a different process.
+ HistoryItem* item = reinterpret_cast<HistoryItem*>(
+ g_object_get_data(G_OBJECT(sender), kHistoryItem));
+
+ // If this item can be restored using TabRestoreService, do so. Otherwise,
+ // just load the URL.
+ TabRestoreService* service =
+ TabRestoreServiceFactory::GetForProfile(profile_);
+ if (item->session_id && service) {
+ service->RestoreEntryById(browser_->tab_restore_service_delegate(),
+ item->session_id, browser_->host_desktop_type(),
+ UNKNOWN);
+ } else {
+ DCHECK(item->url.is_valid());
+ browser_->OpenURL(content::OpenURLParams(
+ item->url,
+ content::Referrer(),
+ NEW_FOREGROUND_TAB,
+ content::PAGE_TRANSITION_AUTO_BOOKMARK,
+ false));
+ }
+}
+
+void GlobalMenuBarX11::OnHistoryMenuAboutToShow(DbusmenuMenuitem* item) {
+ if (!tab_restore_service_) {
+ tab_restore_service_ = TabRestoreServiceFactory::GetForProfile(profile_);
+ if (tab_restore_service_) {
+ 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_);
+ }
+ }
+}
« no previous file with comments | « chrome/browser/ui/views/frame/global_menu_bar_x11.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698