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

Unified Diff: chrome/browser/ui/gtk/global_menu_bar.cc

Issue 6840068: GTK: Add Recently Closed tabs to the History menu in the global menu bar. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Add bookmark menu stub for string freeze reasons Created 9 years, 8 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
Index: chrome/browser/ui/gtk/global_menu_bar.cc
diff --git a/chrome/browser/ui/gtk/global_menu_bar.cc b/chrome/browser/ui/gtk/global_menu_bar.cc
index 6442e41dce300efbc8a7f7549a03538f1812bba8..cd2c924953eaae2ecbfabb9c647307589bcd2068 100644
--- a/chrome/browser/ui/gtk/global_menu_bar.cc
+++ b/chrome/browser/ui/gtk/global_menu_bar.cc
@@ -6,26 +6,63 @@
#include <gtk/gtk.h>
+#include "base/utf_string_conversions.h"
+#include "base/stl_util-inl.h"
+#include "base/string_number_conversions.h"
#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/favicon_service.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_tab_restore_service_delegate.h"
#include "chrome/browser/ui/gtk/accelerators_gtk.h"
+#include "chrome/browser/ui/gtk/gtk_util.h"
+#include "chrome/browser/ui/gtk/gtk_theme_service.h"
+#include "chrome/browser/ui/gtk/owned_widget_gtk.h"
#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
#include "content/common/notification_service.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/text/text_elider.h"
+#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/gtk_util.h"
struct GlobalMenuBarCommand {
int str_id;
int command;
+ int tag;
+};
+
+struct GlobalMenuBar::ClearMenuClosure {
+ GtkWidget* container;
+ GlobalMenuBar* menu_bar;
+ int tag;
+};
+
+struct GlobalMenuBar::GetIndexClosure {
+ bool found;
+ int current_index;
+ int tag;
};
namespace {
const int MENU_SEPARATOR =-1;
const int MENU_END = -2;
+const int MENU_DISABLED_LABEL = -3;
+
+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;
+
+// The number of recently closed items to get.
+const unsigned int kRecentlyClosedCount = 10;
+
+// Menus more than this many chars long will get trimmed.
+const int kMaximumMenuWidthInChars = 50;
GlobalMenuBarCommand file_menu[] = {
{ IDS_NEW_TAB, IDC_NEW_TAB },
@@ -99,6 +136,45 @@ GlobalMenuBarCommand view_menu[] = {
{ MENU_END, MENU_END }
};
+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_LABEL, TAG_MOST_VISITED_HEADER },
+
+ { MENU_SEPARATOR, MENU_SEPARATOR },
+
+ { IDS_HISTORY_CLOSED_LINUX, MENU_DISABLED_LABEL, TAG_RECENTLY_CLOSED_HEADER },
+
+ { MENU_SEPARATOR, MENU_SEPARATOR },
+
+ { IDS_SHOWFULLHISTORY_LINK, IDC_SHOW_HISTORY },
+
+ { MENU_END, MENU_END }
+};
+
+GlobalMenuBarCommand bookmark_menu[] = {
+ { IDS_BOOKMARK_MANAGER, IDC_SHOW_BOOKMARK_MANAGER },
+ { IDS_BOOKMARK_CURRENT_PAGE_LINUX, IDC_BOOKMARK_PAGE },
+ { IDS_BOOKMARK_ALL_TABS_LINUX, IDC_BOOKMARK_ALL_TABS },
+
+ { MENU_SEPARATOR, MENU_SEPARATOR },
+ // TODO(erg): Real implementation of bookmark bar bookmarks!
+ { MENU_SEPARATOR, MENU_SEPARATOR },
+
+ { IDS_BOOMARK_BAR_OPEN_ALL, IDC_BOOKMARK_BAR_OPEN_ALL },
+ { IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW, IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW },
+ { IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO, IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO },
+
+ { MENU_SEPARATOR, MENU_SEPARATOR },
+ // TODO(erg): "Other bookmarks" bookmarks
+
+ { MENU_END, MENU_END }
+};
+
GlobalMenuBarCommand tools_menu[] = {
{ IDS_SHOW_DOWNLOADS, IDC_SHOW_DOWNLOADS },
{ IDS_SHOW_HISTORY, IDC_SHOW_HISTORY },
@@ -126,28 +202,77 @@ GlobalMenuBarCommand help_menu[] = {
} // namespace
-GlobalMenuBar::GlobalMenuBar(Browser* browser,
- BrowserWindowGtk* window)
+class GlobalMenuBar::HistoryItem {
+ public:
+ HistoryItem()
+ : icon_requested(false),
+ menu_item(NULL),
+ 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;
+
+ // If the icon is being requested from the FaviconService, |icon_requested|
+ // will be true and |icon_handle| will be non-NULL. If this is false, then
+ // |icon_handle| will be NULL.
+ bool icon_requested;
+ // The Handle given to us by the FaviconService for the icon fetch request.
+ FaviconService::Handle icon_handle;
+
+ // The icon as a GtkImage for inclusion in a GtkImageMenuItem.
+ OwnedWidgetGtk icon_image;
+
+ // A pointer to the menu_item. This is a weak reference in the GTK+ version
+ // because the GtkMenu must sink the reference.
+ GtkWidget* menu_item;
+
+ // 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);
+};
+
+
Evan Stade 2011/04/15 19:00:41 extra line
+GlobalMenuBar::GlobalMenuBar(Browser* browser)
: browser_(browser),
- browser_window_(window),
+ profile_(browser_->profile()),
+ default_favicon_(NULL),
menu_bar_(gtk_menu_bar_new()),
dummy_accel_group_(gtk_accel_group_new()),
- block_activation_(false) {
+ block_activation_(false),
+ history_menu_(NULL),
+ tab_restore_service_(NULL) {
// The global menu bar should never actually be shown in the app; it should
// instead remain in our widget hierarchy simply to be noticed by third party
// components.
- gtk_widget_set_no_show_all(menu_bar_, TRUE);
+ gtk_widget_set_no_show_all(menu_bar_.get(), TRUE);
// Set a nice name so it shows up in gtkparasite and others.
- gtk_widget_set_name(menu_bar_, "chrome-hidden-global-menubar");
+ gtk_widget_set_name(menu_bar_.get(), "chrome-hidden-global-menubar");
BuildGtkMenuFrom(IDS_FILE_MENU_LINUX, &id_to_menu_item_, file_menu);
BuildGtkMenuFrom(IDS_EDIT_MENU_LINUX, &id_to_menu_item_, edit_menu);
BuildGtkMenuFrom(IDS_VIEW_MENU_LINUX, &id_to_menu_item_, view_menu);
+ history_menu_ = BuildGtkMenuFrom(IDS_HISTORY_MENU_LINUX, &id_to_menu_item_,
+ history_menu);
+ BuildGtkMenuFrom(IDS_BOOKMARKS_MENU_LINUX, &id_to_menu_item_, bookmark_menu);
BuildGtkMenuFrom(IDS_TOOLS_MENU_LINUX, &id_to_menu_item_, tools_menu);
BuildGtkMenuFrom(IDS_HELP_MENU_LINUX, &id_to_menu_item_, help_menu);
- for (IDMenuItemMap::const_iterator it = id_to_menu_item_.begin();
+ for (CommandIDMenuItemMap::const_iterator it = id_to_menu_item_.begin();
it != id_to_menu_item_.end(); ++it) {
// Get the starting enabled state.
gtk_widget_set_sensitive(
@@ -170,6 +295,24 @@ GlobalMenuBar::GlobalMenuBar(Browser* browser,
browser_->command_updater()->AddCommandObserver(it->first, this);
}
+ default_favicon_ = GtkThemeService::GetDefaultFavicon(true);
+
+ if (profile_) {
+ tab_restore_service_ = profile_->GetTabRestoreService();
+ 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_);
+ }
+
+ registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
+ Source<Profile>(profile_));
+ }
+
// Listen for bookmark bar visibility changes and set the initial state.
registrar_.Add(this, NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED,
NotificationService::AllSources());
@@ -179,56 +322,265 @@ GlobalMenuBar::GlobalMenuBar(Browser* browser,
}
GlobalMenuBar::~GlobalMenuBar() {
- for (IDMenuItemMap::const_iterator it = id_to_menu_item_.begin();
+ for (CommandIDMenuItemMap::const_iterator it = id_to_menu_item_.begin();
it != id_to_menu_item_.end(); ++it) {
browser_->command_updater()->RemoveCommandObserver(it->first, this);
}
+ if (tab_restore_service_)
+ tab_restore_service_->RemoveObserver(this);
+
+ STLDeleteContainerPairSecondPointers(menu_item_history_map_.begin(),
+ menu_item_history_map_.end());
+ menu_item_history_map_.clear();
+
g_object_unref(dummy_accel_group_);
}
-void GlobalMenuBar::BuildGtkMenuFrom(int menu_str_id,
- std::map<int, GtkWidget*>* id_to_menu_item,
- GlobalMenuBarCommand* commands) {
+GtkWidget* GlobalMenuBar::BuildGtkMenuFrom(
+ int menu_str_id,
+ std::map<int, GtkWidget*>* id_to_menu_item,
+ GlobalMenuBarCommand* commands) {
GtkWidget* menu = gtk_menu_new();
for (int i = 0; commands[i].str_id != MENU_END; ++i) {
- GtkWidget* menu_item = NULL;
- if (commands[i].str_id == MENU_SEPARATOR) {
- menu_item = gtk_separator_menu_item_new();
- } else {
- int command_id = commands[i].command;
- std::string label =
- gfx::ConvertAcceleratorsFromWindowsStyle(
- l10n_util::GetStringUTF8(commands[i].str_id));
+ GtkWidget* menu_item = BuildMenuItem(
+ commands[i].str_id, commands[i].command, commands[i].tag,
+ id_to_menu_item, menu);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
+ }
+
+ gtk_widget_show(menu);
+
+ GtkWidget* menu_item = gtk_menu_item_new_with_mnemonic(
+ gfx::ConvertAcceleratorsFromWindowsStyle(
+ l10n_util::GetStringUTF8(menu_str_id)).c_str());
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), menu);
+ gtk_widget_show(menu_item);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar_.get()), menu_item);
- if (command_id == IDC_SHOW_BOOKMARK_BAR)
- menu_item = gtk_check_menu_item_new_with_mnemonic(label.c_str());
- else
- menu_item = gtk_menu_item_new_with_mnemonic(label.c_str());
+ return menu;
+}
+GtkWidget* GlobalMenuBar::BuildMenuItem(
+ int string_id,
+ int command_id,
+ int tag_id,
+ std::map<int, GtkWidget*>* id_to_menu_item,
+ GtkWidget* menu_to_add_to) {
+ GtkWidget* menu_item = NULL;
+ if (string_id == MENU_SEPARATOR) {
+ menu_item = gtk_separator_menu_item_new();
+ } else {
+ std::string label =
+ gfx::ConvertAcceleratorsFromWindowsStyle(
+ l10n_util::GetStringUTF8(string_id));
+
+ if (command_id == IDC_SHOW_BOOKMARK_BAR)
+ menu_item = gtk_check_menu_item_new_with_mnemonic(label.c_str());
+ else
+ menu_item = gtk_menu_item_new_with_mnemonic(label.c_str());
+
+ if (tag_id) {
+ g_object_set_data(G_OBJECT(menu_item), "type-tag",
+ GINT_TO_POINTER(tag_id));
+ }
+
+ if (command_id == MENU_DISABLED_LABEL) {
+ gtk_widget_set_sensitive(menu_item, FALSE);
+ } else {
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, "activate",
G_CALLBACK(OnItemActivatedThunk), this);
}
- gtk_widget_show(menu_item);
- gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
}
+ gtk_widget_show(menu_item);
+ return menu_item;
+}
- gtk_widget_show(menu);
+GlobalMenuBar::HistoryItem* GlobalMenuBar::HistoryItemForMenuItem(
+ GtkWidget* menu_item) {
+ MenuItemToHistoryMap::iterator it = menu_item_history_map_.find(menu_item);
+ if (it != menu_item_history_map_.end()) {
Evan Stade 2011/04/15 19:00:41 nit: return it != menu_item_history_map_.end() ? i
+ return it->second;
+ }
+ return NULL;
+}
- GtkWidget* menu_item = gtk_menu_item_new_with_mnemonic(
- gfx::ConvertAcceleratorsFromWindowsStyle(
- l10n_util::GetStringUTF8(menu_str_id)).c_str());
- gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), menu);
+GlobalMenuBar::HistoryItem* GlobalMenuBar::HistoryItemForTab(
+ const TabRestoreService::Tab& entry) {
+ if (entry.navigations.empty())
+ return NULL;
+
+ const TabNavigation& current_navigation =
+ entry.navigations.at(entry.current_navigation_index);
+ if (current_navigation.virtual_url() == GURL(chrome::kChromeUINewTabURL))
+ return NULL;
+
+ HistoryItem* item = new HistoryItem();
+ item->title = current_navigation.title();
+ item->url = current_navigation.virtual_url();
+ item->session_id = entry.id;
+
+ // Tab navigations don't come with icons, so we always have to request them.
+ GetFaviconForHistoryItem(item);
+
+ return item;
+
+}
+
+GtkWidget* GlobalMenuBar::AddHistoryItemToMenu(HistoryItem* item,
+ GtkWidget* 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);
+
+ GtkWidget* menu_item = gtk_image_menu_item_new_with_label(
+ UTF16ToUTF8(title).c_str());
+ gtk_image_menu_item_set_always_show_image(GTK_IMAGE_MENU_ITEM(menu_item),
+ TRUE);
+ item->menu_item = menu_item;
gtk_widget_show(menu_item);
+ g_object_set_data(G_OBJECT(menu_item), "type-tag", GINT_TO_POINTER(tag));
+ g_signal_connect(menu_item, "activate",
+ G_CALLBACK(OnRecentlyClosedItemActivatedThunk), this);
+ if (item->icon_image.get()) {
+ gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
+ item->icon_image.get());
+ } else if (!item->tabs.size()) {
+ gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
+ gtk_image_new_from_pixbuf(default_favicon_));
+ }
+
+ std::string tooltip = gtk_util::BuildTooltipTitleFor(item->title, item->url);
+ gtk_widget_set_tooltip_markup(menu_item, tooltip.c_str());
+
+ menu_item_history_map_.insert(std::make_pair(menu_item, item));
+ gtk_menu_shell_insert(GTK_MENU_SHELL(menu), menu_item, index);
+
+ return menu_item;
+}
+
+void GlobalMenuBar::GetFaviconForHistoryItem(HistoryItem* item) {
+ FaviconService* service =
+ profile_->GetFaviconService(Profile::EXPLICIT_ACCESS);
+ FaviconService::Handle handle = service->GetFaviconForURL(
+ item->url,
+ history::FAVICON,
+ &favicon_consumer_,
+ NewCallback(this, &GlobalMenuBar::GotFaviconData));
+ favicon_consumer_.SetClientData(service, handle, item);
+ item->icon_handle = handle;
+ item->icon_requested = true;
+}
- gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar_), menu_item);
+void GlobalMenuBar::GotFaviconData(FaviconService::Handle handle,
+ history::FaviconData favicon) {
+ HistoryItem* item =
+ favicon_consumer_.GetClientData(
+ profile_->GetFaviconService(Profile::EXPLICIT_ACCESS), handle);
+ DCHECK(item);
+ item->icon_requested = false;
+ item->icon_handle = NULL;
+
+ SkBitmap icon;
+ if (favicon.is_valid() &&
+ gfx::PNGCodec::Decode(favicon.image_data->front(),
+ favicon.image_data->size(), &icon)) {
+ GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&icon);
+ if (pixbuf) {
+ item->icon_image.Own(gtk_image_new_from_pixbuf(pixbuf));
+ g_object_unref(pixbuf);
+
+ if (item->menu_item) {
+ gtk_image_menu_item_set_image(
+ GTK_IMAGE_MENU_ITEM(item->menu_item),
+ item->icon_image.get());
+ }
+ }
+ }
+}
+
+void GlobalMenuBar::CancelFaviconRequest(HistoryItem* item) {
+ DCHECK(item);
+ if (item->icon_requested) {
+ FaviconService* service =
+ profile_->GetFaviconService(Profile::EXPLICIT_ACCESS);
+ service->CancelRequest(item->icon_handle);
+ item->icon_requested = false;
+ item->icon_handle = NULL;
+ }
+}
+
+int GlobalMenuBar::GetIndexOfMenuItemWithTag(GtkWidget* menu, int tag_id) {
+ GetIndexClosure closure;
+ closure.found = false;
+ closure.current_index = 0;
+ closure.tag = tag_id;
+
+ gtk_container_foreach(
+ GTK_CONTAINER(menu),
+ reinterpret_cast<void (*)(GtkWidget*, void*)>(GetIndexCallback),
+ &closure);
+
+ return closure.current_index;
+}
+
+void GlobalMenuBar::ClearMenuSection(GtkWidget* menu, int tag) {
+ ClearMenuClosure closure;
+ closure.container = menu;
+ closure.menu_bar = this;
+ closure.tag = tag;
+
+ gtk_container_foreach(
+ GTK_CONTAINER(menu),
+ reinterpret_cast<void (*)(GtkWidget*, void*)>(ClearMenuCallback),
+ &closure);
+}
+
+// static
+void GlobalMenuBar::GetIndexCallback(GtkWidget* menu_item,
+ GetIndexClosure* closure) {
+ int tag = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menu_item), "type-tag"));
+ if (tag == closure->tag)
+ closure->found = true;
+
+ if (!closure->found)
+ closure->current_index++;
+}
+
+// static
+void GlobalMenuBar::ClearMenuCallback(GtkWidget* menu_item,
+ ClearMenuClosure* closure) {
+ DCHECK_NE(closure->tag, 0);
+
+ int tag = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menu_item), "type-tag"));
+ if (closure->tag == tag) {
+ HistoryItem* item = closure->menu_bar->HistoryItemForMenuItem(menu_item);
+
+ if (item) {
+ closure->menu_bar->CancelFaviconRequest(item);
+ closure->menu_bar->menu_item_history_map_.erase(menu_item);
+ delete item;
+ }
+
+ GtkWidget* submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu_item));
+ if (submenu) {
Evan Stade 2011/04/15 19:00:41 nit: no curlies
+ closure->menu_bar->ClearMenuSection(submenu, closure->tag);
+ }
+
+ gtk_container_remove(GTK_CONTAINER(closure->container), menu_item);
+ }
}
void GlobalMenuBar::EnabledStateChangedForCommand(int id, bool enabled) {
- IDMenuItemMap::iterator it = id_to_menu_item_.find(id);
+ CommandIDMenuItemMap::iterator it = id_to_menu_item_.find(id);
if (it != id_to_menu_item_.end())
gtk_widget_set_sensitive(it->second, enabled);
}
@@ -236,19 +588,140 @@ void GlobalMenuBar::EnabledStateChangedForCommand(int id, bool enabled) {
void GlobalMenuBar::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
- DCHECK(type.value == NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED);
-
- IDMenuItemMap::iterator it = id_to_menu_item_.find(IDC_SHOW_BOOKMARK_BAR);
- if (it != id_to_menu_item_.end()) {
- PrefService* prefs = browser_->profile()->GetPrefs();
+ if (type.value == NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED) {
+ CommandIDMenuItemMap::iterator it =
+ id_to_menu_item_.find(IDC_SHOW_BOOKMARK_BAR);
+ if (it != id_to_menu_item_.end()) {
+ PrefService* prefs = browser_->profile()->GetPrefs();
+
+ block_activation_ = true;
+ gtk_check_menu_item_set_active(
+ GTK_CHECK_MENU_ITEM(it->second),
+ prefs->GetBoolean(prefs::kShowBookmarkBar));
+ block_activation_ = false;
+ }
+ } else if (type.value == NotificationType::BROWSER_THEME_CHANGED) {
+ // Keeping track of which menu items have the default icon is going an
+ // error-prone pain, so instead just store the new default favicon and
+ // we'll update on the next menu change event.
+ default_favicon_ = GtkThemeService::GetDefaultFavicon(true);
+ } else {
+ NOTREACHED();
+ }
+}
- block_activation_ = true;
- gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(it->second),
- prefs->GetBoolean(prefs::kShowBookmarkBar));
- block_activation_ = false;
+void GlobalMenuBar::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) {
Evan Stade 2011/04/15 19:00:41 instead of added_count can we track the size of hi
Elliot Glaysher 2011/04/15 20:29:03 We can in this patch, but we won't be able to once
+ TabRestoreService::Entry* entry = *it;
+
+ if (entry->type == TabRestoreService::WINDOW) {
+ TabRestoreService::Window* entry_win = (TabRestoreService::Window*)entry;
Evan Stade 2011/04/15 19:00:41 C++ style cast
+ std::vector<TabRestoreService::Tab>& tabs = entry_win->tabs;
+ if (!tabs.size())
Evan Stade 2011/04/15 19:00:41 empty()
+ continue;
+
+ // Create the item for the parent/window. Do not set the title yet
+ // because the actual number of items that are in the menu will not be
+ // known until things like the NTP are filtered out, which is done when
+ // the tab items are actually created.
+ HistoryItem* item = new HistoryItem();
+ item->session_id = entry_win->id;
+
+ GtkWidget* submenu = gtk_menu_new();
+
+ GtkWidget* restore_item = gtk_menu_item_new_with_label(
+ l10n_util::GetStringUTF8(
+ IDS_HISTORY_CLOSED_RESTORE_WINDOW_LINUX).c_str());
+ g_object_set_data(G_OBJECT(restore_item), "type-tag",
+ GINT_TO_POINTER(TAG_RECENTLY_CLOSED));
+ g_signal_connect(restore_item, "activate",
+ G_CALLBACK(OnRecentlyClosedItemActivatedThunk), this);
+ gtk_widget_show(restore_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.
+ menu_item_history_map_.insert(std::make_pair(restore_item, item));
+ gtk_menu_shell_append(GTK_MENU_SHELL(submenu), restore_item);
+
+ GtkWidget* separator = gtk_separator_menu_item_new();
+ gtk_widget_show(separator);
+ gtk_menu_shell_append(GTK_MENU_SHELL(submenu), separator);
+
+ // Loop over the window's tabs and add them to the submenu.
+ int subindex = 2;
+ int subadd_count = 0;
+ std::vector<TabRestoreService::Tab>::const_iterator it;
+ for (it = tabs.begin(); it != tabs.end(); ++it) {
+ TabRestoreService::Tab tab = *it;
+ HistoryItem* tab_item = HistoryItemForTab(tab);
+ if (tab_item) {
+ ++subadd_count;
+ item->tabs.push_back(tab_item);
+ AddHistoryItemToMenu(tab_item, submenu, TAG_RECENTLY_CLOSED,
+ subindex++);
+ }
+ }
+
+ // Sometimes it is possible for there to not be any subitems for a given
+ // window; if that is the case, do not add the entry to the main menu.
+ if (subadd_count) {
Evan Stade 2011/04/15 19:00:41 use subindex > 2 instead?
+ // Now that the number of tabs that has been added is known, set the
+ // title of the parent menu item.
+ 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()));
+
+ // Create the menu item parent. Unlike mac, it's can't be activated.
+ GtkWidget* parent_item = gtk_image_menu_item_new_with_label(
+ title.c_str());
+ gtk_widget_show(parent_item);
+ g_object_set_data(G_OBJECT(parent_item), "type-tag",
+ GINT_TO_POINTER(TAG_RECENTLY_CLOSED));
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(parent_item), submenu);
+
+ gtk_menu_shell_insert(GTK_MENU_SHELL(history_menu_), parent_item,
+ index++);
+ ++added_count;
+ } else {
+ // Clean up after this failed attempt to make a submenu.
+ menu_item_history_map_.erase(restore_item);
Evan Stade 2011/04/15 19:00:41 can we avoid adding it to the map in the first pla
+ g_object_ref_sink(submenu);
+ g_object_unref(submenu);
Evan Stade 2011/04/15 19:00:41 I think it would be a good idea to gtk_widget_dest
+ }
+ } else if (entry->type == TabRestoreService::TAB) {
+ TabRestoreService::Tab* tab =
+ static_cast<TabRestoreService::Tab*>(entry);
+ HistoryItem* item = HistoryItemForTab(*tab);
+ if (item) {
+ AddHistoryItemToMenu(item, history_menu_, TAG_RECENTLY_CLOSED, index++);
+ ++added_count;
+ }
+ }
}
}
+void GlobalMenuBar::TabRestoreServiceDestroyed(
+ TabRestoreService* service) {
+ // Intentionally left blank. We hold a weak reference to the service.
+}
+
void GlobalMenuBar::OnItemActivated(GtkWidget* sender) {
if (block_activation_)
return;
@@ -256,3 +729,21 @@ void GlobalMenuBar::OnItemActivated(GtkWidget* sender) {
int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(sender), "command-id"));
browser_->ExecuteCommandIfEnabled(id);
}
+
+void GlobalMenuBar::OnRecentlyClosedItemActivated(GtkWidget* sender) {
+ WindowOpenDisposition disposition =
+ gtk_util::DispositionForCurrentButtonPressEvent();
+ HistoryItem* item = HistoryItemForMenuItem(sender);
+
+ // If this item can be restored using TabRestoreService, do so. Otherwise,
+ // just load the URL.
+ TabRestoreService* service = browser_->profile()->GetTabRestoreService();
+ if (item->session_id && service) {
+ service->RestoreEntryById(browser_->tab_restore_service_delegate(),
+ item->session_id, false);
+ } else {
+ DCHECK(item->url.is_valid());
+ browser_->OpenURL(item->url, GURL(), disposition,
+ PageTransition::AUTO_BOOKMARK);
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698