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

Side by Side Diff: chrome/browser/jumplist.cc

Issue 56175: Integrates a custom JumpList of Windows 7.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/jumplist.h ('k') | chrome/browser/views/frame/browser_view.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/jumplist.h"
6
7 #include <windows.h>
8 #include <shobjidl.h>
9 #include <propkey.h>
10 #include <propvarutil.h>
11
12 #include <string>
13 #include <vector>
14
15 #include "app/gfx/icon_util.h"
16 #include "app/l10n_util.h"
17 #include "base/command_line.h"
18 #include "base/file_util.h"
19 #include "base/gfx/png_decoder.h"
20 #include "base/path_service.h"
21 #include "base/scoped_comptr_win.h"
22 #include "base/string_util.h"
23 #include "base/thread.h"
24 #include "base/win_util.h"
25 #include "chrome/browser/browser_process.h"
26 #include "chrome/browser/history/history.h"
27 #include "chrome/browser/history/page_usage_data.h"
28 #include "chrome/browser/profile.h"
29 #include "chrome/browser/sessions/tab_restore_service.h"
30 #include "chrome/common/chrome_constants.h"
31 #include "chrome/common/chrome_switches.h"
32 #include "chrome/common/url_constants.h"
33 #include "googleurl/src/gurl.h"
34 #include "third_party/skia/include/core/SkBitmap.h"
35
36 #include "grit/generated_resources.h"
37
38 namespace {
39
40 // COM interfaces used in this file.
41 // These interface declarations are copied from Windows SDK 7.0.
42 // TODO(hbono): Bug 16903: to be deleted them when we use Windows SDK 7.0.
43 #ifndef __IObjectArray_INTERFACE_DEFINED__
44 #define __IObjectArray_INTERFACE_DEFINED__
45
46 MIDL_INTERFACE("92CA9DCD-5622-4bba-A805-5E9F541BD8C9")
47 IObjectArray : public IUnknown {
48 public:
49 virtual HRESULT STDMETHODCALLTYPE GetCount(
50 /* [out] */ __RPC__out UINT *pcObjects) = 0;
51 virtual HRESULT STDMETHODCALLTYPE GetAt(
52 /* [in] */ UINT uiIndex,
53 /* [in] */ __RPC__in REFIID riid,
54 /* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0;
55 };
56
57 #endif // __IObjectArray_INTERFACE_DEFINED__
58
59 #ifndef __IObjectCollection_INTERFACE_DEFINED__
60 #define __IObjectCollection_INTERFACE_DEFINED__
61
62 MIDL_INTERFACE("5632b1a4-e38a-400a-928a-d4cd63230295")
63 IObjectCollection : public IObjectArray {
64 public:
65 virtual HRESULT STDMETHODCALLTYPE AddObject(
66 /* [in] */ __RPC__in_opt IUnknown *punk) = 0;
67 virtual HRESULT STDMETHODCALLTYPE AddFromArray(
68 /* [in] */ __RPC__in_opt IObjectArray *poaSource) = 0;
69 virtual HRESULT STDMETHODCALLTYPE RemoveObjectAt(
70 /* [in] */ UINT uiIndex) = 0;
71 virtual HRESULT STDMETHODCALLTYPE Clear(void) = 0;
72 };
73
74 #endif // __IObjectCollection_INTERFACE_DEFINED__
75
76 #ifndef __ICustomDestinationList_INTERFACE_DEFINED__
77 #define __ICustomDestinationList_INTERFACE_DEFINED__
78
79 typedef /* [v1_enum] */ enum tagKNOWNDESTCATEGORY {
80 KDC_FREQUENT = 1,
81 KDC_RECENT = (KDC_FREQUENT + 1)
82 } KNOWNDESTCATEGORY;
83
84 MIDL_INTERFACE("6332debf-87b5-4670-90c0-5e57b408a49e")
85 ICustomDestinationList : public IUnknown {
86 public:
87 virtual HRESULT STDMETHODCALLTYPE SetAppID(
88 /* [string][in] */__RPC__in_string LPCWSTR pszAppID) = 0;
89 virtual HRESULT STDMETHODCALLTYPE BeginList(
90 /* [out] */ __RPC__out UINT *pcMaxSlots,
91 /* [in] */ __RPC__in REFIID riid,
92 /* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0;
93 virtual HRESULT STDMETHODCALLTYPE AppendCategory(
94 /* [string][in] */ __RPC__in_string LPCWSTR pszCategory,
95 /* [in] */ __RPC__in_opt IObjectArray *poa) = 0;
96 virtual HRESULT STDMETHODCALLTYPE AppendKnownCategory(
97 /* [in] */ KNOWNDESTCATEGORY category) = 0;
98 virtual HRESULT STDMETHODCALLTYPE AddUserTasks(
99 /* [in] */ __RPC__in_opt IObjectArray *poa) = 0;
100 virtual HRESULT STDMETHODCALLTYPE CommitList(void) = 0;
101 virtual HRESULT STDMETHODCALLTYPE GetRemovedDestinations(
102 /* [in] */ __RPC__in REFIID riid,
103 /* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0;
104 virtual HRESULT STDMETHODCALLTYPE DeleteList(
105 /* [string][in] */ __RPC__in_string LPCWSTR pszAppID) = 0;
106 virtual HRESULT STDMETHODCALLTYPE AbortList(void) = 0;
107 };
108
109 #endif // __ICustomDestinationList_INTERFACE_DEFINED__
110
111 // Class IDs used in this file.
112 // These class IDs should be defined in an anonymous namespace to avoid
113 // potential conflicts with ones defined in "shell32.lib" of Microsoft SDK 7.0.
114 // TODO(hbono): Bug 16903: to be deleted them when we use Windows SDK 7.0.
115 EXTERN_C const CLSID CLSID_DestinationList = {
116 0x77f10cf0, 0x3db5, 0x4966, {0xb5, 0x20, 0xb7, 0xc5, 0x4f, 0xd3, 0x5e, 0xd6}
117 };
118
119 EXTERN_C const CLSID CLSID_EnumerableObjectCollection = {
120 0x2d3468c1, 0x36a7, 0x43b6, {0xac, 0x24, 0xd3, 0xf0, 0x2f, 0xd9, 0x60, 0x7a}
121 };
122
123 }; // namespace
124
125 // END OF WINDOWS 7 SDK DEFINITIONS
126
127 namespace {
128
129 // Represents a class which encapsulates a PROPVARIANT object containing a
130 // string for AddShellLink().
131 // This class automatically deletes all the resources attached to the
132 // PROPVARIANT object in its destructor.
133 class PropVariantString {
134 public:
135 PropVariantString() {
136 property_.vt = VT_EMPTY;
137 }
138
139 HRESULT Init(const std::wstring& value) {
140 // Call InitPropVariantFromString() to initialize this PROPVARIANT object.
141 // To read <propvarutil.h>, it seems InitPropVariantFromString() is an
142 // inline function that initialize a PROPVARIANT object and calls
143 // SHStrDupW() to set a copy of its input string.
144 // So, we just calls it without creating a copy.
145 return InitPropVariantFromString(value.c_str(), &property_);
146 }
147
148 ~PropVariantString() {
149 if (property_.vt != VT_EMPTY)
150 PropVariantClear(&property_);
151 }
152
153 const PROPVARIANT& Get() {
154 return property_;
155 }
156
157 private:
158 PROPVARIANT property_;
159
160 DISALLOW_COPY_AND_ASSIGN(PropVariantString);
161 };
162
163 // Creates an IShellLink object.
164 // An IShellLink object is almost the same as an application shortcut, and it
165 // requires three items: the absolute path to an application, an argument
166 // string, and a title string.
167 HRESULT AddShellLink(ScopedComPtr<IObjectCollection> collection,
168 const std::wstring& application,
169 const std::wstring& switches,
170 scoped_refptr<ShellLinkItem> item) {
171 // Create an IShellLink object.
172 ScopedComPtr<IShellLink> link;
173 HRESULT result = link.CreateInstance(CLSID_ShellLink, NULL,
174 CLSCTX_INPROC_SERVER);
175 if (FAILED(result))
176 return result;
177
178 // Set the application path.
179 // We should exit this function when this call fails because it doesn't make
180 // any sense to add a shortcut that we cannot execute.
181 result = link->SetPath(application.c_str());
182 if (FAILED(result))
183 return result;
184
185 // Attach the command-line switches of this process before the given
186 // arguments and set it as the arguments of this IShellLink object.
187 // We also exit this function when this call fails because it isn't usuful to
188 // add a shortcut that cannot open the given page.
189 std::wstring arguments(switches);
190 if (!item->arguments().empty()) {
191 arguments.push_back(L' ');
192 arguments += item->arguments();
193 }
194 result = link->SetArguments(arguments.c_str());
195 if (FAILED(result))
196 return result;
197
198 // Attach the given icon path to this IShellLink object.
199 // Since an icon is an optional item for an IShellLink object, so we don't
200 // have to exit even when it fails.
201 if (!item->icon().empty())
202 link->SetIconLocation(item->icon().c_str(), item->index());
203
204 // Set the title of the IShellLink object.
205 // The IShellLink interface does not have any functions which update its
206 // title because this interface is originally for creating an application
207 // shortcut which doesn't have titles.
208 // So, we should use the IPropertyStore interface to set its title as
209 // listed in the steps below:
210 // 1. Retrieve the IPropertyStore interface from the IShellLink object;
211 // 2. Start a transaction that changes a value of the object with the
212 // IPropertyStore interface;
213 // 3. Create a string PROPVARIANT, and;
214 // 4. Call the IPropertyStore::SetValue() function to Set the title property
215 // of the IShellLink object.
216 // 5. Commit the transaction.
217 ScopedComPtr<IPropertyStore> property_store;
218 result = link.QueryInterface(property_store.Receive());
219 if (FAILED(result))
220 return result;
221
222 PropVariantString property_title;
223 result = property_title.Init(item->title());
224 if (FAILED(result))
225 return result;
226
227 result = property_store->SetValue(PKEY_Title, property_title.Get());
228 if (FAILED(result))
229 return result;
230
231 result = property_store->Commit();
232 if (FAILED(result))
233 return result;
234
235 // Add this IShellLink object to the given collection.
236 return collection->AddObject(link);
237 }
238
239 // Creates a temporary icon file to be shown in JumpList.
240 bool CreateIconFile(const SkBitmap& bitmap,
241 const std::wstring& icon_dir,
242 std::wstring* icon_path) {
243 // Retrieve the path to a temporary file.
244 // We don't have to care about the extension of this temporary file because
245 // JumpList does not care about it.
246 std::wstring path;
247 if (!file_util::CreateTemporaryFileNameInDir(icon_dir, &path))
248 return false;
249
250 // Create an icon file from the favicon attached to the given |page|, and
251 // save it as the temporary file.
252 if (!IconUtil::CreateIconFileFromSkBitmap(bitmap, path))
253 return false;
254
255 // Add this icon file to the list and return its absolute path.
256 // The IShellLink::SetIcon() function needs the absolute path to an icon.
257 icon_path->assign(path);
258 return true;
259 }
260
261 // Updates a specified category of an application JumpList.
262 // This function cannot update registered categories (such as "Tasks") because
263 // special steps are required for updating them.
264 // So, this function can be used only for adding an unregistered category.
265 // Parameters:
266 // * category_id (int)
267 // A string ID which contains the category name.
268 // * application (std::wstring)
269 // An application name to be used for creating JumpList items.
270 // Even though we can add command-line switches to this parameter, it is
271 // better to use the |switches| parameter below.
272 // * switches (std::wstring)
273 // Command-lien switches for the application. This string is to be added
274 // before the arguments of each ShellLinkItem object. If there aren't any
275 // switches, use an empty string.
276 // * data (ShellLinkItemList)
277 // A list of ShellLinkItem objects to be added under the specified category.
278 HRESULT UpdateCategory(ScopedComPtr<ICustomDestinationList> list,
279 int category_id,
280 const std::wstring& application,
281 const std::wstring& switches,
282 const ShellLinkItemList& data) {
283 // Exit this function when the given vector does not contain any items
284 // because an ICustomDestinationList::AppendCategory() call fails in this
285 // case.
286 if (data.empty())
287 return S_OK;
288
289 std::wstring category = l10n_util::GetString(category_id);
290
291 // Create an EnumerableObjectCollection object.
292 // We once add the given items to this collection object and add this
293 // collection to the JumpList.
294 ScopedComPtr<IObjectCollection> collection;
295 HRESULT result = collection.CreateInstance(CLSID_EnumerableObjectCollection,
296 NULL, CLSCTX_INPROC_SERVER);
297 if (FAILED(result))
298 return false;
299
300 for (ShellLinkItemList::const_iterator item = data.begin();
301 item != data.end(); ++item) {
302 scoped_refptr<ShellLinkItem> link(*item);
303 AddShellLink(collection, application, switches, link);
304 }
305
306 // We can now add the new list to the JumpList.
307 // The ICustomDestinationList::AppendCategory() function needs the
308 // IObjectArray interface to retrieve each item in the list. So, we retrive
309 // the IObjectArray interface from the IEnumeratableObjectCollection object
310 // and use it.
311 // It seems the ICustomDestinationList::AppendCategory() function just
312 // replaces all items in the given category with the ones in the new list.
313 ScopedComPtr<IObjectArray> object_array;
314 result = collection.QueryInterface(object_array.Receive());
315 if (FAILED(result))
316 return false;
317
318 return list->AppendCategory(category.c_str(), object_array);
319 }
320
321 // Updates the "Tasks" category of the JumpList.
322 // Even though this function is almost the same as UpdateCategory(), this
323 // function has the following differences:
324 // * The "Task" category is a registered category.
325 // We should use AddUserTasks() instead of AppendCategory().
326 // * The items in the "Task" category are static.
327 // We don't have to use a list.
328 HRESULT UpdateTaskCategory(ScopedComPtr<ICustomDestinationList> list,
329 const std::wstring& chrome_path,
330 const std::wstring& chrome_switches) {
331 // Create an EnumerableObjectCollection object to be added items of the
332 // "Task" category. (We can also use this object for the "Task" category.)
333 ScopedComPtr<IObjectCollection> collection;
334 HRESULT result = collection.CreateInstance(CLSID_EnumerableObjectCollection,
335 NULL, CLSCTX_INPROC_SERVER);
336 if (FAILED(result))
337 return result;
338
339 // Create an IShellLink object which launches Chrome, and add it to the
340 // collection. We use our application icon as the icon for this item.
341 // We remove '&' characters from this string so we can share it with our
342 // system menu.
343 scoped_refptr<ShellLinkItem> chrome(new ShellLinkItem);
344 std::wstring chrome_title(l10n_util::GetString(IDS_NEW_WINDOW));
345 ReplaceSubstringsAfterOffset(&chrome_title, 0, L"&", L"");
346 chrome->SetTitle(chrome_title);
347 chrome->SetIcon(chrome_path, 0, false);
348 AddShellLink(collection, chrome_path, chrome_switches, chrome);
349
350 // Create an IShellLink object which launches Chrome in incognito mode, and
351 // add it to the collection. We use our application icon as the icon for
352 // this item.
353 scoped_refptr<ShellLinkItem> incognito(new ShellLinkItem);
354 incognito->SetArguments(
355 CommandLine::PrefixedSwitchString(switches::kIncognito));
356 std::wstring incognito_title(l10n_util::GetString(IDS_NEW_INCOGNITO_WINDOW));
357 ReplaceSubstringsAfterOffset(&incognito_title, 0, L"&", L"");
358 incognito->SetTitle(incognito_title);
359 incognito->SetIcon(chrome_path, 0, false);
360 AddShellLink(collection, chrome_path, chrome_switches, incognito);
361
362 // We can now add the new list to the JumpList.
363 // ICustomDestinationList::AddUserTasks() also uses the IObjectArray
364 // interface to retrieve each item in the list. So, we retrieve the
365 // IObjectArray interface from the EnumerableObjectCollection object.
366 ScopedComPtr<IObjectArray> object_array;
367 result = collection.QueryInterface(object_array.Receive());
368 if (FAILED(result))
369 return result;
370
371 return list->AddUserTasks(object_array);
372 }
373
374 // Updates the application JumpList.
375 // This function encapsulates all OS-specific operations required for updating
376 // the Chromium JumpList, such as:
377 // * Creating an ICustomDestinationList instance;
378 // * Updating the categories of the ICustomDestinationList instance, and;
379 // * Sending it to Taskbar of Windows 7.
380 bool UpdateJumpList(const ShellLinkItemList& most_visited_pages,
381 const ShellLinkItemList& recently_closed_pages) {
382 // JumpList is implemented only on Windows 7 or later.
383 // So, we should return now when this function is called on earlier versions
384 // of Windows.
385 if (win_util::GetWinVersion() < win_util::WINVERSION_WIN7)
386 return true;
387
388 // Create an ICustomDestinationList object and attach it to our application.
389 ScopedComPtr<ICustomDestinationList> destination_list;
390 HRESULT result = destination_list.CreateInstance(CLSID_DestinationList, NULL,
391 CLSCTX_INPROC_SERVER);
392 if (FAILED(result))
393 return false;
394
395 // Start a transaction that updates the JumpList of this application.
396 // This implementation just replaces the all items in this JumpList, so
397 // we don't have to use the IObjectArray object returned from this call.
398 // It seems Windows 7 RC (Build 7100) automatically checks the items in this
399 // removed list and prevent us from adding the same item.
400 UINT max_slots;
401 ScopedComPtr<IObjectArray> removed;
402 result = destination_list->BeginList(&max_slots, __uuidof(*removed),
403 reinterpret_cast<void**>(&removed));
404 if (FAILED(result))
405 return false;
406
407 // Retrieve the absolute path to "chrome.exe".
408 std::wstring chrome_path;
409 if (!PathService::Get(base::FILE_EXE, &chrome_path))
410 return false;
411
412 // Retrieve the command-line switches of this process.
413 std::wstring chrome_switches;
414
415 // Update the "Most Visited" category of the JumpList.
416 // This update request is applied into the JumpList when we commit this
417 // transaction.
418 result = UpdateCategory(destination_list, IDS_NEW_TAB_MOST_VISITED,
419 chrome_path, chrome_switches, most_visited_pages);
420 if (FAILED(result))
421 return false;
422
423 // Update the "Recently Closed" category of the JumpList.
424 result = UpdateCategory(destination_list, IDS_NEW_TAB_RECENTLY_CLOSED,
425 chrome_path, chrome_switches, recently_closed_pages);
426 if (FAILED(result))
427 return false;
428
429 // Update the "Tasks" category of the JumpList.
430 result = UpdateTaskCategory(destination_list, chrome_path, chrome_switches);
431 if (FAILED(result))
432 return false;
433
434 // Commit this transaction and send the updated JumpList to Windows.
435 result = destination_list->CommitList();
436 if (FAILED(result))
437 return false;
438
439 return true;
440 }
441
442 // Represents a task which updates an application JumpList.
443 // This task encapsulates all I/O tasks and OS-specific tasks required for
444 // updating a JumpList from Chromium, such as:
445 // * Deleting the directory containing temporary icon files;
446 // * Creating temporary icon files used by the JumpList;
447 // * Creating an ICustomDestinationList instance;
448 // * Adding items in the ICustomDestinationList instance.
449 // To spawn this task,
450 // 1. Prepare objects required by this task:
451 // * a std::wstring that contains a temporary icons;
452 // * a ShellLinkItemList that contains the items of the "Most Visited"
453 // category, and;
454 // * a ShellLinkItemList that contains the items of the "Recently Closed"
455 // category.
456 // 2. Create a JumpListUpdateTask instance, and;
457 // 3. Post this task to the file thread.
458 class JumpListUpdateTask : public Task {
459 public:
460 JumpListUpdateTask(const std::wstring& icon_dir,
461 const ShellLinkItemList& most_visited_pages,
462 const ShellLinkItemList& recently_closed_pages)
463 : icon_dir_(icon_dir),
464 most_visited_pages_(most_visited_pages),
465 recently_closed_pages_(recently_closed_pages) {
466 }
467
468 private:
469 // Represents an entry point of this task.
470 // When we post this task to a file thread, the thread calls this function.
471 void Run();
472
473 // The directory which contains JumpList icons.
474 std::wstring icon_dir_;
475
476 // Items in the "Most Visited" category of the application JumpList.
477 ShellLinkItemList most_visited_pages_;
478
479 // Items in the "Recently Closed" category of the application JumpList.
480 ShellLinkItemList recently_closed_pages_;
481 };
482
483 void JumpListUpdateTask::Run() {
484 // Delete the directory which contains old icon files, rename the current
485 // icon directory, and create a new directory which contains new JumpList
486 // icon files.
487 std::wstring icon_dir_old(icon_dir_ + L"Old");
488 if (file_util::PathExists(icon_dir_old))
489 file_util::Delete(icon_dir_old, true);
490 file_util::Move(icon_dir_, icon_dir_old);
491 file_util::CreateDirectory(icon_dir_);
492
493 // Create temporary icon files for shortcuts in the "Most Visited" category.
494 for (ShellLinkItemList::const_iterator item = most_visited_pages_.begin();
495 item != most_visited_pages_.end(); ++item) {
496 SkBitmap icon_bitmap;
497 if ((*item)->data().get() &&
498 PNGDecoder::Decode(&(*item)->data()->data, &icon_bitmap)) {
499 std::wstring icon_path;
500 if (CreateIconFile(icon_bitmap, icon_dir_, &icon_path))
501 (*item)->SetIcon(icon_path, 0, true);
502 }
503 }
504
505 // Create temporary icon files for shortcuts in the "Recently Closed"
506 // category.
507 for (ShellLinkItemList::const_iterator item = recently_closed_pages_.begin();
508 item != recently_closed_pages_.end(); ++item) {
509 SkBitmap icon_bitmap;
510 if ((*item)->data().get() &&
511 PNGDecoder::Decode(&(*item)->data()->data, &icon_bitmap)) {
512 std::wstring icon_path;
513 if (CreateIconFile(icon_bitmap, icon_dir_, &icon_path))
514 (*item)->SetIcon(icon_path, 0, true);
515 }
516 }
517
518 // We finished collecting all resources needed for updating an appliation
519 // JumpList. So, create a new JumpList and replace the current JumpList
520 // with it.
521 UpdateJumpList(most_visited_pages_, recently_closed_pages_);
522
523 // Delete all items in these lists now since we don't need the ShellLinkItem
524 // objects in these lists.
525 most_visited_pages_.clear();
526 recently_closed_pages_.clear();
527 }
528
529 } // namespace
530
531 JumpList::JumpList() : profile_(NULL) {
532 }
533
534 JumpList::~JumpList() {
535 RemoveObserver();
536 }
537
538 // static
539 bool JumpList::Enabled() {
540 return (win_util::GetWinVersion() >= win_util::WINVERSION_WIN7 &&
541 CommandLine::ForCurrentProcess()->HasSwitch(
542 switches::kEnableCustomJumpList));
543 }
544
545 bool JumpList::AddObserver(Profile* profile) {
546 // To update JumpList when a tab is added or removed, we add this object to
547 // the observer list of the TabRestoreService class.
548 // When we add this object to the observer list, we save the pointer to this
549 // TabRestoreService object. This pointer is used when we remove this object
550 // from the observer list.
551 if (win_util::GetWinVersion() < win_util::WINVERSION_WIN7 || !profile)
552 return false;
553
554 TabRestoreService* tab_restore_service = profile->GetTabRestoreService();
555 if (!tab_restore_service)
556 return false;
557
558 icon_dir_ = profile->GetPath().Append(chrome::kJumpListIconDirname).value();
559 profile_ = profile;
560 tab_restore_service->AddObserver(this);
561 return true;
562 }
563
564 void JumpList::RemoveObserver() {
565 if (profile_ && profile_->GetTabRestoreService())
566 profile_->GetTabRestoreService()->RemoveObserver(this);
567 profile_ = NULL;
568 }
569
570 void JumpList::TabRestoreServiceChanged(TabRestoreService* service) {
571 // Added or removed a tab.
572 // Exit if we are updating the application JumpList.
573 if (!icon_urls_.empty())
574 return;
575
576 // Send a query to HistoryService and retrieve the "Most Visited" pages.
577 // This code is copied from MostVisitedHandler::HandleGetMostVisited() to
578 // emulate its behaviors.
579 const int kMostVisitedScope = 90;
580 const int kMostVisitedCount = 9;
581 int result_count = kMostVisitedCount;
582 HistoryService* history_service =
583 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
584 history_service->QuerySegmentUsageSince(
585 &most_visited_consumer_,
586 base::Time::Now() - base::TimeDelta::FromDays(kMostVisitedScope),
587 result_count,
588 NewCallback(this, &JumpList::OnSegmentUsageAvailable));
589 }
590
591 void JumpList::TabRestoreServiceDestroyed(TabRestoreService* service) {
592 }
593
594 bool JumpList::AddTab(const TabRestoreService::Tab* tab,
595 ShellLinkItemList* list,
596 size_t max_items) {
597 // This code adds the URL and the title strings of the given tab to the
598 // specified list.
599 // This code is copied from RecentlyClosedTabsHandler::TabToValue().
600 if (tab->navigations.empty() || list->size() >= max_items)
601 return false;
602
603 const TabNavigation& current_navigation =
604 tab->navigations.at(tab->current_navigation_index);
605 if (current_navigation.url() == GURL(chrome::kChromeUINewTabURL))
606 return false;
607
608 scoped_refptr<ShellLinkItem> link(new ShellLinkItem);
609 std::string url = current_navigation.url().spec();
610 link->SetArguments(UTF8ToWide(url));
611 link->SetTitle(current_navigation.title());
612 list->push_back(link);
613 icon_urls_.push_back(make_pair(url, link));
614 return true;
615 }
616
617 bool JumpList::AddWindow(const TabRestoreService::Window* window,
618 ShellLinkItemList* list,
619 size_t max_items) {
620 // This code enumerates al the tabs in the given window object and add their
621 // URLs and titles to the list.
622 // This code is copied from RecentlyClosedTabsHandler::WindowToValue().
623 if (window->tabs.empty()) {
624 NOTREACHED();
625 return false;
626 }
627 for (size_t i = 0; i < window->tabs.size(); ++i) {
628 if (!AddTab(&window->tabs[i], list, max_items))
629 return false;
630 }
631
632 return true;
633 }
634
635 bool JumpList::StartLoadingFavIcon() {
636 if (icon_urls_.empty())
637 return false;
638
639 // Ask HistoryService if it has a fav icon of a URL.
640 // When HistoryService has one, it will call OnFavIconDataAvailable().
641 GURL url(icon_urls_.front().first);
642 HistoryService* history_service =
643 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
644 HistoryService::Handle handle = history_service->GetFavIconForURL(
645 url, &fav_icon_consumer_,
646 NewCallback(this, &JumpList::OnFavIconDataAvailable));
647 return true;
648 }
649
650 void JumpList::OnSegmentUsageAvailable(
651 CancelableRequestProvider::Handle handle,
652 std::vector<PageUsageData*>* data) {
653 // Create a list of ShellLinkItem objects from the given list of
654 // PageUsageData objects.
655 // The command that opens a web page with chrome is:
656 // "chrome.exe <url-to-the-web-page>".
657 // So, we create a ShellLinkItem object with the following parameters.
658 // * arguments
659 // The URL of a PageUsagedata object (converted to std::wstring).
660 // * title
661 // The title of a PageUsageData object. If this string is empty, we use
662 // the URL as our "Most Visited" page does.
663 // * icon
664 // An empty string. This value is to be updated in OnFavIconDataAvailable().
665 most_visited_pages_.clear();
666 for (std::vector<PageUsageData*>::const_iterator page = data->begin();
667 page != data->end(); ++page) {
668 scoped_refptr<ShellLinkItem> link(new ShellLinkItem);
669 std::string url = (*page)->GetURL().spec();
670 link->SetArguments(UTF8ToWide(url));
671 link->SetTitle(
672 !(*page)->GetTitle().empty() ? (*page)->GetTitle() : link->arguments());
673 most_visited_pages_.push_back(link);
674 icon_urls_.push_back(make_pair(url, link));
675 }
676
677 // Create a list of ShellLinkItems from the "Recently Closed" pages.
678 // As noted above, we create a ShellLinkItem objects with the following
679 // parameters.
680 // * arguments
681 // The last URL of the tab object.
682 // * title
683 // The title of the last URL.
684 // * icon
685 // An empty string. This value is to be updated in OnFavIconDataAvailable().
686 // This code is copied from
687 // RecentlyClosedTabsHandler::TabRestoreServiceChanged() to emulate it.
688 recently_closed_pages_.clear();
689 TabRestoreService* tab_restore_service = profile_->GetTabRestoreService();
690 const TabRestoreService::Entries& entries = tab_restore_service->entries();
691 for (TabRestoreService::Entries::const_iterator it = entries.begin();
692 it != entries.end(); ++it) {
693 const TabRestoreService::Entry* entry = *it;
694 if (entry->type == TabRestoreService::TAB) {
695 AddTab(static_cast<const TabRestoreService::Tab*>(entry),
696 &recently_closed_pages_, 3);
697 } else if (entry->type == TabRestoreService::WINDOW) {
698 AddWindow(static_cast<const TabRestoreService::Window*>(entry),
699 &recently_closed_pages_, 3);
700 }
701 }
702
703 // Send a query that retrieves the first fav icon.
704 StartLoadingFavIcon();
705 }
706
707 void JumpList::OnFavIconDataAvailable(
708 HistoryService::Handle handle,
709 bool know_favicon,
710 scoped_refptr<RefCountedBytes> data,
711 bool expired,
712 GURL icon_url) {
713 // Attach the received data to the ShellLinkItem object.
714 // This data will be decoded by JumpListUpdateTask.
715 if (know_favicon && data.get() && !data->data.empty())
716 icon_urls_.front().second->SetIconData(data);
717
718 // if we need to load more fav icons, we send another query and exit.
719 icon_urls_.pop_front();
720 if (StartLoadingFavIcon())
721 return;
722
723 // Finished Loading all fav icons needed by the application JumpList.
724 // We create a JumpListUpdateTask that creates icon files, and we post it to
725 // the file thread.
726 Task* icon_task = new JumpListUpdateTask(icon_dir_,
727 most_visited_pages_,
728 recently_closed_pages_);
729 MessageLoop* file_loop = g_browser_process->file_thread()->message_loop();
730 if (file_loop)
731 file_loop->PostTask(FROM_HERE, icon_task);
732
733 // Delete all items in these lists since we don't need these lists any longer.
734 most_visited_pages_.clear();
735 recently_closed_pages_.clear();
736 }
OLDNEW
« no previous file with comments | « chrome/browser/jumplist.h ('k') | chrome/browser/views/frame/browser_view.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698