diff --git a/browser/api/atom_api_app.cc b/browser/api/atom_api_app.cc index 909bff3950c7..375087a99f6c 100644 --- a/browser/api/atom_api_app.cc +++ b/browser/api/atom_api_app.cc @@ -101,11 +101,38 @@ v8::Handle App::Focus(const v8::Arguments &args) { // static v8::Handle App::GetVersion(const v8::Arguments &args) { + return ToV8Value(Browser::Get()->GetVersion()); +} + +// static +v8::Handle App::SetVersion(const v8::Arguments &args) { v8::HandleScope scope; - std::string version(Browser::Get()->GetVersion()); + std::string version; + if (!FromV8Arguments(args, &version)) + return node::ThrowError("Bad argument"); - return v8::String::New(version.data(), version.size()); + Browser::Get()->SetVersion(version); + + return v8::Undefined(); +} + +// static +v8::Handle App::GetName(const v8::Arguments &args) { + return ToV8Value(Browser::Get()->GetName()); +} + +// static +v8::Handle App::SetName(const v8::Arguments &args) { + v8::HandleScope scope; + + std::string name; + if (!FromV8Arguments(args, &name)) + return node::ThrowError("Bad argument"); + + Browser::Get()->SetName(name); + + return v8::Undefined(); } // static @@ -144,7 +171,10 @@ v8::Handle App::AppendArgument(const v8::Arguments &args) { // static v8::Handle App::DockBounce(const v8::Arguments& args) { - std::string type = FromV8Value(args[0]); + std::string type; + if (!FromV8Arguments(args, &type)) + return node::ThrowError("Bad argument"); + int request_id = -1; if (type == "critical") @@ -154,7 +184,7 @@ v8::Handle App::DockBounce(const v8::Arguments& args) { else return node::ThrowTypeError("Invalid bounce type"); - return v8::Integer::New(request_id); + return ToV8Value(request_id); } // static @@ -190,6 +220,9 @@ void App::Initialize(v8::Handle target) { NODE_SET_PROTOTYPE_METHOD(t, "terminate", Terminate); NODE_SET_PROTOTYPE_METHOD(t, "focus", Focus); NODE_SET_PROTOTYPE_METHOD(t, "getVersion", GetVersion); + NODE_SET_PROTOTYPE_METHOD(t, "setVersion", SetVersion); + NODE_SET_PROTOTYPE_METHOD(t, "getName", GetName); + NODE_SET_PROTOTYPE_METHOD(t, "setName", SetName); target->Set(v8::String::NewSymbol("Application"), t->GetFunction()); diff --git a/browser/api/atom_api_app.h b/browser/api/atom_api_app.h index 04b70eb78f91..ab701d9369f3 100644 --- a/browser/api/atom_api_app.h +++ b/browser/api/atom_api_app.h @@ -40,6 +40,9 @@ class App : public EventEmitter, static v8::Handle Terminate(const v8::Arguments &args); static v8::Handle Focus(const v8::Arguments &args); static v8::Handle GetVersion(const v8::Arguments &args); + static v8::Handle SetVersion(const v8::Arguments &args); + static v8::Handle GetName(const v8::Arguments &args); + static v8::Handle SetName(const v8::Arguments &args); static v8::Handle AppendSwitch(const v8::Arguments &args); static v8::Handle AppendArgument(const v8::Arguments &args); diff --git a/browser/api/atom_api_window.cc b/browser/api/atom_api_window.cc index c05493ca9672..27cf5706bbbc 100644 --- a/browser/api/atom_api_window.cc +++ b/browser/api/atom_api_window.cc @@ -576,16 +576,17 @@ v8::Handle Window::IsCrashed(const v8::Arguments &args) { v8::Handle Window::LoadURL(const v8::Arguments &args) { UNWRAP_WINDOW_AND_CHECK; - std::string url; + GURL url; if (!FromV8Arguments(args, &url)) return node::ThrowTypeError("Bad argument"); NavigationController& controller = self->window_->GetWebContents()->GetController(); - controller.LoadURL(GURL(url), - content::Referrer(), - content::PAGE_TRANSITION_AUTO_TOPLEVEL, - std::string()); + + content::NavigationController::LoadURLParams params(url); + params.transition_type = content::PAGE_TRANSITION_TYPED; + params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE; + controller.LoadURLWithParams(params); return v8::Undefined(); } @@ -596,9 +597,9 @@ v8::Handle Window::GetURL(const v8::Arguments &args) { NavigationController& controller = self->window_->GetWebContents()->GetController(); - std::string url; + GURL url; if (controller.GetActiveEntry()) - url = controller.GetActiveEntry()->GetVirtualURL().spec(); + url = controller.GetActiveEntry()->GetVirtualURL(); return ToV8Value(url); } diff --git a/browser/atom/atom.coffee b/browser/atom/atom.coffee index 6a52cac919b1..2488620467f4 100644 --- a/browser/atom/atom.coffee +++ b/browser/atom/atom.coffee @@ -59,5 +59,15 @@ catch error packagePath = path.join process.resourcesPath, 'browser', 'default_app' packageJson = JSON.parse(fs.readFileSync(path.join(packagePath, 'package.json'))) +# Set application's version. +app = require 'app' +app.setVersion packageJson.version if packageJson.version? + +# Set application's name. +if packageJson.productName? + app.setName packageJson.productName +else if packageJson.name? + app.setName packageJson.name + # Finally load app's main.js and transfer control to C++. require path.join(packagePath, packageJson.main) diff --git a/browser/browser.cc b/browser/browser.cc index c4a2d50cdf8f..49f2cef4ef6d 100644 --- a/browser/browser.cc +++ b/browser/browser.cc @@ -33,6 +33,34 @@ void Browser::Quit() { window_list->CloseAllWindows(); } +std::string Browser::GetVersion() const { + if (version_override_.empty()) { + std::string version = GetExecutableFileVersion(); + if (!version.empty()) + return version; + } + + return version_override_; +} + +void Browser::SetVersion(const std::string& version) { + version_override_ = version; +} + +std::string Browser::GetName() const { + if (name_override_.empty()) { + std::string name = GetExecutableFileProductName(); + if (!name.empty()) + return name; + } + + return name_override_; +} + +void Browser::SetName(const std::string& name) { + name_override_ = name; +} + bool Browser::OpenFile(const std::string& file_path) { bool prevent_default = false; FOR_EACH_OBSERVER(BrowserObserver, diff --git a/browser/browser.h b/browser/browser.h index c715dfe1c618..d20fc973ff26 100644 --- a/browser/browser.h +++ b/browser/browser.h @@ -31,7 +31,16 @@ class Browser : public WindowListObserver { void Focus(); // Returns the version of the executable (or bundle). - std::string GetVersion(); + std::string GetVersion() const; + + // Overrides the application version. + void SetVersion(const std::string& version); + + // Returns the application's name, default is just Atom-Shell. + std::string GetName() const; + + // Overrides the application name. + void SetName(const std::string& name); #if defined(OS_MACOSX) // Bounce the dock icon. @@ -68,6 +77,12 @@ class Browser : public WindowListObserver { bool is_quiting() const { return is_quiting_; } protected: + // Returns the version of application bundle or executable file. + std::string GetExecutableFileVersion() const; + + // Returns the name of application bundle or executable file. + std::string GetExecutableFileProductName() const; + // Send the will-quit message and then terminate the application. void NotifyAndTerminate(); @@ -84,6 +99,9 @@ class Browser : public WindowListObserver { // Observers of the browser. ObserverList observers_; + std::string version_override_; + std::string name_override_; + DISALLOW_COPY_AND_ASSIGN(Browser); }; diff --git a/browser/browser_mac.mm b/browser/browser_mac.mm index 95ce57e1d1bd..63312f4e6ec1 100644 --- a/browser/browser_mac.mm +++ b/browser/browser_mac.mm @@ -19,12 +19,18 @@ void Browser::Focus() { [[AtomApplication sharedApplication] activateIgnoringOtherApps:YES]; } -std::string Browser::GetVersion() { +std::string Browser::GetExecutableFileVersion() const { NSDictionary* infoDictionary = base::mac::OuterBundle().infoDictionary; NSString *version = [infoDictionary objectForKey:@"CFBundleVersion"]; return base::SysNSStringToUTF8(version); } +std::string Browser::GetExecutableFileProductName() const { + NSDictionary* infoDictionary = base::mac::OuterBundle().infoDictionary; + NSString *version = [infoDictionary objectForKey:@"CFBundleName"]; + return base::SysNSStringToUTF8(version); +} + void Browser::CancelQuit() { [[AtomApplication sharedApplication] replyToApplicationShouldTerminate:NO]; } diff --git a/browser/browser_win.cc b/browser/browser_win.cc index 1948abff5cb4..b065f70782fd 100644 --- a/browser/browser_win.cc +++ b/browser/browser_win.cc @@ -12,6 +12,7 @@ #include "base/memory/scoped_ptr.h" #include "base/path_service.h" #include "base/strings/utf_string_conversions.h" +#include "common/atom_version.h" namespace atom { @@ -43,7 +44,7 @@ void Browser::Focus() { EnumWindows(&WindowsEnumerationHandler, reinterpret_cast(&pid)); } -std::string Browser::GetVersion() { +std::string Browser::GetExecutableFileVersion() const { base::FilePath path; if (PathService::Get(base::FILE_EXE, &path)) { scoped_ptr version_info( @@ -51,7 +52,18 @@ std::string Browser::GetVersion() { return UTF16ToUTF8(version_info->product_version()); } - return ""; + return ATOM_VERSION_STRING; +} + +std::string Browser::GetExecutableFileProductName() const { + base::FilePath path; + if (PathService::Get(base::FILE_EXE, &path)) { + scoped_ptr version_info( + FileVersionInfo::CreateFileVersionInfo(path)); + return UTF16ToUTF8(version_info->product_name()); + } + + return "Atom-Shell"; } void Browser::CancelQuit() { diff --git a/browser/default_app/package.json b/browser/default_app/package.json index f27949723edf..b6abcc866952 100644 --- a/browser/default_app/package.json +++ b/browser/default_app/package.json @@ -1,5 +1,5 @@ { - "name": "atom", + "name": "atom-shell-default-app", "version": "0.1.0", "main": "main.js", "dependencies": { diff --git a/browser/native_window.cc b/browser/native_window.cc index 99e89d57320c..16e0891bc8d3 100644 --- a/browser/native_window.cc +++ b/browser/native_window.cc @@ -8,6 +8,7 @@ #include "base/file_util.h" #include "base/message_loop.h" +#include "base/stringprintf.h" #include "base/utf_string_conversions.h" #include "base/values.h" #include "brightray/browser/inspectable_web_contents.h" @@ -16,6 +17,7 @@ #include "browser/atom_browser_context.h" #include "browser/atom_browser_main_parts.h" #include "browser/atom_javascript_dialog_manager.h" +#include "browser/browser.h" #include "browser/window_list.h" #include "content/public/browser/devtools_agent_host.h" #include "content/public/browser/invalidate_type.h" @@ -26,7 +28,9 @@ #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host_view.h" +#include "content/public/common/renderer_preferences.h" #include "common/api/api_messages.h" +#include "common/atom_version.h" #include "common/options_switches.h" #include "ipc/ipc_message_macros.h" #include "ui/gfx/codec/png_codec.h" @@ -34,6 +38,7 @@ #include "ui/gfx/rect.h" #include "ui/gfx/size.h" #include "webkit/glue/image_decoder.h" +#include "webkit/user_agent/user_agent_util.h" using content::NavigationEntry; @@ -59,6 +64,15 @@ NativeWindow::NativeWindow(content::WebContents* web_contents, WindowList::AddWindow(this); + // Override the user agent to contain application and atom-shell's version. + Browser* browser = Browser::Get(); + std::string product_name = base::StringPrintf( + "%s/%s Atom-Shell/" ATOM_VERSION_STRING, + browser->GetName().c_str(), + browser->GetVersion().c_str()); + web_contents->GetMutableRendererPrefs()->user_agent_override = + webkit_glue::BuildUserAgentFromProduct(product_name); + // Get notified of title updated message. registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED, content::Source(web_contents)); diff --git a/common/v8_conversions.h b/common/v8_conversions.h index 57d69c2daae6..55b770996a7a 100644 --- a/common/v8_conversions.h +++ b/common/v8_conversions.h @@ -12,6 +12,7 @@ #include "base/files/file_path.h" #include "base/string16.h" #include "browser/api/atom_api_window.h" +#include "googleurl/src/gurl.h" #include "ui/gfx/rect.h" #include "v8/include/v8.h" @@ -36,6 +37,11 @@ struct FromV8Value { return string16(reinterpret_cast(*s), s.length()); } + operator GURL() { + std::string str = FromV8Value(value_); + return GURL(str); + } + operator base::FilePath() { return base::FilePath::FromUTF8Unsafe(FromV8Value(value_)); } @@ -116,6 +122,10 @@ inline v8::Handle ToV8Value(const string16& s) { return v8::String::New(reinterpret_cast(s.data()), s.size()); } +inline v8::Handle ToV8Value(const GURL& url) { + return ToV8Value(url.spec()); +} + inline v8::Handle ToV8Value(const base::FilePath& path) { std::string path_string(path.AsUTF8Unsafe()); return v8::String::New(path_string.data(), path_string.size()); @@ -159,6 +169,11 @@ bool V8ValueCanBeConvertedTo(v8::Handle value) { return V8ValueCanBeConvertedTo(value); } +template<> inline +bool V8ValueCanBeConvertedTo(v8::Handle value) { + return V8ValueCanBeConvertedTo(value); +} + template<> inline bool V8ValueCanBeConvertedTo(v8::Handle value) { return V8ValueCanBeConvertedTo(value); diff --git a/docs/api/browser/app.md b/docs/api/browser/app.md index c6e16a8875bf..55898cf30556 100644 --- a/docs/api/browser/app.md +++ b/docs/api/browser/app.md @@ -77,7 +77,19 @@ code will not run. ## app.getVersion() -Returns the version of current bundle or executable. +Returns the version of loaded application, if no version is found in +application's `package.json`, the version of current bundle or executable would +be returned. + +## app.getName() + +Returns current application's name, the name in `package.json` would be +used. + +Usually the `name` field of `package.json` is a short lowercased name, according +to the spec of npm modules. So usually you should also specify a `productName` +field, which is your application's full capitalized name, and it will be +preferred over `name` by atom-shell. ## app.getBrowserWindows() diff --git a/spec/api/app.coffee b/spec/api/app.coffee new file mode 100644 index 000000000000..d2d912db701e --- /dev/null +++ b/spec/api/app.coffee @@ -0,0 +1,23 @@ +assert = require 'assert' +app = require('remote').require 'app' + +describe 'app module', -> + describe 'app.getVersion()', -> + it 'returns the version field of package.json', -> + assert.equal app.getVersion(), '0.1.0' + + describe 'app.setVersion(version)', -> + it 'overrides the version', -> + assert.equal app.getVersion(), '0.1.0' + app.setVersion 'test-version' + assert.equal app.getVersion(), 'test-version' + + describe 'app.getName()', -> + it 'returns the name field of package.json', -> + assert.equal app.getName(), 'atom-shell-default-app' + + describe 'app.setName(name)', -> + it 'overrides the name', -> + assert.equal app.getName(), 'atom-shell-default-app' + app.setName 'test-name' + assert.equal app.getName(), 'test-name'