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