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

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();
MAD 2011/08/16 17:02:31 I would add a call to terminate here, just to be o
582 } 490 }
583 491
584 // static 492 // static
585 bool JumpList::Enabled() { 493 bool JumpList::Enabled() {
586 return (base::win::GetVersion() >= base::win::VERSION_WIN7 && 494 return (base::win::GetVersion() >= base::win::VERSION_WIN7 &&
587 !CommandLine::ForCurrentProcess()->HasSwitch( 495 !CommandLine::ForCurrentProcess()->HasSwitch(
588 switches::kDisableCustomJumpList)); 496 switches::kDisableCustomJumpList));
589 } 497 }
590 498
591 bool JumpList::AddObserver(Profile* profile) { 499 bool JumpList::AddObserver(Profile* profile) {
592 // To update JumpList when a tab is added or removed, we add this object to 500 // To update JumpList when a tab is added or removed, we add this object to
593 // the observer list of the TabRestoreService class. 501 // the observer list of the TabRestoreService class.
594 // When we add this object to the observer list, we save the pointer to this 502 // 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 503 // TabRestoreService object. This pointer is used when we remove this object
596 // from the observer list. 504 // from the observer list.
597 if (base::win::GetVersion() < base::win::VERSION_WIN7 || !profile) 505 if (base::win::GetVersion() < base::win::VERSION_WIN7 || !profile)
598 return false; 506 return false;
599 507
600 TabRestoreService* tab_restore_service = 508 TabRestoreService* tab_restore_service =
601 TabRestoreServiceFactory::GetForProfile(profile); 509 TabRestoreServiceFactory::GetForProfile(profile);
602 if (!tab_restore_service) 510 if (!tab_restore_service)
603 return false; 511 return false;
604 512
605 app_id_ = ShellIntegration::GetChromiumAppId(profile->GetPath()); 513 app_id_ = ShellIntegration::GetChromiumAppId(profile->GetPath());
606 icon_dir_ = profile->GetPath().Append(chrome::kJumpListIconDirname); 514 icon_dir_ = profile->GetPath().Append(chrome::kJumpListIconDirname);
607 profile_ = profile; 515 profile_ = profile;
516 history::TopSites* top_sites = profile_->GetTopSites();
517 if (top_sites) {
518 // TopSites updates itself after a delay. This is especially noticable when
519 // your profile is empty. Ask TopSites to update itself when we're about to
520 // show the new tab page.
521 top_sites->SyncWithHistory();
522 // Register for notification when TopSites changes so that we can update
523 // ourself.
524 registrar_.Add(this, chrome::NOTIFICATION_TOP_SITES_CHANGED,
525 Source<history::TopSites>(top_sites));
526 }
608 tab_restore_service->AddObserver(this); 527 tab_restore_service->AddObserver(this);
609 return true; 528 return true;
610 } 529 }
611 530
531 void JumpList::Observe(int type,
532 const NotificationSource& source,
533 const NotificationDetails& details) {
534 DCHECK_EQ(type, chrome::NOTIFICATION_TOP_SITES_CHANGED);
535
536 // Most visited urls changed, query again.
537 history::TopSites* top_sites = profile_->GetTopSites();
538 if (top_sites) {
539 top_sites->GetMostVisitedURLs(
540 &topsites_consumer_,
541 NewCallback(this, &JumpList::OnMostVisitedURLsAvailable));
542 }
543 }
544
612 void JumpList::RemoveObserver() { 545 void JumpList::RemoveObserver() {
613 if (profile_) { 546 if (profile_) {
614 TabRestoreService* tab_restore_service = 547 TabRestoreService* tab_restore_service =
615 TabRestoreServiceFactory::GetForProfile(profile_); 548 TabRestoreServiceFactory::GetForProfile(profile_);
616 if (tab_restore_service) 549 if (tab_restore_service)
617 tab_restore_service->RemoveObserver(this); 550 tab_restore_service->RemoveObserver(this);
618 } 551 }
619 profile_ = NULL; 552 profile_ = NULL;
620 } 553 }
621 554
555 void JumpList::CancelPendingUpdate() {
556 if (handle_) {
557 FaviconService* favicon_service =
558 profile_->GetFaviconService(Profile::EXPLICIT_ACCESS);
559 favicon_service->CancelRequest(handle_);
560 handle_ = NULL;
561 }
562 }
563
564 void JumpList::Terminate() {
565 CancelPendingUpdate();
566 RemoveObserver();
567 }
568
569 void JumpList::OnMostVisitedURLsAvailable(
570 const history::MostVisitedURLList& data) {
571
572 // If we have a pending favicon request, cancel it here (it is out of date).
573 CancelPendingUpdate();
574
575 {
576 base::AutoLock auto_lock(list_lock_);
577 most_visited_pages_.clear();
578 for (size_t i = 0; i < data.size(); i++) {
579 const history::MostVisitedURL& url = data[i];
580 scoped_refptr<ShellLinkItem> link(new ShellLinkItem);
581 std::string url_string = url.url.spec();
582 link->SetArguments(UTF8ToWide(url_string));
583 link->SetTitle(!url.title.empty()? url.title : link->arguments());
584 most_visited_pages_.push_back(link);
585 icon_urls_.push_back(make_pair(url_string, link));
586 }
587 }
588
589 // Send a query that retrieves the first favicon.
590 StartLoadingFavicon();
591 }
592
622 void JumpList::TabRestoreServiceChanged(TabRestoreService* service) { 593 void JumpList::TabRestoreServiceChanged(TabRestoreService* service) {
623 // Added or removed a tab. 594 // if we have a pending handle request, cancel it here (it is out of date).
624 // Exit if we are updating the application JumpList. 595 CancelPendingUpdate();
625 if (!icon_urls_.empty())
626 return;
627 596
628 // Send a query to HistoryService and retrieve the "Most Visited" pages. 597 // local list to pass to methods
629 // This code is copied from MostVisitedHandler::HandleGetMostVisited() to 598 ShellLinkItemList temp_list;
630 // emulate its behaviors. 599
631 const int kMostVisitedScope = 90; 600 // Create a list of ShellLinkItems from the "Recently Closed" pages.
632 const int kMostVisitedCount = 9; 601 // As noted above, we create a ShellLinkItem objects with the following
633 int result_count = kMostVisitedCount; 602 // parameters.
634 HistoryService* history_service = 603 // * arguments
635 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); 604 // The last URL of the tab object.
636 history_service->QuerySegmentUsageSince( 605 // * title
637 &most_visited_consumer_, 606 // The title of the last URL.
638 base::Time::Now() - base::TimeDelta::FromDays(kMostVisitedScope), 607 // * icon
639 result_count, 608 // An empty string. This value is to be updated in OnFaviconDataAvailable().
640 NewCallback(this, &JumpList::OnSegmentUsageAvailable)); 609 // This code is copied from
610 // RecentlyClosedTabsHandler::TabRestoreServiceChanged() to emulate it.
611 const int kRecentlyClosedCount = 4;
612 TabRestoreService* tab_restore_service =
613 TabRestoreServiceFactory::GetForProfile(profile_);
614 const TabRestoreService::Entries& entries = tab_restore_service->entries();
615 for (TabRestoreService::Entries::const_iterator it = entries.begin();
616 it != entries.end(); ++it) {
617 const TabRestoreService::Entry* entry = *it;
618 if (entry->type == TabRestoreService::TAB) {
619 AddTab(static_cast<const TabRestoreService::Tab*>(entry),
620 &temp_list, kRecentlyClosedCount);
621 } else if (entry->type == TabRestoreService::WINDOW) {
622 AddWindow(static_cast<const TabRestoreService::Window*>(entry),
623 &temp_list, kRecentlyClosedCount);
624 }
625 }
626 // Lock recently_closed_pages and copy temp_list into it.
627 {
628 base::AutoLock auto_lock(list_lock_);
629 recently_closed_pages_ = temp_list;
630 }
631
632 // Send a query that retrieves the first favicon.
633 StartLoadingFavicon();
641 } 634 }
642 635
643 void JumpList::TabRestoreServiceDestroyed(TabRestoreService* service) { 636 void JumpList::TabRestoreServiceDestroyed(TabRestoreService* service) {
644 } 637 }
645 638
646 bool JumpList::AddTab(const TabRestoreService::Tab* tab, 639 bool JumpList::AddTab(const TabRestoreService::Tab* tab,
647 ShellLinkItemList* list, 640 ShellLinkItemList* list,
648 size_t max_items) { 641 size_t max_items) {
649 // This code adds the URL and the title strings of the given tab to the 642 // This code adds the URL and the title strings of the given tab to the
650 // specified list. 643 // specified list.
(...skipping 27 matching lines...) Expand all
678 } 671 }
679 for (size_t i = 0; i < window->tabs.size(); ++i) { 672 for (size_t i = 0; i < window->tabs.size(); ++i) {
680 if (!AddTab(&window->tabs[i], list, max_items)) 673 if (!AddTab(&window->tabs[i], list, max_items))
681 return false; 674 return false;
682 } 675 }
683 676
684 return true; 677 return true;
685 } 678 }
686 679
687 bool JumpList::StartLoadingFavicon() { 680 bool JumpList::StartLoadingFavicon() {
688 if (icon_urls_.empty()) 681 GURL url;
689 return false; 682 {
690 683 base::AutoLock auto_lock(list_lock_);
691 // Ask FaviconService if it has a favicon of a URL. 684 if (icon_urls_.empty())
692 // When FaviconService has one, it will call OnFaviconDataAvailable(). 685 return false;
693 GURL url(icon_urls_.front().first); 686 // Ask FaviconService if it has a favicon of a URL.
687 // When FaviconService has one, it will call OnFaviconDataAvailable().
688 url = GURL(icon_urls_.front().first);
689 }
694 FaviconService* favicon_service = 690 FaviconService* favicon_service =
695 profile_->GetFaviconService(Profile::EXPLICIT_ACCESS); 691 profile_->GetFaviconService(Profile::EXPLICIT_ACCESS);
696 FaviconService::Handle handle = favicon_service->GetFaviconForURL( 692 handle_ = favicon_service->GetFaviconForURL(
697 url, history::FAVICON, &favicon_consumer_, 693 url, history::FAVICON, &favicon_consumer_,
698 NewCallback(this, &JumpList::OnFaviconDataAvailable)); 694 NewCallback(this, &JumpList::OnFaviconDataAvailable));
699 return true; 695 return true;
700 } 696 }
701 697
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( 698 void JumpList::OnFaviconDataAvailable(
762 FaviconService::Handle handle, 699 FaviconService::Handle handle,
763 history::FaviconData favicon) { 700 history::FaviconData favicon) {
764 // Attach the received data to the ShellLinkItem object. 701 // If there is currently a favicon request in progress, it is now outdated,
765 // This data will be decoded by JumpListUpdateTask. 702 // as we have received another, so nullify the handle from the old request.
766 if (favicon.is_valid()) { 703 handle_ = NULL;
767 if (!icon_urls_.empty() && icon_urls_.front().second) 704 // lock the list to set icon data and pop the url
768 icon_urls_.front().second->SetIconData(favicon.image_data); 705 {
706 base::AutoLock auto_lock(list_lock_);
707 // Attach the received data to the ShellLinkItem object.
708 // This data will be decoded by the RunUpdate method.
709 if (favicon.is_valid()) {
710 if (!icon_urls_.empty() && icon_urls_.front().second)
711 icon_urls_.front().second->SetIconData(favicon.image_data);
712 }
713
714 if (!icon_urls_.empty())
715 icon_urls_.pop_front();
769 } 716 }
770
771 // if we need to load more favicons, we send another query and exit. 717 // 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()) 718 if (StartLoadingFavicon())
775 return; 719 return;
776 720
777 // Finished loading all favicons needed by the application JumpList. 721 // Finished loading all favicons needed by the application JumpList.
778 // We create a JumpListUpdateTask that creates icon files, and we post it to 722 // We use a RunnableMethod that creates icon files, and we post it to
779 // the file thread. 723 // the file thread.
780 BrowserThread::PostTask( 724 BrowserThread::PostTask(
781 BrowserThread::FILE, FROM_HERE, 725 BrowserThread::FILE, FROM_HERE,
782 new JumpListUpdateTask(app_id_.c_str(), icon_dir_, most_visited_pages_, 726 NewRunnableMethod(this, &JumpList::RunUpdate));
783 recently_closed_pages_)); 727 }
784 728
785 // Delete all items in these lists since we don't need these lists any longer. 729 void JumpList::RunUpdate() {
786 most_visited_pages_.clear(); 730 ShellLinkItemList local_most_visited_pages;
787 recently_closed_pages_.clear(); 731 ShellLinkItemList local_recently_closed_pages;
732
733 {
734 base::AutoLock auto_lock(list_lock_);
735 // Make sure we are not out of date: if icon_urls_ is not empty, then
736 // another notification has been received since we processed this one
737 if (!icon_urls_.empty())
738 return;
739
740 // Make local copies of lists so we can release the lock.
741 local_most_visited_pages = most_visited_pages_;
742 local_recently_closed_pages = recently_closed_pages_;
743 }
744
745 // Delete the directory which contains old icon files, rename the current
746 // icon directory, and create a new directory which contains new JumpList
747 // icon files.
748 FilePath icon_dir_old(icon_dir_.value() + L"Old");
749 if (file_util::PathExists(icon_dir_old))
750 file_util::Delete(icon_dir_old, true);
751 file_util::Move(icon_dir_, icon_dir_old);
752 file_util::CreateDirectory(icon_dir_);
753
754 // Create temporary icon files for shortcuts in the "Most Visited" category.
755 DecodeIconData(local_most_visited_pages);
756
757 // Create temporary icon files for shortcuts in the "Recently Closed"
758 // category.
759 DecodeIconData(local_recently_closed_pages);
760
761 // We finished collecting all resources needed for updating an appliation
762 // JumpList. So, create a new JumpList and replace the current JumpList
763 // with it.
764 UpdateJumpList(app_id_.c_str(), local_most_visited_pages,
765 local_recently_closed_pages);
788 } 766 }
767
768 void JumpList::DecodeIconData(const ShellLinkItemList& item_list) {
769 for (ShellLinkItemList::const_iterator item = item_list.begin();
770 item != item_list.end(); ++item) {
771 SkBitmap icon_bitmap;
772 if ((*item)->data().get() &&
773 gfx::PNGCodec::Decode((*item)->data()->front(),
774 (*item)->data()->size(),
775 &icon_bitmap)) {
776 FilePath icon_path;
777 if (CreateIconFile(icon_bitmap, icon_dir_, &icon_path))
778 (*item)->SetIcon(icon_path.value(), 0, true);
779 }
780 }
781 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698