widget/windows/JumpListBuilder.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "JumpListBuilder.h"
michael@0 7
michael@0 8 #include "nsError.h"
michael@0 9 #include "nsCOMPtr.h"
michael@0 10 #include "nsServiceManagerUtils.h"
michael@0 11 #include "nsAutoPtr.h"
michael@0 12 #include "nsString.h"
michael@0 13 #include "nsArrayUtils.h"
michael@0 14 #include "nsIMutableArray.h"
michael@0 15 #include "nsWidgetsCID.h"
michael@0 16 #include "WinTaskbar.h"
michael@0 17 #include "nsDirectoryServiceUtils.h"
michael@0 18 #include "nsISimpleEnumerator.h"
michael@0 19 #include "mozilla/Preferences.h"
michael@0 20 #include "nsStringStream.h"
michael@0 21 #include "nsNetUtil.h"
michael@0 22 #include "nsThreadUtils.h"
michael@0 23 #include "mozilla/LazyIdleThread.h"
michael@0 24
michael@0 25 #include "WinUtils.h"
michael@0 26
michael@0 27 // The amount of time, in milliseconds, that our IO thread will stay alive after the last event it processes.
michael@0 28 #define DEFAULT_THREAD_TIMEOUT_MS 30000
michael@0 29
michael@0 30 namespace mozilla {
michael@0 31 namespace widget {
michael@0 32
michael@0 33 static NS_DEFINE_CID(kJumpListItemCID, NS_WIN_JUMPLISTITEM_CID);
michael@0 34 static NS_DEFINE_CID(kJumpListLinkCID, NS_WIN_JUMPLISTLINK_CID);
michael@0 35 static NS_DEFINE_CID(kJumpListShortcutCID, NS_WIN_JUMPLISTSHORTCUT_CID);
michael@0 36
michael@0 37 // defined in WinTaskbar.cpp
michael@0 38 extern const wchar_t *gMozillaJumpListIDGeneric;
michael@0 39
michael@0 40 bool JumpListBuilder::sBuildingList = false;
michael@0 41 const char kPrefTaskbarEnabled[] = "browser.taskbar.lists.enabled";
michael@0 42
michael@0 43 NS_IMPL_ISUPPORTS(JumpListBuilder, nsIJumpListBuilder, nsIObserver)
michael@0 44
michael@0 45 JumpListBuilder::JumpListBuilder() :
michael@0 46 mMaxItems(0),
michael@0 47 mHasCommit(false)
michael@0 48 {
michael@0 49 ::CoInitialize(nullptr);
michael@0 50
michael@0 51 CoCreateInstance(CLSID_DestinationList, nullptr, CLSCTX_INPROC_SERVER,
michael@0 52 IID_ICustomDestinationList, getter_AddRefs(mJumpListMgr));
michael@0 53
michael@0 54 // Make a lazy thread for any IO
michael@0 55 mIOThread = new LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS,
michael@0 56 NS_LITERAL_CSTRING("Jump List"),
michael@0 57 LazyIdleThread::ManualShutdown);
michael@0 58 Preferences::AddStrongObserver(this, kPrefTaskbarEnabled);
michael@0 59 }
michael@0 60
michael@0 61 JumpListBuilder::~JumpListBuilder()
michael@0 62 {
michael@0 63 mIOThread->Shutdown();
michael@0 64 Preferences::RemoveObserver(this, kPrefTaskbarEnabled);
michael@0 65 mJumpListMgr = nullptr;
michael@0 66 ::CoUninitialize();
michael@0 67 }
michael@0 68
michael@0 69 /* readonly attribute short available; */
michael@0 70 NS_IMETHODIMP JumpListBuilder::GetAvailable(int16_t *aAvailable)
michael@0 71 {
michael@0 72 *aAvailable = false;
michael@0 73
michael@0 74 if (mJumpListMgr)
michael@0 75 *aAvailable = true;
michael@0 76
michael@0 77 return NS_OK;
michael@0 78 }
michael@0 79
michael@0 80 /* readonly attribute boolean isListCommitted; */
michael@0 81 NS_IMETHODIMP JumpListBuilder::GetIsListCommitted(bool *aCommit)
michael@0 82 {
michael@0 83 *aCommit = mHasCommit;
michael@0 84
michael@0 85 return NS_OK;
michael@0 86 }
michael@0 87
michael@0 88 /* readonly attribute short maxItems; */
michael@0 89 NS_IMETHODIMP JumpListBuilder::GetMaxListItems(int16_t *aMaxItems)
michael@0 90 {
michael@0 91 if (!mJumpListMgr)
michael@0 92 return NS_ERROR_NOT_AVAILABLE;
michael@0 93
michael@0 94 *aMaxItems = 0;
michael@0 95
michael@0 96 if (sBuildingList) {
michael@0 97 *aMaxItems = mMaxItems;
michael@0 98 return NS_OK;
michael@0 99 }
michael@0 100
michael@0 101 IObjectArray *objArray;
michael@0 102 if (SUCCEEDED(mJumpListMgr->BeginList(&mMaxItems, IID_PPV_ARGS(&objArray)))) {
michael@0 103 *aMaxItems = mMaxItems;
michael@0 104
michael@0 105 if (objArray)
michael@0 106 objArray->Release();
michael@0 107
michael@0 108 mJumpListMgr->AbortList();
michael@0 109 }
michael@0 110
michael@0 111 return NS_OK;
michael@0 112 }
michael@0 113
michael@0 114 /* boolean initListBuild(in nsIMutableArray removedItems); */
michael@0 115 NS_IMETHODIMP JumpListBuilder::InitListBuild(nsIMutableArray *removedItems, bool *_retval)
michael@0 116 {
michael@0 117 NS_ENSURE_ARG_POINTER(removedItems);
michael@0 118
michael@0 119 *_retval = false;
michael@0 120
michael@0 121 if (!mJumpListMgr)
michael@0 122 return NS_ERROR_NOT_AVAILABLE;
michael@0 123
michael@0 124 if(sBuildingList)
michael@0 125 AbortListBuild();
michael@0 126
michael@0 127 IObjectArray *objArray;
michael@0 128
michael@0 129 if (SUCCEEDED(mJumpListMgr->BeginList(&mMaxItems, IID_PPV_ARGS(&objArray)))) {
michael@0 130 if (objArray) {
michael@0 131 TransferIObjectArrayToIMutableArray(objArray, removedItems);
michael@0 132 objArray->Release();
michael@0 133 }
michael@0 134
michael@0 135 RemoveIconCacheForItems(removedItems);
michael@0 136
michael@0 137 sBuildingList = true;
michael@0 138 *_retval = true;
michael@0 139 return NS_OK;
michael@0 140 }
michael@0 141
michael@0 142 return NS_OK;
michael@0 143 }
michael@0 144
michael@0 145 // Ensures that we don't have old ICO files that aren't in our jump lists
michael@0 146 // anymore left over in the cache.
michael@0 147 nsresult JumpListBuilder::RemoveIconCacheForItems(nsIMutableArray *items)
michael@0 148 {
michael@0 149 NS_ENSURE_ARG_POINTER(items);
michael@0 150
michael@0 151 nsresult rv;
michael@0 152 uint32_t length;
michael@0 153 items->GetLength(&length);
michael@0 154 for (uint32_t i = 0; i < length; ++i) {
michael@0 155
michael@0 156 //Obtain an IJumpListItem and get the type
michael@0 157 nsCOMPtr<nsIJumpListItem> item = do_QueryElementAt(items, i);
michael@0 158 if (!item) {
michael@0 159 continue;
michael@0 160 }
michael@0 161 int16_t type;
michael@0 162 if (NS_FAILED(item->GetType(&type))) {
michael@0 163 continue;
michael@0 164 }
michael@0 165
michael@0 166 // If the item is a shortcut, remove its associated icon if any
michael@0 167 if (type == nsIJumpListItem::JUMPLIST_ITEM_SHORTCUT) {
michael@0 168 nsCOMPtr<nsIJumpListShortcut> shortcut = do_QueryInterface(item);
michael@0 169 if (shortcut) {
michael@0 170 nsCOMPtr<nsIURI> uri;
michael@0 171 rv = shortcut->GetFaviconPageUri(getter_AddRefs(uri));
michael@0 172 if (NS_SUCCEEDED(rv) && uri) {
michael@0 173
michael@0 174 // The local file path is stored inside the nsIURI
michael@0 175 // Get the nsIURI spec which stores the local path for the icon to remove
michael@0 176 nsAutoCString spec;
michael@0 177 nsresult rv = uri->GetSpec(spec);
michael@0 178 NS_ENSURE_SUCCESS(rv, rv);
michael@0 179
michael@0 180 nsCOMPtr<nsIRunnable> event
michael@0 181 = new mozilla::widget::AsyncDeleteIconFromDisk(NS_ConvertUTF8toUTF16(spec));
michael@0 182 mIOThread->Dispatch(event, NS_DISPATCH_NORMAL);
michael@0 183
michael@0 184 // The shortcut was generated from an IShellLinkW so IShellLinkW can
michael@0 185 // only tell us what the original icon is and not the URI.
michael@0 186 // So this field was used only temporarily as the actual icon file
michael@0 187 // path. It should be cleared.
michael@0 188 shortcut->SetFaviconPageUri(nullptr);
michael@0 189 }
michael@0 190 }
michael@0 191 }
michael@0 192
michael@0 193 } // end for
michael@0 194
michael@0 195 return NS_OK;
michael@0 196 }
michael@0 197
michael@0 198 // Ensures that we have no old ICO files left in the jump list cache
michael@0 199 nsresult JumpListBuilder::RemoveIconCacheForAllItems()
michael@0 200 {
michael@0 201 // Construct the path of our jump list cache
michael@0 202 nsCOMPtr<nsIFile> jumpListCacheDir;
michael@0 203 nsresult rv = NS_GetSpecialDirectory("ProfLDS",
michael@0 204 getter_AddRefs(jumpListCacheDir));
michael@0 205 NS_ENSURE_SUCCESS(rv, rv);
michael@0 206 rv = jumpListCacheDir->AppendNative(nsDependentCString(
michael@0 207 mozilla::widget::FaviconHelper::kJumpListCacheDir));
michael@0 208 NS_ENSURE_SUCCESS(rv, rv);
michael@0 209 nsCOMPtr<nsISimpleEnumerator> entries;
michael@0 210 rv = jumpListCacheDir->GetDirectoryEntries(getter_AddRefs(entries));
michael@0 211 NS_ENSURE_SUCCESS(rv, rv);
michael@0 212
michael@0 213 // Loop through each directory entry and remove all ICO files found
michael@0 214 do {
michael@0 215 bool hasMore = false;
michael@0 216 if (NS_FAILED(entries->HasMoreElements(&hasMore)) || !hasMore)
michael@0 217 break;
michael@0 218
michael@0 219 nsCOMPtr<nsISupports> supp;
michael@0 220 if (NS_FAILED(entries->GetNext(getter_AddRefs(supp))))
michael@0 221 break;
michael@0 222
michael@0 223 nsCOMPtr<nsIFile> currFile(do_QueryInterface(supp));
michael@0 224 nsAutoString path;
michael@0 225 if (NS_FAILED(currFile->GetPath(path)))
michael@0 226 continue;
michael@0 227
michael@0 228 int32_t len = path.Length();
michael@0 229 if (StringTail(path, 4).LowerCaseEqualsASCII(".ico")) {
michael@0 230 // Check if the cached ICO file exists
michael@0 231 bool exists;
michael@0 232 if (NS_FAILED(currFile->Exists(&exists)) || !exists)
michael@0 233 continue;
michael@0 234
michael@0 235 // We found an ICO file that exists, so we should remove it
michael@0 236 currFile->Remove(false);
michael@0 237 }
michael@0 238 } while(true);
michael@0 239
michael@0 240 return NS_OK;
michael@0 241 }
michael@0 242
michael@0 243 /* boolean addListToBuild(in short aCatType, [optional] in nsIArray items, [optional] in AString catName); */
michael@0 244 NS_IMETHODIMP JumpListBuilder::AddListToBuild(int16_t aCatType, nsIArray *items, const nsAString &catName, bool *_retval)
michael@0 245 {
michael@0 246 nsresult rv;
michael@0 247
michael@0 248 *_retval = false;
michael@0 249
michael@0 250 if (!mJumpListMgr)
michael@0 251 return NS_ERROR_NOT_AVAILABLE;
michael@0 252
michael@0 253 switch(aCatType) {
michael@0 254 case nsIJumpListBuilder::JUMPLIST_CATEGORY_TASKS:
michael@0 255 {
michael@0 256 NS_ENSURE_ARG_POINTER(items);
michael@0 257
michael@0 258 HRESULT hr;
michael@0 259 nsRefPtr<IObjectCollection> collection;
michael@0 260 hr = CoCreateInstance(CLSID_EnumerableObjectCollection, nullptr,
michael@0 261 CLSCTX_INPROC_SERVER, IID_IObjectCollection,
michael@0 262 getter_AddRefs(collection));
michael@0 263 if (FAILED(hr))
michael@0 264 return NS_ERROR_UNEXPECTED;
michael@0 265
michael@0 266 // Build the list
michael@0 267 uint32_t length;
michael@0 268 items->GetLength(&length);
michael@0 269 for (uint32_t i = 0; i < length; ++i) {
michael@0 270 nsCOMPtr<nsIJumpListItem> item = do_QueryElementAt(items, i);
michael@0 271 if (!item)
michael@0 272 continue;
michael@0 273 // Check for separators
michael@0 274 if (IsSeparator(item)) {
michael@0 275 nsRefPtr<IShellLinkW> link;
michael@0 276 rv = JumpListSeparator::GetSeparator(link);
michael@0 277 if (NS_FAILED(rv))
michael@0 278 return rv;
michael@0 279 collection->AddObject(link);
michael@0 280 continue;
michael@0 281 }
michael@0 282 // These should all be ShellLinks
michael@0 283 nsRefPtr<IShellLinkW> link;
michael@0 284 rv = JumpListShortcut::GetShellLink(item, link, mIOThread);
michael@0 285 if (NS_FAILED(rv))
michael@0 286 return rv;
michael@0 287 collection->AddObject(link);
michael@0 288 }
michael@0 289
michael@0 290 // We need IObjectArray to submit
michael@0 291 nsRefPtr<IObjectArray> pArray;
michael@0 292 hr = collection->QueryInterface(IID_IObjectArray, getter_AddRefs(pArray));
michael@0 293 if (FAILED(hr))
michael@0 294 return NS_ERROR_UNEXPECTED;
michael@0 295
michael@0 296 // Add the tasks
michael@0 297 hr = mJumpListMgr->AddUserTasks(pArray);
michael@0 298 if (SUCCEEDED(hr))
michael@0 299 *_retval = true;
michael@0 300 return NS_OK;
michael@0 301 }
michael@0 302 break;
michael@0 303 case nsIJumpListBuilder::JUMPLIST_CATEGORY_RECENT:
michael@0 304 {
michael@0 305 if (SUCCEEDED(mJumpListMgr->AppendKnownCategory(KDC_RECENT)))
michael@0 306 *_retval = true;
michael@0 307 return NS_OK;
michael@0 308 }
michael@0 309 break;
michael@0 310 case nsIJumpListBuilder::JUMPLIST_CATEGORY_FREQUENT:
michael@0 311 {
michael@0 312 if (SUCCEEDED(mJumpListMgr->AppendKnownCategory(KDC_FREQUENT)))
michael@0 313 *_retval = true;
michael@0 314 return NS_OK;
michael@0 315 }
michael@0 316 break;
michael@0 317 case nsIJumpListBuilder::JUMPLIST_CATEGORY_CUSTOMLIST:
michael@0 318 {
michael@0 319 NS_ENSURE_ARG_POINTER(items);
michael@0 320
michael@0 321 if (catName.IsEmpty())
michael@0 322 return NS_ERROR_INVALID_ARG;
michael@0 323
michael@0 324 HRESULT hr;
michael@0 325 nsRefPtr<IObjectCollection> collection;
michael@0 326 hr = CoCreateInstance(CLSID_EnumerableObjectCollection, nullptr,
michael@0 327 CLSCTX_INPROC_SERVER, IID_IObjectCollection,
michael@0 328 getter_AddRefs(collection));
michael@0 329 if (FAILED(hr))
michael@0 330 return NS_ERROR_UNEXPECTED;
michael@0 331
michael@0 332 uint32_t length;
michael@0 333 items->GetLength(&length);
michael@0 334 for (uint32_t i = 0; i < length; ++i) {
michael@0 335 nsCOMPtr<nsIJumpListItem> item = do_QueryElementAt(items, i);
michael@0 336 if (!item)
michael@0 337 continue;
michael@0 338 int16_t type;
michael@0 339 if (NS_FAILED(item->GetType(&type)))
michael@0 340 continue;
michael@0 341 switch(type) {
michael@0 342 case nsIJumpListItem::JUMPLIST_ITEM_SEPARATOR:
michael@0 343 {
michael@0 344 nsRefPtr<IShellLinkW> shellItem;
michael@0 345 rv = JumpListSeparator::GetSeparator(shellItem);
michael@0 346 if (NS_FAILED(rv))
michael@0 347 return rv;
michael@0 348 collection->AddObject(shellItem);
michael@0 349 }
michael@0 350 break;
michael@0 351 case nsIJumpListItem::JUMPLIST_ITEM_LINK:
michael@0 352 {
michael@0 353 nsRefPtr<IShellItem2> shellItem;
michael@0 354 rv = JumpListLink::GetShellItem(item, shellItem);
michael@0 355 if (NS_FAILED(rv))
michael@0 356 return rv;
michael@0 357 collection->AddObject(shellItem);
michael@0 358 }
michael@0 359 break;
michael@0 360 case nsIJumpListItem::JUMPLIST_ITEM_SHORTCUT:
michael@0 361 {
michael@0 362 nsRefPtr<IShellLinkW> shellItem;
michael@0 363 rv = JumpListShortcut::GetShellLink(item, shellItem, mIOThread);
michael@0 364 if (NS_FAILED(rv))
michael@0 365 return rv;
michael@0 366 collection->AddObject(shellItem);
michael@0 367 }
michael@0 368 break;
michael@0 369 }
michael@0 370 }
michael@0 371
michael@0 372 // We need IObjectArray to submit
michael@0 373 nsRefPtr<IObjectArray> pArray;
michael@0 374 hr = collection->QueryInterface(IID_IObjectArray, (LPVOID*)&pArray);
michael@0 375 if (FAILED(hr))
michael@0 376 return NS_ERROR_UNEXPECTED;
michael@0 377
michael@0 378 // Add the tasks
michael@0 379 hr = mJumpListMgr->AppendCategory(reinterpret_cast<const wchar_t*>(catName.BeginReading()), pArray);
michael@0 380 if (SUCCEEDED(hr))
michael@0 381 *_retval = true;
michael@0 382 return NS_OK;
michael@0 383 }
michael@0 384 break;
michael@0 385 }
michael@0 386 return NS_OK;
michael@0 387 }
michael@0 388
michael@0 389 /* void abortListBuild(); */
michael@0 390 NS_IMETHODIMP JumpListBuilder::AbortListBuild()
michael@0 391 {
michael@0 392 if (!mJumpListMgr)
michael@0 393 return NS_ERROR_NOT_AVAILABLE;
michael@0 394
michael@0 395 mJumpListMgr->AbortList();
michael@0 396 sBuildingList = false;
michael@0 397
michael@0 398 return NS_OK;
michael@0 399 }
michael@0 400
michael@0 401 /* boolean commitListBuild(); */
michael@0 402 NS_IMETHODIMP JumpListBuilder::CommitListBuild(bool *_retval)
michael@0 403 {
michael@0 404 *_retval = false;
michael@0 405
michael@0 406 if (!mJumpListMgr)
michael@0 407 return NS_ERROR_NOT_AVAILABLE;
michael@0 408
michael@0 409 HRESULT hr = mJumpListMgr->CommitList();
michael@0 410 sBuildingList = false;
michael@0 411
michael@0 412 // XXX We might want some specific error data here.
michael@0 413 if (SUCCEEDED(hr)) {
michael@0 414 *_retval = true;
michael@0 415 mHasCommit = true;
michael@0 416 }
michael@0 417
michael@0 418 return NS_OK;
michael@0 419 }
michael@0 420
michael@0 421 /* boolean deleteActiveList(); */
michael@0 422 NS_IMETHODIMP JumpListBuilder::DeleteActiveList(bool *_retval)
michael@0 423 {
michael@0 424 *_retval = false;
michael@0 425
michael@0 426 if (!mJumpListMgr)
michael@0 427 return NS_ERROR_NOT_AVAILABLE;
michael@0 428
michael@0 429 if(sBuildingList)
michael@0 430 AbortListBuild();
michael@0 431
michael@0 432 nsAutoString uid;
michael@0 433 if (!WinTaskbar::GetAppUserModelID(uid))
michael@0 434 return NS_OK;
michael@0 435
michael@0 436 if (SUCCEEDED(mJumpListMgr->DeleteList(uid.get())))
michael@0 437 *_retval = true;
michael@0 438
michael@0 439 return NS_OK;
michael@0 440 }
michael@0 441
michael@0 442 /* internal */
michael@0 443
michael@0 444 bool JumpListBuilder::IsSeparator(nsCOMPtr<nsIJumpListItem>& item)
michael@0 445 {
michael@0 446 int16_t type;
michael@0 447 item->GetType(&type);
michael@0 448 if (NS_FAILED(item->GetType(&type)))
michael@0 449 return false;
michael@0 450
michael@0 451 if (type == nsIJumpListItem::JUMPLIST_ITEM_SEPARATOR)
michael@0 452 return true;
michael@0 453 return false;
michael@0 454 }
michael@0 455
michael@0 456 // TransferIObjectArrayToIMutableArray - used in converting removed items
michael@0 457 // to our objects.
michael@0 458 nsresult JumpListBuilder::TransferIObjectArrayToIMutableArray(IObjectArray *objArray, nsIMutableArray *removedItems)
michael@0 459 {
michael@0 460 NS_ENSURE_ARG_POINTER(objArray);
michael@0 461 NS_ENSURE_ARG_POINTER(removedItems);
michael@0 462
michael@0 463 nsresult rv;
michael@0 464
michael@0 465 uint32_t count = 0;
michael@0 466 objArray->GetCount(&count);
michael@0 467
michael@0 468 nsCOMPtr<nsIJumpListItem> item;
michael@0 469
michael@0 470 for (uint32_t idx = 0; idx < count; idx++) {
michael@0 471 IShellLinkW * pLink = nullptr;
michael@0 472 IShellItem * pItem = nullptr;
michael@0 473
michael@0 474 if (SUCCEEDED(objArray->GetAt(idx, IID_IShellLinkW, (LPVOID*)&pLink))) {
michael@0 475 nsCOMPtr<nsIJumpListShortcut> shortcut =
michael@0 476 do_CreateInstance(kJumpListShortcutCID, &rv);
michael@0 477 if (NS_FAILED(rv))
michael@0 478 return NS_ERROR_UNEXPECTED;
michael@0 479 rv = JumpListShortcut::GetJumpListShortcut(pLink, shortcut);
michael@0 480 item = do_QueryInterface(shortcut);
michael@0 481 }
michael@0 482 else if (SUCCEEDED(objArray->GetAt(idx, IID_IShellItem, (LPVOID*)&pItem))) {
michael@0 483 nsCOMPtr<nsIJumpListLink> link =
michael@0 484 do_CreateInstance(kJumpListLinkCID, &rv);
michael@0 485 if (NS_FAILED(rv))
michael@0 486 return NS_ERROR_UNEXPECTED;
michael@0 487 rv = JumpListLink::GetJumpListLink(pItem, link);
michael@0 488 item = do_QueryInterface(link);
michael@0 489 }
michael@0 490
michael@0 491 if (pLink)
michael@0 492 pLink->Release();
michael@0 493 if (pItem)
michael@0 494 pItem->Release();
michael@0 495
michael@0 496 if (NS_SUCCEEDED(rv)) {
michael@0 497 removedItems->AppendElement(item, false);
michael@0 498 }
michael@0 499 }
michael@0 500 return NS_OK;
michael@0 501 }
michael@0 502
michael@0 503 NS_IMETHODIMP JumpListBuilder::Observe(nsISupports* aSubject,
michael@0 504 const char* aTopic,
michael@0 505 const char16_t* aData)
michael@0 506 {
michael@0 507 if (nsDependentString(aData).EqualsASCII(kPrefTaskbarEnabled)) {
michael@0 508 bool enabled = Preferences::GetBool(kPrefTaskbarEnabled, true);
michael@0 509 if (!enabled) {
michael@0 510
michael@0 511 nsCOMPtr<nsIRunnable> event =
michael@0 512 new mozilla::widget::AsyncDeleteAllFaviconsFromDisk();
michael@0 513 mIOThread->Dispatch(event, NS_DISPATCH_NORMAL);
michael@0 514 }
michael@0 515 }
michael@0 516 return NS_OK;
michael@0 517 }
michael@0 518
michael@0 519 } // namespace widget
michael@0 520 } // namespace mozilla
michael@0 521

mercurial