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

Side by Side 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: Fix for the Hardy trybots 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/ui/gtk/global_menu_bar.h ('k') | chrome/browser/ui/gtk/gtk_util.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/gtk/global_menu_bar.h" 5 #include "chrome/browser/ui/gtk/global_menu_bar.h"
6 6
7 #include <gtk/gtk.h> 7 #include <gtk/gtk.h>
8 8
9 #include "base/utf_string_conversions.h"
10 #include "base/stl_util-inl.h"
11 #include "base/string_number_conversions.h"
9 #include "chrome/app/chrome_command_ids.h" 12 #include "chrome/app/chrome_command_ids.h"
13 #include "chrome/browser/favicon_service.h"
10 #include "chrome/browser/prefs/pref_service.h" 14 #include "chrome/browser/prefs/pref_service.h"
11 #include "chrome/browser/profiles/profile.h" 15 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/ui/browser.h" 16 #include "chrome/browser/ui/browser.h"
17 #include "chrome/browser/ui/browser_tab_restore_service_delegate.h"
13 #include "chrome/browser/ui/gtk/accelerators_gtk.h" 18 #include "chrome/browser/ui/gtk/accelerators_gtk.h"
19 #include "chrome/browser/ui/gtk/gtk_util.h"
20 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
21 #include "chrome/browser/ui/gtk/owned_widget_gtk.h"
14 #include "chrome/common/pref_names.h" 22 #include "chrome/common/pref_names.h"
23 #include "chrome/common/url_constants.h"
15 #include "content/common/notification_service.h" 24 #include "content/common/notification_service.h"
16 #include "grit/generated_resources.h" 25 #include "grit/generated_resources.h"
17 #include "ui/base/l10n/l10n_util.h" 26 #include "ui/base/l10n/l10n_util.h"
27 #include "ui/base/text/text_elider.h"
28 #include "ui/gfx/codec/png_codec.h"
18 #include "ui/gfx/gtk_util.h" 29 #include "ui/gfx/gtk_util.h"
19 30
20 struct GlobalMenuBarCommand { 31 struct GlobalMenuBarCommand {
21 int str_id; 32 int str_id;
22 int command; 33 int command;
34 int tag;
35 };
36
37 struct GlobalMenuBar::ClearMenuClosure {
38 GtkWidget* container;
39 GlobalMenuBar* menu_bar;
40 int tag;
41 };
42
43 struct GlobalMenuBar::GetIndexClosure {
44 bool found;
45 int current_index;
46 int tag;
23 }; 47 };
24 48
25 namespace { 49 namespace {
26 50
27 const int MENU_SEPARATOR =-1; 51 const int MENU_SEPARATOR =-1;
28 const int MENU_END = -2; 52 const int MENU_END = -2;
53 const int MENU_DISABLED_LABEL = -3;
54
55 const int TAG_NORMAL = 0;
56 const int TAG_MOST_VISITED = 1;
57 const int TAG_RECENTLY_CLOSED = 2;
58 const int TAG_MOST_VISITED_HEADER = 3;
59 const int TAG_RECENTLY_CLOSED_HEADER = 4;
60
61 // The number of recently closed items to get.
62 const unsigned int kRecentlyClosedCount = 10;
63
64 // Menus more than this many chars long will get trimmed.
65 const int kMaximumMenuWidthInChars = 50;
29 66
30 GlobalMenuBarCommand file_menu[] = { 67 GlobalMenuBarCommand file_menu[] = {
31 { IDS_NEW_TAB, IDC_NEW_TAB }, 68 { IDS_NEW_TAB, IDC_NEW_TAB },
32 { IDS_NEW_WINDOW, IDC_NEW_WINDOW }, 69 { IDS_NEW_WINDOW, IDC_NEW_WINDOW },
33 { IDS_NEW_INCOGNITO_WINDOW, IDC_NEW_INCOGNITO_WINDOW }, 70 { IDS_NEW_INCOGNITO_WINDOW, IDC_NEW_INCOGNITO_WINDOW },
34 { IDS_REOPEN_CLOSED_TABS_LINUX, IDC_RESTORE_TAB }, 71 { IDS_REOPEN_CLOSED_TABS_LINUX, IDC_RESTORE_TAB },
35 { IDS_OPEN_FILE_LINUX, IDC_OPEN_FILE }, 72 { IDS_OPEN_FILE_LINUX, IDC_OPEN_FILE },
36 { IDS_OPEN_LOCATION_LINUX, IDC_FOCUS_LOCATION }, 73 { IDS_OPEN_LOCATION_LINUX, IDC_FOCUS_LOCATION },
37 74
38 { MENU_SEPARATOR, MENU_SEPARATOR }, 75 { MENU_SEPARATOR, MENU_SEPARATOR },
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
92 { MENU_SEPARATOR, MENU_SEPARATOR }, 129 { MENU_SEPARATOR, MENU_SEPARATOR },
93 130
94 { IDS_FULLSCREEN, IDC_FULLSCREEN }, 131 { IDS_FULLSCREEN, IDC_FULLSCREEN },
95 { IDS_TEXT_DEFAULT_LINUX, IDC_ZOOM_NORMAL }, 132 { IDS_TEXT_DEFAULT_LINUX, IDC_ZOOM_NORMAL },
96 { IDS_TEXT_BIGGER_LINUX, IDC_ZOOM_PLUS }, 133 { IDS_TEXT_BIGGER_LINUX, IDC_ZOOM_PLUS },
97 { IDS_TEXT_SMALLER_LINUX, IDC_ZOOM_MINUS }, 134 { IDS_TEXT_SMALLER_LINUX, IDC_ZOOM_MINUS },
98 135
99 { MENU_END, MENU_END } 136 { MENU_END, MENU_END }
100 }; 137 };
101 138
139 GlobalMenuBarCommand history_menu[] = {
140 { IDS_HISTORY_HOME_LINUX, IDC_HOME },
141 { IDS_HISTORY_BACK_LINUX, IDC_BACK },
142 { IDS_HISTORY_FORWARD_LINUX, IDC_FORWARD },
143
144 { MENU_SEPARATOR, MENU_SEPARATOR },
145
146 { IDS_HISTORY_VISITED_LINUX, MENU_DISABLED_LABEL, TAG_MOST_VISITED_HEADER },
147
148 { MENU_SEPARATOR, MENU_SEPARATOR },
149
150 { IDS_HISTORY_CLOSED_LINUX, MENU_DISABLED_LABEL, TAG_RECENTLY_CLOSED_HEADER },
151
152 { MENU_SEPARATOR, MENU_SEPARATOR },
153
154 { IDS_SHOWFULLHISTORY_LINK, IDC_SHOW_HISTORY },
155
156 { MENU_END, MENU_END }
157 };
158
159 GlobalMenuBarCommand bookmark_menu[] = {
160 { IDS_BOOKMARK_MANAGER, IDC_SHOW_BOOKMARK_MANAGER },
161 { IDS_BOOKMARK_CURRENT_PAGE_LINUX, IDC_BOOKMARK_PAGE },
162 { IDS_BOOKMARK_ALL_TABS_LINUX, IDC_BOOKMARK_ALL_TABS },
163
164 { MENU_SEPARATOR, MENU_SEPARATOR },
165 // TODO(erg): Real implementation of bookmark bar bookmarks!
166 { MENU_SEPARATOR, MENU_SEPARATOR },
167
168 { IDS_BOOMARK_BAR_OPEN_ALL, IDC_BOOKMARK_BAR_OPEN_ALL },
169 { IDS_BOOMARK_BAR_OPEN_ALL_NEW_WINDOW, IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW },
170 { IDS_BOOMARK_BAR_OPEN_ALL_INCOGNITO, IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO },
171
172 { MENU_SEPARATOR, MENU_SEPARATOR },
173 // TODO(erg): "Other bookmarks" bookmarks
174
175 { MENU_END, MENU_END }
176 };
177
102 GlobalMenuBarCommand tools_menu[] = { 178 GlobalMenuBarCommand tools_menu[] = {
103 { IDS_SHOW_DOWNLOADS, IDC_SHOW_DOWNLOADS }, 179 { IDS_SHOW_DOWNLOADS, IDC_SHOW_DOWNLOADS },
104 { IDS_SHOW_HISTORY, IDC_SHOW_HISTORY }, 180 { IDS_SHOW_HISTORY, IDC_SHOW_HISTORY },
105 { IDS_SHOW_EXTENSIONS, IDC_MANAGE_EXTENSIONS }, 181 { IDS_SHOW_EXTENSIONS, IDC_MANAGE_EXTENSIONS },
106 182
107 { MENU_SEPARATOR, MENU_SEPARATOR }, 183 { MENU_SEPARATOR, MENU_SEPARATOR },
108 184
109 { IDS_TASK_MANAGER, IDC_TASK_MANAGER }, 185 { IDS_TASK_MANAGER, IDC_TASK_MANAGER },
110 { IDS_CLEAR_BROWSING_DATA, IDC_CLEAR_BROWSING_DATA }, 186 { IDS_CLEAR_BROWSING_DATA, IDC_CLEAR_BROWSING_DATA },
111 187
112 { MENU_SEPARATOR, MENU_SEPARATOR }, 188 { MENU_SEPARATOR, MENU_SEPARATOR },
113 189
114 { IDS_VIEW_SOURCE, IDC_VIEW_SOURCE }, 190 { IDS_VIEW_SOURCE, IDC_VIEW_SOURCE },
115 { IDS_DEV_TOOLS, IDC_DEV_TOOLS }, 191 { IDS_DEV_TOOLS, IDC_DEV_TOOLS },
116 { IDS_DEV_TOOLS_CONSOLE, IDC_DEV_TOOLS_CONSOLE }, 192 { IDS_DEV_TOOLS_CONSOLE, IDC_DEV_TOOLS_CONSOLE },
117 193
118 { MENU_END, MENU_END } 194 { MENU_END, MENU_END }
119 }; 195 };
120 196
121 GlobalMenuBarCommand help_menu[] = { 197 GlobalMenuBarCommand help_menu[] = {
122 { IDS_FEEDBACK, IDC_FEEDBACK }, 198 { IDS_FEEDBACK, IDC_FEEDBACK },
123 { IDS_HELP_PAGE , IDC_HELP_PAGE }, 199 { IDS_HELP_PAGE , IDC_HELP_PAGE },
124 { MENU_END, MENU_END } 200 { MENU_END, MENU_END }
125 }; 201 };
126 202
127 } // namespace 203 } // namespace
128 204
129 GlobalMenuBar::GlobalMenuBar(Browser* browser, 205 class GlobalMenuBar::HistoryItem {
130 BrowserWindowGtk* window) 206 public:
207 HistoryItem()
208 : icon_requested(false),
209 menu_item(NULL),
210 session_id(0) {}
211
212 // The title for the menu item.
213 string16 title;
214 // The URL that will be navigated to if the user selects this item.
215 GURL url;
216
217 // If the icon is being requested from the FaviconService, |icon_requested|
218 // will be true and |icon_handle| will be non-NULL. If this is false, then
219 // |icon_handle| will be NULL.
220 bool icon_requested;
221 // The Handle given to us by the FaviconService for the icon fetch request.
222 FaviconService::Handle icon_handle;
223
224 // The icon as a GtkImage for inclusion in a GtkImageMenuItem.
225 OwnedWidgetGtk icon_image;
226
227 // A pointer to the menu_item. This is a weak reference in the GTK+ version
228 // because the GtkMenu must sink the reference.
229 GtkWidget* menu_item;
230
231 // This ID is unique for a browser session and can be passed to the
232 // TabRestoreService to re-open the closed window or tab that this
233 // references. A non-0 session ID indicates that this is an entry can be
234 // restored that way. Otherwise, the URL will be used to open the item and
235 // this ID will be 0.
236 SessionID::id_type session_id;
237
238 // If the HistoryItem is a window, this will be the vector of tabs. Note
239 // that this is a list of weak references. The |menu_item_map_| is the owner
240 // of all items. If it is not a window, then the entry is a single page and
241 // the vector will be empty.
242 std::vector<HistoryItem*> tabs;
243
244 private:
245 DISALLOW_COPY_AND_ASSIGN(HistoryItem);
246 };
247
248 GlobalMenuBar::GlobalMenuBar(Browser* browser)
131 : browser_(browser), 249 : browser_(browser),
132 browser_window_(window), 250 profile_(browser_->profile()),
251 default_favicon_(NULL),
133 menu_bar_(gtk_menu_bar_new()), 252 menu_bar_(gtk_menu_bar_new()),
134 dummy_accel_group_(gtk_accel_group_new()), 253 dummy_accel_group_(gtk_accel_group_new()),
135 block_activation_(false) { 254 block_activation_(false),
255 history_menu_(NULL),
256 tab_restore_service_(NULL) {
136 // The global menu bar should never actually be shown in the app; it should 257 // The global menu bar should never actually be shown in the app; it should
137 // instead remain in our widget hierarchy simply to be noticed by third party 258 // instead remain in our widget hierarchy simply to be noticed by third party
138 // components. 259 // components.
139 gtk_widget_set_no_show_all(menu_bar_, TRUE); 260 gtk_widget_set_no_show_all(menu_bar_.get(), TRUE);
140 261
141 // Set a nice name so it shows up in gtkparasite and others. 262 // Set a nice name so it shows up in gtkparasite and others.
142 gtk_widget_set_name(menu_bar_, "chrome-hidden-global-menubar"); 263 gtk_widget_set_name(menu_bar_.get(), "chrome-hidden-global-menubar");
143 264
144 BuildGtkMenuFrom(IDS_FILE_MENU_LINUX, &id_to_menu_item_, file_menu); 265 BuildGtkMenuFrom(IDS_FILE_MENU_LINUX, &id_to_menu_item_, file_menu);
145 BuildGtkMenuFrom(IDS_EDIT_MENU_LINUX, &id_to_menu_item_, edit_menu); 266 BuildGtkMenuFrom(IDS_EDIT_MENU_LINUX, &id_to_menu_item_, edit_menu);
146 BuildGtkMenuFrom(IDS_VIEW_MENU_LINUX, &id_to_menu_item_, view_menu); 267 BuildGtkMenuFrom(IDS_VIEW_MENU_LINUX, &id_to_menu_item_, view_menu);
268 history_menu_ = BuildGtkMenuFrom(IDS_HISTORY_MENU_LINUX, &id_to_menu_item_,
269 history_menu);
270 BuildGtkMenuFrom(IDS_BOOKMARKS_MENU_LINUX, &id_to_menu_item_, bookmark_menu);
147 BuildGtkMenuFrom(IDS_TOOLS_MENU_LINUX, &id_to_menu_item_, tools_menu); 271 BuildGtkMenuFrom(IDS_TOOLS_MENU_LINUX, &id_to_menu_item_, tools_menu);
148 BuildGtkMenuFrom(IDS_HELP_MENU_LINUX, &id_to_menu_item_, help_menu); 272 BuildGtkMenuFrom(IDS_HELP_MENU_LINUX, &id_to_menu_item_, help_menu);
149 273
150 for (IDMenuItemMap::const_iterator it = id_to_menu_item_.begin(); 274 for (CommandIDMenuItemMap::const_iterator it = id_to_menu_item_.begin();
151 it != id_to_menu_item_.end(); ++it) { 275 it != id_to_menu_item_.end(); ++it) {
152 // Get the starting enabled state. 276 // Get the starting enabled state.
153 gtk_widget_set_sensitive( 277 gtk_widget_set_sensitive(
154 it->second, 278 it->second,
155 browser_->command_updater()->IsCommandEnabled(it->first)); 279 browser_->command_updater()->IsCommandEnabled(it->first));
156 280
157 // Set the accelerator for each menu item. 281 // Set the accelerator for each menu item.
158 const ui::AcceleratorGtk* accelerator_gtk = 282 const ui::AcceleratorGtk* accelerator_gtk =
159 AcceleratorsGtk::GetInstance()->GetPrimaryAcceleratorForCommand( 283 AcceleratorsGtk::GetInstance()->GetPrimaryAcceleratorForCommand(
160 it->first); 284 it->first);
161 if (accelerator_gtk) { 285 if (accelerator_gtk) {
162 gtk_widget_add_accelerator(it->second, 286 gtk_widget_add_accelerator(it->second,
163 "activate", 287 "activate",
164 dummy_accel_group_, 288 dummy_accel_group_,
165 accelerator_gtk->GetGdkKeyCode(), 289 accelerator_gtk->GetGdkKeyCode(),
166 accelerator_gtk->gdk_modifier_type(), 290 accelerator_gtk->gdk_modifier_type(),
167 GTK_ACCEL_VISIBLE); 291 GTK_ACCEL_VISIBLE);
168 } 292 }
169 293
170 browser_->command_updater()->AddCommandObserver(it->first, this); 294 browser_->command_updater()->AddCommandObserver(it->first, this);
171 } 295 }
172 296
297 default_favicon_ = GtkThemeService::GetDefaultFavicon(true);
298
299 if (profile_) {
300 tab_restore_service_ = profile_->GetTabRestoreService();
301 if (tab_restore_service_) {
302 tab_restore_service_->LoadTabsFromLastSession();
303 tab_restore_service_->AddObserver(this);
304
305 // If LoadTabsFromLastSession doesn't load tabs, it won't call
306 // TabRestoreServiceChanged(). This ensures that all new windows after
307 // the first one will have their menus populated correctly.
308 TabRestoreServiceChanged(tab_restore_service_);
309 }
310
311 registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
312 Source<Profile>(profile_));
313 }
314
173 // Listen for bookmark bar visibility changes and set the initial state. 315 // Listen for bookmark bar visibility changes and set the initial state.
174 registrar_.Add(this, NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED, 316 registrar_.Add(this, NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED,
175 NotificationService::AllSources()); 317 NotificationService::AllSources());
176 Observe(NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED, 318 Observe(NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED,
177 NotificationService::AllSources(), 319 NotificationService::AllSources(),
178 NotificationService::NoDetails()); 320 NotificationService::NoDetails());
179 } 321 }
180 322
181 GlobalMenuBar::~GlobalMenuBar() { 323 GlobalMenuBar::~GlobalMenuBar() {
182 for (IDMenuItemMap::const_iterator it = id_to_menu_item_.begin(); 324 for (CommandIDMenuItemMap::const_iterator it = id_to_menu_item_.begin();
183 it != id_to_menu_item_.end(); ++it) { 325 it != id_to_menu_item_.end(); ++it) {
184 browser_->command_updater()->RemoveCommandObserver(it->first, this); 326 browser_->command_updater()->RemoveCommandObserver(it->first, this);
185 } 327 }
186 328
329 if (tab_restore_service_)
330 tab_restore_service_->RemoveObserver(this);
331
332 STLDeleteContainerPairSecondPointers(menu_item_history_map_.begin(),
333 menu_item_history_map_.end());
334 menu_item_history_map_.clear();
335
187 g_object_unref(dummy_accel_group_); 336 g_object_unref(dummy_accel_group_);
188 } 337 }
189 338
190 void GlobalMenuBar::BuildGtkMenuFrom(int menu_str_id, 339 GtkWidget* GlobalMenuBar::BuildGtkMenuFrom(
191 std::map<int, GtkWidget*>* id_to_menu_item, 340 int menu_str_id,
192 GlobalMenuBarCommand* commands) { 341 std::map<int, GtkWidget*>* id_to_menu_item,
342 GlobalMenuBarCommand* commands) {
193 GtkWidget* menu = gtk_menu_new(); 343 GtkWidget* menu = gtk_menu_new();
194 for (int i = 0; commands[i].str_id != MENU_END; ++i) { 344 for (int i = 0; commands[i].str_id != MENU_END; ++i) {
195 GtkWidget* menu_item = NULL; 345 GtkWidget* menu_item = BuildMenuItem(
196 if (commands[i].str_id == MENU_SEPARATOR) { 346 commands[i].str_id, commands[i].command, commands[i].tag,
197 menu_item = gtk_separator_menu_item_new(); 347 id_to_menu_item, menu);
348 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
349 }
350
351 gtk_widget_show(menu);
352
353 GtkWidget* menu_item = gtk_menu_item_new_with_mnemonic(
354 gfx::ConvertAcceleratorsFromWindowsStyle(
355 l10n_util::GetStringUTF8(menu_str_id)).c_str());
356 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), menu);
357 gtk_widget_show(menu_item);
358 gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar_.get()), menu_item);
359
360 return menu;
361 }
362
363 GtkWidget* GlobalMenuBar::BuildMenuItem(
364 int string_id,
365 int command_id,
366 int tag_id,
367 std::map<int, GtkWidget*>* id_to_menu_item,
368 GtkWidget* menu_to_add_to) {
369 GtkWidget* menu_item = NULL;
370 if (string_id == MENU_SEPARATOR) {
371 menu_item = gtk_separator_menu_item_new();
372 } else {
373 std::string label =
374 gfx::ConvertAcceleratorsFromWindowsStyle(
375 l10n_util::GetStringUTF8(string_id));
376
377 if (command_id == IDC_SHOW_BOOKMARK_BAR)
378 menu_item = gtk_check_menu_item_new_with_mnemonic(label.c_str());
379 else
380 menu_item = gtk_menu_item_new_with_mnemonic(label.c_str());
381
382 if (tag_id) {
383 g_object_set_data(G_OBJECT(menu_item), "type-tag",
384 GINT_TO_POINTER(tag_id));
385 }
386
387 if (command_id == MENU_DISABLED_LABEL) {
388 gtk_widget_set_sensitive(menu_item, FALSE);
198 } else { 389 } else {
199 int command_id = commands[i].command;
200 std::string label =
201 gfx::ConvertAcceleratorsFromWindowsStyle(
202 l10n_util::GetStringUTF8(commands[i].str_id));
203
204 if (command_id == IDC_SHOW_BOOKMARK_BAR)
205 menu_item = gtk_check_menu_item_new_with_mnemonic(label.c_str());
206 else
207 menu_item = gtk_menu_item_new_with_mnemonic(label.c_str());
208
209 id_to_menu_item->insert(std::make_pair(command_id, menu_item)); 390 id_to_menu_item->insert(std::make_pair(command_id, menu_item));
210 g_object_set_data(G_OBJECT(menu_item), "command-id", 391 g_object_set_data(G_OBJECT(menu_item), "command-id",
211 GINT_TO_POINTER(command_id)); 392 GINT_TO_POINTER(command_id));
212 g_signal_connect(menu_item, "activate", 393 g_signal_connect(menu_item, "activate",
213 G_CALLBACK(OnItemActivatedThunk), this); 394 G_CALLBACK(OnItemActivatedThunk), this);
214 } 395 }
215 gtk_widget_show(menu_item); 396 }
216 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
217 }
218
219 gtk_widget_show(menu);
220
221 GtkWidget* menu_item = gtk_menu_item_new_with_mnemonic(
222 gfx::ConvertAcceleratorsFromWindowsStyle(
223 l10n_util::GetStringUTF8(menu_str_id)).c_str());
224 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), menu);
225 gtk_widget_show(menu_item); 397 gtk_widget_show(menu_item);
226 398 return menu_item;
227 gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar_), menu_item); 399 }
400
401 GlobalMenuBar::HistoryItem* GlobalMenuBar::HistoryItemForMenuItem(
402 GtkWidget* menu_item) {
403 MenuItemToHistoryMap::iterator it = menu_item_history_map_.find(menu_item);
404 return it != menu_item_history_map_.end() ? it->second : NULL;
405 }
406
407 bool GlobalMenuBar::HasValidHistoryItemForTab(
408 const TabRestoreService::Tab& entry) {
409 if (entry.navigations.empty())
410 return false;
411
412 const TabNavigation& current_navigation =
413 entry.navigations.at(entry.current_navigation_index);
414 if (current_navigation.virtual_url() == GURL(chrome::kChromeUINewTabURL))
415 return false;
416
417 return true;
418 }
419
420 GlobalMenuBar::HistoryItem* GlobalMenuBar::HistoryItemForTab(
421 const TabRestoreService::Tab& entry) {
422 if (!HasValidHistoryItemForTab(entry))
423 return NULL;
424
425 const TabNavigation& current_navigation =
426 entry.navigations.at(entry.current_navigation_index);
427 HistoryItem* item = new HistoryItem();
428 item->title = current_navigation.title();
429 item->url = current_navigation.virtual_url();
430 item->session_id = entry.id;
431
432 // Tab navigations don't come with icons, so we always have to request them.
433 GetFaviconForHistoryItem(item);
434
435 return item;
436
437 }
438
439 GtkWidget* GlobalMenuBar::AddHistoryItemToMenu(HistoryItem* item,
440 GtkWidget* menu,
441 int tag,
442 int index) {
443 string16 title = item->title;
444 std::string url_string = item->url.possibly_invalid_spec();
445
446 if (title.empty())
447 title = UTF8ToUTF16(url_string);
448 ui::ElideString(title, kMaximumMenuWidthInChars, &title);
449
450 GtkWidget* menu_item = gtk_image_menu_item_new_with_label(
451 UTF16ToUTF8(title).c_str());
452 gtk_util::SetAlwaysShowImage(menu_item);
453
454 item->menu_item = menu_item;
455 gtk_widget_show(menu_item);
456 g_object_set_data(G_OBJECT(menu_item), "type-tag", GINT_TO_POINTER(tag));
457 g_signal_connect(menu_item, "activate",
458 G_CALLBACK(OnRecentlyClosedItemActivatedThunk), this);
459 if (item->icon_image.get()) {
460 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
461 item->icon_image.get());
462 } else if (!item->tabs.size()) {
463 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
464 gtk_image_new_from_pixbuf(default_favicon_));
465 }
466
467 std::string tooltip = gtk_util::BuildTooltipTitleFor(item->title, item->url);
468 gtk_widget_set_tooltip_markup(menu_item, tooltip.c_str());
469
470 menu_item_history_map_.insert(std::make_pair(menu_item, item));
471 gtk_menu_shell_insert(GTK_MENU_SHELL(menu), menu_item, index);
472
473 return menu_item;
474 }
475
476 void GlobalMenuBar::GetFaviconForHistoryItem(HistoryItem* item) {
477 FaviconService* service =
478 profile_->GetFaviconService(Profile::EXPLICIT_ACCESS);
479 FaviconService::Handle handle = service->GetFaviconForURL(
480 item->url,
481 history::FAVICON,
482 &favicon_consumer_,
483 NewCallback(this, &GlobalMenuBar::GotFaviconData));
484 favicon_consumer_.SetClientData(service, handle, item);
485 item->icon_handle = handle;
486 item->icon_requested = true;
487 }
488
489 void GlobalMenuBar::GotFaviconData(FaviconService::Handle handle,
490 history::FaviconData favicon) {
491 HistoryItem* item =
492 favicon_consumer_.GetClientData(
493 profile_->GetFaviconService(Profile::EXPLICIT_ACCESS), handle);
494 DCHECK(item);
495 item->icon_requested = false;
496 item->icon_handle = NULL;
497
498 SkBitmap icon;
499 if (favicon.is_valid() &&
500 gfx::PNGCodec::Decode(favicon.image_data->front(),
501 favicon.image_data->size(), &icon)) {
502 GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&icon);
503 if (pixbuf) {
504 item->icon_image.Own(gtk_image_new_from_pixbuf(pixbuf));
505 g_object_unref(pixbuf);
506
507 if (item->menu_item) {
508 gtk_image_menu_item_set_image(
509 GTK_IMAGE_MENU_ITEM(item->menu_item),
510 item->icon_image.get());
511 }
512 }
513 }
514 }
515
516 void GlobalMenuBar::CancelFaviconRequest(HistoryItem* item) {
517 DCHECK(item);
518 if (item->icon_requested) {
519 FaviconService* service =
520 profile_->GetFaviconService(Profile::EXPLICIT_ACCESS);
521 service->CancelRequest(item->icon_handle);
522 item->icon_requested = false;
523 item->icon_handle = NULL;
524 }
525 }
526
527 int GlobalMenuBar::GetIndexOfMenuItemWithTag(GtkWidget* menu, int tag_id) {
528 GetIndexClosure closure;
529 closure.found = false;
530 closure.current_index = 0;
531 closure.tag = tag_id;
532
533 gtk_container_foreach(
534 GTK_CONTAINER(menu),
535 reinterpret_cast<void (*)(GtkWidget*, void*)>(GetIndexCallback),
536 &closure);
537
538 return closure.current_index;
539 }
540
541 void GlobalMenuBar::ClearMenuSection(GtkWidget* menu, int tag) {
542 ClearMenuClosure closure;
543 closure.container = menu;
544 closure.menu_bar = this;
545 closure.tag = tag;
546
547 gtk_container_foreach(
548 GTK_CONTAINER(menu),
549 reinterpret_cast<void (*)(GtkWidget*, void*)>(ClearMenuCallback),
550 &closure);
551 }
552
553 // static
554 void GlobalMenuBar::GetIndexCallback(GtkWidget* menu_item,
555 GetIndexClosure* closure) {
556 int tag = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menu_item), "type-tag"));
557 if (tag == closure->tag)
558 closure->found = true;
559
560 if (!closure->found)
561 closure->current_index++;
562 }
563
564 // static
565 void GlobalMenuBar::ClearMenuCallback(GtkWidget* menu_item,
566 ClearMenuClosure* closure) {
567 DCHECK_NE(closure->tag, 0);
568
569 int tag = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menu_item), "type-tag"));
570 if (closure->tag == tag) {
571 HistoryItem* item = closure->menu_bar->HistoryItemForMenuItem(menu_item);
572
573 if (item) {
574 closure->menu_bar->CancelFaviconRequest(item);
575 closure->menu_bar->menu_item_history_map_.erase(menu_item);
576 delete item;
577 }
578
579 GtkWidget* submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu_item));
580 if (submenu)
581 closure->menu_bar->ClearMenuSection(submenu, closure->tag);
582
583 gtk_container_remove(GTK_CONTAINER(closure->container), menu_item);
584 }
228 } 585 }
229 586
230 void GlobalMenuBar::EnabledStateChangedForCommand(int id, bool enabled) { 587 void GlobalMenuBar::EnabledStateChangedForCommand(int id, bool enabled) {
231 IDMenuItemMap::iterator it = id_to_menu_item_.find(id); 588 CommandIDMenuItemMap::iterator it = id_to_menu_item_.find(id);
232 if (it != id_to_menu_item_.end()) 589 if (it != id_to_menu_item_.end())
233 gtk_widget_set_sensitive(it->second, enabled); 590 gtk_widget_set_sensitive(it->second, enabled);
234 } 591 }
235 592
236 void GlobalMenuBar::Observe(NotificationType type, 593 void GlobalMenuBar::Observe(NotificationType type,
237 const NotificationSource& source, 594 const NotificationSource& source,
238 const NotificationDetails& details) { 595 const NotificationDetails& details) {
239 DCHECK(type.value == NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED); 596 if (type.value == NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED) {
597 CommandIDMenuItemMap::iterator it =
598 id_to_menu_item_.find(IDC_SHOW_BOOKMARK_BAR);
599 if (it != id_to_menu_item_.end()) {
600 PrefService* prefs = browser_->profile()->GetPrefs();
240 601
241 IDMenuItemMap::iterator it = id_to_menu_item_.find(IDC_SHOW_BOOKMARK_BAR); 602 block_activation_ = true;
242 if (it != id_to_menu_item_.end()) { 603 gtk_check_menu_item_set_active(
243 PrefService* prefs = browser_->profile()->GetPrefs(); 604 GTK_CHECK_MENU_ITEM(it->second),
605 prefs->GetBoolean(prefs::kShowBookmarkBar));
606 block_activation_ = false;
607 }
608 } else if (type.value == NotificationType::BROWSER_THEME_CHANGED) {
609 // Keeping track of which menu items have the default icon is going an
610 // error-prone pain, so instead just store the new default favicon and
611 // we'll update on the next menu change event.
612 default_favicon_ = GtkThemeService::GetDefaultFavicon(true);
613 } else {
614 NOTREACHED();
615 }
616 }
244 617
245 block_activation_ = true; 618 void GlobalMenuBar::TabRestoreServiceChanged(TabRestoreService* service) {
246 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(it->second), 619 const TabRestoreService::Entries& entries = service->entries();
247 prefs->GetBoolean(prefs::kShowBookmarkBar)); 620
248 block_activation_ = false; 621 ClearMenuSection(history_menu_, TAG_RECENTLY_CLOSED);
622
623 // We'll get the index the "Recently Closed" header. (This can vary depending
624 // on the number of "Most Visited" items.
625 int index = GetIndexOfMenuItemWithTag(history_menu_,
626 TAG_RECENTLY_CLOSED_HEADER) + 1;
627
628 unsigned int added_count = 0;
629 for (TabRestoreService::Entries::const_iterator it = entries.begin();
630 it != entries.end() && added_count < kRecentlyClosedCount; ++it) {
631 TabRestoreService::Entry* entry = *it;
632
633 if (entry->type == TabRestoreService::WINDOW) {
634 TabRestoreService::Window* entry_win =
635 static_cast<TabRestoreService::Window*>(entry);
636 std::vector<TabRestoreService::Tab>& tabs = entry_win->tabs;
637 if (tabs.empty())
638 continue;
639
640 // Check that this window has valid content. Sometimes it is possible for
641 // there to not be any subitems for a given window; if that is the case,
642 // do not add the entry to the main menu.
643 int valid_tab_count = 0;
644 std::vector<TabRestoreService::Tab>::const_iterator it;
645 for (it = tabs.begin(); it != tabs.end(); ++it) {
646 if (HasValidHistoryItemForTab(*it))
647 valid_tab_count++;
648 }
649 if (valid_tab_count == 0)
650 continue;
651
652 // Create the item for the parent/window. Do not set the title yet
653 // because the actual number of items that are in the menu will not be
654 // known until things like the NTP are filtered out, which is done when
655 // the tab items are actually created.
656 HistoryItem* item = new HistoryItem();
657 item->session_id = entry_win->id;
658
659 GtkWidget* submenu = gtk_menu_new();
660
661 GtkWidget* restore_item = gtk_menu_item_new_with_label(
662 l10n_util::GetStringUTF8(
663 IDS_HISTORY_CLOSED_RESTORE_WINDOW_LINUX).c_str());
664 g_object_set_data(G_OBJECT(restore_item), "type-tag",
665 GINT_TO_POINTER(TAG_RECENTLY_CLOSED));
666 g_signal_connect(restore_item, "activate",
667 G_CALLBACK(OnRecentlyClosedItemActivatedThunk), this);
668 gtk_widget_show(restore_item);
669
670 // The mac version of this code allows the user to click on the parent
671 // menu item to have the same effect as clicking the restore window
672 // submenu item. GTK+ helpfully activates a menu item when it shows a
673 // submenu so toss that feature out.
674 menu_item_history_map_.insert(std::make_pair(restore_item, item));
675 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), restore_item);
676
677 GtkWidget* separator = gtk_separator_menu_item_new();
678 gtk_widget_show(separator);
679 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), separator);
680
681 // Loop over the window's tabs and add them to the submenu.
682 int subindex = 2;
683 for (it = tabs.begin(); it != tabs.end(); ++it) {
684 TabRestoreService::Tab tab = *it;
685 HistoryItem* tab_item = HistoryItemForTab(tab);
686 if (tab_item) {
687 item->tabs.push_back(tab_item);
688 AddHistoryItemToMenu(tab_item, submenu, TAG_RECENTLY_CLOSED,
689 subindex++);
690 }
691 }
692
693 // Now that the number of tabs that has been added is known, set the
694 // title of the parent menu item.
695 std::string title =
696 (item->tabs.size() == 1) ?
697 l10n_util::GetStringUTF8(
698 IDS_NEW_TAB_RECENTLY_CLOSED_WINDOW_SINGLE) :
699 l10n_util::GetStringFUTF8(
700 IDS_NEW_TAB_RECENTLY_CLOSED_WINDOW_MULTIPLE,
701 base::IntToString16(item->tabs.size()));
702
703 // Create the menu item parent. Unlike mac, it's can't be activated.
704 GtkWidget* parent_item = gtk_image_menu_item_new_with_label(
705 title.c_str());
706 gtk_widget_show(parent_item);
707 g_object_set_data(G_OBJECT(parent_item), "type-tag",
708 GINT_TO_POINTER(TAG_RECENTLY_CLOSED));
709 gtk_menu_item_set_submenu(GTK_MENU_ITEM(parent_item), submenu);
710
711 gtk_menu_shell_insert(GTK_MENU_SHELL(history_menu_), parent_item,
712 index++);
713 ++added_count;
714 } else if (entry->type == TabRestoreService::TAB) {
715 TabRestoreService::Tab* tab =
716 static_cast<TabRestoreService::Tab*>(entry);
717 HistoryItem* item = HistoryItemForTab(*tab);
718 if (item) {
719 AddHistoryItemToMenu(item, history_menu_, TAG_RECENTLY_CLOSED, index++);
720 ++added_count;
721 }
722 }
249 } 723 }
250 } 724 }
251 725
726 void GlobalMenuBar::TabRestoreServiceDestroyed(
727 TabRestoreService* service) {
728 // Intentionally left blank. We hold a weak reference to the service.
Evan Stade 2011/04/18 18:11:19 I think observers usually do hold weak refs. The i
729 }
730
252 void GlobalMenuBar::OnItemActivated(GtkWidget* sender) { 731 void GlobalMenuBar::OnItemActivated(GtkWidget* sender) {
253 if (block_activation_) 732 if (block_activation_)
254 return; 733 return;
255 734
256 int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(sender), "command-id")); 735 int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(sender), "command-id"));
257 browser_->ExecuteCommandIfEnabled(id); 736 browser_->ExecuteCommandIfEnabled(id);
258 } 737 }
738
739 void GlobalMenuBar::OnRecentlyClosedItemActivated(GtkWidget* sender) {
740 WindowOpenDisposition disposition =
741 gtk_util::DispositionForCurrentButtonPressEvent();
742 HistoryItem* item = HistoryItemForMenuItem(sender);
743
744 // If this item can be restored using TabRestoreService, do so. Otherwise,
745 // just load the URL.
746 TabRestoreService* service = browser_->profile()->GetTabRestoreService();
747 if (item->session_id && service) {
748 service->RestoreEntryById(browser_->tab_restore_service_delegate(),
749 item->session_id, false);
750 } else {
751 DCHECK(item->url.is_valid());
752 browser_->OpenURL(item->url, GURL(), disposition,
753 PageTransition::AUTO_BOOKMARK);
754 }
755 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/gtk/global_menu_bar.h ('k') | chrome/browser/ui/gtk/gtk_util.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698