forked from mirrors/gecko-dev
Bug 1425144 - Init Jump list on lazy idle thread r=aklotz
We're already committing jump lists on mIOThread, and I see no errors or problems with initting on mIOThread either, so I think this is okay. Had to restructure some things to make using a Promise simple, and to avoid dispatching to mIOThread from within mIOThread (since we can only dispatch to a LazyIdleThread from the owner thread). MozReview-Commit-ID: 1imBF8Jzmn6 --HG-- extra : rebase_source : 4f912e819cec898910e72d95311e3924714a3090
This commit is contained in:
parent
c9cbf586a8
commit
56f41b91a9
5 changed files with 115 additions and 172 deletions
|
|
@ -6,7 +6,6 @@
|
|||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIArray;
|
||||
interface nsIMutableArray;
|
||||
|
||||
[scriptable, function, uuid(5131a62a-e99f-4631-9138-751f8aad1ae4)]
|
||||
interface nsIJumpListCommittedCallback : nsISupports
|
||||
|
|
@ -103,17 +102,17 @@ interface nsIJumpListBuilder : nsISupports
|
|||
readonly attribute short maxListItems;
|
||||
|
||||
/**
|
||||
* Initializes a jump list build and returns a list of items the user removed
|
||||
* since the last time a jump list was committed. Removed items can become state
|
||||
* after initListBuild is called, lists should be built in single-shot fasion.
|
||||
* Initializes a jump list build and returns a promise with the list of
|
||||
* items the user removed since the last time a jump list was committed.
|
||||
* Removed items can become state after initListBuild is called, lists
|
||||
* should be built in single-shot fasion.
|
||||
*
|
||||
* @param removedItems
|
||||
* A list of items that were removed by the user since the last commit.
|
||||
*
|
||||
* @returns true if the operation completed successfully.
|
||||
* @returns a promise with the list of items that were removed by the user
|
||||
* since the last commit.
|
||||
*/
|
||||
boolean initListBuild(in nsIMutableArray removedItems);
|
||||
|
||||
[implicit_jscontext]
|
||||
Promise initListBuild();
|
||||
|
||||
/**
|
||||
* Adds a list and if required, a set of items for the list.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -21,9 +21,13 @@
|
|||
#include "mozilla/LazyIdleThread.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
|
||||
#include <shellapi.h>
|
||||
#include "WinUtils.h"
|
||||
|
||||
using mozilla::dom::Promise;
|
||||
|
||||
// The amount of time, in milliseconds, that our IO thread will stay alive after the last event it processes.
|
||||
#define DEFAULT_THREAD_TIMEOUT_MS 30000
|
||||
|
||||
|
|
@ -177,91 +181,68 @@ NS_IMETHODIMP JumpListBuilder::GetMaxListItems(int16_t *aMaxItems)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP JumpListBuilder::InitListBuild(nsIMutableArray *removedItems, bool *_retval)
|
||||
NS_IMETHODIMP JumpListBuilder::InitListBuild(JSContext* aCx,
|
||||
Promise** aPromise)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(removedItems);
|
||||
|
||||
*_retval = false;
|
||||
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
if (!mJumpListMgr)
|
||||
if (!mJumpListMgr) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
if(sBuildingList)
|
||||
AbortListBuild();
|
||||
|
||||
IObjectArray *objArray;
|
||||
|
||||
// The returned objArray of removed items are for manually removed items.
|
||||
// This does not return items which are removed because they were previously
|
||||
// part of the jump list but are no longer part of the jump list.
|
||||
if (SUCCEEDED(mJumpListMgr->BeginList(&mMaxItems, IID_PPV_ARGS(&objArray)))) {
|
||||
if (objArray) {
|
||||
TransferIObjectArrayToIMutableArray(objArray, removedItems);
|
||||
objArray->Release();
|
||||
}
|
||||
|
||||
RemoveIconCacheForItems(removedItems);
|
||||
|
||||
sBuildingList = true;
|
||||
*_retval = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIGlobalObject* globalObject =
|
||||
xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
|
||||
|
||||
if (NS_WARN_IF(!globalObject)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
ErrorResult result;
|
||||
RefPtr<Promise> promise = Promise::Create(globalObject, result);
|
||||
if (NS_WARN_IF(result.Failed())) {
|
||||
return result.StealNSResult();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NewRunnableMethod<StoreCopyPassByRRef<RefPtr<Promise>>>("InitListBuild",
|
||||
this,
|
||||
&JumpListBuilder::DoInitListBuild,
|
||||
promise);
|
||||
nsresult rv = mIOThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
promise.forget(aPromise);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Ensures that we don't have old ICO files that aren't in our jump lists
|
||||
// anymore left over in the cache.
|
||||
nsresult JumpListBuilder::RemoveIconCacheForItems(nsIMutableArray *items)
|
||||
void JumpListBuilder::DoInitListBuild(RefPtr<Promise>&& aPromise)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(items);
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
MOZ_ASSERT(mJumpListMgr);
|
||||
|
||||
nsresult rv;
|
||||
uint32_t length;
|
||||
items->GetLength(&length);
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
if(sBuildingList) {
|
||||
AbortListBuild();
|
||||
}
|
||||
|
||||
//Obtain an IJumpListItem and get the type
|
||||
nsCOMPtr<nsIJumpListItem> item = do_QueryElementAt(items, i);
|
||||
if (!item) {
|
||||
continue;
|
||||
}
|
||||
int16_t type;
|
||||
if (NS_FAILED(item->GetType(&type))) {
|
||||
continue;
|
||||
}
|
||||
nsTArray<nsString> urisToRemove;
|
||||
RefPtr<IObjectArray> objArray;
|
||||
HRESULT hr = mJumpListMgr->BeginList(&mMaxItems,
|
||||
IID_PPV_ARGS(static_cast<IObjectArray**>
|
||||
(getter_AddRefs(objArray))));
|
||||
// The returned objArray of removed items are for manually removed items.
|
||||
// This does not return items which are removed because they were previously
|
||||
// part of the jump list but are no longer part of the jump list.
|
||||
if (SUCCEEDED(hr) && objArray) {
|
||||
sBuildingList = true;
|
||||
RemoveIconCacheAndGetJumplistShortcutURIs(objArray, urisToRemove);
|
||||
}
|
||||
|
||||
// If the item is a shortcut, remove its associated icon if any
|
||||
if (type == nsIJumpListItem::JUMPLIST_ITEM_SHORTCUT) {
|
||||
nsCOMPtr<nsIJumpListShortcut> shortcut = do_QueryInterface(item);
|
||||
if (shortcut) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = shortcut->GetFaviconPageUri(getter_AddRefs(uri));
|
||||
if (NS_SUCCEEDED(rv) && uri) {
|
||||
|
||||
// The local file path is stored inside the nsIURI
|
||||
// Get the nsIURI spec which stores the local path for the icon to remove
|
||||
nsAutoCString spec;
|
||||
nsresult rv = uri->GetSpec(spec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIRunnable> event
|
||||
= new mozilla::widget::AsyncDeleteIconFromDisk(NS_ConvertUTF8toUTF16(spec));
|
||||
mIOThread->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
|
||||
// The shortcut was generated from an IShellLinkW so IShellLinkW can
|
||||
// only tell us what the original icon is and not the URI.
|
||||
// So this field was used only temporarily as the actual icon file
|
||||
// path. It should be cleared.
|
||||
shortcut->SetFaviconPageUri(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end for
|
||||
|
||||
return NS_OK;
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction("InitListBuildResolve",
|
||||
[urisToRemove = std::move(urisToRemove),
|
||||
promise = std::move(aPromise)]() {
|
||||
promise->MaybeResolve(urisToRemove);
|
||||
}));
|
||||
}
|
||||
|
||||
// Ensures that we have no old ICO files left in the jump list cache
|
||||
|
|
@ -542,51 +523,64 @@ bool JumpListBuilder::IsSeparator(nsCOMPtr<nsIJumpListItem>& item)
|
|||
return false;
|
||||
}
|
||||
|
||||
// TransferIObjectArrayToIMutableArray - used in converting removed items
|
||||
// to our objects.
|
||||
nsresult JumpListBuilder::TransferIObjectArrayToIMutableArray(IObjectArray *objArray, nsIMutableArray *removedItems)
|
||||
// RemoveIconCacheAndGetJumplistShortcutURIs - does multiple things to
|
||||
// avoid unnecessary extra XPCOM incantations. For each object in the input
|
||||
// array, if it's an IShellLinkW, this deletes the cached icon and adds the
|
||||
// url param to a list of URLs to be removed from the places database.
|
||||
void JumpListBuilder::RemoveIconCacheAndGetJumplistShortcutURIs(IObjectArray *aObjArray,
|
||||
nsTArray<nsString>& aURISpecs)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(objArray);
|
||||
NS_ENSURE_ARG_POINTER(removedItems);
|
||||
|
||||
nsresult rv;
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
uint32_t count = 0;
|
||||
objArray->GetCount(&count);
|
||||
|
||||
nsCOMPtr<nsIJumpListItem> item;
|
||||
aObjArray->GetCount(&count);
|
||||
|
||||
for (uint32_t idx = 0; idx < count; idx++) {
|
||||
IShellLinkW * pLink = nullptr;
|
||||
IShellItem * pItem = nullptr;
|
||||
RefPtr<IShellLinkW> pLink;
|
||||
|
||||
if (SUCCEEDED(objArray->GetAt(idx, IID_IShellLinkW, (LPVOID*)&pLink))) {
|
||||
nsCOMPtr<nsIJumpListShortcut> shortcut =
|
||||
do_CreateInstance(kJumpListShortcutCID, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
rv = JumpListShortcut::GetJumpListShortcut(pLink, shortcut);
|
||||
item = do_QueryInterface(shortcut);
|
||||
}
|
||||
else if (SUCCEEDED(objArray->GetAt(idx, IID_IShellItem, (LPVOID*)&pItem))) {
|
||||
nsCOMPtr<nsIJumpListLink> link =
|
||||
do_CreateInstance(kJumpListLinkCID, &rv);
|
||||
if (NS_FAILED(rv))
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
rv = JumpListLink::GetJumpListLink(pItem, link);
|
||||
item = do_QueryInterface(link);
|
||||
if (FAILED(aObjArray->GetAt(idx, IID_IShellLinkW,
|
||||
static_cast<void**>(getter_AddRefs(pLink))))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pLink)
|
||||
pLink->Release();
|
||||
if (pItem)
|
||||
pItem->Release();
|
||||
wchar_t buf[MAX_PATH];
|
||||
HRESULT hres = pLink->GetArguments(buf, MAX_PATH);
|
||||
if (SUCCEEDED(hres)) {
|
||||
LPWSTR *arglist;
|
||||
int32_t numArgs;
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
removedItems->AppendElement(item);
|
||||
arglist = ::CommandLineToArgvW(buf, &numArgs);
|
||||
if(arglist && numArgs > 0) {
|
||||
nsString spec(arglist[0]);
|
||||
aURISpecs.AppendElement(std::move(spec));
|
||||
::LocalFree(arglist);
|
||||
}
|
||||
}
|
||||
|
||||
int iconIdx = 0;
|
||||
hres = pLink->GetIconLocation(buf, MAX_PATH, &iconIdx);
|
||||
if (SUCCEEDED(hres)) {
|
||||
nsDependentString spec(buf);
|
||||
DeleteIconFromDisk(spec);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void JumpListBuilder::DeleteIconFromDisk(const nsAString& aPath)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
// Check that we aren't deleting some arbitrary file that is not an icon
|
||||
if (StringTail(aPath, 4).LowerCaseEqualsASCII(".ico")) {
|
||||
// Construct the parent path of the passed in path
|
||||
nsCOMPtr<nsIFile> icoFile;
|
||||
nsresult rv = NS_NewLocalFile(aPath, true, getter_AddRefs(icoFile));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
icoFile->Remove(false);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP JumpListBuilder::Observe(nsISupports* aSubject,
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "nsIJumpListItem.h"
|
||||
#include "JumpListItem.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
|
||||
|
|
@ -37,7 +38,7 @@ class JumpListBuilder : public nsIJumpListBuilder,
|
|||
virtual ~JumpListBuilder();
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIJUMPLISTBUILDER
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
|
|
@ -54,10 +55,11 @@ private:
|
|||
ReentrantMonitor mMonitor;
|
||||
|
||||
bool IsSeparator(nsCOMPtr<nsIJumpListItem>& item);
|
||||
nsresult TransferIObjectArrayToIMutableArray(IObjectArray *objArray, nsIMutableArray *removedItems);
|
||||
nsresult RemoveIconCacheForItems(nsIMutableArray *removedItems);
|
||||
void RemoveIconCacheAndGetJumplistShortcutURIs(IObjectArray *aObjArray, nsTArray<nsString>& aURISpecs);
|
||||
void DeleteIconFromDisk(const nsAString& aPath);
|
||||
nsresult RemoveIconCacheForAllItems();
|
||||
void DoCommitListBuild(RefPtr<detail::DoneCommitListBuildCallback> aCallback);
|
||||
void DoInitListBuild(RefPtr<dom::Promise>&& aPromise);
|
||||
|
||||
friend class WinTaskbar;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -413,7 +413,6 @@ NS_IMPL_ISUPPORTS(myDownloadObserver, nsIDownloadObserver)
|
|||
NS_IMPL_ISUPPORTS(AsyncFaviconDataReady, nsIFaviconDataCallback)
|
||||
#endif
|
||||
NS_IMPL_ISUPPORTS(AsyncEncodeAndWriteIcon, nsIRunnable)
|
||||
NS_IMPL_ISUPPORTS(AsyncDeleteIconFromDisk, nsIRunnable)
|
||||
NS_IMPL_ISUPPORTS(AsyncDeleteAllFaviconsFromDisk, nsIRunnable)
|
||||
|
||||
|
||||
|
|
@ -1405,42 +1404,6 @@ AsyncEncodeAndWriteIcon::~AsyncEncodeAndWriteIcon()
|
|||
{
|
||||
}
|
||||
|
||||
AsyncDeleteIconFromDisk::AsyncDeleteIconFromDisk(const nsAString &aIconPath)
|
||||
: mIconPath(aIconPath)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP AsyncDeleteIconFromDisk::Run()
|
||||
{
|
||||
// Construct the parent path of the passed in path
|
||||
nsCOMPtr<nsIFile> icoFile = do_CreateInstance("@mozilla.org/file/local;1");
|
||||
NS_ENSURE_TRUE(icoFile, NS_ERROR_FAILURE);
|
||||
nsresult rv = icoFile->InitWithPath(mIconPath);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Check if the cached ICO file exists
|
||||
bool exists;
|
||||
rv = icoFile->Exists(&exists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Check that we aren't deleting some arbitrary file that is not an icon
|
||||
if (StringTail(mIconPath, 4).LowerCaseEqualsASCII(".ico")) {
|
||||
// Check if the cached ICO file exists
|
||||
bool exists;
|
||||
if (NS_FAILED(icoFile->Exists(&exists)) || !exists)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// We found an ICO file that exists, so we should remove it
|
||||
icoFile->Remove(false);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
AsyncDeleteIconFromDisk::~AsyncDeleteIconFromDisk()
|
||||
{
|
||||
}
|
||||
|
||||
AsyncDeleteAllFaviconsFromDisk::
|
||||
AsyncDeleteAllFaviconsFromDisk(bool aIgnoreRecent)
|
||||
: mIgnoreRecent(aIgnoreRecent)
|
||||
|
|
|
|||
|
|
@ -557,21 +557,6 @@ private:
|
|||
uint32_t mHeight;
|
||||
};
|
||||
|
||||
|
||||
class AsyncDeleteIconFromDisk : public nsIRunnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
explicit AsyncDeleteIconFromDisk(const nsAString &aIconPath);
|
||||
|
||||
private:
|
||||
virtual ~AsyncDeleteIconFromDisk();
|
||||
|
||||
nsAutoString mIconPath;
|
||||
};
|
||||
|
||||
class AsyncDeleteAllFaviconsFromDisk : public nsIRunnable
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
Loading…
Reference in a new issue