Merge pull request #2 from atom/master

Update from original
This commit is contained in:
Heilig Benedek 2015-11-12 01:20:33 +01:00
commit c571776da6
281 changed files with 9187 additions and 1920 deletions

1
.gitignore vendored
View file

@ -1,4 +1,5 @@
.DS_Store .DS_Store
/.idea/
/build/ /build/
/dist/ /dist/
/external_binaries/ /external_binaries/

View file

@ -10,6 +10,7 @@ os:
- osx - osx
env: env:
- TARGET_ARCH=x64 - TARGET_ARCH=x64
osx_image: xcode7
matrix: matrix:
include: include:

View file

@ -8,7 +8,7 @@
:zap: *프레임워크 이름이 Atom Shell에서 Electron으로 변경되었습니다* :zap: :zap: *프레임워크 이름이 Atom Shell에서 Electron으로 변경되었습니다* :zap:
Electron 프레임워크는 JavaScript, HTML 그리고 CSS를 사용하여 Cross-Platform 데스크톱 어플리케이션을 개발할 수 있도록 해주는 프레임워크입니다. 이 프레임워크는 [io.js](http://iojs.org) 와 Electron 프레임워크는 JavaScript, HTML 그리고 CSS를 사용하여 Cross-Platform 데스크톱 어플리케이션을 개발할 수 있도록 해주는 프레임워크입니다. 이 프레임워크는 [Node.js](https://nodejs.org) 와
[Chromium](http://www.chromium.org)을 기반으로 만들어 졌으며 [Atom Editor](https://github.com/atom/atom)에 사용되고 있습니다. [Chromium](http://www.chromium.org)을 기반으로 만들어 졌으며 [Atom Editor](https://github.com/atom/atom)에 사용되고 있습니다.
Electron에 대한 중요한 알림을 받고 싶다면 Twitter에서 [@ElectronJS](https://twitter.com/electronjs)를 팔로우 하세요. Electron에 대한 중요한 알림을 받고 싶다면 Twitter에서 [@ElectronJS](https://twitter.com/electronjs)를 팔로우 하세요.
@ -47,9 +47,13 @@ Electron을 빌드 하는 방법과 프로젝트에 기여하는 방법도 문
- [중국어 간체](https://github.com/atom/electron/tree/master/docs-translations/zh-CN) - [중국어 간체](https://github.com/atom/electron/tree/master/docs-translations/zh-CN)
- [중국어 번체](https://github.com/atom/electron/tree/master/docs-translations/zh-TW) - [중국어 번체](https://github.com/atom/electron/tree/master/docs-translations/zh-TW)
## 시작하기
[`atom/electron-quick-start`](https://github.com/atom/electron-quick-start) 저장소를 클론하여 Electron을 간단히 접해볼 수 있습니다.
## 커뮤니티 ## 커뮤니티
다음 링크를 통해 커뮤니티에 질문을 올리거나 토론을 나누실 수 있습니다: 다음 링크를 통해 커뮤니티에 질문을 올리거나 토론을 나 수 있습니다:
- Atom 포럼의 [`electron`](http://discuss.atom.io/category/electron) 카테고리 - Atom 포럼의 [`electron`](http://discuss.atom.io/category/electron) 카테고리
- Freenode 채팅의 `#atom-shell` 채널 - Freenode 채팅의 `#atom-shell` 채널

View file

@ -7,20 +7,20 @@
: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 [io.js](http://iojs.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.
## Downloads ## Downloads
Prebuilt binaries and debug symbols of Electron for Linux, Windows and Mac can Prebuilt binaries and debug symbols of Electron for Linux, Windows and OS X can
be found on the [releases](https://github.com/atom/electron/releases) page. be found on the [releases](https://github.com/atom/electron/releases) page.
You can also use [`npm`](https://docs.npmjs.com/) to install prebuilt electron You can also use [`npm`](https://docs.npmjs.com/) to install prebuilt electron
@ -53,11 +53,16 @@ contains documents describing how to build and contribute to Electron.
- [Simplified Chinese](https://github.com/atom/electron/tree/master/docs-translations/zh-CN) - [Simplified Chinese](https://github.com/atom/electron/tree/master/docs-translations/zh-CN)
- [Traditional Chinese](https://github.com/atom/electron/tree/master/docs-translations/zh-TW) - [Traditional Chinese](https://github.com/atom/electron/tree/master/docs-translations/zh-TW)
## Quick Start
Clone and run the [`atom/electron-quick-start`](https://github.com/atom/electron-quick-start)
repository to see a minimal Electron app in action.
## Community ## Community
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.33.6', 'version%': '0.34.3',
}, },
'includes': [ 'includes': [
'filenames.gypi', 'filenames.gypi',
@ -64,9 +64,6 @@
'files': [ 'files': [
'<(PRODUCT_DIR)/<(product_name) Helper.app', '<(PRODUCT_DIR)/<(product_name) Helper.app',
'<(PRODUCT_DIR)/<(product_name) Framework.framework', '<(PRODUCT_DIR)/<(product_name) Framework.framework',
'external_binaries/Squirrel.framework',
'external_binaries/ReactiveCocoa.framework',
'external_binaries/Mantle.framework',
], ],
}, },
{ {
@ -109,7 +106,21 @@
'<@(locale_dirs)', '<@(locale_dirs)',
], ],
}, },
] ],
'conditions': [
['mas_build==0', {
'copies': [
{
'destination': '<(PRODUCT_DIR)/<(product_name).app/Contents/Frameworks',
'files': [
'external_binaries/Squirrel.framework',
'external_binaries/ReactiveCocoa.framework',
'external_binaries/Mantle.framework',
],
},
],
}],
],
}, { # OS=="mac" }, { # OS=="mac"
'dependencies': [ 'dependencies': [
'make_locale_paks', 'make_locale_paks',
@ -285,12 +296,28 @@
'vendor/breakpad/breakpad.gyp:breakpad_sender', 'vendor/breakpad/breakpad.gyp:breakpad_sender',
], ],
}], # OS=="win" }], # OS=="win"
['OS=="mac"', { ['OS=="mac" and mas_build==0', {
'dependencies': [ 'dependencies': [
'vendor/crashpad/client/client.gyp:crashpad_client', 'vendor/crashpad/client/client.gyp:crashpad_client',
'vendor/crashpad/handler/handler.gyp:crashpad_handler', 'vendor/crashpad/handler/handler.gyp:crashpad_handler',
], ],
}], # OS=="mac" 'link_settings': {
# Do not link with QTKit for mas build.
'libraries': [
'$(SDKROOT)/System/Library/Frameworks/QTKit.framework',
],
},
}], # OS=="mac" and mas_build==0
['OS=="mac" and mas_build==1', {
'defines': [
'MAS_BUILD',
],
'sources!': [
'atom/browser/auto_updater_mac.mm',
'atom/common/crash_reporter/crash_reporter_mac.h',
'atom/common/crash_reporter/crash_reporter_mac.mm',
],
}], # OS=="mac" and mas_build==1
['OS=="linux"', { ['OS=="linux"', {
'link_settings': { 'link_settings': {
'ldflags': [ 'ldflags': [
@ -393,9 +420,6 @@
'libraries': [ 'libraries': [
'$(SDKROOT)/System/Library/Frameworks/Carbon.framework', '$(SDKROOT)/System/Library/Frameworks/Carbon.framework',
'$(SDKROOT)/System/Library/Frameworks/QuartzCore.framework', '$(SDKROOT)/System/Library/Frameworks/QuartzCore.framework',
'external_binaries/Squirrel.framework',
'external_binaries/ReactiveCocoa.framework',
'external_binaries/Mantle.framework',
], ],
}, },
'mac_bundle': 1, 'mac_bundle': 1,
@ -439,12 +463,6 @@
'<@(copied_libraries)', '<@(copied_libraries)',
], ],
}, },
{
'destination': '<(PRODUCT_DIR)/<(product_name) Framework.framework/Versions/A/Resources',
'files': [
'<(PRODUCT_DIR)/crashpad_handler',
],
},
], ],
'postbuilds': [ 'postbuilds': [
{ {
@ -476,6 +494,25 @@
], ],
}, },
], ],
'conditions': [
['mas_build==0', {
'link_settings': {
'libraries': [
'external_binaries/Squirrel.framework',
'external_binaries/ReactiveCocoa.framework',
'external_binaries/Mantle.framework',
],
},
'copies': [
{
'destination': '<(PRODUCT_DIR)/<(product_name) Framework.framework/Versions/A/Resources',
'files': [
'<(PRODUCT_DIR)/crashpad_handler',
],
},
],
}],
],
}, # target framework }, # target framework
{ {
'target_name': '<(project_name)_helper', 'target_name': '<(project_name)_helper',

View file

@ -99,7 +99,7 @@ void AtomContentClient::AddAdditionalSchemes(
void AtomContentClient::AddPepperPlugins( void AtomContentClient::AddPepperPlugins(
std::vector<content::PepperPluginInfo>* plugins) { std::vector<content::PepperPluginInfo>* plugins) {
auto command_line = base::CommandLine::ForCurrentProcess(); auto command_line = base::CommandLine::ForCurrentProcess();
auto flash_path = command_line->GetSwitchValueNative( auto flash_path = command_line->GetSwitchValuePath(
switches::kPpapiFlashPath); switches::kPpapiFlashPath);
if (flash_path.empty()) if (flash_path.empty())
return; return;
@ -108,7 +108,7 @@ void AtomContentClient::AddPepperPlugins(
switches::kPpapiFlashVersion); switches::kPpapiFlashVersion);
plugins->push_back( plugins->push_back(
CreatePepperFlashInfo(base::FilePath(flash_path), flash_version)); CreatePepperFlashInfo(flash_path, flash_version));
} }
} // namespace atom } // namespace atom

View file

@ -10,6 +10,7 @@
#include "base/at_exit.h" #include "base/at_exit.h"
#include "base/i18n/icu_util.h" #include "base/i18n/icu_util.h"
#include "base/mac/bundle_locations.h" #include "base/mac/bundle_locations.h"
#include "base/mac/scoped_nsautorelease_pool.h"
#include "brightray/common/mac/main_application_bundle.h" #include "brightray/common/mac/main_application_bundle.h"
#include "content/public/app/content_main.h" #include "content/public/app/content_main.h"
@ -25,6 +26,7 @@ int AtomMain(int argc, const char* argv[]) {
int AtomInitializeICUandStartNode(int argc, char *argv[]) { int AtomInitializeICUandStartNode(int argc, char *argv[]) {
base::AtExitManager atexit_manager; base::AtExitManager atexit_manager;
base::mac::ScopedNSAutoreleasePool pool;
base::mac::SetOverrideFrameworkBundlePath( base::mac::SetOverrideFrameworkBundlePath(
brightray::MainApplicationBundlePath() brightray::MainApplicationBundlePath()
.Append("Contents") .Append("Contents")

View file

@ -5,6 +5,7 @@
#include "atom/app/atom_main_delegate.h" #include "atom/app/atom_main_delegate.h"
#include <string> #include <string>
#include <iostream>
#include "atom/app/atom_content_client.h" #include "atom/app/atom_content_client.h"
#include "atom/browser/atom_browser_client.h" #include "atom/browser/atom_browser_client.h"
@ -20,6 +21,15 @@
namespace atom { namespace atom {
namespace {
bool IsBrowserProcess(base::CommandLine* cmd) {
std::string process_type = cmd->GetSwitchValueASCII(switches::kProcessType);
return process_type.empty();
}
} // namespace
AtomMainDelegate::AtomMainDelegate() { AtomMainDelegate::AtomMainDelegate() {
} }
@ -27,8 +37,14 @@ AtomMainDelegate::~AtomMainDelegate() {
} }
bool AtomMainDelegate::BasicStartupComplete(int* exit_code) { bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
auto command_line = base::CommandLine::ForCurrentProcess();
logging::LoggingSettings settings; logging::LoggingSettings settings;
#if defined(OS_WIN) #if defined(OS_WIN)
// On Windows the terminal returns immediately, so we add a new line to
// prevent output in the same line as the prompt.
if (IsBrowserProcess(command_line))
std::wcout << std::endl;
#if defined(DEBUG) #if defined(DEBUG)
// Print logging to debug.log on Windows // Print logging to debug.log on Windows
settings.logging_dest = logging::LOG_TO_ALL; settings.logging_dest = logging::LOG_TO_ALL;
@ -43,19 +59,25 @@ bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
#endif // !defined(OS_WIN) #endif // !defined(OS_WIN)
// Only enable logging when --enable-logging is specified. // Only enable logging when --enable-logging is specified.
auto command_line = base::CommandLine::ForCurrentProcess(); scoped_ptr<base::Environment> env(base::Environment::Create());
if (!command_line->HasSwitch(switches::kEnableLogging)) if (!command_line->HasSwitch(switches::kEnableLogging) &&
!env->HasVar("ELECTRON_ENABLE_LOGGING")) {
settings.logging_dest = logging::LOG_NONE; settings.logging_dest = logging::LOG_NONE;
logging::SetMinLogLevel(logging::LOG_NUM_SEVERITIES);
}
logging::InitLogging(settings); logging::InitLogging(settings);
// Logging with pid and timestamp. // Logging with pid and timestamp.
logging::SetLogItems(true, false, true, false); logging::SetLogItems(true, false, true, false);
#if defined(DEBUG) && defined(OS_LINUX)
// Enable convient stack printing. // Enable convient stack printing.
base::debug::EnableInProcessStackDumping(); bool enable_stack_dumping = env->HasVar("ELECTRON_ENABLE_STACK_DUMPING");
#if defined(DEBUG) && defined(OS_LINUX)
enable_stack_dumping = true;
#endif #endif
if (enable_stack_dumping)
base::debug::EnableInProcessStackDumping();
return brightray::MainDelegate::BasicStartupComplete(exit_code); return brightray::MainDelegate::BasicStartupComplete(exit_code);
} }
@ -77,16 +99,9 @@ void AtomMainDelegate::PreSandboxStartup() {
} }
// Only append arguments for browser process. // Only append arguments for browser process.
if (!process_type.empty()) 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

@ -7,8 +7,8 @@
#include "atom/app/uv_task_runner.h" #include "atom/app/uv_task_runner.h"
#include "atom/browser/javascript_environment.h" #include "atom/browser/javascript_environment.h"
#include "atom/browser/node_debugger.h" #include "atom/browser/node_debugger.h"
#include "atom/common/node_includes.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "atom/common/node_includes.h"
#include "base/thread_task_runner_handle.h" #include "base/thread_task_runner_handle.h"
#include "gin/array_buffer.h" #include "gin/array_buffer.h"
#include "gin/public/isolate_holder.h" #include "gin/public/isolate_holder.h"
@ -19,25 +19,22 @@ namespace atom {
int NodeMain(int argc, char *argv[]) { int NodeMain(int argc, char *argv[]) {
base::CommandLine::Init(argc, argv); base::CommandLine::Init(argc, argv);
argv = uv_setup_args(argc, argv);
int exec_argc;
const char** exec_argv;
node::Init(&argc, const_cast<const char**>(argv), &exec_argc, &exec_argv);
int exit_code = 1; int exit_code = 1;
{ {
// Feed gin::PerIsolateData with a task runner. // Feed gin::PerIsolateData with a task runner.
argv = uv_setup_args(argc, argv);
uv_loop_t* loop = uv_default_loop(); uv_loop_t* loop = uv_default_loop();
scoped_refptr<UvTaskRunner> uv_task_runner(new UvTaskRunner(loop)); scoped_refptr<UvTaskRunner> uv_task_runner(new UvTaskRunner(loop));
base::ThreadTaskRunnerHandle handle(uv_task_runner); base::ThreadTaskRunnerHandle handle(uv_task_runner);
gin::V8Initializer::LoadV8Snapshot(); gin::V8Initializer::LoadV8Snapshot();
gin::V8Initializer::LoadV8Natives(); gin::V8Initializer::LoadV8Natives();
gin::IsolateHolder::Initialize(
gin::IsolateHolder::kNonStrictMode,
gin::ArrayBufferAllocator::SharedInstance());
JavascriptEnvironment gin_env; JavascriptEnvironment gin_env;
int exec_argc;
const char** exec_argv;
node::Init(&argc, const_cast<const char**>(argv), &exec_argc, &exec_argv);
node::Environment* env = node::CreateEnvironment( node::Environment* env = node::CreateEnvironment(
gin_env.isolate(), loop, gin_env.context(), argc, argv, gin_env.isolate(), loop, gin_env.context(), argc, argv,
exec_argc, exec_argv); exec_argc, exec_argv);

View file

@ -48,8 +48,13 @@ void UvTaskRunner::OnTimeout(uv_timer_t* timer) {
self->tasks_[timer].Run(); self->tasks_[timer].Run();
self->tasks_.erase(timer); self->tasks_.erase(timer);
uv_unref(reinterpret_cast<uv_handle_t*>(timer)); uv_timer_stop(timer);
delete timer; uv_close(reinterpret_cast<uv_handle_t*>(timer), UvTaskRunner::OnClose);
}
// static
void UvTaskRunner::OnClose(uv_handle_t* handle) {
delete reinterpret_cast<uv_timer_t*>(handle);
} }
} // namespace atom } // namespace atom

View file

@ -31,6 +31,7 @@ class UvTaskRunner : public base::SingleThreadTaskRunner {
private: private:
static void OnTimeout(uv_timer_t* timer); static void OnTimeout(uv_timer_t* timer);
static void OnClose(uv_handle_t* handle);
uv_loop_t* loop_; uv_loop_t* loop_;

View file

@ -7,19 +7,18 @@
#include <string> #include <string>
#include <vector> #include <vector>
#if defined(OS_WIN)
#include <shlobj.h>
#endif
#include "atom/browser/api/atom_api_menu.h" #include "atom/browser/api/atom_api_menu.h"
#include "atom/browser/api/atom_api_session.h" #include "atom/browser/api/atom_api_session.h"
#include "atom/browser/api/atom_api_web_contents.h"
#include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_context.h"
#include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/browser.h" #include "atom/browser/browser.h"
#include "atom/browser/api/atom_api_web_contents.h" #include "atom/browser/login_handler.h"
#include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/net_converter.h"
#include "atom/common/native_mate_converters/file_path_converter.h" #include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/node_includes.h" #include "atom/common/node_includes.h"
#include "atom/common/options_switches.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/environment.h" #include "base/environment.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
@ -27,6 +26,7 @@
#include "brightray/browser/brightray_paths.h" #include "brightray/browser/brightray_paths.h"
#include "content/public/browser/client_certificate_delegate.h" #include "content/public/browser/client_certificate_delegate.h"
#include "content/public/browser/gpu_data_manager.h" #include "content/public/browser/gpu_data_manager.h"
#include "content/public/common/content_switches.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h" #include "native_mate/object_template_builder.h"
#include "net/ssl/ssl_cert_request_info.h" #include "net/ssl/ssl_cert_request_info.h"
@ -109,12 +109,27 @@ int GetPathConstant(const std::string& name) {
return -1; return -1;
} }
bool NotificationCallbackWrapper(
const ProcessSingleton::NotificationCallback& callback,
const base::CommandLine::StringVector& cmd,
const base::FilePath& cwd) {
// Make sure the callback is called after app gets ready.
if (Browser::Get()->is_ready()) {
callback.Run(cmd, cwd);
} else {
scoped_refptr<base::SingleThreadTaskRunner> task_runner(
base::ThreadTaskRunnerHandle::Get());
task_runner->PostTask(
FROM_HERE, base::Bind(base::IgnoreResult(callback), cmd, cwd));
}
// ProcessSingleton needs to know whether current process is quiting.
return !Browser::Get()->is_shutting_down();
}
void OnClientCertificateSelected( void OnClientCertificateSelected(
v8::Isolate* isolate, v8::Isolate* isolate,
std::shared_ptr<content::ClientCertificateDelegate> delegate, std::shared_ptr<content::ClientCertificateDelegate> delegate,
mate::Arguments* args) { mate::Arguments* args) {
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
mate::Dictionary cert_data; mate::Dictionary cert_data;
if (!(args->Length() == 1 && args->GetNext(&cert_data))) { if (!(args->Length() == 1 && args->GetNext(&cert_data))) {
args->ThrowError(); args->ThrowError();
@ -128,10 +143,18 @@ void OnClientCertificateSelected(
net::X509Certificate::CreateCertificateListFromBytes( net::X509Certificate::CreateCertificateListFromBytes(
encoded_data.data(), encoded_data.size(), encoded_data.data(), encoded_data.size(),
net::X509Certificate::FORMAT_AUTO); net::X509Certificate::FORMAT_AUTO);
delegate->ContinueWithCertificate(certs[0].get()); delegate->ContinueWithCertificate(certs[0].get());
} }
void PassLoginInformation(scoped_refptr<LoginHandler> login_handler,
mate::Arguments* args) {
base::string16 username, password;
if (args->GetNext(&username) && args->GetNext(&password))
login_handler->Login(username, password);
else
login_handler->CancelAuth();
}
} // namespace } // namespace
App::App() { App::App() {
@ -158,6 +181,11 @@ void App::OnWindowAllClosed() {
void App::OnQuit() { void App::OnQuit() {
Emit("quit"); Emit("quit");
if (process_singleton_.get()) {
process_singleton_->Cleanup();
process_singleton_.reset();
}
} }
void App::OnOpenFile(bool* prevent_default, const std::string& file_path) { void App::OnOpenFile(bool* prevent_default, const std::string& file_path) {
@ -209,6 +237,31 @@ void App::OnSelectCertificate(
cert_request_info->client_certs[0].get()); cert_request_info->client_certs[0].get());
} }
void App::OnLogin(LoginHandler* login_handler) {
// Convert the args explicitly since they will be passed for twice.
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
auto web_contents =
WebContents::CreateFrom(isolate(), login_handler->GetWebContents());
auto request = mate::ConvertToV8(isolate(), login_handler->request());
auto auth_info = mate::ConvertToV8(isolate(), login_handler->auth_info());
auto callback = mate::ConvertToV8(
isolate(),
base::Bind(&PassLoginInformation, make_scoped_refptr(login_handler)));
bool prevent_default =
Emit("login", web_contents, request, auth_info, callback);
// Also pass it to WebContents.
if (!prevent_default)
prevent_default =
web_contents->Emit("login", request, auth_info, callback);
// Default behavior is to always cancel the auth.
if (!prevent_default)
login_handler->CancelAuth();
}
void App::OnGpuProcessCrashed(base::TerminationStatus exit_code) { void App::OnGpuProcessCrashed(base::TerminationStatus exit_code) {
Emit("gpu-process-crashed"); Emit("gpu-process-crashed");
} }
@ -242,11 +295,10 @@ void App::SetDesktopName(const std::string& desktop_name) {
#endif #endif
} }
void App::SetAppUserModelId(const std::string& app_id) { void App::AllowNTLMCredentialsForAllDomains(bool should_allow) {
#if defined(OS_WIN) auto browser_context = static_cast<AtomBrowserContext*>(
base::string16 app_id_utf16 = base::UTF8ToUTF16(app_id); AtomBrowserMainParts::Get()->browser_context());
SetCurrentProcessExplicitAppUserModelID(app_id_utf16.c_str()); browser_context->AllowNTLMCredentialsForAllDomains(should_allow);
#endif
} }
std::string App::GetLocale() { std::string App::GetLocale() {
@ -260,11 +312,34 @@ v8::Local<v8::Value> App::DefaultSession(v8::Isolate* isolate) {
return v8::Local<v8::Value>::New(isolate, default_session_); return v8::Local<v8::Value>::New(isolate, default_session_);
} }
bool App::MakeSingleInstance(
const ProcessSingleton::NotificationCallback& callback) {
if (process_singleton_.get())
return false;
base::FilePath user_dir;
PathService::Get(brightray::DIR_USER_DATA, &user_dir);
process_singleton_.reset(new ProcessSingleton(
user_dir, base::Bind(NotificationCallbackWrapper, callback)));
switch (process_singleton_->NotifyOtherProcessOrCreate()) {
case ProcessSingleton::NotifyResult::LOCK_ERROR:
case ProcessSingleton::NotifyResult::PROFILE_IN_USE:
case ProcessSingleton::NotifyResult::PROCESS_NOTIFIED:
process_singleton_.reset();
return true;
case ProcessSingleton::NotifyResult::PROCESS_NONE:
default: // Shouldn't be needed, but VS warns if it is not there.
return false;
}
}
mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder( mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
v8::Isolate* isolate) { v8::Isolate* isolate) {
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))
@ -275,6 +350,8 @@ mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
base::Bind(&Browser::AddRecentDocument, browser)) base::Bind(&Browser::AddRecentDocument, browser))
.SetMethod("clearRecentDocuments", .SetMethod("clearRecentDocuments",
base::Bind(&Browser::ClearRecentDocuments, browser)) base::Bind(&Browser::ClearRecentDocuments, browser))
.SetMethod("setAppUserModelId",
base::Bind(&Browser::SetAppUserModelID, browser))
#if defined(OS_WIN) #if defined(OS_WIN)
.SetMethod("setUserTasks", .SetMethod("setUserTasks",
base::Bind(&Browser::SetUserTasks, browser)) base::Bind(&Browser::SetUserTasks, browser))
@ -282,8 +359,10 @@ mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
.SetMethod("setPath", &App::SetPath) .SetMethod("setPath", &App::SetPath)
.SetMethod("getPath", &App::GetPath) .SetMethod("getPath", &App::GetPath)
.SetMethod("setDesktopName", &App::SetDesktopName) .SetMethod("setDesktopName", &App::SetDesktopName)
.SetMethod("setAppUserModelId", &App::SetAppUserModelId) .SetMethod("allowNTLMCredentialsForAllDomains",
&App::AllowNTLMCredentialsForAllDomains)
.SetMethod("getLocale", &App::GetLocale) .SetMethod("getLocale", &App::GetLocale)
.SetMethod("makeSingleInstance", &App::MakeSingleInstance)
.SetProperty("defaultSession", &App::DefaultSession); .SetProperty("defaultSession", &App::DefaultSession);
} }
@ -301,6 +380,16 @@ namespace {
void AppendSwitch(const std::string& switch_string, mate::Arguments* args) { void AppendSwitch(const std::string& switch_string, mate::Arguments* args) {
auto command_line = base::CommandLine::ForCurrentProcess(); auto command_line = base::CommandLine::ForCurrentProcess();
if (switch_string == atom::switches::kPpapiFlashPath ||
switch_string == atom::switches::kClientCertificate ||
switch_string == switches::kLogNetLog) {
base::FilePath path;
args->GetNext(&path);
command_line->AppendSwitchPath(switch_string, path);
return;
}
std::string value; std::string value;
if (args->GetNext(&value)) if (args->GetNext(&value))
command_line->AppendSwitchASCII(switch_string, value); command_line->AppendSwitchASCII(switch_string, value);

View file

@ -9,6 +9,8 @@
#include "atom/browser/api/event_emitter.h" #include "atom/browser/api/event_emitter.h"
#include "atom/browser/browser_observer.h" #include "atom/browser/browser_observer.h"
#include "atom/common/native_mate_converters/callback.h"
#include "chrome/browser/process_singleton.h"
#include "content/public/browser/gpu_data_manager_observer.h" #include "content/public/browser/gpu_data_manager_observer.h"
#include "native_mate/handle.h" #include "native_mate/handle.h"
@ -48,6 +50,7 @@ class App : public mate::EventEmitter,
content::WebContents* web_contents, content::WebContents* web_contents,
net::SSLCertRequestInfo* cert_request_info, net::SSLCertRequestInfo* cert_request_info,
scoped_ptr<content::ClientCertificateDelegate> delegate) override; scoped_ptr<content::ClientCertificateDelegate> delegate) override;
void OnLogin(LoginHandler* login_handler) override;
// content::GpuDataManagerObserver: // content::GpuDataManagerObserver:
void OnGpuProcessCrashed(base::TerminationStatus exit_code) override; void OnGpuProcessCrashed(base::TerminationStatus exit_code) override;
@ -64,12 +67,16 @@ class App : public mate::EventEmitter,
const base::FilePath& path); const base::FilePath& path);
void SetDesktopName(const std::string& desktop_name); void SetDesktopName(const std::string& desktop_name);
void SetAppUserModelId(const std::string& app_id); void AllowNTLMCredentialsForAllDomains(bool should_allow);
bool MakeSingleInstance(
const ProcessSingleton::NotificationCallback& callback);
std::string GetLocale(); std::string GetLocale();
v8::Local<v8::Value> DefaultSession(v8::Isolate* isolate); v8::Local<v8::Value> DefaultSession(v8::Isolate* isolate);
v8::Global<v8::Value> default_session_; v8::Global<v8::Value> default_session_;
scoped_ptr<ProcessSingleton> process_singleton_;
DISALLOW_COPY_AND_ASSIGN(App); DISALLOW_COPY_AND_ASSIGN(App);
}; };

View file

@ -5,12 +5,31 @@
#include "atom/browser/api/atom_api_auto_updater.h" #include "atom/browser/api/atom_api_auto_updater.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "atom/browser/auto_updater.h"
#include "atom/browser/browser.h" #include "atom/browser/browser.h"
#include "atom/browser/native_window.h"
#include "atom/browser/window_list.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/node_includes.h" #include "atom/common/node_includes.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h" #include "native_mate/object_template_builder.h"
namespace mate {
template<>
struct Converter<base::Time> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
const base::Time& val) {
v8::MaybeLocal<v8::Value> date = v8::Date::New(
isolate->GetCurrentContext(), val.ToJsTime());
if (date.IsEmpty())
return v8::Null(isolate);
else
return date.ToLocalChecked();
}
};
} // namespace mate
namespace atom { namespace atom {
namespace api { namespace api {
@ -20,11 +39,18 @@ AutoUpdater::AutoUpdater() {
} }
AutoUpdater::~AutoUpdater() { AutoUpdater::~AutoUpdater() {
auto_updater::AutoUpdater::SetDelegate(NULL); auto_updater::AutoUpdater::SetDelegate(nullptr);
} }
void AutoUpdater::OnError(const std::string& error) { void AutoUpdater::OnError(const std::string& message) {
Emit("error", error); v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
auto error = v8::Exception::Error(mate::StringToV8(isolate(), message));
EmitCustomEvent(
"error",
error->ToObject(isolate()->GetCurrentContext()).ToLocalChecked(),
// Message is also emitted to keep compatibility with old code.
message);
} }
void AutoUpdater::OnCheckingForUpdate() { void AutoUpdater::OnCheckingForUpdate() {
@ -42,11 +68,14 @@ void AutoUpdater::OnUpdateNotAvailable() {
void AutoUpdater::OnUpdateDownloaded(const std::string& release_notes, void AutoUpdater::OnUpdateDownloaded(const std::string& release_notes,
const std::string& release_name, const std::string& release_name,
const base::Time& release_date, const base::Time& release_date,
const std::string& update_url, const std::string& url) {
const base::Closure& quit_and_install) { Emit("update-downloaded", release_notes, release_name, release_date, url,
quit_and_install_ = quit_and_install; // Keep compatibility with old APIs.
Emit("update-downloaded-raw", release_notes, release_name, base::Bind(&AutoUpdater::QuitAndInstall, base::Unretained(this)));
release_date.ToJsTime(), update_url); }
void AutoUpdater::OnWindowAllClosed() {
QuitAndInstall();
} }
mate::ObjectTemplateBuilder AutoUpdater::GetObjectTemplateBuilder( mate::ObjectTemplateBuilder AutoUpdater::GetObjectTemplateBuilder(
@ -54,14 +83,21 @@ mate::ObjectTemplateBuilder AutoUpdater::GetObjectTemplateBuilder(
return mate::ObjectTemplateBuilder(isolate) return mate::ObjectTemplateBuilder(isolate)
.SetMethod("setFeedUrl", &auto_updater::AutoUpdater::SetFeedURL) .SetMethod("setFeedUrl", &auto_updater::AutoUpdater::SetFeedURL)
.SetMethod("checkForUpdates", &auto_updater::AutoUpdater::CheckForUpdates) .SetMethod("checkForUpdates", &auto_updater::AutoUpdater::CheckForUpdates)
.SetMethod("_quitAndInstall", &AutoUpdater::QuitAndInstall); .SetMethod("quitAndInstall", &AutoUpdater::QuitAndInstall);
} }
void AutoUpdater::QuitAndInstall() { void AutoUpdater::QuitAndInstall() {
if (quit_and_install_.is_null()) // If we don't have any window then quitAndInstall immediately.
Browser::Get()->Shutdown(); WindowList* window_list = WindowList::GetInstance();
else if (window_list->size() == 0) {
quit_and_install_.Run(); auto_updater::AutoUpdater::QuitAndInstall();
return;
}
// Otherwise do the restart after all windows have been closed.
window_list->AddObserver(this);
for (NativeWindow* window : *window_list)
window->Close();
} }
// static // static

View file

@ -7,9 +7,9 @@
#include <string> #include <string>
#include "base/callback.h"
#include "atom/browser/api/event_emitter.h" #include "atom/browser/api/event_emitter.h"
#include "atom/browser/auto_updater_delegate.h" #include "atom/browser/auto_updater.h"
#include "atom/browser/window_list_observer.h"
#include "native_mate/handle.h" #include "native_mate/handle.h"
namespace atom { namespace atom {
@ -17,7 +17,8 @@ namespace atom {
namespace api { namespace api {
class AutoUpdater : public mate::EventEmitter, class AutoUpdater : public mate::EventEmitter,
public auto_updater::AutoUpdaterDelegate { public auto_updater::Delegate,
public WindowListObserver {
public: public:
static mate::Handle<AutoUpdater> Create(v8::Isolate* isolate); static mate::Handle<AutoUpdater> Create(v8::Isolate* isolate);
@ -25,17 +26,18 @@ class AutoUpdater : public mate::EventEmitter,
AutoUpdater(); AutoUpdater();
virtual ~AutoUpdater(); virtual ~AutoUpdater();
// AutoUpdaterDelegate implementations. // Delegate implementations.
void OnError(const std::string& error) override; void OnError(const std::string& error) override;
void OnCheckingForUpdate() override; void OnCheckingForUpdate() override;
void OnUpdateAvailable() override; void OnUpdateAvailable() override;
void OnUpdateNotAvailable() override; void OnUpdateNotAvailable() override;
void OnUpdateDownloaded( void OnUpdateDownloaded(const std::string& release_notes,
const std::string& release_notes, const std::string& release_name,
const std::string& release_name, const base::Time& release_date,
const base::Time& release_date, const std::string& update_url) override;
const std::string& update_url,
const base::Closure& quit_and_install) override; // WindowListObserver:
void OnWindowAllClosed() override;
// mate::Wrappable implementations: // mate::Wrappable implementations:
mate::ObjectTemplateBuilder GetObjectTemplateBuilder( mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
@ -44,8 +46,6 @@ class AutoUpdater : public mate::EventEmitter,
private: private:
void QuitAndInstall(); void QuitAndInstall();
base::Closure quit_and_install_;
DISALLOW_COPY_AND_ASSIGN(AutoUpdater); DISALLOW_COPY_AND_ASSIGN(AutoUpdater);
}; };

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

@ -12,27 +12,12 @@
#include "atom/browser/net/url_request_fetch_job.h" #include "atom/browser/net/url_request_fetch_job.h"
#include "atom/browser/net/url_request_string_job.h" #include "atom/browser/net/url_request_string_job.h"
#include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/net_converter.h"
#include "atom/common/node_includes.h" #include "atom/common/node_includes.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
using content::BrowserThread; using content::BrowserThread;
namespace mate {
template<>
struct Converter<const net::URLRequest*> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
const net::URLRequest* val) {
return mate::ObjectTemplateBuilder(isolate)
.SetValue("method", val->method())
.SetValue("url", val->url().spec())
.SetValue("referrer", val->referrer())
.Build()->NewInstance();
}
};
} // namespace mate
namespace atom { namespace atom {
namespace api { namespace api {

View file

@ -9,8 +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/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"
@ -104,6 +106,24 @@ struct Converter<ClearStorageDataOptions> {
} }
}; };
template<>
struct Converter<net::ProxyConfig> {
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
net::ProxyConfig* out) {
std::string proxy;
if (!ConvertFromV8(isolate, val, &proxy))
return false;
auto pac_url = GURL(proxy);
if (pac_url.is_valid()) {
out->set_pac_url(pac_url);
} else {
out->proxy_rules().ParseFromString(proxy);
}
return true;
}
};
} // namespace mate } // namespace mate
namespace atom { namespace atom {
@ -208,12 +228,12 @@ void ClearHttpCacheInIO(
} }
void SetProxyInIO(net::URLRequestContextGetter* getter, void SetProxyInIO(net::URLRequestContextGetter* getter,
const std::string& proxy, const net::ProxyConfig& config,
const base::Closure& callback) { const base::Closure& callback) {
net::ProxyConfig config;
config.proxy_rules().ParseFromString(proxy);
auto proxy_service = getter->GetURLRequestContext()->proxy_service(); auto proxy_service = getter->GetURLRequestContext()->proxy_service();
proxy_service->ResetConfigService(new net::ProxyConfigServiceFixed(config)); proxy_service->ResetConfigService(new net::ProxyConfigServiceFixed(config));
// Refetches and applies the new pac script if provided.
proxy_service->ForceReloadProxyConfig();
RunCallbackInUI(callback); RunCallbackInUI(callback);
} }
@ -237,6 +257,8 @@ Session::~Session() {
void Session::OnDownloadCreated(content::DownloadManager* manager, void Session::OnDownloadCreated(content::DownloadManager* manager,
content::DownloadItem* item) { content::DownloadItem* item) {
auto web_contents = item->GetWebContents(); auto web_contents = item->GetWebContents();
if (SavePageHandler::IsSavePageTypes(item->GetMimeType()))
return;
bool prevent_default = Emit( bool prevent_default = Emit(
"will-download", "will-download",
DownloadItem::Create(isolate(), item), DownloadItem::Create(isolate(), item),
@ -284,11 +306,11 @@ void Session::ClearStorageData(mate::Arguments* args) {
base::Time(), base::Time::Max(), callback); base::Time(), base::Time::Max(), callback);
} }
void Session::SetProxy(const std::string& proxy, void Session::SetProxy(const net::ProxyConfig& config,
const base::Closure& callback) { const base::Closure& callback) {
auto getter = browser_context_->GetRequestContext(); auto getter = browser_context_->GetRequestContext();
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&SetProxyInIO, base::Unretained(getter), proxy, callback)); base::Bind(&SetProxyInIO, base::Unretained(getter), config, callback));
} }
void Session::SetDownloadPath(const base::FilePath& path) { void Session::SetDownloadPath(const base::FilePath& path) {
@ -374,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
@ -394,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

@ -23,6 +23,10 @@ class Arguments;
class Dictionary; class Dictionary;
} }
namespace net {
class ProxyConfig;
}
namespace atom { namespace atom {
class AtomBrowserContext; class AtomBrowserContext;
@ -64,7 +68,7 @@ class Session: public mate::TrackableObject<Session>,
void ResolveProxy(const GURL& url, ResolveProxyCallback callback); void ResolveProxy(const GURL& url, ResolveProxyCallback callback);
void ClearCache(const net::CompletionCallback& callback); void ClearCache(const net::CompletionCallback& callback);
void ClearStorageData(mate::Arguments* args); void ClearStorageData(mate::Arguments* args);
void SetProxy(const std::string& proxy, const base::Closure& callback); void SetProxy(const net::ProxyConfig& config, const base::Closure& callback);
void SetDownloadPath(const base::FilePath& path); void SetDownloadPath(const base::FilePath& path);
void EnableNetworkEmulation(const mate::Dictionary& options); void EnableNetworkEmulation(const mate::Dictionary& options);
void DisableNetworkEmulation(); void DisableNetworkEmulation();

View file

@ -74,10 +74,26 @@ void Tray::OnBalloonClosed() {
Emit("balloon-closed"); Emit("balloon-closed");
} }
void Tray::OnDrop() {
Emit("drop");
}
void Tray::OnDropFiles(const std::vector<std::string>& files) { void Tray::OnDropFiles(const std::vector<std::string>& files) {
Emit("drop-files", files); Emit("drop-files", files);
} }
void Tray::OnDragEntered() {
Emit("drag-enter");
}
void Tray::OnDragExited() {
Emit("drag-leave");
}
void Tray::OnDragEnded() {
Emit("drag-end");
}
bool Tray::IsDestroyed() const { bool Tray::IsDestroyed() const {
return !tray_icon_; return !tray_icon_;
} }

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;
@ -48,12 +48,18 @@ class Tray : public mate::EventEmitter,
void OnBalloonShow() override; void OnBalloonShow() override;
void OnBalloonClicked() override; void OnBalloonClicked() override;
void OnBalloonClosed() override; void OnBalloonClosed() override;
void OnDrop() override;
void OnDropFiles(const std::vector<std::string>& files) override; void OnDropFiles(const std::vector<std::string>& files) override;
void OnDragEntered() override;
void OnDragExited() override;
void OnDragEnded() override;
// 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

@ -18,6 +18,7 @@
#include "atom/common/api/event_emitter_caller.h" #include "atom/common/api/event_emitter_caller.h"
#include "atom/common/native_mate_converters/blink_converter.h" #include "atom/common/native_mate_converters/blink_converter.h"
#include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/content_converter.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/gfx_converter.h" #include "atom/common/native_mate_converters/gfx_converter.h"
#include "atom/common/native_mate_converters/gurl_converter.h" #include "atom/common/native_mate_converters/gurl_converter.h"
@ -31,6 +32,7 @@
#include "chrome/browser/printing/print_view_manager_basic.h" #include "chrome/browser/printing/print_view_manager_basic.h"
#include "chrome/browser/printing/print_preview_message_handler.h" #include "chrome/browser/printing/print_preview_message_handler.h"
#include "content/common/view_messages.h" #include "content/common/view_messages.h"
#include "content/public/browser/browser_plugin_guest_manager.h"
#include "content/public/browser/favicon_status.h" #include "content/public/browser/favicon_status.h"
#include "content/public/browser/native_web_keyboard_event.h" #include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/navigation_details.h" #include "content/public/browser/navigation_details.h"
@ -45,12 +47,14 @@
#include "content/public/browser/storage_partition.h" #include "content/public/browser/storage_partition.h"
#include "content/public/browser/site_instance.h" #include "content/public/browser/site_instance.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "content/public/common/context_menu_params.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
#include "native_mate/object_template_builder.h" #include "native_mate/object_template_builder.h"
#include "net/http/http_response_headers.h" #include "net/http/http_response_headers.h"
#include "net/url_request/static_http_user_agent_settings.h" #include "net/url_request/static_http_user_agent_settings.h"
#include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context.h"
#include "third_party/WebKit/public/web/WebInputEvent.h" #include "third_party/WebKit/public/web/WebInputEvent.h"
#include "ui/base/l10n/l10n_util.h"
#include "atom/common/node_includes.h" #include "atom/common/node_includes.h"
@ -62,9 +66,21 @@ struct PrintSettings {
}; };
void SetUserAgentInIO(scoped_refptr<net::URLRequestContextGetter> getter, void SetUserAgentInIO(scoped_refptr<net::URLRequestContextGetter> getter,
std::string accept_lang,
std::string user_agent) { std::string user_agent) {
getter->GetURLRequestContext()->set_http_user_agent_settings( getter->GetURLRequestContext()->set_http_user_agent_settings(
new net::StaticHttpUserAgentSettings("en-us,en", user_agent)); new net::StaticHttpUserAgentSettings(
net::HttpUtil::GenerateAcceptLanguageHeader(accept_lang),
user_agent));
}
bool NotifyZoomLevelChanged(
double level, content::WebContents* guest_web_contents) {
guest_web_contents->SendToAllFrames(
new AtomViewMsg_SetZoomLevel(MSG_ROUTING_NONE, level));
// Return false to iterate over all guests.
return false;
} }
} // namespace } // namespace
@ -133,7 +149,6 @@ struct Converter<net::HttpResponseHeaders*> {
std::string value; std::string value;
while (headers->EnumerateHeaderLines(&iter, &key, &value)) { while (headers->EnumerateHeaderLines(&iter, &key, &value)) {
key = base::StringToLowerASCII(key); key = base::StringToLowerASCII(key);
value = base::StringToLowerASCII(value);
if (response_headers.HasKey(key)) { if (response_headers.HasKey(key)) {
base::ListValue* values = nullptr; base::ListValue* values = nullptr;
if (response_headers.GetList(key, &values)) if (response_headers.GetList(key, &values))
@ -149,6 +164,27 @@ struct Converter<net::HttpResponseHeaders*> {
} }
}; };
template<>
struct Converter<content::SavePageType> {
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
content::SavePageType* out) {
std::string save_type;
if (!ConvertFromV8(isolate, val, &save_type))
return false;
save_type = base::StringToLowerASCII(save_type);
if (save_type == "htmlonly") {
*out = content::SAVE_PAGE_TYPE_AS_ONLY_HTML;
} else if (save_type == "htmlcomplete") {
*out = content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML;
} else if (save_type == "mhtml") {
*out = content::SAVE_PAGE_TYPE_AS_MHTML;
} else {
return false;
}
return true;
}
};
} // namespace mate } // namespace mate
@ -233,9 +269,7 @@ WebContents::WebContents(v8::Isolate* isolate,
managed_web_contents()->GetView()->SetDelegate(this); managed_web_contents()->GetView()->SetDelegate(this);
// Save the preferences in C++. // Save the preferences in C++.
base::DictionaryValue web_preferences; new WebContentsPreferences(web_contents, options);
mate::ConvertFromV8(isolate, options.GetHandle(), &web_preferences);
new WebContentsPreferences(web_contents, &web_preferences);
web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent()); web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
@ -371,6 +405,15 @@ void WebContents::RendererResponsive(content::WebContents* source) {
owner_window()->RendererResponsive(source); owner_window()->RendererResponsive(source);
} }
bool WebContents::HandleContextMenu(const content::ContextMenuParams& params) {
if (!params.custom_context.is_pepper_menu)
return false;
Emit("pepper-context-menu", std::make_pair(params, web_contents()));
web_contents()->NotifyContextMenuClosed(params.custom_context);
return true;
}
void WebContents::BeforeUnloadFired(const base::TimeTicks& proceed_time) { void WebContents::BeforeUnloadFired(const base::TimeTicks& proceed_time) {
// Do nothing, we override this method just to avoid compilation error since // Do nothing, we override this method just to avoid compilation error since
// there are two virtual functions named BeforeUnloadFired. // there are two virtual functions named BeforeUnloadFired.
@ -528,6 +571,7 @@ bool WebContents::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message, OnRendererMessage) IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message, OnRendererMessage)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_Message_Sync, IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_Message_Sync,
OnRendererMessageSync) OnRendererMessageSync)
IPC_MESSAGE_HANDLER(AtomViewHostMsg_ZoomLevelChanged, OnZoomLevelChanged)
IPC_MESSAGE_UNHANDLED(handled = false) IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP() IPC_END_MESSAGE_MAP()
@ -584,6 +628,10 @@ void WebContents::LoadURL(const GURL& url, const mate::Dictionary& options) {
if (options.Get("userAgent", &user_agent)) if (options.Get("userAgent", &user_agent))
SetUserAgent(user_agent); SetUserAgent(user_agent);
std::string extra_headers;
if (options.Get("extraHeaders", &extra_headers))
params.extra_headers = extra_headers;
params.transition_type = ui::PAGE_TRANSITION_TYPED; params.transition_type = ui::PAGE_TRANSITION_TYPED;
params.should_clear_history_list = true; params.should_clear_history_list = true;
params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE; params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE;
@ -637,8 +685,10 @@ void WebContents::SetUserAgent(const std::string& user_agent) {
web_contents()->SetUserAgentOverride(user_agent); web_contents()->SetUserAgentOverride(user_agent);
scoped_refptr<net::URLRequestContextGetter> getter = scoped_refptr<net::URLRequestContextGetter> getter =
web_contents()->GetBrowserContext()->GetRequestContext(); web_contents()->GetBrowserContext()->GetRequestContext();
auto accept_lang = l10n_util::GetApplicationLocale("");
getter->GetNetworkTaskRunner()->PostTask(FROM_HERE, getter->GetNetworkTaskRunner()->PostTask(FROM_HERE,
base::Bind(&SetUserAgentInIO, getter, user_agent)); base::Bind(&SetUserAgentInIO, getter, accept_lang, user_agent));
} }
std::string WebContents::GetUserAgent() { std::string WebContents::GetUserAgent() {
@ -649,6 +699,13 @@ void WebContents::InsertCSS(const std::string& css) {
web_contents()->InsertCSS(css); web_contents()->InsertCSS(css);
} }
bool WebContents::SavePage(const base::FilePath& full_file_path,
const content::SavePageType& save_type,
const SavePageHandler::SavePageCallback& callback) {
auto handler = new SavePageHandler(web_contents(), callback);
return handler->Handle(full_file_path, save_type);
}
void WebContents::ExecuteJavaScript(const base::string16& code, void WebContents::ExecuteJavaScript(const base::string16& code,
bool has_user_gesture) { bool has_user_gesture) {
Send(new AtomViewMsg_ExecuteJavaScript(routing_id(), code, has_user_gesture)); Send(new AtomViewMsg_ExecuteJavaScript(routing_id(), code, has_user_gesture));
@ -960,6 +1017,7 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
.SetMethod("setUserAgent", &WebContents::SetUserAgent) .SetMethod("setUserAgent", &WebContents::SetUserAgent)
.SetMethod("getUserAgent", &WebContents::GetUserAgent) .SetMethod("getUserAgent", &WebContents::GetUserAgent)
.SetMethod("insertCSS", &WebContents::InsertCSS) .SetMethod("insertCSS", &WebContents::InsertCSS)
.SetMethod("savePage", &WebContents::SavePage)
.SetMethod("_executeJavaScript", &WebContents::ExecuteJavaScript) .SetMethod("_executeJavaScript", &WebContents::ExecuteJavaScript)
.SetMethod("openDevTools", &WebContents::OpenDevTools) .SetMethod("openDevTools", &WebContents::OpenDevTools)
.SetMethod("closeDevTools", &WebContents::CloseDevTools) .SetMethod("closeDevTools", &WebContents::CloseDevTools)
@ -1033,6 +1091,15 @@ void WebContents::OnRendererMessageSync(const base::string16& channel,
EmitWithSender(base::UTF16ToUTF8(channel), web_contents(), message, args); EmitWithSender(base::UTF16ToUTF8(channel), web_contents(), message, args);
} }
void WebContents::OnZoomLevelChanged(double level) {
auto manager = web_contents()->GetBrowserContext()->GetGuestManager();
if (!manager)
return;
manager->ForEachGuest(web_contents(),
base::Bind(&NotifyZoomLevelChanged,
level));
}
// static // static
mate::Handle<WebContents> WebContents::CreateFrom( mate::Handle<WebContents> WebContents::CreateFrom(
v8::Isolate* isolate, content::WebContents* web_contents) { v8::Isolate* isolate, content::WebContents* web_contents) {
@ -1055,14 +1122,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
@ -1076,7 +1147,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

@ -9,6 +9,7 @@
#include <vector> #include <vector>
#include "atom/browser/api/frame_subscriber.h" #include "atom/browser/api/frame_subscriber.h"
#include "atom/browser/api/save_page_handler.h"
#include "atom/browser/api/trackable_object.h" #include "atom/browser/api/trackable_object.h"
#include "atom/browser/common_web_contents_delegate.h" #include "atom/browser/common_web_contents_delegate.h"
#include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_observer.h"
@ -73,6 +74,9 @@ class WebContents : public mate::TrackableObject<WebContents>,
void SetUserAgent(const std::string& user_agent); void SetUserAgent(const std::string& user_agent);
std::string GetUserAgent(); std::string GetUserAgent();
void InsertCSS(const std::string& css); void InsertCSS(const std::string& css);
bool SavePage(const base::FilePath& full_file_path,
const content::SavePageType& save_type,
const SavePageHandler::SavePageCallback& callback);
void ExecuteJavaScript(const base::string16& code, void ExecuteJavaScript(const base::string16& code,
bool has_user_gesture); bool has_user_gesture);
void OpenDevTools(mate::Arguments* args); void OpenDevTools(mate::Arguments* args);
@ -185,6 +189,7 @@ class WebContents : public mate::TrackableObject<WebContents>,
void ExitFullscreenModeForTab(content::WebContents* source) override; void ExitFullscreenModeForTab(content::WebContents* source) override;
void RendererUnresponsive(content::WebContents* source) override; void RendererUnresponsive(content::WebContents* source) override;
void RendererResponsive(content::WebContents* source) override; void RendererResponsive(content::WebContents* source) override;
bool HandleContextMenu(const content::ContextMenuParams& params) override;
// content::WebContentsObserver: // content::WebContentsObserver:
void BeforeUnloadFired(const base::TimeTicks& proceed_time) override; void BeforeUnloadFired(const base::TimeTicks& proceed_time) override;
@ -247,6 +252,10 @@ class WebContents : public mate::TrackableObject<WebContents>,
const base::ListValue& args, const base::ListValue& args,
IPC::Message* message); IPC::Message* message);
// Called when guests need to be notified of
// embedders' zoom level change.
void OnZoomLevelChanged(double level);
v8::Global<v8::Value> session_; v8::Global<v8::Value> session_;
v8::Global<v8::Value> devtools_web_contents_; v8::Global<v8::Value> devtools_web_contents_;

View file

@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "atom/browser/api/atom_api_window.h" #include "atom/browser/api/atom_api_window.h"
#include "atom/common/native_mate_converters/value_converter.h"
#include "atom/browser/api/atom_api_menu.h" #include "atom/browser/api/atom_api_menu.h"
#include "atom/browser/api/atom_api_web_contents.h" #include "atom/browser/api/atom_api_web_contents.h"
@ -60,11 +61,71 @@ void OnCapturePageDone(
callback.Run(gfx::Image::CreateFrom1xBitmap(bitmap)); callback.Run(gfx::Image::CreateFrom1xBitmap(bitmap));
} }
// Converts min-width to minWidth, returns false if no conversion is needed.
bool TranslateOldKey(const std::string& key, std::string* new_key) {
if (key.find('-') == std::string::npos)
return false;
new_key->reserve(key.size());
bool next_upper_case = false;
for (char c : key) {
if (c == '-') {
next_upper_case = true;
} else if (next_upper_case) {
new_key->push_back(base::ToUpperASCII(c));
next_upper_case = false;
} else {
new_key->push_back(c);
}
}
return true;
}
// Converts min-width to minWidth recursively in the dictionary.
void TranslateOldOptions(v8::Isolate* isolate, v8::Local<v8::Object> options) {
auto context = isolate->GetCurrentContext();
auto maybe_keys = options->GetOwnPropertyNames(context);
if (maybe_keys.IsEmpty())
return;
std::vector<std::string> keys;
if (!mate::ConvertFromV8(isolate, maybe_keys.ToLocalChecked(), &keys))
return;
mate::Dictionary dict(isolate, options);
for (const auto& key : keys) {
v8::Local<v8::Value> value;
if (!dict.Get(key, &value)) // Shouldn't happen, but guard it anyway.
continue;
// Go recursively.
v8::Local<v8::Object> sub_options;
if (mate::ConvertFromV8(isolate, value, &sub_options))
TranslateOldOptions(isolate, sub_options);
// Translate key.
std::string new_key;
if (TranslateOldKey(key, &new_key)) {
dict.Set(new_key, value);
dict.Delete(key);
}
}
}
#if defined(OS_WIN)
// Converts binary data to Buffer.
v8::Local<v8::Value> ToBuffer(v8::Isolate* isolate, void* val, int size) {
auto buffer = node::Buffer::New(isolate, static_cast<char*>(val), size);
if (buffer.IsEmpty())
return v8::Null(isolate);
else
return buffer.ToLocalChecked();
}
#endif
} // namespace } // namespace
Window::Window(v8::Isolate* isolate, const mate::Dictionary& options) { Window::Window(v8::Isolate* isolate, const mate::Dictionary& options) {
// Use options['web-preferences'] to create WebContents. // Be compatible with old style field names like min-width.
TranslateOldOptions(isolate, options.GetHandle());
// Use options.webPreferences to create WebContents.
mate::Dictionary web_preferences = mate::Dictionary::CreateEmpty(isolate); mate::Dictionary web_preferences = mate::Dictionary::CreateEmpty(isolate);
options.Get(switches::kWebPreferences, &web_preferences); options.Get(switches::kWebPreferences, &web_preferences);
@ -189,6 +250,16 @@ void Window::OnExecuteWindowsCommand(const std::string& command_name) {
Emit("app-command", command_name); Emit("app-command", command_name);
} }
#if defined(OS_WIN)
void Window::OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) {
if (IsWindowMessageHooked(message)) {
messages_callback_map_[message].Run(
ToBuffer(isolate(), static_cast<void*>(&w_param), sizeof(WPARAM)),
ToBuffer(isolate(), static_cast<void*>(&l_param), sizeof(LPARAM)));
}
}
#endif
// static // static
mate::Wrappable* Window::New(v8::Isolate* isolate, mate::Wrappable* Window::New(v8::Isolate* isolate,
const mate::Dictionary& options) { const mate::Dictionary& options) {
@ -385,6 +456,10 @@ bool Window::IsKiosk() {
return window_->IsKiosk(); return window_->IsKiosk();
} }
void Window::SetBackgroundColor(const std::string& color_name) {
window_->SetBackgroundColor(color_name);
}
void Window::FocusOnWebView() { void Window::FocusOnWebView() {
window_->FocusOnWebView(); window_->FocusOnWebView();
} }
@ -488,6 +563,29 @@ bool Window::IsMenuBarVisible() {
return window_->IsMenuBarVisible(); return window_->IsMenuBarVisible();
} }
#if defined(OS_WIN)
bool Window::HookWindowMessage(UINT message,
const MessageCallback& callback) {
messages_callback_map_[message] = callback;
return true;
}
void Window::UnhookWindowMessage(UINT message) {
if (!ContainsKey(messages_callback_map_, message))
return;
messages_callback_map_.erase(message);
}
bool Window::IsWindowMessageHooked(UINT message) {
return ContainsKey(messages_callback_map_, message);
}
void Window::UnhookAllWindowMessages() {
messages_callback_map_.clear();
}
#endif
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
void Window::ShowDefinitionForSelection() { void Window::ShowDefinitionForSelection() {
window_->ShowDefinitionForSelection(); window_->ShowDefinitionForSelection();
@ -564,6 +662,7 @@ void Window::BuildPrototype(v8::Isolate* isolate,
.SetMethod("setSkipTaskbar", &Window::SetSkipTaskbar) .SetMethod("setSkipTaskbar", &Window::SetSkipTaskbar)
.SetMethod("setKiosk", &Window::SetKiosk) .SetMethod("setKiosk", &Window::SetKiosk)
.SetMethod("isKiosk", &Window::IsKiosk) .SetMethod("isKiosk", &Window::IsKiosk)
.SetMethod("setBackgroundColor", &Window::SetBackgroundColor)
.SetMethod("setRepresentedFilename", &Window::SetRepresentedFilename) .SetMethod("setRepresentedFilename", &Window::SetRepresentedFilename)
.SetMethod("getRepresentedFilename", &Window::GetRepresentedFilename) .SetMethod("getRepresentedFilename", &Window::GetRepresentedFilename)
.SetMethod("setDocumentEdited", &Window::SetDocumentEdited) .SetMethod("setDocumentEdited", &Window::SetDocumentEdited)
@ -585,6 +684,12 @@ void Window::BuildPrototype(v8::Isolate* isolate,
&Window::SetVisibleOnAllWorkspaces) &Window::SetVisibleOnAllWorkspaces)
.SetMethod("isVisibleOnAllWorkspaces", .SetMethod("isVisibleOnAllWorkspaces",
&Window::IsVisibleOnAllWorkspaces) &Window::IsVisibleOnAllWorkspaces)
#if defined(OS_WIN)
.SetMethod("hookWindowMessage", &Window::HookWindowMessage)
.SetMethod("isWindowMessageHooked", &Window::IsWindowMessageHooked)
.SetMethod("unhookWindowMessage", &Window::UnhookWindowMessage)
.SetMethod("unhookAllWindowMessages", &Window::UnhookAllWindowMessages)
#endif
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
.SetMethod("showDefinitionForSelection", .SetMethod("showDefinitionForSelection",
&Window::ShowDefinitionForSelection) &Window::ShowDefinitionForSelection)

View file

@ -5,6 +5,7 @@
#ifndef ATOM_BROWSER_API_ATOM_API_WINDOW_H_ #ifndef ATOM_BROWSER_API_ATOM_API_WINDOW_H_
#define ATOM_BROWSER_API_ATOM_API_WINDOW_H_ #define ATOM_BROWSER_API_ATOM_API_WINDOW_H_
#include <map>
#include <string> #include <string>
#include <vector> #include <vector>
@ -75,6 +76,10 @@ class Window : public mate::TrackableObject<Window>,
void OnRendererResponsive() override; void OnRendererResponsive() override;
void OnExecuteWindowsCommand(const std::string& command_name) override; void OnExecuteWindowsCommand(const std::string& command_name) override;
#if defined(OS_WIN)
void OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) override;
#endif
// mate::Wrappable: // mate::Wrappable:
bool IsDestroyed() const override; bool IsDestroyed() const override;
@ -122,6 +127,7 @@ class Window : public mate::TrackableObject<Window>,
void SetSkipTaskbar(bool skip); void SetSkipTaskbar(bool skip);
void SetKiosk(bool kiosk); void SetKiosk(bool kiosk);
bool IsKiosk(); bool IsKiosk();
void SetBackgroundColor(const std::string& color_name);
void FocusOnWebView(); void FocusOnWebView();
void BlurWebView(); void BlurWebView();
bool IsWebViewFocused(); bool IsWebViewFocused();
@ -142,6 +148,16 @@ class Window : public mate::TrackableObject<Window>,
bool IsMenuBarVisible(); bool IsMenuBarVisible();
void SetAspectRatio(double aspect_ratio, mate::Arguments* args); void SetAspectRatio(double aspect_ratio, mate::Arguments* args);
#if defined(OS_WIN)
typedef base::Callback<void(v8::Local<v8::Value>,
v8::Local<v8::Value>)> MessageCallback;
bool HookWindowMessage(UINT message, const MessageCallback& callback);
bool IsWindowMessageHooked(UINT message);
void UnhookWindowMessage(UINT message);
void UnhookAllWindowMessages();
#endif
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
void ShowDefinitionForSelection(); void ShowDefinitionForSelection();
#endif #endif
@ -152,6 +168,11 @@ class Window : public mate::TrackableObject<Window>,
int32_t ID() const; int32_t ID() const;
v8::Local<v8::Value> WebContents(v8::Isolate* isolate); v8::Local<v8::Value> WebContents(v8::Isolate* isolate);
#if defined(OS_WIN)
typedef std::map<UINT, MessageCallback> MessageCallbackMap;
MessageCallbackMap messages_callback_map_;
#endif
v8::Global<v8::Value> web_contents_; v8::Global<v8::Value> web_contents_;
v8::Global<v8::Value> menu_; v8::Global<v8::Value> menu_;

View file

@ -1,3 +1,4 @@
deprecate = require 'deprecate'
EventEmitter = require('events').EventEmitter EventEmitter = require('events').EventEmitter
bindings = process.atomBinding 'app' bindings = process.atomBinding 'app'
@ -7,19 +8,6 @@ downloadItemBindings = process.atomBinding 'download_item'
app = bindings.app app = bindings.app
app.__proto__ = EventEmitter.prototype app.__proto__ = EventEmitter.prototype
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
# 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()
app.setApplicationMenu = (menu) -> app.setApplicationMenu = (menu) ->
require('menu').setApplicationMenu menu require('menu').setApplicationMenu menu
@ -47,22 +35,38 @@ app.setAppPath = (path) ->
app.getAppPath = -> app.getAppPath = ->
appPath appPath
# Be compatible with old API. # Helpers.
app.once 'ready', -> @emit 'finish-launching' app.resolveProxy = (url, callback) -> @defaultSession.resolveProxy url, callback
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. # Deprecated.
app.getHomeDir = deprecate 'app.getHomeDir', 'app.getPath', ->
@getPath 'home'
app.getDataPath = deprecate 'app.getDataPath', 'app.getPath', ->
@getPath 'userData'
app.setDataPath = deprecate 'app.setDataPath', 'app.setPath', (path) ->
@setPath 'userData', path
deprecate.rename app, 'terminate', 'quit'
deprecate.event app, 'finish-launching', 'ready', ->
setImmediate => # give default app a chance to setup default menu.
@emit 'finish-launching'
deprecate.event app, 'activate-with-no-open-windows', 'activate', (event, hasVisibleWindows) ->
@emit 'activate-with-no-open-windows' if not hasVisibleWindows
# Wrappers for native classes.
wrapSession = (session) ->
# session is an EventEmitter.
session.__proto__ = EventEmitter.prototype
sessionBindings._setWrapSession wrapSession sessionBindings._setWrapSession wrapSession
process.once 'exit', sessionBindings._clearWrapSession
wrapDownloadItem = (downloadItem) ->
# downloadItem is an EventEmitter.
downloadItem.__proto__ = EventEmitter.prototype
# Deprecated.
deprecate.property downloadItem, 'url', 'getUrl'
deprecate.property downloadItem, 'filename', 'getFilename'
deprecate.property downloadItem, 'mimeType', 'getMimeType'
deprecate.property downloadItem, 'hasUserGesture', 'hasUserGesture'
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

@ -1,6 +0,0 @@
module.exports =
browserMainParts:
preMainMessageLoopRun: ->
setImmediate ->
module.exports.browserMainParts.preMainMessageLoopRun()

View file

@ -1,24 +1,7 @@
autoUpdater = process.atomBinding('auto_updater').autoUpdater switch process.platform
EventEmitter = require('events').EventEmitter when 'win32'
module.exports = require './auto-updater/auto-updater-win'
autoUpdater.__proto__ = EventEmitter.prototype when 'darwin'
module.exports = require './auto-updater/auto-updater-mac'
autoUpdater.on 'update-downloaded-raw', (args...) -> else
args[3] = new Date(args[3]) # releaseDate throw new Error('auto-updater is not implemented on this platform')
@emit 'update-downloaded', args..., => @quitAndInstall()
autoUpdater.quitAndInstall = ->
# If we don't have any window then quitAndInstall immediately.
BrowserWindow = require 'browser-window'
windows = BrowserWindow.getAllWindows()
if windows.length is 0
@_quitAndInstall()
return
# Do the restart after all windows have been closed.
app = require 'app'
app.removeAllListeners 'window-all-closed'
app.once 'window-all-closed', @_quitAndInstall.bind(this)
win.close() for win in windows
module.exports = autoUpdater

View file

@ -0,0 +1,6 @@
{EventEmitter} = require 'events'
{autoUpdater} = process.atomBinding 'auto_updater'
autoUpdater.__proto__ = EventEmitter.prototype
module.exports = autoUpdater

View file

@ -0,0 +1,42 @@
app = require 'app'
url = require 'url'
{EventEmitter} = require 'events'
squirrelUpdate = require './squirrel-update-win'
class AutoUpdater extends EventEmitter
quitAndInstall: ->
squirrelUpdate.processStart()
app.quit()
setFeedUrl: (updateUrl) ->
@updateUrl = updateUrl
checkForUpdates: ->
return @emitError 'Update URL is not set' unless @updateUrl
return @emitError 'Can not find Squirrel' unless squirrelUpdate.supported()
@emit 'checking-for-update'
squirrelUpdate.download @updateUrl, (error, update) =>
return @emitError error if error?
return @emit 'update-not-available' unless update?
@emit 'update-available'
squirrelUpdate.update @updateUrl, (error) =>
return @emitError error if error?
{releaseNotes, version} = update
# Following information is not available on Windows, so fake them.
date = new Date
url = @updateUrl
@emit 'update-downloaded', {}, releaseNotes, version, date, url, => @quitAndInstall()
# Private: Emit both error object and message, this is to keep compatibility
# with Old APIs.
emitError: (message) ->
@emit 'error', new Error(message), message
module.exports = new AutoUpdater

View file

@ -0,0 +1,67 @@
fs = require 'fs'
path = require 'path'
{spawn} = require 'child_process'
appFolder = path.dirname process.execPath # i.e. my-app/app-0.1.13/
updateExe = path.resolve appFolder, '..', 'Update.exe' # i.e. my-app/Update.exe
exeName = path.basename process.execPath
# Spawn a command and invoke the callback when it completes with an error
# and the output from standard out.
spawnUpdate = (args, detached, callback) ->
try
spawnedProcess = spawn updateExe, args, {detached}
catch error
# Shouldn't happen, but still guard it.
process.nextTick -> callback error
return
stdout = ''
stderr = ''
spawnedProcess.stdout.on 'data', (data) -> stdout += data
spawnedProcess.stderr.on 'data', (data) -> stderr += data
errorEmitted = false
spawnedProcess.on 'error', (error) ->
errorEmitted = true
callback error
spawnedProcess.on 'exit', (code, signal) ->
# We may have already emitted an error.
return if errorEmitted
# Process terminated with error.
if code isnt 0
return callback "Command failed: #{signal ? code}\n#{stderr}"
# Success.
callback null, stdout
# Start an instance of the installed app.
exports.processStart = (callback) ->
spawnUpdate ['--processStart', exeName], true, ->
# Download the releases specified by the URL and write new results to stdout.
exports.download = (updateUrl, callback) ->
spawnUpdate ['--download', updateUrl], false, (error, stdout) ->
return callback(error) if error?
try
# Last line of output is the JSON details about the releases
json = stdout.trim().split('\n').pop()
update = JSON.parse(json)?.releasesToApply?.pop?()
catch
return callback "Invalid result:\n#{stdout}"
callback null, update
# Update the application to the latest remote version specified by URL.
exports.update = (updateUrl, callback) ->
spawnUpdate ['--update', updateUrl], false, callback
# Is the Update.exe installed with the current application?
exports.supported = ->
try
fs.accessSync updateExe, fs.R_OK
return true
catch
return false

View file

@ -1,6 +1,7 @@
EventEmitter = require('events').EventEmitter EventEmitter = require('events').EventEmitter
app = require 'app' app = require 'app'
ipc = require 'ipc' ipc = require 'ipc-main'
deprecate = require 'deprecate'
BrowserWindow = process.atomBinding('window').BrowserWindow BrowserWindow = process.atomBinding('window').BrowserWindow
BrowserWindow::__proto__ = EventEmitter.prototype BrowserWindow::__proto__ = EventEmitter.prototype
@ -71,32 +72,32 @@ BrowserWindow.fromDevToolsWebContents = (webContents) ->
# Helpers. # Helpers.
BrowserWindow::loadUrl = -> @webContents.loadUrl.apply @webContents, arguments BrowserWindow::loadUrl = -> @webContents.loadUrl.apply @webContents, arguments
BrowserWindow::send = -> @webContents.send.apply @webContents, arguments
# Be compatible with old API.
BrowserWindow::undo = -> @webContents.undo()
BrowserWindow::redo = -> @webContents.redo()
BrowserWindow::cut = -> @webContents.cut()
BrowserWindow::copy = -> @webContents.copy()
BrowserWindow::paste = -> @webContents.paste()
BrowserWindow::selectAll = -> @webContents.selectAll()
BrowserWindow::restart = -> @webContents.reload()
BrowserWindow::getUrl = -> @webContents.getUrl()
BrowserWindow::reload = -> @webContents.reload.apply @webContents, arguments BrowserWindow::reload = -> @webContents.reload.apply @webContents, arguments
BrowserWindow::reloadIgnoringCache = -> @webContents.reloadIgnoringCache.apply @webContents, arguments BrowserWindow::send = -> @webContents.send.apply @webContents, arguments
BrowserWindow::getPageTitle = -> @webContents.getTitle()
BrowserWindow::isLoading = -> @webContents.isLoading()
BrowserWindow::isWaitingForResponse = -> @webContents.isWaitingForResponse()
BrowserWindow::stop = -> @webContents.stop()
BrowserWindow::isCrashed = -> @webContents.isCrashed()
BrowserWindow::executeJavaScriptInDevTools = (code) -> @devToolsWebContents?.executeJavaScript code
BrowserWindow::openDevTools = -> @webContents.openDevTools.apply @webContents, arguments BrowserWindow::openDevTools = -> @webContents.openDevTools.apply @webContents, arguments
BrowserWindow::closeDevTools = -> @webContents.closeDevTools() BrowserWindow::closeDevTools = -> @webContents.closeDevTools()
BrowserWindow::isDevToolsOpened = -> @webContents.isDevToolsOpened() BrowserWindow::isDevToolsOpened = -> @webContents.isDevToolsOpened()
BrowserWindow::toggleDevTools = -> @webContents.toggleDevTools() BrowserWindow::toggleDevTools = -> @webContents.toggleDevTools()
BrowserWindow::inspectElement = -> @webContents.inspectElement.apply @webContents, arguments BrowserWindow::inspectElement = -> @webContents.inspectElement.apply @webContents, arguments
BrowserWindow::inspectServiceWorker = -> @webContents.inspectServiceWorker() BrowserWindow::inspectServiceWorker = -> @webContents.inspectServiceWorker()
BrowserWindow::print = -> @webContents.print.apply @webContents, arguments
BrowserWindow::printToPDF = -> @webContents.printToPDF.apply @webContents, arguments # Deprecated.
deprecate.rename BrowserWindow, 'restart', 'reload'
deprecate.member BrowserWindow, 'undo', 'webContents'
deprecate.member BrowserWindow, 'redo', 'webContents'
deprecate.member BrowserWindow, 'cut', 'webContents'
deprecate.member BrowserWindow, 'copy', 'webContents'
deprecate.member BrowserWindow, 'paste', 'webContents'
deprecate.member BrowserWindow, 'selectAll', 'webContents'
deprecate.member BrowserWindow, 'getUrl', 'webContents'
deprecate.member BrowserWindow, 'reloadIgnoringCache', 'webContents'
deprecate.member BrowserWindow, 'getPageTitle', 'webContents'
deprecate.member BrowserWindow, 'isLoading', 'webContents'
deprecate.member BrowserWindow, 'isWaitingForResponse', 'webContents'
deprecate.member BrowserWindow, 'stop', 'webContents'
deprecate.member BrowserWindow, 'isCrashed', 'webContents'
deprecate.member BrowserWindow, 'executeJavaScriptInDevTools', 'webContents'
deprecate.member BrowserWindow, 'print', 'webContents'
deprecate.member BrowserWindow, 'printToPDF', 'webContents'
module.exports = BrowserWindow module.exports = BrowserWindow

View file

@ -0,0 +1,3 @@
{EventEmitter} = require 'events'
module.exports = new EventEmitter

View file

@ -1,3 +1,6 @@
EventEmitter = require('events').EventEmitter deprecate = require 'deprecate'
module.exports = new EventEmitter # This module is deprecated, we mirror everything from ipcMain.
deprecate.warn 'ipc module', 'ipcMain module'
module.exports = require 'ipc-main'

View file

@ -1,4 +1,4 @@
ipc = require 'ipc' ipc = require 'ipc-main'
# The history operation in renderer is redirected to browser. # The history operation in renderer is redirected to browser.
ipc.on 'ATOM_SHELL_NAVIGATION_CONTROLLER', (event, method, args...) -> ipc.on 'ATOM_SHELL_NAVIGATION_CONTROLLER', (event, method, args...) ->

View file

@ -1,7 +1,8 @@
EventEmitter = require('events').EventEmitter EventEmitter = require('events').EventEmitter
Menu = require './menu'
NavigationController = require './navigation-controller' NavigationController = require './navigation-controller'
binding = process.atomBinding 'web_contents' binding = process.atomBinding 'web_contents'
ipc = require 'ipc' ipc = require 'ipc-main'
nextId = 0 nextId = 0
getNextId = -> ++nextId getNextId = -> ++nextId
@ -65,6 +66,11 @@ wrapWebContents = (webContents) ->
Object.defineProperty event, 'returnValue', set: (value) -> event.sendReply JSON.stringify(value) Object.defineProperty event, 'returnValue', set: (value) -> event.sendReply JSON.stringify(value)
ipc.emit channel, event, args... ipc.emit channel, event, args...
# Handle context menu action request from pepper plugin.
webContents.on 'pepper-context-menu', (event, params) ->
menu = Menu.buildFromTemplate params.menu
menu.popup params.x, params.y
webContents.printToPDF = (options, callback) -> webContents.printToPDF = (options, callback) ->
printingSetting = printingSetting =
pageRage: [] pageRage: []
@ -106,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

@ -0,0 +1,83 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/api/save_page_handler.h"
#include <string>
#include "atom/browser/atom_browser_context.h"
#include "base/callback.h"
#include "base/files/file_path.h"
#include "content/public/browser/web_contents.h"
namespace atom {
namespace api {
SavePageHandler::SavePageHandler(content::WebContents* web_contents,
const SavePageCallback& callback)
: web_contents_(web_contents),
callback_(callback) {
}
SavePageHandler::~SavePageHandler() {
}
void SavePageHandler::OnDownloadCreated(content::DownloadManager* manager,
content::DownloadItem* item) {
// OnDownloadCreated is invoked during WebContents::SavePage, so the |item|
// here is the one stated by WebContents::SavePage.
item->AddObserver(this);
}
bool SavePageHandler::Handle(const base::FilePath& full_path,
const content::SavePageType& save_type) {
auto download_manager = content::BrowserContext::GetDownloadManager(
web_contents_->GetBrowserContext());
download_manager->AddObserver(this);
// Chromium will create a 'foo_files' directory under the directory of saving
// page 'foo.html' for holding other resource files of 'foo.html'.
base::FilePath saved_main_directory_path = full_path.DirName().Append(
full_path.RemoveExtension().BaseName().value() +
FILE_PATH_LITERAL("_files"));
bool result = web_contents_->SavePage(full_path,
saved_main_directory_path,
save_type);
download_manager->RemoveObserver(this);
// If initialization fails which means fail to create |DownloadItem|, we need
// to delete the |SavePageHandler| instance to avoid memory-leak.
if (!result)
delete this;
return result;
}
void SavePageHandler::OnDownloadUpdated(content::DownloadItem* item) {
if (item->IsDone()) {
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
if (item->GetState() == content::DownloadItem::COMPLETE) {
callback_.Run(v8::Null(isolate));
} else {
v8::Local<v8::String> error_message = v8::String::NewFromUtf8(
isolate, "Fail to save page");
callback_.Run(v8::Exception::Error(error_message));
}
Destroy(item);
}
}
void SavePageHandler::Destroy(content::DownloadItem* item) {
item->RemoveObserver(this);
delete this;
}
// static
bool SavePageHandler::IsSavePageTypes(const std::string& type) {
return type == "multipart/related" || type == "text/html";
}
} // namespace api
} // namespace atom

View file

@ -0,0 +1,60 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_API_SAVE_PAGE_HANDLER_H_
#define ATOM_BROWSER_API_SAVE_PAGE_HANDLER_H_
#include <string>
#include "content/public/browser/download_item.h"
#include "content/public/browser/download_manager.h"
#include "content/public/browser/save_page_type.h"
#include "v8/include/v8.h"
namespace base {
class FilePath;
}
namespace content {
class WebContents;
}
namespace atom {
namespace api {
// A self-destroyed class for handling save page request.
class SavePageHandler : public content::DownloadManager::Observer,
public content::DownloadItem::Observer {
public:
using SavePageCallback = base::Callback<void(v8::Local<v8::Value>)>;
SavePageHandler(content::WebContents* web_contents,
const SavePageCallback& callback);
~SavePageHandler();
bool Handle(const base::FilePath& full_path,
const content::SavePageType& save_type);
static bool IsSavePageTypes(const std::string& type);
private:
void Destroy(content::DownloadItem* item);
// content::DownloadManager::Observer:
void OnDownloadCreated(content::DownloadManager* manager,
content::DownloadItem* item) override;
// content::DownloadItem::Observer:
void OnDownloadUpdated(content::DownloadItem* item) override;
content::WebContents* web_contents_; // weak
SavePageCallback callback_;
};
} // namespace api
} // namespace atom
#endif // ATOM_BROWSER_API_SAVE_PAGE_HANDLER_H_

View file

@ -60,7 +60,8 @@ std::string RemoveWhitespace(const std::string& str) {
AtomBrowserContext::AtomBrowserContext(const std::string& partition, AtomBrowserContext::AtomBrowserContext(const std::string& partition,
bool in_memory) bool in_memory)
: brightray::BrowserContext(partition, in_memory), : brightray::BrowserContext(partition, in_memory),
job_factory_(new AtomURLRequestJobFactory) { job_factory_(new AtomURLRequestJobFactory),
allow_ntlm_everywhere_(false) {
} }
AtomBrowserContext::~AtomBrowserContext() { AtomBrowserContext::~AtomBrowserContext() {
@ -168,6 +169,16 @@ void AtomBrowserContext::RegisterPrefs(PrefRegistrySimple* pref_registry) {
base::FilePath()); base::FilePath());
} }
bool AtomBrowserContext::AllowNTLMCredentialsForDomain(const GURL& origin) {
if (allow_ntlm_everywhere_)
return true;
return Delegate::AllowNTLMCredentialsForDomain(origin);
}
void AtomBrowserContext::AllowNTLMCredentialsForAllDomains(bool should_allow) {
allow_ntlm_everywhere_ = should_allow;
}
} // namespace atom } // namespace atom
namespace brightray { namespace brightray {

View file

@ -28,6 +28,7 @@ class AtomBrowserContext : public brightray::BrowserContext {
net::HttpCache::BackendFactory* CreateHttpCacheBackendFactory( net::HttpCache::BackendFactory* CreateHttpCacheBackendFactory(
const base::FilePath& base_path) override; const base::FilePath& base_path) override;
net::SSLConfigService* CreateSSLConfigService() override; net::SSLConfigService* CreateSSLConfigService() override;
bool AllowNTLMCredentialsForDomain(const GURL& auth_origin) override;
// content::BrowserContext: // content::BrowserContext:
content::DownloadManagerDelegate* GetDownloadManagerDelegate() override; content::DownloadManagerDelegate* GetDownloadManagerDelegate() override;
@ -36,6 +37,8 @@ class AtomBrowserContext : public brightray::BrowserContext {
// brightray::BrowserContext: // brightray::BrowserContext:
void RegisterPrefs(PrefRegistrySimple* pref_registry) override; void RegisterPrefs(PrefRegistrySimple* pref_registry) override;
void AllowNTLMCredentialsForAllDomains(bool should_allow);
AtomURLRequestJobFactory* job_factory() const { return job_factory_; } AtomURLRequestJobFactory* job_factory() const { return job_factory_; }
private: private:
@ -45,6 +48,8 @@ class AtomBrowserContext : public brightray::BrowserContext {
// Managed by brightray::BrowserContext. // Managed by brightray::BrowserContext.
AtomURLRequestJobFactory* job_factory_; AtomURLRequestJobFactory* job_factory_;
bool allow_ntlm_everywhere_;
DISALLOW_COPY_AND_ASSIGN(AtomBrowserContext); DISALLOW_COPY_AND_ASSIGN(AtomBrowserContext);
}; };

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);
@ -62,17 +71,15 @@ void AtomBrowserMainParts::PreEarlyInitialization() {
void AtomBrowserMainParts::PostEarlyInitialization() { void AtomBrowserMainParts::PostEarlyInitialization() {
brightray::BrowserMainParts::PostEarlyInitialization(); brightray::BrowserMainParts::PostEarlyInitialization();
{ // Temporary set the bridge_task_runner_ as current thread's task runner,
// Temporary set the bridge_task_runner_ as current thread's task runner, // so we can fool gin::PerIsolateData to use it as its task runner, instead
// so we can fool gin::PerIsolateData to use it as its task runner, instead // of getting current message loop's task runner, which is null for now.
// of getting current message loop's task runner, which is null for now. bridge_task_runner_ = new BridgeTaskRunner;
bridge_task_runner_ = new BridgeTaskRunner; base::ThreadTaskRunnerHandle handle(bridge_task_runner_);
base::ThreadTaskRunnerHandle handle(bridge_task_runner_);
// The ProxyResolverV8 has setup a complete V8 environment, in order to // The ProxyResolverV8 has setup a complete V8 environment, in order to
// avoid conflicts we only initialize our V8 environment after that. // avoid conflicts we only initialize our V8 environment after that.
js_env_.reset(new JavascriptEnvironment); js_env_.reset(new JavascriptEnvironment);
}
node_bindings_->Initialize(); node_bindings_->Initialize();
@ -107,6 +114,7 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() {
1000)); 1000));
brightray::BrowserMainParts::PreMainMessageLoopRun(); brightray::BrowserMainParts::PreMainMessageLoopRun();
BridgeTaskRunner::MessageLoopIsReady();
#if defined(USE_X11) #if defined(USE_X11)
libgtk2ui::GtkInitFromCommandLine(*base::CommandLine::ForCurrentProcess()); libgtk2ui::GtkInitFromCommandLine(*base::CommandLine::ForCurrentProcess());
@ -119,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)
@ -129,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

@ -4,6 +4,7 @@
#include "atom/browser/atom_resource_dispatcher_host_delegate.h" #include "atom/browser/atom_resource_dispatcher_host_delegate.h"
#include "atom/browser/login_handler.h"
#include "atom/common/platform_util.h" #include "atom/common/platform_util.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "net/base/escape.h" #include "net/base/escape.h"
@ -29,4 +30,11 @@ bool AtomResourceDispatcherHostDelegate::HandleExternalProtocol(
return true; return true;
} }
content::ResourceDispatcherHostLoginDelegate*
AtomResourceDispatcherHostDelegate::CreateLoginDelegate(
net::AuthChallengeInfo* auth_info,
net::URLRequest* request) {
return new LoginHandler(auth_info, request);
}
} // namespace atom } // namespace atom

View file

@ -21,6 +21,9 @@ class AtomResourceDispatcherHostDelegate
bool is_main_frame, bool is_main_frame,
ui::PageTransition transition, ui::PageTransition transition,
bool has_user_gesture) override; bool has_user_gesture) override;
content::ResourceDispatcherHostLoginDelegate* CreateLoginDelegate(
net::AuthChallengeInfo* auth_info,
net::URLRequest* request) override;
}; };
} // namespace atom } // namespace atom

View file

@ -5,11 +5,14 @@
#include "atom/browser/atom_ssl_config_service.h" #include "atom/browser/atom_ssl_config_service.h"
#include <string> #include <string>
#include <vector>
#include "base/command_line.h" #include "base/command_line.h"
#include "base/strings/string_split.h"
#include "atom/common/options_switches.h" #include "atom/common/options_switches.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "net/socket/ssl_client_socket.h" #include "net/socket/ssl_client_socket.h"
#include "net/ssl/ssl_cipher_suite_names.h"
namespace atom { namespace atom {
@ -26,6 +29,23 @@ uint16 GetSSLProtocolVersion(const std::string& version_string) {
return version; return version;
} }
std::vector<uint16> ParseCipherSuites(
const std::vector<std::string>& cipher_strings) {
std::vector<uint16> cipher_suites;
cipher_suites.reserve(cipher_strings.size());
for (auto& cipher_string : cipher_strings) {
uint16 cipher_suite = 0;
if (!net::ParseSSLCipherString(cipher_string, &cipher_suite)) {
LOG(ERROR) << "Ignoring unrecognised cipher suite : "
<< cipher_string;
continue;
}
cipher_suites.push_back(cipher_suite);
}
return cipher_suites;
}
} // namespace } // namespace
AtomSSLConfigService::AtomSSLConfigService() { AtomSSLConfigService::AtomSSLConfigService() {
@ -35,6 +55,13 @@ AtomSSLConfigService::AtomSSLConfigService() {
cmd_line->GetSwitchValueASCII(switches::kSSLVersionFallbackMin); cmd_line->GetSwitchValueASCII(switches::kSSLVersionFallbackMin);
config_.version_fallback_min = GetSSLProtocolVersion(version_string); config_.version_fallback_min = GetSSLProtocolVersion(version_string);
} }
if (cmd_line->HasSwitch(switches::kCipherSuiteBlacklist)) {
auto cipher_strings = base::SplitString(
cmd_line->GetSwitchValueASCII(switches::kCipherSuiteBlacklist),
",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
config_.disabled_cipher_suites = ParseCipherSuites(cipher_strings);
}
} }
AtomSSLConfigService::~AtomSSLConfigService() { AtomSSLConfigService::~AtomSSLConfigService() {

View file

@ -6,14 +6,25 @@
namespace auto_updater { namespace auto_updater {
AutoUpdaterDelegate* AutoUpdater::delegate_ = NULL; Delegate* AutoUpdater::delegate_ = nullptr;
AutoUpdaterDelegate* AutoUpdater::GetDelegate() { Delegate* AutoUpdater::GetDelegate() {
return delegate_; return delegate_;
} }
void AutoUpdater::SetDelegate(AutoUpdaterDelegate* delegate) { void AutoUpdater::SetDelegate(Delegate* delegate) {
delegate_ = delegate; delegate_ = delegate;
} }
#if !defined(OS_MACOSX) || defined(MAS_BUILD)
void AutoUpdater::SetFeedURL(const std::string& url) {
}
void AutoUpdater::CheckForUpdates() {
}
void AutoUpdater::QuitAndInstall() {
}
#endif
} // namespace auto_updater } // namespace auto_updater

View file

@ -9,21 +9,48 @@
#include "base/basictypes.h" #include "base/basictypes.h"
namespace base {
class Time;
}
namespace auto_updater { namespace auto_updater {
class AutoUpdaterDelegate; class Delegate {
public:
// An error happened.
virtual void OnError(const std::string& error) {}
// Checking to see if there is an update
virtual void OnCheckingForUpdate() {}
// There is an update available and it is being downloaded
virtual void OnUpdateAvailable() {}
// There is no available update.
virtual void OnUpdateNotAvailable() {}
// There is a new update which has been downloaded.
virtual void OnUpdateDownloaded(const std::string& release_notes,
const std::string& release_name,
const base::Time& release_date,
const std::string& update_url) {}
protected:
virtual ~Delegate() {}
};
class AutoUpdater { class AutoUpdater {
public: public:
// Gets/Sets the delegate. // Gets/Sets the delegate.
static AutoUpdaterDelegate* GetDelegate(); static Delegate* GetDelegate();
static void SetDelegate(AutoUpdaterDelegate* delegate); static void SetDelegate(Delegate* delegate);
static void SetFeedURL(const std::string& url); static void SetFeedURL(const std::string& url);
static void CheckForUpdates(); static void CheckForUpdates();
static void QuitAndInstall();
private: private:
static AutoUpdaterDelegate* delegate_; static Delegate* delegate_;
DISALLOW_IMPLICIT_CONSTRUCTORS(AutoUpdater); DISALLOW_IMPLICIT_CONSTRUCTORS(AutoUpdater);
}; };

View file

@ -1,45 +0,0 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_AUTO_UPDATER_DELEGATE_H_
#define ATOM_BROWSER_AUTO_UPDATER_DELEGATE_H_
#include <string>
#include "base/callback_forward.h"
namespace base {
class Time;
}
namespace auto_updater {
class AutoUpdaterDelegate {
public:
// An error happened.
virtual void OnError(const std::string& error) {}
// Checking to see if there is an update
virtual void OnCheckingForUpdate() {}
// There is an update available and it is being downloaded
virtual void OnUpdateAvailable() {}
// There is no available update.
virtual void OnUpdateNotAvailable() {}
// There is a new update which has been downloaded.
virtual void OnUpdateDownloaded(const std::string& release_notes,
const std::string& release_name,
const base::Time& release_date,
const std::string& update_url,
const base::Closure& quit_and_install) {}
protected:
virtual ~AutoUpdaterDelegate() {}
};
} // namespace auto_updater
#endif // ATOM_BROWSER_AUTO_UPDATER_DELEGATE_H_

View file

@ -1,17 +0,0 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/auto_updater.h"
namespace auto_updater {
// static
void AutoUpdater::SetFeedURL(const std::string& url) {
}
// static
void AutoUpdater::CheckForUpdates() {
}
} // namespace auto_updater

View file

@ -12,9 +12,6 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "base/strings/sys_string_conversions.h" #include "base/strings/sys_string_conversions.h"
#include "atom/browser/auto_updater_delegate.h"
#include <iostream>
namespace auto_updater { namespace auto_updater {
@ -23,20 +20,12 @@ namespace {
// The gloal SQRLUpdater object. // The gloal SQRLUpdater object.
SQRLUpdater* g_updater = nil; SQRLUpdater* g_updater = nil;
void RelaunchToInstallUpdate() {
[[g_updater relaunchToInstallUpdate] subscribeError:^(NSError* error) {
AutoUpdaterDelegate* delegate = AutoUpdater::GetDelegate();
if (delegate)
delegate->OnError(base::SysNSStringToUTF8(error.localizedDescription));
}];
}
} // namespace } // namespace
// static // static
void AutoUpdater::SetFeedURL(const std::string& feed) { void AutoUpdater::SetFeedURL(const std::string& feed) {
if (g_updater == nil) { if (g_updater == nil) {
AutoUpdaterDelegate* delegate = GetDelegate(); Delegate* delegate = GetDelegate();
if (!delegate) if (!delegate)
return; return;
@ -67,7 +56,7 @@ void AutoUpdater::SetFeedURL(const std::string& feed) {
// static // static
void AutoUpdater::CheckForUpdates() { void AutoUpdater::CheckForUpdates() {
AutoUpdaterDelegate* delegate = GetDelegate(); Delegate* delegate = GetDelegate();
if (!delegate) if (!delegate)
return; return;
@ -86,8 +75,7 @@ void AutoUpdater::CheckForUpdates() {
base::SysNSStringToUTF8(update.releaseNotes), base::SysNSStringToUTF8(update.releaseNotes),
base::SysNSStringToUTF8(update.releaseName), base::SysNSStringToUTF8(update.releaseName),
base::Time::FromDoubleT(update.releaseDate.timeIntervalSince1970), base::Time::FromDoubleT(update.releaseDate.timeIntervalSince1970),
base::SysNSStringToUTF8(update.updateURL.absoluteString), base::SysNSStringToUTF8(update.updateURL.absoluteString));
base::Bind(RelaunchToInstallUpdate));
} else { } else {
// When the completed event is sent with no update, then we know there // When the completed event is sent with no update, then we know there
// is no update available. // is no update available.
@ -100,4 +88,12 @@ void AutoUpdater::CheckForUpdates() {
}]; }];
} }
void AutoUpdater::QuitAndInstall() {
[[g_updater relaunchToInstallUpdate] subscribeError:^(NSError* error) {
Delegate* delegate = AutoUpdater::GetDelegate();
if (delegate)
delegate->OnError(base::SysNSStringToUTF8(error.localizedDescription));
}];
}
} // namespace auto_updater } // namespace auto_updater

View file

@ -1,17 +0,0 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/auto_updater.h"
namespace auto_updater {
// static
void AutoUpdater::SetFeedURL(const std::string& url) {
}
// static
void AutoUpdater::CheckForUpdates() {
}
} // namespace auto_updater

View file

@ -8,13 +8,33 @@
namespace atom { namespace atom {
// static
std::vector<BridgeTaskRunner::TaskPair> BridgeTaskRunner::tasks_;
std::vector<BridgeTaskRunner::TaskPair> BridgeTaskRunner::non_nestable_tasks_;
// static
void BridgeTaskRunner::MessageLoopIsReady() {
auto message_loop = base::MessageLoop::current();
CHECK(message_loop);
for (const TaskPair& task : tasks_) {
message_loop->task_runner()->PostDelayedTask(
base::get<0>(task), base::get<1>(task), base::get<2>(task));
}
for (const TaskPair& task : non_nestable_tasks_) {
message_loop->task_runner()->PostNonNestableDelayedTask(
base::get<0>(task), base::get<1>(task), base::get<2>(task));
}
}
bool BridgeTaskRunner::PostDelayedTask( bool BridgeTaskRunner::PostDelayedTask(
const tracked_objects::Location& from_here, const tracked_objects::Location& from_here,
const base::Closure& task, const base::Closure& task,
base::TimeDelta delay) { base::TimeDelta delay) {
auto message_loop = base::MessageLoop::current(); auto message_loop = base::MessageLoop::current();
if (!message_loop) if (!message_loop) {
return false; tasks_.push_back(base::MakeTuple(from_here, task, delay));
return true;
}
return message_loop->task_runner()->PostDelayedTask(from_here, task, delay); return message_loop->task_runner()->PostDelayedTask(from_here, task, delay);
} }
@ -22,7 +42,7 @@ bool BridgeTaskRunner::PostDelayedTask(
bool BridgeTaskRunner::RunsTasksOnCurrentThread() const { bool BridgeTaskRunner::RunsTasksOnCurrentThread() const {
auto message_loop = base::MessageLoop::current(); auto message_loop = base::MessageLoop::current();
if (!message_loop) if (!message_loop)
return false; return true;
return message_loop->task_runner()->RunsTasksOnCurrentThread(); return message_loop->task_runner()->RunsTasksOnCurrentThread();
} }
@ -32,8 +52,10 @@ bool BridgeTaskRunner::PostNonNestableDelayedTask(
const base::Closure& task, const base::Closure& task,
base::TimeDelta delay) { base::TimeDelta delay) {
auto message_loop = base::MessageLoop::current(); auto message_loop = base::MessageLoop::current();
if (!message_loop) if (!message_loop) {
return false; non_nestable_tasks_.push_back(base::MakeTuple(from_here, task, delay));
return true;
}
return message_loop->task_runner()->PostNonNestableDelayedTask( return message_loop->task_runner()->PostNonNestableDelayedTask(
from_here, task, delay); from_here, task, delay);

View file

@ -5,17 +5,23 @@
#ifndef ATOM_BROWSER_BRIDGE_TASK_RUNNER_H_ #ifndef ATOM_BROWSER_BRIDGE_TASK_RUNNER_H_
#define ATOM_BROWSER_BRIDGE_TASK_RUNNER_H_ #define ATOM_BROWSER_BRIDGE_TASK_RUNNER_H_
#include <vector>
#include "base/single_thread_task_runner.h" #include "base/single_thread_task_runner.h"
#include "base/tuple.h"
namespace atom { namespace atom {
// Post all tasks to the current message loop's task runner if available, // Post all tasks to the current message loop's task runner if available,
// otherwise fail silently. // otherwise delay the work until message loop is ready.
class BridgeTaskRunner : public base::SingleThreadTaskRunner { class BridgeTaskRunner : public base::SingleThreadTaskRunner {
public: public:
BridgeTaskRunner() {} BridgeTaskRunner() {}
~BridgeTaskRunner() override {} ~BridgeTaskRunner() override {}
// Called when message loop is ready.
static void MessageLoopIsReady();
// base::SingleThreadTaskRunner: // base::SingleThreadTaskRunner:
bool PostDelayedTask(const tracked_objects::Location& from_here, bool PostDelayedTask(const tracked_objects::Location& from_here,
const base::Closure& task, const base::Closure& task,
@ -27,6 +33,11 @@ class BridgeTaskRunner : public base::SingleThreadTaskRunner {
base::TimeDelta delay) override; base::TimeDelta delay) override;
private: private:
using TaskPair = base::Tuple<
tracked_objects::Location, base::Closure, base::TimeDelta>;
static std::vector<TaskPair> tasks_;
static std::vector<TaskPair> non_nestable_tasks_;
DISALLOW_COPY_AND_ASSIGN(BridgeTaskRunner); DISALLOW_COPY_AND_ASSIGN(BridgeTaskRunner);
}; };

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;
@ -53,8 +75,14 @@ void Browser::Shutdown() {
is_quiting_ = true; is_quiting_ = true;
FOR_EACH_OBSERVER(BrowserObserver, observers_, OnQuit()); FOR_EACH_OBSERVER(BrowserObserver, observers_, OnQuit());
base::MessageLoop::current()->PostTask(
FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); if (base::MessageLoop::current()) {
base::MessageLoop::current()->PostTask(
FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
} else {
// There is no message loop available so we are in early stage.
exit(0);
}
} }
std::string Browser::GetVersion() const { std::string Browser::GetVersion() const {
@ -83,10 +111,6 @@ std::string Browser::GetName() const {
void Browser::SetName(const std::string& name) { void Browser::SetName(const std::string& name) {
name_override_ = name; name_override_ = name;
#if defined(OS_WIN)
SetAppUserModelID(name);
#endif
} }
bool Browser::OpenFile(const std::string& file_path) { bool Browser::OpenFile(const std::string& file_path) {
@ -128,6 +152,10 @@ void Browser::ClientCertificateSelector(
delegate.Pass())); delegate.Pass()));
} }
void Browser::RequestLogin(LoginHandler* login_handler) {
FOR_EACH_OBSERVER(BrowserObserver, observers_, OnLogin(login_handler));
}
void Browser::NotifyAndShutdown() { void Browser::NotifyAndShutdown() {
if (is_shutdown_) if (is_shutdown_)
return; return;

View file

@ -11,12 +11,12 @@
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/observer_list.h" #include "base/observer_list.h"
#include "base/strings/string16.h"
#include "atom/browser/browser_observer.h" #include "atom/browser/browser_observer.h"
#include "atom/browser/window_list_observer.h" #include "atom/browser/window_list_observer.h"
#if defined(OS_WIN) #if defined(OS_WIN)
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/strings/string16.h"
#endif #endif
namespace base { namespace base {
@ -29,6 +29,8 @@ class MenuModel;
namespace atom { namespace atom {
class LoginHandler;
// This class is used for control application-wide operations. // This class is used for control application-wide operations.
class Browser : public WindowListObserver { class Browser : public WindowListObserver {
public: public:
@ -40,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();
@ -64,6 +69,9 @@ class Browser : public WindowListObserver {
// Clear the recent documents list. // Clear the recent documents list.
void ClearRecentDocuments(); void ClearRecentDocuments();
// Set the application user model ID.
void SetAppUserModelID(const base::string16& name);
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
// Bounce the dock icon. // Bounce the dock icon.
enum BounceType { enum BounceType {
@ -98,8 +106,10 @@ class Browser : public WindowListObserver {
// Add a custom task to jump list. // Add a custom task to jump list.
void SetUserTasks(const std::vector<UserTask>& tasks); void SetUserTasks(const std::vector<UserTask>& tasks);
// Set the application user model ID, called when "SetName" is called. // Returns the application user model ID, if there isn't one, then create
void SetAppUserModelID(const std::string& name); // one from app's name.
// The returned string managed by Browser, and should not be modified.
PCWSTR GetAppUserModelID();
#endif #endif
// Tell the application to open a file. // Tell the application to open a file.
@ -122,6 +132,9 @@ class Browser : public WindowListObserver {
net::SSLCertRequestInfo* cert_request_info, net::SSLCertRequestInfo* cert_request_info,
scoped_ptr<content::ClientCertificateDelegate> delegate); scoped_ptr<content::ClientCertificateDelegate> delegate);
// Request basic auth login.
void RequestLogin(LoginHandler* login_handler);
void AddObserver(BrowserObserver* obs) { void AddObserver(BrowserObserver* obs) {
observers_.AddObserver(obs); observers_.AddObserver(obs);
} }
@ -130,6 +143,7 @@ class Browser : public WindowListObserver {
observers_.RemoveObserver(obs); observers_.RemoveObserver(obs);
} }
bool is_shutting_down() const { return is_shutdown_; }
bool is_quiting() const { return is_quiting_; } bool is_quiting() const { return is_quiting_; }
bool is_ready() const { return is_ready_; } bool is_ready() const { return is_ready_; }

View file

@ -31,6 +31,9 @@ void Browser::AddRecentDocument(const base::FilePath& path) {
void Browser::ClearRecentDocuments() { void Browser::ClearRecentDocuments() {
} }
void Browser::SetAppUserModelID(const base::string16& name) {
}
std::string Browser::GetExecutableFileVersion() const { std::string Browser::GetExecutableFileVersion() const {
return brightray::GetApplicationVersion(); return brightray::GetApplicationVersion();
} }

View file

@ -26,6 +26,9 @@ void Browser::AddRecentDocument(const base::FilePath& path) {
void Browser::ClearRecentDocuments() { void Browser::ClearRecentDocuments() {
} }
void Browser::SetAppUserModelID(const base::string16& name) {
}
std::string Browser::GetExecutableFileVersion() const { std::string Browser::GetExecutableFileVersion() const {
return brightray::GetApplicationVersion(); return brightray::GetApplicationVersion();
} }

View file

@ -20,6 +20,8 @@ class SSLCertRequestInfo;
namespace atom { namespace atom {
class LoginHandler;
class BrowserObserver { class BrowserObserver {
public: public:
// The browser is about to close all windows. // The browser is about to close all windows.
@ -57,6 +59,9 @@ class BrowserObserver {
net::SSLCertRequestInfo* cert_request_info, net::SSLCertRequestInfo* cert_request_info,
scoped_ptr<content::ClientCertificateDelegate> delegate) {} scoped_ptr<content::ClientCertificateDelegate> delegate) {}
// The browser requests HTTP login.
virtual void OnLogin(LoginHandler* login_handler) {}
protected: protected:
virtual ~BrowserObserver() {} virtual ~BrowserObserver() {}
}; };

View file

@ -15,6 +15,7 @@
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/path_service.h" #include "base/path_service.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/win/win_util.h" #include "base/win/win_util.h"
@ -25,6 +26,8 @@ namespace atom {
namespace { namespace {
const wchar_t kAppUserModelIDFormat[] = L"electron.app.$1";
BOOL CALLBACK WindowsEnumerationHandler(HWND hwnd, LPARAM param) { BOOL CALLBACK WindowsEnumerationHandler(HWND hwnd, LPARAM param) {
DWORD target_process_id = *reinterpret_cast<DWORD*>(param); DWORD target_process_id = *reinterpret_cast<DWORD*>(param);
DWORD process_id = 0; DWORD process_id = 0;
@ -56,7 +59,7 @@ void Browser::AddRecentDocument(const base::FilePath& path) {
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) {
SHARDAPPIDINFO info; SHARDAPPIDINFO info;
info.psi = item; info.psi = item;
info.pszAppID = app_user_model_id_.c_str(); info.pszAppID = GetAppUserModelID();
SHAddToRecentDocs(SHARD_APPIDINFO, &info); SHAddToRecentDocs(SHARD_APPIDINFO, &info);
} }
} }
@ -66,16 +69,21 @@ void Browser::ClearRecentDocuments() {
if (FAILED(destinations.CoCreateInstance(CLSID_ApplicationDestinations, if (FAILED(destinations.CoCreateInstance(CLSID_ApplicationDestinations,
NULL, CLSCTX_INPROC_SERVER))) NULL, CLSCTX_INPROC_SERVER)))
return; return;
if (FAILED(destinations->SetAppID(app_user_model_id_.c_str()))) if (FAILED(destinations->SetAppID(GetAppUserModelID())))
return; return;
destinations->RemoveAllDestinations(); destinations->RemoveAllDestinations();
} }
void Browser::SetAppUserModelID(const base::string16& name) {
app_user_model_id_ = name;
SetCurrentProcessExplicitAppUserModelID(app_user_model_id_.c_str());
}
void Browser::SetUserTasks(const std::vector<UserTask>& tasks) { void Browser::SetUserTasks(const std::vector<UserTask>& tasks) {
CComPtr<ICustomDestinationList> destinations; CComPtr<ICustomDestinationList> destinations;
if (FAILED(destinations.CoCreateInstance(CLSID_DestinationList))) if (FAILED(destinations.CoCreateInstance(CLSID_DestinationList)))
return; return;
if (FAILED(destinations->SetAppID(app_user_model_id_.c_str()))) if (FAILED(destinations->SetAppID(GetAppUserModelID())))
return; return;
// Start a transaction that updates the JumpList of this application. // Start a transaction that updates the JumpList of this application.
@ -117,10 +125,13 @@ void Browser::SetUserTasks(const std::vector<UserTask>& tasks) {
destinations->CommitList(); destinations->CommitList();
} }
void Browser::SetAppUserModelID(const std::string& name) { PCWSTR Browser::GetAppUserModelID() {
app_user_model_id_ = base::string16(L"electron.app."); if (app_user_model_id_.empty()) {
app_user_model_id_ += base::UTF8ToUTF16(name); SetAppUserModelID(ReplaceStringPlaceholders(
SetCurrentProcessExplicitAppUserModelID(app_user_model_id_.c_str()); kAppUserModelIDFormat, base::UTF8ToUTF16(GetName()), nullptr));
}
return app_user_model_id_.c_str();
} }
std::string Browser::GetExecutableFileVersion() const { std::string Browser::GetExecutableFileVersion() const {

View file

@ -12,8 +12,8 @@ app.on('ready', function() {
mainWindow = new BrowserWindow({ mainWindow = new BrowserWindow({
width: 800, width: 800,
height: 600, height: 600,
'auto-hide-menu-bar': true, autoHideMenuBar: true,
'use-content-size': true, useContentSize: true,
}); });
mainWindow.loadUrl('file://' + __dirname + '/index.html'); mainWindow.loadUrl('file://' + __dirname + '/index.html');
mainWindow.focus(); mainWindow.focus();

View file

@ -18,6 +18,9 @@ for (var i = 0; i < argv.length; i++) {
if (argv[i] == '--version' || argv[i] == '-v') { if (argv[i] == '--version' || argv[i] == '-v') {
option.version = true; option.version = true;
break; break;
} else if (argv[i].match(/^--app=/)) {
option.file = argv[i].split('=')[1];
break;
} else if (argv[i] == '--help' || argv[i] == '-h') { } else if (argv[i] == '--help' || argv[i] == '-h') {
option.help = true; option.help = true;
break; break;
@ -260,7 +263,7 @@ if (option.file && !option.webdriver) {
helpMessage += "A path to an Electron application may be specified. The path must be to \n"; helpMessage += "A path to an Electron application may be specified. The path must be to \n";
helpMessage += "an index.js file or to a folder containing a package.json or index.js file.\n\n"; helpMessage += "an index.js file or to a folder containing a package.json or index.js file.\n\n";
helpMessage += "Options:\n"; helpMessage += "Options:\n";
helpMessage += " -r, --require Module to preload (option can be repeated)"; helpMessage += " -r, --require Module to preload (option can be repeated)\n";
helpMessage += " -h, --help Print this usage message.\n"; helpMessage += " -h, --help Print this usage message.\n";
helpMessage += " -v, --version Print the version."; helpMessage += " -v, --version Print the version.";
console.log(helpMessage); console.log(helpMessage);

View file

@ -4,6 +4,7 @@
#include "atom/browser/javascript_environment.h" #include "atom/browser/javascript_environment.h"
#include "base/command_line.h"
#include "gin/array_buffer.h" #include "gin/array_buffer.h"
#include "gin/v8_initializer.h" #include "gin/v8_initializer.h"
@ -20,7 +21,12 @@ JavascriptEnvironment::JavascriptEnvironment()
} }
bool JavascriptEnvironment::Initialize() { bool JavascriptEnvironment::Initialize() {
gin::V8Initializer::LoadV8Snapshot(); auto cmd = base::CommandLine::ForCurrentProcess();
if (cmd->HasSwitch("debug-brk")) {
// Need to be called before v8::Initialize().
const char expose_debug_as[] = "--expose_debug_as=v8debug";
v8::V8::SetFlagsFromString(expose_debug_as, sizeof(expose_debug_as) - 1);
}
gin::IsolateHolder::Initialize(gin::IsolateHolder::kNonStrictMode, gin::IsolateHolder::Initialize(gin::IsolateHolder::kNonStrictMode,
gin::ArrayBufferAllocator::SharedInstance()); gin::ArrayBufferAllocator::SharedInstance());
return true; return true;

View file

@ -55,7 +55,7 @@ app.once 'ready', ->
BrowserWindow = require 'browser-window' BrowserWindow = require 'browser-window'
# Load persistented extensions. # Load persistented extensions.
loadedExtensionsPath = path.join app.getDataPath(), 'DevTools Extensions' loadedExtensionsPath = path.join app.getPath('userData'), 'DevTools Extensions'
try try
loadedExtensions = JSON.parse fs.readFileSync(loadedExtensionsPath) loadedExtensions = JSON.parse fs.readFileSync(loadedExtensionsPath)

View file

@ -1,4 +1,4 @@
ipc = require 'ipc' ipc = require 'ipc-main'
webContents = require 'web-contents' webContents = require 'web-contents'
webViewManager = null # Doesn't exist in early initialization. webViewManager = null # Doesn't exist in early initialization.
@ -118,11 +118,11 @@ attachGuest = (embedder, elementInstanceId, guestInstanceId, params) ->
destroyGuest embedder, oldGuestInstanceId destroyGuest embedder, oldGuestInstanceId
webPreferences = webPreferences =
'guest-instance-id': guestInstanceId guestInstanceId: guestInstanceId
'node-integration': params.nodeintegration ? false nodeIntegration: params.nodeintegration ? false
'plugins': params.plugins plugins: params.plugins
'web-security': !params.disablewebsecurity webSecurity: !params.disablewebsecurity
webPreferences['preload-url'] = params.preload if params.preload webPreferences.preloadUrl = params.preload if params.preload
webViewManager.addGuest guestInstanceId, elementInstanceId, embedder, guest, webPreferences webViewManager.addGuest guestInstanceId, elementInstanceId, embedder, guest, webPreferences
guest.attachParams = params guest.attachParams = params

View file

@ -1,18 +1,27 @@
ipc = require 'ipc' ipc = require 'ipc-main'
v8Util = process.atomBinding 'v8_util' v8Util = process.atomBinding 'v8_util'
BrowserWindow = require 'browser-window' BrowserWindow = require 'browser-window'
frameToGuest = {} frameToGuest = {}
# Copy attribute of |parent| to |child| if it is not defined in |child|.
mergeOptions = (child, parent) ->
for own key, value of parent when key not in child
if typeof value is 'object'
child[key] = mergeOptions {}, value
else
child[key] = value
child
# Merge |options| with the |embedder|'s window's options. # Merge |options| with the |embedder|'s window's options.
mergeBrowserWindowOptions = (embedder, options) -> mergeBrowserWindowOptions = (embedder, options) ->
if embedder.browserWindowOptions? if embedder.browserWindowOptions?
# Inherit the original options if it is a BrowserWindow. # Inherit the original options if it is a BrowserWindow.
options.__proto__ = embedder.browserWindowOptions mergeOptions options, embedder.browserWindowOptions
else else
# Or only inherit web-preferences if it is a webview. # Or only inherit web-preferences if it is a webview.
options['web-preferences'] ?= {} options.webPreferences ?= {}
options['web-preferences'].__proto__ = embedder.getWebPreferences() mergeOptions options.webPreferences, embedder.getWebPreferences()
options options
# Create a new guest created by |embedder| with |options|. # Create a new guest created by |embedder| with |options|.
@ -67,7 +76,7 @@ ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_METHOD', (event, guestId, method,
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', (event, guestId, message, targetOrigin) -> ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', (event, guestId, message, targetOrigin) ->
guestContents = BrowserWindow.fromId(guestId)?.webContents guestContents = BrowserWindow.fromId(guestId)?.webContents
if guestContents?.getUrl().indexOf(targetOrigin) is 0 or targetOrigin is '*' if guestContents?.getUrl().indexOf(targetOrigin) is 0 or targetOrigin is '*'
guestContents.send 'ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', message, targetOrigin guestContents.send 'ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', guestId, message, targetOrigin
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPENER_POSTMESSAGE', (event, guestId, message, targetOrigin, sourceOrigin) -> ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPENER_POSTMESSAGE', (event, guestId, message, targetOrigin, sourceOrigin) ->
embedder = v8Util.getHiddenValue event.sender, 'embedder' embedder = v8Util.getHiddenValue event.sender, 'embedder'

View file

@ -21,10 +21,15 @@ globalPaths.push path.resolve(__dirname, '..', 'api', 'lib')
if process.platform is 'win32' if process.platform is 'win32'
# Redirect node's console to use our own implementations, since node can not # Redirect node's console to use our own implementations, since node can not
# handle console output when running as GUI program. # handle console output when running as GUI program.
print = (args...) -> consoleLog = (args...) ->
process.log util.format(args...) process.log util.format(args...) + "\n"
console.log = console.error = console.warn = print streamWrite = (chunk, encoding, callback) ->
process.stdout.write = process.stderr.write = print chunk = chunk.toString(encoding) if Buffer.isBuffer chunk
process.log chunk
callback() if callback
true
console.log = console.error = console.warn = consoleLog
process.stdout.write = process.stderr.write = streamWrite
# Always returns EOF for stdin stream. # Always returns EOF for stdin stream.
Readable = require('stream').Readable Readable = require('stream').Readable
@ -48,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

@ -34,6 +34,7 @@ class ObjectsRegistry extends EventEmitter
@dereference id, 1 @dereference id, 1
# Also reduce the count in owner. # Also reduce the count in owner.
pointer = @owners[webContentsId] pointer = @owners[webContentsId]
return unless pointer?
--pointer[id] --pointer[id]
delete pointer[id] if pointer[id] is 0 delete pointer[id] if pointer[id] is 0
@ -57,6 +58,7 @@ class ObjectsRegistry extends EventEmitter
# Private: Dereference the object from store. # Private: Dereference the object from store.
dereference: (id, count) -> dereference: (id, count) ->
pointer = @storage[id] pointer = @storage[id]
return unless pointer?
pointer.count -= count pointer.count -= count
if pointer.count is 0 if pointer.count is 0
v8Util.deleteHiddenValue pointer.object, 'atomId' v8Util.deleteHiddenValue pointer.object, 'atomId'

View file

@ -1,7 +1,8 @@
ipc = require 'ipc' ipc = require 'ipc-main'
path = require 'path' path = require 'path'
objectsRegistry = require './objects-registry.js' objectsRegistry = require './objects-registry.js'
v8Util = process.atomBinding 'v8_util' v8Util = process.atomBinding 'v8_util'
IDWeakMap = process.atomBinding('id_weak_map').IDWeakMap
# Convert a real value into meta data. # Convert a real value into meta data.
valueToMeta = (sender, value, optimizeSimpleObject=false) -> valueToMeta = (sender, value, optimizeSimpleObject=false) ->
@ -10,6 +11,8 @@ valueToMeta = (sender, value, optimizeSimpleObject=false) ->
meta.type = 'buffer' if Buffer.isBuffer value meta.type = 'buffer' if Buffer.isBuffer value
meta.type = 'value' if value is null meta.type = 'value' if value is null
meta.type = 'array' if Array.isArray value meta.type = 'array' if Array.isArray value
meta.type = 'error' if value instanceof Error
meta.type = 'date' if value instanceof Date
meta.type = 'promise' if value? and value.constructor.name is 'Promise' meta.type = 'promise' if value? and value.constructor.name is 'Promise'
# Treat simple objects as value. # Treat simple objects as value.
@ -30,21 +33,28 @@ valueToMeta = (sender, value, optimizeSimpleObject=false) ->
# it. # it.
meta.id = objectsRegistry.add sender.getId(), value meta.id = objectsRegistry.add sender.getId(), value
meta.members = [] meta.members = ({name, type: typeof field} for name, field of value)
meta.members.push {name: prop, type: typeof field} for prop, field of value
else if meta.type is 'buffer' else if meta.type is 'buffer'
meta.value = Array::slice.call value, 0 meta.value = Array::slice.call value, 0
else if meta.type is 'promise' else if meta.type is 'promise'
meta.then = valueToMeta(sender, value.then.bind(value)) meta.then = valueToMeta sender, value.then.bind(value)
else if meta.type is 'error'
meta.members = plainObjectToMeta value
else if meta.type is 'date'
meta.value = value.getTime()
else else
meta.type = 'value' meta.type = 'value'
meta.value = value meta.value = value
meta meta
# Convert object to meta by value.
plainObjectToMeta = (obj) ->
Object.getOwnPropertyNames(obj).map (name) -> {name, value: obj[name]}
# Convert Error into meta data. # Convert Error into meta data.
errorToMeta = (error) -> exceptionToMeta = (error) ->
type: 'error', message: error.message, stack: (error.stack || error) type: 'exception', message: error.message, stack: (error.stack || error)
# Convert array of meta data from renderer into array of real values. # Convert array of meta data from renderer into array of real values.
unwrapArgs = (sender, args) -> unwrapArgs = (sender, args) ->
@ -64,16 +74,27 @@ unwrapArgs = (sender, args) ->
returnValue = metaToValue meta.value returnValue = metaToValue meta.value
-> returnValue -> returnValue
when 'function' when 'function'
# Cache the callbacks in renderer.
unless sender.callbacks
sender.callbacks = new IDWeakMap
sender.on 'render-view-deleted', ->
sender.callbacks.clear()
return sender.callbacks.get meta.id if sender.callbacks.has meta.id
rendererReleased = false rendererReleased = false
objectsRegistry.once "clear-#{sender.getId()}", -> objectsRegistry.once "clear-#{sender.getId()}", ->
rendererReleased = true rendererReleased = true
ret = -> ret = ->
throw new Error('Calling a callback of released renderer view') if rendererReleased if rendererReleased
throw new Error("Attempting to call a function in a renderer window
that has been closed or released. Function provided here: #{meta.location}.")
sender.send 'ATOM_RENDERER_CALLBACK', meta.id, valueToMeta(sender, arguments) sender.send 'ATOM_RENDERER_CALLBACK', meta.id, valueToMeta(sender, arguments)
v8Util.setDestructor ret, -> v8Util.setDestructor ret, ->
return if rendererReleased return if rendererReleased
sender.callbacks.remove meta.id
sender.send 'ATOM_RENDERER_RELEASE_CALLBACK', meta.id sender.send 'ATOM_RENDERER_RELEASE_CALLBACK', meta.id
sender.callbacks.set meta.id, ret
ret ret
else throw new TypeError("Unknown type: #{meta.type}") else throw new TypeError("Unknown type: #{meta.type}")
@ -98,19 +119,19 @@ ipc.on 'ATOM_BROWSER_REQUIRE', (event, module) ->
try try
event.returnValue = valueToMeta event.sender, process.mainModule.require(module) event.returnValue = valueToMeta event.sender, process.mainModule.require(module)
catch e catch e
event.returnValue = errorToMeta e event.returnValue = exceptionToMeta e
ipc.on 'ATOM_BROWSER_GLOBAL', (event, name) -> ipc.on 'ATOM_BROWSER_GLOBAL', (event, name) ->
try try
event.returnValue = valueToMeta event.sender, global[name] event.returnValue = valueToMeta event.sender, global[name]
catch e catch e
event.returnValue = errorToMeta e event.returnValue = exceptionToMeta e
ipc.on 'ATOM_BROWSER_CURRENT_WINDOW', (event) -> ipc.on 'ATOM_BROWSER_CURRENT_WINDOW', (event) ->
try try
event.returnValue = valueToMeta event.sender, event.sender.getOwnerBrowserWindow() event.returnValue = valueToMeta event.sender, event.sender.getOwnerBrowserWindow()
catch e catch e
event.returnValue = errorToMeta e event.returnValue = exceptionToMeta e
ipc.on 'ATOM_BROWSER_CURRENT_WEB_CONTENTS', (event) -> ipc.on 'ATOM_BROWSER_CURRENT_WEB_CONTENTS', (event) ->
event.returnValue = valueToMeta event.sender, event.sender event.returnValue = valueToMeta event.sender, event.sender
@ -124,7 +145,7 @@ ipc.on 'ATOM_BROWSER_CONSTRUCTOR', (event, id, args) ->
obj = new (Function::bind.apply(constructor, [null].concat(args))) obj = new (Function::bind.apply(constructor, [null].concat(args)))
event.returnValue = valueToMeta event.sender, obj event.returnValue = valueToMeta event.sender, obj
catch e catch e
event.returnValue = errorToMeta e event.returnValue = exceptionToMeta e
ipc.on 'ATOM_BROWSER_FUNCTION_CALL', (event, id, args) -> ipc.on 'ATOM_BROWSER_FUNCTION_CALL', (event, id, args) ->
try try
@ -132,7 +153,7 @@ ipc.on 'ATOM_BROWSER_FUNCTION_CALL', (event, id, args) ->
func = objectsRegistry.get id func = objectsRegistry.get id
callFunction event, func, global, args callFunction event, func, global, args
catch e catch e
event.returnValue = errorToMeta e event.returnValue = exceptionToMeta e
ipc.on 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', (event, id, method, args) -> ipc.on 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', (event, id, method, args) ->
try try
@ -142,7 +163,7 @@ ipc.on 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', (event, id, method, args) ->
obj = new (Function::bind.apply(constructor, [null].concat(args))) obj = new (Function::bind.apply(constructor, [null].concat(args)))
event.returnValue = valueToMeta event.sender, obj event.returnValue = valueToMeta event.sender, obj
catch e catch e
event.returnValue = errorToMeta e event.returnValue = exceptionToMeta e
ipc.on 'ATOM_BROWSER_MEMBER_CALL', (event, id, method, args) -> ipc.on 'ATOM_BROWSER_MEMBER_CALL', (event, id, method, args) ->
try try
@ -150,7 +171,7 @@ ipc.on 'ATOM_BROWSER_MEMBER_CALL', (event, id, method, args) ->
obj = objectsRegistry.get id obj = objectsRegistry.get id
callFunction event, obj[method], obj, args callFunction event, obj[method], obj, args
catch e catch e
event.returnValue = errorToMeta e event.returnValue = exceptionToMeta e
ipc.on 'ATOM_BROWSER_MEMBER_SET', (event, id, name, value) -> ipc.on 'ATOM_BROWSER_MEMBER_SET', (event, id, name, value) ->
try try
@ -158,14 +179,14 @@ ipc.on 'ATOM_BROWSER_MEMBER_SET', (event, id, name, value) ->
obj[name] = value obj[name] = value
event.returnValue = null event.returnValue = null
catch e catch e
event.returnValue = errorToMeta e event.returnValue = exceptionToMeta e
ipc.on 'ATOM_BROWSER_MEMBER_GET', (event, id, name) -> ipc.on 'ATOM_BROWSER_MEMBER_GET', (event, id, name) ->
try try
obj = objectsRegistry.get id obj = objectsRegistry.get id
event.returnValue = valueToMeta event.sender, obj[name] event.returnValue = valueToMeta event.sender, obj[name]
catch e catch e
event.returnValue = errorToMeta e event.returnValue = exceptionToMeta e
ipc.on 'ATOM_BROWSER_DEREFERENCE', (event, id) -> ipc.on 'ATOM_BROWSER_DEREFERENCE', (event, id) ->
objectsRegistry.remove event.sender.getId(), id objectsRegistry.remove event.sender.getId(), id
@ -175,4 +196,4 @@ ipc.on 'ATOM_BROWSER_GUEST_WEB_CONTENTS', (event, guestInstanceId) ->
guestViewManager = require './guest-view-manager' guestViewManager = require './guest-view-manager'
event.returnValue = valueToMeta event.sender, guestViewManager.getGuest(guestInstanceId) event.returnValue = valueToMeta event.sender, guestViewManager.getGuest(guestInstanceId)
catch e catch e
event.returnValue = errorToMeta e event.returnValue = exceptionToMeta e

View file

@ -0,0 +1,109 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/login_handler.h"
#include "atom/browser/browser.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/resource_dispatcher_host.h"
#include "content/public/browser/resource_request_info.h"
#include "content/public/browser/web_contents.h"
#include "net/base/auth.h"
#include "net/url_request/url_request.h"
using content::BrowserThread;
namespace atom {
namespace {
// Helper to remove the ref from an net::URLRequest to the LoginHandler.
// Should only be called from the IO thread, since it accesses an
// net::URLRequest.
void ResetLoginHandlerForRequest(net::URLRequest* request) {
content::ResourceDispatcherHost::Get()->ClearLoginDelegateForRequest(request);
}
} // namespace
LoginHandler::LoginHandler(net::AuthChallengeInfo* auth_info,
net::URLRequest* request)
: handled_auth_(false),
auth_info_(auth_info),
request_(request),
render_process_host_id_(0),
render_frame_id_(0) {
content::ResourceRequestInfo::ForRequest(request_)->GetAssociatedRenderFrame(
&render_process_host_id_, &render_frame_id_);
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&Browser::RequestLogin,
base::Unretained(Browser::Get()),
make_scoped_refptr(this)));
}
LoginHandler::~LoginHandler() {
}
content::WebContents* LoginHandler::GetWebContents() const {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(
render_process_host_id_, render_frame_id_);
return content::WebContents::FromRenderFrameHost(rfh);
}
void LoginHandler::Login(const base::string16& username,
const base::string16& password) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (TestAndSetAuthHandled())
return;
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&LoginHandler::DoLogin, this, username, password));
}
void LoginHandler::CancelAuth() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (TestAndSetAuthHandled())
return;
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&LoginHandler::DoCancelAuth, this));
}
void LoginHandler::OnRequestCancelled() {
TestAndSetAuthHandled();
request_ = nullptr;
}
// Marks authentication as handled and returns the previous handled state.
bool LoginHandler::TestAndSetAuthHandled() {
base::AutoLock lock(handled_auth_lock_);
bool was_handled = handled_auth_;
handled_auth_ = true;
return was_handled;
}
void LoginHandler::DoCancelAuth() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (request_) {
request_->CancelAuth();
// Verify that CancelAuth doesn't destroy the request via our delegate.
DCHECK(request_ != nullptr);
ResetLoginHandlerForRequest(request_);
}
}
void LoginHandler::DoLogin(const base::string16& username,
const base::string16& password) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (request_) {
request_->SetAuth(net::AuthCredentials(username, password));
ResetLoginHandlerForRequest(request_);
}
}
} // namespace atom

View file

@ -0,0 +1,76 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_BROWSER_LOGIN_HANDLER_H_
#define ATOM_BROWSER_LOGIN_HANDLER_H_
#include "base/strings/string16.h"
#include "base/synchronization/lock.h"
#include "content/public/browser/resource_dispatcher_host_login_delegate.h"
namespace content {
class WebContents;
}
namespace net {
class AuthChallengeInfo;
class URLRequest;
}
namespace atom {
// Handles the HTTP basic auth, must be created on IO thread.
class LoginHandler : public content::ResourceDispatcherHostLoginDelegate {
public:
LoginHandler(net::AuthChallengeInfo* auth_info, net::URLRequest* request);
// Returns the WebContents associated with the request, must be called on UI
// thread.
content::WebContents* GetWebContents() const;
// The auth is cancelled, must be called on UI thread.
void CancelAuth();
// Login with |username| and |password|, must be called on UI thread.
void Login(const base::string16& username, const base::string16& password);
const net::AuthChallengeInfo* auth_info() const { return auth_info_.get(); }
const net::URLRequest* request() const { return request_; }
protected:
~LoginHandler() override;
// content::ResourceDispatcherHostLoginDelegate:
void OnRequestCancelled() override;
private:
// Must be called on IO thread.
void DoCancelAuth();
void DoLogin(const base::string16& username, const base::string16& password);
// Marks authentication as handled and returns the previous handled
// state.
bool TestAndSetAuthHandled();
// True if we've handled auth (Login or CancelAuth has been called).
bool handled_auth_;
mutable base::Lock handled_auth_lock_;
// Who/where/what asked for the authentication.
scoped_refptr<net::AuthChallengeInfo> auth_info_;
// The request that wants login data.
// This should only be accessed on the IO loop.
net::URLRequest* request_;
// Cached from the net::URLRequest, in case it goes NULL on us.
int render_process_host_id_;
int render_frame_id_;
DISALLOW_COPY_AND_ASSIGN(LoginHandler);
};
} // namespace atom
#endif // ATOM_BROWSER_LOGIN_HANDLER_H_

View file

@ -43,11 +43,20 @@
atom::Browser::Get()->OpenURL(base::SysNSStringToUTF8(url)); atom::Browser::Get()->OpenURL(base::SysNSStringToUTF8(url));
} }
- (bool)voiceOverEnabled {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults addSuiteNamed:@"com.apple.universalaccess"];
[defaults synchronize];
return [defaults boolForKey:@"voiceOverOnOffKey"];
}
- (void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute { - (void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute {
// Undocumented attribute that VoiceOver happens to set while running. // Undocumented attribute that VoiceOver happens to set while running.
// Chromium uses this too, even though it's not exactly right. // Chromium uses this too, even though it's not exactly right.
if ([attribute isEqualToString:@"AXEnhancedUserInterface"]) { if ([attribute isEqualToString:@"AXEnhancedUserInterface"]) {
[self updateAccessibilityEnabled:[value boolValue]]; bool enableAccessibility = ([self voiceOverEnabled] && [value boolValue]);
[self updateAccessibilityEnabled:enableAccessibility];
} }
return [super accessibilitySetValue:value forAttribute:attribute]; return [super accessibilitySetValue:value forAttribute:attribute];
} }

View file

@ -43,26 +43,6 @@ DEFINE_WEB_CONTENTS_USER_DATA_KEY(atom::NativeWindowRelay);
namespace atom { namespace atom {
namespace {
// Convert draggable regions in raw format to SkRegion format. Caller is
// responsible for deleting the returned SkRegion instance.
scoped_ptr<SkRegion> DraggableRegionsToSkRegion(
const std::vector<DraggableRegion>& regions) {
scoped_ptr<SkRegion> sk_region(new SkRegion);
for (const DraggableRegion& region : regions) {
sk_region->op(
region.bounds.x(),
region.bounds.y(),
region.bounds.right(),
region.bounds.bottom(),
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
}
return sk_region.Pass();
}
} // namespace
NativeWindow::NativeWindow( NativeWindow::NativeWindow(
brightray::InspectableWebContents* inspectable_web_contents, brightray::InspectableWebContents* inspectable_web_contents,
const mate::Dictionary& options) const mate::Dictionary& options)
@ -112,27 +92,35 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) {
int x = -1, y = -1; int x = -1, y = -1;
bool center; bool center;
if (options.Get(switches::kX, &x) && options.Get(switches::kY, &y)) { if (options.Get(switches::kX, &x) && options.Get(switches::kY, &y)) {
int width = -1, height = -1; SetPosition(gfx::Point(x, y));
options.Get(switches::kWidth, &width);
options.Get(switches::kHeight, &height);
SetBounds(gfx::Rect(x, y, width, height));
} else if (options.Get(switches::kCenter, &center) && center) { } else if (options.Get(switches::kCenter, &center) && center) {
Center(); Center();
} }
// On Linux and Window we may already have maximum size defined.
extensions::SizeConstraints size_constraints(GetContentSizeConstraints());
int min_height = 0, min_width = 0; int min_height = 0, min_width = 0;
if (options.Get(switches::kMinHeight, &min_height) | if (options.Get(switches::kMinHeight, &min_height) |
options.Get(switches::kMinWidth, &min_width)) { options.Get(switches::kMinWidth, &min_width)) {
SetMinimumSize(gfx::Size(min_width, min_height)); size_constraints.set_minimum_size(gfx::Size(min_width, min_height));
} }
int max_height = INT_MAX, max_width = INT_MAX; int max_height = INT_MAX, max_width = INT_MAX;
if (options.Get(switches::kMaxHeight, &max_height) | if (options.Get(switches::kMaxHeight, &max_height) |
options.Get(switches::kMaxWidth, &max_width)) { options.Get(switches::kMaxWidth, &max_width)) {
SetMaximumSize(gfx::Size(max_width, max_height)); size_constraints.set_maximum_size(gfx::Size(max_width, max_height));
} }
bool use_content_size = false;
options.Get(switches::kUseContentSize, &use_content_size);
if (use_content_size) {
SetContentSizeConstraints(size_constraints);
} else {
SetSizeConstraints(size_constraints);
}
#if defined(OS_WIN) || defined(USE_X11)
bool resizable; bool resizable;
if (options.Get(switches::kResizable, &resizable)) { if (options.Get(switches::kResizable, &resizable)) {
SetResizable(resizable); SetResizable(resizable);
} }
#endif
bool top; bool top;
if (options.Get(switches::kAlwaysOnTop, &top) && top) { if (options.Get(switches::kAlwaysOnTop, &top) && top) {
SetAlwaysOnTop(true); SetAlwaysOnTop(true);
@ -151,6 +139,10 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) {
if (options.Get(switches::kKiosk, &kiosk) && kiosk) { if (options.Get(switches::kKiosk, &kiosk) && kiosk) {
SetKiosk(kiosk); SetKiosk(kiosk);
} }
std::string color;
if (options.Get(switches::kBackgroundColor, &color)) {
SetBackgroundColor(color);
}
std::string title("Electron"); std::string title("Electron");
options.Get(switches::kTitle, &title); options.Get(switches::kTitle, &title);
SetTitle(title); SetTitle(title);
@ -178,6 +170,67 @@ gfx::Point NativeWindow::GetPosition() {
return GetBounds().origin(); return GetBounds().origin();
} }
void NativeWindow::SetContentSize(const gfx::Size& size) {
SetSize(ContentSizeToWindowSize(size));
}
gfx::Size NativeWindow::GetContentSize() {
return WindowSizeToContentSize(GetSize());
}
void NativeWindow::SetSizeConstraints(
const extensions::SizeConstraints& window_constraints) {
extensions::SizeConstraints content_constraints;
if (window_constraints.HasMaximumSize())
content_constraints.set_maximum_size(
WindowSizeToContentSize(window_constraints.GetMaximumSize()));
if (window_constraints.HasMinimumSize())
content_constraints.set_minimum_size(
WindowSizeToContentSize(window_constraints.GetMinimumSize()));
SetContentSizeConstraints(content_constraints);
}
extensions::SizeConstraints NativeWindow::GetSizeConstraints() {
extensions::SizeConstraints content_constraints = GetContentSizeConstraints();
extensions::SizeConstraints window_constraints;
if (content_constraints.HasMaximumSize())
window_constraints.set_maximum_size(
ContentSizeToWindowSize(content_constraints.GetMaximumSize()));
if (content_constraints.HasMinimumSize())
window_constraints.set_minimum_size(
ContentSizeToWindowSize(content_constraints.GetMinimumSize()));
return window_constraints;
}
void NativeWindow::SetContentSizeConstraints(
const extensions::SizeConstraints& size_constraints) {
size_constraints_ = size_constraints;
}
extensions::SizeConstraints NativeWindow::GetContentSizeConstraints() {
return size_constraints_;
}
void NativeWindow::SetMinimumSize(const gfx::Size& size) {
extensions::SizeConstraints size_constraints;
size_constraints.set_minimum_size(size);
SetSizeConstraints(size_constraints);
}
gfx::Size NativeWindow::GetMinimumSize() {
return GetSizeConstraints().GetMinimumSize();
}
void NativeWindow::SetMaximumSize(const gfx::Size& size) {
extensions::SizeConstraints size_constraints;
size_constraints.set_maximum_size(size);
SetSizeConstraints(size_constraints);
}
gfx::Size NativeWindow::GetMaximumSize() {
return GetSizeConstraints().GetMaximumSize();
}
void NativeWindow::SetRepresentedFilename(const std::string& filename) { void NativeWindow::SetRepresentedFilename(const std::string& filename) {
} }
@ -411,6 +464,28 @@ void NativeWindow::NotifyWindowExecuteWindowsCommand(
OnExecuteWindowsCommand(command)); OnExecuteWindowsCommand(command));
} }
#if defined(OS_WIN)
void NativeWindow::NotifyWindowMessage(
UINT message, WPARAM w_param, LPARAM l_param) {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_,
OnWindowMessage(message, w_param, l_param));
}
#endif
scoped_ptr<SkRegion> NativeWindow::DraggableRegionsToSkRegion(
const std::vector<DraggableRegion>& regions) {
scoped_ptr<SkRegion> sk_region(new SkRegion);
for (const DraggableRegion& region : regions) {
sk_region->op(
region.bounds.x(),
region.bounds.y(),
region.bounds.right(),
region.bounds.bottom(),
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
}
return sk_region.Pass();
}
void NativeWindow::RenderViewCreated( void NativeWindow::RenderViewCreated(
content::RenderViewHost* render_view_host) { content::RenderViewHost* render_view_host) {
if (!transparent_) if (!transparent_)

View file

@ -19,6 +19,7 @@
#include "content/public/browser/readback_types.h" #include "content/public/browser/readback_types.h"
#include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h" #include "content/public/browser/web_contents_user_data.h"
#include "extensions/browser/app_window/size_constraints.h"
#include "ui/gfx/image/image.h" #include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia.h" #include "ui/gfx/image/image_skia.h"
@ -110,12 +111,18 @@ class NativeWindow : public base::SupportsUserData,
virtual gfx::Size GetSize(); virtual gfx::Size GetSize();
virtual void SetPosition(const gfx::Point& position); virtual void SetPosition(const gfx::Point& position);
virtual gfx::Point GetPosition(); virtual gfx::Point GetPosition();
virtual void SetContentSize(const gfx::Size& size) = 0; virtual void SetContentSize(const gfx::Size& size);
virtual gfx::Size GetContentSize() = 0; virtual gfx::Size GetContentSize();
virtual void SetMinimumSize(const gfx::Size& size) = 0; virtual void SetSizeConstraints(
virtual gfx::Size GetMinimumSize() = 0; const extensions::SizeConstraints& size_constraints);
virtual void SetMaximumSize(const gfx::Size& size) = 0; virtual extensions::SizeConstraints GetSizeConstraints();
virtual gfx::Size GetMaximumSize() = 0; virtual void SetContentSizeConstraints(
const extensions::SizeConstraints& size_constraints);
virtual extensions::SizeConstraints GetContentSizeConstraints();
virtual void SetMinimumSize(const gfx::Size& size);
virtual gfx::Size GetMinimumSize();
virtual void SetMaximumSize(const gfx::Size& size);
virtual gfx::Size GetMaximumSize();
virtual void SetResizable(bool resizable) = 0; virtual void SetResizable(bool resizable) = 0;
virtual bool IsResizable() = 0; virtual bool IsResizable() = 0;
virtual void SetAlwaysOnTop(bool top) = 0; virtual void SetAlwaysOnTop(bool top) = 0;
@ -127,6 +134,7 @@ class NativeWindow : public base::SupportsUserData,
virtual void SetSkipTaskbar(bool skip) = 0; virtual void SetSkipTaskbar(bool skip) = 0;
virtual void SetKiosk(bool kiosk) = 0; virtual void SetKiosk(bool kiosk) = 0;
virtual bool IsKiosk() = 0; virtual bool IsKiosk() = 0;
virtual void SetBackgroundColor(const std::string& color_name) = 0;
virtual void SetRepresentedFilename(const std::string& filename); virtual void SetRepresentedFilename(const std::string& filename);
virtual std::string GetRepresentedFilename(); virtual std::string GetRepresentedFilename();
virtual void SetDocumentEdited(bool edited); virtual void SetDocumentEdited(bool edited);
@ -202,6 +210,10 @@ class NativeWindow : public base::SupportsUserData,
void NotifyWindowLeaveHtmlFullScreen(); void NotifyWindowLeaveHtmlFullScreen();
void NotifyWindowExecuteWindowsCommand(const std::string& command); void NotifyWindowExecuteWindowsCommand(const std::string& command);
#if defined(OS_WIN)
void NotifyWindowMessage(UINT message, WPARAM w_param, LPARAM l_param);
#endif
void AddObserver(NativeWindowObserver* obs) { void AddObserver(NativeWindowObserver* obs) {
observers_.AddObserver(obs); observers_.AddObserver(obs);
} }
@ -234,6 +246,19 @@ class NativeWindow : public base::SupportsUserData,
NativeWindow(brightray::InspectableWebContents* inspectable_web_contents, NativeWindow(brightray::InspectableWebContents* inspectable_web_contents,
const mate::Dictionary& options); const mate::Dictionary& options);
// Convert draggable regions in raw format to SkRegion format. Caller is
// responsible for deleting the returned SkRegion instance.
scoped_ptr<SkRegion> DraggableRegionsToSkRegion(
const std::vector<DraggableRegion>& regions);
// Converts between content size to window size.
virtual gfx::Size ContentSizeToWindowSize(const gfx::Size& size) = 0;
virtual gfx::Size WindowSizeToContentSize(const gfx::Size& size) = 0;
// Called when the window needs to update its draggable region.
virtual void UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions);
// content::WebContentsObserver: // content::WebContentsObserver:
void RenderViewCreated(content::RenderViewHost* render_view_host) override; void RenderViewCreated(content::RenderViewHost* render_view_host) override;
void BeforeUnloadDialogCancelled() override; void BeforeUnloadDialogCancelled() override;
@ -241,10 +266,6 @@ class NativeWindow : public base::SupportsUserData,
bool OnMessageReceived(const IPC::Message& message) override; bool OnMessageReceived(const IPC::Message& message) override;
private: private:
// Called when the window needs to update its draggable region.
void UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions);
// Schedule a notification unresponsive event. // Schedule a notification unresponsive event.
void ScheduleUnresponsiveEvent(int ms); void ScheduleUnresponsiveEvent(int ms);
@ -269,6 +290,9 @@ class NativeWindow : public base::SupportsUserData,
// has to been explicitly provided. // has to been explicitly provided.
scoped_ptr<SkRegion> draggable_region_; // used in custom drag. scoped_ptr<SkRegion> draggable_region_; // used in custom drag.
// Minimum and maximum size, stored as content size.
extensions::SizeConstraints size_constraints_;
// Whether window can be resized larger than screen. // Whether window can be resized larger than screen.
bool enable_larger_than_screen_; bool enable_larger_than_screen_;

View file

@ -44,12 +44,8 @@ class NativeWindowMac : public NativeWindow {
bool IsFullscreen() const override; bool IsFullscreen() const override;
void SetBounds(const gfx::Rect& bounds) override; void SetBounds(const gfx::Rect& bounds) override;
gfx::Rect GetBounds() override; gfx::Rect GetBounds() override;
void SetContentSize(const gfx::Size& size) override; void SetContentSizeConstraints(
gfx::Size GetContentSize() override; const extensions::SizeConstraints& size_constraints) override;
void SetMinimumSize(const gfx::Size& size) override;
gfx::Size GetMinimumSize() override;
void SetMaximumSize(const gfx::Size& size) override;
gfx::Size GetMaximumSize() override;
void SetResizable(bool resizable) override; void SetResizable(bool resizable) override;
bool IsResizable() override; bool IsResizable() override;
void SetAlwaysOnTop(bool top) override; void SetAlwaysOnTop(bool top) override;
@ -61,6 +57,7 @@ class NativeWindowMac : public NativeWindow {
void SetSkipTaskbar(bool skip) override; void SetSkipTaskbar(bool skip) override;
void SetKiosk(bool kiosk) override; void SetKiosk(bool kiosk) override;
bool IsKiosk() override; bool IsKiosk() override;
void SetBackgroundColor(const std::string& color_name) override;
void SetRepresentedFilename(const std::string& filename) override; void SetRepresentedFilename(const std::string& filename) override;
std::string GetRepresentedFilename() override; std::string GetRepresentedFilename() override;
void SetDocumentEdited(bool edited) override; void SetDocumentEdited(bool edited) override;
@ -75,12 +72,10 @@ class NativeWindowMac : public NativeWindow {
void SetVisibleOnAllWorkspaces(bool visible) override; void SetVisibleOnAllWorkspaces(bool visible) override;
bool IsVisibleOnAllWorkspaces() override; bool IsVisibleOnAllWorkspaces() override;
// Returns true if |point| in local Cocoa coordinate system falls within // Refresh the DraggableRegion views.
// the draggable region. void UpdateDraggableRegionViews() {
bool IsWithinDraggableRegion(NSPoint point) const; UpdateDraggableRegionViews(draggable_regions_);
}
// Called to handle a mouse event.
void HandleMouseEvent(NSEvent* event);
protected: protected:
// NativeWindow: // NativeWindow:
@ -88,13 +83,24 @@ class NativeWindowMac : public NativeWindow {
content::WebContents*, content::WebContents*,
const content::NativeWebKeyboardEvent&) override; const content::NativeWebKeyboardEvent&) override;
// Return a vector of non-draggable regions that fill a window of size
// |width| by |height|, but leave gaps where the window should be draggable.
std::vector<gfx::Rect> CalculateNonDraggableRegions(
const std::vector<DraggableRegion>& regions, int width, int height);
private: private:
// NativeWindow:
gfx::Size ContentSizeToWindowSize(const gfx::Size& size) override;
gfx::Size WindowSizeToContentSize(const gfx::Size& size) override;
void UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) override;
void InstallView(); void InstallView();
void UninstallView(); void UninstallView();
// Install the drag view, which will cover the whole window and decides // Install the drag view, which will cover the whole window and decides
// whehter we can drag. // whehter we can drag.
void InstallDraggableRegionView(); void UpdateDraggableRegionViews(const std::vector<DraggableRegion>& regions);
base::scoped_nsobject<AtomNSWindow> window_; base::scoped_nsobject<AtomNSWindow> window_;
base::scoped_nsobject<AtomNSWindowDelegate> window_delegate_; base::scoped_nsobject<AtomNSWindowDelegate> window_delegate_;
@ -102,6 +108,8 @@ class NativeWindowMac : public NativeWindow {
// The view that will fill the whole frameless window. // The view that will fill the whole frameless window.
base::scoped_nsobject<FullSizeContentView> content_view_; base::scoped_nsobject<FullSizeContentView> content_view_;
std::vector<DraggableRegion> draggable_regions_;
bool is_kiosk_; bool is_kiosk_;
NSInteger attention_request_id_; // identifier from requestUserAttention NSInteger attention_request_id_; // identifier from requestUserAttention
@ -109,10 +117,6 @@ class NativeWindowMac : public NativeWindow {
// The presentation options before entering kiosk mode. // The presentation options before entering kiosk mode.
NSApplicationPresentationOptions kiosk_options_; NSApplicationPresentationOptions kiosk_options_;
// Mouse location since the last mouse event, in screen coordinates. This is
// used in custom drag to compute the window movement.
NSPoint last_mouse_offset_;
DISALLOW_COPY_AND_ASSIGN(NativeWindowMac); DISALLOW_COPY_AND_ASSIGN(NativeWindowMac);
}; };

View file

@ -19,6 +19,7 @@
#include "content/public/browser/render_view_host.h" #include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/render_widget_host_view.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
#include "ui/gfx/skia_util.h"
namespace { namespace {
@ -146,6 +147,7 @@ bool ScopedDisableResize::disable_resize_ = false;
} }
- (void)windowDidResize:(NSNotification*)notification { - (void)windowDidResize:(NSNotification*)notification {
shell_->UpdateDraggableRegionViews();
shell_->NotifyWindowResize(); shell_->NotifyWindowResize();
} }
@ -257,43 +259,23 @@ bool ScopedDisableResize::disable_resize_ = false;
@end @end
@interface ControlRegionView : NSView { @interface ControlRegionView : NSView
@private
atom::NativeWindowMac* shellWindow_; // Weak; owns self.
}
@end @end
@implementation ControlRegionView @implementation ControlRegionView
- (id)initWithShellWindow:(atom::NativeWindowMac*)shellWindow {
if ((self = [super init]))
shellWindow_ = shellWindow;
return self;
}
- (BOOL)mouseDownCanMoveWindow { - (BOOL)mouseDownCanMoveWindow {
return NO; return NO;
} }
- (NSView*)hitTest:(NSPoint)aPoint { - (NSView*)hitTest:(NSPoint)aPoint {
if (!shellWindow_->IsWithinDraggableRegion(aPoint)) { return nil;
return nil;
}
return self;
} }
- (void)mouseDown:(NSEvent*)event { @end
shellWindow_->HandleMouseEvent(event);
}
- (void)mouseDragged:(NSEvent*)event {
shellWindow_->HandleMouseEvent(event);
}
- (BOOL)acceptsFirstMouse:(NSEvent*)event {
return YES;
}
@interface NSView (WebContentsView)
- (void)setMouseDownCanMoveWindow:(BOOL)can_move;
@end @end
@interface AtomProgressBar : NSProgressIndicator @interface AtomProgressBar : NSProgressIndicator
@ -350,6 +332,8 @@ NativeWindowMac::NativeWindowMac(
bool useStandardWindow = true; bool useStandardWindow = true;
options.Get(switches::kStandardWindow, &useStandardWindow); options.Get(switches::kStandardWindow, &useStandardWindow);
bool resizable = true;
options.Get(switches::kResizable, &resizable);
// New title bar styles are available in Yosemite or newer // New title bar styles are available in Yosemite or newer
std::string titleBarStyle; std::string titleBarStyle;
@ -357,10 +341,13 @@ NativeWindowMac::NativeWindowMac(
options.Get(switches::kTitleBarStyle, &titleBarStyle); options.Get(switches::kTitleBarStyle, &titleBarStyle);
NSUInteger styleMask = NSTitledWindowMask | NSClosableWindowMask | NSUInteger styleMask = NSTitledWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask | NSResizableWindowMask; NSMiniaturizableWindowMask;
if (!useStandardWindow || transparent() || !has_frame()) { if (!useStandardWindow || transparent() || !has_frame()) {
styleMask |= NSTexturedBackgroundWindowMask; styleMask |= NSTexturedBackgroundWindowMask;
} }
if (resizable) {
styleMask |= NSResizableWindowMask;
}
if ((titleBarStyle == "hidden") || (titleBarStyle == "hidden-inset")) { if ((titleBarStyle == "hidden") || (titleBarStyle == "hidden-inset")) {
styleMask |= NSFullSizeContentViewWindowMask; styleMask |= NSFullSizeContentViewWindowMask;
styleMask |= NSUnifiedTitleAndToolbarWindowMask; styleMask |= NSUnifiedTitleAndToolbarWindowMask;
@ -434,11 +421,6 @@ NativeWindowMac::NativeWindowMac(
[view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; [view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
InstallView(); InstallView();
// Install the DraggableRegionView if it is forced to use draggable regions
// for normal window.
if (has_frame() && force_using_draggable_region())
InstallDraggableRegionView();
} }
NativeWindowMac::~NativeWindowMac() { NativeWindowMac::~NativeWindowMac() {
@ -549,56 +531,30 @@ gfx::Rect NativeWindowMac::GetBounds() {
return bounds; return bounds;
} }
void NativeWindowMac::SetContentSize(const gfx::Size& size) { void NativeWindowMac::SetContentSizeConstraints(
if (!has_frame()) { const extensions::SizeConstraints& size_constraints) {
SetSize(size); auto convertSize = [this](const gfx::Size& size) {
return; // Our frameless window still has titlebar attached, so setting contentSize
// will result in actual content size being larger.
if (!has_frame()) {
NSRect frame = NSMakeRect(0, 0, size.width(), size.height());
NSRect content = [window_ contentRectForFrameRect:frame];
return content.size;
} else {
return NSMakeSize(size.width(), size.height());
}
};
NSView* content = [window_ contentView];
if (size_constraints.HasMinimumSize()) {
NSSize min_size = convertSize(size_constraints.GetMinimumSize());
[window_ setContentMinSize:[content convertSize:min_size toView:nil]];
} }
if (size_constraints.HasMaximumSize()) {
NSRect frame_nsrect = [window_ frame]; NSSize max_size = convertSize(size_constraints.GetMaximumSize());
NSSize frame = frame_nsrect.size; [window_ setContentMaxSize:[content convertSize:max_size toView:nil]];
NSSize content = [window_ contentRectForFrameRect:frame_nsrect].size; }
NativeWindow::SetContentSizeConstraints(size_constraints);
int width = size.width() + frame.width - content.width;
int height = size.height() + frame.height - content.height;
frame_nsrect.origin.y -= height - frame_nsrect.size.height;
frame_nsrect.size.width = width;
frame_nsrect.size.height = height;
[window_ setFrame:frame_nsrect display:YES];
}
gfx::Size NativeWindowMac::GetContentSize() {
if (!has_frame())
return GetSize();
NSRect bounds = [[window_ contentView] bounds];
return gfx::Size(bounds.size.width, bounds.size.height);
}
void NativeWindowMac::SetMinimumSize(const gfx::Size& size) {
NSSize min_size = NSMakeSize(size.width(), size.height());
NSView* content = [window_ contentView];
[window_ setContentMinSize:[content convertSize:min_size toView:nil]];
}
gfx::Size NativeWindowMac::GetMinimumSize() {
NSView* content = [window_ contentView];
NSSize min_size = [content convertSize:[window_ contentMinSize]
fromView:nil];
return gfx::Size(min_size.width, min_size.height);
}
void NativeWindowMac::SetMaximumSize(const gfx::Size& size) {
NSSize max_size = NSMakeSize(size.width(), size.height());
NSView* content = [window_ contentView];
[window_ setContentMaxSize:[content convertSize:max_size toView:nil]];
}
gfx::Size NativeWindowMac::GetMaximumSize() {
NSView* content = [window_ contentView];
NSSize max_size = [content convertSize:[window_ contentMaxSize]
fromView:nil];
return gfx::Size(max_size.width, max_size.height);
} }
void NativeWindowMac::SetResizable(bool resizable) { void NativeWindowMac::SetResizable(bool resizable) {
@ -679,6 +635,9 @@ bool NativeWindowMac::IsKiosk() {
return is_kiosk_; return is_kiosk_;
} }
void NativeWindowMac::SetBackgroundColor(const std::string& color_name) {
}
void NativeWindowMac::SetRepresentedFilename(const std::string& filename) { void NativeWindowMac::SetRepresentedFilename(const std::string& filename) {
[window_ setRepresentedFilename:base::SysUTF8ToNSString(filename)]; [window_ setRepresentedFilename:base::SysUTF8ToNSString(filename)];
} }
@ -767,36 +726,6 @@ bool NativeWindowMac::IsVisibleOnAllWorkspaces() {
return collectionBehavior & NSWindowCollectionBehaviorCanJoinAllSpaces; return collectionBehavior & NSWindowCollectionBehaviorCanJoinAllSpaces;
} }
bool NativeWindowMac::IsWithinDraggableRegion(NSPoint point) const {
if (!draggable_region())
return false;
if (!web_contents())
return false;
NSView* webView = web_contents()->GetNativeView();
NSInteger webViewHeight = NSHeight([webView bounds]);
// |draggable_region_| is stored in local platform-indepdent coordiate system
// while |point| is in local Cocoa coordinate system. Do the conversion
// to match these two.
return draggable_region()->contains(point.x, webViewHeight - point.y);
}
void NativeWindowMac::HandleMouseEvent(NSEvent* event) {
NSPoint eventLoc = [event locationInWindow];
NSRect mouseRect = [window_ convertRectToScreen:NSMakeRect(eventLoc.x, eventLoc.y, 0, 0)];
NSPoint current_mouse_location = mouseRect.origin;
if ([event type] == NSLeftMouseDown) {
NSPoint frame_origin = [window_ frame].origin;
last_mouse_offset_ = NSMakePoint(
frame_origin.x - current_mouse_location.x,
frame_origin.y - current_mouse_location.y);
} else if ([event type] == NSLeftMouseDragged) {
[window_ setFrameOrigin:NSMakePoint(
current_mouse_location.x + last_mouse_offset_.x,
current_mouse_location.y + last_mouse_offset_.y)];
}
}
void NativeWindowMac::HandleKeyboardEvent( void NativeWindowMac::HandleKeyboardEvent(
content::WebContents*, content::WebContents*,
const content::NativeWebKeyboardEvent& event) { const content::NativeWebKeyboardEvent& event) {
@ -821,6 +750,48 @@ void NativeWindowMac::HandleKeyboardEvent(
} }
} }
std::vector<gfx::Rect> NativeWindowMac::CalculateNonDraggableRegions(
const std::vector<DraggableRegion>& regions, int width, int height) {
std::vector<gfx::Rect> result;
if (regions.empty()) {
result.push_back(gfx::Rect(0, 0, width, height));
} else {
scoped_ptr<SkRegion> draggable(DraggableRegionsToSkRegion(regions));
scoped_ptr<SkRegion> non_draggable(new SkRegion);
non_draggable->op(0, 0, width, height, SkRegion::kUnion_Op);
non_draggable->op(*draggable, SkRegion::kDifference_Op);
for (SkRegion::Iterator it(*non_draggable); !it.done(); it.next()) {
result.push_back(gfx::SkIRectToRect(it.rect()));
}
}
return result;
}
gfx::Size NativeWindowMac::ContentSizeToWindowSize(const gfx::Size& size) {
if (!has_frame())
return size;
NSRect content = NSMakeRect(0, 0, size.width(), size.height());
NSRect frame = [window_ frameRectForContentRect:content];
return gfx::Size(frame.size);
}
gfx::Size NativeWindowMac::WindowSizeToContentSize(const gfx::Size& size) {
if (!has_frame())
return size;
NSRect frame = NSMakeRect(0, 0, size.width(), size.height());
NSRect content = [window_ contentRectForFrameRect:frame];
return gfx::Size(content.size);
}
void NativeWindowMac::UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) {
NativeWindow::UpdateDraggableRegions(regions);
draggable_regions_ = regions;
UpdateDraggableRegionViews(regions);
}
void NativeWindowMac::InstallView() { void NativeWindowMac::InstallView() {
// Make sure the bottom corner is rounded: http://crbug.com/396264. // Make sure the bottom corner is rounded: http://crbug.com/396264.
[[window_ contentView] setWantsLayer:YES]; [[window_ contentView] setWantsLayer:YES];
@ -843,8 +814,6 @@ void NativeWindowMac::InstallView() {
[view setFrame:[content_view_ bounds]]; [view setFrame:[content_view_ bounds]];
[content_view_ addSubview:view]; [content_view_ addSubview:view];
InstallDraggableRegionView();
[[window_ standardWindowButton:NSWindowZoomButton] setHidden:YES]; [[window_ standardWindowButton:NSWindowZoomButton] setHidden:YES];
[[window_ standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES]; [[window_ standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
[[window_ standardWindowButton:NSWindowCloseButton] setHidden:YES]; [[window_ standardWindowButton:NSWindowCloseButton] setHidden:YES];
@ -861,14 +830,55 @@ void NativeWindowMac::UninstallView() {
[view removeFromSuperview]; [view removeFromSuperview];
} }
void NativeWindowMac::InstallDraggableRegionView() { void NativeWindowMac::UpdateDraggableRegionViews(
const std::vector<DraggableRegion>& regions) {
if (has_frame() && !force_using_draggable_region())
return;
// All ControlRegionViews should be added as children of the WebContentsView,
// because WebContentsView will be removed and re-added when entering and
// leaving fullscreen mode.
NSView* webView = web_contents()->GetNativeView(); NSView* webView = web_contents()->GetNativeView();
base::scoped_nsobject<NSView> controlRegion( NSInteger webViewWidth = NSWidth([webView bounds]);
[[ControlRegionView alloc] initWithShellWindow:this]); NSInteger webViewHeight = NSHeight([webView bounds]);
[controlRegion setFrame:NSMakeRect(0, 0,
NSWidth([webView bounds]), [webView setMouseDownCanMoveWindow:YES];
NSHeight([webView bounds]))];
[webView addSubview:controlRegion]; // Remove all ControlRegionViews that are added last time.
// Note that [webView subviews] returns the view's mutable internal array and
// it should be copied to avoid mutating the original array while enumerating
// it.
base::scoped_nsobject<NSArray> subviews([[webView subviews] copy]);
for (NSView* subview in subviews.get())
if ([subview isKindOfClass:[ControlRegionView class]])
[subview removeFromSuperview];
// Draggable regions is implemented by having the whole web view draggable
// (mouseDownCanMoveWindow) and overlaying regions that are not draggable.
std::vector<gfx::Rect> system_drag_exclude_areas =
CalculateNonDraggableRegions(regions, webViewWidth, webViewHeight);
// Create and add a ControlRegionView for each region that needs to be
// excluded from the dragging.
for (std::vector<gfx::Rect>::const_iterator iter =
system_drag_exclude_areas.begin();
iter != system_drag_exclude_areas.end();
++iter) {
base::scoped_nsobject<NSView> controlRegion(
[[ControlRegionView alloc] initWithFrame:NSZeroRect]);
[controlRegion setFrame:NSMakeRect(iter->x(),
webViewHeight - iter->bottom(),
iter->width(),
iter->height())];
[webView addSubview:controlRegion];
}
// AppKit will not update its cache of mouseDownCanMoveWindow unless something
// changes. Previously we tried adding an NSView and removing it, but for some
// reason it required reposting the mouse-down event, and didn't always work.
// Calling the below seems to be an effective solution.
[window_ setMovableByWindowBackground:NO];
[window_ setMovableByWindowBackground:YES];
} }
// static // static

View file

@ -11,6 +11,10 @@
#include "ui/base/window_open_disposition.h" #include "ui/base/window_open_disposition.h"
#include "url/gurl.h" #include "url/gurl.h"
#if defined(OS_WIN)
#include <windows.h>
#endif
namespace atom { namespace atom {
class NativeWindowObserver { class NativeWindowObserver {
@ -55,6 +59,11 @@ class NativeWindowObserver {
virtual void OnWindowEnterHtmlFullScreen() {} virtual void OnWindowEnterHtmlFullScreen() {}
virtual void OnWindowLeaveHtmlFullScreen() {} virtual void OnWindowLeaveHtmlFullScreen() {}
// Called when window message received
#if defined(OS_WIN)
virtual void OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) {}
#endif
// Called when renderer is hung. // Called when renderer is hung.
virtual void OnRendererUnresponsive() {} virtual void OnRendererUnresponsive() {}

View file

@ -42,6 +42,7 @@
#elif defined(OS_WIN) #elif defined(OS_WIN)
#include "atom/browser/ui/views/win_frame_view.h" #include "atom/browser/ui/views/win_frame_view.h"
#include "atom/browser/ui/win/atom_desktop_window_tree_host_win.h" #include "atom/browser/ui/win/atom_desktop_window_tree_host_win.h"
#include "skia/ext/skia_utils_win.h"
#include "ui/base/win/shell.h" #include "ui/base/win/shell.h"
#include "ui/gfx/win/dpi.h" #include "ui/gfx/win/dpi.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h" #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
@ -77,69 +78,28 @@ bool IsAltModifier(const content::NativeWebKeyboardEvent& event) {
(modifiers == (Modifiers::AltKey | Modifiers::IsRight)); (modifiers == (Modifiers::AltKey | Modifiers::IsRight));
} }
#if defined(OS_WIN) SkColor ParseHexColor(const std::string& name) {
// Convert Win32 WM_APPCOMMANDS to strings. SkColor result = 0xFF000000;
const char* AppCommandToString(int command_id) { unsigned value = 0;
switch (command_id) { auto color = name.substr(1);
case APPCOMMAND_BROWSER_BACKWARD : return "browser-backward"; unsigned length = color.size();
case APPCOMMAND_BROWSER_FORWARD : return "browser-forward"; if (length != 3 && length != 6)
case APPCOMMAND_BROWSER_REFRESH : return "browser-refresh"; return result;
case APPCOMMAND_BROWSER_STOP : return "browser-stop"; for (unsigned i = 0; i < length; ++i) {
case APPCOMMAND_BROWSER_SEARCH : return "browser-search"; if (!base::IsHexDigit(color[i]))
case APPCOMMAND_BROWSER_FAVORITES : return "browser-favorites"; return result;
case APPCOMMAND_BROWSER_HOME : return "browser-home"; value <<= 4;
case APPCOMMAND_VOLUME_MUTE : return "volume-mute"; value |= (color[i] < 'A' ? color[i] - '0' : (color[i] - 'A' + 10) & 0xF);
case APPCOMMAND_VOLUME_DOWN : return "volume-down";
case APPCOMMAND_VOLUME_UP : return "volume-up";
case APPCOMMAND_MEDIA_NEXTTRACK : return "media-nexttrack";
case APPCOMMAND_MEDIA_PREVIOUSTRACK : return "media-previoustrack";
case APPCOMMAND_MEDIA_STOP : return "media-stop";
case APPCOMMAND_MEDIA_PLAY_PAUSE : return "media-play_pause";
case APPCOMMAND_LAUNCH_MAIL : return "launch-mail";
case APPCOMMAND_LAUNCH_MEDIA_SELECT : return "launch-media-select";
case APPCOMMAND_LAUNCH_APP1 : return "launch-app1";
case APPCOMMAND_LAUNCH_APP2 : return "launch-app2";
case APPCOMMAND_BASS_DOWN : return "bass-down";
case APPCOMMAND_BASS_BOOST : return "bass-boost";
case APPCOMMAND_BASS_UP : return "bass-up";
case APPCOMMAND_TREBLE_DOWN : return "treble-down";
case APPCOMMAND_TREBLE_UP : return "treble-up";
case APPCOMMAND_MICROPHONE_VOLUME_MUTE : return "microphone-volume-mute";
case APPCOMMAND_MICROPHONE_VOLUME_DOWN : return "microphone-volume-down";
case APPCOMMAND_MICROPHONE_VOLUME_UP : return "microphone-volume-up";
case APPCOMMAND_HELP : return "help";
case APPCOMMAND_FIND : return "find";
case APPCOMMAND_NEW : return "new";
case APPCOMMAND_OPEN : return "open";
case APPCOMMAND_CLOSE : return "close";
case APPCOMMAND_SAVE : return "save";
case APPCOMMAND_PRINT : return "print";
case APPCOMMAND_UNDO : return "undo";
case APPCOMMAND_REDO : return "redo";
case APPCOMMAND_COPY : return "copy";
case APPCOMMAND_CUT : return "cut";
case APPCOMMAND_PASTE : return "paste";
case APPCOMMAND_REPLY_TO_MAIL : return "reply-to-mail";
case APPCOMMAND_FORWARD_MAIL : return "forward-mail";
case APPCOMMAND_SEND_MAIL : return "send-mail";
case APPCOMMAND_SPELL_CHECK : return "spell-check";
case APPCOMMAND_MIC_ON_OFF_TOGGLE : return "mic-on-off-toggle";
case APPCOMMAND_CORRECTION_LIST : return "correction-list";
case APPCOMMAND_MEDIA_PLAY : return "media-play";
case APPCOMMAND_MEDIA_PAUSE : return "media-pause";
case APPCOMMAND_MEDIA_RECORD : return "media-record";
case APPCOMMAND_MEDIA_FAST_FORWARD : return "media-fast-forward";
case APPCOMMAND_MEDIA_REWIND : return "media-rewind";
case APPCOMMAND_MEDIA_CHANNEL_UP : return "media-channel-up";
case APPCOMMAND_MEDIA_CHANNEL_DOWN : return "media-channel-down";
case APPCOMMAND_DELETE : return "delete";
case APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE:
return "dictate-or-command-control-toggle";
default:
return "unknown";
} }
if (length == 6) {
result |= value;
return result;
}
result |= (value & 0xF00) << 12 | (value & 0xF00) << 8
| (value & 0xF0) << 8 | (value & 0xF0) << 4
| (value & 0xF) << 4 | (value & 0xF);
return result;
} }
#endif
class NativeWindowClientView : public views::ClientView { class NativeWindowClientView : public views::ClientView {
public: public:
@ -186,7 +146,8 @@ NativeWindowViews::NativeWindowViews(
// will not allow us to resize the window larger than scree. // will not allow us to resize the window larger than scree.
// Setting directly to INT_MAX somehow doesn't work, so we just devide // Setting directly to INT_MAX somehow doesn't work, so we just devide
// by 10, which should still be large enough. // by 10, which should still be large enough.
maximum_size_.SetSize(INT_MAX / 10, INT_MAX / 10); SetContentSizeConstraints(extensions::SizeConstraints(
gfx::Size(), gfx::Size(INT_MAX / 10, INT_MAX / 10)));
int width = 800, height = 600; int width = 800, height = 600;
options.Get(switches::kWidth, &width); options.Get(switches::kWidth, &width);
@ -268,13 +229,8 @@ NativeWindowViews::NativeWindowViews(
// Add web view. // Add web view.
SetLayoutManager(new MenuLayout(this, kMenuBarHeight)); SetLayoutManager(new MenuLayout(this, kMenuBarHeight));
set_background(views::Background::CreateStandardPanelBackground());
AddChildView(web_view_);
if (has_frame() && AddChildView(web_view_);
options.Get(switches::kUseContentSize, &use_content_size_) &&
use_content_size_)
bounds = ContentBoundsToWindowBounds(bounds);
#if defined(OS_WIN) #if defined(OS_WIN)
// Save initial window state. // Save initial window state.
@ -316,8 +272,14 @@ NativeWindowViews::NativeWindowViews(
if (transparent() && !has_frame()) if (transparent() && !has_frame())
wm::SetShadowType(GetNativeWindow(), wm::SHADOW_TYPE_NONE); wm::SetShadowType(GetNativeWindow(), wm::SHADOW_TYPE_NONE);
gfx::Size size = bounds.size();
if (has_frame() &&
options.Get(switches::kUseContentSize, &use_content_size_) &&
use_content_size_)
size = ContentSizeToWindowSize(size);
window_->UpdateWindowIcon(); window_->UpdateWindowIcon();
window_->CenterWindow(bounds.size()); window_->CenterWindow(size);
Layout(); Layout();
} }
@ -440,42 +402,26 @@ gfx::Rect NativeWindowViews::GetBounds() {
return window_->GetWindowBoundsInScreen(); return window_->GetWindowBoundsInScreen();
} }
void NativeWindowViews::SetContentSize(const gfx::Size& size) {
if (!has_frame()) {
NativeWindow::SetSize(size);
return;
}
gfx::Rect bounds = window_->GetWindowBoundsInScreen();
bounds.set_size(size);
SetBounds(ContentBoundsToWindowBounds(bounds));
}
gfx::Size NativeWindowViews::GetContentSize() { gfx::Size NativeWindowViews::GetContentSize() {
if (!has_frame()) #if defined(OS_WIN)
return GetSize(); if (IsMinimized())
return NativeWindow::GetContentSize();
#endif
gfx::Size content_size = return web_view_->size();
window_->non_client_view()->frame_view()->GetBoundsForClientView().size();
if (menu_bar_ && menu_bar_visible_)
content_size.set_height(content_size.height() - kMenuBarHeight);
return content_size;
} }
void NativeWindowViews::SetMinimumSize(const gfx::Size& size) { void NativeWindowViews::SetContentSizeConstraints(
minimum_size_ = size; const extensions::SizeConstraints& size_constraints) {
} NativeWindow::SetContentSizeConstraints(size_constraints);
// widget_delegate() is only available after Init() is called, we make use of
gfx::Size NativeWindowViews::GetMinimumSize() { // this to determine whether native widget has initialized.
return minimum_size_; if (window_ && window_->widget_delegate())
} window_->OnSizeConstraintsChanged();
#if defined(USE_X11)
void NativeWindowViews::SetMaximumSize(const gfx::Size& size) { if (resizable_)
maximum_size_ = size; old_size_constraints_ = size_constraints;
} #endif
gfx::Size NativeWindowViews::GetMaximumSize() {
return maximum_size_;
} }
void NativeWindowViews::SetResizable(bool resizable) { void NativeWindowViews::SetResizable(bool resizable) {
@ -494,11 +440,13 @@ void NativeWindowViews::SetResizable(bool resizable) {
// On Linux there is no "resizable" property of a window, we have to set // On Linux there is no "resizable" property of a window, we have to set
// both the minimum and maximum size to the window size to achieve it. // both the minimum and maximum size to the window size to achieve it.
if (resizable) { if (resizable) {
SetMaximumSize(gfx::Size()); SetContentSizeConstraints(old_size_constraints_);
SetMinimumSize(gfx::Size());
} else { } else {
SetMaximumSize(GetSize()); old_size_constraints_ = GetContentSizeConstraints();
SetMinimumSize(GetSize()); resizable_ = false;
gfx::Size content_size = GetContentSize();
SetContentSizeConstraints(
extensions::SizeConstraints(content_size, content_size));
} }
} }
#endif #endif
@ -572,6 +520,21 @@ bool NativeWindowViews::IsKiosk() {
return IsFullscreen(); return IsFullscreen();
} }
void NativeWindowViews::SetBackgroundColor(const std::string& color_name) {
// web views' background color.
SkColor background_color = ParseHexColor(color_name);
set_background(views::Background::CreateSolidBackground(background_color));
#if defined(OS_WIN)
// Set the background color of native window.
HBRUSH brush = CreateSolidBrush(skia::SkColorToCOLORREF(background_color));
ULONG_PTR previous_brush = SetClassLongPtr(
GetAcceleratedWidget(), GCLP_HBRBACKGROUND, (LONG)brush);
if (previous_brush)
DeleteObject((HBRUSH)previous_brush);
#endif
}
void NativeWindowViews::SetMenu(ui::MenuModel* menu_model) { void NativeWindowViews::SetMenu(ui::MenuModel* menu_model) {
if (menu_model == nullptr) { if (menu_model == nullptr) {
// Remove accelerators // Remove accelerators
@ -610,8 +573,24 @@ void NativeWindowViews::SetMenu(ui::MenuModel* menu_model) {
if (!menu_bar_autohide_) { if (!menu_bar_autohide_) {
SetMenuBarVisibility(true); SetMenuBarVisibility(true);
if (use_content_size_) if (use_content_size_) {
// Enlarge the size constraints for the menu.
extensions::SizeConstraints constraints = GetContentSizeConstraints();
if (constraints.HasMinimumSize()) {
gfx::Size min_size = constraints.GetMinimumSize();
min_size.set_height(min_size.height() + kMenuBarHeight);
constraints.set_minimum_size(min_size);
}
if (constraints.HasMaximumSize()) {
gfx::Size max_size = constraints.GetMaximumSize();
max_size.set_height(max_size.height() + kMenuBarHeight);
constraints.set_maximum_size(max_size);
}
SetContentSizeConstraints(constraints);
// Resize the window to make sure content size is not changed.
SetContentSize(content_size); SetContentSize(content_size);
}
} }
} }
@ -814,103 +793,45 @@ void NativeWindowViews::OnWidgetMove() {
NotifyWindowMove(); NotifyWindowMove();
} }
#if defined(OS_WIN) gfx::Size NativeWindowViews::ContentSizeToWindowSize(const gfx::Size& size) {
bool NativeWindowViews::ExecuteWindowsCommand(int command_id) { if (!has_frame())
std::string command = AppCommandToString(command_id);
NotifyWindowExecuteWindowsCommand(command);
return false;
}
bool NativeWindowViews::PreHandleMSG(
UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) {
switch (message) {
case WM_COMMAND:
// Handle thumbar button click message.
if (HIWORD(w_param) == THBN_CLICKED)
return taskbar_host_.HandleThumbarButtonEvent(LOWORD(w_param));
return false;
case WM_SIZE:
// Handle window state change.
HandleSizeEvent(w_param, l_param);
return false;
default:
return false;
}
}
void NativeWindowViews::HandleSizeEvent(WPARAM w_param, LPARAM l_param) {
// Here we handle the WM_SIZE event in order to figure out what is the current
// window state and notify the user accordingly.
switch (w_param) {
case SIZE_MAXIMIZED:
last_window_state_ = ui::SHOW_STATE_MAXIMIZED;
NotifyWindowMaximize();
break;
case SIZE_MINIMIZED:
last_window_state_ = ui::SHOW_STATE_MINIMIZED;
NotifyWindowMinimize();
break;
case SIZE_RESTORED:
if (last_window_state_ == ui::SHOW_STATE_NORMAL) {
// Window was resized so we save it's new size.
last_normal_size_ = GetSize();
} else {
switch (last_window_state_) {
case ui::SHOW_STATE_MAXIMIZED:
last_window_state_ = ui::SHOW_STATE_NORMAL;
// When the window is restored we resize it to the previous known
// normal size.
NativeWindow::SetSize(last_normal_size_);
NotifyWindowUnmaximize();
break;
case ui::SHOW_STATE_MINIMIZED:
if (IsFullscreen()) {
last_window_state_ = ui::SHOW_STATE_FULLSCREEN;
NotifyWindowEnterFullScreen();
} else {
last_window_state_ = ui::SHOW_STATE_NORMAL;
// When the window is restored we resize it to the previous known
// normal size.
NativeWindow::SetSize(last_normal_size_);
NotifyWindowRestore();
}
break;
}
}
break;
}
}
#endif
gfx::Size NativeWindowViews::WindowSizeToFramelessSize(
const gfx::Size& size) {
if (size.width() == 0 && size.height() == 0)
return size; return size;
gfx::Rect window_bounds = gfx::Rect(size); gfx::Size window_size(size);
if (use_content_size_) {
if (menu_bar_ && menu_bar_visible_) {
window_bounds.set_height(window_bounds.height() + kMenuBarHeight);
}
} else if (has_frame()) {
#if defined(OS_WIN) #if defined(OS_WIN)
gfx::Size frame_size = gfx::win::ScreenToDIPRect( gfx::Rect dpi_bounds =
window_->non_client_view()->GetWindowBoundsForClientBounds( gfx::Rect(gfx::Point(), gfx::win::DIPToScreenSize(size));
gfx::Rect())).size(); gfx::Rect window_bounds = gfx::win::ScreenToDIPRect(
#else window_->non_client_view()->GetWindowBoundsForClientBounds(dpi_bounds));
gfx::Size frame_size = window_size = window_bounds.size();
window_->non_client_view()->GetWindowBoundsForClientBounds(
gfx::Rect()).size();
#endif #endif
window_bounds.set_height(window_bounds.height() - frame_size.height());
window_bounds.set_width(window_bounds.width() - frame_size.width());
}
return window_bounds.size(); if (menu_bar_ && menu_bar_visible_)
window_size.set_height(window_size.height() + kMenuBarHeight);
return window_size;
}
gfx::Size NativeWindowViews::WindowSizeToContentSize(const gfx::Size& size) {
if (!has_frame())
return size;
gfx::Size content_size(size);
#if defined(OS_WIN)
content_size = gfx::win::DIPToScreenSize(content_size);
RECT rect;
SetRectEmpty(&rect);
HWND hwnd = GetAcceleratedWidget();
DWORD style = ::GetWindowLong(hwnd, GWL_STYLE);
DWORD ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
AdjustWindowRectEx(&rect, style, FALSE, ex_style);
content_size.set_width(content_size.width() - (rect.right - rect.left));
content_size.set_height(content_size.height() - (rect.bottom - rect.top));
content_size = gfx::win::ScreenToDIPSize(content_size);
#endif
if (menu_bar_ && menu_bar_visible_)
content_size.set_height(content_size.height() - kMenuBarHeight);
return content_size;
} }
void NativeWindowViews::HandleKeyboardEvent( void NativeWindowViews::HandleKeyboardEvent(
@ -954,6 +875,14 @@ void NativeWindowViews::HandleKeyboardEvent(
} }
} }
gfx::Size NativeWindowViews::GetMinimumSize() {
return NativeWindow::GetMinimumSize();
}
gfx::Size NativeWindowViews::GetMaximumSize() {
return NativeWindow::GetMaximumSize();
}
bool NativeWindowViews::AcceleratorPressed(const ui::Accelerator& accelerator) { bool NativeWindowViews::AcceleratorPressed(const ui::Accelerator& accelerator) {
return accelerator_util::TriggerAcceleratorTableCommand( return accelerator_util::TriggerAcceleratorTableCommand(
&accelerator_table_, accelerator); &accelerator_table_, accelerator);
@ -976,26 +905,6 @@ void NativeWindowViews::RegisterAccelerators(ui::MenuModel* menu_model) {
} }
} }
gfx::Rect NativeWindowViews::ContentBoundsToWindowBounds(
const gfx::Rect& bounds) {
gfx::Point origin = bounds.origin();
#if defined(OS_WIN)
gfx::Rect dpi_bounds = gfx::win::DIPToScreenRect(bounds);
gfx::Rect window_bounds = gfx::win::ScreenToDIPRect(
window_->non_client_view()->GetWindowBoundsForClientBounds(dpi_bounds));
#else
gfx::Rect window_bounds =
window_->non_client_view()->GetWindowBoundsForClientBounds(bounds);
#endif
// The window's position would also be changed, but we only want to change
// the size.
window_bounds.set_origin(origin);
if (menu_bar_ && menu_bar_visible_)
window_bounds.set_height(window_bounds.height() + kMenuBarHeight);
return window_bounds;
}
ui::WindowShowState NativeWindowViews::GetRestoredState() { ui::WindowShowState NativeWindowViews::GetRestoredState() {
if (IsMaximized()) if (IsMaximized())
return ui::SHOW_STATE_MAXIMIZED; return ui::SHOW_STATE_MAXIMIZED;

View file

@ -63,12 +63,9 @@ class NativeWindowViews : public NativeWindow,
bool IsFullscreen() const override; bool IsFullscreen() const override;
void SetBounds(const gfx::Rect& bounds) override; void SetBounds(const gfx::Rect& bounds) override;
gfx::Rect GetBounds() override; gfx::Rect GetBounds() override;
void SetContentSize(const gfx::Size& size) override;
gfx::Size GetContentSize() override; gfx::Size GetContentSize() override;
void SetMinimumSize(const gfx::Size& size) override; void SetContentSizeConstraints(
gfx::Size GetMinimumSize() override; const extensions::SizeConstraints& size_constraints) override;
void SetMaximumSize(const gfx::Size& size) override;
gfx::Size GetMaximumSize() override;
void SetResizable(bool resizable) override; void SetResizable(bool resizable) override;
bool IsResizable() override; bool IsResizable() override;
void SetAlwaysOnTop(bool top) override; void SetAlwaysOnTop(bool top) override;
@ -80,6 +77,7 @@ class NativeWindowViews : public NativeWindow,
void SetSkipTaskbar(bool skip) override; void SetSkipTaskbar(bool skip) override;
void SetKiosk(bool kiosk) override; void SetKiosk(bool kiosk) override;
bool IsKiosk() override; bool IsKiosk() override;
void SetBackgroundColor(const std::string& color_name) override;
void SetMenu(ui::MenuModel* menu_model) override; void SetMenu(ui::MenuModel* menu_model) override;
gfx::NativeWindow GetNativeWindow() override; gfx::NativeWindow GetNativeWindow() override;
void SetOverlayIcon(const gfx::Image& overlay, void SetOverlayIcon(const gfx::Image& overlay,
@ -94,8 +92,6 @@ class NativeWindowViews : public NativeWindow,
gfx::AcceleratedWidget GetAcceleratedWidget(); gfx::AcceleratedWidget GetAcceleratedWidget();
gfx::Size WindowSizeToFramelessSize(const gfx::Size& size);
views::Widget* widget() const { return window_.get(); } views::Widget* widget() const { return window_.get(); }
#if defined(OS_WIN) #if defined(OS_WIN)
@ -142,20 +138,20 @@ class NativeWindowViews : public NativeWindow,
#endif #endif
// NativeWindow: // NativeWindow:
gfx::Size ContentSizeToWindowSize(const gfx::Size& size) override;
gfx::Size WindowSizeToContentSize(const gfx::Size& size) override;
void HandleKeyboardEvent( void HandleKeyboardEvent(
content::WebContents*, content::WebContents*,
const content::NativeWebKeyboardEvent& event) override; const content::NativeWebKeyboardEvent& event) override;
// views::View: // views::View:
gfx::Size GetMinimumSize() override;
gfx::Size GetMaximumSize() override;
bool AcceleratorPressed(const ui::Accelerator& accelerator) override; bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
// Register accelerators supported by the menu model. // Register accelerators supported by the menu model.
void RegisterAccelerators(ui::MenuModel* menu_model); void RegisterAccelerators(ui::MenuModel* menu_model);
// Converts between client area and window area, since we include the menu bar
// in client area we need to substract/add menu bar's height in convertions.
gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& content_bounds);
// Returns the restore state for the window. // Returns the restore state for the window.
ui::WindowShowState GetRestoredState(); ui::WindowShowState GetRestoredState();
@ -172,6 +168,11 @@ class NativeWindowViews : public NativeWindow,
// Handles window state events. // Handles window state events.
scoped_ptr<WindowStateWatcher> window_state_watcher_; scoped_ptr<WindowStateWatcher> window_state_watcher_;
// The "resizable" flag on Linux is implemented by setting size constraints,
// we need to make sure size constraints are restored when window becomes
// resizable again.
extensions::SizeConstraints old_size_constraints_;
#elif defined(OS_WIN) #elif defined(OS_WIN)
// Weak ref. // Weak ref.
AtomDesktopWindowTreeHostWin* atom_desktop_window_tree_host_win_; AtomDesktopWindowTreeHostWin* atom_desktop_window_tree_host_win_;
@ -197,8 +198,6 @@ class NativeWindowViews : public NativeWindow,
bool use_content_size_; bool use_content_size_;
bool resizable_; bool resizable_;
std::string title_; std::string title_;
gfx::Size minimum_size_;
gfx::Size maximum_size_;
gfx::Size widget_size_; gfx::Size widget_size_;
DISALLOW_COPY_AND_ASSIGN(NativeWindowViews); DISALLOW_COPY_AND_ASSIGN(NativeWindowViews);

View file

@ -0,0 +1,162 @@
// Copyright (c) 2015 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/native_window_views.h"
#include "content/public/browser/browser_accessibility_state.h"
namespace atom {
namespace {
// Convert Win32 WM_APPCOMMANDS to strings.
const char* AppCommandToString(int command_id) {
switch (command_id) {
case APPCOMMAND_BROWSER_BACKWARD : return "browser-backward";
case APPCOMMAND_BROWSER_FORWARD : return "browser-forward";
case APPCOMMAND_BROWSER_REFRESH : return "browser-refresh";
case APPCOMMAND_BROWSER_STOP : return "browser-stop";
case APPCOMMAND_BROWSER_SEARCH : return "browser-search";
case APPCOMMAND_BROWSER_FAVORITES : return "browser-favorites";
case APPCOMMAND_BROWSER_HOME : return "browser-home";
case APPCOMMAND_VOLUME_MUTE : return "volume-mute";
case APPCOMMAND_VOLUME_DOWN : return "volume-down";
case APPCOMMAND_VOLUME_UP : return "volume-up";
case APPCOMMAND_MEDIA_NEXTTRACK : return "media-nexttrack";
case APPCOMMAND_MEDIA_PREVIOUSTRACK : return "media-previoustrack";
case APPCOMMAND_MEDIA_STOP : return "media-stop";
case APPCOMMAND_MEDIA_PLAY_PAUSE : return "media-play_pause";
case APPCOMMAND_LAUNCH_MAIL : return "launch-mail";
case APPCOMMAND_LAUNCH_MEDIA_SELECT : return "launch-media-select";
case APPCOMMAND_LAUNCH_APP1 : return "launch-app1";
case APPCOMMAND_LAUNCH_APP2 : return "launch-app2";
case APPCOMMAND_BASS_DOWN : return "bass-down";
case APPCOMMAND_BASS_BOOST : return "bass-boost";
case APPCOMMAND_BASS_UP : return "bass-up";
case APPCOMMAND_TREBLE_DOWN : return "treble-down";
case APPCOMMAND_TREBLE_UP : return "treble-up";
case APPCOMMAND_MICROPHONE_VOLUME_MUTE : return "microphone-volume-mute";
case APPCOMMAND_MICROPHONE_VOLUME_DOWN : return "microphone-volume-down";
case APPCOMMAND_MICROPHONE_VOLUME_UP : return "microphone-volume-up";
case APPCOMMAND_HELP : return "help";
case APPCOMMAND_FIND : return "find";
case APPCOMMAND_NEW : return "new";
case APPCOMMAND_OPEN : return "open";
case APPCOMMAND_CLOSE : return "close";
case APPCOMMAND_SAVE : return "save";
case APPCOMMAND_PRINT : return "print";
case APPCOMMAND_UNDO : return "undo";
case APPCOMMAND_REDO : return "redo";
case APPCOMMAND_COPY : return "copy";
case APPCOMMAND_CUT : return "cut";
case APPCOMMAND_PASTE : return "paste";
case APPCOMMAND_REPLY_TO_MAIL : return "reply-to-mail";
case APPCOMMAND_FORWARD_MAIL : return "forward-mail";
case APPCOMMAND_SEND_MAIL : return "send-mail";
case APPCOMMAND_SPELL_CHECK : return "spell-check";
case APPCOMMAND_MIC_ON_OFF_TOGGLE : return "mic-on-off-toggle";
case APPCOMMAND_CORRECTION_LIST : return "correction-list";
case APPCOMMAND_MEDIA_PLAY : return "media-play";
case APPCOMMAND_MEDIA_PAUSE : return "media-pause";
case APPCOMMAND_MEDIA_RECORD : return "media-record";
case APPCOMMAND_MEDIA_FAST_FORWARD : return "media-fast-forward";
case APPCOMMAND_MEDIA_REWIND : return "media-rewind";
case APPCOMMAND_MEDIA_CHANNEL_UP : return "media-channel-up";
case APPCOMMAND_MEDIA_CHANNEL_DOWN : return "media-channel-down";
case APPCOMMAND_DELETE : return "delete";
case APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE:
return "dictate-or-command-control-toggle";
default:
return "unknown";
}
}
} // namespace
bool NativeWindowViews::ExecuteWindowsCommand(int command_id) {
std::string command = AppCommandToString(command_id);
NotifyWindowExecuteWindowsCommand(command);
return false;
}
bool NativeWindowViews::PreHandleMSG(
UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) {
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)
return taskbar_host_.HandleThumbarButtonEvent(LOWORD(w_param));
return false;
case WM_SIZE:
// Handle window state change.
HandleSizeEvent(w_param, l_param);
return false;
default:
return false;
}
}
void NativeWindowViews::HandleSizeEvent(WPARAM w_param, LPARAM l_param) {
// Here we handle the WM_SIZE event in order to figure out what is the current
// window state and notify the user accordingly.
switch (w_param) {
case SIZE_MAXIMIZED:
last_window_state_ = ui::SHOW_STATE_MAXIMIZED;
NotifyWindowMaximize();
break;
case SIZE_MINIMIZED:
last_window_state_ = ui::SHOW_STATE_MINIMIZED;
NotifyWindowMinimize();
break;
case SIZE_RESTORED:
if (last_window_state_ == ui::SHOW_STATE_NORMAL) {
// Window was resized so we save it's new size.
last_normal_size_ = GetSize();
} else {
switch (last_window_state_) {
case ui::SHOW_STATE_MAXIMIZED:
last_window_state_ = ui::SHOW_STATE_NORMAL;
// When the window is restored we resize it to the previous known
// normal size.
NativeWindow::SetSize(last_normal_size_);
NotifyWindowUnmaximize();
break;
case ui::SHOW_STATE_MINIMIZED:
if (IsFullscreen()) {
last_window_state_ = ui::SHOW_STATE_FULLSCREEN;
NotifyWindowEnterFullScreen();
} else {
last_window_state_ = ui::SHOW_STATE_NORMAL;
// When the window is restored we resize it to the previous known
// normal size.
NativeWindow::SetSize(last_normal_size_);
NotifyWindowRestore();
}
break;
}
}
break;
}
}
} // namespace atom

View file

@ -8,7 +8,6 @@
#include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/v8_value_converter.h" #include "atom/common/native_mate_converters/v8_value_converter.h"
#include "native_mate/function_template.h"
namespace atom { namespace atom {
@ -16,34 +15,14 @@ namespace internal {
namespace { namespace {
struct CallbackHolder {
ResponseCallback callback;
};
// Cached JavaScript version of |HandlerCallback|.
v8::Persistent<v8::FunctionTemplate> g_handler_callback_;
// The callback which is passed to |handler|. // The callback which is passed to |handler|.
void HandlerCallback(v8::Isolate* isolate, void HandlerCallback(const ResponseCallback& callback, mate::Arguments* args) {
v8::Local<v8::External> external,
v8::Local<v8::Object> state,
mate::Arguments* args) {
// Check if the callback has already been called.
v8::Local<v8::String> called_symbol = mate::StringToSymbol(isolate, "called");
if (state->Has(called_symbol))
return; // no nothing
else
state->Set(called_symbol, v8::Boolean::New(isolate, true));
// If there is no argument passed then we failed. // If there is no argument passed then we failed.
scoped_ptr<CallbackHolder> holder(
static_cast<CallbackHolder*>(external->Value()));
CHECK(holder);
v8::Local<v8::Value> value; v8::Local<v8::Value> value;
if (!args->GetNext(&value)) { if (!args->GetNext(&value)) {
content::BrowserThread::PostTask( content::BrowserThread::PostTask(
content::BrowserThread::IO, FROM_HERE, content::BrowserThread::IO, FROM_HERE,
base::Bind(holder->callback, false, nullptr)); base::Bind(callback, false, nullptr));
return; return;
} }
@ -53,42 +32,7 @@ void HandlerCallback(v8::Isolate* isolate,
scoped_ptr<base::Value> options(converter.FromV8Value(value, context)); scoped_ptr<base::Value> options(converter.FromV8Value(value, context));
content::BrowserThread::PostTask( content::BrowserThread::PostTask(
content::BrowserThread::IO, FROM_HERE, content::BrowserThread::IO, FROM_HERE,
base::Bind(holder->callback, true, base::Passed(&options))); base::Bind(callback, true, base::Passed(&options)));
}
// func.bind(func, arg1, arg2).
// NB(zcbenz): Using C++11 version crashes VS.
v8::Local<v8::Value> BindFunctionWith(v8::Isolate* isolate,
v8::Local<v8::Context> context,
v8::Local<v8::Function> func,
v8::Local<v8::Value> arg1,
v8::Local<v8::Value> arg2) {
v8::MaybeLocal<v8::Value> bind = func->Get(mate::StringToV8(isolate, "bind"));
CHECK(!bind.IsEmpty());
v8::Local<v8::Function> bind_func =
v8::Local<v8::Function>::Cast(bind.ToLocalChecked());
v8::Local<v8::Value> converted[] = { func, arg1, arg2 };
return bind_func->Call(
context, func, arraysize(converted), converted).ToLocalChecked();
}
// Generate the callback that will be passed to |handler|.
v8::MaybeLocal<v8::Value> GenerateCallback(v8::Isolate* isolate,
v8::Local<v8::Context> context,
const ResponseCallback& callback) {
// The FunctionTemplate is cached.
if (g_handler_callback_.IsEmpty())
g_handler_callback_.Reset(
isolate,
mate::CreateFunctionTemplate(isolate, base::Bind(&HandlerCallback)));
v8::Local<v8::FunctionTemplate> handler_callback =
v8::Local<v8::FunctionTemplate>::New(isolate, g_handler_callback_);
CallbackHolder* holder = new CallbackHolder;
holder->callback = callback;
return BindFunctionWith(isolate, context, handler_callback->GetFunction(),
v8::External::New(isolate, holder),
v8::Object::New(isolate));
} }
} // namespace } // namespace
@ -102,16 +46,9 @@ void AskForOptions(v8::Isolate* isolate,
v8::HandleScope handle_scope(isolate); v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = isolate->GetCurrentContext(); v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::Context::Scope context_scope(context); v8::Context::Scope context_scope(context);
// We don't convert the callback to C++ directly because creating handler.Run(request,
// FunctionTemplate will cause memory leak since V8 never releases it. So we mate::ConvertToV8(isolate,
// have to create the function object in JavaScript to work around it. base::Bind(&HandlerCallback, callback)));
v8::MaybeLocal<v8::Value> wrapped_callback = GenerateCallback(
isolate, context, callback);
if (wrapped_callback.IsEmpty()) {
callback.Run(false, nullptr);
return;
}
handler.Run(request, wrapped_callback.ToLocalChecked());
} }
bool IsErrorOptions(base::Value* value, int* error) { bool IsErrorOptions(base::Value* value, int* error) {

View file

@ -35,17 +35,14 @@ NodeDebugger::NodeDebugger(v8::Isolate* isolate)
weak_factory_(this) { weak_factory_(this) {
bool use_debug_agent = false; bool use_debug_agent = false;
int port = 5858; int port = 5858;
bool wait_for_connection = false;
std::string port_str; std::string port_str;
base::CommandLine* cmd = base::CommandLine::ForCurrentProcess(); base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
if (cmd->HasSwitch("debug")) { if (cmd->HasSwitch("debug")) {
use_debug_agent = true; use_debug_agent = true;
port_str = cmd->GetSwitchValueASCII("debug"); port_str = cmd->GetSwitchValueASCII("debug");
} } else if (cmd->HasSwitch("debug-brk")) {
if (cmd->HasSwitch("debug-brk")) {
use_debug_agent = true; use_debug_agent = true;
wait_for_connection = true;
port_str = cmd->GetSwitchValueASCII("debug-brk"); port_str = cmd->GetSwitchValueASCII("debug-brk");
} }
@ -56,9 +53,6 @@ NodeDebugger::NodeDebugger(v8::Isolate* isolate)
isolate_->SetData(kIsolateSlot, this); isolate_->SetData(kIsolateSlot, this);
v8::Debug::SetMessageHandler(DebugMessageHandler); v8::Debug::SetMessageHandler(DebugMessageHandler);
if (wait_for_connection)
v8::Debug::DebugBreak(isolate_);
uv_async_init(uv_default_loop(), &weak_up_ui_handle_, ProcessMessageInUI); uv_async_init(uv_default_loop(), &weak_up_ui_handle_, ProcessMessageInUI);
// Start a new IO thread. // Start a new IO thread.

View file

@ -17,7 +17,11 @@
<key>CFBundleIconFile</key> <key>CFBundleIconFile</key>
<string>atom.icns</string> <string>atom.icns</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>0.33.6</string> <string>0.34.3</string>
<key>CFBundleShortVersionString</key>
<string>0.34.3</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.developer-tools</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
<string>10.8.0</string> <string>10.8.0</string>
<key>NSMainNibFile</key> <key>NSMainNibFile</key>

View file

@ -56,8 +56,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,33,6,0 FILEVERSION 0,34,3,0
PRODUCTVERSION 0,33,6,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.33.6" 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.33.6" VALUE "ProductVersion", "0.34.3"
VALUE "SquirrelAwareVersion", "1" VALUE "SquirrelAwareVersion", "1"
END END
END END

View file

@ -79,8 +79,25 @@ class FileDialog {
if (!title.empty()) if (!title.empty())
GetPtr()->SetTitle(base::UTF8ToUTF16(title).c_str()); GetPtr()->SetTitle(base::UTF8ToUTF16(title).c_str());
if (!filterspec.empty()) // By default, *.* will be added to the file name if file type is "*.*". In
GetPtr()->SetDefaultExtension(filterspec.front().pszSpec); // Electron, we disable it to make a better experience.
//
// From MSDN: https://msdn.microsoft.com/en-us/library/windows/desktop/
// bb775970(v=vs.85).aspx
//
// If SetDefaultExtension is not called, the dialog will not update
// automatically when user choose a new file type in the file dialog.
//
// We set file extension to the first none-wildcard extension to make
// sure the dialog will update file extension automatically.
for (size_t i = 0; i < filterspec.size(); ++i) {
if (std::wstring(filterspec[i].pszSpec) != L"*.*") {
// SetFileTypeIndex is regarded as one-based index.
GetPtr()->SetFileTypeIndex(i+1);
GetPtr()->SetDefaultExtension(filterspec[i].pszSpec);
break;
}
}
SetDefaultFolder(default_path); SetDefaultFolder(default_path);
} }
@ -255,7 +272,8 @@ bool ShowSaveDialog(atom::NativeWindow* parent_window,
bool matched = false; bool matched = false;
for (size_t i = 0; i < filter.second.size(); ++i) { for (size_t i = 0; i < filter.second.size(); ++i) {
if (base::EndsWith(file_name, filter.second[i], false)) { if (filter.second[i] == "*" ||
base::EndsWith(file_name, filter.second[i], false)) {
matched = true; matched = true;
break;; break;;
} }

View file

@ -55,8 +55,24 @@ void TrayIcon::NotifyRightClicked(const gfx::Rect& bounds, int modifiers) {
OnRightClicked(bounds, modifiers)); OnRightClicked(bounds, modifiers));
} }
void TrayIcon::NotfiyDropFiles(const std::vector<std::string>& files) { void TrayIcon::NotifyDrop() {
FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnDrop());
}
void TrayIcon::NotifyDropFiles(const std::vector<std::string>& files) {
FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnDropFiles(files)); FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnDropFiles(files));
} }
void TrayIcon::NotifyDragEntered() {
FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnDragEntered());
}
void TrayIcon::NotifyDragExited() {
FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnDragExited());
}
void TrayIcon::NotifyDragEnded() {
FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnDragEnded());
}
} // namespace atom } // namespace atom

View file

@ -61,7 +61,11 @@ class TrayIcon {
void NotifyBalloonClosed(); void NotifyBalloonClosed();
void NotifyRightClicked(const gfx::Rect& bounds = gfx::Rect(), void NotifyRightClicked(const gfx::Rect& bounds = gfx::Rect(),
int modifiers = 0); int modifiers = 0);
void NotfiyDropFiles(const std::vector<std::string>& files); void NotifyDrop();
void NotifyDropFiles(const std::vector<std::string>& files);
void NotifyDragEntered();
void NotifyDragExited();
void NotifyDragEnded();
protected: protected:
TrayIcon(); TrayIcon();

View file

@ -254,9 +254,23 @@ const CGFloat kVerticalTitleMargin = 2;
} }
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender { - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender {
trayIcon_->NotifyDragEntered();
return NSDragOperationCopy; return NSDragOperationCopy;
} }
- (void)draggingExited:(id <NSDraggingInfo>)sender {
trayIcon_->NotifyDragExited();
}
- (void)draggingEnded:(id <NSDraggingInfo>)sender {
trayIcon_->NotifyDragEnded();
}
- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender {
trayIcon_->NotifyDrop();
return YES;
}
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender { - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender {
NSPasteboard* pboard = [sender draggingPasteboard]; NSPasteboard* pboard = [sender draggingPasteboard];
@ -265,7 +279,7 @@ const CGFloat kVerticalTitleMargin = 2;
NSArray* files = [pboard propertyListForType:NSFilenamesPboardType]; NSArray* files = [pboard propertyListForType:NSFilenamesPboardType];
for (NSString* file in files) for (NSString* file in files)
dropFiles.push_back(base::SysNSStringToUTF8(file)); dropFiles.push_back(base::SysNSStringToUTF8(file));
trayIcon_->NotfiyDropFiles(dropFiles); trayIcon_->NotifyDropFiles(dropFiles);
return YES; return YES;
} }
return NO; return NO;

View file

@ -22,7 +22,11 @@ class TrayIconObserver {
virtual void OnBalloonClicked() {} virtual void OnBalloonClicked() {}
virtual void OnBalloonClosed() {} virtual void OnBalloonClosed() {}
virtual void OnRightClicked(const gfx::Rect& bounds, int modifiers) {} virtual void OnRightClicked(const gfx::Rect& bounds, int modifiers) {}
virtual void OnDrop() {}
virtual void OnDropFiles(const std::vector<std::string>& files) {} virtual void OnDropFiles(const std::vector<std::string>& files) {}
virtual void OnDragEntered() {}
virtual void OnDragExited() {}
virtual void OnDragEnded() {}
protected: protected:
virtual ~TrayIconObserver() {} virtual ~TrayIconObserver() {}

View file

@ -104,11 +104,11 @@ gfx::Size FramelessView::GetPreferredSize() const {
} }
gfx::Size FramelessView::GetMinimumSize() const { gfx::Size FramelessView::GetMinimumSize() const {
return window_->GetMinimumSize(); return window_->GetContentSizeConstraints().GetMinimumSize();
} }
gfx::Size FramelessView::GetMaximumSize() const { gfx::Size FramelessView::GetMaximumSize() const {
return window_->GetMaximumSize(); return window_->GetContentSizeConstraints().GetMaximumSize();
} }
const char* FramelessView::GetClassName() const { const char* FramelessView::GetClassName() const {

Some files were not shown because too many files have changed in this diff Show more