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

Side by Side Diff: chrome/browser/ui/gtk/global_history_menu.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: Resetting to an earlier point and bringing in my Most Visited work 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_history_menu.h ('k') | chrome/browser/ui/gtk/global_menu_bar.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/ui/gtk/global_history_menu.h"
6
7 #include <gtk/gtk.h>
8
9 #include "base/stl_util-inl.h"
10 #include "base/utf_string_conversions.h"
11 #include "base/string_number_conversions.h"
12 #include "chrome/browser/favicon_service.h"
13 #include "chrome/browser/history/history.h"
14 #include "chrome/browser/history/page_usage_data.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/ui/browser.h"
17 #include "chrome/browser/ui/browser_tab_restore_service_delegate.h"
18 #include "chrome/browser/ui/gtk/global_menu_bar.h"
19 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
20 #include "chrome/browser/ui/gtk/gtk_util.h"
21 #include "chrome/browser/ui/gtk/owned_widget_gtk.h"
22 #include "chrome/common/url_constants.h"
23 #include "content/common/notification_service.h"
24 #include "grit/generated_resources.h"
25 #include "ui/base/l10n/l10n_util.h"
26 #include "ui/base/text/text_elider.h"
27 #include "ui/gfx/codec/png_codec.h"
28 #include "ui/gfx/gtk_util.h"
29
30 namespace {
31
32 // Menus more than this many chars long will get trimmed.
33 const int kMaximumMenuWidthInChars = 50;
34
35 // Number of days to consider when getting the number of most visited items.
36 const int kMostVisitedScope = 90;
37
38 // The number of most visisted results to get.
39 const int kMostVisitedCount = 9;
40
41 // The number of recently closed items to get.
42 const unsigned int kRecentlyClosedCount = 10;
43
44 } // namespace
45
46 struct GlobalHistoryMenu::ClearMenuClosure {
47 GtkWidget* container;
48 GlobalHistoryMenu* menu_bar;
49 int tag;
50 };
51
52 struct GlobalHistoryMenu::GetIndexClosure {
53 bool found;
54 int current_index;
55 int tag;
56 };
57
58 class GlobalHistoryMenu::HistoryItem {
59 public:
60 HistoryItem()
61 : icon_requested(false),
62 menu_item(NULL),
63 session_id(0) {}
64
65 // The title for the menu item.
66 string16 title;
67 // The URL that will be navigated to if the user selects this item.
68 GURL url;
69
70 // If the icon is being requested from the FaviconService, |icon_requested|
71 // will be true and |icon_handle| will be non-NULL. If this is false, then
72 // |icon_handle| will be NULL.
73 bool icon_requested;
74 // The Handle given to us by the FaviconService for the icon fetch request.
75 FaviconService::Handle icon_handle;
76
77 // The icon as a GtkImage for inclusion in a GtkImageMenuItem.
78 OwnedWidgetGtk icon_image;
79
80 // A pointer to the menu_item. This is a weak reference in the GTK+ version
81 // because the GtkMenu must sink the reference.
82 GtkWidget* menu_item;
83
84 // This ID is unique for a browser session and can be passed to the
85 // TabRestoreService to re-open the closed window or tab that this
86 // references. A non-0 session ID indicates that this is an entry can be
87 // restored that way. Otherwise, the URL will be used to open the item and
88 // this ID will be 0.
89 SessionID::id_type session_id;
90
91 // If the HistoryItem is a window, this will be the vector of tabs. Note
92 // that this is a list of weak references. The |menu_item_map_| is the owner
93 // of all items. If it is not a window, then the entry is a single page and
94 // the vector will be empty.
95 std::vector<HistoryItem*> tabs;
96
97 private:
98 DISALLOW_COPY_AND_ASSIGN(HistoryItem);
99 };
100
101 GlobalHistoryMenu::GlobalHistoryMenu(Browser* browser)
102 : browser_(browser),
103 profile_(browser_->profile()),
104 default_favicon_(NULL),
105 tab_restore_service_(NULL),
106 history_service_(NULL),
107 create_in_progress_(false),
108 need_recreate_(false) {
109 }
110
111 GlobalHistoryMenu::~GlobalHistoryMenu() {
112 // Unregister ourselves as observers and notifications.
113 const NotificationSource& src = NotificationService::AllSources();
114 if (history_service_) {
115 registrar_.Remove(this, NotificationType::HISTORY_TYPED_URLS_MODIFIED, src);
116 registrar_.Remove(this, NotificationType::HISTORY_URL_VISITED, src);
117 registrar_.Remove(this, NotificationType::HISTORY_URLS_DELETED, src);
118 } else {
119 registrar_.Remove(this, NotificationType::HISTORY_LOADED, src);
120 }
121
122 if (tab_restore_service_)
123 tab_restore_service_->RemoveObserver(this);
124
125 STLDeleteContainerPairSecondPointers(menu_item_history_map_.begin(),
126 menu_item_history_map_.end());
127 menu_item_history_map_.clear();
128 }
129
130 void GlobalHistoryMenu::Init(GtkWidget* history_menu) {
131 history_menu_ = history_menu;
132
133 default_favicon_ = GtkThemeService::GetDefaultFavicon(true);
134
135 if (profile_) {
136 // Check to see if the history service is ready. Because it loads async, it
137 // may not be ready when the Bridge is created. If this happens, register
138 // for a notification that tells us the HistoryService is ready.
139 HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
140 if (hs != NULL && hs->BackendLoaded()) {
141 history_service_ = hs;
142 InitHistoryService();
143
144 need_recreate_ = true;
145 CreateMostVisited();
146 }
147
148 tab_restore_service_ = profile_->GetTabRestoreService();
149 if (tab_restore_service_) {
150 tab_restore_service_->LoadTabsFromLastSession();
151 tab_restore_service_->AddObserver(this);
152
153 // If LoadTabsFromLastSession doesn't load tabs, it won't call
154 // TabRestoreServiceChanged(). This ensures that all new windows after
155 // the first one will have their menus populated correctly.
156 TabRestoreServiceChanged(tab_restore_service_);
157 }
158
159 registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
160 Source<Profile>(profile_));
161 }
162
163 // The service is not ready for use yet, so become notified when it does.
164 if (!history_service_) {
165 registrar_.Add(this,
166 NotificationType::HISTORY_LOADED,
167 NotificationService::AllSources());
168 }
169 }
170
171 void GlobalHistoryMenu::InitHistoryService() {
172 const NotificationSource& source = NotificationService::AllSources();
173 registrar_.Add(this, NotificationType::HISTORY_TYPED_URLS_MODIFIED, source);
174 registrar_.Add(this, NotificationType::HISTORY_URL_VISITED, source);
175 registrar_.Add(this, NotificationType::HISTORY_URLS_DELETED, source);
176 }
177
178 void GlobalHistoryMenu::CreateMostVisited() {
179 // If we're currently running CreateMenu(), wait until it finishes.
180 if (create_in_progress_)
181 return;
182
183 create_in_progress_ = true;
184 need_recreate_ = false;
185
186 history_service_->QuerySegmentUsageSince(
Evan Stade 2011/04/25 23:11:41 why don't you use TopSites?
Elliot Glaysher 2011/04/25 23:27:49 Because I didn't know that existed. I've pulled th
187 &cancelable_request_consumer_,
188 base::Time::Now() - base::TimeDelta::FromDays(kMostVisitedScope),
189 kMostVisitedCount,
190 NewCallback(this, &GlobalHistoryMenu::OnVisitedHistoryResults));
191 }
192
193 void GlobalHistoryMenu::OnVisitedHistoryResults(
194 CancelableRequestProvider::Handle handle,
195 std::vector<PageUsageData*>* results) {
196 ClearMenuSection(history_menu_, GlobalMenuBar::TAG_MOST_VISITED);
197
198 // We'll get the index the "Recently Closed" header. (This can vary depending
199 // on the number of "Most Visited" items.
200 int index = GetIndexOfMenuItemWithTag(
201 history_menu_,
202 GlobalMenuBar::TAG_MOST_VISITED_HEADER) + 1;
203
204 size_t count = results->size();
205 for (size_t i = 0; i < count; ++i) {
206 PageUsageData* history_item = (*results)[i];
207
208 HistoryItem* item = new HistoryItem();
209 item->title = history_item->GetTitle();
210 item->url = history_item->GetURL();
211 if (history_item->HasFavicon()) {
212 GdkPixbuf* pixbuf =
213 gfx::GdkPixbufFromSkBitmap(history_item->GetFavicon());
214 DCHECK(pixbuf);
215 item->icon_image.Own(gtk_image_new_from_pixbuf(pixbuf));
216 } else {
217 GetFaviconForHistoryItem(item);
218 }
219 // This will add |item| to the |menu_item_map_|, which takes ownership.
220 AddHistoryItemToMenu(item, history_menu_, GlobalMenuBar::TAG_MOST_VISITED,
221 index + i);
222 }
223
224 create_in_progress_ = false;
225
226 // We are already invalid by the time we finished, darn.
227 if (need_recreate_)
228 CreateMostVisited();
229 }
230
231
232 GlobalHistoryMenu::HistoryItem* GlobalHistoryMenu::HistoryItemForMenuItem(
233 GtkWidget* menu_item) {
234 MenuItemToHistoryMap::iterator it = menu_item_history_map_.find(menu_item);
235 return it != menu_item_history_map_.end() ? it->second : NULL;
236 }
237
238 bool GlobalHistoryMenu::HasValidHistoryItemForTab(
239 const TabRestoreService::Tab& entry) {
240 if (entry.navigations.empty())
241 return false;
242
243 const TabNavigation& current_navigation =
244 entry.navigations.at(entry.current_navigation_index);
245 if (current_navigation.virtual_url() == GURL(chrome::kChromeUINewTabURL))
246 return false;
247
248 return true;
249 }
250
251 GlobalHistoryMenu::HistoryItem* GlobalHistoryMenu::HistoryItemForTab(
252 const TabRestoreService::Tab& entry) {
253 if (!HasValidHistoryItemForTab(entry))
254 return NULL;
255
256 const TabNavigation& current_navigation =
257 entry.navigations.at(entry.current_navigation_index);
258 HistoryItem* item = new HistoryItem();
259 item->title = current_navigation.title();
260 item->url = current_navigation.virtual_url();
261 item->session_id = entry.id;
262
263 // Tab navigations don't come with icons, so we always have to request them.
264 GetFaviconForHistoryItem(item);
265
266 return item;
267 }
268
269 GtkWidget* GlobalHistoryMenu::AddHistoryItemToMenu(HistoryItem* item,
270 GtkWidget* menu,
271 int tag,
272 int index) {
273 string16 title = item->title;
274 std::string url_string = item->url.possibly_invalid_spec();
275
276 if (title.empty())
277 title = UTF8ToUTF16(url_string);
278 ui::ElideString(title, kMaximumMenuWidthInChars, &title);
279
280 GtkWidget* menu_item = gtk_image_menu_item_new_with_label(
281 UTF16ToUTF8(title).c_str());
282 gtk_util::SetAlwaysShowImage(menu_item);
283
284 item->menu_item = menu_item;
285 gtk_widget_show(menu_item);
286 g_object_set_data(G_OBJECT(menu_item), "type-tag", GINT_TO_POINTER(tag));
287 g_signal_connect(menu_item, "activate",
288 G_CALLBACK(OnRecentlyClosedItemActivatedThunk), this);
289 if (item->icon_image.get()) {
290 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
291 item->icon_image.get());
292 } else if (!item->tabs.size()) {
293 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
294 gtk_image_new_from_pixbuf(default_favicon_));
295 }
296
297 std::string tooltip = gtk_util::BuildTooltipTitleFor(item->title, item->url);
298 gtk_widget_set_tooltip_markup(menu_item, tooltip.c_str());
299
300 menu_item_history_map_.insert(std::make_pair(menu_item, item));
301 gtk_menu_shell_insert(GTK_MENU_SHELL(menu), menu_item, index);
302
303 return menu_item;
304 }
305
306 void GlobalHistoryMenu::GetFaviconForHistoryItem(HistoryItem* item) {
307 FaviconService* service =
308 profile_->GetFaviconService(Profile::EXPLICIT_ACCESS);
309 FaviconService::Handle handle = service->GetFaviconForURL(
310 item->url,
311 history::FAVICON,
312 &favicon_consumer_,
313 NewCallback(this, &GlobalHistoryMenu::GotFaviconData));
314 favicon_consumer_.SetClientData(service, handle, item);
315 item->icon_handle = handle;
316 item->icon_requested = true;
317 }
318
319 void GlobalHistoryMenu::GotFaviconData(FaviconService::Handle handle,
320 history::FaviconData favicon) {
321 HistoryItem* item =
322 favicon_consumer_.GetClientData(
323 profile_->GetFaviconService(Profile::EXPLICIT_ACCESS), handle);
324 DCHECK(item);
325 item->icon_requested = false;
326 item->icon_handle = NULL;
327
328 SkBitmap icon;
329 if (favicon.is_valid() &&
330 gfx::PNGCodec::Decode(favicon.image_data->front(),
331 favicon.image_data->size(), &icon)) {
332 GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&icon);
333 if (pixbuf) {
334 item->icon_image.Own(gtk_image_new_from_pixbuf(pixbuf));
335 g_object_unref(pixbuf);
336
337 if (item->menu_item) {
338 gtk_image_menu_item_set_image(
339 GTK_IMAGE_MENU_ITEM(item->menu_item),
340 item->icon_image.get());
341 }
342 }
343 }
344 }
345
346 void GlobalHistoryMenu::CancelFaviconRequest(HistoryItem* item) {
347 DCHECK(item);
348 if (item->icon_requested) {
349 FaviconService* service =
350 profile_->GetFaviconService(Profile::EXPLICIT_ACCESS);
351 service->CancelRequest(item->icon_handle);
352 item->icon_requested = false;
353 item->icon_handle = NULL;
354 }
355 }
356
357 int GlobalHistoryMenu::GetIndexOfMenuItemWithTag(GtkWidget* menu, int tag_id) {
358 GetIndexClosure closure;
359 closure.found = false;
360 closure.current_index = 0;
361 closure.tag = tag_id;
362
363 gtk_container_foreach(
364 GTK_CONTAINER(menu),
365 reinterpret_cast<void (*)(GtkWidget*, void*)>(GetIndexCallback),
366 &closure);
367
368 return closure.current_index;
369 }
370
371 void GlobalHistoryMenu::ClearMenuSection(GtkWidget* menu, int tag) {
372 ClearMenuClosure closure;
373 closure.container = menu;
374 closure.menu_bar = this;
375 closure.tag = tag;
376
377 gtk_container_foreach(
378 GTK_CONTAINER(menu),
379 reinterpret_cast<void (*)(GtkWidget*, void*)>(ClearMenuCallback),
380 &closure);
381 }
382
383 // static
384 void GlobalHistoryMenu::GetIndexCallback(GtkWidget* menu_item,
385 GetIndexClosure* closure) {
386 int tag = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menu_item), "type-tag"));
387 if (tag == closure->tag)
388 closure->found = true;
389
390 if (!closure->found)
391 closure->current_index++;
392 }
393
394 // static
395 void GlobalHistoryMenu::ClearMenuCallback(GtkWidget* menu_item,
396 ClearMenuClosure* closure) {
397 DCHECK_NE(closure->tag, 0);
398
399 int tag = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menu_item), "type-tag"));
400 if (closure->tag == tag) {
401 HistoryItem* item = closure->menu_bar->HistoryItemForMenuItem(menu_item);
402
403 if (item) {
404 closure->menu_bar->CancelFaviconRequest(item);
405 closure->menu_bar->menu_item_history_map_.erase(menu_item);
406 delete item;
407 }
408
409 GtkWidget* submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu_item));
410 if (submenu)
411 closure->menu_bar->ClearMenuSection(submenu, closure->tag);
412
413 gtk_container_remove(GTK_CONTAINER(closure->container), menu_item);
414 }
415 }
416
417 void GlobalHistoryMenu::Observe(NotificationType type,
418 const NotificationSource& source,
419 const NotificationDetails& details) {
420 if (type.value == NotificationType::BROWSER_THEME_CHANGED) {
421 // Keeping track of which menu items have the default icon is going an
422 // error-prone pain, so instead just store the new default favicon and
423 // we'll update on the next menu change event.
424 default_favicon_ = GtkThemeService::GetDefaultFavicon(true);
425 } else {
426 // A history service is now ready. Check to see if it's the one for the
427 // main profile. If so, perform final initialization.
428 if (type == NotificationType::HISTORY_LOADED) {
429 HistoryService* hs =
430 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
431 if (hs != NULL && hs->BackendLoaded()) {
432 history_service_ = hs;
433 InitHistoryService();
434
435 // Found our HistoryService, so stop listening for this notification.
436 registrar_.Remove(this,
437 NotificationType::HISTORY_LOADED,
438 NotificationService::AllSources());
439 }
440 }
441
442 // All other notification types that we observe indicate that the history
443 // has changed and we need to rebuild.
444 need_recreate_ = true;
445 CreateMostVisited();
446 }
447 }
448
449 void GlobalHistoryMenu::TabRestoreServiceChanged(TabRestoreService* service) {
450 const TabRestoreService::Entries& entries = service->entries();
451
452 ClearMenuSection(history_menu_, GlobalMenuBar::TAG_RECENTLY_CLOSED);
453
454 // We'll get the index the "Recently Closed" header. (This can vary depending
455 // on the number of "Most Visited" items.
456 int index = GetIndexOfMenuItemWithTag(
457 history_menu_,
458 GlobalMenuBar::TAG_RECENTLY_CLOSED_HEADER) + 1;
459
460 unsigned int added_count = 0;
461 for (TabRestoreService::Entries::const_iterator it = entries.begin();
462 it != entries.end() && added_count < kRecentlyClosedCount; ++it) {
463 TabRestoreService::Entry* entry = *it;
464
465 if (entry->type == TabRestoreService::WINDOW) {
466 TabRestoreService::Window* entry_win =
467 static_cast<TabRestoreService::Window*>(entry);
468 std::vector<TabRestoreService::Tab>& tabs = entry_win->tabs;
469 if (tabs.empty())
470 continue;
471
472 // Check that this window has valid content. Sometimes it is possible for
473 // there to not be any subitems for a given window; if that is the case,
474 // do not add the entry to the main menu.
475 int valid_tab_count = 0;
476 std::vector<TabRestoreService::Tab>::const_iterator it;
477 for (it = tabs.begin(); it != tabs.end(); ++it) {
478 if (HasValidHistoryItemForTab(*it))
479 valid_tab_count++;
480 }
481 if (valid_tab_count == 0)
482 continue;
483
484 // Create the item for the parent/window. Do not set the title yet
485 // because the actual number of items that are in the menu will not be
486 // known until things like the NTP are filtered out, which is done when
487 // the tab items are actually created.
488 HistoryItem* item = new HistoryItem();
489 item->session_id = entry_win->id;
490
491 GtkWidget* submenu = gtk_menu_new();
492
493 GtkWidget* restore_item = gtk_menu_item_new_with_label(
494 l10n_util::GetStringUTF8(
495 IDS_HISTORY_CLOSED_RESTORE_WINDOW_LINUX).c_str());
496 g_object_set_data(G_OBJECT(restore_item), "type-tag",
497 GINT_TO_POINTER(GlobalMenuBar::TAG_RECENTLY_CLOSED));
498 g_signal_connect(restore_item, "activate",
499 G_CALLBACK(OnRecentlyClosedItemActivatedThunk), this);
500 gtk_widget_show(restore_item);
501
502 // The mac version of this code allows the user to click on the parent
503 // menu item to have the same effect as clicking the restore window
504 // submenu item. GTK+ helpfully activates a menu item when it shows a
505 // submenu so toss that feature out.
506 menu_item_history_map_.insert(std::make_pair(restore_item, item));
507 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), restore_item);
508
509 GtkWidget* separator = gtk_separator_menu_item_new();
510 gtk_widget_show(separator);
511 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), separator);
512
513 // Loop over the window's tabs and add them to the submenu.
514 int subindex = 2;
515 for (it = tabs.begin(); it != tabs.end(); ++it) {
516 TabRestoreService::Tab tab = *it;
517 HistoryItem* tab_item = HistoryItemForTab(tab);
518 if (tab_item) {
519 item->tabs.push_back(tab_item);
520 AddHistoryItemToMenu(tab_item,
521 submenu,
522 GlobalMenuBar::TAG_RECENTLY_CLOSED,
523 subindex++);
524 }
525 }
526
527 // Now that the number of tabs that has been added is known, set the
528 // title of the parent menu item.
529 std::string title =
530 (item->tabs.size() == 1) ?
531 l10n_util::GetStringUTF8(
532 IDS_NEW_TAB_RECENTLY_CLOSED_WINDOW_SINGLE) :
533 l10n_util::GetStringFUTF8(
534 IDS_NEW_TAB_RECENTLY_CLOSED_WINDOW_MULTIPLE,
535 base::IntToString16(item->tabs.size()));
536
537 // Create the menu item parent. Unlike mac, it's can't be activated.
538 GtkWidget* parent_item = gtk_image_menu_item_new_with_label(
539 title.c_str());
540 gtk_widget_show(parent_item);
541 g_object_set_data(G_OBJECT(parent_item), "type-tag",
542 GINT_TO_POINTER(GlobalMenuBar::TAG_RECENTLY_CLOSED));
543 gtk_menu_item_set_submenu(GTK_MENU_ITEM(parent_item), submenu);
544
545 gtk_menu_shell_insert(GTK_MENU_SHELL(history_menu_), parent_item,
546 index++);
547 ++added_count;
548 } else if (entry->type == TabRestoreService::TAB) {
549 TabRestoreService::Tab* tab =
550 static_cast<TabRestoreService::Tab*>(entry);
551 HistoryItem* item = HistoryItemForTab(*tab);
552 if (item) {
553 AddHistoryItemToMenu(item,
554 history_menu_,
555 GlobalMenuBar::TAG_RECENTLY_CLOSED,
556 index++);
557 ++added_count;
558 }
559 }
560 }
561 }
562
563 void GlobalHistoryMenu::TabRestoreServiceDestroyed(
564 TabRestoreService* service) {
565 tab_restore_service_ = NULL;
566 }
567
568 void GlobalHistoryMenu::OnRecentlyClosedItemActivated(GtkWidget* sender) {
569 WindowOpenDisposition disposition =
570 gtk_util::DispositionForCurrentButtonPressEvent();
571 HistoryItem* item = HistoryItemForMenuItem(sender);
572
573 // If this item can be restored using TabRestoreService, do so. Otherwise,
574 // just load the URL.
575 TabRestoreService* service = browser_->profile()->GetTabRestoreService();
576 if (item->session_id && service) {
577 service->RestoreEntryById(browser_->tab_restore_service_delegate(),
578 item->session_id, false);
579 } else {
580 DCHECK(item->url.is_valid());
581 browser_->OpenURL(item->url, GURL(), disposition,
582 PageTransition::AUTO_BOOKMARK);
583 }
584 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/gtk/global_history_menu.h ('k') | chrome/browser/ui/gtk/global_menu_bar.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698