OLD | NEW |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 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 | 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/jumplist_win.h" | 5 #include "chrome/browser/jumplist_win.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
10 #include "base/files/file_util.h" | 10 #include "base/files/file_util.h" |
11 #include "base/metrics/field_trial.h" | |
12 #include "base/path_service.h" | 11 #include "base/path_service.h" |
13 #include "base/prefs/pref_change_registrar.h" | 12 #include "base/prefs/pref_change_registrar.h" |
14 #include "base/strings/string_util.h" | 13 #include "base/strings/string_util.h" |
15 #include "base/strings/utf_string_conversions.h" | 14 #include "base/strings/utf_string_conversions.h" |
16 #include "base/threading/thread.h" | 15 #include "base/threading/thread.h" |
17 #include "chrome/browser/browser_process.h" | |
18 #include "chrome/browser/chrome_notification_types.h" | 16 #include "chrome/browser/chrome_notification_types.h" |
19 #include "chrome/browser/favicon/favicon_service.h" | 17 #include "chrome/browser/favicon/favicon_service.h" |
20 #include "chrome/browser/favicon/favicon_service_factory.h" | 18 #include "chrome/browser/favicon/favicon_service_factory.h" |
21 #include "chrome/browser/history/history_service.h" | 19 #include "chrome/browser/history/history_service.h" |
22 #include "chrome/browser/history/top_sites_factory.h" | 20 #include "chrome/browser/history/top_sites_factory.h" |
23 #include "chrome/browser/metrics/jumplist_metrics_win.h" | 21 #include "chrome/browser/metrics/jumplist_metrics_win.h" |
24 #include "chrome/browser/profiles/profile.h" | 22 #include "chrome/browser/profiles/profile.h" |
25 #include "chrome/browser/profiles/profile_info_cache.h" | |
26 #include "chrome/browser/profiles/profile_manager.h" | |
27 #include "chrome/browser/sessions/tab_restore_service.h" | 23 #include "chrome/browser/sessions/tab_restore_service.h" |
28 #include "chrome/browser/sessions/tab_restore_service_factory.h" | 24 #include "chrome/browser/sessions/tab_restore_service_factory.h" |
29 #include "chrome/browser/shell_integration.h" | 25 #include "chrome/browser/shell_integration.h" |
30 #include "chrome/common/chrome_constants.h" | 26 #include "chrome/common/chrome_constants.h" |
31 #include "chrome/common/chrome_switches.h" | 27 #include "chrome/common/chrome_switches.h" |
32 #include "chrome/common/pref_names.h" | 28 #include "chrome/common/pref_names.h" |
33 #include "chrome/common/url_constants.h" | 29 #include "chrome/common/url_constants.h" |
34 #include "chrome/grit/generated_resources.h" | 30 #include "chrome/grit/generated_resources.h" |
35 #include "components/favicon_base/favicon_types.h" | 31 #include "components/favicon_base/favicon_types.h" |
36 #include "components/history/core/browser/page_usage_data.h" | 32 #include "components/history/core/browser/page_usage_data.h" |
37 #include "components/history/core/browser/top_sites.h" | 33 #include "components/history/core/browser/top_sites.h" |
38 #include "components/sessions/session_types.h" | 34 #include "components/sessions/session_types.h" |
39 #include "components/signin/core/common/profile_management_switches.h" | |
40 #include "content/public/browser/browser_thread.h" | 35 #include "content/public/browser/browser_thread.h" |
41 #include "content/public/browser/notification_source.h" | 36 #include "content/public/browser/notification_source.h" |
42 #include "ui/base/l10n/l10n_util.h" | 37 #include "ui/base/l10n/l10n_util.h" |
43 #include "ui/gfx/codec/png_codec.h" | 38 #include "ui/gfx/codec/png_codec.h" |
44 #include "ui/gfx/favicon_size.h" | 39 #include "ui/gfx/favicon_size.h" |
45 #include "ui/gfx/icon_util.h" | 40 #include "ui/gfx/icon_util.h" |
46 #include "ui/gfx/image/image_family.h" | 41 #include "ui/gfx/image/image_family.h" |
47 #include "url/gurl.h" | 42 #include "url/gurl.h" |
48 | 43 |
49 using content::BrowserThread; | 44 using content::BrowserThread; |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
128 items.push_back(incognito); | 123 items.push_back(incognito); |
129 } | 124 } |
130 | 125 |
131 return jumplist_updater->AddTasks(items); | 126 return jumplist_updater->AddTasks(items); |
132 } | 127 } |
133 | 128 |
134 // Updates the application JumpList. | 129 // Updates the application JumpList. |
135 bool UpdateJumpList(const wchar_t* app_id, | 130 bool UpdateJumpList(const wchar_t* app_id, |
136 const ShellLinkItemList& most_visited_pages, | 131 const ShellLinkItemList& most_visited_pages, |
137 const ShellLinkItemList& recently_closed_pages, | 132 const ShellLinkItemList& recently_closed_pages, |
138 const ShellLinkItemList& profile_switcher, | 133 IncognitoModePrefs::Availability incognito_availability) { |
139 IncognitoModePrefs::Availability incognito_availability, | |
140 bool use_profiles_category) { | |
141 // JumpList is implemented only on Windows 7 or later. | 134 // JumpList is implemented only on Windows 7 or later. |
142 // So, we should return now when this function is called on earlier versions | 135 // So, we should return now when this function is called on earlier versions |
143 // of Windows. | 136 // of Windows. |
144 if (!JumpListUpdater::IsEnabled()) | 137 if (!JumpListUpdater::IsEnabled()) |
145 return true; | 138 return true; |
146 | 139 |
147 JumpListUpdater jumplist_updater(app_id); | 140 JumpListUpdater jumplist_updater(app_id); |
148 if (!jumplist_updater.BeginUpdate()) | 141 if (!jumplist_updater.BeginUpdate()) |
149 return false; | 142 return false; |
150 | 143 |
151 size_t recently_closed_items; | 144 // We allocate 60% of the given JumpList slots to "most-visited" items |
152 size_t profiles_or_most_visited_items; | 145 // and 40% to "recently-closed" items, respectively. |
153 | 146 // Nevertheless, if there are not so many items in |recently_closed_pages|, |
154 // Depending on the experiment, we are either showing the "Most-Visited" or | 147 // we give the remaining slots to "most-visited" items. |
155 // "People" categories. | 148 const int kMostVisited = 60; |
156 if (use_profiles_category) { | 149 const int kRecentlyClosed = 40; |
157 // Show at most 8 profiles, and fill the rest of the slots with the | 150 const int kTotal = kMostVisited + kRecentlyClosed; |
158 // "recently-closed" items. | 151 size_t most_visited_items = |
159 const size_t kMaxProfiles = 8; | 152 MulDiv(jumplist_updater.user_max_items(), kMostVisited, kTotal); |
160 size_t max_displayed_items = std::min(kMaxProfiles, | 153 size_t recently_closed_items = |
161 jumplist_updater.user_max_items()); | 154 jumplist_updater.user_max_items() - most_visited_items; |
162 profiles_or_most_visited_items = std::min(max_displayed_items, | 155 if (recently_closed_pages.size() < recently_closed_items) { |
163 profile_switcher.size()); | 156 most_visited_items += recently_closed_items - recently_closed_pages.size(); |
164 recently_closed_items = | 157 recently_closed_items = recently_closed_pages.size(); |
165 jumplist_updater.user_max_items() - profiles_or_most_visited_items; | |
166 } else { | |
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 profiles_or_most_visited_items = | |
175 MulDiv(jumplist_updater.user_max_items(), kMostVisited, kTotal); | |
176 recently_closed_items = | |
177 jumplist_updater.user_max_items() - profiles_or_most_visited_items; | |
178 if (recently_closed_pages.size() < recently_closed_items) { | |
179 profiles_or_most_visited_items += | |
180 recently_closed_items - recently_closed_pages.size(); | |
181 recently_closed_items = recently_closed_pages.size(); | |
182 } | |
183 } | 158 } |
184 | 159 |
185 // Update the "Most Visited" category of the JumpList if it exists. | 160 // Update the "Most Visited" category of the JumpList if it exists. |
186 // This update request is applied into the JumpList when we commit this | 161 // This update request is applied into the JumpList when we commit this |
187 // transaction. | 162 // transaction. |
188 if (!use_profiles_category && !jumplist_updater.AddCustomCategory( | 163 if (!jumplist_updater.AddCustomCategory( |
189 l10n_util::GetStringUTF16(IDS_NEW_TAB_MOST_VISITED), | 164 l10n_util::GetStringUTF16(IDS_NEW_TAB_MOST_VISITED), |
190 most_visited_pages, profiles_or_most_visited_items)) { | 165 most_visited_pages, most_visited_items)) { |
191 return false; | 166 return false; |
192 } | 167 } |
193 | 168 |
194 // Update the "Recently Closed" category of the JumpList. | 169 // Update the "Recently Closed" category of the JumpList. |
195 if (!jumplist_updater.AddCustomCategory( | 170 if (!jumplist_updater.AddCustomCategory( |
196 l10n_util::GetStringUTF16(IDS_NEW_TAB_RECENTLY_CLOSED), | 171 l10n_util::GetStringUTF16(IDS_NEW_TAB_RECENTLY_CLOSED), |
197 recently_closed_pages, recently_closed_items)) { | 172 recently_closed_pages, recently_closed_items)) { |
198 return false; | 173 return false; |
199 } | 174 } |
200 | 175 |
201 // Update the "People" category of the JumpList if it exists. Only display it | |
202 // if there's more than one profile available. | |
203 if (use_profiles_category && profile_switcher.size() > 1 && | |
204 !jumplist_updater.AddCustomCategory( | |
205 l10n_util::GetStringUTF16(IDS_PROFILES_OPTIONS_GROUP_NAME), | |
206 profile_switcher, profiles_or_most_visited_items)) { | |
207 return false; | |
208 } | |
209 | |
210 // Update the "Tasks" category of the JumpList. | 176 // Update the "Tasks" category of the JumpList. |
211 if (!UpdateTaskCategory(&jumplist_updater, incognito_availability)) | 177 if (!UpdateTaskCategory(&jumplist_updater, incognito_availability)) |
212 return false; | 178 return false; |
213 | 179 |
214 // Commit this transaction and send the updated JumpList to Windows. | 180 // Commit this transaction and send the updated JumpList to Windows. |
215 if (!jumplist_updater.CommitUpdate()) | 181 if (!jumplist_updater.CommitUpdate()) |
216 return false; | 182 return false; |
217 | 183 |
218 return true; | 184 return true; |
219 } | 185 } |
220 | 186 |
221 // Checks whether the experiment that replaces the Most Visited category | |
222 // with a Profiles list exists. | |
223 bool HasProfilesJumplistExperiment() { | |
224 const std::string group_name = | |
225 base::FieldTrialList::FindFullName("WindowsJumplistProfiles"); | |
226 return group_name == "UseProfiles"; | |
227 } | |
228 | |
229 } // namespace | 187 } // namespace |
230 | 188 |
231 JumpList::JumpList(Profile* profile) | 189 JumpList::JumpList(Profile* profile) |
232 : profile_(profile), | 190 : profile_(profile), |
233 task_id_(base::CancelableTaskTracker::kBadTaskId), | 191 task_id_(base::CancelableTaskTracker::kBadTaskId), |
234 weak_ptr_factory_(this), | 192 weak_ptr_factory_(this) { |
235 use_profiles_category_(false) { | |
236 DCHECK(Enabled()); | 193 DCHECK(Enabled()); |
237 // To update JumpList when a tab is added or removed, we add this object to | 194 // To update JumpList when a tab is added or removed, we add this object to |
238 // the observer list of the TabRestoreService class. | 195 // the observer list of the TabRestoreService class. |
239 // When we add this object to the observer list, we save the pointer to this | 196 // When we add this object to the observer list, we save the pointer to this |
240 // TabRestoreService object. This pointer is used when we remove this object | 197 // TabRestoreService object. This pointer is used when we remove this object |
241 // from the observer list. | 198 // from the observer list. |
242 TabRestoreService* tab_restore_service = | 199 TabRestoreService* tab_restore_service = |
243 TabRestoreServiceFactory::GetForProfile(profile_); | 200 TabRestoreServiceFactory::GetForProfile(profile_); |
244 if (!tab_restore_service) | 201 if (!tab_restore_service) |
245 return; | 202 return; |
246 | 203 |
247 app_id_ = ShellIntegration::GetChromiumModelIdForProfile(profile_->GetPath()); | 204 app_id_ = ShellIntegration::GetChromiumModelIdForProfile(profile_->GetPath()); |
248 icon_dir_ = profile_->GetPath().Append(chrome::kJumpListIconDirname); | 205 icon_dir_ = profile_->GetPath().Append(chrome::kJumpListIconDirname); |
249 use_profiles_category_ = HasProfilesJumplistExperiment(); | |
250 | 206 |
251 scoped_refptr<history::TopSites> top_sites = | 207 scoped_refptr<history::TopSites> top_sites = |
252 TopSitesFactory::GetForProfile(profile_); | 208 TopSitesFactory::GetForProfile(profile_); |
253 if (top_sites) { | 209 if (top_sites) { |
254 // TopSites updates itself after a delay. This is especially noticable when | 210 // TopSites updates itself after a delay. This is especially noticable when |
255 // your profile is empty. Ask TopSites to update itself when jumplist is | 211 // your profile is empty. Ask TopSites to update itself when jumplist is |
256 // initialized. | 212 // initialized. |
257 top_sites->SyncWithHistory(); | 213 top_sites->SyncWithHistory(); |
258 registrar_.reset(new content::NotificationRegistrar); | 214 registrar_.reset(new content::NotificationRegistrar); |
259 // Register as TopSitesObserver so that we can update ourselves when the | 215 // Register as TopSitesObserver so that we can update ourselves when the |
260 // TopSites changes. | 216 // TopSites changes. |
261 top_sites->AddObserver(this); | 217 top_sites->AddObserver(this); |
262 // Register for notification when profile is destroyed to ensure that all | 218 // Register for notification when profile is destroyed to ensure that all |
263 // observers are detatched at that time. | 219 // observers are detatched at that time. |
264 registrar_->Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, | 220 registrar_->Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, |
265 content::Source<Profile>(profile_)); | 221 content::Source<Profile>(profile_)); |
266 } | 222 } |
267 tab_restore_service->AddObserver(this); | 223 tab_restore_service->AddObserver(this); |
268 pref_change_registrar_.reset(new PrefChangeRegistrar); | 224 pref_change_registrar_.reset(new PrefChangeRegistrar); |
269 pref_change_registrar_->Init(profile_->GetPrefs()); | 225 pref_change_registrar_->Init(profile_->GetPrefs()); |
270 pref_change_registrar_->Add( | 226 pref_change_registrar_->Add( |
271 prefs::kIncognitoModeAvailability, | 227 prefs::kIncognitoModeAvailability, |
272 base::Bind(&JumpList::OnIncognitoAvailabilityChanged, this)); | 228 base::Bind(&JumpList::OnIncognitoAvailabilityChanged, this)); |
273 | |
274 ProfileManager* profile_manager = g_browser_process->profile_manager(); | |
275 avatar_menu_.reset(new AvatarMenu( | |
276 &profile_manager->GetProfileInfoCache(), this, NULL)); | |
277 if (use_profiles_category_) { | |
278 avatar_menu_->RebuildMenu(); | |
279 UpdateProfileSwitcher(); | |
280 } | |
281 } | 229 } |
282 | 230 |
283 JumpList::~JumpList() { | 231 JumpList::~JumpList() { |
284 Terminate(); | 232 Terminate(); |
285 } | 233 } |
286 | 234 |
287 // static | 235 // static |
288 bool JumpList::Enabled() { | 236 bool JumpList::Enabled() { |
289 return JumpListUpdater::IsEnabled(); | 237 return JumpListUpdater::IsEnabled(); |
290 } | 238 } |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
386 recently_closed_pages_ = temp_list; | 334 recently_closed_pages_ = temp_list; |
387 } | 335 } |
388 | 336 |
389 // Send a query that retrieves the first favicon. | 337 // Send a query that retrieves the first favicon. |
390 StartLoadingFavicon(); | 338 StartLoadingFavicon(); |
391 } | 339 } |
392 | 340 |
393 void JumpList::TabRestoreServiceDestroyed(TabRestoreService* service) { | 341 void JumpList::TabRestoreServiceDestroyed(TabRestoreService* service) { |
394 } | 342 } |
395 | 343 |
396 void JumpList::OnAvatarMenuChanged(AvatarMenu* avatar_menu) { | |
397 if (!use_profiles_category_) | |
398 return; | |
399 | |
400 UpdateProfileSwitcher(); | |
401 PostRunUpdate(); | |
402 } | |
403 | |
404 bool JumpList::AddTab(const TabRestoreService::Tab* tab, | 344 bool JumpList::AddTab(const TabRestoreService::Tab* tab, |
405 ShellLinkItemList* list, | 345 ShellLinkItemList* list, |
406 size_t max_items) { | 346 size_t max_items) { |
407 // This code adds the URL and the title strings of the given tab to the | 347 // This code adds the URL and the title strings of the given tab to the |
408 // specified list. | 348 // specified list. |
409 if (list->size() >= max_items) | 349 if (list->size() >= max_items) |
410 return false; | 350 return false; |
411 | 351 |
412 scoped_refptr<ShellLinkItem> link = CreateShellLink(); | 352 scoped_refptr<ShellLinkItem> link = CreateShellLink(); |
413 const sessions::SerializedNavigationEntry& current_navigation = | 353 const sessions::SerializedNavigationEntry& current_navigation = |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
507 BrowserThread::FILE, FROM_HERE, | 447 BrowserThread::FILE, FROM_HERE, |
508 base::Bind(&JumpList::RunUpdateOnFileThread, | 448 base::Bind(&JumpList::RunUpdateOnFileThread, |
509 this, | 449 this, |
510 incognito_availability)); | 450 incognito_availability)); |
511 } | 451 } |
512 | 452 |
513 void JumpList::RunUpdateOnFileThread( | 453 void JumpList::RunUpdateOnFileThread( |
514 IncognitoModePrefs::Availability incognito_availability) { | 454 IncognitoModePrefs::Availability incognito_availability) { |
515 ShellLinkItemList local_most_visited_pages; | 455 ShellLinkItemList local_most_visited_pages; |
516 ShellLinkItemList local_recently_closed_pages; | 456 ShellLinkItemList local_recently_closed_pages; |
517 ShellLinkItemList local_profile_switcher; | |
518 | 457 |
519 { | 458 { |
520 base::AutoLock auto_lock(list_lock_); | 459 base::AutoLock auto_lock(list_lock_); |
521 // Make sure we are not out of date: if icon_urls_ is not empty, then | 460 // Make sure we are not out of date: if icon_urls_ is not empty, then |
522 // another notification has been received since we processed this one | 461 // another notification has been received since we processed this one |
523 if (!icon_urls_.empty()) | 462 if (!icon_urls_.empty()) |
524 return; | 463 return; |
525 | 464 |
526 // Make local copies of lists so we can release the lock. | 465 // Make local copies of lists so we can release the lock. |
527 local_most_visited_pages = most_visited_pages_; | 466 local_most_visited_pages = most_visited_pages_; |
528 local_recently_closed_pages = recently_closed_pages_; | 467 local_recently_closed_pages = recently_closed_pages_; |
529 local_profile_switcher = profile_switcher_; | |
530 } | 468 } |
531 | 469 |
532 // Delete the directory which contains old icon files, rename the current | 470 // Delete the directory which contains old icon files, rename the current |
533 // icon directory, and create a new directory which contains new JumpList | 471 // icon directory, and create a new directory which contains new JumpList |
534 // icon files. | 472 // icon files. |
535 base::FilePath icon_dir_old(icon_dir_.value() + L"Old"); | 473 base::FilePath icon_dir_old(icon_dir_.value() + L"Old"); |
536 if (base::PathExists(icon_dir_old)) | 474 if (base::PathExists(icon_dir_old)) |
537 base::DeleteFile(icon_dir_old, true); | 475 base::DeleteFile(icon_dir_old, true); |
538 base::Move(icon_dir_, icon_dir_old); | 476 base::Move(icon_dir_, icon_dir_old); |
539 base::CreateDirectory(icon_dir_); | 477 base::CreateDirectory(icon_dir_); |
540 | 478 |
541 // Create temporary icon files for shortcuts in the "Most Visited" category. | 479 // Create temporary icon files for shortcuts in the "Most Visited" category. |
542 CreateIconFiles(local_most_visited_pages); | 480 CreateIconFiles(local_most_visited_pages); |
543 | 481 |
544 // Create temporary icon files for shortcuts in the "Recently Closed" | 482 // Create temporary icon files for shortcuts in the "Recently Closed" |
545 // category. | 483 // category. |
546 CreateIconFiles(local_recently_closed_pages); | 484 CreateIconFiles(local_recently_closed_pages); |
547 | 485 |
548 // Create temporary icon files for the profile avatars in the "People" | |
549 // category. | |
550 if (use_profiles_category_) | |
551 CreateIconFiles(local_profile_switcher); | |
552 | |
553 // We finished collecting all resources needed for updating an application | 486 // We finished collecting all resources needed for updating an application |
554 // JumpList. So, create a new JumpList and replace the current JumpList | 487 // JumpList. So, create a new JumpList and replace the current JumpList |
555 // with it. | 488 // with it. |
556 UpdateJumpList(app_id_.c_str(), | 489 UpdateJumpList(app_id_.c_str(), |
557 local_most_visited_pages, | 490 local_most_visited_pages, |
558 local_recently_closed_pages, | 491 local_recently_closed_pages, |
559 local_profile_switcher, | 492 incognito_availability); |
560 incognito_availability, | |
561 use_profiles_category_); | |
562 } | 493 } |
563 | 494 |
564 void JumpList::CreateIconFiles(const ShellLinkItemList& item_list) { | 495 void JumpList::CreateIconFiles(const ShellLinkItemList& item_list) { |
565 for (ShellLinkItemList::const_iterator item = item_list.begin(); | 496 for (ShellLinkItemList::const_iterator item = item_list.begin(); |
566 item != item_list.end(); ++item) { | 497 item != item_list.end(); ++item) { |
567 base::FilePath icon_path; | 498 base::FilePath icon_path; |
568 if (CreateIconFile((*item)->icon_data(), icon_dir_, &icon_path)) | 499 if (CreateIconFile((*item)->icon_data(), icon_dir_, &icon_path)) |
569 (*item)->set_icon(icon_path.value(), 0); | 500 (*item)->set_icon(icon_path.value(), 0); |
570 } | 501 } |
571 } | 502 } |
572 | 503 |
573 void JumpList::UpdateProfileSwitcher() { | |
574 DCHECK(use_profiles_category_); | |
575 ShellLinkItemList new_profile_switcher; | |
576 | |
577 // Don't display a menu in the single profile case. | |
578 if (avatar_menu_->GetNumberOfItems() > 1) { | |
579 for (size_t i = 0; i < avatar_menu_->GetNumberOfItems(); ++i) { | |
580 scoped_refptr<ShellLinkItem> link = CreateShellLink(); | |
581 const AvatarMenu::Item& item = avatar_menu_->GetItemAt(i); | |
582 | |
583 link->set_title(item.name); | |
584 link->GetCommandLine()->AppendSwitchPath( | |
585 switches::kProfileDirectory, item.profile_path.BaseName()); | |
586 link->GetCommandLine()->AppendSwitch( | |
587 switches::kActivateExistingProfileBrowser); | |
588 link->GetCommandLine()->AppendSwitchASCII( | |
589 switches::kWinJumplistAction, jumplist::kProfilesCategory); | |
590 | |
591 gfx::Image avatar; | |
592 bool is_rectangle; | |
593 avatar_menu_->GetImageForMenuButton( | |
594 item.profile_path, &avatar, &is_rectangle); | |
595 link->set_icon_data(avatar.AsBitmap()); | |
596 new_profile_switcher.push_back(link); | |
597 } | |
598 } | |
599 | |
600 { | |
601 base::AutoLock auto_lock(list_lock_); | |
602 new_profile_switcher.swap(profile_switcher_); | |
603 } | |
604 } | |
605 | |
606 void JumpList::TopSitesLoaded(history::TopSites* top_sites) { | 504 void JumpList::TopSitesLoaded(history::TopSites* top_sites) { |
607 } | 505 } |
608 | 506 |
609 void JumpList::TopSitesChanged(history::TopSites* top_sites) { | 507 void JumpList::TopSitesChanged(history::TopSites* top_sites) { |
610 top_sites->GetMostVisitedURLs( | 508 top_sites->GetMostVisitedURLs( |
611 base::Bind(&JumpList::OnMostVisitedURLsAvailable, | 509 base::Bind(&JumpList::OnMostVisitedURLsAvailable, |
612 weak_ptr_factory_.GetWeakPtr()), | 510 weak_ptr_factory_.GetWeakPtr()), |
613 false); | 511 false); |
614 } | 512 } |
OLD | NEW |