Merge pull request #3309 from atom/app-model-id

Fix a few problems around Application User Model ID
This commit is contained in:
Cheng Zhao 2015-11-03 17:58:03 +08:00
commit 053cd3dad0
9 changed files with 57 additions and 35 deletions

View file

@ -7,10 +7,6 @@
#include <string> #include <string>
#include <vector> #include <vector>
#if defined(OS_WIN)
#include <shlobj.h>
#endif
#include "atom/browser/api/atom_api_menu.h" #include "atom/browser/api/atom_api_menu.h"
#include "atom/browser/api/atom_api_session.h" #include "atom/browser/api/atom_api_session.h"
#include "atom/browser/api/atom_api_web_contents.h" #include "atom/browser/api/atom_api_web_contents.h"
@ -299,13 +295,6 @@ void App::SetDesktopName(const std::string& desktop_name) {
#endif #endif
} }
void App::SetAppUserModelId(const std::string& app_id) {
#if defined(OS_WIN)
base::string16 app_id_utf16 = base::UTF8ToUTF16(app_id);
SetCurrentProcessExplicitAppUserModelID(app_id_utf16.c_str());
#endif
}
void App::AllowNTLMCredentialsForAllDomains(bool should_allow) { void App::AllowNTLMCredentialsForAllDomains(bool should_allow) {
auto browser_context = static_cast<AtomBrowserContext*>( auto browser_context = static_cast<AtomBrowserContext*>(
AtomBrowserMainParts::Get()->browser_context()); AtomBrowserMainParts::Get()->browser_context());
@ -360,6 +349,8 @@ mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
base::Bind(&Browser::AddRecentDocument, browser)) base::Bind(&Browser::AddRecentDocument, browser))
.SetMethod("clearRecentDocuments", .SetMethod("clearRecentDocuments",
base::Bind(&Browser::ClearRecentDocuments, browser)) base::Bind(&Browser::ClearRecentDocuments, browser))
.SetMethod("setAppUserModelId",
base::Bind(&Browser::SetAppUserModelID, browser))
#if defined(OS_WIN) #if defined(OS_WIN)
.SetMethod("setUserTasks", .SetMethod("setUserTasks",
base::Bind(&Browser::SetUserTasks, browser)) base::Bind(&Browser::SetUserTasks, browser))
@ -367,7 +358,6 @@ mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
.SetMethod("setPath", &App::SetPath) .SetMethod("setPath", &App::SetPath)
.SetMethod("getPath", &App::GetPath) .SetMethod("getPath", &App::GetPath)
.SetMethod("setDesktopName", &App::SetDesktopName) .SetMethod("setDesktopName", &App::SetDesktopName)
.SetMethod("setAppUserModelId", &App::SetAppUserModelId)
.SetMethod("allowNTLMCredentialsForAllDomains", .SetMethod("allowNTLMCredentialsForAllDomains",
&App::AllowNTLMCredentialsForAllDomains) &App::AllowNTLMCredentialsForAllDomains)
.SetMethod("getLocale", &App::GetLocale) .SetMethod("getLocale", &App::GetLocale)

View file

@ -67,7 +67,6 @@ class App : public mate::EventEmitter,
const base::FilePath& path); const base::FilePath& path);
void SetDesktopName(const std::string& desktop_name); void SetDesktopName(const std::string& desktop_name);
void SetAppUserModelId(const std::string& app_id);
void AllowNTLMCredentialsForAllDomains(bool should_allow); void AllowNTLMCredentialsForAllDomains(bool should_allow);
bool MakeSingleInstance( bool MakeSingleInstance(
const ProcessSingleton::NotificationCallback& callback); const ProcessSingleton::NotificationCallback& callback);

View file

