jumplist_win.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/jumplist_win.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <shobjidl.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <propkey.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <propvarutil.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_util.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/path_service.h"
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_comptr.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/win/scoped_propvariant.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/windows_version.h"
267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/favicon/favicon_service.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/favicon/favicon_service_factory.h"
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/history_service.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/page_usage_data.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/top_sites.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sessions/session_types.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sessions/tab_restore_service.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sessions/tab_restore_service_factory.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/shell_integration.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_constants.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_switches.h"
399ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "chrome/common/favicon/favicon_types.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_source.h"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/chromium_strings.h"
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.h"
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkBitmap.h"
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/codec/png_codec.h"
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/favicon_size.h"
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/icon_util.h"
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/gfx/image/image_family.h"
51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "url/gurl.h"
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// COM interfaces used in this file.
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// These interface declarations are copied from Windows SDK 7.0.
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(hbono): Bug 16903: delete them when we use Windows SDK 7.0.
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef __IObjectArray_INTERFACE_DEFINED__
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define __IObjectArray_INTERFACE_DEFINED__
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MIDL_INTERFACE("92CA9DCD-5622-4bba-A805-5E9F541BD8C9")
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IObjectArray : public IUnknown {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual HRESULT STDMETHODCALLTYPE GetCount(
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* [out] */ __RPC__out UINT *pcObjects) = 0;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual HRESULT STDMETHODCALLTYPE GetAt(
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* [in] */ UINT uiIndex,
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* [in] */ __RPC__in REFIID riid,
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // __IObjectArray_INTERFACE_DEFINED__
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef __IObjectCollection_INTERFACE_DEFINED__
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define __IObjectCollection_INTERFACE_DEFINED__
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MIDL_INTERFACE("5632b1a4-e38a-400a-928a-d4cd63230295")
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IObjectCollection : public IObjectArray {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual HRESULT STDMETHODCALLTYPE AddObject(
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* [in] */ __RPC__in_opt IUnknown *punk) = 0;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual HRESULT STDMETHODCALLTYPE AddFromArray(
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* [in] */ __RPC__in_opt IObjectArray *poaSource) = 0;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual HRESULT STDMETHODCALLTYPE RemoveObjectAt(
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* [in] */ UINT uiIndex) = 0;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual HRESULT STDMETHODCALLTYPE Clear(void) = 0;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // __IObjectCollection_INTERFACE_DEFINED__
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef __ICustomDestinationList_INTERFACE_DEFINED__
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define __ICustomDestinationList_INTERFACE_DEFINED__
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef /* [v1_enum] */ enum tagKNOWNDESTCATEGORY {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  KDC_FREQUENT = 1,
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  KDC_RECENT = (KDC_FREQUENT + 1)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} KNOWNDESTCATEGORY;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MIDL_INTERFACE("6332debf-87b5-4670-90c0-5e57b408a49e")
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ICustomDestinationList : public IUnknown {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual HRESULT STDMETHODCALLTYPE SetAppID(
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* [string][in] */__RPC__in_string LPCWSTR pszAppID) = 0;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual HRESULT STDMETHODCALLTYPE BeginList(
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* [out] */ __RPC__out UINT *pcMaxSlots,
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* [in] */ __RPC__in REFIID riid,
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual HRESULT STDMETHODCALLTYPE AppendCategory(
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* [string][in] */ __RPC__in_string LPCWSTR pszCategory,
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* [in] */ __RPC__in_opt IObjectArray *poa) = 0;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual HRESULT STDMETHODCALLTYPE AppendKnownCategory(
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* [in] */ KNOWNDESTCATEGORY category) = 0;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual HRESULT STDMETHODCALLTYPE AddUserTasks(
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* [in] */ __RPC__in_opt IObjectArray *poa) = 0;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual HRESULT STDMETHODCALLTYPE CommitList(void) = 0;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual HRESULT STDMETHODCALLTYPE GetRemovedDestinations(
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* [in] */ __RPC__in REFIID riid,
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual HRESULT STDMETHODCALLTYPE DeleteList(
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      /* [string][in] */ __RPC__in_string LPCWSTR pszAppID) = 0;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual HRESULT STDMETHODCALLTYPE AbortList(void) = 0;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // __ICustomDestinationList_INTERFACE_DEFINED__
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Class IDs used in this file.
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// These class IDs must be defined in an anonymous namespace to avoid
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// conflicts with ones defined in "shell32.lib" of Visual Studio 2008.
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(hbono): Bug 16903: delete them when we use Windows SDK 7.0.
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const CLSID CLSID_DestinationList = {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  0x77f10cf0, 0x3db5, 0x4966, {0xb5, 0x20, 0xb7, 0xc5, 0x4f, 0xd3, 0x5e, 0xd6}
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const CLSID CLSID_EnumerableObjectCollection = {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  0x2d3468c1, 0x36a7, 0x43b6, {0xac, 0x24, 0xd3, 0xf0, 0x2f, 0xd9, 0x60, 0x7a}
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};  // namespace
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// END OF WINDOWS 7 SDK DEFINITIONS
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Creates an IShellLink object.
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// An IShellLink object is almost the same as an application shortcut, and it
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// requires three items: the absolute path to an application, an argument
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// string, and a title string.
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT AddShellLink(base::win::ScopedComPtr<IObjectCollection> collection,
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     const std::wstring& application,
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     const std::wstring& switches,
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     scoped_refptr<ShellLinkItem> item) {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create an IShellLink object.
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedComPtr<IShellLink> link;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT result = link.CreateInstance(CLSID_ShellLink, NULL,
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       CLSCTX_INPROC_SERVER);
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(result))
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set the application path.
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We should exit this function when this call fails because it doesn't make
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // any sense to add a shortcut that we cannot execute.
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = link->SetPath(application.c_str());
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(result))
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Attach the command-line switches of this process before the given
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // arguments and set it as the arguments of this IShellLink object.
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We also exit this function when this call fails because it isn't usuful to
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // add a shortcut that cannot open the given page.
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::wstring arguments(switches);
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!item->arguments().empty()) {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    arguments.push_back(L' ');
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    arguments += item->arguments();
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = link->SetArguments(arguments.c_str());
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(result))
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Attach the given icon path to this IShellLink object.
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Since an icon is an optional item for an IShellLink object, so we don't
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // have to exit even when it fails.
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!item->icon().empty())
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    link->SetIconLocation(item->icon().c_str(), item->index());
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set the title of the IShellLink object.
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The IShellLink interface does not have any functions which update its
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // title because this interface is originally for creating an application
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // shortcut which doesn't have titles.
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // So, we should use the IPropertyStore interface to set its title as
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // listed in the steps below:
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 1. Retrieve the IPropertyStore interface from the IShellLink object;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 2. Start a transaction that changes a value of the object with the
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    IPropertyStore interface;
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 3. Create a string PROPVARIANT, and;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 4. Call the IPropertyStore::SetValue() function to Set the title property
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    of the IShellLink object.
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 5. Commit the transaction.
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedComPtr<IPropertyStore> property_store;
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = link.QueryInterface(property_store.Receive());
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(result))
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::win::ScopedPropVariant property_title;
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Call InitPropVariantFromString() to initialize |property_title|. Reading
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // <propvarutil.h>, it seems InitPropVariantFromString() is an inline function
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // that initializes a PROPVARIANT object and calls SHStrDupW() to set a copy
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // of its input string. It is thus safe to call it without first creating a
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // copy here.
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  result = InitPropVariantFromString(item->title().c_str(),
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     property_title.Receive());
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(result))
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  result = property_store->SetValue(PKEY_Title, property_title.get());
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(result))
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = property_store->Commit();
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(result))
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add this IShellLink object to the given collection.
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return collection->AddObject(link);
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Creates a temporary icon file to be shown in JumpList.
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CreateIconFile(const SkBitmap& bitmap,
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    const base::FilePath& icon_dir,
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    base::FilePath* icon_path) {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Retrieve the path to a temporary file.
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We don't have to care about the extension of this temporary file because
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // JumpList does not care about it.
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath path;
236a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!base::CreateTemporaryFileInDir(icon_dir, &path))
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create an icon file from the favicon attached to the given |page|, and
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // save it as the temporary file.
241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  gfx::ImageFamily image_family;
242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  image_family.Add(gfx::Image::CreateFrom1xBitmap(bitmap));
243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!IconUtil::CreateIconFileFromImageFamily(image_family, path))
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add this icon file to the list and return its absolute path.
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The IShellLink::SetIcon() function needs the absolute path to an icon.
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *icon_path = path;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Updates a specified category of an application JumpList.
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This function cannot update registered categories (such as "Tasks") because
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// special steps are required for updating them.
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// So, this function can be used only for adding an unregistered category.
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Parameters:
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * category_id (int)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   A string ID which contains the category name.
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * application (std::wstring)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   An application name to be used for creating JumpList items.
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   Even though we can add command-line switches to this parameter, it is
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   better to use the |switches| parameter below.
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * switches (std::wstring)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   Command-lien switches for the application. This string is to be added
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   before the arguments of each ShellLinkItem object. If there aren't any
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   switches, use an empty string.
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * data (ShellLinkItemList)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   A list of ShellLinkItem objects to be added under the specified category.
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT UpdateCategory(base::win::ScopedComPtr<ICustomDestinationList> list,
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       int category_id,
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const std::wstring& application,
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const std::wstring& switches,
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const ShellLinkItemList& data,
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       int max_slots) {
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Exit this function when the given vector does not contain any items
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // because an ICustomDestinationList::AppendCategory() call fails in this
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // case.
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (data.empty() || !max_slots)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return S_OK;
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::wstring category = UTF16ToWide(l10n_util::GetStringUTF16(category_id));
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create an EnumerableObjectCollection object.
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We once add the given items to this collection object and add this
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // collection to the JumpList.
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedComPtr<IObjectCollection> collection;
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT result = collection.CreateInstance(CLSID_EnumerableObjectCollection,
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             NULL, CLSCTX_INPROC_SERVER);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(result))
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (ShellLinkItemList::const_iterator item = data.begin();
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       item != data.end() && max_slots > 0; ++item, --max_slots) {
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<ShellLinkItem> link(*item);
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddShellLink(collection, application, switches, link);
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We can now add the new list to the JumpList.
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The ICustomDestinationList::AppendCategory() function needs the
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // IObjectArray interface to retrieve each item in the list. So, we retrive
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the IObjectArray interface from the IEnumeratableObjectCollection object
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and use it.
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It seems the ICustomDestinationList::AppendCategory() function just
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // replaces all items in the given category with the ones in the new list.
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedComPtr<IObjectArray> object_array;
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = collection.QueryInterface(object_array.Receive());
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(result))
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return list->AppendCategory(category.c_str(), object_array);
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Updates the "Tasks" category of the JumpList.
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Even though this function is almost the same as UpdateCategory(), this
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// function has the following differences:
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * The "Task" category is a registered category.
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   We should use AddUserTasks() instead of AppendCategory().
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * The items in the "Task" category are static.
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   We don't have to use a list.
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT UpdateTaskCategory(base::win::ScopedComPtr<ICustomDestinationList> list,
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           const std::wstring& chrome_path,
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           const std::wstring& chrome_switches) {
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create an EnumerableObjectCollection object to be added items of the
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // "Task" category. (We can also use this object for the "Task" category.)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedComPtr<IObjectCollection> collection;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT result = collection.CreateInstance(CLSID_EnumerableObjectCollection,
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             NULL, CLSCTX_INPROC_SERVER);
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(result))
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create an IShellLink object which launches Chrome, and add it to the
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // collection. We use our application icon as the icon for this item.
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We remove '&' characters from this string so we can share it with our
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // system menu.
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<ShellLinkItem> chrome(new ShellLinkItem);
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::wstring chrome_title =
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UTF16ToWide(l10n_util::GetStringUTF16(IDS_NEW_WINDOW));
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReplaceSubstringsAfterOffset(&chrome_title, 0, L"&", L"");
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chrome->SetTitle(chrome_title);
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chrome->SetIcon(chrome_path, 0, false);
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddShellLink(collection, chrome_path, chrome_switches, chrome);
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create an IShellLink object which launches Chrome in incognito mode, and
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // add it to the collection. We use our application icon as the icon for
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // this item.
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<ShellLinkItem> incognito(new ShellLinkItem);
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  incognito->SetArguments(
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ASCIIToWide(std::string("--") + switches::kIncognito));
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::wstring incognito_title =
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UTF16ToWide(l10n_util::GetStringUTF16(IDS_NEW_INCOGNITO_WINDOW));
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReplaceSubstringsAfterOffset(&incognito_title, 0, L"&", L"");
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  incognito->SetTitle(incognito_title);
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  incognito->SetIcon(chrome_path, 0, false);
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddShellLink(collection, chrome_path, chrome_switches, incognito);
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We can now add the new list to the JumpList.
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ICustomDestinationList::AddUserTasks() also uses the IObjectArray
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // interface to retrieve each item in the list. So, we retrieve the
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // IObjectArray interface from the EnumerableObjectCollection object.
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedComPtr<IObjectArray> object_array;
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = collection.QueryInterface(object_array.Receive());
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(result))
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return list->AddUserTasks(object_array);
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Updates the application JumpList.
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This function encapsulates all OS-specific operations required for updating
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the Chromium JumpList, such as:
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Creating an ICustomDestinationList instance;
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Updating the categories of the ICustomDestinationList instance, and;
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Sending it to Taskbar of Windows 7.
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool UpdateJumpList(const wchar_t* app_id,
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    const ShellLinkItemList& most_visited_pages,
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    const ShellLinkItemList& recently_closed_pages) {
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // JumpList is implemented only on Windows 7 or later.
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // So, we should return now when this function is called on earlier versions
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // of Windows.
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::win::GetVersion() < base::win::VERSION_WIN7)
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create an ICustomDestinationList object and attach it to our application.
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedComPtr<ICustomDestinationList> destination_list;
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT result = destination_list.CreateInstance(CLSID_DestinationList, NULL,
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   CLSCTX_INPROC_SERVER);
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(result))
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set the App ID for this JumpList.
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  destination_list->SetAppID(app_id);
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start a transaction that updates the JumpList of this application.
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This implementation just replaces the all items in this JumpList, so
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we don't have to use the IObjectArray object returned from this call.
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It seems Windows 7 RC (Build 7100) automatically checks the items in this
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // removed list and prevent us from adding the same item.
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UINT max_slots;
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedComPtr<IObjectArray> removed;
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = destination_list->BeginList(&max_slots, __uuidof(*removed),
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       reinterpret_cast<void**>(&removed));
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(result))
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Retrieve the absolute path to "chrome.exe".
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath chrome_path;
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!PathService::Get(base::FILE_EXE, &chrome_path))
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Retrieve the command-line switches of this process.
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandLine command_line(CommandLine::NO_PROGRAM);
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath user_data_dir = CommandLine::ForCurrentProcess()->
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetSwitchValuePath(switches::kUserDataDir);
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!user_data_dir.empty())
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    command_line.AppendSwitchPath(switches::kUserDataDir, user_data_dir);
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::wstring chrome_switches = command_line.GetCommandLineString();
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We allocate 60% of the given JumpList slots to "most-visited" items
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and 40% to "recently-closed" items, respectively.
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Nevertheless, if there are not so many items in |recently_closed_pages|,
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we give the remaining slots to "most-visited" items.
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int kMostVisited = 60;
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int kRecentlyClosed = 40;
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int kTotal = kMostVisited + kRecentlyClosed;
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t most_visited_items = MulDiv(max_slots, kMostVisited, kTotal);
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t recently_closed_items = max_slots - most_visited_items;
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (recently_closed_pages.size() < recently_closed_items) {
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    most_visited_items += recently_closed_items - recently_closed_pages.size();
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    recently_closed_items = recently_closed_pages.size();
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Update the "Most Visited" category of the JumpList.
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This update request is applied into the JumpList when we commit this
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // transaction.
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = UpdateCategory(destination_list, IDS_NEW_TAB_MOST_VISITED,
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          chrome_path.value(), chrome_switches,
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          most_visited_pages, most_visited_items);
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(result))
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Update the "Recently Closed" category of the JumpList.
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = UpdateCategory(destination_list, IDS_NEW_TAB_RECENTLY_CLOSED,
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          chrome_path.value(), chrome_switches,
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          recently_closed_pages, recently_closed_items);
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(result))
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Update the "Tasks" category of the JumpList.
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = UpdateTaskCategory(destination_list, chrome_path.value(),
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              chrome_switches);
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(result))
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Commit this transaction and send the updated JumpList to Windows.
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = destination_list->CommitList();
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(result))
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JumpList::JumpList()
466c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    : weak_ptr_factory_(this),
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile_(NULL),
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      task_id_(CancelableTaskTracker::kBadTaskId) {
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JumpList::~JumpList() {
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Terminate();
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool JumpList::Enabled() {
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (base::win::GetVersion() >= base::win::VERSION_WIN7 &&
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          !CommandLine::ForCurrentProcess()->HasSwitch(
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              switches::kDisableCustomJumpList));
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool JumpList::AddObserver(Profile* profile) {
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // To update JumpList when a tab is added or removed, we add this object to
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the observer list of the TabRestoreService class.
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // When we add this object to the observer list, we save the pointer to this
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TabRestoreService object. This pointer is used when we remove this object
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // from the observer list.
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::win::GetVersion() < base::win::VERSION_WIN7 || !profile)
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TabRestoreService* tab_restore_service =
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      TabRestoreServiceFactory::GetForProfile(profile);
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!tab_restore_service)
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  app_id_ = ShellIntegration::GetChromiumModelIdForProfile(profile->GetPath());
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icon_dir_ = profile->GetPath().Append(chrome::kJumpListIconDirname);
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  profile_ = profile;
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  history::TopSites* top_sites = profile_->GetTopSites();
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (top_sites) {
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TopSites updates itself after a delay. This is especially noticable when
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // your profile is empty. Ask TopSites to update itself when jumplist is
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // initialized.
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    top_sites->SyncWithHistory();
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    registrar_.reset(new content::NotificationRegistrar);
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Register for notification when TopSites changes so that we can update
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // ourself.
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    registrar_->Add(this, chrome::NOTIFICATION_TOP_SITES_CHANGED,
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    content::Source<history::TopSites>(top_sites));
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Register for notification when profile is destroyed to ensure that all
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // observers are detatched at that time.
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    registrar_->Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    content::Source<Profile>(profile_));
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tab_restore_service->AddObserver(this);
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void JumpList::Observe(int type,
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const content::NotificationSource& source,
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const content::NotificationDetails& details) {
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (type) {
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case chrome::NOTIFICATION_TOP_SITES_CHANGED: {
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Most visited urls changed, query again.
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      history::TopSites* top_sites = profile_->GetTopSites();
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (top_sites) {
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        top_sites->GetMostVisitedURLs(
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            base::Bind(&JumpList::OnMostVisitedURLsAvailable,
529f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                       weak_ptr_factory_.GetWeakPtr()), false);
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case chrome::NOTIFICATION_PROFILE_DESTROYED: {
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Profile was destroyed, do clean-up.
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Terminate();
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Unexpected notification type.";
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void JumpList::RemoveObserver() {
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (profile_) {
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TabRestoreService* tab_restore_service =
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        TabRestoreServiceFactory::GetForProfile(profile_);
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (tab_restore_service)
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab_restore_service->RemoveObserver(this);
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    registrar_.reset();
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  profile_ = NULL;
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void JumpList::CancelPendingUpdate() {
5552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (task_id_ != CancelableTaskTracker::kBadTaskId) {
5562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    cancelable_task_tracker_.TryCancel(task_id_);
5572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    task_id_ = CancelableTaskTracker::kBadTaskId;
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void JumpList::Terminate() {
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CancelPendingUpdate();
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RemoveObserver();
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void JumpList::OnMostVisitedURLsAvailable(
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const history::MostVisitedURLList& data) {
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we have a pending favicon request, cancel it here (it is out of date).
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CancelPendingUpdate();
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock auto_lock(list_lock_);
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    most_visited_pages_.clear();
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < data.size(); i++) {
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const history::MostVisitedURL& url = data[i];
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scoped_refptr<ShellLinkItem> link(new ShellLinkItem);
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string url_string = url.url.spec();
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      link->SetArguments(UTF8ToWide(url_string));
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      link->SetTitle(!url.title.empty()? url.title : link->arguments());
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      most_visited_pages_.push_back(link);
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      icon_urls_.push_back(make_pair(url_string, link));
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Send a query that retrieves the first favicon.
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StartLoadingFavicon();
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void JumpList::TabRestoreServiceChanged(TabRestoreService* service) {
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // if we have a pending handle request, cancel it here (it is out of date).
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CancelPendingUpdate();
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // local list to pass to methods
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ShellLinkItemList temp_list;
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create a list of ShellLinkItems from the "Recently Closed" pages.
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // As noted above, we create a ShellLinkItem objects with the following
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // parameters.
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // * arguments
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   The last URL of the tab object.
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // * title
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   The title of the last URL.
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // * icon
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   An empty string. This value is to be updated in OnFaviconDataAvailable().
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This code is copied from
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // RecentlyClosedTabsHandler::TabRestoreServiceChanged() to emulate it.
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int kRecentlyClosedCount = 4;
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TabRestoreService* tab_restore_service =
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      TabRestoreServiceFactory::GetForProfile(profile_);
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const TabRestoreService::Entries& entries = tab_restore_service->entries();
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (TabRestoreService::Entries::const_iterator it = entries.begin();
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != entries.end(); ++it) {
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const TabRestoreService::Entry* entry = *it;
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (entry->type == TabRestoreService::TAB) {
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AddTab(static_cast<const TabRestoreService::Tab*>(entry),
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             &temp_list, kRecentlyClosedCount);
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (entry->type == TabRestoreService::WINDOW) {
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AddWindow(static_cast<const TabRestoreService::Window*>(entry),
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                &temp_list, kRecentlyClosedCount);
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Lock recently_closed_pages and copy temp_list into it.
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock auto_lock(list_lock_);
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    recently_closed_pages_ = temp_list;
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Send a query that retrieves the first favicon.
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StartLoadingFavicon();
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void JumpList::TabRestoreServiceDestroyed(TabRestoreService* service) {
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool JumpList::AddTab(const TabRestoreService::Tab* tab,
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      ShellLinkItemList* list,
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      size_t max_items) {
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This code adds the URL and the title strings of the given tab to the
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // specified list.
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (list->size() >= max_items)
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<ShellLinkItem> link(new ShellLinkItem);
645c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const sessions::SerializedNavigationEntry& current_navigation =
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tab->navigations.at(tab->current_navigation_index);
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string url = current_navigation.virtual_url().spec();
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  link->SetArguments(UTF8ToWide(url));
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  link->SetTitle(current_navigation.title());
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  list->push_back(link);
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icon_urls_.push_back(make_pair(url, link));
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void JumpList::AddWindow(const TabRestoreService::Window* window,
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         ShellLinkItemList* list,
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         size_t max_items) {
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This code enumerates al the tabs in the given window object and add their
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // URLs and titles to the list.
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!window->tabs.empty());
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < window->tabs.size(); ++i) {
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!AddTab(&window->tabs[i], list, max_items))
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void JumpList::StartLoadingFavicon() {
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL url;
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock auto_lock(list_lock_);
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (icon_urls_.empty()) {
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // No more favicons are needed by the application JumpList. Schedule a
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // RunUpdate call.
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::PostTask(
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          BrowserThread::FILE, FROM_HERE,
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::Bind(&JumpList::RunUpdate, this));
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Ask FaviconService if it has a favicon of a URL.
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // When FaviconService has one, it will call OnFaviconDataAvailable().
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    url = GURL(icon_urls_.front().first);
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FaviconService* favicon_service =
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FaviconServiceFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS);
6862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  task_id_ = favicon_service->GetFaviconImageForURL(
687f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      FaviconService::FaviconForURLParams(url,
68890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                          chrome::FAVICON,
6892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                          gfx::kFaviconSize),
6902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&JumpList::OnFaviconDataAvailable,
6912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 base::Unretained(this)),
6922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &cancelable_task_tracker_);
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void JumpList::OnFaviconDataAvailable(
69690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const chrome::FaviconImageResult& image_result) {
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If there is currently a favicon request in progress, it is now outdated,
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // as we have received another, so nullify the handle from the old request.
6992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  task_id_ = CancelableTaskTracker::kBadTaskId;
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // lock the list to set icon data and pop the url
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock auto_lock(list_lock_);
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Attach the received data to the ShellLinkItem object.
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This data will be decoded by the RunUpdate method.
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!image_result.image.IsEmpty()) {
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!icon_urls_.empty() && icon_urls_.front().second)
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        icon_urls_.front().second->SetIconData(image_result.image.AsBitmap());
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!icon_urls_.empty())
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      icon_urls_.pop_front();
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check whether we need to load more favicons.
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StartLoadingFavicon();
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void JumpList::RunUpdate() {
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ShellLinkItemList local_most_visited_pages;
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ShellLinkItemList local_recently_closed_pages;
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::AutoLock auto_lock(list_lock_);
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Make sure we are not out of date: if icon_urls_ is not empty, then
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // another notification has been received since we processed this one
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!icon_urls_.empty())
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Make local copies of lists so we can release the lock.
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    local_most_visited_pages = most_visited_pages_;
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    local_recently_closed_pages = recently_closed_pages_;
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Delete the directory which contains old icon files, rename the current
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // icon directory, and create a new directory which contains new JumpList
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // icon files.
7362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath icon_dir_old(icon_dir_.value() + L"Old");
7377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (base::PathExists(icon_dir_old))
7387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    base::DeleteFile(icon_dir_old, true);
739eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::Move(icon_dir_, icon_dir_old);
740a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::CreateDirectory(icon_dir_);
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create temporary icon files for shortcuts in the "Most Visited" category.
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CreateIconFiles(local_most_visited_pages);
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create temporary icon files for shortcuts in the "Recently Closed"
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // category.
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CreateIconFiles(local_recently_closed_pages);
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We finished collecting all resources needed for updating an appliation
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // JumpList. So, create a new JumpList and replace the current JumpList
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // with it.
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateJumpList(app_id_.c_str(), local_most_visited_pages,
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 local_recently_closed_pages);
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void JumpList::CreateIconFiles(const ShellLinkItemList& item_list) {
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (ShellLinkItemList::const_iterator item = item_list.begin();
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      item != item_list.end(); ++item) {
7592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath icon_path;
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (CreateIconFile((*item)->data(), icon_dir_, &icon_path))
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (*item)->SetIcon(icon_path.value(), 0, true);
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
764