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

Side by Side Diff: chrome/browser/jumplist_win.cc

Issue 2098713003: Moved a bunch of win-specific files to the new win folder in chrome/browser (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 4 years, 5 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
« no previous file with comments | « chrome/browser/jumplist_win.h ('k') | chrome/browser/private_working_set_snapshot.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 2012 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/jumplist_win.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/command_line.h"
10 #include "base/files/file_util.h"
11 #include "base/macros.h"
12 #include "base/path_service.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/threading/thread.h"
16 #include "base/trace_event/trace_event.h"
17 #include "chrome/browser/chrome_notification_types.h"
18 #include "chrome/browser/favicon/favicon_service_factory.h"
19 #include "chrome/browser/history/top_sites_factory.h"
20 #include "chrome/browser/metrics/jumplist_metrics_win.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/sessions/tab_restore_service_factory.h"
23 #include "chrome/browser/shell_integration_win.h"
24 #include "chrome/common/chrome_constants.h"
25 #include "chrome/common/chrome_switches.h"
26 #include "chrome/common/pref_names.h"
27 #include "chrome/common/url_constants.h"
28 #include "chrome/grit/generated_resources.h"
29 #include "components/favicon/core/favicon_service.h"
30 #include "components/favicon_base/favicon_types.h"
31 #include "components/history/core/browser/history_service.h"
32 #include "components/history/core/browser/page_usage_data.h"
33 #include "components/history/core/browser/top_sites.h"
34 #include "components/prefs/pref_change_registrar.h"
35 #include "components/sessions/core/session_types.h"
36 #include "components/sessions/core/tab_restore_service.h"
37 #include "components/strings/grit/components_strings.h"
38 #include "content/public/browser/browser_thread.h"
39 #include "content/public/browser/notification_registrar.h"
40 #include "content/public/browser/notification_source.h"
41 #include "ui/base/l10n/l10n_util.h"
42 #include "ui/gfx/codec/png_codec.h"
43 #include "ui/gfx/favicon_size.h"
44 #include "ui/gfx/icon_util.h"
45 #include "ui/gfx/image/image_family.h"
46 #include "url/gurl.h"
47
48 using content::BrowserThread;
49 using JumpListData = JumpList::JumpListData;
50
51 namespace {
52
53 // Delay jumplist updates to allow collapsing of redundant update requests.
54 const int kDelayForJumplistUpdateInMS = 3500;
55
56 // Append the common switches to each shell link.
57 void AppendCommonSwitches(ShellLinkItem* shell_link) {
58 const char* kSwitchNames[] = { switches::kUserDataDir };
59 const base::CommandLine& command_line =
60 *base::CommandLine::ForCurrentProcess();
61 shell_link->GetCommandLine()->CopySwitchesFrom(command_line,
62 kSwitchNames,
63 arraysize(kSwitchNames));
64 }
65
66 // Create a ShellLinkItem preloaded with common switches.
67 scoped_refptr<ShellLinkItem> CreateShellLink() {
68 scoped_refptr<ShellLinkItem> link(new ShellLinkItem);
69 AppendCommonSwitches(link.get());
70 return link;
71 }
72
73 // Creates a temporary icon file to be shown in JumpList.
74 bool CreateIconFile(const SkBitmap& bitmap,
75 const base::FilePath& icon_dir,
76 base::FilePath* icon_path) {
77 // Retrieve the path to a temporary file.
78 // We don't have to care about the extension of this temporary file because
79 // JumpList does not care about it.
80 base::FilePath path;
81 if (!base::CreateTemporaryFileInDir(icon_dir, &path))
82 return false;
83
84 // Create an icon file from the favicon attached to the given |page|, and
85 // save it as the temporary file.
86 gfx::ImageFamily image_family;
87 image_family.Add(gfx::Image::CreateFrom1xBitmap(bitmap));
88 if (!IconUtil::CreateIconFileFromImageFamily(image_family, path,
89 IconUtil::NORMAL_WRITE))
90 return false;
91
92 // Add this icon file to the list and return its absolute path.
93 // The IShellLink::SetIcon() function needs the absolute path to an icon.
94 *icon_path = path;
95 return true;
96 }
97
98 // Helper method for RunUpdate to create icon files for the asynchrounously
99 // loaded icons.
100 void CreateIconFiles(const base::FilePath& icon_dir,
101 const ShellLinkItemList& item_list) {
102 for (ShellLinkItemList::const_iterator item = item_list.begin();
103 item != item_list.end(); ++item) {
104 base::FilePath icon_path;
105 if (CreateIconFile((*item)->icon_data(), icon_dir, &icon_path))
106 (*item)->set_icon(icon_path.value(), 0);
107 }
108 }
109
110 // Updates the "Tasks" category of the JumpList.
111 bool UpdateTaskCategory(
112 JumpListUpdater* jumplist_updater,
113 IncognitoModePrefs::Availability incognito_availability) {
114 base::FilePath chrome_path;
115 if (!PathService::Get(base::FILE_EXE, &chrome_path))
116 return false;
117
118 ShellLinkItemList items;
119
120 // Create an IShellLink object which launches Chrome, and add it to the
121 // collection. We use our application icon as the icon for this item.
122 // We remove '&' characters from this string so we can share it with our
123 // system menu.
124 if (incognito_availability != IncognitoModePrefs::FORCED) {
125 scoped_refptr<ShellLinkItem> chrome = CreateShellLink();
126 base::string16 chrome_title = l10n_util::GetStringUTF16(IDS_NEW_WINDOW);
127 base::ReplaceSubstringsAfterOffset(
128 &chrome_title, 0, L"&", base::StringPiece16());
129 chrome->set_title(chrome_title);
130 chrome->set_icon(chrome_path.value(), 0);
131 items.push_back(chrome);
132 }
133
134 // Create an IShellLink object which launches Chrome in incognito mode, and
135 // add it to the collection. We use our application icon as the icon for
136 // this item.
137 if (incognito_availability != IncognitoModePrefs::DISABLED) {
138 scoped_refptr<ShellLinkItem> incognito = CreateShellLink();
139 incognito->GetCommandLine()->AppendSwitch(switches::kIncognito);
140 base::string16 incognito_title =
141 l10n_util::GetStringUTF16(IDS_NEW_INCOGNITO_WINDOW);
142 base::ReplaceSubstringsAfterOffset(
143 &incognito_title, 0, L"&", base::StringPiece16());
144 incognito->set_title(incognito_title);
145 incognito->set_icon(chrome_path.value(), 0);
146 items.push_back(incognito);
147 }
148
149 return jumplist_updater->AddTasks(items);
150 }
151
152 // Updates the application JumpList.
153 bool UpdateJumpList(const wchar_t* app_id,
154 const ShellLinkItemList& most_visited_pages,
155 const ShellLinkItemList& recently_closed_pages,
156 IncognitoModePrefs::Availability incognito_availability) {
157 // JumpList is implemented only on Windows 7 or later.
158 // So, we should return now when this function is called on earlier versions
159 // of Windows.
160 if (!JumpListUpdater::IsEnabled())
161 return true;
162
163 JumpListUpdater jumplist_updater(app_id);
164 if (!jumplist_updater.BeginUpdate())
165 return false;
166
167 // We allocate 60% of the given JumpList slots to "most-visited" items
168 // and 40% to "recently-closed" items, respectively.
169 // Nevertheless, if there are not so many items in |recently_closed_pages|,
170 // we give the remaining slots to "most-visited" items.
171 const int kMostVisited = 60;
172 const int kRecentlyClosed = 40;
173 const int kTotal = kMostVisited + kRecentlyClosed;
174 size_t most_visited_items =
175 MulDiv(jumplist_updater.user_max_items(), kMostVisited, kTotal);
176 size_t recently_closed_items =
177 jumplist_updater.user_max_items() - most_visited_items;
178 if (recently_closed_pages.size() < recently_closed_items) {
179 most_visited_items += recently_closed_items - recently_closed_pages.size();
180 recently_closed_items = recently_closed_pages.size();
181 }
182
183 // Update the "Most Visited" category of the JumpList if it exists.
184 // This update request is applied into the JumpList when we commit this
185 // transaction.
186 if (!jumplist_updater.AddCustomCategory(
187 l10n_util::GetStringUTF16(IDS_NEW_TAB_MOST_VISITED),
188 most_visited_pages, most_visited_items)) {
189 return false;
190 }
191
192 // Update the "Recently Closed" category of the JumpList.
193 if (!jumplist_updater.AddCustomCategory(
194 l10n_util::GetStringUTF16(IDS_RECENTLY_CLOSED),
195 recently_closed_pages, recently_closed_items)) {
196 return false;
197 }
198
199 // Update the "Tasks" category of the JumpList.
200 if (!UpdateTaskCategory(&jumplist_updater, incognito_availability))
201 return false;
202
203 // Commit this transaction and send the updated JumpList to Windows.
204 if (!jumplist_updater.CommitUpdate())
205 return false;
206
207 return true;
208 }
209
210 // Updates the jumplist, once all the data has been fetched.
211 void RunUpdateOnFileThread(
212 IncognitoModePrefs::Availability incognito_availability,
213 const std::wstring& app_id,
214 const base::FilePath& icon_dir,
215 base::RefCountedData<JumpListData>* ref_counted_data) {
216 JumpListData* data = &ref_counted_data->data;
217 ShellLinkItemList local_most_visited_pages;
218 ShellLinkItemList local_recently_closed_pages;
219
220 {
221 base::AutoLock auto_lock(data->list_lock_);
222 // Make sure we are not out of date: if icon_urls_ is not empty, then
223 // another notification has been received since we processed this one
224 if (!data->icon_urls_.empty())
225 return;
226
227 // Make local copies of lists so we can release the lock.
228 local_most_visited_pages = data->most_visited_pages_;
229 local_recently_closed_pages = data->recently_closed_pages_;
230 }
231
232 // Delete the directory which contains old icon files, rename the current
233 // icon directory, and create a new directory which contains new JumpList
234 // icon files.
235 base::FilePath icon_dir_old(icon_dir.value() + L"Old");
236 if (base::PathExists(icon_dir_old))
237 base::DeleteFile(icon_dir_old, true);
238 base::Move(icon_dir, icon_dir_old);
239 base::CreateDirectory(icon_dir);
240
241 // Create temporary icon files for shortcuts in the "Most Visited" category.
242 CreateIconFiles(icon_dir, local_most_visited_pages);
243
244 // Create temporary icon files for shortcuts in the "Recently Closed"
245 // category.
246 CreateIconFiles(icon_dir, local_recently_closed_pages);
247
248 // We finished collecting all resources needed for updating an application
249 // JumpList. So, create a new JumpList and replace the current JumpList
250 // with it.
251 UpdateJumpList(app_id.c_str(),
252 local_most_visited_pages,
253 local_recently_closed_pages,
254 incognito_availability);
255 }
256
257 } // namespace
258
259 JumpList::JumpListData::JumpListData() {}
260
261 JumpList::JumpListData::~JumpListData() {}
262
263 JumpList::JumpList(Profile* profile)
264 : profile_(profile),
265 jumplist_data_(new base::RefCountedData<JumpListData>),
266 task_id_(base::CancelableTaskTracker::kBadTaskId),
267 weak_ptr_factory_(this) {
268 DCHECK(Enabled());
269 // To update JumpList when a tab is added or removed, we add this object to
270 // the observer list of the TabRestoreService class.
271 // When we add this object to the observer list, we save the pointer to this
272 // TabRestoreService object. This pointer is used when we remove this object
273 // from the observer list.
274 sessions::TabRestoreService* tab_restore_service =
275 TabRestoreServiceFactory::GetForProfile(profile_);
276 if (!tab_restore_service)
277 return;
278
279 app_id_ =
280 shell_integration::win::GetChromiumModelIdForProfile(profile_->GetPath());
281 icon_dir_ = profile_->GetPath().Append(chrome::kJumpListIconDirname);
282
283 scoped_refptr<history::TopSites> top_sites =
284 TopSitesFactory::GetForProfile(profile_);
285 if (top_sites) {
286 // TopSites updates itself after a delay. This is especially noticable when
287 // your profile is empty. Ask TopSites to update itself when jumplist is
288 // initialized.
289 top_sites->SyncWithHistory();
290 registrar_.reset(new content::NotificationRegistrar);
291 // Register as TopSitesObserver so that we can update ourselves when the
292 // TopSites changes.
293 top_sites->AddObserver(this);
294 // Register for notification when profile is destroyed to ensure that all
295 // observers are detatched at that time.
296 registrar_->Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
297 content::Source<Profile>(profile_));
298 }
299 tab_restore_service->AddObserver(this);
300 pref_change_registrar_.reset(new PrefChangeRegistrar);
301 pref_change_registrar_->Init(profile_->GetPrefs());
302 pref_change_registrar_->Add(
303 prefs::kIncognitoModeAvailability,
304 base::Bind(&JumpList::OnIncognitoAvailabilityChanged, this));
305 }
306
307 JumpList::~JumpList() {
308 DCHECK(CalledOnValidThread());
309 Terminate();
310 }
311
312 // static
313 bool JumpList::Enabled() {
314 return JumpListUpdater::IsEnabled();
315 }
316
317 void JumpList::Observe(int type,
318 const content::NotificationSource& source,
319 const content::NotificationDetails& details) {
320 DCHECK(CalledOnValidThread());
321 DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED, type);
322 // Profile was destroyed, do clean-up.
323 Terminate();
324 }
325
326 void JumpList::CancelPendingUpdate() {
327 DCHECK(CalledOnValidThread());
328 if (task_id_ != base::CancelableTaskTracker::kBadTaskId) {
329 cancelable_task_tracker_.TryCancel(task_id_);
330 task_id_ = base::CancelableTaskTracker::kBadTaskId;
331 }
332 }
333
334 void JumpList::Terminate() {
335 DCHECK(CalledOnValidThread());
336 CancelPendingUpdate();
337 if (profile_) {
338 sessions::TabRestoreService* tab_restore_service =
339 TabRestoreServiceFactory::GetForProfile(profile_);
340 if (tab_restore_service)
341 tab_restore_service->RemoveObserver(this);
342 scoped_refptr<history::TopSites> top_sites =
343 TopSitesFactory::GetForProfile(profile_);
344 if (top_sites)
345 top_sites->RemoveObserver(this);
346 registrar_.reset();
347 pref_change_registrar_.reset();
348 }
349 profile_ = NULL;
350 }
351
352 void JumpList::OnMostVisitedURLsAvailable(
353 const history::MostVisitedURLList& urls) {
354 DCHECK(CalledOnValidThread());
355 // If we have a pending favicon request, cancel it here (it is out of date).
356 CancelPendingUpdate();
357
358 {
359 JumpListData* data = &jumplist_data_->data;
360 base::AutoLock auto_lock(data->list_lock_);
361 data->most_visited_pages_.clear();
362 for (size_t i = 0; i < urls.size(); i++) {
363 const history::MostVisitedURL& url = urls[i];
364 scoped_refptr<ShellLinkItem> link = CreateShellLink();
365 std::string url_string = url.url.spec();
366 std::wstring url_string_wide = base::UTF8ToWide(url_string);
367 link->GetCommandLine()->AppendArgNative(url_string_wide);
368 link->GetCommandLine()->AppendSwitchASCII(
369 switches::kWinJumplistAction, jumplist::kMostVisitedCategory);
370 link->set_title(!url.title.empty() ? url.title : url_string_wide);
371 data->most_visited_pages_.push_back(link);
372 data->icon_urls_.push_back(make_pair(url_string, link));
373 }
374 }
375
376 // Send a query that retrieves the first favicon.
377 StartLoadingFavicon();
378 }
379
380 void JumpList::TabRestoreServiceChanged(sessions::TabRestoreService* service) {
381 DCHECK(CalledOnValidThread());
382 // if we have a pending handle request, cancel it here (it is out of date).
383 CancelPendingUpdate();
384
385 // local list to pass to methods
386 ShellLinkItemList temp_list;
387
388 // Create a list of ShellLinkItems from the "Recently Closed" pages.
389 // As noted above, we create a ShellLinkItem objects with the following
390 // parameters.
391 // * arguments
392 // The last URL of the tab object.
393 // * title
394 // The title of the last URL.
395 // * icon
396 // An empty string. This value is to be updated in OnFaviconDataAvailable().
397 // This code is copied from
398 // RecentlyClosedTabsHandler::TabRestoreServiceChanged() to emulate it.
399 const int kRecentlyClosedCount = 4;
400 sessions::TabRestoreService* tab_restore_service =
401 TabRestoreServiceFactory::GetForProfile(profile_);
402 const sessions::TabRestoreService::Entries& entries =
403 tab_restore_service->entries();
404 for (sessions::TabRestoreService::Entries::const_iterator it =
405 entries.begin();
406 it != entries.end(); ++it) {
407 const sessions::TabRestoreService::Entry* entry = *it;
408 if (entry->type == sessions::TabRestoreService::TAB) {
409 AddTab(static_cast<const sessions::TabRestoreService::Tab*>(entry),
410 &temp_list, kRecentlyClosedCount);
411 } else if (entry->type == sessions::TabRestoreService::WINDOW) {
412 AddWindow(static_cast<const sessions::TabRestoreService::Window*>(entry),
413 &temp_list, kRecentlyClosedCount);
414 }
415 }
416 // Lock recently_closed_pages and copy temp_list into it.
417 {
418 JumpListData* data = &jumplist_data_->data;
419 base::AutoLock auto_lock(data->list_lock_);
420 data->recently_closed_pages_ = temp_list;
421 }
422
423 // Send a query that retrieves the first favicon.
424 StartLoadingFavicon();
425 }
426
427 void JumpList::TabRestoreServiceDestroyed(
428 sessions::TabRestoreService* service) {}
429
430 bool JumpList::AddTab(const sessions::TabRestoreService::Tab* tab,
431 ShellLinkItemList* list,
432 size_t max_items) {
433 DCHECK(CalledOnValidThread());
434
435 // This code adds the URL and the title strings of the given tab to the
436 // specified list.
437 if (list->size() >= max_items)
438 return false;
439
440 scoped_refptr<ShellLinkItem> link = CreateShellLink();
441 const sessions::SerializedNavigationEntry& current_navigation =
442 tab->navigations.at(tab->current_navigation_index);
443 std::string url = current_navigation.virtual_url().spec();
444 link->GetCommandLine()->AppendArgNative(base::UTF8ToWide(url));
445 link->GetCommandLine()->AppendSwitchASCII(
446 switches::kWinJumplistAction, jumplist::kRecentlyClosedCategory);
447 link->set_title(current_navigation.title());
448 list->push_back(link);
449 {
450 JumpListData* data = &jumplist_data_->data;
451 base::AutoLock auto_lock(data->list_lock_);
452 data->icon_urls_.push_back(std::make_pair(std::move(url), std::move(link)));
453 }
454 return true;
455 }
456
457 void JumpList::AddWindow(const sessions::TabRestoreService::Window* window,
458 ShellLinkItemList* list,
459 size_t max_items) {
460 DCHECK(CalledOnValidThread());
461
462 // This code enumerates al the tabs in the given window object and add their
463 // URLs and titles to the list.
464 DCHECK(!window->tabs.empty());
465
466 for (size_t i = 0; i < window->tabs.size(); ++i) {
467 if (!AddTab(&window->tabs[i], list, max_items))
468 return;
469 }
470 }
471
472 void JumpList::StartLoadingFavicon() {
473 DCHECK(CalledOnValidThread());
474
475 GURL url;
476 bool waiting_for_icons = true;
477 {
478 JumpListData* data = &jumplist_data_->data;
479 base::AutoLock auto_lock(data->list_lock_);
480 waiting_for_icons = !data->icon_urls_.empty();
481 if (waiting_for_icons) {
482 // Ask FaviconService if it has a favicon of a URL.
483 // When FaviconService has one, it will call OnFaviconDataAvailable().
484 url = GURL(data->icon_urls_.front().first);
485 }
486 }
487
488 if (!waiting_for_icons) {
489 // No more favicons are needed by the application JumpList. Schedule a
490 // RunUpdateOnFileThread call.
491 PostRunUpdate();
492 return;
493 }
494
495 favicon::FaviconService* favicon_service =
496 FaviconServiceFactory::GetForProfile(profile_,
497 ServiceAccessType::EXPLICIT_ACCESS);
498 task_id_ = favicon_service->GetFaviconImageForPageURL(
499 url,
500 base::Bind(&JumpList::OnFaviconDataAvailable, base::Unretained(this)),
501 &cancelable_task_tracker_);
502 }
503
504 void JumpList::OnFaviconDataAvailable(
505 const favicon_base::FaviconImageResult& image_result) {
506 DCHECK(CalledOnValidThread());
507
508 // If there is currently a favicon request in progress, it is now outdated,
509 // as we have received another, so nullify the handle from the old request.
510 task_id_ = base::CancelableTaskTracker::kBadTaskId;
511 // Lock the list to set icon data and pop the url.
512 {
513 JumpListData* data = &jumplist_data_->data;
514 base::AutoLock auto_lock(data->list_lock_);
515 // Attach the received data to the ShellLinkItem object.
516 // This data will be decoded by the RunUpdateOnFileThread method.
517 if (!image_result.image.IsEmpty()) {
518 if (!data->icon_urls_.empty() && data->icon_urls_.front().second.get())
519 data->icon_urls_.front().second->set_icon_data(
520 image_result.image.AsBitmap());
521 }
522
523 if (!data->icon_urls_.empty())
524 data->icon_urls_.pop_front();
525 }
526 // Check whether we need to load more favicons.
527 StartLoadingFavicon();
528 }
529
530 void JumpList::OnIncognitoAvailabilityChanged() {
531 DCHECK(CalledOnValidThread());
532
533 bool waiting_for_icons = true;
534 {
535 JumpListData* data = &jumplist_data_->data;
536 base::AutoLock auto_lock(data->list_lock_);
537 waiting_for_icons = !data->icon_urls_.empty();
538 }
539 if (!waiting_for_icons)
540 PostRunUpdate();
541 // If |icon_urls_| isn't empty then OnFaviconDataAvailable will eventually
542 // call PostRunUpdate().
543 }
544
545 void JumpList::PostRunUpdate() {
546 DCHECK(CalledOnValidThread());
547
548 TRACE_EVENT0("browser", "JumpList::PostRunUpdate");
549 // Initialize the one-shot timer to update the jumplists in a while.
550 // If there is already a request queued then cancel it and post the new
551 // request. This ensures that JumpListUpdates won't happen until there has
552 // been a brief quiet period, thus avoiding update storms.
553 if (timer_.IsRunning()) {
554 timer_.Reset();
555 } else {
556 timer_.Start(FROM_HERE,
557 base::TimeDelta::FromMilliseconds(kDelayForJumplistUpdateInMS),
558 this,
559 &JumpList::DeferredRunUpdate);
560 }
561 }
562
563 void JumpList::DeferredRunUpdate() {
564 DCHECK(CalledOnValidThread());
565
566 TRACE_EVENT0("browser", "JumpList::DeferredRunUpdate");
567 // Check if incognito windows (or normal windows) are disabled by policy.
568 IncognitoModePrefs::Availability incognito_availability =
569 profile_ ? IncognitoModePrefs::GetAvailability(profile_->GetPrefs())
570 : IncognitoModePrefs::ENABLED;
571
572 BrowserThread::PostTask(
573 BrowserThread::FILE, FROM_HERE,
574 base::Bind(&RunUpdateOnFileThread,
575 incognito_availability,
576 app_id_,
577 icon_dir_,
578 base::RetainedRef(jumplist_data_)));
579 }
580
581 void JumpList::TopSitesLoaded(history::TopSites* top_sites) {
582 }
583
584 void JumpList::TopSitesChanged(history::TopSites* top_sites,
585 ChangeReason change_reason) {
586 top_sites->GetMostVisitedURLs(
587 base::Bind(&JumpList::OnMostVisitedURLsAvailable,
588 weak_ptr_factory_.GetWeakPtr()),
589 false);
590 }
OLDNEW
« no previous file with comments | « chrome/browser/jumplist_win.h ('k') | chrome/browser/private_working_set_snapshot.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698