@ -89,10 +89,6 @@ std::string Browser::GetName() const {
void Browser::SetName(const std::string& name) { void Browser::SetName(const std::string& name) {
name_override_ = name; name_override_ = name;
#if defined(OS_WIN)
SetAppUserModelID(name);
#endif
} }
bool Browser::OpenFile(const std::string& file_path) { bool Browser::OpenFile(const std::string& file_path) {

View file

@ -11,12 +11,12 @@
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/observer_list.h" #include "base/observer_list.h"
#include "base/strings/string16.h"
#include "atom/browser/browser_observer.h" #include "atom/browser/browser_observer.h"
#include "atom/browser/window_list_observer.h" #include "atom/browser/window_list_observer.h"
#if defined(OS_WIN) #if defined(OS_WIN)
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/strings/string16.h"
#endif #endif
namespace base { namespace base {
@ -66,6 +66,9 @@ class Browser : public WindowListObserver {
// Clear the recent documents list. // Clear the recent documents list.
void ClearRecentDocuments(); void ClearRecentDocuments();
// Set the application user model ID.
void SetAppUserModelID(const base::string16& name);
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
// Bounce the dock icon. // Bounce the dock icon.
enum BounceType { enum BounceType {
@ -100,8 +103,10 @@ class Browser : public WindowListObserver {
// Add a custom task to jump list. // Add a custom task to jump list.
void SetUserTasks(const std::vector<UserTask>& tasks); void SetUserTasks(const std::vector<UserTask>& tasks);
// Set the application user model ID, called when "SetName" is called. // Returns the application user model ID, if there isn't one, then create
void SetAppUserModelID(const std::string& name); // one from app's name.
// The returned string managed by Browser, and should not be modified.
PCWSTR GetAppUserModelID();
#endif #endif
// Tell the application to open a file. // Tell the application to open a file.

View file

@ -31,6 +31,9 @@ void Browser::AddRecentDocument(const base::FilePath& path) {
void Browser::ClearRecentDocuments() { void Browser::ClearRecentDocuments() {
} }
void Browser::SetAppUserModelID(const base::string16& name) {
}
std::string Browser::GetExecutableFileVersion() const { std::string Browser::GetExecutableFileVersion() const {
return brightray::GetApplicationVersion(); return brightray::GetApplicationVersion();
} }

View file

@ -26,6 +26,9 @@ void Browser::AddRecentDocument(const base::FilePath& path) {
void Browser::ClearRecentDocuments() { void Browser::ClearRecentDocuments() {
} }
void Browser::SetAppUserModelID(const base::string16& name) {
}
std::string Browser::GetExecutableFileVersion() const { std::string Browser::GetExecutableFileVersion() const {
return brightray::GetApplicationVersion(); return brightray::GetApplicationVersion();
} }

View file

@ -15,6 +15,7 @@
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/path_service.h" #include "base/path_service.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/win/win_util.h" #include "base/win/win_util.h"
@ -25,6 +26,8 @@ namespace atom {
namespace { namespace {
const wchar_t kAppUserModelIDFormat[] = L"electron.app.$1";
BOOL CALLBACK WindowsEnumerationHandler(HWND hwnd, LPARAM param) { BOOL CALLBACK WindowsEnumerationHandler(HWND hwnd, LPARAM param) {
DWORD target_process_id = *reinterpret_cast<DWORD*>(param); DWORD target_process_id = *reinterpret_cast<DWORD*>(param);
DWORD process_id = 0; DWORD process_id = 0;
@ -56,7 +59,7 @@ void Browser::AddRecentDocument(const base::FilePath& path) {
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) {
SHARDAPPIDINFO info; SHARDAPPIDINFO info;
info.psi = item; info.psi = item;
info.pszAppID = app_user_model_id_.c_str(); info.pszAppID = GetAppUserModelID();
SHAddToRecentDocs(SHARD_APPIDINFO, &info); SHAddToRecentDocs(SHARD_APPIDINFO, &info);
} }
} }
@ -66,16 +69,21 @@ void Browser::ClearRecentDocuments() {
if (FAILED(destinations.CoCreateInstance(CLSID_ApplicationDestinations, if (FAILED(destinations.CoCreateInstance(CLSID_ApplicationDestinations,
NULL, CLSCTX_INPROC_SERVER))) NULL, CLSCTX_INPROC_SERVER)))
return; return;
if (FAILED(destinations->SetAppID(app_user_model_id_.c_str()))) if (FAILED(destinations->SetAppID(GetAppUserModelID())))
return; return;
destinations->RemoveAllDestinations(); destinations->RemoveAllDestinations();
} }
void Browser::SetAppUserModelID(const base::string16& name) {
app_user_model_id_ = name;
SetCurrentProcessExplicitAppUserModelID(app_user_model_id_.c_str());
}
void Browser::SetUserTasks(const std::vector<UserTask>& tasks) { void Browser::SetUserTasks(const std::vector<UserTask>& tasks) {
CComPtr<ICustomDestinationList> destinations; CComPtr<ICustomDestinationList> destinations;
if (FAILED(destinations.CoCreateInstance(CLSID_DestinationList))) if (FAILED(destinations.CoCreateInstance(CLSID_DestinationList)))
return; return;
if (FAILED(destinations->SetAppID(app_user_model_id_.c_str()))) if (FAILED(destinations->SetAppID(GetAppUserModelID())))
return; return;
// Start a transaction that updates the JumpList of this application. // Start a transaction that updates the JumpList of this application.
@ -117,10 +125,13 @@ void Browser::SetUserTasks(const std::vector<UserTask>& tasks) {
destinations->CommitList(); destinations->CommitList();
} }
void Browser::SetAppUserModelID(const std::string& name) { PCWSTR Browser::GetAppUserModelID() {
app_user_model_id_ = base::string16(L"electron.app."); if (app_user_model_id_.empty()) {
app_user_model_id_ += base::UTF8ToUTF16(name); SetAppUserModelID(ReplaceStringPlaceholders(
SetCurrentProcessExplicitAppUserModelID(app_user_model_id_.c_str()); kAppUserModelIDFormat, base::UTF8ToUTF16(GetName()), nullptr));
}
return app_user_model_id_.c_str();
} }
std::string Browser::GetExecutableFileVersion() const { std::string Browser::GetExecutableFileVersion() const {

View file

@ -375,6 +375,12 @@ app.on('ready', function() {
}); });
``` ```
### `app.setAppUserModelId(id)` _Windows_
* `id` String
Changes the [Application User Model ID][app-user-model-id] to `id`.
### `app.commandLine.appendSwitch(switch[, value])` ### `app.commandLine.appendSwitch(switch[, value])`
Append a switch (with optional `value`) to Chromium's command line. Append a switch (with optional `value`) to Chromium's command line.
@ -435,3 +441,4 @@ Sets the application's [dock menu][dock-menu].
[dock-menu]:https://developer.apple.com/library/mac/documentation/Carbon/Conceptual/customizing_docktile/concepts/dockconcepts.html#//apple_ref/doc/uid/TP30000986-CH2-TPXREF103 [dock-menu]:https://developer.apple.com/library/mac/documentation/Carbon/Conceptual/customizing_docktile/concepts/dockconcepts.html#//apple_ref/doc/uid/TP30000986-CH2-TPXREF103
[tasks]:http://msdn.microsoft.com/en-us/library/windows/desktop/dd378460(v=vs.85).aspx#tasks [tasks]:http://msdn.microsoft.com/en-us/library/windows/desktop/dd378460(v=vs.85).aspx#tasks
[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx

View file

@ -9,15 +9,22 @@ still some subtle differences on each platform.
### OS X ### OS X
On OS X, the `autoUpdater` module is built upon [Squirrel.Mac][squirrel-mac], meaning you On OS X, the `autoUpdater` module is built upon [Squirrel.Mac][squirrel-mac],
don't need any special setup to make it work. For server-side requirements, you meaning you don't need any special setup to make it work. For server-side
can read [Server Support][server-support]. requirements, you can read [Server Support][server-support].
### Windows ### Windows
On Windows, you have to install your app into a user's machine before you can use On Windows, you have to install your app into a user's machine before you can
the auto-updater, so it is recommended to use [grunt-electron-installer][installer] use the auto-updater, so it is recommended to use
module to generate a Windows installer. [grunt-electron-installer][installer] module to generate a Windows installer.
The installer generated with Squirrel will create a shortcut icon with an
[Application User Model ID][app-user-model-id] in the format of
`com.squirrel.PACKAGE_ID.YOUR_EXE_WITHOUT_DOT_EXE`, examples are
`com.squirrel.slack.Slack` and `com.squirrel.code.Code`. You have to use the
same ID for your app with `app.setAppUserModelId` API, otherwise Windows will
not be able to pin your app properly in task bar.
The server-side setup is also different from OS X. You can read the documents of The server-side setup is also different from OS X. You can read the documents of
[Squirrel.Windows][squirrel-windows] to get more details. [Squirrel.Windows][squirrel-windows] to get more details.
@ -84,10 +91,11 @@ using this API.
### `autoUpdater.quitAndInstall()` ### `autoUpdater.quitAndInstall()`
Restarts the app and installs the update after it has been downloaded. It should Restarts the app and installs the update after it has been downloaded. It
only be called after `update-downloaded` has been emitted. should only be called after `update-downloaded` has been emitted.
[squirrel-mac]: https://github.com/Squirrel/Squirrel.Mac [squirrel-mac]: https://github.com/Squirrel/Squirrel.Mac
[server-support]: https://github.com/Squirrel/Squirrel.Mac#server-support [server-support]: https://github.com/Squirrel/Squirrel.Mac#server-support
[squirrel-windows]: https://github.com/Squirrel/Squirrel.Windows [squirrel-windows]: https://github.com/Squirrel/Squirrel.Windows
[installer]: https://github.com/atom/grunt-electron-installer [installer]: https://github.com/atom/grunt-electron-installer
[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx