diff --git a/src/api/nw_app.idl b/src/api/nw_app.idl index be195a1aec..2264ed3f33 100644 --- a/src/api/nw_app.idl +++ b/src/api/nw_app.idl @@ -26,6 +26,8 @@ namespace nw.App { static DOMString[] getArgvSync(); static DOMString getDataPath(); static void crashBrowser(); + static DOMString getDefaultAppUserModelID(); + static void setDefaultAppUserModelID(DOMString app_id); }; interface Events { static void onOpen(DOMString cmdline); diff --git a/src/api/nw_app_api.cc b/src/api/nw_app_api.cc index b89580b14d..8ff6a96eab 100644 --- a/src/api/nw_app_api.cc +++ b/src/api/nw_app_api.cc @@ -2,12 +2,16 @@ #include "base/command_line.h" #include "base/memory/ptr_util.h" +#include "base/strings/utf_string_conversions.h" #include "chrome/browser/browsing_data/browsing_data_appcache_helper.h" #include "chrome/browser/browsing_data/browsing_data_helper.h" #include "chrome/browser/browsing_data/browsing_data_remover_factory.h" #include "chrome/browser/devtools/devtools_window.h" #include "chrome/browser/extensions/devtools_util.h" #include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/web_applications/web_app.h" +#include "content/nw/src/common/shell_switches.h" #include "content/nw/src/nw_base.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" @@ -24,6 +28,10 @@ #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_getter.h" +#if defined(OS_WIN) +#include "chrome/browser/shell_integration_win.h" +#endif + namespace { void SetProxyConfigCallback( base::WaitableEvent* done, @@ -182,5 +190,35 @@ bool NwAppCrashBrowserFunction::RunAsync() { return true; } +bool NwAppGetDefaultAppUserModelIDFunction::RunNWSync(base::ListValue* response, std::string* error) { +#if defined(OS_WIN) + base::string16 app_id; + nw::Package* package = nw::package(); + if (package->root()->GetString(::switches::kmAppUserModelID, &app_id)) { + response->AppendString(app_id); + } else { + std::string app_name = + web_app::GenerateApplicationNameFromExtensionId(extension_id()); + base::string16 app_name_wide = base::UTF8ToWide(app_name); + Profile* profile = + Profile::FromBrowserContext(browser_context()); + app_id = shell_integration::win::GetAppModelIdForProfile( + app_name_wide, profile->GetPath()); + response->AppendString(app_id); + } +#endif + return true; +} + +bool NwAppSetDefaultAppUserModelIDFunction::RunNWSync(base::ListValue* response, std::string* error) { +#if defined(OS_WIN) + std::string app_id; + EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &app_id)); + + nw::Package* package = nw::package(); + package->root()->SetString(::switches::kmAppUserModelID, app_id); +#endif + return true; +} } // namespace extensions diff --git a/src/api/nw_app_api.h b/src/api/nw_app_api.h index 7cdd4473fe..036b0ce2ff 100644 --- a/src/api/nw_app_api.h +++ b/src/api/nw_app_api.h @@ -117,5 +117,31 @@ class NwAppCrashBrowserFunction : public AsyncExtensionFunction { DECLARE_EXTENSION_FUNCTION("nw.App.crashBrowser", UNKNOWN) }; +class NwAppGetDefaultAppUserModelIDFunction : public NWSyncExtensionFunction { + public: + NwAppGetDefaultAppUserModelIDFunction(){} + bool RunNWSync(base::ListValue* response, std::string* error) override; + + protected: + ~NwAppGetDefaultAppUserModelIDFunction() override {} + + DECLARE_EXTENSION_FUNCTION("nw.App.getDefaultAppUserModelID", UNKNOWN) + private: + DISALLOW_COPY_AND_ASSIGN(NwAppGetDefaultAppUserModelIDFunction); +}; + +class NwAppSetDefaultAppUserModelIDFunction : public NWSyncExtensionFunction { + public: + NwAppSetDefaultAppUserModelIDFunction(){} + bool RunNWSync(base::ListValue* response, std::string* error) override; + + protected: + ~NwAppSetDefaultAppUserModelIDFunction() override {} + + DECLARE_EXTENSION_FUNCTION("nw.App.setDefaultAppUserModelID", UNKNOWN) + private: + DISALLOW_COPY_AND_ASSIGN(NwAppSetDefaultAppUserModelIDFunction); +}; + } // namespace extensions #endif diff --git a/src/api/nw_current_window_internal.idl b/src/api/nw_current_window_internal.idl index a1d1dfac56..17e04ed9a7 100644 --- a/src/api/nw_current_window_internal.idl +++ b/src/api/nw_current_window_internal.idl @@ -44,5 +44,7 @@ namespace nw.currentWindowInternal { static object getWinParamInternal(); static void getPrinters(GetPrintersCallback callback); static void setPrintSettingsInternal(optional object options); + static DOMString getAppUserModelID(); + static void setAppUserModelID(DOMString id); }; }; diff --git a/src/api/nw_window.idl b/src/api/nw_window.idl index 0076817dbe..78361a73f0 100644 --- a/src/api/nw_window.idl +++ b/src/api/nw_window.idl @@ -39,6 +39,7 @@ namespace nw.Window { [nodoc] DOMString? icon; [nodoc] DOMString? inject_js_start; [nodoc] DOMString? inject_js_end; + [nodoc] DOMString? app_user_model_id; }; [noinline_doc] dictionary NWWindow { @@ -72,6 +73,8 @@ namespace nw.Window { static void removeAllListeners(DOMString event); static void reload(); static void reloadIgnoringCache(); + static DOMString getAppUserModelID(); + static void setAppUserModelID(DOMString id); static void eval(object frame, DOMString script); static void evalNWBin(object frame, DOMString path); diff --git a/src/api/nw_window_api.cc b/src/api/nw_window_api.cc index f58a375344..0ca7261933 100644 --- a/src/api/nw_window_api.cc +++ b/src/api/nw_window_api.cc @@ -38,6 +38,7 @@ #include "ui/gfx/platform_font.h" #include "ui/display/win/dpi.h" #include "ui/views/win/hwnd_util.h" +#include "chrome/browser/ui/views/apps/chrome_native_app_window_views_win.h" #endif #if defined(OS_LINUX) @@ -746,5 +747,47 @@ bool NwCurrentWindowInternalSetShowInTaskbarFunction::RunAsync() { return true; } +bool NwCurrentWindowInternalGetAppUserModelIDFunction::RunNWSync(base::ListValue* response, std::string* error) { +#if defined(OS_WIN) + AppWindow* app_window = getAppWindow(this); + + if (!app_window) { + *error = "cannot get current window; are you in background page/node context?"; + return false; + } + + ChromeNativeAppWindowViewsWin* native_app_window = static_cast(app_window->GetBaseWindow()); + response->AppendString(native_app_window->app_model_id()); +#endif + return true; +} + +bool NwCurrentWindowInternalSetAppUserModelIDFunction::RunNWSync(base::ListValue* response, std::string* error) { +#if defined(OS_WIN) + EXTENSION_FUNCTION_VALIDATE(args_); + + if (!args_->GetSize()) + return false; + base::string16 app_id; + if (!args_->GetString(0, &app_id)) + return false; + if (app_id.empty()) { + *error = "AppUserModelID cannot set to empty string"; + return false; + } + + AppWindow* app_window = getAppWindow(this); + + if (!app_window) { + *error = "cannot get current window; are you in background page/node context?"; + return false; + } + + ChromeNativeAppWindowViewsWin* native_app_window = static_cast(app_window->GetBaseWindow()); + native_app_window->SetAppModelId(app_id); +#endif + return true; +} + } // namespace extensions diff --git a/src/api/nw_window_api.h b/src/api/nw_window_api.h index 4dd66a6079..5ba11bcb58 100644 --- a/src/api/nw_window_api.h +++ b/src/api/nw_window_api.h @@ -300,5 +300,25 @@ class NwCurrentWindowInternalSetPrintSettingsInternalFunction : public NWSyncExt ~NwCurrentWindowInternalSetPrintSettingsInternalFunction() override {} DECLARE_EXTENSION_FUNCTION("nw.currentWindowInternal.setPrintSettingsInternal", UNKNOWN) }; + +class NwCurrentWindowInternalGetAppUserModelIDFunction : public NWSyncExtensionFunction { + public: + NwCurrentWindowInternalGetAppUserModelIDFunction() {} + bool RunNWSync(base::ListValue* response, std::string* error) override; + + protected: + ~NwCurrentWindowInternalGetAppUserModelIDFunction() override {} + DECLARE_EXTENSION_FUNCTION("nw.currentWindowInternal.getAppUserModelID", UNKNOWN) +}; + +class NwCurrentWindowInternalSetAppUserModelIDFunction : public NWSyncExtensionFunction { + public: + NwCurrentWindowInternalSetAppUserModelIDFunction() {} + bool RunNWSync(base::ListValue* response, std::string* error) override; + + protected: + ~NwCurrentWindowInternalSetAppUserModelIDFunction() override {} + DECLARE_EXTENSION_FUNCTION("nw.currentWindowInternal.setAppUserModelID", UNKNOWN) +}; } // namespace extensions #endif diff --git a/src/common/shell_switches.cc b/src/common/shell_switches.cc index 3ae10c959a..4e7d3e6eb6 100644 --- a/src/common/shell_switches.cc +++ b/src/common/shell_switches.cc @@ -112,6 +112,7 @@ const char kmNewInstance[] = "new-instance"; const char kmInjectJSDocStart[] = "inject_js_start"; const char kmInjectJSDocEnd[] = "inject_js_end"; const char kmInjectCSS[] = "inject-css"; +const char kmAppUserModelID[] = "app_user_model_id"; #if defined(OS_WIN) // Enable conversion from vector to raster for any page. diff --git a/src/common/shell_switches.h b/src/common/shell_switches.h index 097f550db5..2a22e2da1c 100644 --- a/src/common/shell_switches.h +++ b/src/common/shell_switches.h @@ -35,6 +35,7 @@ extern NW_EXPORT const char kmWebkit[]; extern NW_EXPORT const char kmWindow[]; extern NW_EXPORT const char kmChromiumArgs[]; extern NW_EXPORT const char kmJsFlags[]; +extern NW_EXPORT const char kmAppUserModelID[]; extern NW_EXPORT const char kmSingleInstance[]; diff --git a/src/resources/api_nw_app.js b/src/resources/api_nw_app.js index 8ce7517346..ae2bca685b 100644 --- a/src/resources/api_nw_app.js +++ b/src/resources/api_nw_app.js @@ -71,6 +71,12 @@ nw_binding.registerCustomHook(function(bindingsAPI) { apiFunctions.setHandleRequest('removeOriginAccessWhitelistEntry', function() { nwNatives.removeOriginAccessWhitelistEntry.apply(this, arguments); }); + apiFunctions.setHandleRequest('getDefaultAppUserModelID', function() { + return sendRequest.sendRequestSync('nw.App.getDefaultAppUserModelID', arguments, this.definition.parameters, {})[0]; + }); + apiFunctions.setHandleRequest('setDefaultAppUserModelID', function() { + sendRequest.sendRequestSync('nw.App.setDefaultAppUserModelID', arguments, this.definition.parameters, {}); + }); apiFunctions.setHandleRequest('once', function(event, listener) { //FIXME: unify with nw.Window if (typeof listener !== 'function') throw new TypeError('listener must be a function'); @@ -119,7 +125,6 @@ nw_binding.registerCustomHook(function(bindingsAPI) { bindingsAPI.compiledApi.unregisterGlobalHotKey = function() { return nw.Shortcut.unregisterGlobalHotKey.apply(nw.Shortcut, arguments); }; - }); exports.binding = nw_binding.generate(); diff --git a/src/resources/api_nw_window.js b/src/resources/api_nw_window.js index 12c8cc1cd5..5329bf73cc 100644 --- a/src/resources/api_nw_window.js +++ b/src/resources/api_nw_window.js @@ -164,6 +164,12 @@ nw_internal.registerCustomHook(function(bindingsAPI) { apiFunctions.setHandleRequest('setMenu', function() { return sendRequest.sendRequestSync('nw.currentWindowInternal.setMenu', arguments, this.definition.parameters, {})[0]; }); + apiFunctions.setHandleRequest('getAppUserModelID', function() { + return sendRequest.sendRequestSync('nw.currentWindowInternal.getAppUserModelID', arguments, this.definition.parameters, {})[0]; + }); + apiFunctions.setHandleRequest('setAppUserModelID', function() { + return sendRequest.sendRequestSync('nw.currentWindowInternal.setAppUserModelID', arguments, this.definition.parameters, {})[0]; + }); }); nw_binding.registerCustomHook(function(bindingsAPI) { @@ -409,6 +415,12 @@ nw_binding.registerCustomHook(function(bindingsAPI) { NWWindow.prototype.reloadIgnoringCache = function () { currentNWWindowInternal.reloadIgnoringCache(); }; + NWWindow.prototype.getAppUserModelID = function() { + return currentNWWindowInternal.getAppUserModelID(); + }; + NWWindow.prototype.setAppUserModelID = function(app_id) { + return currentNWWindowInternal.setAppUserModelID(app_id); + }; NWWindow.prototype.eval = function (frame, script) { return nwNatives.evalScript(frame, script); }; @@ -670,6 +682,8 @@ nw_binding.registerCustomHook(function(bindingsAPI) { options.inject_js_start = params['inject_js_start']; if (typeof params['inject_js_end'] == 'string') options.inject_js_end = params['inject_js_end']; + if (typeof params['app_user_model_id'] == 'string') + options.app_user_model_id = params['app_user_model_id']; if (params.transparent) options.alphaEnabled = true; if (params.kiosk === true)