Bug 1937061: Hide new profile instances from the recent applications section of the dock. r=nika,spohl,profiles-reviewers,jhirsch
Adds an API to nsIMacDockSupport to allow launching an application bundle and hiding it from the list of recent applications. Differential Revision: https://phabricator.services.mozilla.com/D238206
This commit is contained in:
@@ -663,36 +663,51 @@ class SelectableProfileServiceClass extends EventEmitter {
|
||||
// App session lifecycle methods and multi-process support
|
||||
|
||||
/*
|
||||
* Helper that returns an inited Firefox executable process (nsIProcess).
|
||||
* Mostly useful for mocking in unit testing.
|
||||
* Helper that executes a new Firefox process. Mostly useful for mocking in
|
||||
* unit testing.
|
||||
*/
|
||||
getExecutableProcess() {
|
||||
execProcess(aArgs) {
|
||||
let executable = SelectableProfileServiceClass.getDirectory("XREExeF");
|
||||
|
||||
if (AppConstants.platform == "macosx") {
|
||||
// Use the application bundle if possible.
|
||||
let appBundle = executable.parent.parent.parent;
|
||||
if (appBundle.path.endsWith(".app")) {
|
||||
executable = appBundle;
|
||||
|
||||
Cc["@mozilla.org/widget/macdocksupport;1"]
|
||||
.getService(Ci.nsIMacDockSupport)
|
||||
.launchAppBundle(appBundle, aArgs, { addsToRecentItems: false });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let process = Cc["@mozilla.org/process/util;1"].createInstance(
|
||||
Ci.nsIProcess
|
||||
);
|
||||
let executable = SelectableProfileServiceClass.getDirectory("XREExeF");
|
||||
process.init(executable);
|
||||
return process;
|
||||
process.runw(false, aArgs, aArgs.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch a new Firefox instance using the given selectable profile.
|
||||
*
|
||||
* @param {SelectableProfile} aProfile The profile to launch
|
||||
* @param {string} url A url to open in launched profile
|
||||
* @param {string} aUrl A url to open in launched profile
|
||||
*/
|
||||
launchInstance(aProfile, url) {
|
||||
let process = this.getExecutableProcess();
|
||||
launchInstance(aProfile, aUrl) {
|
||||
let args = ["--profile", aProfile.path];
|
||||
if (Services.appinfo.OS === "Darwin") {
|
||||
args.unshift("-foreground");
|
||||
}
|
||||
if (url) {
|
||||
args.push("-url", url);
|
||||
|
||||
if (aUrl) {
|
||||
args.push("-url", aUrl);
|
||||
} else {
|
||||
args.push(`--${COMMAND_LINE_ACTIVATE}`);
|
||||
}
|
||||
process.runw(false, args, args.length);
|
||||
|
||||
this.execProcess(args);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,15 +15,12 @@ async function promiseAppMenuOpened() {
|
||||
add_task(async function test_appmenu_updates_on_edit() {
|
||||
// Mock the executable process so we don't launch a new process when we
|
||||
// create new profiles.
|
||||
SelectableProfileService._getExecutableProcess =
|
||||
SelectableProfileService.getExecutableProcess;
|
||||
SelectableProfileService._execProcess = SelectableProfileService.execProcess;
|
||||
registerCleanupFunction(() => {
|
||||
SelectableProfileService.getExecutableProcess =
|
||||
SelectableProfileService._getExecutableProcess;
|
||||
SelectableProfileService.execProcess =
|
||||
SelectableProfileService._execProcess;
|
||||
});
|
||||
SelectableProfileService.getExecutableProcess = () => {
|
||||
return { runw: () => {} };
|
||||
};
|
||||
SelectableProfileService.execProcess = () => {};
|
||||
|
||||
// We need to create a second profile for the name to be shown in the app
|
||||
// menu.
|
||||
|
||||
@@ -10,9 +10,7 @@ add_task(async function test_dbLazilyCreated() {
|
||||
);
|
||||
|
||||
// Mock the executable process so we doon't launch a new process
|
||||
SelectableProfileService.getExecutableProcess = () => {
|
||||
return { runw: () => {} };
|
||||
};
|
||||
SelectableProfileService.execProcess = () => {};
|
||||
|
||||
await SelectableProfileService.maybeSetupDataStore();
|
||||
ok(
|
||||
|
||||
@@ -66,13 +66,7 @@ add_task(async function test_selector_window() {
|
||||
// mock() returns an object with a fake `runw` method that, when
|
||||
// called, records its arguments.
|
||||
let input = [];
|
||||
let mock = () => {
|
||||
return {
|
||||
runw: (...args) => {
|
||||
input.push(...args);
|
||||
},
|
||||
};
|
||||
};
|
||||
let mock = args => (input = args);
|
||||
|
||||
const profileSelector = dialog.document.querySelector("profile-selector");
|
||||
await profileSelector.updateComplete;
|
||||
@@ -130,7 +124,7 @@ add_task(async function test_selector_window() {
|
||||
"Profile selector should be disabled"
|
||||
);
|
||||
|
||||
profileSelector.selectableProfileService.getExecutableProcess = mock;
|
||||
profileSelector.selectableProfileService.execProcess = mock;
|
||||
|
||||
const profiles = profileSelector.profileCards;
|
||||
|
||||
@@ -163,7 +157,7 @@ add_task(async function test_selector_window() {
|
||||
expected = ["--profile", profile.path, "--profiles-activate"];
|
||||
}
|
||||
|
||||
Assert.deepEqual(input[1], expected, "Expected runw arguments");
|
||||
Assert.deepEqual(input, expected, "Expected runw arguments");
|
||||
|
||||
await assertGlean("profiles", "selector_window", "launch");
|
||||
|
||||
|
||||
@@ -9,18 +9,14 @@ add_task(async function test_launcher() {
|
||||
// mock() returns an object with a fake `runw` method that, when
|
||||
// called, records its arguments.
|
||||
let input = [];
|
||||
let mock = () => {
|
||||
return {
|
||||
runw: (...args) => {
|
||||
input = args;
|
||||
},
|
||||
};
|
||||
let mock = args => {
|
||||
input = args;
|
||||
};
|
||||
|
||||
let profile = await createTestProfile();
|
||||
|
||||
const SelectableProfileService = getSelectableProfileService();
|
||||
SelectableProfileService.getExecutableProcess = mock;
|
||||
SelectableProfileService.execProcess = mock;
|
||||
SelectableProfileService.launchInstance(profile);
|
||||
|
||||
let expected;
|
||||
@@ -35,7 +31,7 @@ add_task(async function test_launcher() {
|
||||
expected = ["--profile", profile.path, "--profiles-activate"];
|
||||
}
|
||||
|
||||
Assert.deepEqual(expected, input[1], "Expected runw arguments");
|
||||
Assert.deepEqual(expected, input, "Expected runw arguments");
|
||||
|
||||
SelectableProfileService.launchInstance(profile, "about:profilemanager");
|
||||
|
||||
@@ -51,5 +47,5 @@ add_task(async function test_launcher() {
|
||||
expected = ["--profile", profile.path, "-url", "about:profilemanager"];
|
||||
}
|
||||
|
||||
Assert.deepEqual(expected, input[1], "Expected runw arguments");
|
||||
Assert.deepEqual(expected, input, "Expected runw arguments");
|
||||
});
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
#include "nsString.h"
|
||||
#include "imgLoader.h"
|
||||
#include "MOZIconHelper.h"
|
||||
#include "mozilla/MacStringHelpers.h"
|
||||
#include "mozilla/SVGImageContext.h"
|
||||
#include "nsISVGPaintContext.h"
|
||||
#include "nsIFile.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsMacDockSupport, nsIMacDockSupport, nsITaskbarProgress)
|
||||
|
||||
@@ -508,3 +510,43 @@ nsresult nsMacDockSupport::EnsureAppIsPinnedToDock(
|
||||
|
||||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
nsresult nsMacDockSupport::LaunchAppBundle(
|
||||
nsIFile* aAppBundle, const nsTArray<nsCString>& aArgs,
|
||||
nsIAppBundleLaunchOptions* aLaunchOptions) {
|
||||
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
||||
|
||||
nsString bundlePath;
|
||||
nsresult rv = aAppBundle->GetPath(bundlePath);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NSString* launchPath = mozilla::XPCOMStringToNSString(bundlePath);
|
||||
NSMutableArray* arguments = [NSMutableArray arrayWithCapacity:aArgs.Length()];
|
||||
|
||||
for (const auto& arg : aArgs) {
|
||||
[arguments addObject:mozilla::XPCOMStringToNSString(arg)];
|
||||
}
|
||||
|
||||
NSWorkspaceOpenConfiguration* config =
|
||||
[NSWorkspaceOpenConfiguration configuration];
|
||||
[config setArguments:arguments];
|
||||
[config setCreatesNewApplicationInstance:YES];
|
||||
[config setEnvironment:[[NSProcessInfo processInfo] environment]];
|
||||
|
||||
if (aLaunchOptions) {
|
||||
bool val = false;
|
||||
if (NS_SUCCEEDED(aLaunchOptions->GetAddsToRecentItems(&val))) {
|
||||
[config setAddsToRecentItems:val];
|
||||
}
|
||||
}
|
||||
|
||||
[[NSWorkspace sharedWorkspace]
|
||||
openApplicationAtURL:[NSURL fileURLWithPath:launchPath]
|
||||
configuration:config
|
||||
completionHandler:^(NSRunningApplication* aChild, NSError* aError){
|
||||
}];
|
||||
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,16 @@
|
||||
interface nsIStandaloneNativeMenu;
|
||||
interface nsISVGPaintContext;
|
||||
interface imgIContainer;
|
||||
interface nsIFile;
|
||||
|
||||
[scriptable, uuid(2cbde069-b80d-4e63-b7c7-c4dfe4617028)]
|
||||
interface nsIAppBundleLaunchOptions : nsISupports {
|
||||
/**
|
||||
* A Boolean value indicating whether to add the app or documents to the
|
||||
* Recent Items menu.
|
||||
*/
|
||||
readonly attribute boolean addsToRecentItems;
|
||||
};
|
||||
|
||||
/**
|
||||
* Allow applications to interface with the Mac OS X Dock.
|
||||
@@ -77,4 +87,12 @@ interface nsIMacDockSupport : nsISupports
|
||||
*/
|
||||
boolean ensureAppIsPinnedToDock([optional] in AString aAppPath,
|
||||
[optional] in AString aAppToReplacePath);
|
||||
|
||||
/**
|
||||
* Launches an application bundle passing the given command line arguments.
|
||||
* The `aLaunchOptions` parameter can control aspects of how the bundle is
|
||||
* launched.
|
||||
*/
|
||||
void launchAppBundle(in nsIFile aAppBundle, in Array<ACString> aArgs,
|
||||
[optional] in nsIAppBundleLaunchOptions aLaunchOptions);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user