Merge pull request #8515 from electron/auto-launch-squirrel-support

Support custom launch path in app.setLoginItemSettings
This commit is contained in:
Kevin Sawicki 2017-02-06 08:55:32 -08:00 committed by GitHub
commit 18357512f3
8 changed files with 109 additions and 30 deletions

View file

@ -12,7 +12,6 @@
#include "atom/browser/api/atom_api_web_contents.h" #include "atom/browser/api/atom_api_web_contents.h"
#include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/browser.h"
#include "atom/browser/login_handler.h" #include "atom/browser/login_handler.h"
#include "atom/browser/relauncher.h" #include "atom/browser/relauncher.h"
#include "atom/common/atom_command_line.h" #include "atom/common/atom_command_line.h"
@ -298,6 +297,8 @@ struct Converter<Browser::LoginItemSettings> {
dict.Get("openAtLogin", &(out->open_at_login)); dict.Get("openAtLogin", &(out->open_at_login));
dict.Get("openAsHidden", &(out->open_as_hidden)); dict.Get("openAsHidden", &(out->open_as_hidden));
dict.Get("path", &(out->path));
dict.Get("args", &(out->args));
return true; return true;
} }
@ -746,6 +747,12 @@ bool App::IsAccessibilitySupportEnabled() {
return ax_state->IsAccessibleBrowser(); return ax_state->IsAccessibleBrowser();
} }
Browser::LoginItemSettings App::GetLoginItemSettings(mate::Arguments* args) {
Browser::LoginItemSettings options;
args->GetNext(&options);
return Browser::Get()->GetLoginItemSettings(options);
}
#if defined(USE_NSS_CERTS) #if defined(USE_NSS_CERTS)
void App::ImportCertificate( void App::ImportCertificate(
const base::DictionaryValue& options, const base::DictionaryValue& options,
@ -867,8 +874,7 @@ void App::BuildPrototype(
base::Bind(&Browser::RemoveAsDefaultProtocolClient, browser)) base::Bind(&Browser::RemoveAsDefaultProtocolClient, browser))
.SetMethod("setBadgeCount", base::Bind(&Browser::SetBadgeCount, browser)) .SetMethod("setBadgeCount", base::Bind(&Browser::SetBadgeCount, browser))
.SetMethod("getBadgeCount", base::Bind(&Browser::GetBadgeCount, browser)) .SetMethod("getBadgeCount", base::Bind(&Browser::GetBadgeCount, browser))
.SetMethod("getLoginItemSettings", .SetMethod("getLoginItemSettings", &App::GetLoginItemSettings)
base::Bind(&Browser::GetLoginItemSettings, browser))
.SetMethod("setLoginItemSettings", .SetMethod("setLoginItemSettings",
base::Bind(&Browser::SetLoginItemSettings, browser)) base::Bind(&Browser::SetLoginItemSettings, browser))
#if defined(OS_MACOSX) #if defined(OS_MACOSX)

View file

@ -10,6 +10,7 @@
#include "atom/browser/api/event_emitter.h" #include "atom/browser/api/event_emitter.h"
#include "atom/browser/atom_browser_client.h" #include "atom/browser/atom_browser_client.h"
#include "atom/browser/browser.h"
#include "atom/browser/browser_observer.h" #include "atom/browser/browser_observer.h"
#include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/callback.h"
#include "chrome/browser/process_singleton.h" #include "chrome/browser/process_singleton.h"
@ -123,6 +124,7 @@ class App : public AtomBrowserClient::Delegate,
bool Relaunch(mate::Arguments* args); bool Relaunch(mate::Arguments* args);
void DisableHardwareAcceleration(mate::Arguments* args); void DisableHardwareAcceleration(mate::Arguments* args);
bool IsAccessibilitySupportEnabled(); bool IsAccessibilitySupportEnabled();
Browser::LoginItemSettings GetLoginItemSettings(mate::Arguments* args);
#if defined(USE_NSS_CERTS) #if defined(USE_NSS_CERTS)
void ImportCertificate(const base::DictionaryValue& options, void ImportCertificate(const base::DictionaryValue& options,
const net::CompletionCallback& callback); const net::CompletionCallback& callback);

View file

@ -98,9 +98,11 @@ class Browser : public WindowListObserver {
bool restore_state = false; bool restore_state = false;
bool opened_at_login = false; bool opened_at_login = false;
bool opened_as_hidden = false; bool opened_as_hidden = false;
base::string16 path;
std::vector<base::string16> args;
}; };
void SetLoginItemSettings(LoginItemSettings settings); void SetLoginItemSettings(LoginItemSettings settings);
LoginItemSettings GetLoginItemSettings(); LoginItemSettings GetLoginItemSettings(LoginItemSettings options);
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
// Hide the application. // Hide the application.

