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() |
| 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 Loading... | |
| 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 } | |
| OLD | NEW |