gecko-dev/widget/windows/JumpListBuilder.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

628 строки
19 KiB
C++
Исходник Обычный вид История

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2012-05-21 15:12:37 +04:00
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "JumpListBuilder.h"
#include "nsError.h"
#include "nsCOMPtr.h"
#include "nsServiceManagerUtils.h"
#include "nsString.h"
#include "nsArrayUtils.h"
#include "nsIMutableArray.h"
#include "nsWidgetsCID.h"
#include "WinTaskbar.h"
#include "nsDirectoryServiceUtils.h"
#include "nsISimpleEnumerator.h"
#include "mozilla/Preferences.h"
#include "nsStringStream.h"
#include "nsThreadUtils.h"
#include "mozilla/LazyIdleThread.h"
#include "nsIObserverService.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/Unused.h"
#include "mozilla/dom/Promise.h"
Bug 1400344: Rename mscom::MainThreadRuntime to mscom::ProcessRuntime and make it aware of Win32k lockdown and of multiple instantiations; r=Jamie This patch takes care of a bunch of issues and does some cleanup: * We rename mscom::MainThreadRuntime to mscom::ProcessRuntime, as the latter is a more accurate name going forward. * We make ProcessRuntime aware of the Win32k Lockdown process mitigation policy. When Win32k is disabled, we perform process-wide COM initialization in the multi-threaded apartment (since we cannot create an STA window). * We refactor the mscom apartment region stuff to enable the Win32k lockdown pieces in ProcessRuntime. * We move some Gecko-specific stuff into MOZILLA_INTERNAL_API guards so that ProcessRuntime is usable outside of xul.dll (I will be needing it for the launcher process). * Another thing that might happen with the launcher process is that, under error conditions in the launcher, we create a ProcessRuntime object on a background thread for the purposes of telemetry logging, but we also allow the main thread to proceed to start as the browser. This could result in a scenario where the main thread, as the browser process, is attempting to instantiate its ProcessRuntime and ends up racing with the launcher process's telemetry thread which has its own ProcessRuntime. To account for this situation, we add mutual exclusion to the process-wide initialization code. We host this part inside mozglue since that state is shared between both firefox.exe and xul.dll. * We clean up ProcessRuntime::InitializeSecurity by using Vector to set up the EXPLICIT_ACCESS entries. * We remove mscom::MainThreadClientInfo and replace it with a direct call to CoGetCallerTID * We revise all references to this class to use the new name. Differential Revision: https://phabricator.services.mozilla.com/D19551 --HG-- rename : ipc/mscom/COMApartmentRegion.h => ipc/mscom/ApartmentRegion.h rename : ipc/mscom/MainThreadRuntime.cpp => ipc/mscom/ProcessRuntime.cpp rename : ipc/mscom/MainThreadRuntime.h => ipc/mscom/ProcessRuntime.h extra : moz-landing-system : lando
2019-02-14 21:56:20 +03:00
#include "mozilla/mscom/ApartmentRegion.h"
#include "mozilla/mscom/EnsureMTA.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
namespace mozilla {
namespace widget {
// defined in WinTaskbar.cpp
extern const wchar_t* gMozillaJumpListIDGeneric;
Atomic<bool> JumpListBuilder::sBuildingList(false);
const char kPrefTaskbarEnabled[] = "browser.taskbar.lists.enabled";
NS_IMPL_ISUPPORTS(JumpListBuilder, nsIJumpListBuilder, nsIObserver)
#define TOPIC_PROFILE_BEFORE_CHANGE "profile-before-change"
#define TOPIC_CLEAR_PRIVATE_DATA "clear-private-data"
namespace detail {
class DoneCommitListBuildCallback final : public nsIRunnable {
NS_DECL_THREADSAFE_ISUPPORTS
public:
DoneCommitListBuildCallback(nsIJumpListCommittedCallback* aCallback,
JumpListBuilder* aBuilder)
: mCallback(aCallback), mBuilder(aBuilder), mResult(false) {}
NS_IMETHOD Run() override {
MOZ_ASSERT(NS_IsMainThread());
if (mCallback) {
Unused << mCallback->Done(mResult);
}
// Ensure we are releasing on the main thread.
Destroy();
return NS_OK;
}
void SetResult(bool aResult) { mResult = aResult; }
private:
~DoneCommitListBuildCallback() {
// Destructor does not always call on the main thread.
MOZ_ASSERT(!mCallback);
MOZ_ASSERT(!mBuilder);
}
void Destroy() {
MOZ_ASSERT(NS_IsMainThread());
mCallback = nullptr;
mBuilder = nullptr;
}
// These two references MUST be released on the main thread.
RefPtr<nsIJumpListCommittedCallback> mCallback;
RefPtr<JumpListBuilder> mBuilder;
bool mResult;
};
NS_IMPL_ISUPPORTS(DoneCommitListBuildCallback, nsIRunnable);
} // namespace detail
JumpListBuilder::JumpListBuilder()
: mMaxItems(0), mHasCommit(false), mMonitor("JumpListBuilderMonitor") {
MOZ_ASSERT(NS_IsMainThread());
// Instantiate mJumpListMgr in the multithreaded apartment so that proxied
// calls on that object do not need to interact with the main thread's message
// pump.
mscom::EnsureMTA([this]() {
RefPtr<ICustomDestinationList> jumpListMgr;
HRESULT hr = ::CoCreateInstance(
CLSID_DestinationList, nullptr, CLSCTX_INPROC_SERVER,
IID_ICustomDestinationList, getter_AddRefs(jumpListMgr));
if (FAILED(hr)) {
return;
}
// Since we are accessing mJumpListMgr across different threads
// (ie, different apartments), mJumpListMgr must be an agile reference.
mJumpListMgr = jumpListMgr;
});
if (!mJumpListMgr) {
return;
}
// Make a lazy thread for any IO
mIOThread = new LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS,
NS_LITERAL_CSTRING("Jump List"),
LazyIdleThread::ManualShutdown);
Preferences::AddStrongObserver(this, kPrefTaskbarEnabled);
nsCOMPtr<nsIObserverService> observerService =
do_GetService("@mozilla.org/observer-service;1");
if (observerService) {
observerService->AddObserver(this, TOPIC_PROFILE_BEFORE_CHANGE, false);
observerService->AddObserver(this, TOPIC_CLEAR_PRIVATE_DATA, false);
}
}
JumpListBuilder::~JumpListBuilder() {
Preferences::RemoveObserver(this, kPrefTaskbarEnabled);
}
NS_IMETHODIMP JumpListBuilder::GetAvailable(int16_t* aAvailable) {
*aAvailable = false;
ReentrantMonitorAutoEnter lock(mMonitor);
if (mJumpListMgr) *aAvailable = true;
return NS_OK;
}
NS_IMETHODIMP JumpListBuilder::GetIsListCommitted(bool* aCommit) {
*aCommit = mHasCommit;
return NS_OK;
}
NS_IMETHODIMP JumpListBuilder::GetMaxListItems(int16_t* aMaxItems) {
ReentrantMonitorAutoEnter lock(mMonitor);
if (!mJumpListMgr) return NS_ERROR_NOT_AVAILABLE;
*aMaxItems = 0;
if (sBuildingList) {
*aMaxItems = mMaxItems;
return NS_OK;
}
RefPtr<ICustomDestinationList> jumpListMgr = mJumpListMgr;
if (!jumpListMgr) {
return NS_ERROR_UNEXPECTED;
}
IObjectArray* objArray;
if (SUCCEEDED(jumpListMgr->BeginList(&mMaxItems, IID_PPV_ARGS(&objArray)))) {
*aMaxItems = mMaxItems;
if (objArray) objArray->Release();
jumpListMgr->AbortList();
}
return NS_OK;
}
NS_IMETHODIMP JumpListBuilder::InitListBuild(JSContext* aCx,
Promise** aPromise) {
ReentrantMonitorAutoEnter lock(mMonitor);
if (!mJumpListMgr) {
return NS_ERROR_NOT_AVAILABLE;
}
nsIGlobalObject* globalObject = xpc::CurrentNativeGlobal(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;
}
void JumpListBuilder::DoInitListBuild(RefPtr<Promise>&& aPromise) {
// Since we're invoking COM interfaces to talk to the shell on a background
// thread, we need to be running inside a multithreaded apartment.
mscom::MTARegion mta;
MOZ_ASSERT(mta.IsValid());
ReentrantMonitorAutoEnter lock(mMonitor);
MOZ_ASSERT(mJumpListMgr);
if (sBuildingList) {
AbortListBuild();
}
HRESULT hr = E_UNEXPECTED;
auto errorHandler = MakeScopeExit([&aPromise, &hr]() {
if (SUCCEEDED(hr)) {
return;
}
NS_DispatchToMainThread(NS_NewRunnableFunction(
"InitListBuildReject", [promise = std::move(aPromise)]() {
promise->MaybeReject(NS_ERROR_FAILURE);
}));
});
RefPtr<ICustomDestinationList> jumpListMgr = mJumpListMgr;
if (!jumpListMgr) {
return;
}
nsTArray<nsString> urisToRemove;
RefPtr<IObjectArray> objArray;
hr = jumpListMgr->BeginList(
&mMaxItems,
IID_PPV_ARGS(static_cast<IObjectArray**>(getter_AddRefs(objArray))));
if (FAILED(hr)) {
return;
}
// 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.
sBuildingList = true;
RemoveIconCacheAndGetJumplistShortcutURIs(objArray, urisToRemove);
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
nsresult JumpListBuilder::RemoveIconCacheForAllItems() {
// Construct the path of our jump list cache
nsCOMPtr<nsIFile> jumpListCacheDir;
nsresult rv =
NS_GetSpecialDirectory("ProfLDS", getter_AddRefs(jumpListCacheDir));
NS_ENSURE_SUCCESS(rv, rv);
rv = jumpListCacheDir->AppendNative(
nsDependentCString(mozilla::widget::FaviconHelper::kJumpListCacheDir));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDirectoryEnumerator> entries;
rv = jumpListCacheDir->GetDirectoryEntries(getter_AddRefs(entries));
NS_ENSURE_SUCCESS(rv, rv);
// Loop through each directory entry and remove all ICO files found
do {
nsCOMPtr<nsIFile> currFile;
if (NS_FAILED(entries->GetNextFile(getter_AddRefs(currFile))) || !currFile)
break;
nsAutoString path;
if (NS_FAILED(currFile->GetPath(path))) continue;
if (StringTail(path, 4).LowerCaseEqualsASCII(".ico")) {
// Check if the cached ICO file exists
bool exists;
if (NS_FAILED(currFile->Exists(&exists)) || !exists) continue;
// We found an ICO file that exists, so we should remove it
currFile->Remove(false);
}
} while (true);
return NS_OK;
}
NS_IMETHODIMP JumpListBuilder::AddListToBuild(int16_t aCatType, nsIArray* items,
const nsAString& catName,
bool* _retval) {
nsresult rv;
*_retval = false;
ReentrantMonitorAutoEnter lock(mMonitor);
if (!mJumpListMgr) return NS_ERROR_NOT_AVAILABLE;
RefPtr<ICustomDestinationList> jumpListMgr = mJumpListMgr;
if (!jumpListMgr) {
return NS_ERROR_UNEXPECTED;
}
switch (aCatType) {
case nsIJumpListBuilder::JUMPLIST_CATEGORY_TASKS: {
NS_ENSURE_ARG_POINTER(items);
HRESULT hr;
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 08:24:48 +03:00
RefPtr<IObjectCollection> collection;
hr = CoCreateInstance(CLSID_EnumerableObjectCollection, nullptr,
CLSCTX_INPROC_SERVER, IID_IObjectCollection,
getter_AddRefs(collection));
if (FAILED(hr)) return NS_ERROR_UNEXPECTED;
// Build the list
uint32_t length;
items->GetLength(&length);
for (uint32_t i = 0; i < length; ++i) {
nsCOMPtr<nsIJumpListItem> item = do_QueryElementAt(items, i);
if (!item) continue;
// Check for separators
if (IsSeparator(item)) {
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 08:24:48 +03:00
RefPtr<IShellLinkW> link;
rv = JumpListSeparator::GetSeparator(link);
if (NS_FAILED(rv)) return rv;
collection->AddObject(link);
continue;
}
// These should all be ShellLinks
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 08:24:48 +03:00
RefPtr<IShellLinkW> link;
rv = JumpListShortcut::GetShellLink(item, link, mIOThread);
if (NS_FAILED(rv)) return rv;
collection->AddObject(link);
}
// We need IObjectArray to submit
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 08:24:48 +03:00
RefPtr<IObjectArray> pArray;
hr = collection->QueryInterface(IID_IObjectArray, getter_AddRefs(pArray));
if (FAILED(hr)) return NS_ERROR_UNEXPECTED;
// Add the tasks
hr = jumpListMgr->AddUserTasks(pArray);
if (SUCCEEDED(hr)) *_retval = true;
return NS_OK;
} break;
case nsIJumpListBuilder::JUMPLIST_CATEGORY_RECENT: {
if (SUCCEEDED(jumpListMgr->AppendKnownCategory(KDC_RECENT)))
*_retval = true;
return NS_OK;
} break;
case nsIJumpListBuilder::JUMPLIST_CATEGORY_FREQUENT: {
if (SUCCEEDED(jumpListMgr->AppendKnownCategory(KDC_FREQUENT)))
*_retval = true;
return NS_OK;
} break;
case nsIJumpListBuilder::JUMPLIST_CATEGORY_CUSTOMLIST: {
NS_ENSURE_ARG_POINTER(items);
if (catName.IsEmpty()) return NS_ERROR_INVALID_ARG;
HRESULT hr;
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 08:24:48 +03:00
RefPtr<IObjectCollection> collection;
hr = CoCreateInstance(CLSID_EnumerableObjectCollection, nullptr,
CLSCTX_INPROC_SERVER, IID_IObjectCollection,
getter_AddRefs(collection));
if (FAILED(hr)) return NS_ERROR_UNEXPECTED;
uint32_t length;
items->GetLength(&length);
for (uint32_t i = 0; i < length; ++i) {
nsCOMPtr<nsIJumpListItem> item = do_QueryElementAt(items, i);
if (!item) continue;
int16_t type;
if (NS_FAILED(item->GetType(&type))) continue;
switch (type) {
case nsIJumpListItem::JUMPLIST_ITEM_SEPARATOR: {
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 08:24:48 +03:00
RefPtr<IShellLinkW> shellItem;
rv = JumpListSeparator::GetSeparator(shellItem);
if (NS_FAILED(rv)) return rv;
collection->AddObject(shellItem);
} break;
case nsIJumpListItem::JUMPLIST_ITEM_LINK: {
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 08:24:48 +03:00
RefPtr<IShellItem2> shellItem;
rv = JumpListLink::GetShellItem(item, shellItem);
if (NS_FAILED(rv)) return rv;
collection->AddObject(shellItem);
} break;
case nsIJumpListItem::JUMPLIST_ITEM_SHORTCUT: {
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 08:24:48 +03:00
RefPtr<IShellLinkW> shellItem;
rv = JumpListShortcut::GetShellLink(item, shellItem, mIOThread);
if (NS_FAILED(rv)) return rv;
collection->AddObject(shellItem);
} break;
}
}
// We need IObjectArray to submit
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 08:24:48 +03:00
RefPtr<IObjectArray> pArray;
hr = collection->QueryInterface(IID_IObjectArray, (LPVOID*)&pArray);
if (FAILED(hr)) return NS_ERROR_UNEXPECTED;
// Add the tasks
hr = jumpListMgr->AppendCategory(
reinterpret_cast<const wchar_t*>(catName.BeginReading()), pArray);
if (SUCCEEDED(hr)) *_retval = true;
// Get rid of the old icons
nsCOMPtr<nsIRunnable> event =
new mozilla::widget::AsyncDeleteAllFaviconsFromDisk(true);
mIOThread->Dispatch(event, NS_DISPATCH_NORMAL);
return NS_OK;
} break;
}
return NS_OK;
}
NS_IMETHODIMP JumpListBuilder::AbortListBuild() {
ReentrantMonitorAutoEnter lock(mMonitor);
if (!mJumpListMgr) return NS_ERROR_NOT_AVAILABLE;
RefPtr<ICustomDestinationList> jumpListMgr = mJumpListMgr;
if (!jumpListMgr) {
return NS_ERROR_UNEXPECTED;
}
jumpListMgr->AbortList();
sBuildingList = false;
return NS_OK;
}
NS_IMETHODIMP JumpListBuilder::CommitListBuild(
nsIJumpListCommittedCallback* aCallback) {
ReentrantMonitorAutoEnter lock(mMonitor);
if (!mJumpListMgr) return NS_ERROR_NOT_AVAILABLE;
// Also holds a strong reference to this to prevent use-after-free.
RefPtr<detail::DoneCommitListBuildCallback> callback =
new detail::DoneCommitListBuildCallback(aCallback, this);
// The builder has a strong reference in the callback already, so we do not
// need to do it for this runnable again.
RefPtr<nsIRunnable> event =
NewNonOwningRunnableMethod<RefPtr<detail::DoneCommitListBuildCallback>>(
"JumpListBuilder::DoCommitListBuild", this,
&JumpListBuilder::DoCommitListBuild, std::move(callback));
Unused << mIOThread->Dispatch(event, NS_DISPATCH_NORMAL);
return NS_OK;
}
void JumpListBuilder::DoCommitListBuild(
RefPtr<detail::DoneCommitListBuildCallback> aCallback) {
// Since we're invoking COM interfaces to talk to the shell on a background
// thread, we need to be running inside a multithreaded apartment.
mscom::MTARegion mta;
MOZ_ASSERT(mta.IsValid());
ReentrantMonitorAutoEnter lock(mMonitor);
MOZ_ASSERT(mJumpListMgr);
MOZ_ASSERT(aCallback);
HRESULT hr = E_UNEXPECTED;
auto onExit = MakeScopeExit([&hr, &aCallback]() {
// XXX We might want some specific error data here.
aCallback->SetResult(SUCCEEDED(hr));
Unused << NS_DispatchToMainThread(aCallback);
});
RefPtr<ICustomDestinationList> jumpListMgr = mJumpListMgr;
if (!jumpListMgr) {
return;
}
hr = jumpListMgr->CommitList();
sBuildingList = false;
if (SUCCEEDED(hr)) {
mHasCommit = true;
}
}
NS_IMETHODIMP JumpListBuilder::DeleteActiveList(bool* _retval) {
*_retval = false;
ReentrantMonitorAutoEnter lock(mMonitor);
if (!mJumpListMgr) return NS_ERROR_NOT_AVAILABLE;
if (sBuildingList) {
AbortListBuild();
}
nsAutoString uid;
if (!WinTaskbar::GetAppUserModelID(uid)) return NS_OK;
RefPtr<ICustomDestinationList> jumpListMgr = mJumpListMgr;
if (!jumpListMgr) {
return NS_ERROR_UNEXPECTED;
}
if (SUCCEEDED(jumpListMgr->DeleteList(uid.get()))) {
*_retval = true;
}
return NS_OK;
}
/* internal */
bool JumpListBuilder::IsSeparator(nsCOMPtr<nsIJumpListItem>& item) {
int16_t type;
item->GetType(&type);
if (NS_FAILED(item->GetType(&type))) return false;
if (type == nsIJumpListItem::JUMPLIST_ITEM_SEPARATOR) return true;
return false;
}
// 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) {
MOZ_ASSERT(!NS_IsMainThread());
// Early return here just in case some versions of Windows don't populate this
if (!aObjArray) {
return;
}
uint32_t count = 0;
aObjArray->GetCount(&count);
for (uint32_t idx = 0; idx < count; idx++) {
RefPtr<IShellLinkW> pLink;
if (FAILED(aObjArray->GetAt(idx, IID_IShellLinkW,
static_cast<void**>(getter_AddRefs(pLink))))) {
continue;
}
wchar_t buf[MAX_PATH];
HRESULT hres = pLink->GetArguments(buf, MAX_PATH);
if (SUCCEEDED(hres)) {
LPWSTR* arglist;
int32_t numArgs;
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);
}
}
}
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,
const char* aTopic,
const char16_t* aData) {
NS_ENSURE_ARG_POINTER(aTopic);
if (strcmp(aTopic, TOPIC_PROFILE_BEFORE_CHANGE) == 0) {
nsCOMPtr<nsIObserverService> observerService =
do_GetService("@mozilla.org/observer-service;1");
if (observerService) {
observerService->RemoveObserver(this, TOPIC_PROFILE_BEFORE_CHANGE);
}
mIOThread->Shutdown();
// Clear out mJumpListMgr, as MSCOM services won't be available soon.
ReentrantMonitorAutoEnter lock(mMonitor);
mJumpListMgr = nullptr;
} else if (strcmp(aTopic, "nsPref:changed") == 0 &&
nsDependentString(aData).EqualsASCII(kPrefTaskbarEnabled)) {
bool enabled = Preferences::GetBool(kPrefTaskbarEnabled, true);
if (!enabled) {
nsCOMPtr<nsIRunnable> event =
new mozilla::widget::AsyncDeleteAllFaviconsFromDisk();
mIOThread->Dispatch(event, NS_DISPATCH_NORMAL);
}
} else if (strcmp(aTopic, TOPIC_CLEAR_PRIVATE_DATA) == 0) {
// Delete JumpListCache icons from Disk, if any.
nsCOMPtr<nsIRunnable> event =
new mozilla::widget::AsyncDeleteAllFaviconsFromDisk(false);
mIOThread->Dispatch(event, NS_DISPATCH_NORMAL);
}
return NS_OK;
}
} // namespace widget
} // namespace mozilla