View file

@ -63,7 +63,8 @@ bool Browser::SetBadgeCount(int count) {
void Browser::SetLoginItemSettings(LoginItemSettings settings) { void Browser::SetLoginItemSettings(LoginItemSettings settings) {
} }
Browser::LoginItemSettings Browser::GetLoginItemSettings() { Browser::LoginItemSettings Browser::GetLoginItemSettings(
LoginItemSettings options) {
return LoginItemSettings(); return LoginItemSettings();
} }

View file

@ -152,7 +152,8 @@ bool Browser::ContinueUserActivity(const std::string& type,
return prevent_default; return prevent_default;
} }
Browser::LoginItemSettings Browser::GetLoginItemSettings() { Browser::LoginItemSettings Browser::GetLoginItemSettings(
LoginItemSettings options) {
LoginItemSettings settings; LoginItemSettings settings;
settings.open_at_login = base::mac::CheckLoginItemStatus( settings.open_at_login = base::mac::CheckLoginItemStatus(
&settings.open_as_hidden); &settings.open_as_hidden);

View file

@ -43,15 +43,19 @@ BOOL CALLBACK WindowsEnumerationHandler(HWND hwnd, LPARAM param) {
return TRUE; return TRUE;
} }
bool GetProcessExecPath(base::string16* exe) {
base::FilePath path;
if (!PathService::Get(base::FILE_EXE, &path)) {
LOG(ERROR) << "Error getting app exe path";
return false;
}
*exe = path.value();
return true;
}
bool GetProtocolLaunchPath(mate::Arguments* args, base::string16* exe) { bool GetProtocolLaunchPath(mate::Arguments* args, base::string16* exe) {
// Executable Path if (!args->GetNext(exe) && !GetProcessExecPath(exe)) {
if (!args->GetNext(exe)) { return false;
base::FilePath path;
if (!PathService::Get(base::FILE_EXE, &path)) {
LOG(ERROR) << "Error getting app exe path";
return false;
}
*exe = path.value();
} }
// Read in optional args arg // Read in optional args arg
@ -65,6 +69,22 @@ bool GetProtocolLaunchPath(mate::Arguments* args, base::string16* exe) {
return true; return true;
} }
bool FormatCommandLineString(base::string16* exe,
const std::vector<base::string16>& launch_args) {
if (exe->empty() && !GetProcessExecPath(exe)) {
return false;
}
if (!launch_args.empty()) {
base::string16 formatString = L"%s %s";
*exe = base::StringPrintf(formatString.c_str(),
exe->c_str(),
base::JoinString(launch_args, L" ").c_str());
}
return true;
}
} // namespace } // namespace
void Browser::Focus() { void Browser::Focus() {
@ -257,34 +277,32 @@ void Browser::SetLoginItemSettings(LoginItemSettings settings) {
base::win::RegKey key(HKEY_CURRENT_USER, keyPath.c_str(), KEY_ALL_ACCESS); base::win::RegKey key(HKEY_CURRENT_USER, keyPath.c_str(), KEY_ALL_ACCESS);
if (settings.open_at_login) { if (settings.open_at_login) {
base::FilePath path; base::string16 exe = settings.path;
if (PathService::Get(base::FILE_EXE, &path)) { if (FormatCommandLineString(&exe, settings.args)) {
base::string16 exePath(path.value()); key.WriteValue(GetAppUserModelID(), exe.c_str());
key.WriteValue(GetAppUserModelID(), exePath.c_str());
} }
} else { } else {
key.DeleteValue(GetAppUserModelID()); key.DeleteValue(GetAppUserModelID());
} }
} }
Browser::LoginItemSettings Browser::GetLoginItemSettings() { Browser::LoginItemSettings Browser::GetLoginItemSettings(
LoginItemSettings options) {
LoginItemSettings settings; LoginItemSettings settings;
base::string16 keyPath = L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"; base::string16 keyPath = L"Software\\Microsoft\\Windows\\CurrentVersion\\Run";
base::win::RegKey key(HKEY_CURRENT_USER, keyPath.c_str(), KEY_ALL_ACCESS); base::win::RegKey key(HKEY_CURRENT_USER, keyPath.c_str(), KEY_ALL_ACCESS);
base::string16 keyVal; base::string16 keyVal;
if (!FAILED(key.ReadValue(GetAppUserModelID(), &keyVal))) { if (!FAILED(key.ReadValue(GetAppUserModelID(), &keyVal))) {
base::FilePath path; base::string16 exe = options.path;
if (PathService::Get(base::FILE_EXE, &path)) { if (FormatCommandLineString(&exe, options.args)) {
base::string16 exePath(path.value()); settings.open_at_login = keyVal == exe;
settings.open_at_login = keyVal == exePath;
} }
} }
return settings; return settings;
} }
PCWSTR Browser::GetAppUserModelID() { PCWSTR Browser::GetAppUserModelID() {
if (app_user_model_id_.empty()) { if (app_user_model_id_.empty()) {
SetAppUserModelID(base::ReplaceStringPlaceholders( SetAppUserModelID(base::ReplaceStringPlaceholders(

View file

@ -758,7 +758,16 @@ Returns `Integer` - The current value displayed in the counter badge.
Returns `Boolean` - Whether the current desktop environment is Unity launcher. Returns `Boolean` - Whether the current desktop environment is Unity launcher.
### `app.getLoginItemSettings()` _macOS_ _Windows_ ### `app.getLoginItemSettings([options])` _macOS_ _Windows_
* `options` Object (optional)
* `path` String (optional) _Windows_ - The executable path to compare against.
Defaults to `process.execPath`.
* `args` String[] (optional) _Windows_ - The command-line arguments to compare
against. Defaults to an empty array.
If you provided `path` and `args` options to `app.setLoginItemSettings` then you
need to pass the same arguments here for `openAtLogin` to be set correctly.
Returns `Object`: Returns `Object`:
@ -775,10 +784,9 @@ Returns `Object`:
app should restore the windows that were open the last time the app was app should restore the windows that were open the last time the app was
closed. This setting is only supported on macOS. closed. This setting is only supported on macOS.
**Note:** This API has no effect on **Note:** This API has no effect on [MAS builds][mas-builds].
[MAS builds][mas-builds].
### `app.setLoginItemSettings(settings)` _macOS_ _Windows_ ### `app.setLoginItemSettings(settings[, path, args])` _macOS_ _Windows_
* `settings` Object * `settings` Object
* `openAtLogin` Boolean (optional) - `true` to open the app at login, `false` to remove * `openAtLogin` Boolean (optional) - `true` to open the app at login, `false` to remove
@ -788,11 +796,34 @@ Returns `Object`:
`app.getLoginItemStatus().wasOpenedAsHidden` should be checked when the app `app.getLoginItemStatus().wasOpenedAsHidden` should be checked when the app
is opened to know the current value. This setting is only supported on is opened to know the current value. This setting is only supported on
macOS. macOS.
* `path` String (optional) _Windows_ - The executable to launch at login.
Defaults to `process.execPath`.
* `args` String[] (optional) _Windows_ - The command-line arguments to pass to
the executable. Defaults to an empty array. Take care to wrap paths in
quotes.
Set the app's login item settings. Set the app's login item settings.
**Note:** This API has no effect on To work with Electron's `autoUpdater` on Windows, which uses [Squirrel](Squirrel-Windows),
[MAS builds][mas-builds]. you'll want to set the launch path to Update.exe, and pass arguments that specify your
application name. For example:
``` javascript
const appFolder = path.dirname(process.execPath)
const updateExe = path.resolve(appFolder, '..', 'Update.exe')
const exeName = path.basename(process.execPath)
app.setLoginItemSettings({
openAtLogin: true,
path: updateExe,
args: [
'--processStart', `"${exeName}"`,
'--process-start-args', `"--hidden"`
]
})
```
**Note:** This API has no effect on [MAS builds][mas-builds].
### `app.isAccessibilitySupportEnabled()` _macOS_ _Windows_ ### `app.isAccessibilitySupportEnabled()` _macOS_ _Windows_
@ -904,5 +935,6 @@ Sets the `image` associated with this dock icon.
[activity-type]: https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSUserActivity_Class/index.html#//apple_ref/occ/instp/NSUserActivity/activityType [activity-type]: https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSUserActivity_Class/index.html#//apple_ref/occ/instp/NSUserActivity/activityType
[unity-requirement]: ../tutorial/desktop-environment-integration.md#unity-launcher-shortcuts-linux [unity-requirement]: ../tutorial/desktop-environment-integration.md#unity-launcher-shortcuts-linux
[mas-builds]: ../tutorial/mac-app-store-submission-guide.md [mas-builds]: ../tutorial/mac-app-store-submission-guide.md
[Squirrel-Windows]: https://github.com/Squirrel/Squirrel.Windows
[JumpListBeginListMSDN]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378398(v=vs.85).aspx [JumpListBeginListMSDN]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378398(v=vs.85).aspx
[about-panel-options]: https://developer.apple.com/reference/appkit/nsapplication/1428479-orderfrontstandardaboutpanelwith?language=objc [about-panel-options]: https://developer.apple.com/reference/appkit/nsapplication/1428479-orderfrontstandardaboutpanelwith?language=objc

View file

@ -313,12 +313,20 @@ describe('app module', function () {
describe('app.get/setLoginItemSettings API', function () { describe('app.get/setLoginItemSettings API', function () {
if (process.platform === 'linux') return if (process.platform === 'linux') return
const updateExe = path.resolve(path.dirname(process.execPath), '..', 'Update.exe')
const processStartArgs = [
'--processStart', `"${path.basename(process.execPath)}"`,
'--process-start-args', `"--hidden"`
]
beforeEach(function () { beforeEach(function () {
app.setLoginItemSettings({openAtLogin: false}) app.setLoginItemSettings({openAtLogin: false})
app.setLoginItemSettings({openAtLogin: false, path: updateExe, args: processStartArgs})
}) })
afterEach(function () { afterEach(function () {
app.setLoginItemSettings({openAtLogin: false}) app.setLoginItemSettings({openAtLogin: false})
app.setLoginItemSettings({openAtLogin: false, path: updateExe, args: processStartArgs})
}) })
it('returns the login item status of the app', function () { it('returns the login item status of the app', function () {
@ -349,6 +357,15 @@ describe('app module', function () {
restoreState: false restoreState: false
}) })
}) })
it('allows you to pass a custom executable and arguments', () => {
if (process.platform !== 'win32') return
app.setLoginItemSettings({openAtLogin: true, path: updateExe, args: processStartArgs})
assert.equal(app.getLoginItemSettings().openAtLogin, false)
assert.equal(app.getLoginItemSettings({path: updateExe, args: processStartArgs}).openAtLogin, true)
})
}) })
describe('isAccessibilitySupportEnabled API', function () { describe('isAccessibilitySupportEnabled API', function () {