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

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

Issue 7538022: Jumplist Bug (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: '' Created 9 years, 4 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
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/jumplist_win.h" 5 #include "chrome/browser/jumplist_win.h"
6 6
7 #include <windows.h> 7 #include <windows.h>
8 #include <shobjidl.h> 8 #include <shobjidl.h>
9 #include <propkey.h> 9 #include <propkey.h>
10 #include <propvarutil.h> 10 #include <propvarutil.h>
11 11
12 #include <string> 12 #include <string>
13 #include <vector> 13 #include <vector>
14 14
15 #include "base/callback.h" 15 #include "base/callback.h"
16 #include "base/command_line.h" 16 #include "base/command_line.h"
17 #include "base/file_util.h" 17 #include "base/file_util.h"
18 #include "base/path_service.h" 18 #include "base/path_service.h"
19 #include "base/string_util.h" 19 #include "base/string_util.h"
20 #include "base/threading/thread.h" 20 #include "base/threading/thread.h"
21 #include "base/utf_string_conversions.h" 21 #include "base/utf_string_conversions.h"
22 #include "base/win/scoped_comptr.h" 22 #include "base/win/scoped_comptr.h"
23 #include "base/win/windows_version.h" 23 #include "base/win/windows_version.h"
24 #include "chrome/browser/favicon/favicon_service.h" 24 #include "chrome/browser/favicon/favicon_service.h"
25 #include "chrome/browser/history/history.h" 25 #include "chrome/browser/history/history.h"
26 #include "chrome/browser/history/page_usage_data.h" 26 #include "chrome/browser/history/page_usage_data.h"
27 #include "chrome/browser/history/top_sites.h"
27 #include "chrome/browser/profiles/profile.h" 28 #include "chrome/browser/profiles/profile.h"
28 #include "chrome/browser/sessions/session_types.h" 29 #include "chrome/browser/sessions/session_types.h"
29 #include "chrome/browser/sessions/tab_restore_service.h" 30 #include "chrome/browser/sessions/tab_restore_service.h"
30 #include "chrome/browser/sessions/tab_restore_service_factory.h" 31 #include "chrome/browser/sessions/tab_restore_service_factory.h"
31 #include "chrome/browser/shell_integration.h" 32 #include "chrome/browser/shell_integration.h"
32 #include "chrome/common/chrome_constants.h" 33 #include "chrome/common/chrome_constants.h"
34 #include "chrome/common/chrome_notification_types.h"
33 #include "chrome/common/chrome_switches.h" 35 #include "chrome/common/chrome_switches.h"
34 #include "chrome/common/url_constants.h" 36 #include "chrome/common/url_constants.h"
35 #include "content/browser/browser_thread.h" 37 #include "content/browser/browser_thread.h"
38 #include "content/common/notification_service.h"
36 #include "googleurl/src/gurl.h" 39 #include "googleurl/src/gurl.h"
37 #include "grit/chromium_strings.h" 40 #include "grit/chromium_strings.h"
38 #include "grit/generated_resources.h" 41 #include "grit/generated_resources.h"
39 #include "third_party/skia/include/core/SkBitmap.h" 42 #include "third_party/skia/include/core/SkBitmap.h"
40 #include "ui/base/l10n/l10n_util.h" 43 #include "ui/base/l10n/l10n_util.h"
41 #include "ui/gfx/codec/png_codec.h" 44 #include "ui/gfx/codec/png_codec.h"
42 #include "ui/gfx/icon_util.h" 45 #include "ui/gfx/icon_util.h"
43 46
44 47
45 namespace { 48 namespace {
(...skipping 423 matching lines...) Expand 10 before | Expand all | Expand 10 after
469 return false; 472 return false;
470 473
471 // Commit this transaction and send the updated JumpList to Windows. 474 // Commit this transaction and send the updated JumpList to Windows.
472 result = destination_list->CommitList(); 475 result = destination_list->CommitList();
473 if (FAILED(result)) 476 if (FAILED(result))
474 return false; 477 return false;
475 478
476 return true; 479 return true;
477 } 480 }
478 481
479 // Represents a task which updates an application JumpList.
480 // This task encapsulates all I/O tasks and OS-specific tasks required for
481 // updating a JumpList from Chromium, such as:
482 // * Deleting the directory containing temporary icon files;
483 // * Creating temporary icon files used by the JumpList;
484 // * Creating an ICustomDestinationList instance;
485 // * Adding items in the ICustomDestinationList instance.
486 // To spawn this task,
487 // 1. Prepare objects required by this task:
488 // * a std::wstring that contains a temporary icons;
489 // * a ShellLinkItemList that contains the items of the "Most Visited"
490 // category, and;
491 // * a ShellLinkItemList that contains the items of the "Recently Closed"
492 // category.
493 // 2. Create a JumpListUpdateTask instance, and;
494 // 3. Post this task to the file thread.
495 class JumpListUpdateTask : public Task {
496 public:
497 JumpListUpdateTask(const wchar_t* app_id,
498 const FilePath& icon_dir,
499 const ShellLinkItemList& most_visited_pages,
500 const ShellLinkItemList& recently_closed_pages)
501 : app_id_(app_id),
502 icon_dir_(icon_dir),
503 most_visited_pages_(most_visited_pages),
504 recently_closed_pages_(recently_closed_pages) {
505 }
506
507 private:
508 // Represents an entry point of this task.
509 // When we post this task to a file thread, the thread calls this function.
510 void Run();
511
512 // App id to associate with the jump list.
513 std::wstring app_id_;
514
515 // The directory which contains JumpList icons.
516 FilePath icon_dir_;
517
518 // Items in the "Most Visited" category of the application JumpList.
519 ShellLinkItemList most_visited_pages_;
520
521 // Items in the "Recently Closed" category of the application JumpList.
522 ShellLinkItemList recently_closed_pages_;
523 };
524
525 void JumpListUpdateTask::Run() {
526 // Delete the directory which contains old icon files, rename the current
527 // icon directory, and create a new directory which contains new JumpList
528 // icon files.
529 FilePath icon_dir_old(icon_dir_.value() + L"Old");
530 if (file_util::PathExists(icon_dir_old))
531 file_util::Delete(icon_dir_old, true);
532 file_util::Move(icon_dir_, icon_dir_old);
533 file_util::CreateDirectory(icon_dir_);
534
535 // Create temporary icon files for shortcuts in the "Most Visited" category.
536 for (ShellLinkItemList::const_iterator item = most_visited_pages_.begin();
537 item != most_visited_pages_.end(); ++item) {
538 SkBitmap icon_bitmap;
539 if ((*item)->data().get() &&
540 gfx::PNGCodec::Decode((*item)->data()->front(),
541 (*item)->data()->size(),
542 &icon_bitmap)) {
543 FilePath icon_path;
544 if (CreateIconFile(icon_bitmap, icon_dir_, &icon_path))
545 (*item)->SetIcon(icon_path.value(), 0, true);
546 }
547 }
548
549 // Create temporary icon files for shortcuts in the "Recently Closed"
550 // category.
551 for (ShellLinkItemList::const_iterator item = recently_closed_pages_.begin();
552 item != recently_closed_pages_.end(); ++item) {
553 SkBitmap icon_bitmap;
554 if ((*item)->data().get() &&
555 gfx::PNGCodec::Decode((*item)->data()->front(),
556 (*item)->data()->size(),
557 &icon_bitmap)) {
558 FilePath icon_path;
559 if (CreateIconFile(icon_bitmap, icon_dir_, &icon_path))
560 (*item)->SetIcon(icon_path.value(), 0, true);
561 }
562 }
563
564 // We finished collecting all resources needed for updating an appliation
565 // JumpList. So, create a new JumpList and replace the current JumpList
566 // with it.
567 UpdateJumpList(app_id_.c_str(), most_visited_pages_, recently_closed_pages_);
568
569 // Delete all items in these lists now since we don't need the ShellLinkItem
570 // objects in these lists.
571 most_visited_pages_.clear();
572 recently_closed_pages_.clear();
573 }
574
575 } // namespace 482 } // namespace
576 483
577 JumpList::JumpList() : profile_(NULL) { 484 JumpList::JumpList()
485 : profile_(NULL),
486 handle_(NULL) {
578 } 487 }
579 488
580 JumpList::~JumpList() { 489 JumpList::~JumpList() {
581 RemoveObserver(); 490 Terminate();
582 } 491 }
583 492
584 // static 493 // static
585 bool JumpList::Enabled() { 494 bool JumpList::Enabled() {
586 return (base::win::GetVersion() >= base::win::VERSION_WIN7 && 495 return (base::win::GetVersion() >= base::win::VERSION_WIN7 &&
587 !CommandLine::ForCurrentProcess()->HasSwitch( 496 !CommandLine::ForCurrentProcess()->HasSwitch(
588 switches::kDisableCustomJumpList)); 497 switches::kDisableCustomJumpList));
589 } 498 }
590 499
591 bool JumpList::AddObserver(Profile* profile) { 500 bool JumpList::AddObserver(Profile* profile) {
592 // To update JumpList when a tab is added or removed, we add this object to 501 // To update JumpList when a tab is added or removed, we add this object to
593 // the observer list of the TabRestoreService class. 502 // the observer list of the TabRestoreService class.
594 // When we add this object to the observer list, we save the pointer to this 503 // When we add this object to the observer list, we save the pointer to this
595 // TabRestoreService object. This pointer is used when we remove this object 504 // TabRestoreService object. This pointer is used when we remove this object
596 // from the observer list. 505 // from the observer list.
597 if (base::win::GetVersion() < base::win::VERSION_WIN7 || !profile) 506 if (base::win::GetVersion() < base::win::VERSION_WIN7 || !profile)
598 return false; 507 return false;
599 508
600 TabRestoreService* tab_restore_service = 509 TabRestoreService* tab_restore_service =
601 TabRestoreServiceFactory::GetForProfile(profile); 510 TabRestoreServiceFactory::GetForProfile(profile);
602 if (!tab_restore_service) 511 if (!tab_restore_service)
603 return false; 512 return false;
604 513
605 app_id_ = ShellIntegration::GetChromiumAppId(profile->GetPath()); 514 app_id_ = ShellIntegration::GetChromiumAppId(profile->GetPath());
606 icon_dir_ = profile->GetPath().Append(chrome::kJumpListIconDirname); 515 icon_dir_ = profile->GetPath().Append(chrome::kJumpListIconDirname);
607 profile_ = profile; 516 profile_ = profile;
517 history::TopSites* top_sites = profile_->GetTopSites();
518 if (top_sites) {
519 // TopSites updates itself after a delay. This is especially noticable when
520 // your profile is empty. Ask TopSites to update itself when we're about to
521 // show the new tab page.
MAD 2011/08/19 14:46:03 I don't think we are about to show the new tab pag
522 top_sites->SyncWithHistory();
523 // Register for notification when TopSites changes so that we can update
524 // ourself.
525 registrar_.Add(this, chrome::NOTIFICATION_TOP_SITES_CHANGED,
526 Source<history::TopSites>(top_sites));
527 // Register for notification when profile is destroyed to ensure that all
528 // observers are detatched at that time.
529 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
530 Source<Profile>(profile_));
MAD 2011/08/19 14:46:03 Bad alignment, should be aligned to this, right af
531 }
608 tab_restore_service->AddObserver(this); 532 tab_restore_service->AddObserver(this);
609 return true; 533 return true;
610 } 534 }
611 535
536 void JumpList::Observe(int type,
537 const NotificationSource& source,
538 const NotificationDetails& details) {
539 switch (type) {
540 case chrome::NOTIFICATION_TOP_SITES_CHANGED: {
541 // Most visited urls changed, query again.
542 history::TopSites* top_sites = profile_->GetTopSites();
543 if (top_sites) {
544 top_sites->GetMostVisitedURLs(
545 &topsites_consumer_,
546 NewCallback(this, &JumpList::OnMostVisitedURLsAvailable));
547 }
548 break;
549 }
550 case chrome::NOTIFICATION_PROFILE_DESTROYED: {
551 // Profile was destroyed, do clean-up.
552 Terminate();
553 break;
554 }
555 default:
556 NOTREACHED() << "Unexpected notification type.";
557 }
558 }
559
612 void JumpList::RemoveObserver() { 560 void JumpList::RemoveObserver() {
613 if (profile_) { 561 if (profile_) {
614 TabRestoreService* tab_restore_service = 562 TabRestoreService* tab_restore_service =
615 TabRestoreServiceFactory::GetForProfile(profile_); 563 TabRestoreServiceFactory::GetForProfile(profile_);
616 if (tab_restore_service) 564 if (tab_restore_service)
617 tab_restore_service->RemoveObserver(this); 565 tab_restore_service->RemoveObserver(this);
566 registrar_.Remove(this, chrome::NOTIFICATION_TOP_SITES_CHANGED,
567 Source<history::TopSites>(profile_->GetTopSites()));
568 registrar_.Remove(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
569 Source<Profile>(profile_));
618 } 570 }
619 profile_ = NULL; 571 profile_ = NULL;
620 } 572 }
621 573
574 void JumpList::CancelPendingUpdate() {
575 if (handle_) {
576 FaviconService* favicon_service =
577 profile_->GetFaviconService(Profile::EXPLICIT_ACCESS);
578 favicon_service->CancelRequest(handle_);
579 handle_ = NULL;
580 }
581 }
582
583 void JumpList::Terminate() {
584 CancelPendingUpdate();
585 RemoveObserver();
586 }
587
588 void JumpList::OnMostVisitedURLsAvailable(
589 const history::MostVisitedURLList& data) {
590
591 // If we have a pending favicon request, cancel it here (it is out of date).
592 CancelPendingUpdate();
593
594 {
595 base::AutoLock auto_lock(list_lock_);
596 most_visited_pages_.clear();
597 for (size_t i = 0; i < data.size(); i++) {
598 const history::MostVisitedURL& url = data[i];
599 scoped_refptr<ShellLinkItem> link(new ShellLinkItem);
600 std::string url_string = url.url.spec();
601 link->SetArguments(UTF8ToWide(url_string));
602 link->SetTitle(!url.title.empty()? url.title : link->arguments());
603 most_visited_pages_.push_back(link);
604 icon_urls_.push_back(make_pair(url_string, link));
605 }
606 }
607
608 // Send a query that retrieves the first favicon.
609 StartLoadingFavicon();
610 }
611
622 void JumpList::TabRestoreServiceChanged(TabRestoreService* service) { 612 void JumpList::TabRestoreServiceChanged(TabRestoreService* service) {
623 // Added or removed a tab. 613 // if we have a pending handle request, cancel it here (it is out of date).
624 // Exit if we are updating the application JumpList. 614 CancelPendingUpdate();
625 if (!icon_urls_.empty())
626 return;
627 615
628 // Send a query to HistoryService and retrieve the "Most Visited" pages. 616 // local list to pass to methods
629 // This code is copied from MostVisitedHandler::HandleGetMostVisited() to 617 ShellLinkItemList temp_list;
630 // emulate its behaviors. 618
631 const int kMostVisitedScope = 90; 619 // Create a list of ShellLinkItems from the "Recently Closed" pages.
632 const int kMostVisitedCount = 9; 620 // As noted above, we create a ShellLinkItem objects with the following
633 int result_count = kMostVisitedCount; 621 // parameters.
634 HistoryService* history_service = 622 // * arguments
635 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); 623 // The last URL of the tab object.
636 history_service->QuerySegmentUsageSince( 624 // * title
637 &most_visited_consumer_, 625 // The title of the last URL.
638 base::Time::Now() - base::TimeDelta::FromDays(kMostVisitedScope), 626 // * icon
639 result_count, 627 // An empty string. This value is to be updated in OnFaviconDataAvailable().
640 NewCallback(this, &JumpList::OnSegmentUsageAvailable)); 628 // This code is copied from
629 // RecentlyClosedTabsHandler::TabRestoreServiceChanged() to emulate it.
630 const int kRecentlyClosedCount = 4;
631 TabRestoreService* tab_restore_service =
632 TabRestoreServiceFactory::GetForProfile(profile_);
633 const TabRestoreService::Entries& entries = tab_restore_service->entries();
634 for (TabRestoreService::Entries::const_iterator it = entries.begin();
635 it != entries.end(); ++it) {
636 const TabRestoreService::Entry* entry = *it;
637 if (entry->type == TabRestoreService::TAB) {
638 AddTab(static_cast<const TabRestoreService::Tab*>(entry),
639 &temp_list, kRecentlyClosedCount);
640 } else if (entry->type == TabRestoreService::WINDOW) {
641 AddWindow(static_cast<const TabRestoreService::Window*>(entry),
642 &temp_list, kRecentlyClosedCount);
643 }
644 }
645 // Lock recently_closed_pages and copy temp_list into it.
646 {
647 base::AutoLock auto_lock(list_lock_);
648 recently_closed_pages_ = temp_list;
649 }
650
651 // Send a query that retrieves the first favicon.
652 StartLoadingFavicon();
641 } 653 }
642 654
643 void JumpList::TabRestoreServiceDestroyed(TabRestoreService* service) { 655 void JumpList::TabRestoreServiceDestroyed(TabRestoreService* service) {
644 } 656 }
645 657
646 bool JumpList::AddTab(const TabRestoreService::Tab* tab, 658 bool JumpList::AddTab(const TabRestoreService::Tab* tab,
647 ShellLinkItemList* list, 659 ShellLinkItemList* list,
648 size_t max_items) { 660 size_t max_items) {
649 // This code adds the URL and the title strings of the given tab to the 661 // This code adds the URL and the title strings of the given tab to the
650 // specified list. 662 // specified list.
(...skipping 27 matching lines...) Expand all
678 } 690 }
679 for (size_t i = 0; i < window->tabs.size(); ++i) { 691 for (size_t i = 0; i < window->tabs.size(); ++i) {
680 if (!AddTab(&window->tabs[i], list, max_items)) 692 if (!AddTab(&window->tabs[i], list, max_items))
681 return false; 693 return false;
682 } 694 }
683 695
684 return true; 696 return true;
685 } 697 }
686 698
687 bool JumpList::StartLoadingFavicon() { 699 bool JumpList::StartLoadingFavicon() {
688 if (icon_urls_.empty()) 700 GURL url;
689 return false; 701 {
690 702 base::AutoLock auto_lock(list_lock_);
691 // Ask FaviconService if it has a favicon of a URL. 703 if (icon_urls_.empty())
692 // When FaviconService has one, it will call OnFaviconDataAvailable(). 704 return false;
693 GURL url(icon_urls_.front().first); 705 // Ask FaviconService if it has a favicon of a URL.
706 // When FaviconService has one, it will call OnFaviconDataAvailable().
707 url = GURL(icon_urls_.front().first);
708 }
694 FaviconService* favicon_service = 709 FaviconService* favicon_service =
695 profile_->GetFaviconService(Profile::EXPLICIT_ACCESS); 710 profile_->GetFaviconService(Profile::EXPLICIT_ACCESS);
696 FaviconService::Handle handle = favicon_service->GetFaviconForURL( 711 handle_ = favicon_service->GetFaviconForURL(
697 url, history::FAVICON, &favicon_consumer_, 712 url, history::FAVICON, &favicon_consumer_,
698 NewCallback(this, &JumpList::OnFaviconDataAvailable)); 713 NewCallback(this, &JumpList::OnFaviconDataAvailable));
699 return true; 714 return true;
700 } 715 }
701 716
702 void JumpList::OnSegmentUsageAvailable(
703 CancelableRequestProvider::Handle handle,
704 std::vector<PageUsageData*>* data) {
705 // Create a list of ShellLinkItem objects from the given list of
706 // PageUsageData objects.
707 // The command that opens a web page with chrome is:
708 // "chrome.exe <url-to-the-web-page>".
709 // So, we create a ShellLinkItem object with the following parameters.
710 // * arguments
711 // The URL of a PageUsagedata object (converted to std::wstring).
712 // * title
713 // The title of a PageUsageData object. If this string is empty, we use
714 // the URL as our "Most Visited" page does.
715 // * icon
716 // An empty string. This value is to be updated in OnFaviconDataAvailable().
717 most_visited_pages_.clear();
718 for (std::vector<PageUsageData*>::const_iterator page = data->begin();
719 page != data->end(); ++page) {
720 scoped_refptr<ShellLinkItem> link(new ShellLinkItem);
721 std::string url = (*page)->GetURL().spec();
722 link->SetArguments(UTF8ToWide(url));
723 link->SetTitle(
724 !(*page)->GetTitle().empty() ? (*page)->GetTitle() : link->arguments());
725 most_visited_pages_.push_back(link);
726 icon_urls_.push_back(make_pair(url, link));
727 }
728
729 // Create a list of ShellLinkItems from the "Recently Closed" pages.
730 // As noted above, we create a ShellLinkItem objects with the following
731 // parameters.
732 // * arguments
733 // The last URL of the tab object.
734 // * title
735 // The title of the last URL.
736 // * icon
737 // An empty string. This value is to be updated in OnFaviconDataAvailable().
738 // This code is copied from
739 // RecentlyClosedTabsHandler::TabRestoreServiceChanged() to emulate it.
740 const int kRecentlyClosedCount = 4;
741 recently_closed_pages_.clear();
742 TabRestoreService* tab_restore_service =
743 TabRestoreServiceFactory::GetForProfile(profile_);
744 const TabRestoreService::Entries& entries = tab_restore_service->entries();
745 for (TabRestoreService::Entries::const_iterator it = entries.begin();
746 it != entries.end(); ++it) {
747 const TabRestoreService::Entry* entry = *it;
748 if (entry->type == TabRestoreService::TAB) {
749 AddTab(static_cast<const TabRestoreService::Tab*>(entry),
750 &recently_closed_pages_, kRecentlyClosedCount);
751 } else if (entry->type == TabRestoreService::WINDOW) {
752 AddWindow(static_cast<const TabRestoreService::Window*>(entry),
753 &recently_closed_pages_, kRecentlyClosedCount);
754 }
755 }
756
757 // Send a query that retrieves the first favicon.
758 StartLoadingFavicon();
759 }
760
761 void JumpList::OnFaviconDataAvailable( 717 void JumpList::OnFaviconDataAvailable(
762 FaviconService::Handle handle, 718 FaviconService::Handle handle,
763 history::FaviconData favicon) { 719 history::FaviconData favicon) {
764 // Attach the received data to the ShellLinkItem object. 720 // If there is currently a favicon request in progress, it is now outdated,
765 // This data will be decoded by JumpListUpdateTask. 721 // as we have received another, so nullify the handle from the old request.
766 if (favicon.is_valid()) { 722 handle_ = NULL;
767 if (!icon_urls_.empty() && icon_urls_.front().second) 723 // lock the list to set icon data and pop the url
768 icon_urls_.front().second->SetIconData(favicon.image_data); 724 {
725 base::AutoLock auto_lock(list_lock_);
726 // Attach the received data to the ShellLinkItem object.
727 // This data will be decoded by the RunUpdate method.
728 if (favicon.is_valid()) {
729 if (!icon_urls_.empty() && icon_urls_.front().second)
730 icon_urls_.front().second->SetIconData(favicon.image_data);
731 }
732
733 if (!icon_urls_.empty())
734 icon_urls_.pop_front();
769 } 735 }
770
771 // if we need to load more favicons, we send another query and exit. 736 // if we need to load more favicons, we send another query and exit.
772 if (!icon_urls_.empty())
773 icon_urls_.pop_front();
774 if (StartLoadingFavicon()) 737 if (StartLoadingFavicon())
775 return; 738 return;
776 739
777 // Finished loading all favicons needed by the application JumpList. 740 // Finished loading all favicons needed by the application JumpList.
778 // We create a JumpListUpdateTask that creates icon files, and we post it to 741 // We use a RunnableMethod that creates icon files, and we post it to
779 // the file thread. 742 // the file thread.
780 BrowserThread::PostTask( 743 BrowserThread::PostTask(
781 BrowserThread::FILE, FROM_HERE, 744 BrowserThread::FILE, FROM_HERE,
782 new JumpListUpdateTask(app_id_.c_str(), icon_dir_, most_visited_pages_, 745 NewRunnableMethod(this, &JumpList::RunUpdate));
783 recently_closed_pages_)); 746 }
784 747
785 // Delete all items in these lists since we don't need these lists any longer. 748 void JumpList::RunUpdate() {
786 most_visited_pages_.clear(); 749 ShellLinkItemList local_most_visited_pages;
787 recently_closed_pages_.clear(); 750 ShellLinkItemList local_recently_closed_pages;
751
752 {
753 base::AutoLock auto_lock(list_lock_);
754 // Make sure we are not out of date: if icon_urls_ is not empty, then
755 // another notification has been received since we processed this one
756 if (!icon_urls_.empty())
757 return;
758
759 // Make local copies of lists so we can release the lock.
760 local_most_visited_pages = most_visited_pages_;
761 local_recently_closed_pages = recently_closed_pages_;
762 }
763
764 // Delete the directory which contains old icon files, rename the current
765 // icon directory, and create a new directory which contains new JumpList
766 // icon files.
767 FilePath icon_dir_old(icon_dir_.value() + L"Old");
768 if (file_util::PathExists(icon_dir_old))
769 file_util::Delete(icon_dir_old, true);
770 file_util::Move(icon_dir_, icon_dir_old);
771 file_util::CreateDirectory(icon_dir_);
772
773 // Create temporary icon files for shortcuts in the "Most Visited" category.
774 DecodeIconData(local_most_visited_pages);
775
776 // Create temporary icon files for shortcuts in the "Recently Closed"
777 // category.
778 DecodeIconData(local_recently_closed_pages);
779
780 // We finished collecting all resources needed for updating an appliation
781 // JumpList. So, create a new JumpList and replace the current JumpList
782 // with it.
783 UpdateJumpList(app_id_.c_str(), local_most_visited_pages,
784 local_recently_closed_pages);
MAD 2011/08/19 14:46:03 Wrong alignment, should be aligned to app_id, righ
788 } 785 }
786
787 void JumpList::DecodeIconData(const ShellLinkItemList& item_list) {
788 for (ShellLinkItemList::const_iterator item = item_list.begin();
789 item != item_list.end(); ++item) {
790 SkBitmap icon_bitmap;
791 if ((*item)->data().get() &&
792 gfx::PNGCodec::Decode((*item)->data()->front(),
793 (*item)->data()->size(),
794 &icon_bitmap)) {
795 FilePath icon_path;
796 if (CreateIconFile(icon_bitmap, icon_dir_, &icon_path))
797 (*item)->SetIcon(icon_path.value(), 0, true);
798 }
799 }
800 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698