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:
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

View file

@ -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',

View file

@ -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);

View file

@ -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))

View file

@ -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

View file

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

View file

@ -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(

View file

@ -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;

View file

@ -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:

View file

@ -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;

View file

@ -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)

View file

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

View file

@ -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;

View file

@ -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();

View file

@ -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);
};

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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

View file

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

View file

@ -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

View file

@ -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_;

View file

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

View file

@ -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;

View file

@ -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();

View file

@ -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'

View file

@ -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)

View file

@ -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>

View file

@ -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

View file

@ -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();

View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -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
}

View file

@ -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.

View file

@ -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;
}
};

View file

@ -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(

View file

@ -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() {

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
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.

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
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:

View file

@ -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

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