Merge remote-tracking branch 'refs/remotes/atom/master'

This commit is contained in:
Plusb Preco 2015-11-09 08:17:12 +09:00
commit 91c7043a1b
42 changed files with 484 additions and 123 deletions

View file

@ -7,14 +7,14 @@
:zap: *Formerly known as Atom Shell* :zap: :zap: *Formerly known as Atom Shell* :zap:
The Electron framework lets you write cross-platform desktop applications The Electron framework lets you write cross-platform desktop applications
using JavaScript, HTML and CSS. It is based on [Node.js](https://nodejs.org) and using JavaScript, HTML and CSS. It is based on [Node.js](https://nodejs.org/) and
[Chromium](http://www.chromium.org) and is used in the [Atom [Chromium](http://www.chromium.org) and is used in the [Atom
editor](https://github.com/atom/atom). editor](https://github.com/atom/atom).
Follow [@ElectronJS](https://twitter.com/electronjs) on Twitter for important Follow [@ElectronJS](https://twitter.com/electronjs) on Twitter for important
announcements. announcements.
This project adheres to the [Contributor Covenant 1.2](http://contributor-covenant.org/version/1/2/0). This project adheres to the [Contributor Covenant 1.2](http://contributor-covenant.org/version/1/2/0/).
By participating, you are expected to uphold this code. Please report By participating, you are expected to uphold this code. Please report
unacceptable behavior to atom@github.com. unacceptable behavior to atom@github.com.
@ -62,7 +62,7 @@ repository to see a minimal Electron app in action.
You can ask questions and interact with the community in the following You can ask questions and interact with the community in the following
locations: locations:
- [`electron`](http://discuss.atom.io/category/electron) category on the Atom - [`electron`](http://discuss.atom.io/c/electron) category on the Atom
forums forums
- `#atom-shell` channel on Freenode - `#atom-shell` channel on Freenode
- [`Atom`](http://atom-slack.herokuapp.com/) channel on Slack - [`Atom`](http://atom-slack.herokuapp.com/) channel on Slack

View file

@ -4,7 +4,7 @@
'product_name%': 'Electron', 'product_name%': 'Electron',
'company_name%': 'GitHub, Inc', 'company_name%': 'GitHub, Inc',
'company_abbr%': 'github', 'company_abbr%': 'github',
'version%': '0.34.2', 'version%': '0.34.3',
}, },
'includes': [ 'includes': [
'filenames.gypi', 'filenames.gypi',

View file

@ -102,13 +102,6 @@ void AtomMainDelegate::PreSandboxStartup() {
if (!IsBrowserProcess(command_line)) if (!IsBrowserProcess(command_line))
return; return;
#if defined(OS_WIN)
// Disable the LegacyRenderWidgetHostHWND, it made frameless windows unable
// to move and resize. We may consider enabling it again after upgraded to
// Chrome 38, which should have fixed the problem.
command_line->AppendSwitch(switches::kDisableLegacyIntermediateWindow);
#endif
// Disable renderer sandbox for most of node's functions. // Disable renderer sandbox for most of node's functions.
command_line->AppendSwitch(switches::kNoSandbox); command_line->AppendSwitch(switches::kNoSandbox);

View file

@ -339,6 +339,7 @@ mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
auto browser = base::Unretained(Browser::Get()); auto browser = base::Unretained(Browser::Get());
return mate::ObjectTemplateBuilder(isolate) return mate::ObjectTemplateBuilder(isolate)
.SetMethod("quit", base::Bind(&Browser::Quit, browser)) .SetMethod("quit", base::Bind(&Browser::Quit, browser))
.SetMethod("exit", base::Bind(&Browser::Exit, browser))
.SetMethod("focus", base::Bind(&Browser::Focus, browser)) .SetMethod("focus", base::Bind(&Browser::Focus, browser))
.SetMethod("getVersion", base::Bind(&Browser::GetVersion, browser)) .SetMethod("getVersion", base::Bind(&Browser::GetVersion, browser))
.SetMethod("setVersion", base::Bind(&Browser::SetVersion, browser)) .SetMethod("setVersion", base::Bind(&Browser::SetVersion, browser))

View file

@ -6,6 +6,7 @@
#include <map> #include <map>
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/file_path_converter.h" #include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/native_mate_converters/gurl_converter.h" #include "atom/common/native_mate_converters/gurl_converter.h"
@ -159,14 +160,6 @@ mate::ObjectTemplateBuilder DownloadItem::GetObjectTemplateBuilder(
.SetMethod("setSavePath", &DownloadItem::SetSavePath); .SetMethod("setSavePath", &DownloadItem::SetSavePath);
} }
void SetWrapDownloadItem(const WrapDownloadItemCallback& callback) {
g_wrap_download_item = callback;
}
void ClearWrapDownloadItem() {
g_wrap_download_item.Reset();
}
// static // static
mate::Handle<DownloadItem> DownloadItem::Create( mate::Handle<DownloadItem> DownloadItem::Create(
v8::Isolate* isolate, content::DownloadItem* item) { v8::Isolate* isolate, content::DownloadItem* item) {
@ -182,6 +175,18 @@ void* DownloadItem::UserDataKey() {
return &kDownloadItemSavePathKey; return &kDownloadItemSavePathKey;
} }
void ClearWrapDownloadItem() {
g_wrap_download_item.Reset();
}
void SetWrapDownloadItem(const WrapDownloadItemCallback& callback) {
g_wrap_download_item = callback;
// Cleanup the wrapper on exit.
atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback(
base::Bind(ClearWrapDownloadItem));
}
} // namespace api } // namespace api
} // namespace atom } // namespace atom
@ -193,7 +198,6 @@ void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
v8::Isolate* isolate = context->GetIsolate(); v8::Isolate* isolate = context->GetIsolate();
mate::Dictionary dict(isolate, exports); mate::Dictionary dict(isolate, exports);
dict.SetMethod("_setWrapDownloadItem", &atom::api::SetWrapDownloadItem); dict.SetMethod("_setWrapDownloadItem", &atom::api::SetWrapDownloadItem);
dict.SetMethod("_clearWrapDownloadItem", &atom::api::ClearWrapDownloadItem);
} }
} // namespace } // namespace

View file

@ -23,6 +23,9 @@ GlobalShortcut::GlobalShortcut() {
} }
GlobalShortcut::~GlobalShortcut() { GlobalShortcut::~GlobalShortcut() {
}
void GlobalShortcut::Destroy() {
UnregisterAll(); UnregisterAll();
} }

View file

@ -8,9 +8,9 @@
#include <map> #include <map>
#include <string> #include <string>
#include "atom/browser/api/trackable_object.h"
#include "base/callback.h" #include "base/callback.h"
#include "chrome/browser/extensions/global_shortcut_listener.h" #include "chrome/browser/extensions/global_shortcut_listener.h"
#include "native_mate/wrappable.h"
#include "native_mate/handle.h" #include "native_mate/handle.h"
#include "ui/base/accelerators/accelerator.h" #include "ui/base/accelerators/accelerator.h"
@ -19,13 +19,16 @@ namespace atom {
namespace api { namespace api {
class GlobalShortcut : public extensions::GlobalShortcutListener::Observer, class GlobalShortcut : public extensions::GlobalShortcutListener::Observer,
public mate::Wrappable { public mate::TrackableObject<GlobalShortcut> {
public: public:
static mate::Handle<GlobalShortcut> Create(v8::Isolate* isolate); static mate::Handle<GlobalShortcut> Create(v8::Isolate* isolate);
protected: protected:
GlobalShortcut(); GlobalShortcut();
virtual ~GlobalShortcut(); ~GlobalShortcut() override;
// mate::TrackableObject:
void Destroy() override;
// mate::Wrappable implementations: // mate::Wrappable implementations:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder( mate::ObjectTemplateBuilder GetObjectTemplateBuilder(

View file

@ -27,6 +27,14 @@ Menu::Menu()
Menu::~Menu() { Menu::~Menu() {
} }
void Menu::Destroy() {
model_.reset();
}
bool Menu::IsDestroyed() const {
return !model_;
}
void Menu::AfterInit(v8::Isolate* isolate) { void Menu::AfterInit(v8::Isolate* isolate) {
mate::Dictionary wrappable(isolate, GetWrapper(isolate)); mate::Dictionary wrappable(isolate, GetWrapper(isolate));
mate::Dictionary delegate; mate::Dictionary delegate;

View file

@ -8,16 +8,16 @@
#include <string> #include <string>
#include "atom/browser/api/atom_api_window.h" #include "atom/browser/api/atom_api_window.h"
#include "atom/browser/api/trackable_object.h"
#include "atom/browser/ui/atom_menu_model.h" #include "atom/browser/ui/atom_menu_model.h"
#include "base/callback.h" #include "base/callback.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "native_mate/wrappable.h"
namespace atom { namespace atom {
namespace api { namespace api {
class Menu : public mate::Wrappable, class Menu : public mate::TrackableObject<Menu>,
public AtomMenuModel::Delegate { public AtomMenuModel::Delegate {
public: public:
static mate::Wrappable* Create(); static mate::Wrappable* Create();
@ -37,9 +37,13 @@ class Menu : public mate::Wrappable,
protected: protected:
Menu(); Menu();
virtual ~Menu(); ~Menu() override;
// mate::TrackableObject:
void Destroy() override;
// mate::Wrappable: // mate::Wrappable:
bool IsDestroyed() const override;
void AfterInit(v8::Isolate* isolate) override; void AfterInit(v8::Isolate* isolate) override;
// ui::SimpleMenuModel::Delegate: // ui::SimpleMenuModel::Delegate:

View file

@ -19,6 +19,7 @@ class MenuMac : public Menu {
protected: protected:
MenuMac(); MenuMac();
void Destroy() override;
void Popup(Window* window) override; void Popup(Window* window) override;
void PopupAt(Window* window, int x, int y) override; void PopupAt(Window* window, int x, int y) override;

View file

@ -18,6 +18,11 @@ namespace api {
MenuMac::MenuMac() { MenuMac::MenuMac() {
} }
void MenuMac::Destroy() {
menu_controller_.reset();
Menu::Destroy();
}
void MenuMac::Popup(Window* window) { void MenuMac::Popup(Window* window) {
NativeWindow* native_window = window->window(); NativeWindow* native_window = window->window();
if (!native_window) if (!native_window)

View file

@ -19,6 +19,9 @@ PowerMonitor::PowerMonitor() {
} }
PowerMonitor::~PowerMonitor() { PowerMonitor::~PowerMonitor() {
}
void PowerMonitor::Destroy() {
base::PowerMonitor::Get()->RemoveObserver(this); base::PowerMonitor::Get()->RemoveObserver(this);
} }

View file

@ -5,7 +5,7 @@
#ifndef ATOM_BROWSER_API_ATOM_API_POWER_MONITOR_H_ #ifndef ATOM_BROWSER_API_ATOM_API_POWER_MONITOR_H_
#define ATOM_BROWSER_API_ATOM_API_POWER_MONITOR_H_ #define ATOM_BROWSER_API_ATOM_API_POWER_MONITOR_H_
#include "atom/browser/api/event_emitter.h" #include "atom/browser/api/trackable_object.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/power_monitor/power_observer.h" #include "base/power_monitor/power_observer.h"
#include "native_mate/handle.h" #include "native_mate/handle.h"
@ -14,14 +14,17 @@ namespace atom {
namespace api { namespace api {
class PowerMonitor : public mate::EventEmitter, class PowerMonitor : public mate::TrackableObject<PowerMonitor>,
public base::PowerObserver { public base::PowerObserver {
public: public:
static v8::Local<v8::Value> Create(v8::Isolate* isolate); static v8::Local<v8::Value> Create(v8::Isolate* isolate);
protected: protected:
PowerMonitor(); PowerMonitor();
virtual ~PowerMonitor(); ~PowerMonitor() override;
// mate::TrackableObject:
void Destroy() override;
// base::PowerObserver implementations: // base::PowerObserver implementations:
void OnPowerStateChange(bool on_battery_power) override; void OnPowerStateChange(bool on_battery_power) override;

View file

@ -45,6 +45,11 @@ PowerSaveBlocker::PowerSaveBlocker()
PowerSaveBlocker::~PowerSaveBlocker() { PowerSaveBlocker::~PowerSaveBlocker() {
} }
void PowerSaveBlocker::Destroy() {
power_save_blocker_types_.clear();
power_save_blocker_.reset();
}
void PowerSaveBlocker::UpdatePowerSaveBlocker() { void PowerSaveBlocker::UpdatePowerSaveBlocker() {
if (power_save_blocker_types_.empty()) { if (power_save_blocker_types_.empty()) {
power_save_blocker_.reset(); power_save_blocker_.reset();

View file

@ -7,10 +7,10 @@
#include <map> #include <map>
#include "atom/browser/api/trackable_object.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "content/public/browser/power_save_blocker.h" #include "content/public/browser/power_save_blocker.h"
#include "native_mate/handle.h" #include "native_mate/handle.h"
#include "native_mate/wrappable.h"
namespace mate { namespace mate {
class Dictionary; class Dictionary;
@ -20,13 +20,16 @@ namespace atom {
namespace api { namespace api {
class PowerSaveBlocker : public mate::Wrappable { class PowerSaveBlocker : public mate::TrackableObject<PowerSaveBlocker> {
public: public:
static mate::Handle<PowerSaveBlocker> Create(v8::Isolate* isolate); static mate::Handle<PowerSaveBlocker> Create(v8::Isolate* isolate);
protected: protected:
PowerSaveBlocker(); PowerSaveBlocker();
virtual ~PowerSaveBlocker(); ~PowerSaveBlocker() override;
// mate::TrackableObject:
void Destroy() override;
// mate::Wrappable implementations: // mate::Wrappable implementations:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder( mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
@ -48,7 +51,6 @@ class PowerSaveBlocker : public mate::Wrappable {
std::map<int, content::PowerSaveBlocker::PowerSaveBlockerType>; std::map<int, content::PowerSaveBlocker::PowerSaveBlockerType>;
PowerSaveBlockerTypeMap power_save_blocker_types_; PowerSaveBlockerTypeMap power_save_blocker_types_;
DISALLOW_COPY_AND_ASSIGN(PowerSaveBlocker); DISALLOW_COPY_AND_ASSIGN(PowerSaveBlocker);
}; };

View file

@ -9,9 +9,10 @@
#include "atom/browser/api/atom_api_cookies.h" #include "atom/browser/api/atom_api_cookies.h"
#include "atom/browser/api/atom_api_download_item.h" #include "atom/browser/api/atom_api_download_item.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/api/atom_api_web_contents.h" #include "atom/browser/api/atom_api_web_contents.h"
#include "atom/browser/api/save_page_handler.h" #include "atom/browser/api/save_page_handler.h"
#include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/gurl_converter.h" #include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/native_mate_converters/file_path_converter.h" #include "atom/common/native_mate_converters/file_path_converter.h"
@ -395,14 +396,18 @@ mate::Handle<Session> Session::FromPartition(
static_cast<AtomBrowserContext*>(browser_context.get())); static_cast<AtomBrowserContext*>(browser_context.get()));
} }
void SetWrapSession(const WrapSessionCallback& callback) {
g_wrap_session = callback;
}
void ClearWrapSession() { void ClearWrapSession() {
g_wrap_session.Reset(); g_wrap_session.Reset();
} }
void SetWrapSession(const WrapSessionCallback& callback) {
g_wrap_session = callback;
// Cleanup the wrapper on exit.
atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback(
base::Bind(ClearWrapSession));
}
} // namespace api } // namespace api
} // namespace atom } // namespace atom
@ -415,7 +420,6 @@ void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
mate::Dictionary dict(isolate, exports); mate::Dictionary dict(isolate, exports);
dict.SetMethod("fromPartition", &atom::api::Session::FromPartition); dict.SetMethod("fromPartition", &atom::api::Session::FromPartition);
dict.SetMethod("_setWrapSession", &atom::api::SetWrapSession); dict.SetMethod("_setWrapSession", &atom::api::SetWrapSession);
dict.SetMethod("_clearWrapSession", &atom::api::ClearWrapSession);
} }
} // namespace } // namespace

View file

@ -8,7 +8,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "atom/browser/api/event_emitter.h" #include "atom/browser/api/trackable_object.h"
#include "atom/browser/ui/tray_icon_observer.h" #include "atom/browser/ui/tray_icon_observer.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
@ -29,7 +29,7 @@ namespace api {
class Menu; class Menu;
class Tray : public mate::EventEmitter, class Tray : public mate::TrackableObject<Tray>,
public TrayIconObserver { public TrayIconObserver {
public: public:
static mate::Wrappable* New(v8::Isolate* isolate, const gfx::Image& image); static mate::Wrappable* New(v8::Isolate* isolate, const gfx::Image& image);
@ -39,7 +39,7 @@ class Tray : public mate::EventEmitter,
protected: protected:
explicit Tray(const gfx::Image& image); explicit Tray(const gfx::Image& image);
virtual ~Tray(); ~Tray() override;
// TrayIconObserver: // TrayIconObserver:
void OnClicked(const gfx::Rect& bounds, int modifiers) override; void OnClicked(const gfx::Rect& bounds, int modifiers) override;
@ -53,7 +53,9 @@ class Tray : public mate::EventEmitter,
// mate::Wrappable: // mate::Wrappable:
bool IsDestroyed() const override; bool IsDestroyed() const override;
void Destroy(); // mate::TrackableObject:
void Destroy() override;
void SetImage(mate::Arguments* args, const gfx::Image& image); void SetImage(mate::Arguments* args, const gfx::Image& image);
void SetPressedImage(mate::Arguments* args, const gfx::Image& image); void SetPressedImage(mate::Arguments* args, const gfx::Image& image);
void SetToolTip(mate::Arguments* args, const std::string& tool_tip); void SetToolTip(mate::Arguments* args, const std::string& tool_tip);

View file

@ -1124,14 +1124,18 @@ mate::Handle<WebContents> WebContents::Create(
return handle; return handle;
} }
void SetWrapWebContents(const WrapWebContentsCallback& callback) {
g_wrap_web_contents = callback;
}
void ClearWrapWebContents() { void ClearWrapWebContents() {
g_wrap_web_contents.Reset(); g_wrap_web_contents.Reset();
} }
void SetWrapWebContents(const WrapWebContentsCallback& callback) {
g_wrap_web_contents = callback;
// Cleanup the wrapper on exit.
atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback(
base::Bind(ClearWrapWebContents));
}
} // namespace api } // namespace api
} // namespace atom } // namespace atom
@ -1145,7 +1149,6 @@ void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
mate::Dictionary dict(isolate, exports); mate::Dictionary dict(isolate, exports);
dict.SetMethod("create", &atom::api::WebContents::Create); dict.SetMethod("create", &atom::api::WebContents::Create);
dict.SetMethod("_setWrapWebContents", &atom::api::SetWrapWebContents); dict.SetMethod("_setWrapWebContents", &atom::api::SetWrapWebContents);
dict.SetMethod("_clearWrapWebContents", &atom::api::ClearWrapWebContents);
} }
} // namespace } // namespace

View file

@ -11,14 +11,14 @@ wrapSession = (session) ->
# session is an Event Emitter. # session is an Event Emitter.
session.__proto__ = EventEmitter.prototype session.__proto__ = EventEmitter.prototype
wrapDownloadItem = (download_item) -> wrapDownloadItem = (downloadItem) ->
# download_item is an Event Emitter. # downloadItem is an Event Emitter.
download_item.__proto__ = EventEmitter.prototype downloadItem.__proto__ = EventEmitter.prototype
# Be compatible with old APIs. # Be compatible with old APIs.
download_item.url = download_item.getUrl() downloadItem.url = downloadItem.getUrl()
download_item.filename = download_item.getFilename() downloadItem.filename = downloadItem.getFilename()
download_item.mimeType = download_item.getMimeType() downloadItem.mimeType = downloadItem.getMimeType()
download_item.hasUserGesture = download_item.hasUserGesture() downloadItem.hasUserGesture = downloadItem.hasUserGesture()
app.setApplicationMenu = (menu) -> app.setApplicationMenu = (menu) ->
require('menu').setApplicationMenu menu require('menu').setApplicationMenu menu
@ -50,19 +50,15 @@ app.getAppPath = ->
# Be compatible with old API. # Be compatible with old API.
app.once 'ready', -> @emit 'finish-launching' app.once 'ready', -> @emit 'finish-launching'
app.terminate = app.quit app.terminate = app.quit
app.exit = process.exit
app.getHomeDir = -> @getPath 'home' app.getHomeDir = -> @getPath 'home'
app.getDataPath = -> @getPath 'userData' app.getDataPath = -> @getPath 'userData'
app.setDataPath = (path) -> @setPath 'userData', path app.setDataPath = (path) -> @setPath 'userData', path
app.resolveProxy = -> @defaultSession.resolveProxy.apply @defaultSession, arguments app.resolveProxy = -> @defaultSession.resolveProxy.apply @defaultSession, arguments
app.on 'activate', (event, hasVisibleWindows) -> @emit 'activate-with-no-open-windows' if not hasVisibleWindows app.on 'activate', (event, hasVisibleWindows) -> @emit 'activate-with-no-open-windows' if not hasVisibleWindows
# Session wrapper. # Wrappers for native classes.
sessionBindings._setWrapSession wrapSession sessionBindings._setWrapSession wrapSession
process.once 'exit', sessionBindings._clearWrapSession
downloadItemBindings._setWrapDownloadItem wrapDownloadItem downloadItemBindings._setWrapDownloadItem wrapDownloadItem
process.once 'exit', downloadItemBindings._clearWrapDownloadItem
# Only one App object pemitted. # Only one App object pemitted.
module.exports = app module.exports = app

View file

@ -112,7 +112,6 @@ wrapWebContents = (webContents) ->
@_printToPDF printingSetting, callback @_printToPDF printingSetting, callback
binding._setWrapWebContents wrapWebContents binding._setWrapWebContents wrapWebContents
process.once 'exit', binding._clearWrapWebContents
module.exports.create = (options={}) -> module.exports.create = (options={}) ->
binding.create(options) binding.create(options)

View file

@ -30,6 +30,7 @@ AtomBrowserMainParts* AtomBrowserMainParts::self_ = NULL;
AtomBrowserMainParts::AtomBrowserMainParts() AtomBrowserMainParts::AtomBrowserMainParts()
: fake_browser_process_(new BrowserProcess), : fake_browser_process_(new BrowserProcess),
exit_code_(nullptr),
browser_(new Browser), browser_(new Browser),
node_bindings_(NodeBindings::Create(true)), node_bindings_(NodeBindings::Create(true)),
atom_bindings_(new AtomBindings), atom_bindings_(new AtomBindings),
@ -47,6 +48,14 @@ AtomBrowserMainParts* AtomBrowserMainParts::Get() {
return self_; return self_;
} }
bool AtomBrowserMainParts::SetExitCode(int code) {
if (!exit_code_)
return false;
*exit_code_ = code;
return true;
}
void AtomBrowserMainParts::RegisterDestructionCallback( void AtomBrowserMainParts::RegisterDestructionCallback(
const base::Closure& callback) { const base::Closure& callback) {
destruction_callbacks_.push_back(callback); destruction_callbacks_.push_back(callback);
@ -118,6 +127,11 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() {
#endif #endif
} }
bool AtomBrowserMainParts::MainMessageLoopRun(int* result_code) {
exit_code_ = result_code;
return brightray::BrowserMainParts::MainMessageLoopRun(result_code);
}
void AtomBrowserMainParts::PostMainMessageLoopStart() { void AtomBrowserMainParts::PostMainMessageLoopStart() {
brightray::BrowserMainParts::PostMainMessageLoopStart(); brightray::BrowserMainParts::PostMainMessageLoopStart();
#if defined(OS_POSIX) #if defined(OS_POSIX)
@ -128,11 +142,23 @@ void AtomBrowserMainParts::PostMainMessageLoopStart() {
void AtomBrowserMainParts::PostMainMessageLoopRun() { void AtomBrowserMainParts::PostMainMessageLoopRun() {
brightray::BrowserMainParts::PostMainMessageLoopRun(); brightray::BrowserMainParts::PostMainMessageLoopRun();
#if defined(OS_MACOSX)
FreeAppDelegate();
#endif
// Make sure destruction callbacks are called before message loop is // Make sure destruction callbacks are called before message loop is
// destroyed, otherwise some objects that need to be deleted on IO thread // destroyed, otherwise some objects that need to be deleted on IO thread
// won't be freed. // won't be freed.
for (const auto& callback : destruction_callbacks_) for (const auto& callback : destruction_callbacks_)
callback.Run(); callback.Run();
// Destroy JavaScript environment immediately after running destruction
// callbacks.
gc_timer_.Stop();
node_debugger_.reset();
atom_bindings_.reset();
node_bindings_.reset();
js_env_.reset();
} }
} // namespace atom } // namespace atom

View file

@ -31,6 +31,9 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
static AtomBrowserMainParts* Get(); static AtomBrowserMainParts* Get();
// Sets the exit code, will fail if the the message loop is not ready.
bool SetExitCode(int code);
// Register a callback that should be destroyed before JavaScript environment // Register a callback that should be destroyed before JavaScript environment
// gets destroyed. // gets destroyed.
void RegisterDestructionCallback(const base::Closure& callback); void RegisterDestructionCallback(const base::Closure& callback);
@ -42,11 +45,11 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
void PreEarlyInitialization() override; void PreEarlyInitialization() override;
void PostEarlyInitialization() override; void PostEarlyInitialization() override;
void PreMainMessageLoopRun() override; void PreMainMessageLoopRun() override;
bool MainMessageLoopRun(int* result_code) override;
void PostMainMessageLoopStart() override; void PostMainMessageLoopStart() override;
void PostMainMessageLoopRun() override; void PostMainMessageLoopRun() override;
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
void PreMainMessageLoopStart() override; void PreMainMessageLoopStart() override;
void PostDestroyThreads() override;
#endif #endif
private: private:
@ -56,6 +59,10 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
void HandleShutdownSignals(); void HandleShutdownSignals();
#endif #endif
#if defined(OS_MACOSX)
void FreeAppDelegate();
#endif
// A fake BrowserProcess object that used to feed the source code from chrome. // A fake BrowserProcess object that used to feed the source code from chrome.
scoped_ptr<BrowserProcess> fake_browser_process_; scoped_ptr<BrowserProcess> fake_browser_process_;
@ -63,6 +70,9 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
// with a task runner that will post all work to main loop. // with a task runner that will post all work to main loop.
scoped_refptr<BridgeTaskRunner> bridge_task_runner_; scoped_refptr<BridgeTaskRunner> bridge_task_runner_;
// Pointer to exit code.
int* exit_code_;
scoped_ptr<Browser> browser_; scoped_ptr<Browser> browser_;
scoped_ptr<JavascriptEnvironment> js_env_; scoped_ptr<JavascriptEnvironment> js_env_;
scoped_ptr<NodeBindings> node_bindings_; scoped_ptr<NodeBindings> node_bindings_;

View file

@ -34,7 +34,7 @@ void AtomBrowserMainParts::PreMainMessageLoopStart() {
setObject:@"NO" forKey:@"NSTreatUnknownArgumentsAsOpen"]; setObject:@"NO" forKey:@"NSTreatUnknownArgumentsAsOpen"];
} }
void AtomBrowserMainParts::PostDestroyThreads() { void AtomBrowserMainParts::FreeAppDelegate() {
[[NSApp delegate] release]; [[NSApp delegate] release];
[NSApp setDelegate:nil]; [NSApp setDelegate:nil];
} }

View file

@ -7,6 +7,7 @@
#include <string> #include <string>
#include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/native_window.h"
#include "atom/browser/window_list.h" #include "atom/browser/window_list.h"
#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop.h"
#include "content/public/browser/client_certificate_delegate.h" #include "content/public/browser/client_certificate_delegate.h"
@ -45,6 +46,27 @@ void Browser::Quit() {
window_list->CloseAllWindows(); window_list->CloseAllWindows();
} }
void Browser::Exit(int code) {
if (!AtomBrowserMainParts::Get()->SetExitCode(code)) {
// Message loop is not ready, quit directly.
exit(code);
} else {
// Prepare to quit when all windows have been closed..
is_quiting_ = true;
// Must destroy windows before quitting, otherwise bad things can happen.
atom::WindowList* window_list = atom::WindowList::GetInstance();
if (window_list->size() == 0) {
NotifyAndShutdown();
} else {
// Unlike Quit(), we do not ask to close window, but destroy the window
// without asking.
for (NativeWindow* window : *window_list)
window->CloseContents(nullptr); // e.g. Destroy()
}
}
}
void Browser::Shutdown() { void Browser::Shutdown() {
if (is_shutdown_) if (is_shutdown_)
return; return;

View file

@ -42,6 +42,9 @@ class Browser : public WindowListObserver {
// Try to close all windows and quit the application. // Try to close all windows and quit the application.
void Quit(); void Quit();
// Exit the application immediately and set exit code.
void Exit(int code);
// Cleanup everything and shutdown the application gracefully. // Cleanup everything and shutdown the application gracefully.
void Shutdown(); void Shutdown();

View file

@ -53,6 +53,9 @@ app = require 'app'
app.on 'quit', -> app.on 'quit', ->
process.emit 'exit' process.emit 'exit'
# Map process.exit to app.exit, which quits gracefully.
process.exit = app.exit
# Load the RPC server. # Load the RPC server.
require './rpc-server' require './rpc-server'

View file

@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "atom/browser/native_window_views.h" #include "atom/browser/native_window_views.h"
#include "content/public/browser/browser_accessibility_state.h"
namespace atom { namespace atom {
@ -83,6 +84,20 @@ bool NativeWindowViews::PreHandleMSG(
NotifyWindowMessage(message, w_param, l_param); NotifyWindowMessage(message, w_param, l_param);
switch (message) { switch (message) {
// Screen readers send WM_GETOBJECT in order to get the accessibility
// object, so take this opportunity to push Chromium into accessible
// mode if it isn't already, always say we didn't handle the message
// because we still want Chromium to handle returning the actual
// accessibility object.
case WM_GETOBJECT: {
const DWORD obj_id = static_cast<DWORD>(l_param);
if (obj_id == OBJID_CLIENT) {
const auto axState = content::BrowserAccessibilityState::GetInstance();
if (axState && !axState->IsAccessibleBrowser())
axState->OnScreenReaderDetected();
}
return false;
}
case WM_COMMAND: case WM_COMMAND:
// Handle thumbar button click message. // Handle thumbar button click message.
if (HIWORD(w_param) == THBN_CLICKED) if (HIWORD(w_param) == THBN_CLICKED)

View file

@ -17,9 +17,9 @@
<key>CFBundleIconFile</key> <key>CFBundleIconFile</key>
<string>atom.icns</string> <string>atom.icns</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>0.34.2</string> <string>0.34.3</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0.34.2</string> <string>0.34.3</string>
<key>LSApplicationCategoryType</key> <key>LSApplicationCategoryType</key>
<string>public.app-category.developer-tools</string> <string>public.app-category.developer-tools</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>

View file

@ -56,8 +56,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,34,2,0 FILEVERSION 0,34,3,0
PRODUCTVERSION 0,34,2,0 PRODUCTVERSION 0,34,3,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -74,12 +74,12 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "GitHub, Inc." VALUE "CompanyName", "GitHub, Inc."
VALUE "FileDescription", "Electron" VALUE "FileDescription", "Electron"
VALUE "FileVersion", "0.34.2" VALUE "FileVersion", "0.34.3"
VALUE "InternalName", "electron.exe" VALUE "InternalName", "electron.exe"
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved." VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
VALUE "OriginalFilename", "electron.exe" VALUE "OriginalFilename", "electron.exe"
VALUE "ProductName", "Electron" VALUE "ProductName", "Electron"
VALUE "ProductVersion", "0.34.2" VALUE "ProductVersion", "0.34.3"
VALUE "SquirrelAwareVersion", "1" VALUE "SquirrelAwareVersion", "1"
END END
END END

View file

@ -113,7 +113,7 @@ void NotifyIcon::SetToolTip(const std::string& tool_tip) {
NOTIFYICONDATA icon_data; NOTIFYICONDATA icon_data;
InitIconData(&icon_data); InitIconData(&icon_data);
icon_data.uFlags |= NIF_TIP; icon_data.uFlags |= NIF_TIP;
wcscpy_s(icon_data.szTip, base::UTF8ToUTF16(tool_tip).c_str()); wcsncpy_s(icon_data.szTip, base::UTF8ToUTF16(tool_tip).c_str(), _TRUNCATE);
BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data); BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data);
if (!result) if (!result)
LOG(WARNING) << "Unable to set tooltip for status tray icon"; LOG(WARNING) << "Unable to set tooltip for status tray icon";
@ -126,8 +126,8 @@ void NotifyIcon::DisplayBalloon(const gfx::Image& icon,
InitIconData(&icon_data); InitIconData(&icon_data);
icon_data.uFlags |= NIF_INFO; icon_data.uFlags |= NIF_INFO;
icon_data.dwInfoFlags = NIIF_INFO; icon_data.dwInfoFlags = NIIF_INFO;
wcscpy_s(icon_data.szInfoTitle, title.c_str()); wcsncpy_s(icon_data.szInfoTitle, title.c_str(), _TRUNCATE);
wcscpy_s(icon_data.szInfo, contents.c_str()); wcsncpy_s(icon_data.szInfo, contents.c_str(), _TRUNCATE);
icon_data.uTimeout = 0; icon_data.uTimeout = 0;
base::win::Version win_version = base::win::GetVersion(); base::win::Version win_version = base::win::GetVersion();

View file

@ -97,7 +97,8 @@ bool TaskbarHost::SetThumbarButtons(
// Set tooltip. // Set tooltip.
if (!button.tooltip.empty()) { if (!button.tooltip.empty()) {
thumb_button.dwMask |= THB_TOOLTIP; thumb_button.dwMask |= THB_TOOLTIP;
wcscpy_s(thumb_button.szTip, base::UTF8ToUTF16(button.tooltip).c_str()); wcsncpy_s(thumb_button.szTip, base::UTF8ToUTF16(button.tooltip).c_str(),
_TRUNCATE);
} }
// Save callback. // Save callback.

View file

@ -1,5 +1 @@
module.exports = process.atomBinding 'shell' module.exports = process.atomBinding 'shell'
if process.platform is 'win32' and process.type is 'renderer'
module.exports.showItemInFolder = (item) ->
require('remote').require('shell').showItemInFolder item

View file

@ -7,7 +7,7 @@
#define ATOM_MAJOR_VERSION 0 #define ATOM_MAJOR_VERSION 0
#define ATOM_MINOR_VERSION 34 #define ATOM_MINOR_VERSION 34
#define ATOM_PATCH_VERSION 2 #define ATOM_PATCH_VERSION 3
#define ATOM_VERSION_IS_RELEASE 1 #define ATOM_VERSION_IS_RELEASE 1

View file

@ -80,7 +80,7 @@ struct ExceptionHandlerRecord {
unsigned char thunk[12]; unsigned char thunk[12];
}; };
void RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes) { bool RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes) {
ExceptionHandlerRecord* record = ExceptionHandlerRecord* record =
reinterpret_cast<ExceptionHandlerRecord*>(start); reinterpret_cast<ExceptionHandlerRecord*>(start);
@ -117,17 +117,17 @@ void RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes) {
// Protect reserved page against modifications. // Protect reserved page against modifications.
DWORD old_protect; DWORD old_protect;
CHECK(VirtualProtect( return VirtualProtect(start, sizeof(ExceptionHandlerRecord),
start, sizeof(ExceptionHandlerRecord), PAGE_EXECUTE_READ, &old_protect)); PAGE_EXECUTE_READ, &old_protect) &&
CHECK(RtlAddFunctionTable( RtlAddFunctionTable(&record->runtime_function, 1,
&record->runtime_function, 1, reinterpret_cast<DWORD64>(start))); reinterpret_cast<DWORD64>(start));
} }
void UnregisterNonABICompliantCodeRange(void* start) { void UnregisterNonABICompliantCodeRange(void* start) {
ExceptionHandlerRecord* record = ExceptionHandlerRecord* record =
reinterpret_cast<ExceptionHandlerRecord*>(start); reinterpret_cast<ExceptionHandlerRecord*>(start);
CHECK(RtlDeleteFunctionTable(&record->runtime_function)); RtlDeleteFunctionTable(&record->runtime_function);
} }
#endif // _WIN64 #endif // _WIN64
@ -184,6 +184,7 @@ void CrashReporterWin::InitBreakpad(const std::string& product_name,
LOG(ERROR) << "Cannot initialize out-of-process crash handler"; LOG(ERROR) << "Cannot initialize out-of-process crash handler";
#ifdef _WIN64 #ifdef _WIN64
bool registered = false;
// Hook up V8 to breakpad. // Hook up V8 to breakpad.
{ {
// gin::Debug::SetCodeRangeCreatedCallback only runs the callback when // gin::Debug::SetCodeRangeCreatedCallback only runs the callback when
@ -192,9 +193,10 @@ void CrashReporterWin::InitBreakpad(const std::string& product_name,
size_t size = 0; size_t size = 0;
v8::Isolate::GetCurrent()->GetCodeRange(&code_range, &size); v8::Isolate::GetCurrent()->GetCodeRange(&code_range, &size);
if (code_range && size) if (code_range && size)
RegisterNonABICompliantCodeRange(code_range, size); registered = RegisterNonABICompliantCodeRange(code_range, size);
} }
gin::Debug::SetCodeRangeDeletedCallback(UnregisterNonABICompliantCodeRange); if (registered)
gin::Debug::SetCodeRangeDeletedCallback(UnregisterNonABICompliantCodeRange);
#endif #endif
} }

View file

@ -4,6 +4,8 @@
#include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/callback.h"
#include "atom/browser/atom_browser_main_parts.h"
namespace mate { namespace mate {
namespace internal { namespace internal {
@ -54,6 +56,33 @@ v8::Local<v8::Value> BindFunctionWith(v8::Isolate* isolate,
} // namespace } // namespace
SafeV8Function::SafeV8Function(v8::Isolate* isolate, v8::Local<v8::Value> value)
: v8_function_(new RefCountedPersistent<v8::Function>(isolate, value)),
weak_factory_(this) {
Init();
}
SafeV8Function::SafeV8Function(const SafeV8Function& other)
: v8_function_(other.v8_function_),
weak_factory_(this) {
Init();
}
v8::Local<v8::Function> SafeV8Function::NewHandle() const {
return v8_function_->NewHandle();
}
void SafeV8Function::Init() {
if (Locker::IsBrowserProcess() && atom::AtomBrowserMainParts::Get())
atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback(
base::Bind(&SafeV8Function::FreeHandle, weak_factory_.GetWeakPtr()));
}
void SafeV8Function::FreeHandle() {
Locker locker(v8_function_->isolate());
v8_function_ = nullptr;
}
v8::Local<v8::Value> CreateFunctionFromTranslater( v8::Local<v8::Value> CreateFunctionFromTranslater(
v8::Isolate* isolate, const Translater& translater) { v8::Isolate* isolate, const Translater& translater) {
// The FunctionTemplate is cached. // The FunctionTemplate is cached.

View file

@ -10,6 +10,7 @@
#include "atom/common/api/locker.h" #include "atom/common/api/locker.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/callback.h" #include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "native_mate/function_template.h" #include "native_mate/function_template.h"
#include "native_mate/scoped_persistent.h" #include "native_mate/scoped_persistent.h"
#include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h" #include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h"
@ -18,7 +19,24 @@ namespace mate {
namespace internal { namespace internal {
typedef scoped_refptr<RefCountedPersistent<v8::Function> > SafeV8Function; // Manages the V8 function with RAII, and automatically cleans the handle when
// JavaScript context is destroyed, even when the class is not destroyed.
class SafeV8Function {
public:
SafeV8Function(v8::Isolate* isolate, v8::Local<v8::Value> value);
SafeV8Function(const SafeV8Function& other);
bool is_alive() const { return v8_function_.get(); }
v8::Local<v8::Function> NewHandle() const;
private:
void Init();
void FreeHandle();
scoped_refptr<RefCountedPersistent<v8::Function>> v8_function_;
base::WeakPtrFactory<SafeV8Function> weak_factory_;
};
// Helper to invoke a V8 function with C++ parameters. // Helper to invoke a V8 function with C++ parameters.
template <typename Sig> template <typename Sig>
@ -26,14 +44,17 @@ struct V8FunctionInvoker {};
template <typename... ArgTypes> template <typename... ArgTypes>
struct V8FunctionInvoker<v8::Local<v8::Value>(ArgTypes...)> { struct V8FunctionInvoker<v8::Local<v8::Value>(ArgTypes...)> {
static v8::Local<v8::Value> Go(v8::Isolate* isolate, SafeV8Function function, static v8::Local<v8::Value> Go(v8::Isolate* isolate,
const SafeV8Function& function,
ArgTypes... raw) { ArgTypes... raw) {
Locker locker(isolate); Locker locker(isolate);
v8::EscapableHandleScope handle_scope(isolate); v8::EscapableHandleScope handle_scope(isolate);
if (!function.is_alive())
return v8::Null(isolate);
scoped_ptr<blink::WebScopedRunV8Script> script_scope( scoped_ptr<blink::WebScopedRunV8Script> script_scope(
Locker::IsBrowserProcess() ? Locker::IsBrowserProcess() ?
nullptr : new blink::WebScopedRunV8Script(isolate)); nullptr : new blink::WebScopedRunV8Script(isolate));
v8::Local<v8::Function> holder = function->NewHandle(); v8::Local<v8::Function> holder = function.NewHandle();
v8::Local<v8::Context> context = holder->CreationContext(); v8::Local<v8::Context> context = holder->CreationContext();
v8::Context::Scope context_scope(context); v8::Context::Scope context_scope(context);
std::vector<v8::Local<v8::Value>> args = { ConvertToV8(isolate, raw)... }; std::vector<v8::Local<v8::Value>> args = { ConvertToV8(isolate, raw)... };
@ -44,14 +65,17 @@ struct V8FunctionInvoker<v8::Local<v8::Value>(ArgTypes...)> {
template <typename... ArgTypes> template <typename... ArgTypes>
struct V8FunctionInvoker<void(ArgTypes...)> { struct V8FunctionInvoker<void(ArgTypes...)> {
static void Go(v8::Isolate* isolate, SafeV8Function function, static void Go(v8::Isolate* isolate,
const SafeV8Function& function,
ArgTypes... raw) { ArgTypes... raw) {
Locker locker(isolate); Locker locker(isolate);
v8::HandleScope handle_scope(isolate); v8::HandleScope handle_scope(isolate);
if (!function.is_alive())
return;
scoped_ptr<blink::WebScopedRunV8Script> script_scope( scoped_ptr<blink::WebScopedRunV8Script> script_scope(
Locker::IsBrowserProcess() ? Locker::IsBrowserProcess() ?
nullptr : new blink::WebScopedRunV8Script(isolate)); nullptr : new blink::WebScopedRunV8Script(isolate));
v8::Local<v8::Function> holder = function->NewHandle(); v8::Local<v8::Function> holder = function.NewHandle();
v8::Local<v8::Context> context = holder->CreationContext(); v8::Local<v8::Context> context = holder->CreationContext();
v8::Context::Scope context_scope(context); v8::Context::Scope context_scope(context);
std::vector<v8::Local<v8::Value>> args = { ConvertToV8(isolate, raw)... }; std::vector<v8::Local<v8::Value>> args = { ConvertToV8(isolate, raw)... };
@ -61,17 +85,20 @@ struct V8FunctionInvoker<void(ArgTypes...)> {
template <typename ReturnType, typename... ArgTypes> template <typename ReturnType, typename... ArgTypes>
struct V8FunctionInvoker<ReturnType(ArgTypes...)> { struct V8FunctionInvoker<ReturnType(ArgTypes...)> {
static ReturnType Go(v8::Isolate* isolate, SafeV8Function function, static ReturnType Go(v8::Isolate* isolate,
const SafeV8Function& function,
ArgTypes... raw) { ArgTypes... raw) {
Locker locker(isolate); Locker locker(isolate);
v8::HandleScope handle_scope(isolate); v8::HandleScope handle_scope(isolate);
ReturnType ret = ReturnType();
if (!function.is_alive())
return ret;
scoped_ptr<blink::WebScopedRunV8Script> script_scope( scoped_ptr<blink::WebScopedRunV8Script> script_scope(
Locker::IsBrowserProcess() ? Locker::IsBrowserProcess() ?
nullptr : new blink::WebScopedRunV8Script(isolate)); nullptr : new blink::WebScopedRunV8Script(isolate));
v8::Local<v8::Function> holder = function->NewHandle(); v8::Local<v8::Function> holder = function.NewHandle();
v8::Local<v8::Context> context = holder->CreationContext(); v8::Local<v8::Context> context = holder->CreationContext();
v8::Context::Scope context_scope(context); v8::Context::Scope context_scope(context);
ReturnType ret = ReturnType();
std::vector<v8::Local<v8::Value>> args = { ConvertToV8(isolate, raw)... }; std::vector<v8::Local<v8::Value>> args = { ConvertToV8(isolate, raw)... };
v8::Local<v8::Value> result; v8::Local<v8::Value> result;
auto maybe_result = auto maybe_result =
@ -119,9 +146,8 @@ struct Converter<base::Callback<Sig>> {
if (!val->IsFunction()) if (!val->IsFunction())
return false; return false;
internal::SafeV8Function function( *out = base::Bind(&internal::V8FunctionInvoker<Sig>::Go,
new RefCountedPersistent<v8::Function>(isolate, val)); isolate, internal::SafeV8Function(isolate, val));
*out = base::Bind(&internal::V8FunctionInvoker<Sig>::Go, isolate, function);
return true; return true;
} }
}; };

View file

@ -14,6 +14,7 @@
#include "atom/common/node_includes.h" #include "atom/common/node_includes.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/base_paths.h" #include "base/base_paths.h"
#include "base/environment.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop.h"
#include "base/path_service.h" #include "base/path_service.h"
@ -141,6 +142,14 @@ void NodeBindings::Initialize() {
// Init node. // Init node.
// (we assume node::Init would not modify the parameters under embedded mode). // (we assume node::Init would not modify the parameters under embedded mode).
node::Init(nullptr, nullptr, nullptr, nullptr); node::Init(nullptr, nullptr, nullptr, nullptr);
#if defined(OS_WIN)
// uv_init overrides error mode to suppress the default crash dialog, bring
// it back if user wants to show it.
scoped_ptr<base::Environment> env(base::Environment::Create());
if (env->HasVar("ELECTRON_DEFAULT_ERROR_MODE"))
SetErrorMode(0);
#endif
} }
node::Environment* NodeBindings::CreateEnvironment( node::Environment* NodeBindings::CreateEnvironment(

View file

@ -5,7 +5,9 @@
#include "atom/common/platform_util.h" #include "atom/common/platform_util.h"
#include <windows.h> #include <windows.h>
#include <atlbase.h>
#include <commdlg.h> #include <commdlg.h>
#include <comdef.h>
#include <dwmapi.h> #include <dwmapi.h>
#include <shellapi.h> #include <shellapi.h>
#include <shlobj.h> #include <shlobj.h>
@ -19,6 +21,7 @@
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/win/registry.h" #include "base/win/registry.h"
#include "base/win/scoped_co_mem.h" #include "base/win/scoped_co_mem.h"
#include "base/win/scoped_com_initializer.h"
#include "base/win/scoped_comptr.h" #include "base/win/scoped_comptr.h"
#include "base/win/windows_version.h" #include "base/win/windows_version.h"
#include "url/gurl.h" #include "url/gurl.h"
@ -42,11 +45,168 @@ bool ValidateShellCommandForScheme(const std::string& scheme) {
return true; return true;
} }
// Required COM implementation of IFileOperationProgressSink so we can
// precheck files before deletion to make sure they can be move to the
// Recycle Bin.
class DeleteFileProgressSink : public IFileOperationProgressSink {
public:
DeleteFileProgressSink();
private:
ULONG STDMETHODCALLTYPE AddRef(void);
ULONG STDMETHODCALLTYPE Release(void);
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID* ppvObj);
HRESULT STDMETHODCALLTYPE StartOperations(void);
HRESULT STDMETHODCALLTYPE FinishOperations(HRESULT);
HRESULT STDMETHODCALLTYPE PreRenameItem(
DWORD, IShellItem*, LPCWSTR);
HRESULT STDMETHODCALLTYPE PostRenameItem(
DWORD, IShellItem*, LPCWSTR, HRESULT, IShellItem*);
HRESULT STDMETHODCALLTYPE PreMoveItem(
DWORD, IShellItem*, IShellItem*, LPCWSTR);
HRESULT STDMETHODCALLTYPE PostMoveItem(
DWORD, IShellItem*, IShellItem*, LPCWSTR, HRESULT, IShellItem*);
HRESULT STDMETHODCALLTYPE PreCopyItem(
DWORD, IShellItem*, IShellItem*, LPCWSTR);
HRESULT STDMETHODCALLTYPE PostCopyItem(
DWORD, IShellItem*, IShellItem*, LPCWSTR, HRESULT, IShellItem*);
HRESULT STDMETHODCALLTYPE PreDeleteItem(DWORD, IShellItem*);
HRESULT STDMETHODCALLTYPE PostDeleteItem(
DWORD, IShellItem*, HRESULT, IShellItem*);
HRESULT STDMETHODCALLTYPE PreNewItem(
DWORD, IShellItem*, LPCWSTR);
HRESULT STDMETHODCALLTYPE PostNewItem(
DWORD, IShellItem*, LPCWSTR, LPCWSTR, DWORD, HRESULT, IShellItem*);
HRESULT STDMETHODCALLTYPE UpdateProgress(UINT, UINT);
HRESULT STDMETHODCALLTYPE ResetTimer(void);
HRESULT STDMETHODCALLTYPE PauseTimer(void);
HRESULT STDMETHODCALLTYPE ResumeTimer(void);
ULONG m_cRef;
};
DeleteFileProgressSink::DeleteFileProgressSink() {
m_cRef = 0;
}
HRESULT DeleteFileProgressSink::PreDeleteItem(DWORD dwFlags, IShellItem*) {
if (!(dwFlags & TSF_DELETE_RECYCLE_IF_POSSIBLE)) {
// TSF_DELETE_RECYCLE_IF_POSSIBLE will not be set for items that cannot be
// recycled. In this case, we abort the delete operation. This bubbles
// up and stops the Delete in IFileOperation.
return E_ABORT;
}
// Returns S_OK if successful, or an error value otherwise. In the case of an
// error value, the delete operation and all subsequent operations pending
// from the call to IFileOperation are canceled.
return S_OK;
}
HRESULT DeleteFileProgressSink::QueryInterface(REFIID riid, LPVOID* ppvObj) {
// Always set out parameter to NULL, validating it first.
if (!ppvObj)
return E_INVALIDARG;
*ppvObj = nullptr;
if (riid == IID_IUnknown || riid == IID_IFileOperationProgressSink) {
// Increment the reference count and return the pointer.
*ppvObj = reinterpret_cast<IUnknown*>(this);
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
ULONG DeleteFileProgressSink::AddRef() {
InterlockedIncrement(&m_cRef);
return m_cRef;
}
ULONG DeleteFileProgressSink::Release() {
// Decrement the object's internal counter.
ULONG ulRefCount = InterlockedDecrement(&m_cRef);
if (0 == m_cRef) {
delete this;
}
return ulRefCount;
}
HRESULT DeleteFileProgressSink::StartOperations() {
return S_OK;
}
HRESULT DeleteFileProgressSink::FinishOperations(HRESULT) {
return S_OK;
}
HRESULT DeleteFileProgressSink::PreRenameItem(DWORD, IShellItem*, LPCWSTR) {
return S_OK;
}
HRESULT DeleteFileProgressSink::PostRenameItem(
DWORD, IShellItem*, __RPC__in_string LPCWSTR, HRESULT, IShellItem*) {
return E_NOTIMPL;
}
HRESULT DeleteFileProgressSink::PreMoveItem(
DWORD, IShellItem*, IShellItem*, LPCWSTR) {
return E_NOTIMPL;
}
HRESULT DeleteFileProgressSink::PostMoveItem(
DWORD, IShellItem*, IShellItem*, LPCWSTR, HRESULT, IShellItem*) {
return E_NOTIMPL;
}
HRESULT DeleteFileProgressSink::PreCopyItem(
DWORD, IShellItem*, IShellItem*, LPCWSTR) {
return E_NOTIMPL;
}
HRESULT DeleteFileProgressSink::PostCopyItem(
DWORD, IShellItem*, IShellItem*, LPCWSTR, HRESULT, IShellItem*) {
return E_NOTIMPL;
}
HRESULT DeleteFileProgressSink::PostDeleteItem(
DWORD, IShellItem*, HRESULT, IShellItem*) {
return S_OK;
}
HRESULT DeleteFileProgressSink::PreNewItem(
DWORD dwFlags, IShellItem*, LPCWSTR) {
return E_NOTIMPL;
}
HRESULT DeleteFileProgressSink::PostNewItem(
DWORD, IShellItem*, LPCWSTR, LPCWSTR, DWORD, HRESULT, IShellItem*) {
return E_NOTIMPL;
}
HRESULT DeleteFileProgressSink::UpdateProgress(UINT, UINT) {
return S_OK;
}
HRESULT DeleteFileProgressSink::ResetTimer() {
return S_OK;
}
HRESULT DeleteFileProgressSink::PauseTimer() {
return S_OK;
}
HRESULT DeleteFileProgressSink::ResumeTimer() {
return S_OK;
}
} // namespace } // namespace
namespace platform_util { namespace platform_util {
void ShowItemInFolder(const base::FilePath& full_path) { void ShowItemInFolder(const base::FilePath& full_path) {
base::win::ScopedCOMInitializer com_initializer;
if (!com_initializer.succeeded())
return;
base::FilePath dir = full_path.DirName().AsEndingWithSeparator(); base::FilePath dir = full_path.DirName().AsEndingWithSeparator();
// ParseDisplayName will fail if the directory is "C:", it must be "C:\\". // ParseDisplayName will fail if the directory is "C:", it must be "C:\\".
if (dir.empty()) if (dir.empty())
@ -170,32 +330,40 @@ bool OpenExternal(const GURL& url) {
} }
bool MoveItemToTrash(const base::FilePath& path) { bool MoveItemToTrash(const base::FilePath& path) {
// SHFILEOPSTRUCT wants the path to be terminated with two NULLs, base::win::ScopedCOMInitializer com_initializer;
// so we have to use wcscpy because wcscpy_s writes non-NULLs if (!com_initializer.succeeded())
// into the rest of the buffer.
wchar_t double_terminated_path[MAX_PATH + 1] = {0};
#pragma warning(suppress:4996) // don't complain about wcscpy deprecation
wcscpy(double_terminated_path, path.value().c_str());
SHFILEOPSTRUCT file_operation = {0};
file_operation.wFunc = FO_DELETE;
file_operation.pFrom = double_terminated_path;
file_operation.fFlags = FOF_ALLOWUNDO | FOF_SILENT | FOF_NOCONFIRMATION;
int err = SHFileOperation(&file_operation);
// Since we're passing flags to the operation telling it to be silent,
// it's possible for the operation to be aborted/cancelled without err
// being set (although MSDN doesn't give any scenarios for how this can
// happen). See MSDN for SHFileOperation and SHFILEOPTSTRUCT.
if (file_operation.fAnyOperationsAborted)
return false; return false;
// Some versions of Windows return ERROR_FILE_NOT_FOUND (0x2) when deleting base::win::ScopedComPtr<IFileOperation> pfo;
// an empty directory and some return 0x402 when they should be returning if (FAILED(pfo.CreateInstance(CLSID_FileOperation)))
// ERROR_FILE_NOT_FOUND. MSDN says Vista and up won't return 0x402. Windows 7 return false;
// can return DE_INVALIDFILES (0x7C) for nonexistent directories.
return (err == 0 || err == ERROR_FILE_NOT_FOUND || err == 0x402 || // Elevation prompt enabled for UAC protected files. This overrides the
err == 0x7C); // SILENT, NO_UI and NOERRORUI flags.
if (FAILED(pfo->SetOperationFlags(FOF_NO_UI |
FOF_ALLOWUNDO |
FOF_NOERRORUI |
FOF_SILENT |
FOFX_SHOWELEVATIONPROMPT |
FOFX_RECYCLEONDELETE)))
return false;
// Create an IShellItem from the supplied source path.
base::win::ScopedComPtr<IShellItem> delete_item;
if (FAILED(SHCreateItemFromParsingName(path.value().c_str(),
NULL,
IID_PPV_ARGS(delete_item.Receive()))))
return false;
base::win::ScopedComPtr<IFileOperationProgressSink> delete_sink(
new DeleteFileProgressSink);
if (!delete_sink)
return false;
// Processes the queued command DeleteItem. This will trigger
// the DeleteFileProgressSink to check for Recycle Bin.
return SUCCEEDED(pfo->DeleteItem(delete_item.get(), delete_sink.get())) &&
SUCCEEDED(pfo->PerformOperations());
} }
void Beep() { void Beep() {

View file

@ -208,6 +208,15 @@ This method guarantees that all `beforeunload` and `unload` event handlers are
correctly executed. It is possible that a window cancels the quitting by correctly executed. It is possible that a window cancels the quitting by
returning `false` in the `beforeunload` event handler. returning `false` in the `beforeunload` event handler.
### `app.exit(exitCode)`
* `exitCode` Integer
Exits immediately with `exitCode`.
All windows will be closed immediately without asking user and the `before-quit`
and `will-quit` events will not be emitted.
### `app.getAppPath()` ### `app.getAppPath()`
Returns the current application directory. Returns the current application directory.

View file

@ -8,6 +8,8 @@ the `BrowserWindow.addDevToolsExtension` API to load them. The loaded extensions
will be remembered so you don't need to call the API every time when creating will be remembered so you don't need to call the API every time when creating
a window. a window.
** NOTE: React DevTools does not work, follow the issue here https://github.com/atom/electron/issues/915 **
For example, to use the [React DevTools Extension](https://github.com/facebook/react-devtools) For example, to use the [React DevTools Extension](https://github.com/facebook/react-devtools)
, first you need to download its source code: , first you need to download its source code:

View file

@ -53,5 +53,6 @@ describe 'crash-reporter module', ->
protocol: 'file' protocol: 'file'
pathname: path.join fixtures, 'api', 'crash.html' pathname: path.join fixtures, 'api', 'crash.html'
search: "?port=#{port}" search: "?port=#{port}"
crashReporter.start {'submitUrl': 'http://127.0.0.1:' + port} if process.platform is 'darwin'
crashReporter.start {'submitUrl': 'http://127.0.0.1:' + port}
w.loadUrl url w.loadUrl url

2
vendor/brightray vendored

@ -1 +1 @@
Subproject commit 49a86c123f4cc43f4dca886ded612104a8a1fec6 Subproject commit 98b3eb04d85a8a70b8d9f29477437061c2e77a83