Merge remote-tracking branch 'refs/remotes/atom/master'
This commit is contained in:
commit
91c7043a1b
42 changed files with 484 additions and 123 deletions
|
@ -7,14 +7,14 @@
|
|||
:zap: *Formerly known as Atom Shell* :zap:
|
||||
|
||||
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
|
||||
editor](https://github.com/atom/atom).
|
||||
|
||||
Follow [@ElectronJS](https://twitter.com/electronjs) on Twitter for important
|
||||
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
|
||||
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
|
||||
locations:
|
||||
- [`electron`](http://discuss.atom.io/category/electron) category on the Atom
|
||||
- [`electron`](http://discuss.atom.io/c/electron) category on the Atom
|
||||
forums
|
||||
- `#atom-shell` channel on Freenode
|
||||
- [`Atom`](http://atom-slack.herokuapp.com/) channel on Slack
|
||||
|
|
2
atom.gyp
2
atom.gyp
|
@ -4,7 +4,7 @@
|
|||
'product_name%': 'Electron',
|
||||
'company_name%': 'GitHub, Inc',
|
||||
'company_abbr%': 'github',
|
||||
'version%': '0.34.2',
|
||||
'version%': '0.34.3',
|
||||
},
|
||||
'includes': [
|
||||
'filenames.gypi',
|
||||
|
|
|
@ -102,13 +102,6 @@ void AtomMainDelegate::PreSandboxStartup() {
|
|||
if (!IsBrowserProcess(command_line))
|
||||
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.
|
||||
command_line->AppendSwitch(switches::kNoSandbox);
|
||||
|
||||
|
|
|
@ -339,6 +339,7 @@ mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
|
|||
auto browser = base::Unretained(Browser::Get());
|
||||
return mate::ObjectTemplateBuilder(isolate)
|
||||
.SetMethod("quit", base::Bind(&Browser::Quit, browser))
|
||||
.SetMethod("exit", base::Bind(&Browser::Exit, browser))
|
||||
.SetMethod("focus", base::Bind(&Browser::Focus, browser))
|
||||
.SetMethod("getVersion", base::Bind(&Browser::GetVersion, browser))
|
||||
.SetMethod("setVersion", base::Bind(&Browser::SetVersion, browser))
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <map>
|
||||
|
||||
#include "atom/browser/atom_browser_main_parts.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/gurl_converter.h"
|
||||
|
@ -159,14 +160,6 @@ mate::ObjectTemplateBuilder DownloadItem::GetObjectTemplateBuilder(
|
|||
.SetMethod("setSavePath", &DownloadItem::SetSavePath);
|
||||
}
|
||||
|
||||
void SetWrapDownloadItem(const WrapDownloadItemCallback& callback) {
|
||||
g_wrap_download_item = callback;
|
||||
}
|
||||
|
||||
void ClearWrapDownloadItem() {
|
||||
g_wrap_download_item.Reset();
|
||||
}
|
||||
|
||||
// static
|
||||
mate::Handle<DownloadItem> DownloadItem::Create(
|
||||
v8::Isolate* isolate, content::DownloadItem* item) {
|
||||
|
@ -182,6 +175,18 @@ void* DownloadItem::UserDataKey() {
|
|||
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 atom
|
||||
|
@ -193,7 +198,6 @@ void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
|
|||
v8::Isolate* isolate = context->GetIsolate();
|
||||
mate::Dictionary dict(isolate, exports);
|
||||
dict.SetMethod("_setWrapDownloadItem", &atom::api::SetWrapDownloadItem);
|
||||
dict.SetMethod("_clearWrapDownloadItem", &atom::api::ClearWrapDownloadItem);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -23,6 +23,9 @@ GlobalShortcut::GlobalShortcut() {
|
|||
}
|
||||
|
||||
GlobalShortcut::~GlobalShortcut() {
|
||||
}
|
||||
|
||||
void GlobalShortcut::Destroy() {
|
||||
UnregisterAll();
|
||||
}
|
||||
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/api/trackable_object.h"
|
||||
#include "base/callback.h"
|
||||
#include "chrome/browser/extensions/global_shortcut_listener.h"
|
||||
#include "native_mate/wrappable.h"
|
||||
#include "native_mate/handle.h"
|
||||
#include "ui/base/accelerators/accelerator.h"
|
||||
|
||||
|
@ -19,13 +19,16 @@ namespace atom {
|
|||
namespace api {
|
||||
|
||||
class GlobalShortcut : public extensions::GlobalShortcutListener::Observer,
|
||||
public mate::Wrappable {
|
||||
public mate::TrackableObject<GlobalShortcut> {
|
||||
public:
|
||||
static mate::Handle<GlobalShortcut> Create(v8::Isolate* isolate);
|
||||
|
||||
protected:
|
||||
GlobalShortcut();
|
||||
virtual ~GlobalShortcut();
|
||||
~GlobalShortcut() override;
|
||||
|
||||
// mate::TrackableObject:
|
||||
void Destroy() override;
|
||||
|
||||
// mate::Wrappable implementations:
|
||||
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
||||
|
|
|
@ -27,6 +27,14 @@ Menu::Menu()
|
|||
Menu::~Menu() {
|
||||
}
|
||||
|
||||
void Menu::Destroy() {
|
||||
model_.reset();
|
||||
}
|
||||
|
||||
bool Menu::IsDestroyed() const {
|
||||
return !model_;
|
||||
}
|
||||
|
||||
void Menu::AfterInit(v8::Isolate* isolate) {
|
||||
mate::Dictionary wrappable(isolate, GetWrapper(isolate));
|
||||
mate::Dictionary delegate;
|
||||
|
|
|
@ -8,16 +8,16 @@
|
|||
#include <string>
|
||||
|
||||
#include "atom/browser/api/atom_api_window.h"
|
||||
#include "atom/browser/api/trackable_object.h"
|
||||
#include "atom/browser/ui/atom_menu_model.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "native_mate/wrappable.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
class Menu : public mate::Wrappable,
|
||||
class Menu : public mate::TrackableObject<Menu>,
|
||||
public AtomMenuModel::Delegate {
|
||||
public:
|
||||
static mate::Wrappable* Create();
|
||||
|
@ -37,9 +37,13 @@ class Menu : public mate::Wrappable,
|
|||
|
||||
protected:
|
||||
Menu();
|
||||
virtual ~Menu();
|
||||
~Menu() override;
|
||||
|
||||
// mate::TrackableObject:
|
||||
void Destroy() override;
|
||||
|
||||
// mate::Wrappable:
|
||||
bool IsDestroyed() const override;
|
||||
void AfterInit(v8::Isolate* isolate) override;
|
||||
|
||||
// ui::SimpleMenuModel::Delegate:
|
||||
|
|
|
@ -19,6 +19,7 @@ class MenuMac : public Menu {
|
|||
protected:
|
||||
MenuMac();
|
||||
|
||||
void Destroy() override;
|
||||
void Popup(Window* window) override;
|
||||
void PopupAt(Window* window, int x, int y) override;
|
||||
|
||||
|
|
|
@ -18,6 +18,11 @@ namespace api {
|
|||
MenuMac::MenuMac() {
|
||||
}
|
||||
|
||||
void MenuMac::Destroy() {
|
||||
menu_controller_.reset();
|
||||
Menu::Destroy();
|
||||
}
|
||||
|
||||
void MenuMac::Popup(Window* window) {
|
||||
NativeWindow* native_window = window->window();
|
||||
if (!native_window)
|
||||
|
|
|
@ -19,6 +19,9 @@ PowerMonitor::PowerMonitor() {
|
|||
}
|
||||
|
||||
PowerMonitor::~PowerMonitor() {
|
||||
}
|
||||
|
||||
void PowerMonitor::Destroy() {
|
||||
base::PowerMonitor::Get()->RemoveObserver(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#ifndef 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/power_monitor/power_observer.h"
|
||||
#include "native_mate/handle.h"
|
||||
|
@ -14,14 +14,17 @@ namespace atom {
|
|||
|
||||
namespace api {
|
||||
|
||||
class PowerMonitor : public mate::EventEmitter,
|
||||
class PowerMonitor : public mate::TrackableObject<PowerMonitor>,
|
||||
public base::PowerObserver {
|
||||
public:
|
||||
static v8::Local<v8::Value> Create(v8::Isolate* isolate);
|
||||
|
||||
protected:
|
||||
PowerMonitor();
|
||||
virtual ~PowerMonitor();
|
||||
~PowerMonitor() override;
|
||||
|
||||
// mate::TrackableObject:
|
||||
void Destroy() override;
|
||||
|
||||
// base::PowerObserver implementations:
|
||||
void OnPowerStateChange(bool on_battery_power) override;
|
||||
|
|
|
@ -45,6 +45,11 @@ PowerSaveBlocker::PowerSaveBlocker()
|
|||
PowerSaveBlocker::~PowerSaveBlocker() {
|
||||
}
|
||||
|
||||
void PowerSaveBlocker::Destroy() {
|
||||
power_save_blocker_types_.clear();
|
||||
power_save_blocker_.reset();
|
||||
}
|
||||
|
||||
void PowerSaveBlocker::UpdatePowerSaveBlocker() {
|
||||
if (power_save_blocker_types_.empty()) {
|
||||
power_save_blocker_.reset();
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
#include <map>
|
||||
|
||||
#include "atom/browser/api/trackable_object.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "content/public/browser/power_save_blocker.h"
|
||||
#include "native_mate/handle.h"
|
||||
#include "native_mate/wrappable.h"
|
||||
|
||||
namespace mate {
|
||||
class Dictionary;
|
||||
|
@ -20,13 +20,16 @@ namespace atom {
|
|||
|
||||
namespace api {
|
||||
|
||||
class PowerSaveBlocker : public mate::Wrappable {
|
||||
class PowerSaveBlocker : public mate::TrackableObject<PowerSaveBlocker> {
|
||||
public:
|
||||
static mate::Handle<PowerSaveBlocker> Create(v8::Isolate* isolate);
|
||||
|
||||
protected:
|
||||
PowerSaveBlocker();
|
||||
virtual ~PowerSaveBlocker();
|
||||
~PowerSaveBlocker() override;
|
||||
|
||||
// mate::TrackableObject:
|
||||
void Destroy() override;
|
||||
|
||||
// mate::Wrappable implementations:
|
||||
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
||||
|
@ -48,7 +51,6 @@ class PowerSaveBlocker : public mate::Wrappable {
|
|||
std::map<int, content::PowerSaveBlocker::PowerSaveBlockerType>;
|
||||
PowerSaveBlockerTypeMap power_save_blocker_types_;
|
||||
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(PowerSaveBlocker);
|
||||
};
|
||||
|
||||
|
|
|
@ -9,9 +9,10 @@
|
|||
|
||||
#include "atom/browser/api/atom_api_cookies.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/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/gurl_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()));
|
||||
}
|
||||
|
||||
void SetWrapSession(const WrapSessionCallback& callback) {
|
||||
g_wrap_session = callback;
|
||||
}
|
||||
|
||||
void ClearWrapSession() {
|
||||
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 atom
|
||||
|
@ -415,7 +420,6 @@ void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
|
|||
mate::Dictionary dict(isolate, exports);
|
||||
dict.SetMethod("fromPartition", &atom::api::Session::FromPartition);
|
||||
dict.SetMethod("_setWrapSession", &atom::api::SetWrapSession);
|
||||
dict.SetMethod("_clearWrapSession", &atom::api::ClearWrapSession);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#include <string>
|
||||
#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 "base/memory/scoped_ptr.h"
|
||||
|
||||
|
@ -29,7 +29,7 @@ namespace api {
|
|||
|
||||
class Menu;
|
||||
|
||||
class Tray : public mate::EventEmitter,
|
||||
class Tray : public mate::TrackableObject<Tray>,
|
||||
public TrayIconObserver {
|
||||
public:
|
||||
static mate::Wrappable* New(v8::Isolate* isolate, const gfx::Image& image);
|
||||
|
@ -39,7 +39,7 @@ class Tray : public mate::EventEmitter,
|
|||
|
||||
protected:
|
||||
explicit Tray(const gfx::Image& image);
|
||||
virtual ~Tray();
|
||||
~Tray() override;
|
||||
|
||||
// TrayIconObserver:
|
||||
void OnClicked(const gfx::Rect& bounds, int modifiers) override;
|
||||
|
@ -53,7 +53,9 @@ class Tray : public mate::EventEmitter,
|
|||
// mate::Wrappable:
|
||||
bool IsDestroyed() const override;
|
||||
|
||||
void Destroy();
|
||||
// mate::TrackableObject:
|
||||
void Destroy() override;
|
||||
|
||||
void SetImage(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);
|
||||
|
|
|
@ -1124,14 +1124,18 @@ mate::Handle<WebContents> WebContents::Create(
|
|||
return handle;
|
||||
}
|
||||
|
||||
void SetWrapWebContents(const WrapWebContentsCallback& callback) {
|
||||
g_wrap_web_contents = callback;
|
||||
}
|
||||
|
||||
void ClearWrapWebContents() {
|
||||
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 atom
|
||||
|
@ -1145,7 +1149,6 @@ void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
|
|||
mate::Dictionary dict(isolate, exports);
|
||||
dict.SetMethod("create", &atom::api::WebContents::Create);
|
||||
dict.SetMethod("_setWrapWebContents", &atom::api::SetWrapWebContents);
|
||||
dict.SetMethod("_clearWrapWebContents", &atom::api::ClearWrapWebContents);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -11,14 +11,14 @@ wrapSession = (session) ->
|
|||
# session is an Event Emitter.
|
||||
session.__proto__ = EventEmitter.prototype
|
||||
|
||||
wrapDownloadItem = (download_item) ->
|
||||
# download_item is an Event Emitter.
|
||||
download_item.__proto__ = EventEmitter.prototype
|
||||
wrapDownloadItem = (downloadItem) ->
|
||||
# downloadItem is an Event Emitter.
|
||||
downloadItem.__proto__ = EventEmitter.prototype
|
||||
# Be compatible with old APIs.
|
||||
download_item.url = download_item.getUrl()
|
||||
download_item.filename = download_item.getFilename()
|
||||
download_item.mimeType = download_item.getMimeType()
|
||||
download_item.hasUserGesture = download_item.hasUserGesture()
|
||||
downloadItem.url = downloadItem.getUrl()
|
||||
downloadItem.filename = downloadItem.getFilename()
|
||||
downloadItem.mimeType = downloadItem.getMimeType()
|
||||
downloadItem.hasUserGesture = downloadItem.hasUserGesture()
|
||||
|
||||
app.setApplicationMenu = (menu) ->
|
||||
require('menu').setApplicationMenu menu
|
||||
|
@ -50,19 +50,15 @@ app.getAppPath = ->
|
|||
# Be compatible with old API.
|
||||
app.once 'ready', -> @emit 'finish-launching'
|
||||
app.terminate = app.quit
|
||||
app.exit = process.exit
|
||||
app.getHomeDir = -> @getPath 'home'
|
||||
app.getDataPath = -> @getPath 'userData'
|
||||
app.setDataPath = (path) -> @setPath 'userData', path
|
||||
app.resolveProxy = -> @defaultSession.resolveProxy.apply @defaultSession, arguments
|
||||
app.on 'activate', (event, hasVisibleWindows) -> @emit 'activate-with-no-open-windows' if not hasVisibleWindows
|
||||
|
||||
# Session wrapper.
|
||||
# Wrappers for native classes.
|
||||
sessionBindings._setWrapSession wrapSession
|
||||
process.once 'exit', sessionBindings._clearWrapSession
|
||||
|
||||
downloadItemBindings._setWrapDownloadItem wrapDownloadItem
|
||||
process.once 'exit', downloadItemBindings._clearWrapDownloadItem
|
||||
|
||||
# Only one App object pemitted.
|
||||
module.exports = app
|
||||
|
|
|
@ -112,7 +112,6 @@ wrapWebContents = (webContents) ->
|
|||
@_printToPDF printingSetting, callback
|
||||
|
||||
binding._setWrapWebContents wrapWebContents
|
||||
process.once 'exit', binding._clearWrapWebContents
|
||||
|
||||
module.exports.create = (options={}) ->
|
||||
binding.create(options)
|
||||
|
|
|
@ -30,6 +30,7 @@ AtomBrowserMainParts* AtomBrowserMainParts::self_ = NULL;
|
|||
|
||||
AtomBrowserMainParts::AtomBrowserMainParts()
|
||||
: fake_browser_process_(new BrowserProcess),
|
||||
exit_code_(nullptr),
|
||||
browser_(new Browser),
|
||||
node_bindings_(NodeBindings::Create(true)),
|
||||
atom_bindings_(new AtomBindings),
|
||||
|
@ -47,6 +48,14 @@ AtomBrowserMainParts* AtomBrowserMainParts::Get() {
|
|||
return self_;
|
||||
}
|
||||
|
||||
bool AtomBrowserMainParts::SetExitCode(int code) {
|
||||
if (!exit_code_)
|
||||
return false;
|
||||
|
||||
*exit_code_ = code;
|
||||
return true;
|
||||
}
|
||||
|
||||
void AtomBrowserMainParts::RegisterDestructionCallback(
|
||||
const base::Closure& callback) {
|
||||
destruction_callbacks_.push_back(callback);
|
||||
|
@ -118,6 +127,11 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() {
|
|||
#endif
|
||||
}
|
||||
|
||||
bool AtomBrowserMainParts::MainMessageLoopRun(int* result_code) {
|
||||
exit_code_ = result_code;
|
||||
return brightray::BrowserMainParts::MainMessageLoopRun(result_code);
|
||||
}
|
||||
|
||||
void AtomBrowserMainParts::PostMainMessageLoopStart() {
|
||||
brightray::BrowserMainParts::PostMainMessageLoopStart();
|
||||
#if defined(OS_POSIX)
|
||||
|
@ -128,11 +142,23 @@ void AtomBrowserMainParts::PostMainMessageLoopStart() {
|
|||
void AtomBrowserMainParts::PostMainMessageLoopRun() {
|
||||
brightray::BrowserMainParts::PostMainMessageLoopRun();
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
FreeAppDelegate();
|
||||
#endif
|
||||
|
||||
// Make sure destruction callbacks are called before message loop is
|
||||
// destroyed, otherwise some objects that need to be deleted on IO thread
|
||||
// won't be freed.
|
||||
for (const auto& callback : destruction_callbacks_)
|
||||
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
|
||||
|
|
|
@ -31,6 +31,9 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
|
|||
|
||||
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
|
||||
// gets destroyed.
|
||||
void RegisterDestructionCallback(const base::Closure& callback);
|
||||
|
@ -42,11 +45,11 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
|
|||
void PreEarlyInitialization() override;
|
||||
void PostEarlyInitialization() override;
|
||||
void PreMainMessageLoopRun() override;
|
||||
bool MainMessageLoopRun(int* result_code) override;
|
||||
void PostMainMessageLoopStart() override;
|
||||
void PostMainMessageLoopRun() override;
|
||||
#if defined(OS_MACOSX)
|
||||
void PreMainMessageLoopStart() override;
|
||||
void PostDestroyThreads() override;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
@ -56,6 +59,10 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
|
|||
void HandleShutdownSignals();
|
||||
#endif
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
void FreeAppDelegate();
|
||||
#endif
|
||||
|
||||
// A fake BrowserProcess object that used to feed the source code from chrome.
|
||||
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.
|
||||
scoped_refptr<BridgeTaskRunner> bridge_task_runner_;
|
||||
|
||||
// Pointer to exit code.
|
||||
int* exit_code_;
|
||||
|
||||
scoped_ptr<Browser> browser_;
|
||||
scoped_ptr<JavascriptEnvironment> js_env_;
|
||||
scoped_ptr<NodeBindings> node_bindings_;
|
||||
|
|
|
@ -34,7 +34,7 @@ void AtomBrowserMainParts::PreMainMessageLoopStart() {
|
|||
setObject:@"NO" forKey:@"NSTreatUnknownArgumentsAsOpen"];
|
||||
}
|
||||
|
||||
void AtomBrowserMainParts::PostDestroyThreads() {
|
||||
void AtomBrowserMainParts::FreeAppDelegate() {
|
||||
[[NSApp delegate] release];
|
||||
[NSApp setDelegate:nil];
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <string>
|
||||
|
||||
#include "atom/browser/atom_browser_main_parts.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/window_list.h"
|
||||
#include "base/message_loop/message_loop.h"
|
||||
#include "content/public/browser/client_certificate_delegate.h"
|
||||
|
@ -45,6 +46,27 @@ void Browser::Quit() {
|
|||
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() {
|
||||
if (is_shutdown_)
|
||||
return;
|
||||
|
|
|
@ -42,6 +42,9 @@ class Browser : public WindowListObserver {
|
|||
// Try to close all windows and quit the application.
|
||||
void Quit();
|
||||
|
||||
// Exit the application immediately and set exit code.
|
||||
void Exit(int code);
|
||||
|
||||
// Cleanup everything and shutdown the application gracefully.
|
||||
void Shutdown();
|
||||
|
||||
|
|
|
@ -53,6 +53,9 @@ app = require 'app'
|
|||
app.on 'quit', ->
|
||||
process.emit 'exit'
|
||||
|
||||
# Map process.exit to app.exit, which quits gracefully.
|
||||
process.exit = app.exit
|
||||
|
||||
# Load the RPC server.
|
||||
require './rpc-server'
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/native_window_views.h"
|
||||
#include "content/public/browser/browser_accessibility_state.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
|
@ -83,6 +84,20 @@ bool NativeWindowViews::PreHandleMSG(
|
|||
NotifyWindowMessage(message, w_param, l_param);
|
||||
|
||||
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:
|
||||
// Handle thumbar button click message.
|
||||
if (HIWORD(w_param) == THBN_CLICKED)
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
<key>CFBundleIconFile</key>
|
||||
<string>atom.icns</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.34.2</string>
|
||||
<string>0.34.3</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.34.2</string>
|
||||
<string>0.34.3</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.developer-tools</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
|
|
|
@ -56,8 +56,8 @@ END
|
|||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 0,34,2,0
|
||||
PRODUCTVERSION 0,34,2,0
|
||||
FILEVERSION 0,34,3,0
|
||||
PRODUCTVERSION 0,34,3,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
@ -74,12 +74,12 @@ BEGIN
|
|||
BEGIN
|
||||
VALUE "CompanyName", "GitHub, Inc."
|
||||
VALUE "FileDescription", "Electron"
|
||||
VALUE "FileVersion", "0.34.2"
|
||||
VALUE "FileVersion", "0.34.3"
|
||||
VALUE "InternalName", "electron.exe"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
|
||||
VALUE "OriginalFilename", "electron.exe"
|
||||
VALUE "ProductName", "Electron"
|
||||
VALUE "ProductVersion", "0.34.2"
|
||||
VALUE "ProductVersion", "0.34.3"
|
||||
VALUE "SquirrelAwareVersion", "1"
|
||||
END
|
||||
END
|
||||
|
|
|
@ -113,7 +113,7 @@ void NotifyIcon::SetToolTip(const std::string& tool_tip) {
|
|||
NOTIFYICONDATA icon_data;
|
||||
InitIconData(&icon_data);
|
||||
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);
|
||||
if (!result)
|
||||
LOG(WARNING) << "Unable to set tooltip for status tray icon";
|
||||
|
@ -126,8 +126,8 @@ void NotifyIcon::DisplayBalloon(const gfx::Image& icon,
|
|||
InitIconData(&icon_data);
|
||||
icon_data.uFlags |= NIF_INFO;
|
||||
icon_data.dwInfoFlags = NIIF_INFO;
|
||||
wcscpy_s(icon_data.szInfoTitle, title.c_str());
|
||||
wcscpy_s(icon_data.szInfo, contents.c_str());
|
||||
wcsncpy_s(icon_data.szInfoTitle, title.c_str(), _TRUNCATE);
|
||||
wcsncpy_s(icon_data.szInfo, contents.c_str(), _TRUNCATE);
|
||||
icon_data.uTimeout = 0;
|
||||
|
||||
base::win::Version win_version = base::win::GetVersion();
|
||||
|
|
|
@ -97,7 +97,8 @@ bool TaskbarHost::SetThumbarButtons(
|
|||
// Set tooltip.
|
||||
if (!button.tooltip.empty()) {
|
||||
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.
|
||||
|
|
|
@ -1,5 +1 @@
|
|||
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
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#define ATOM_MAJOR_VERSION 0
|
||||
#define ATOM_MINOR_VERSION 34
|
||||
#define ATOM_PATCH_VERSION 2
|
||||
#define ATOM_PATCH_VERSION 3
|
||||
|
||||
#define ATOM_VERSION_IS_RELEASE 1
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ struct ExceptionHandlerRecord {
|
|||
unsigned char thunk[12];
|
||||
};
|
||||
|
||||
void RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes) {
|
||||
bool RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes) {
|
||||
ExceptionHandlerRecord* record =
|
||||
reinterpret_cast<ExceptionHandlerRecord*>(start);
|
||||
|
||||
|
@ -117,17 +117,17 @@ void RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes) {
|
|||
|
||||
// Protect reserved page against modifications.
|
||||
DWORD old_protect;
|
||||
CHECK(VirtualProtect(
|
||||
start, sizeof(ExceptionHandlerRecord), PAGE_EXECUTE_READ, &old_protect));
|
||||
CHECK(RtlAddFunctionTable(
|
||||
&record->runtime_function, 1, reinterpret_cast<DWORD64>(start)));
|
||||
return VirtualProtect(start, sizeof(ExceptionHandlerRecord),
|
||||
PAGE_EXECUTE_READ, &old_protect) &&
|
||||
RtlAddFunctionTable(&record->runtime_function, 1,
|
||||
reinterpret_cast<DWORD64>(start));
|
||||
}
|
||||
|
||||
void UnregisterNonABICompliantCodeRange(void* start) {
|
||||
ExceptionHandlerRecord* record =
|
||||
reinterpret_cast<ExceptionHandlerRecord*>(start);
|
||||
|
||||
CHECK(RtlDeleteFunctionTable(&record->runtime_function));
|
||||
RtlDeleteFunctionTable(&record->runtime_function);
|
||||
}
|
||||
#endif // _WIN64
|
||||
|
||||
|
@ -184,6 +184,7 @@ void CrashReporterWin::InitBreakpad(const std::string& product_name,
|
|||
LOG(ERROR) << "Cannot initialize out-of-process crash handler";
|
||||
|
||||
#ifdef _WIN64
|
||||
bool registered = false;
|
||||
// Hook up V8 to breakpad.
|
||||
{
|
||||
// gin::Debug::SetCodeRangeCreatedCallback only runs the callback when
|
||||
|
@ -192,9 +193,10 @@ void CrashReporterWin::InitBreakpad(const std::string& product_name,
|
|||
size_t size = 0;
|
||||
v8::Isolate::GetCurrent()->GetCodeRange(&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
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
|
||||
#include "atom/browser/atom_browser_main_parts.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
namespace internal {
|
||||
|
@ -54,6 +56,33 @@ v8::Local<v8::Value> BindFunctionWith(v8::Isolate* isolate,
|
|||
|
||||
} // 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::Isolate* isolate, const Translater& translater) {
|
||||
// The FunctionTemplate is cached.
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "atom/common/api/locker.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "native_mate/function_template.h"
|
||||
#include "native_mate/scoped_persistent.h"
|
||||
#include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h"
|
||||
|
@ -18,7 +19,24 @@ namespace mate {
|
|||
|
||||
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.
|
||||
template <typename Sig>
|
||||
|
@ -26,14 +44,17 @@ struct V8FunctionInvoker {};
|
|||
|
||||
template <typename... 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) {
|
||||
Locker locker(isolate);
|
||||
v8::EscapableHandleScope handle_scope(isolate);
|
||||
if (!function.is_alive())
|
||||
return v8::Null(isolate);
|
||||
scoped_ptr<blink::WebScopedRunV8Script> script_scope(
|
||||
Locker::IsBrowserProcess() ?
|
||||
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::Context::Scope context_scope(context);
|
||||
std::vector<v8::Local<v8::Value>> args = { ConvertToV8(isolate, raw)... };
|
||||
|
@ -44,14 +65,17 @@ struct V8FunctionInvoker<v8::Local<v8::Value>(ArgTypes...)> {
|
|||
|
||||
template <typename... ArgTypes>
|
||||
struct V8FunctionInvoker<void(ArgTypes...)> {
|
||||
static void Go(v8::Isolate* isolate, SafeV8Function function,
|
||||
static void Go(v8::Isolate* isolate,
|
||||
const SafeV8Function& function,
|
||||
ArgTypes... raw) {
|
||||
Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
if (!function.is_alive())
|
||||
return;
|
||||
scoped_ptr<blink::WebScopedRunV8Script> script_scope(
|
||||
Locker::IsBrowserProcess() ?
|
||||
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::Context::Scope context_scope(context);
|
||||
std::vector<v8::Local<v8::Value>> args = { ConvertToV8(isolate, raw)... };
|
||||
|
@ -61,17 +85,20 @@ struct V8FunctionInvoker<void(ArgTypes...)> {
|
|||
|
||||
template <typename ReturnType, typename... ArgTypes>
|
||||
struct V8FunctionInvoker<ReturnType(ArgTypes...)> {
|
||||
static ReturnType Go(v8::Isolate* isolate, SafeV8Function function,
|
||||
static ReturnType Go(v8::Isolate* isolate,
|
||||
const SafeV8Function& function,
|
||||
ArgTypes... raw) {
|
||||
Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
ReturnType ret = ReturnType();
|
||||
if (!function.is_alive())
|
||||
return ret;
|
||||
scoped_ptr<blink::WebScopedRunV8Script> script_scope(
|
||||
Locker::IsBrowserProcess() ?
|
||||
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::Context::Scope context_scope(context);
|
||||
ReturnType ret = ReturnType();
|
||||
std::vector<v8::Local<v8::Value>> args = { ConvertToV8(isolate, raw)... };
|
||||
v8::Local<v8::Value> result;
|
||||
auto maybe_result =
|
||||
|
@ -119,9 +146,8 @@ struct Converter<base::Callback<Sig>> {
|
|||
if (!val->IsFunction())
|
||||
return false;
|
||||
|
||||
internal::SafeV8Function function(
|
||||
new RefCountedPersistent<v8::Function>(isolate, val));
|
||||
*out = base::Bind(&internal::V8FunctionInvoker<Sig>::Go, isolate, function);
|
||||
*out = base::Bind(&internal::V8FunctionInvoker<Sig>::Go,
|
||||
isolate, internal::SafeV8Function(isolate, val));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "atom/common/node_includes.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/base_paths.h"
|
||||
#include "base/environment.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/message_loop/message_loop.h"
|
||||
#include "base/path_service.h"
|
||||
|
@ -141,6 +142,14 @@ void NodeBindings::Initialize() {
|
|||
// Init node.
|
||||
// (we assume node::Init would not modify the parameters under embedded mode).
|
||||
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(
|
||||
|
|
|
@ -5,7 +5,9 @@
|
|||
#include "atom/common/platform_util.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <atlbase.h>
|
||||
#include <commdlg.h>
|
||||
#include <comdef.h>
|
||||
#include <dwmapi.h>
|
||||
#include <shellapi.h>
|
||||
#include <shlobj.h>
|
||||
|
@ -19,6 +21,7 @@
|
|||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/win/registry.h"
|
||||
#include "base/win/scoped_co_mem.h"
|
||||
#include "base/win/scoped_com_initializer.h"
|
||||
#include "base/win/scoped_comptr.h"
|
||||
#include "base/win/windows_version.h"
|
||||
#include "url/gurl.h"
|
||||
|
@ -42,11 +45,168 @@ bool ValidateShellCommandForScheme(const std::string& scheme) {
|
|||
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 platform_util {
|
||||
|
||||
void ShowItemInFolder(const base::FilePath& full_path) {
|
||||
base::win::ScopedCOMInitializer com_initializer;
|
||||
if (!com_initializer.succeeded())
|
||||
return;
|
||||
|
||||
base::FilePath dir = full_path.DirName().AsEndingWithSeparator();
|
||||
// ParseDisplayName will fail if the directory is "C:", it must be "C:\\".
|
||||
if (dir.empty())
|
||||
|
@ -170,32 +330,40 @@ bool OpenExternal(const GURL& url) {
|
|||
}
|
||||
|
||||
bool MoveItemToTrash(const base::FilePath& path) {
|
||||
// SHFILEOPSTRUCT wants the path to be terminated with two NULLs,
|
||||
// so we have to use wcscpy because wcscpy_s writes non-NULLs
|
||||
// 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)
|
||||
base::win::ScopedCOMInitializer com_initializer;
|
||||
if (!com_initializer.succeeded())
|
||||
return false;
|
||||
|
||||
// Some versions of Windows return ERROR_FILE_NOT_FOUND (0x2) when deleting
|
||||
// an empty directory and some return 0x402 when they should be returning
|
||||
// ERROR_FILE_NOT_FOUND. MSDN says Vista and up won't return 0x402. Windows 7
|
||||
// can return DE_INVALIDFILES (0x7C) for nonexistent directories.
|
||||
return (err == 0 || err == ERROR_FILE_NOT_FOUND || err == 0x402 ||
|
||||
err == 0x7C);
|
||||
base::win::ScopedComPtr<IFileOperation> pfo;
|
||||
if (FAILED(pfo.CreateInstance(CLSID_FileOperation)))
|
||||
return false;
|
||||
|
||||
// Elevation prompt enabled for UAC protected files. This overrides the
|
||||
// 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() {
|
||||
|
|
|
@ -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
|
||||
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()`
|
||||
|
||||
Returns the current application directory.
|
||||
|
|
|
@ -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
|
||||
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)
|
||||
, first you need to download its source code:
|
||||
|
||||
|
|
|
@ -53,5 +53,6 @@ describe 'crash-reporter module', ->
|
|||
protocol: 'file'
|
||||
pathname: path.join fixtures, 'api', 'crash.html'
|
||||
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
|
||||
|
|
2
vendor/brightray
vendored
2
vendor/brightray
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 49a86c123f4cc43f4dca886ded612104a8a1fec6
|
||||
Subproject commit 98b3eb04d85a8a70b8d9f29477437061c2e77a83
|
Loading…
Reference in a new issue