Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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(): profile_(NULL) |
| 485 , handle_(NULL) { | |
|
MAD
2011/08/15 21:52:42
fits on a single line... otherwise, we prefer this
| |
| 578 } | 486 } |
| 579 | 487 |
| 580 JumpList::~JumpList() { | 488 JumpList::~JumpList() { |
| 581 RemoveObserver(); | 489 RemoveObserver(); |
| 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( |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 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::OnMostVisitedURLsAvailable( | |
| 565 const history::MostVisitedURLList& data) { | |
| 566 | |
| 567 // If we have a pending favicon request, cancel it here (it is out of date). | |
| 568 CancelPendingUpdate(); | |
| 569 | |
| 570 { | |
| 571 base::AutoLock auto_lock(list_lock_); | |
| 572 most_visited_pages_.clear(); | |
| 573 for (size_t i = 0; i < data.size(); i++) { | |
| 574 const history::MostVisitedURL& url = data[i]; | |
| 575 scoped_refptr<ShellLinkItem> link(new ShellLinkItem); | |
| 576 std::string url_string = url.url.spec(); | |
| 577 link->SetArguments(UTF8ToWide(url_string)); | |
| 578 link->SetTitle(!url.title.empty()? url.title : link->arguments()); | |
| 579 most_visited_pages_.push_back(link); | |
| 580 icon_urls_.push_back(make_pair(url_string, link)); | |
| 581 } | |
| 582 } | |
| 583 | |
| 584 // Send a query that retrieves the first favicon. | |
| 585 StartLoadingFavicon(); | |
| 586 } | |
| 587 | |
| 622 void JumpList::TabRestoreServiceChanged(TabRestoreService* service) { | 588 void JumpList::TabRestoreServiceChanged(TabRestoreService* service) { |
| 623 // Added or removed a tab. | 589 // if we have a pending handle request, cancel it here (it is out of date). |
| 624 // Exit if we are updating the application JumpList. | 590 CancelPendingUpdate(); |
| 625 if (!icon_urls_.empty()) | |
| 626 return; | |
| 627 | 591 |
| 628 // Send a query to HistoryService and retrieve the "Most Visited" pages. | 592 // local list to pass to methods |
| 629 // This code is copied from MostVisitedHandler::HandleGetMostVisited() to | 593 ShellLinkItemList temp_list; |
| 630 // emulate its behaviors. | 594 |
| 631 const int kMostVisitedScope = 90; | 595 // Create a list of ShellLinkItems from the "Recently Closed" pages. |
| 632 const int kMostVisitedCount = 9; | 596 // As noted above, we create a ShellLinkItem objects with the following |
| 633 int result_count = kMostVisitedCount; | 597 // parameters. |
| 634 HistoryService* history_service = | 598 // * arguments |
| 635 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); | 599 // The last URL of the tab object. |
| 636 history_service->QuerySegmentUsageSince( | 600 // * title |
| 637 &most_visited_consumer_, | 601 // The title of the last URL. |
| 638 base::Time::Now() - base::TimeDelta::FromDays(kMostVisitedScope), | 602 // * icon |
| 639 result_count, | 603 // An empty string. This value is to be updated in OnFaviconDataAvailable(). |
| 640 NewCallback(this, &JumpList::OnSegmentUsageAvailable)); | 604 // This code is copied from |
| 605 // RecentlyClosedTabsHandler::TabRestoreServiceChanged() to emulate it. | |
| 606 const int kRecentlyClosedCount = 4; | |
| 607 TabRestoreService* tab_restore_service = | |
| 608 TabRestoreServiceFactory::GetForProfile(profile_); | |
| 609 const TabRestoreService::Entries& entries = tab_restore_service->entries(); | |
| 610 for (TabRestoreService::Entries::const_iterator it = entries.begin(); | |
| 611 it != entries.end(); ++it) { | |
| 612 const TabRestoreService::Entry* entry = *it; | |
| 613 if (entry->type == TabRestoreService::TAB) { | |
| 614 AddTab(static_cast<const TabRestoreService::Tab*>(entry), | |
| 615 &temp_list, kRecentlyClosedCount); | |
| 616 } else if (entry->type == TabRestoreService::WINDOW) { | |
| 617 AddWindow(static_cast<const TabRestoreService::Window*>(entry), | |
| 618 &temp_list, kRecentlyClosedCount); | |
| 619 } | |
| 620 } | |
| 621 // Lock recently_closed_pages and copy temp_list into it. | |
| 622 { | |
| 623 base::AutoLock auto_lock(list_lock_); | |
| 624 recently_closed_pages_ = temp_list; | |
| 625 } | |
| 626 | |
| 627 // Send a query that retrieves the first favicon. | |
| 628 StartLoadingFavicon(); | |
| 641 } | 629 } |
| 642 | 630 |
| 643 void JumpList::TabRestoreServiceDestroyed(TabRestoreService* service) { | 631 void JumpList::TabRestoreServiceDestroyed(TabRestoreService* service) { |
| 644 } | 632 } |
| 645 | 633 |
| 646 bool JumpList::AddTab(const TabRestoreService::Tab* tab, | 634 bool JumpList::AddTab(const TabRestoreService::Tab* tab, |
| 647 ShellLinkItemList* list, | 635 ShellLinkItemList* list, |
| 648 size_t max_items) { | 636 size_t max_items) { |
| 649 // This code adds the URL and the title strings of the given tab to the | 637 // This code adds the URL and the title strings of the given tab to the |
| 650 // specified list. | 638 // specified list. |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 678 } | 666 } |
| 679 for (size_t i = 0; i < window->tabs.size(); ++i) { | 667 for (size_t i = 0; i < window->tabs.size(); ++i) { |
| 680 if (!AddTab(&window->tabs[i], list, max_items)) | 668 if (!AddTab(&window->tabs[i], list, max_items)) |
| 681 return false; | 669 return false; |
| 682 } | 670 } |
| 683 | 671 |
| 684 return true; | 672 return true; |
| 685 } | 673 } |
| 686 | 674 |
| 687 bool JumpList::StartLoadingFavicon() { | 675 bool JumpList::StartLoadingFavicon() { |
| 688 if (icon_urls_.empty()) | 676 { |
| 689 return false; | 677 base::AutoLock auto_lock(list_lock_); |
| 678 if (icon_urls_.empty()) | |
| 679 return false; | |
| 680 } | |
|
MAD
2011/08/15 21:52:42
I think we can merge these two locked blocks...
| |
| 690 | 681 |
| 691 // Ask FaviconService if it has a favicon of a URL. | 682 // Ask FaviconService if it has a favicon of a URL. |
| 692 // When FaviconService has one, it will call OnFaviconDataAvailable(). | 683 // When FaviconService has one, it will call OnFaviconDataAvailable(). |
| 693 GURL url(icon_urls_.front().first); | 684 GURL url; |
| 685 { | |
| 686 base::AutoLock auto_lock(list_lock_); | |
| 687 url = GURL(icon_urls_.front().first); | |
| 688 } | |
| 694 FaviconService* favicon_service = | 689 FaviconService* favicon_service = |
| 695 profile_->GetFaviconService(Profile::EXPLICIT_ACCESS); | 690 profile_->GetFaviconService(Profile::EXPLICIT_ACCESS); |
| 696 FaviconService::Handle handle = favicon_service->GetFaviconForURL( | 691 handle_ = favicon_service->GetFaviconForURL( |
| 697 url, history::FAVICON, &favicon_consumer_, | 692 url, history::FAVICON, &favicon_consumer_, |
| 698 NewCallback(this, &JumpList::OnFaviconDataAvailable)); | 693 NewCallback(this, &JumpList::OnFaviconDataAvailable)); |
| 699 return true; | 694 return true; |
| 700 } | 695 } |
| 701 | 696 |
| 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( | 697 void JumpList::OnFaviconDataAvailable( |
| 762 FaviconService::Handle handle, | 698 FaviconService::Handle handle, |
| 763 history::FaviconData favicon) { | 699 history::FaviconData favicon) { |
| 764 // Attach the received data to the ShellLinkItem object. | 700 // If there is currently a favicon request in progress, it is now outdated, |
| 765 // This data will be decoded by JumpListUpdateTask. | 701 // as we have received another, so nullify the handle from the old request. |
| 766 if (favicon.is_valid()) { | 702 handle_ = NULL; |
| 767 if (!icon_urls_.empty() && icon_urls_.front().second) | 703 // lock the list to set icon data and pop the url |
| 768 icon_urls_.front().second->SetIconData(favicon.image_data); | 704 { |
| 705 base::AutoLock auto_lock(list_lock_); | |
| 706 // Attach the received data to the ShellLinkItem object. | |
| 707 // This data will be decoded by the RunUpdate method. | |
| 708 if (favicon.is_valid()) { | |
| 709 if (!icon_urls_.empty() && icon_urls_.front().second) | |
| 710 icon_urls_.front().second->SetIconData(favicon.image_data); | |
| 711 } | |
| 712 | |
| 713 if (!icon_urls_.empty()) | |
| 714 icon_urls_.pop_front(); | |
| 769 } | 715 } |
| 770 | |
| 771 // if we need to load more favicons, we send another query and exit. | 716 // 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()) | 717 if (StartLoadingFavicon()) |
| 775 return; | 718 return; |
| 776 | 719 |
| 777 // Finished loading all favicons needed by the application JumpList. | 720 // Finished loading all favicons needed by the application JumpList. |
| 778 // We create a JumpListUpdateTask that creates icon files, and we post it to | 721 // We use a RunnableMethod that creates icon files, and we post it to |
| 779 // the file thread. | 722 // the file thread. |
| 780 BrowserThread::PostTask( | 723 BrowserThread::PostTask( |
| 781 BrowserThread::FILE, FROM_HERE, | 724 BrowserThread::FILE, FROM_HERE, |
| 782 new JumpListUpdateTask(app_id_.c_str(), icon_dir_, most_visited_pages_, | 725 NewRunnableMethod(this, &JumpList::RunUpdate)); |
| 783 recently_closed_pages_)); | 726 } |
| 784 | 727 |
| 785 // Delete all items in these lists since we don't need these lists any longer. | 728 void JumpList::RunUpdate() { |
| 786 most_visited_pages_.clear(); | 729 ShellLinkItemList local_most_visited_pages; |
| 787 recently_closed_pages_.clear(); | 730 ShellLinkItemList local_recently_closed_pages; |
| 731 | |
| 732 { | |
| 733 base::AutoLock auto_lock(list_lock_); | |
| 734 // Make sure we are not out of date: if icon_urls_ is not empty, then | |
| 735 // another notification has been received since we processed this one | |
| 736 if (!icon_urls_.empty()) | |
| 737 return; | |
| 738 | |
| 739 // Make local copies of lists so we can release the lock. | |
| 740 local_most_visited_pages = most_visited_pages_; | |
| 741 local_recently_closed_pages = recently_closed_pages_; | |
| 742 } | |
| 743 | |
| 744 // Delete the directory which contains old icon files, rename the current | |
| 745 // icon directory, and create a new directory which contains new JumpList | |
| 746 // icon files. | |
| 747 FilePath icon_dir_old(icon_dir_.value() + L"Old"); | |
| 748 if (file_util::PathExists(icon_dir_old)) | |
| 749 file_util::Delete(icon_dir_old, true); | |
| 750 file_util::Move(icon_dir_, icon_dir_old); | |
| 751 file_util::CreateDirectory(icon_dir_); | |
| 752 | |
| 753 // Create temporary icon files for shortcuts in the "Most Visited" category. | |
| 754 DecodeIconData(local_most_visited_pages); | |
| 755 | |
| 756 // Create temporary icon files for shortcuts in the "Recently Closed" | |
| 757 // category. | |
| 758 DecodeIconData(local_recently_closed_pages); | |
| 759 | |
| 760 // We finished collecting all resources needed for updating an appliation | |
| 761 // JumpList. So, create a new JumpList and replace the current JumpList | |
| 762 // with it. | |
| 763 UpdateJumpList(app_id_.c_str(), local_most_visited_pages, | |
| 764 local_recently_closed_pages); | |
| 788 } | 765 } |
| 766 | |
| 767 void JumpList::DecodeIconData(const ShellLinkItemList& item_list) { | |
| 768 for (ShellLinkItemList::const_iterator item = item_list.begin(); | |
| 769 item != item_list.end(); ++item) { | |
| 770 SkBitmap icon_bitmap; | |
| 771 if ((*item)->data().get() && | |
| 772 gfx::PNGCodec::Decode((*item)->data()->front(), | |
| 773 (*item)->data()->size(), | |
| 774 &icon_bitmap)) { | |
| 775 FilePath icon_path; | |
| 776 if (CreateIconFile(icon_bitmap, icon_dir_, &icon_path)) | |
| 777 (*item)->SetIcon(icon_path.value(), 0, true); | |
| 778 } | |
| 779 } | |
| 780 } | |
| OLD | NEW |