mirror of
https://github.com/electron/electron.git
synced 2026-02-19 03:14:51 -05:00
Compare commits
189 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a840799b46 | ||
|
|
c8ef79817a | ||
|
|
29abba824d | ||
|
|
6ccec45c61 | ||
|
|
1dabd20d99 | ||
|
|
fedb08899c | ||
|
|
b8bfe8a9ad | ||
|
|
a230daa998 | ||
|
|
ba41634ad6 | ||
|
|
e9536508a5 | ||
|
|
965f2b1b6b | ||
|
|
e25417ab31 | ||
|
|
48c227c263 | ||
|
|
cbd6541e9a | ||
|
|
2a9f5a5fb8 | ||
|
|
78afa29ade | ||
|
|
73bb05e530 | ||
|
|
8cc23aca8d | ||
|
|
f96c6e4bd7 | ||
|
|
3afb4e017c | ||
|
|
54ee12308d | ||
|
|
fd09f13c9b | ||
|
|
86dd8e2dfa | ||
|
|
1b70ca2098 | ||
|
|
e8d1c69ea8 | ||
|
|
1883da463f | ||
|
|
e9879a3e4b | ||
|
|
dec05988f4 | ||
|
|
4087062798 | ||
|
|
31135321c0 | ||
|
|
226cbda7a6 | ||
|
|
66ef1a067d | ||
|
|
8a7efcdcd2 | ||
|
|
adb8fb59bd | ||
|
|
0ca9e8ee82 | ||
|
|
e7647ba183 | ||
|
|
be6599807d | ||
|
|
a8ca0329b4 | ||
|
|
6d9a88f415 | ||
|
|
0018d4b705 | ||
|
|
72e8b2882f | ||
|
|
89539ca15e | ||
|
|
175d052a28 | ||
|
|
d1a93a5135 | ||
|
|
f96485f950 | ||
|
|
79dfb2d2f3 | ||
|
|
de7ff0f944 | ||
|
|
80c77ef3a8 | ||
|
|
cad9580796 | ||
|
|
253789353f | ||
|
|
73262be2c2 | ||
|
|
0ad4c3ca93 | ||
|
|
b26e3a9629 | ||
|
|
c55f6d82d8 | ||
|
|
4b90c02420 | ||
|
|
d4fb1c1f8c | ||
|
|
445fe158cc | ||
|
|
a696f06a23 | ||
|
|
c019f13e8c | ||
|
|
b4f00f3b40 | ||
|
|
f60d8066f8 | ||
|
|
b8d5aa586e | ||
|
|
eeff20f1bc | ||
|
|
9035ffff55 | ||
|
|
ca522f06d3 | ||
|
|
7f534652a6 | ||
|
|
b93564894c | ||
|
|
54b8a62920 | ||
|
|
bcfba96d29 | ||
|
|
8e21530550 | ||
|
|
a4f59bc04e | ||
|
|
a378a719e9 | ||
|
|
441ee0d978 | ||
|
|
8d7a59161a | ||
|
|
d175a99811 | ||
|
|
724b29d6d4 | ||
|
|
336908eba0 | ||
|
|
0f5d929c09 | ||
|
|
c4b0170a0a | ||
|
|
936860edd5 | ||
|
|
1cadc9221a | ||
|
|
4890eebd3a | ||
|
|
3a65942b97 | ||
|
|
e06c558a86 | ||
|
|
0a0a408bf8 | ||
|
|
c9702b56e2 | ||
|
|
279eb23b38 | ||
|
|
8eb650ce03 | ||
|
|
7f9ac88c31 | ||
|
|
424a00cf29 | ||
|
|
3c078b4dab | ||
|
|
8cc49ffa80 | ||
|
|
58a09f6495 | ||
|
|
c2885f77c9 | ||
|
|
5d5a3138bc | ||
|
|
09f9d0729c | ||
|
|
3d989b6736 | ||
|
|
daa00e6539 | ||
|
|
382dbb500c | ||
|
|
92d6fd641f | ||
|
|
f219e7f0dd | ||
|
|
8a9e1824c3 | ||
|
|
b139d97f3d | ||
|
|
d29efb7f81 | ||
|
|
53cedc6e5d | ||
|
|
4f4aabef7a | ||
|
|
a888e4b960 | ||
|
|
15c31ad1ba | ||
|
|
196be5291d | ||
|
|
fe9f94555b | ||
|
|
47e0a61dd8 | ||
|
|
5ba324ca9a | ||
|
|
0721b34847 | ||
|
|
dc257f1f86 | ||
|
|
dfe111b95a | ||
|
|
a76ae8cd35 | ||
|
|
866e20b4be | ||
|
|
d25645ba67 | ||
|
|
ad1efa67bc | ||
|
|
cbb14f5ca2 | ||
|
|
a8cd101ff5 | ||
|
|
009e0790fe | ||
|
|
d31ebb71db | ||
|
|
2125a0be82 | ||
|
|
6dc01945af | ||
|
|
28b9df24a6 | ||
|
|
94b4ceb8ce | ||
|
|
e3eaf909a5 | ||
|
|
33580f66df | ||
|
|
139316b975 | ||
|
|
8fe8cd46b9 | ||
|
|
e3118359ad | ||
|
|
681de1b048 | ||
|
|
4880096f3d | ||
|
|
9c038a2402 | ||
|
|
c4d9dc91a6 | ||
|
|
16428baea2 | ||
|
|
4cd3119125 | ||
|
|
191b1aa719 | ||
|
|
035679057e | ||
|
|
fb4ec66b37 | ||
|
|
89f565906b | ||
|
|
6a5f732bba | ||
|
|
fba1772000 | ||
|
|
e62986b97d | ||
|
|
2e38bafdb1 | ||
|
|
f3e49b0696 | ||
|
|
70aad83b07 | ||
|
|
10c862f0bb | ||
|
|
d993c92cea | ||
|
|
546e4e431d | ||
|
|
4a7e98e398 | ||
|
|
ab4558ae32 | ||
|
|
978f73756b | ||
|
|
5086873f78 | ||
|
|
b2217474c1 | ||
|
|
9342d59a7c | ||
|
|
ad827eee90 | ||
|
|
a8034364ff | ||
|
|
c2c5111d75 | ||
|
|
4b3bd9c3cc | ||
|
|
476f545a67 | ||
|
|
16a1edb422 | ||
|
|
474445fb7d | ||
|
|
5db31517cb | ||
|
|
740e7fbf1a | ||
|
|
be5789b483 | ||
|
|
1c415b0666 | ||
|
|
8dd7f81175 | ||
|
|
87019a1a70 | ||
|
|
10c52bd6a6 | ||
|
|
c23c667c2d | ||
|
|
ec4275ca13 | ||
|
|
143bde007a | ||
|
|
a6ede12cd7 | ||
|
|
7a89a08534 | ||
|
|
5ad203ad99 | ||
|
|
82dcdc6314 | ||
|
|
371e38198f | ||
|
|
472a95e433 | ||
|
|
b84226244d | ||
|
|
e4290393af | ||
|
|
cab00a1450 | ||
|
|
ce50b38a75 | ||
|
|
e8d59c4326 | ||
|
|
b9d64784bb | ||
|
|
ad3eac2e38 | ||
|
|
58c56ce7ae | ||
|
|
66983c7f67 |
@@ -1,4 +1,8 @@
|
||||
language: objective-c
|
||||
language: cpp
|
||||
compiler: clang
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
notifications:
|
||||
email:
|
||||
|
||||
28
appveyor.yml
Normal file
28
appveyor.yml
Normal file
@@ -0,0 +1,28 @@
|
||||
# appveyor file
|
||||
# http://www.appveyor.com/docs/appveyor-yml
|
||||
version: "{build}"
|
||||
|
||||
init:
|
||||
- git config --global core.autocrlf input
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- nodejs_version: 0.10
|
||||
|
||||
platform:
|
||||
- x86
|
||||
|
||||
install:
|
||||
- ps: Install-Product node $env:nodejs_version
|
||||
- cmd: SET PATH=C:\Program Files (x86)\MSBuild\12.0\bin\;%PATH%
|
||||
- cmd: SET PATH=C:\python27;%PATH%
|
||||
- cmd: python script/bootstrap.py
|
||||
- cmd: python script/build.py -c Debug
|
||||
|
||||
test_script:
|
||||
- node --version
|
||||
- npm --version
|
||||
- cmd: python script/cpplint.py
|
||||
- cmd: python script/coffeelint.py
|
||||
|
||||
build: off
|
||||
62
atom.gyp
62
atom.gyp
@@ -18,7 +18,9 @@
|
||||
'atom/browser/api/lib/atom-delegate.coffee',
|
||||
'atom/browser/api/lib/auto-updater.coffee',
|
||||
'atom/browser/api/lib/browser-window.coffee',
|
||||
'atom/browser/api/lib/content-tracing.coffee',
|
||||
'atom/browser/api/lib/dialog.coffee',
|
||||
'atom/browser/api/lib/global-shortcut.coffee',
|
||||
'atom/browser/api/lib/ipc.coffee',
|
||||
'atom/browser/api/lib/menu.coffee',
|
||||
'atom/browser/api/lib/menu-item.coffee',
|
||||
@@ -51,7 +53,10 @@
|
||||
'atom/browser/api/atom_api_app.h',
|
||||
'atom/browser/api/atom_api_auto_updater.cc',
|
||||
'atom/browser/api/atom_api_auto_updater.h',
|
||||
'atom/browser/api/atom_api_content_tracing.cc',
|
||||
'atom/browser/api/atom_api_dialog.cc',
|
||||
'atom/browser/api/atom_api_global_shortcut.cc',
|
||||
'atom/browser/api/atom_api_global_shortcut.h',
|
||||
'atom/browser/api/atom_api_menu.cc',
|
||||
'atom/browser/api/atom_api_menu.h',
|
||||
'atom/browser/api/atom_api_menu_views.cc',
|
||||
@@ -78,6 +83,8 @@
|
||||
'atom/browser/auto_updater_linux.cc',
|
||||
'atom/browser/auto_updater_mac.mm',
|
||||
'atom/browser/auto_updater_win.cc',
|
||||
'atom/browser/atom_access_token_store.cc',
|
||||
'atom/browser/atom_access_token_store.h',
|
||||
'atom/browser/atom_browser_client.cc',
|
||||
'atom/browser/atom_browser_client.h',
|
||||
'atom/browser/atom_browser_context.cc',
|
||||
@@ -87,12 +94,16 @@
|
||||
'atom/browser/atom_browser_main_parts_mac.mm',
|
||||
'atom/browser/atom_javascript_dialog_manager.cc',
|
||||
'atom/browser/atom_javascript_dialog_manager.h',
|
||||
'atom/browser/atom_resource_dispatcher_host_delegate.cc',
|
||||
'atom/browser/atom_resource_dispatcher_host_delegate.h',
|
||||
'atom/browser/browser.cc',
|
||||
'atom/browser/browser.h',
|
||||
'atom/browser/browser_linux.cc',
|
||||
'atom/browser/browser_mac.mm',
|
||||
'atom/browser/browser_win.cc',
|
||||
'atom/browser/browser_observer.h',
|
||||
'atom/browser/javascript_environment.cc',
|
||||
'atom/browser/javascript_environment.h',
|
||||
'atom/browser/mac/atom_application.h',
|
||||
'atom/browser/mac/atom_application.mm',
|
||||
'atom/browser/mac/atom_application_delegate.h',
|
||||
@@ -106,8 +117,6 @@
|
||||
'atom/browser/native_window_observer.h',
|
||||
'atom/browser/net/adapter_request_job.cc',
|
||||
'atom/browser/net/adapter_request_job.h',
|
||||
'atom/browser/net/atom_url_request_context_getter.cc',
|
||||
'atom/browser/net/atom_url_request_context_getter.h',
|
||||
'atom/browser/net/atom_url_request_job_factory.cc',
|
||||
'atom/browser/net/atom_url_request_job_factory.h',
|
||||
'atom/browser/net/url_request_string_job.cc',
|
||||
@@ -145,6 +154,8 @@
|
||||
'atom/browser/ui/views/menu_delegate.h',
|
||||
'atom/browser/ui/views/menu_layout.cc',
|
||||
'atom/browser/ui/views/menu_layout.h',
|
||||
'atom/browser/ui/views/submenu_button.cc',
|
||||
'atom/browser/ui/views/submenu_button.h',
|
||||
'atom/browser/ui/views/win_frame_view.cc',
|
||||
'atom/browser/ui/views/win_frame_view.h',
|
||||
'atom/browser/ui/win/notify_icon_host.cc',
|
||||
@@ -168,8 +179,6 @@
|
||||
'atom/common/api/atom_bindings.h',
|
||||
'atom/common/api/object_life_monitor.cc',
|
||||
'atom/common/api/object_life_monitor.h',
|
||||
'atom/common/browser_v8_locker.cc',
|
||||
'atom/common/browser_v8_locker.h',
|
||||
'atom/common/crash_reporter/crash_reporter.cc',
|
||||
'atom/common/crash_reporter/crash_reporter.h',
|
||||
'atom/common/crash_reporter/crash_reporter_linux.cc',
|
||||
@@ -187,8 +196,9 @@
|
||||
'atom/common/draggable_region.cc',
|
||||
'atom/common/draggable_region.h',
|
||||
'atom/common/linux/application_info.cc',
|
||||
'atom/common/native_mate_converters/accelerator_converter.cc',
|
||||
'atom/common/native_mate_converters/accelerator_converter.h',
|
||||
'atom/common/native_mate_converters/file_path_converter.h',
|
||||
'atom/common/native_mate_converters/function_converter.h',
|
||||
'atom/common/native_mate_converters/gurl_converter.h',
|
||||
'atom/common/native_mate_converters/image_converter.cc',
|
||||
'atom/common/native_mate_converters/image_converter.h',
|
||||
@@ -221,6 +231,14 @@
|
||||
'atom/renderer/atom_render_view_observer.h',
|
||||
'atom/renderer/atom_renderer_client.cc',
|
||||
'atom/renderer/atom_renderer_client.h',
|
||||
'chromium_src/chrome/browser/extensions/global_shortcut_listener.cc',
|
||||
'chromium_src/chrome/browser/extensions/global_shortcut_listener.h',
|
||||
'chromium_src/chrome/browser/extensions/global_shortcut_listener_mac.mm',
|
||||
'chromium_src/chrome/browser/extensions/global_shortcut_listener_mac.h',
|
||||
'chromium_src/chrome/browser/extensions/global_shortcut_listener_x11.cc',
|
||||
'chromium_src/chrome/browser/extensions/global_shortcut_listener_x11.h',
|
||||
'chromium_src/chrome/browser/extensions/global_shortcut_listener_win.cc',
|
||||
'chromium_src/chrome/browser/extensions/global_shortcut_listener_win.h',
|
||||
'chromium_src/chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.cc',
|
||||
'chromium_src/chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.h',
|
||||
'chromium_src/chrome/browser/ui/libgtk2ui/gtk2_status_icon.cc',
|
||||
@@ -377,6 +395,9 @@
|
||||
'<(libchromiumcontent_resources_dir)/ui_resources_200_percent.pak',
|
||||
'<(libchromiumcontent_resources_dir)/webkit_resources_200_percent.pak',
|
||||
'external_binaries/d3dcompiler_43.dll',
|
||||
'external_binaries/msvcp120.dll',
|
||||
'external_binaries/msvcr120.dll',
|
||||
'external_binaries/vccorlib120.dll',
|
||||
'external_binaries/xinput1_3.dll',
|
||||
],
|
||||
},
|
||||
@@ -617,7 +638,10 @@
|
||||
# Gyp action requires a output file, add a fake one here.
|
||||
'<(PRODUCT_DIR)/dummy_file',
|
||||
],
|
||||
'action': [ 'strip', '<@(_inputs)' ],
|
||||
'action': [
|
||||
'tools/posix/strip.sh',
|
||||
'<@(_inputs)',
|
||||
],
|
||||
},
|
||||
],
|
||||
}], # OS=="linux"
|
||||
@@ -780,5 +804,31 @@
|
||||
}, # target generate_node_lib
|
||||
],
|
||||
}], # OS==win
|
||||
# Using Visual Studio Express.
|
||||
['msvs_express==1', {
|
||||
'target_defaults': {
|
||||
'defines!': [
|
||||
'_SECURE_ATL',
|
||||
],
|
||||
'msvs_settings': {
|
||||
'VCLibrarianTool': {
|
||||
'AdditionalLibraryDirectories': [
|
||||
'<(atom_source_root)/external_binaries/atl/lib',
|
||||
],
|
||||
},
|
||||
'VCLinkerTool': {
|
||||
'AdditionalLibraryDirectories': [
|
||||
'<(atom_source_root)/external_binaries/atl/lib',
|
||||
],
|
||||
'AdditionalDependencies': [
|
||||
'atls.lib',
|
||||
],
|
||||
},
|
||||
},
|
||||
'msvs_system_include_dirs': [
|
||||
'<(atom_source_root)/external_binaries/atl/include',
|
||||
],
|
||||
},
|
||||
}], # msvs_express==1
|
||||
],
|
||||
}
|
||||
|
||||
@@ -74,6 +74,13 @@ void AtomMainDelegate::PreSandboxStartup() {
|
||||
// Add a flag to mark the start of switches added by atom-shell.
|
||||
command_line->AppendSwitch("atom-shell-switches-start");
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Disable the LegacyRenderWidgetHostHWND, it made frameless windows unable
|
||||
// to move and resize. We may consider enabling it again after upgraded to
|
||||
// Chrome 38, which should have fixed the problem.
|
||||
command_line->AppendSwitch(switches::kDisableLegacyIntermediateWindow);
|
||||
#endif
|
||||
|
||||
// Disable renderer sandbox for most of node's functions.
|
||||
command_line->AppendSwitch(switches::kNoSandbox);
|
||||
|
||||
|
||||
@@ -5,15 +5,23 @@
|
||||
#include "atom/browser/api/atom_api_app.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/values.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/environment.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/path_service.h"
|
||||
#include "atom/browser/browser.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/object_template_builder.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
#include "base/nix/xdg_util.h"
|
||||
#endif
|
||||
|
||||
using atom::Browser;
|
||||
|
||||
namespace atom {
|
||||
@@ -60,6 +68,21 @@ void App::OnFinishLaunching() {
|
||||
Emit("ready");
|
||||
}
|
||||
|
||||
base::FilePath App::GetDataPath() {
|
||||
base::FilePath path;
|
||||
#if defined(OS_LINUX)
|
||||
scoped_ptr<base::Environment> env(base::Environment::Create());
|
||||
path = base::nix::GetXDGDirectory(env.get(),
|
||||
base::nix::kXdgConfigHomeEnvVar,
|
||||
base::nix::kDotConfigDir);
|
||||
#else
|
||||
CHECK(PathService::Get(base::DIR_APP_DATA, &path));
|
||||
#endif
|
||||
|
||||
return path.Append(base::FilePath::FromUTF8Unsafe(
|
||||
Browser::Get()->GetName()));
|
||||
}
|
||||
|
||||
mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) {
|
||||
Browser* browser = Browser::Get();
|
||||
@@ -75,7 +98,8 @@ mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
|
||||
.SetMethod("getName", base::Bind(&Browser::GetName,
|
||||
base::Unretained(browser)))
|
||||
.SetMethod("setName", base::Bind(&Browser::SetName,
|
||||
base::Unretained(browser)));
|
||||
base::Unretained(browser)))
|
||||
.SetMethod("getDataPath", &App::GetDataPath);
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "base/compiler_specific.h"
|
||||
#include "atom/browser/api/event_emitter.h"
|
||||
#include "atom/browser/browser_observer.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "native_mate/handle.h"
|
||||
|
||||
namespace atom {
|
||||
@@ -34,6 +35,7 @@ class App : public mate::EventEmitter,
|
||||
virtual void OnActivateWithNoOpenWindows() OVERRIDE;
|
||||
virtual void OnWillFinishLaunching() OVERRIDE;
|
||||
virtual void OnFinishLaunching() OVERRIDE;
|
||||
virtual base::FilePath GetDataPath();
|
||||
|
||||
// mate::Wrappable implementations:
|
||||
virtual mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
||||
|
||||
77
atom/browser/api/atom_api_content_tracing.cc
Normal file
77
atom/browser/api/atom_api_content_tracing.cc
Normal file
@@ -0,0 +1,77 @@
|
||||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "base/bind.h"
|
||||
#include "content/public/browser/tracing_controller.h"
|
||||
#include "native_mate/callback.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
using content::TracingController;
|
||||
|
||||
namespace mate {
|
||||
|
||||
template<typename T>
|
||||
struct Converter<std::set<T> > {
|
||||
static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const std::set<T>& val) {
|
||||
v8::Handle<v8::Array> result = v8::Array::New(
|
||||
isolate, static_cast<int>(val.size()));
|
||||
typename std::set<T>::const_iterator it;
|
||||
int i;
|
||||
for (i = 0, it = val.begin(); it != val.end(); ++it, ++i)
|
||||
result->Set(i, Converter<T>::ToV8(isolate, *it));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Converter<TracingController::Options> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Handle<v8::Value> val,
|
||||
TracingController::Options* out) {
|
||||
if (!val->IsNumber())
|
||||
return false;
|
||||
*out = static_cast<TracingController::Options>(val->IntegerValue());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
namespace {
|
||||
|
||||
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
|
||||
v8::Handle<v8::Context> context, void* priv) {
|
||||
TracingController* controller = TracingController::GetInstance();
|
||||
mate::Dictionary dict(context->GetIsolate(), exports);
|
||||
dict.SetMethod("getCategories", base::Bind(
|
||||
&TracingController::GetCategories, base::Unretained(controller)));
|
||||
dict.SetMethod("startRecording", base::Bind(
|
||||
&TracingController::EnableRecording, base::Unretained(controller)));
|
||||
dict.SetMethod("stopRecording", base::Bind(
|
||||
&TracingController::DisableRecording, base::Unretained(controller)));
|
||||
dict.SetMethod("startMonitoring", base::Bind(
|
||||
&TracingController::EnableMonitoring, base::Unretained(controller)));
|
||||
dict.SetMethod("stopMonitoring", base::Bind(
|
||||
&TracingController::DisableMonitoring, base::Unretained(controller)));
|
||||
dict.SetMethod("captureMonitoringSnapshot", base::Bind(
|
||||
&TracingController::CaptureMonitoringSnapshot,
|
||||
base::Unretained(controller)));
|
||||
dict.SetMethod("getTraceBufferPercentFull", base::Bind(
|
||||
&TracingController::GetTraceBufferPercentFull,
|
||||
base::Unretained(controller)));
|
||||
dict.SetMethod("setWatchEvent", base::Bind(
|
||||
&TracingController::SetWatchEvent, base::Unretained(controller)));
|
||||
dict.SetMethod("cancelWatchEvent", base::Bind(
|
||||
&TracingController::CancelWatchEvent, base::Unretained(controller)));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_content_tracing, Initialize)
|
||||
@@ -3,19 +3,39 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "atom/browser/api/atom_api_window.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/ui/file_dialog.h"
|
||||
#include "atom/browser/ui/message_box.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "atom/common/native_mate_converters/function_converter.h"
|
||||
#include "native_mate/callback.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
template<>
|
||||
struct Converter<file_dialog::Filter> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Handle<v8::Value> val,
|
||||
file_dialog::Filter* out) {
|
||||
mate::Dictionary dict(isolate);
|
||||
if (!ConvertFromV8(isolate, val, &dict))
|
||||
return false;
|
||||
if (!dict.Get("name", &(out->first)))
|
||||
return false;
|
||||
if (!dict.Get("extensions", &(out->second)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
namespace {
|
||||
|
||||
void ShowMessageBox(int type,
|
||||
@@ -41,6 +61,7 @@ void ShowMessageBox(int type,
|
||||
|
||||
void ShowOpenDialog(const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
const file_dialog::Filters& filters,
|
||||
int properties,
|
||||
atom::NativeWindow* window,
|
||||
mate::Arguments* args) {
|
||||
@@ -49,18 +70,19 @@ void ShowOpenDialog(const std::string& title,
|
||||
if (mate::Converter<file_dialog::OpenDialogCallback>::FromV8(args->isolate(),
|
||||
peek,
|
||||
&callback)) {
|
||||
file_dialog::ShowOpenDialog(window, title, default_path, properties,
|
||||
callback);
|
||||
file_dialog::ShowOpenDialog(window, title, default_path, filters,
|
||||
properties, callback);
|
||||
} else {
|
||||
std::vector<base::FilePath> paths;
|
||||
if (file_dialog::ShowOpenDialog(window, title, default_path, properties,
|
||||
&paths))
|
||||
if (file_dialog::ShowOpenDialog(window, title, default_path, filters,
|
||||
properties, &paths))
|
||||
args->Return(paths);
|
||||
}
|
||||
}
|
||||
|
||||
void ShowSaveDialog(const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
const file_dialog::Filters& filters,
|
||||
atom::NativeWindow* window,
|
||||
mate::Arguments* args) {
|
||||
v8::Handle<v8::Value> peek = args->PeekNext();
|
||||
@@ -68,10 +90,11 @@ void ShowSaveDialog(const std::string& title,
|
||||
if (mate::Converter<file_dialog::SaveDialogCallback>::FromV8(args->isolate(),
|
||||
peek,
|
||||
&callback)) {
|
||||
file_dialog::ShowSaveDialog(window, title, default_path, callback);
|
||||
file_dialog::ShowSaveDialog(window, title, default_path, filters, callback);
|
||||
} else {
|
||||
base::FilePath path;
|
||||
if (file_dialog::ShowSaveDialog(window, title, default_path, &path))
|
||||
if (file_dialog::ShowSaveDialog(window, title, default_path, filters,
|
||||
&path))
|
||||
args->Return(path);
|
||||
}
|
||||
}
|
||||
|
||||
107
atom/browser/api/atom_api_global_shortcut.cc
Normal file
107
atom/browser/api/atom_api_global_shortcut.cc
Normal file
@@ -0,0 +1,107 @@
|
||||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/api/atom_api_global_shortcut.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "atom/common/native_mate_converters/accelerator_converter.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "native_mate/callback.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
using extensions::GlobalShortcutListener;
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
GlobalShortcut::GlobalShortcut() {
|
||||
}
|
||||
|
||||
GlobalShortcut::~GlobalShortcut() {
|
||||
UnregisterAll();
|
||||
}
|
||||
|
||||
void GlobalShortcut::OnKeyPressed(const ui::Accelerator& accelerator) {
|
||||
if (accelerator_callback_map_.find(accelerator) ==
|
||||
accelerator_callback_map_.end()) {
|
||||
// This should never occur, because if it does, GlobalGlobalShortcutListener
|
||||
// notifes us with wrong accelerator.
|
||||
NOTREACHED();
|
||||
return;
|
||||
}
|
||||
accelerator_callback_map_[accelerator].Run();
|
||||
}
|
||||
|
||||
bool GlobalShortcut::Register(const ui::Accelerator& accelerator,
|
||||
const base::Closure& callback) {
|
||||
if (!GlobalShortcutListener::GetInstance()->RegisterAccelerator(
|
||||
accelerator, this)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
accelerator_callback_map_[accelerator] = callback;
|
||||
return true;
|
||||
}
|
||||
|
||||
void GlobalShortcut::Unregister(const ui::Accelerator& accelerator) {
|
||||
if (!ContainsKey(accelerator_callback_map_, accelerator))
|
||||
return;
|
||||
|
||||
accelerator_callback_map_.erase(accelerator);
|
||||
GlobalShortcutListener::GetInstance()->UnregisterAccelerator(
|
||||
accelerator, this);
|
||||
}
|
||||
|
||||
bool GlobalShortcut::IsRegistered(const ui::Accelerator& accelerator) {
|
||||
return ContainsKey(accelerator_callback_map_, accelerator);
|
||||
}
|
||||
|
||||
void GlobalShortcut::UnregisterAll() {
|
||||
accelerator_callback_map_.clear();
|
||||
GlobalShortcutListener::GetInstance()->UnregisterAccelerators(this);
|
||||
}
|
||||
|
||||
// static
|
||||
mate::ObjectTemplateBuilder GlobalShortcut::GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) {
|
||||
return mate::ObjectTemplateBuilder(isolate)
|
||||
.SetMethod("register",
|
||||
base::Bind(&GlobalShortcut::Register,
|
||||
base::Unretained(this)))
|
||||
.SetMethod("isRegistered",
|
||||
base::Bind(&GlobalShortcut::IsRegistered,
|
||||
base::Unretained(this)))
|
||||
.SetMethod("unregister",
|
||||
base::Bind(&GlobalShortcut::Unregister,
|
||||
base::Unretained(this)))
|
||||
.SetMethod("unregisterAll",
|
||||
base::Bind(&GlobalShortcut::UnregisterAll,
|
||||
base::Unretained(this)));
|
||||
}
|
||||
|
||||
// static
|
||||
mate::Handle<GlobalShortcut> GlobalShortcut::Create(v8::Isolate* isolate) {
|
||||
return CreateHandle(isolate, new GlobalShortcut);
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
||||
|
||||
namespace {
|
||||
|
||||
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
|
||||
v8::Handle<v8::Context> context, void* priv) {
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
mate::Dictionary dict(isolate, exports);
|
||||
dict.Set("globalShortcut", atom::api::GlobalShortcut::Create(isolate));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_global_shortcut, Initialize)
|
||||
55
atom/browser/api/atom_api_global_shortcut.h
Normal file
55
atom/browser/api/atom_api_global_shortcut.h
Normal file
@@ -0,0 +1,55 @@
|
||||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_API_ATOM_API_GLOBAL_SHORTCUT_H_
|
||||
#define ATOM_BROWSER_API_ATOM_API_GLOBAL_SHORTCUT_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "chrome/browser/extensions/global_shortcut_listener.h"
|
||||
#include "native_mate/wrappable.h"
|
||||
#include "native_mate/handle.h"
|
||||
#include "ui/base/accelerators/accelerator.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
class GlobalShortcut : public extensions::GlobalShortcutListener::Observer,
|
||||
public mate::Wrappable {
|
||||
public:
|
||||
static mate::Handle<GlobalShortcut> Create(v8::Isolate* isolate);
|
||||
|
||||
protected:
|
||||
GlobalShortcut();
|
||||
virtual ~GlobalShortcut();
|
||||
|
||||
// mate::Wrappable implementations:
|
||||
virtual mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) OVERRIDE;
|
||||
|
||||
private:
|
||||
typedef std::map<ui::Accelerator, base::Closure> AcceleratorCallbackMap;
|
||||
|
||||
bool Register(const ui::Accelerator& accelerator,
|
||||
const base::Closure& callback);
|
||||
bool IsRegistered(const ui::Accelerator& accelerator);
|
||||
void Unregister(const ui::Accelerator& accelerator);
|
||||
void UnregisterAll();
|
||||
|
||||
// GlobalShortcutListener::Observer implementation.
|
||||
virtual void OnKeyPressed(const ui::Accelerator& accelerator) OVERRIDE;
|
||||
|
||||
AcceleratorCallbackMap accelerator_callback_map_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(GlobalShortcut);
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_API_ATOM_API_GLOBAL_SHORTCUT_H_
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "atom/browser/api/atom_api_menu.h"
|
||||
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/ui/accelerator_util.h"
|
||||
#include "atom/common/native_mate_converters/accelerator_converter.h"
|
||||
#include "atom/common/native_mate_converters/string16_converter.h"
|
||||
#include "native_mate/constructor.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
@@ -92,12 +92,7 @@ bool Menu::GetAcceleratorForCommandId(int command_id,
|
||||
GetWrapper(isolate),
|
||||
"getAcceleratorForCommandId",
|
||||
command_id);
|
||||
if (shortcut->IsString()) {
|
||||
std::string shortcut_str = mate::V8ToString(shortcut);
|
||||
return accelerator_util::StringToAccelerator(shortcut_str, accelerator);
|
||||
}
|
||||
|
||||
return false;
|
||||
return mate::ConvertFromV8(isolate, shortcut, accelerator);
|
||||
}
|
||||
|
||||
bool Menu::IsItemForCommandIdDynamic(int command_id) const {
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include "base/message_loop/message_loop.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/browser/web_contents_view.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
@@ -44,7 +43,7 @@ void MenuMac::Popup(Window* window) {
|
||||
// Show the menu.
|
||||
[NSMenu popUpContextMenu:[menu_controller menu]
|
||||
withEvent:clickEvent
|
||||
forView:web_contents->GetView()->GetContentNativeView()];
|
||||
forView:web_contents->GetContentNativeView()];
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
@@ -8,10 +8,6 @@
|
||||
#include "ui/gfx/screen.h"
|
||||
#include "ui/views/controls/menu/menu_runner.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "ui/gfx/win/dpi.h"
|
||||
#endif
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
@@ -21,16 +17,12 @@ MenuViews::MenuViews() {
|
||||
|
||||
void MenuViews::Popup(Window* window) {
|
||||
gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
|
||||
#if defined(OS_WIN)
|
||||
cursor = gfx::win::ScreenToDIPPoint(cursor);
|
||||
#endif
|
||||
|
||||
views::MenuRunner menu_runner(model());
|
||||
ignore_result(menu_runner.RunMenuAt(
|
||||
static_cast<NativeWindowViews*>(window->window())->widget(),
|
||||
NULL,
|
||||
gfx::Rect(cursor, gfx::Size()),
|
||||
views::MenuItemView::TOPLEFT,
|
||||
views::MENU_ANCHOR_TOPLEFT,
|
||||
ui::MENU_SOURCE_MOUSE,
|
||||
views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU));
|
||||
}
|
||||
|
||||
@@ -4,14 +4,12 @@
|
||||
|
||||
#include "atom/browser/api/atom_api_protocol.h"
|
||||
|
||||
#include "base/stl_util.h"
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/net/adapter_request_job.h"
|
||||
#include "atom/browser/net/atom_url_request_context_getter.h"
|
||||
#include "atom/browser/net/atom_url_request_job_factory.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "atom/common/native_mate_converters/function_converter.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "native_mate/callback.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "net/url_request/url_request_context.h"
|
||||
|
||||
@@ -152,8 +150,9 @@ class CustomProtocolHandler : public ProtocolHandler {
|
||||
|
||||
} // namespace
|
||||
|
||||
Protocol::Protocol() : job_factory_(
|
||||
AtomBrowserContext::Get()->url_request_context_getter()->job_factory()) {
|
||||
Protocol::Protocol()
|
||||
: job_factory_(AtomBrowserContext::Get()->job_factory()) {
|
||||
CHECK(job_factory_);
|
||||
}
|
||||
|
||||
Protocol::JsProtocolHandler Protocol::GetProtocolHandler(
|
||||
@@ -324,10 +323,6 @@ namespace {
|
||||
|
||||
void Initialize(v8::Handle<v8::Object> exports, v8::Handle<v8::Value> unused,
|
||||
v8::Handle<v8::Context> context, void* priv) {
|
||||
// Make sure the job factory has been created.
|
||||
atom::AtomBrowserContext::Get()->url_request_context_getter()->
|
||||
GetURLRequestContext();
|
||||
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
mate::Dictionary dict(isolate, exports);
|
||||
dict.Set("protocol", atom::api::Protocol::Create(isolate));
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "atom/common/native_mate_converters/string16_converter.h"
|
||||
#include "atom/common/native_mate_converters/value_converter.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "content/public/browser/render_frame_host.h"
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
@@ -66,7 +67,7 @@ bool WebContents::OnMessageReceived(const IPC::Message& message) {
|
||||
return handled;
|
||||
}
|
||||
|
||||
void WebContents::WebContentsDestroyed(content::WebContents*) {
|
||||
void WebContents::WebContentsDestroyed() {
|
||||
// The RenderViewDeleted was not called when the WebContents is destroyed.
|
||||
RenderViewDeleted(web_contents_->GetRenderViewHost());
|
||||
Emit("destroyed");
|
||||
@@ -155,8 +156,7 @@ bool WebContents::IsCrashed() const {
|
||||
}
|
||||
|
||||
void WebContents::ExecuteJavaScript(const base::string16& code) {
|
||||
web_contents()->GetRenderViewHost()->ExecuteJavascriptInWebFrame(
|
||||
base::string16(), code);
|
||||
web_contents()->GetMainFrame()->ExecuteJavaScript(code);
|
||||
}
|
||||
|
||||
bool WebContents::SendIPCMessage(const base::string16& channel,
|
||||
|
||||
@@ -62,7 +62,7 @@ class WebContents : public mate::EventEmitter,
|
||||
virtual void DidStopLoading(
|
||||
content::RenderViewHost* render_view_host) OVERRIDE;
|
||||
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
|
||||
virtual void WebContentsDestroyed(content::WebContents*) OVERRIDE;
|
||||
virtual void WebContentsDestroyed() OVERRIDE;
|
||||
|
||||
private:
|
||||
// Called when received a message from renderer.
|
||||
|
||||
@@ -6,10 +6,8 @@
|
||||
|
||||
#include "atom/browser/api/atom_api_web_contents.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/common/native_mate_converters/function_converter.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/callback.h"
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
#include "native_mate/callback.h"
|
||||
#include "native_mate/constructor.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "ui/gfx/point.h"
|
||||
@@ -161,6 +159,10 @@ void Window::Restore() {
|
||||
window_->Restore();
|
||||
}
|
||||
|
||||
bool Window::IsMinimized() {
|
||||
return window_->IsMinimized();
|
||||
}
|
||||
|
||||
void Window::SetFullscreen(bool fullscreen) {
|
||||
window_->SetFullscreen(fullscreen);
|
||||
}
|
||||
@@ -357,6 +359,7 @@ void Window::BuildPrototype(v8::Isolate* isolate,
|
||||
.SetMethod("isMaximized", &Window::IsMaximized)
|
||||
.SetMethod("minimize", &Window::Minimize)
|
||||
.SetMethod("restore", &Window::Restore)
|
||||
.SetMethod("isMinimized", &Window::IsMinimized)
|
||||
.SetMethod("setFullScreen", &Window::SetFullscreen)
|
||||
.SetMethod("isFullScreen", &Window::IsFullscreen)
|
||||
.SetMethod("getSize", &Window::GetSize)
|
||||
|
||||
@@ -66,6 +66,7 @@ class Window : public mate::EventEmitter,
|
||||
bool IsMaximized();
|
||||
void Minimize();
|
||||
void Restore();
|
||||
bool IsMinimized();
|
||||
void SetFullscreen(bool fullscreen);
|
||||
bool IsFullscreen();
|
||||
void SetSize(int width, int height);
|
||||
|
||||
@@ -36,7 +36,7 @@ void Event::SetSenderAndMessage(content::WebContents* sender,
|
||||
Observe(sender);
|
||||
}
|
||||
|
||||
void Event::WebContentsDestroyed(content::WebContents* web_contents) {
|
||||
void Event::WebContentsDestroyed() {
|
||||
sender_ = NULL;
|
||||
message_ = NULL;
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ class Event : public Wrappable,
|
||||
virtual ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate);
|
||||
|
||||
// content::WebContentsObserver implementations:
|
||||
virtual void WebContentsDestroyed(content::WebContents*) OVERRIDE;
|
||||
virtual void WebContentsDestroyed() OVERRIDE;
|
||||
|
||||
private:
|
||||
// Replyer for the synchronous messages.
|
||||
|
||||
@@ -24,8 +24,8 @@ if process.platform is 'darwin'
|
||||
cancelBounce: bindings.dockCancelBounce
|
||||
setBadge: bindings.dockSetBadgeText
|
||||
getBadge: bindings.dockGetBadgeText
|
||||
hide: bindings.hide
|
||||
show: bindings.show
|
||||
hide: bindings.dockHide
|
||||
show: bindings.dockShow
|
||||
|
||||
# Be compatible with old API.
|
||||
app.once 'ready', -> app.emit 'finish-launching'
|
||||
|
||||
7
atom/browser/api/lib/content-tracing.coffee
Normal file
7
atom/browser/api/lib/content-tracing.coffee
Normal file
@@ -0,0 +1,7 @@
|
||||
module.exports = process.atomBinding 'content_tracing'
|
||||
|
||||
# Mirrored from content::TracingController::Options
|
||||
module.exports.DEFAULT_OPTIONS = 0
|
||||
module.exports.ENABLE_SYSTRACE = 1 << 0
|
||||
module.exports.ENABLE_SAMPLING = 1 << 1
|
||||
module.exports.RECORD_CONTINUOUSLY = 1 << 2
|
||||
@@ -3,7 +3,10 @@ v8Util = process.atomBinding 'v8_util'
|
||||
BrowserWindow = require 'browser-window'
|
||||
|
||||
fileDialogProperties =
|
||||
openFile: 1, openDirectory: 2, multiSelections: 4, createDirectory: 8
|
||||
openFile: 1 << 0
|
||||
openDirectory: 1 << 1
|
||||
multiSelections: 1 << 2
|
||||
createDirectory: 1 << 3
|
||||
|
||||
messageBoxTypes = ['none', 'info', 'warning']
|
||||
|
||||
@@ -25,6 +28,7 @@ module.exports =
|
||||
|
||||
options.title ?= ''
|
||||
options.defaultPath ?= ''
|
||||
options.filters ?= []
|
||||
|
||||
wrappedCallback =
|
||||
if typeof callback is 'function'
|
||||
@@ -34,6 +38,7 @@ module.exports =
|
||||
|
||||
binding.showOpenDialog String(options.title),
|
||||
String(options.defaultPath),
|
||||
options.filters
|
||||
properties,
|
||||
window,
|
||||
wrappedCallback
|
||||
@@ -48,6 +53,7 @@ module.exports =
|
||||
options ?= title: 'Save'
|
||||
options.title ?= ''
|
||||
options.defaultPath ?= ''
|
||||
options.filters ?= []
|
||||
|
||||
wrappedCallback =
|
||||
if typeof callback is 'function'
|
||||
@@ -57,6 +63,7 @@ module.exports =
|
||||
|
||||
binding.showSaveDialog String(options.title),
|
||||
String(options.defaultPath),
|
||||
options.filters
|
||||
window,
|
||||
wrappedCallback
|
||||
|
||||
|
||||
5
atom/browser/api/lib/global-shortcut.coffee
Normal file
5
atom/browser/api/lib/global-shortcut.coffee
Normal file
@@ -0,0 +1,5 @@
|
||||
bindings = process.atomBinding 'global_shortcut'
|
||||
|
||||
globalShortcut = bindings.globalShortcut
|
||||
|
||||
module.exports = globalShortcut
|
||||
53
atom/browser/atom_access_token_store.cc
Normal file
53
atom/browser/atom_access_token_store.cc
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/atom_access_token_store.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
|
||||
#ifndef GOOGLEAPIS_API_KEY
|
||||
#define GOOGLEAPIS_API_KEY "AIzaSyAQfxPJiounkhOjODEO5ZieffeBv6yft2Q"
|
||||
#endif
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
// Notice that we just combined the api key with the url together here, because
|
||||
// if we use the standard {url: key} format Chromium would override our key with
|
||||
// the predefined one in common.gypi of libchromiumcontent, which is empty.
|
||||
const char* kGeolocationProviderUrl =
|
||||
"https://www.googleapis.com/geolocation/v1/geolocate?key="
|
||||
GOOGLEAPIS_API_KEY;
|
||||
|
||||
} // namespace
|
||||
|
||||
AtomAccessTokenStore::AtomAccessTokenStore() {
|
||||
}
|
||||
|
||||
AtomAccessTokenStore::~AtomAccessTokenStore() {
|
||||
}
|
||||
|
||||
void AtomAccessTokenStore::LoadAccessTokens(
|
||||
const LoadAccessTokensCallbackType& callback) {
|
||||
AccessTokenSet access_token_set;
|
||||
|
||||
// Equivelent to access_token_set[kGeolocationProviderUrl].
|
||||
// Somehow base::string16 is causing compilation errors when used in a pair
|
||||
// of std::map on Linux, this can work around it.
|
||||
std::pair<GURL, base::string16> token_pair;
|
||||
token_pair.first = GURL(kGeolocationProviderUrl);
|
||||
access_token_set.insert(token_pair);
|
||||
|
||||
callback.Run(access_token_set,
|
||||
AtomBrowserContext::Get()->url_request_context_getter());
|
||||
}
|
||||
|
||||
void AtomAccessTokenStore::SaveAccessToken(const GURL& server_url,
|
||||
const base::string16& access_token) {
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
31
atom/browser/atom_access_token_store.h
Normal file
31
atom/browser/atom_access_token_store.h
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_ATOM_ACCESS_TOKEN_STORE_H_
|
||||
#define ATOM_BROWSER_ATOM_ACCESS_TOKEN_STORE_H_
|
||||
|
||||
#include "content/public/browser/access_token_store.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomBrowserContext;
|
||||
|
||||
class AtomAccessTokenStore : public content::AccessTokenStore {
|
||||
public:
|
||||
AtomAccessTokenStore();
|
||||
virtual ~AtomAccessTokenStore();
|
||||
|
||||
// content::AccessTokenStore:
|
||||
virtual void LoadAccessTokens(
|
||||
const LoadAccessTokensCallbackType& callback) OVERRIDE;
|
||||
virtual void SaveAccessToken(const GURL& server_url,
|
||||
const base::string16& access_token) OVERRIDE;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomAccessTokenStore);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_ATOM_ACCESS_TOKEN_STORE_H_
|
||||
@@ -4,13 +4,15 @@
|
||||
|
||||
#include "atom/browser/atom_browser_client.h"
|
||||
|
||||
#include "atom/browser/atom_access_token_store.h"
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/atom_browser_main_parts.h"
|
||||
#include "atom/browser/atom_resource_dispatcher_host_delegate.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/net/atom_url_request_context_getter.h"
|
||||
#include "atom/browser/window_list.h"
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#include "content/public/browser/resource_dispatcher_host.h"
|
||||
#include "content/public/browser/site_instance.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
@@ -46,12 +48,14 @@ AtomBrowserClient::AtomBrowserClient()
|
||||
AtomBrowserClient::~AtomBrowserClient() {
|
||||
}
|
||||
|
||||
net::URLRequestContextGetter* AtomBrowserClient::CreateRequestContext(
|
||||
content::BrowserContext* browser_context,
|
||||
content::ProtocolHandlerMap* protocol_handlers,
|
||||
content::ProtocolHandlerScopedVector protocol_interceptors) {
|
||||
return static_cast<AtomBrowserContext*>(browser_context)->
|
||||
CreateRequestContext(protocol_handlers);
|
||||
void AtomBrowserClient::ResourceDispatcherHostCreated() {
|
||||
resource_dispatcher_delegate_.reset(new AtomResourceDispatcherHostDelegate);
|
||||
content::ResourceDispatcherHost::Get()->SetDelegate(
|
||||
resource_dispatcher_delegate_.get());
|
||||
}
|
||||
|
||||
content::AccessTokenStore* AtomBrowserClient::CreateAccessTokenStore() {
|
||||
return new AtomAccessTokenStore;
|
||||
}
|
||||
|
||||
void AtomBrowserClient::OverrideWebkitPrefs(
|
||||
|
||||
@@ -11,16 +11,17 @@
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomResourceDispatcherHostDelegate;
|
||||
|
||||
class AtomBrowserClient : public brightray::BrowserClient {
|
||||
public:
|
||||
AtomBrowserClient();
|
||||
virtual ~AtomBrowserClient();
|
||||
|
||||
protected:
|
||||
net::URLRequestContextGetter* CreateRequestContext(
|
||||
content::BrowserContext* browser_context,
|
||||
content::ProtocolHandlerMap* protocol_handlers,
|
||||
content::ProtocolHandlerScopedVector protocol_interceptors) OVERRIDE;
|
||||
// content::ContentBrowserClient:
|
||||
virtual void ResourceDispatcherHostCreated() OVERRIDE;
|
||||
virtual content::AccessTokenStore* CreateAccessTokenStore() OVERRIDE;
|
||||
virtual void OverrideWebkitPrefs(content::RenderViewHost* render_view_host,
|
||||
const GURL& url,
|
||||
WebPreferences* prefs) OVERRIDE;
|
||||
@@ -36,6 +37,8 @@ class AtomBrowserClient : public brightray::BrowserClient {
|
||||
virtual brightray::BrowserMainParts* OverrideCreateBrowserMainParts(
|
||||
const content::MainFunctionParams&) OVERRIDE;
|
||||
|
||||
scoped_ptr<AtomResourceDispatcherHostDelegate> resource_dispatcher_delegate_;
|
||||
|
||||
// The render process which would be swapped out soon.
|
||||
content::RenderProcessHost* dying_render_process_;
|
||||
|
||||
|
||||
@@ -5,72 +5,54 @@
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
|
||||
#include "atom/browser/atom_browser_main_parts.h"
|
||||
#include "atom/browser/net/atom_url_request_context_getter.h"
|
||||
#include "atom/browser/net/atom_url_request_job_factory.h"
|
||||
#include "base/threading/sequenced_worker_pool.h"
|
||||
#include "base/threading/worker_pool.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/resource_context.h"
|
||||
#include "vendor/brightray/browser/network_delegate.h"
|
||||
|
||||
namespace atom {
|
||||
#include "content/public/common/url_constants.h"
|
||||
#include "net/url_request/data_protocol_handler.h"
|
||||
#include "net/url_request/file_protocol_handler.h"
|
||||
#include "net/url_request/protocol_intercept_job_factory.h"
|
||||
|
||||
using content::BrowserThread;
|
||||
|
||||
class AtomResourceContext : public content::ResourceContext {
|
||||
public:
|
||||
AtomResourceContext() : getter_(NULL) {}
|
||||
|
||||
void set_url_request_context_getter(AtomURLRequestContextGetter* getter) {
|
||||
getter_ = getter;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual net::HostResolver* GetHostResolver() OVERRIDE {
|
||||
DCHECK(getter_);
|
||||
return getter_->host_resolver();
|
||||
}
|
||||
|
||||
virtual net::URLRequestContext* GetRequestContext() OVERRIDE {
|
||||
DCHECK(getter_);
|
||||
return getter_->GetURLRequestContext();
|
||||
}
|
||||
|
||||
virtual bool AllowMicAccess(const GURL& origin) OVERRIDE {
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool AllowCameraAccess(const GURL& origin) OVERRIDE {
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
AtomURLRequestContextGetter* getter_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomResourceContext);
|
||||
};
|
||||
namespace atom {
|
||||
|
||||
AtomBrowserContext::AtomBrowserContext()
|
||||
: resource_context_(new AtomResourceContext) {
|
||||
: job_factory_(new AtomURLRequestJobFactory) {
|
||||
}
|
||||
|
||||
AtomBrowserContext::~AtomBrowserContext() {
|
||||
}
|
||||
|
||||
AtomURLRequestContextGetter* AtomBrowserContext::CreateRequestContext(
|
||||
content::ProtocolHandlerMap* protocol_handlers) {
|
||||
DCHECK(!url_request_getter_);
|
||||
url_request_getter_ = new AtomURLRequestContextGetter(
|
||||
GetPath(),
|
||||
BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::IO),
|
||||
BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::FILE),
|
||||
base::Bind(&AtomBrowserContext::CreateNetworkDelegate,
|
||||
base::Unretained(this)),
|
||||
protocol_handlers);
|
||||
scoped_ptr<net::URLRequestJobFactory>
|
||||
AtomBrowserContext::CreateURLRequestJobFactory(
|
||||
content::ProtocolHandlerMap* handlers,
|
||||
content::ProtocolHandlerScopedVector* interceptors) {
|
||||
scoped_ptr<AtomURLRequestJobFactory> job_factory(job_factory_);
|
||||
|
||||
resource_context_->set_url_request_context_getter(url_request_getter_.get());
|
||||
return url_request_getter_.get();
|
||||
}
|
||||
for (content::ProtocolHandlerMap::iterator it = handlers->begin();
|
||||
it != handlers->end(); ++it)
|
||||
job_factory->SetProtocolHandler(it->first, it->second.release());
|
||||
handlers->clear();
|
||||
|
||||
content::ResourceContext* AtomBrowserContext::GetResourceContext() {
|
||||
return resource_context_.get();
|
||||
job_factory->SetProtocolHandler(
|
||||
content::kDataScheme, new net::DataProtocolHandler);
|
||||
job_factory->SetProtocolHandler(
|
||||
content::kFileScheme, new net::FileProtocolHandler(
|
||||
BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior(
|
||||
base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)));
|
||||
|
||||
// Set up interceptors in the reverse order.
|
||||
scoped_ptr<net::URLRequestJobFactory> top_job_factory =
|
||||
job_factory.PassAs<net::URLRequestJobFactory>();
|
||||
content::ProtocolHandlerScopedVector::reverse_iterator it;
|
||||
for (it = interceptors->rbegin(); it != interceptors->rend(); ++it)
|
||||
top_job_factory.reset(new net::ProtocolInterceptJobFactory(
|
||||
top_job_factory.Pass(), make_scoped_ptr(*it)));
|
||||
interceptors->weak_clear();
|
||||
|
||||
return top_job_factory.Pass();
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
@@ -5,13 +5,11 @@
|
||||
#ifndef ATOM_BROWSER_ATOM_BROWSER_CONTEXT_H_
|
||||
#define ATOM_BROWSER_ATOM_BROWSER_CONTEXT_H_
|
||||
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "brightray/browser/browser_context.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomResourceContext;
|
||||
class AtomURLRequestContextGetter;
|
||||
class AtomURLRequestJobFactory;
|
||||
|
||||
class AtomBrowserContext : public brightray::BrowserContext {
|
||||
public:
|
||||
@@ -21,22 +19,16 @@ class AtomBrowserContext : public brightray::BrowserContext {
|
||||
// Returns the browser context singleton.
|
||||
static AtomBrowserContext* Get();
|
||||
|
||||
// Creates or returns the request context.
|
||||
AtomURLRequestContextGetter* CreateRequestContext(
|
||||
content::ProtocolHandlerMap*);
|
||||
|
||||
AtomURLRequestContextGetter* url_request_context_getter() const {
|
||||
DCHECK(url_request_getter_);
|
||||
return url_request_getter_.get();
|
||||
}
|
||||
AtomURLRequestJobFactory* job_factory() const { return job_factory_; }
|
||||
|
||||
protected:
|
||||
// content::BrowserContext implementations:
|
||||
virtual content::ResourceContext* GetResourceContext() OVERRIDE;
|
||||
// brightray::BrowserContext:
|
||||
virtual scoped_ptr<net::URLRequestJobFactory> CreateURLRequestJobFactory(
|
||||
content::ProtocolHandlerMap* handlers,
|
||||
content::ProtocolHandlerScopedVector* interceptors) OVERRIDE;
|
||||
|
||||
private:
|
||||
scoped_ptr<AtomResourceContext> resource_context_;
|
||||
scoped_refptr<AtomURLRequestContextGetter> url_request_getter_;
|
||||
AtomURLRequestJobFactory* job_factory_; // Weak reference.
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomBrowserContext);
|
||||
};
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
#include "atom/browser/atom_browser_client.h"
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/browser.h"
|
||||
#include "atom/browser/javascript_environment.h"
|
||||
#include "atom/common/api/atom_bindings.h"
|
||||
#include "atom/common/node_bindings.h"
|
||||
#include "base/command_line.h"
|
||||
#include "net/proxy/proxy_resolver_v8.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "ui/gfx/win/dpi.h"
|
||||
@@ -28,14 +28,9 @@ namespace atom {
|
||||
AtomBrowserMainParts* AtomBrowserMainParts::self_ = NULL;
|
||||
|
||||
AtomBrowserMainParts::AtomBrowserMainParts()
|
||||
: atom_bindings_(new AtomBindings),
|
||||
browser_(new Browser),
|
||||
: browser_(new Browser),
|
||||
node_bindings_(NodeBindings::Create(true)),
|
||||
isolate_(v8::Isolate::GetCurrent()),
|
||||
locker_(isolate_),
|
||||
handle_scope_(isolate_),
|
||||
context_(isolate_, v8::Context::New(isolate_)),
|
||||
context_scope_(v8::Local<v8::Context>::New(isolate_, context_)) {
|
||||
atom_bindings_(new AtomBindings) {
|
||||
DCHECK(!self_) << "Cannot have two AtomBrowserMainParts";
|
||||
self_ = this;
|
||||
}
|
||||
@@ -53,39 +48,35 @@ brightray::BrowserContext* AtomBrowserMainParts::CreateBrowserContext() {
|
||||
return new AtomBrowserContext();
|
||||
}
|
||||
|
||||
void AtomBrowserMainParts::InitProxyResolverV8() {
|
||||
// Since we are integrating node in browser, we can just be sure that an
|
||||
// V8 instance would be prepared, while the ProxyResolverV8::CreateIsolate()
|
||||
// would try to create a V8 isolate, which messed everything on Windows, so
|
||||
// we have to override and call RememberDefaultIsolate on Windows instead.
|
||||
net::ProxyResolverV8::RememberDefaultIsolate();
|
||||
}
|
||||
|
||||
void AtomBrowserMainParts::PostEarlyInitialization() {
|
||||
brightray::BrowserMainParts::PostEarlyInitialization();
|
||||
|
||||
// The ProxyResolverV8 has setup a complete V8 environment, in order to avoid
|
||||
// conflicts we only initialize our V8 environment after that.
|
||||
js_env_.reset(new JavascriptEnvironment);
|
||||
|
||||
node_bindings_->Initialize();
|
||||
|
||||
// Create the global environment.
|
||||
global_env = node_bindings_->CreateEnvironment(
|
||||
v8::Local<v8::Context>::New(isolate_, context_));
|
||||
global_env = node_bindings_->CreateEnvironment(js_env_->context());
|
||||
|
||||
// Add atom-shell extended APIs.
|
||||
atom_bindings_->BindTo(isolate_, global_env->process_object());
|
||||
atom_bindings_->BindTo(js_env_->isolate(), global_env->process_object());
|
||||
}
|
||||
|
||||
void AtomBrowserMainParts::PreMainMessageLoopRun() {
|
||||
// Run user's main script before most things get initialized, so we can have
|
||||
// a chance to setup everything.
|
||||
node_bindings_->PrepareMessageLoop();
|
||||
node_bindings_->RunMessageLoop();
|
||||
|
||||
brightray::BrowserMainParts::PreMainMessageLoopRun();
|
||||
|
||||
#if defined(USE_X11)
|
||||
libgtk2ui::GtkInitFromCommandLine(*CommandLine::ForCurrentProcess());
|
||||
#endif
|
||||
|
||||
node_bindings_->PrepareMessageLoop();
|
||||
node_bindings_->RunMessageLoop();
|
||||
|
||||
// Make sure the url request job factory is created before the
|
||||
// will-finish-launching event.
|
||||
// Make sure the url request job factory is created before the ready event.
|
||||
static_cast<content::BrowserContext*>(AtomBrowserContext::Get())->
|
||||
GetRequestContext();
|
||||
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
#define ATOM_BROWSER_ATOM_BROWSER_MAIN_PARTS_H_
|
||||
|
||||
#include "brightray/browser/browser_main_parts.h"
|
||||
#include "v8/include/v8.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomBindings;
|
||||
class Browser;
|
||||
class JavascriptEnvironment;
|
||||
class NodeBindings;
|
||||
|
||||
class AtomBrowserMainParts : public brightray::BrowserMainParts {
|
||||
@@ -26,7 +26,6 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
|
||||
protected:
|
||||
// Implementations of brightray::BrowserMainParts.
|
||||
virtual brightray::BrowserContext* CreateBrowserContext() OVERRIDE;
|
||||
virtual void InitProxyResolverV8() OVERRIDE;
|
||||
|
||||
// Implementations of content::BrowserMainParts.
|
||||
virtual void PostEarlyInitialization() OVERRIDE;
|
||||
@@ -37,16 +36,10 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
|
||||
#endif
|
||||
|
||||
private:
|
||||
scoped_ptr<AtomBindings> atom_bindings_;
|
||||
scoped_ptr<Browser> browser_;
|
||||
scoped_ptr<JavascriptEnvironment> js_env_;
|
||||
scoped_ptr<NodeBindings> node_bindings_;
|
||||
|
||||
// The V8 environment of browser process.
|
||||
v8::Isolate* isolate_;
|
||||
v8::Locker locker_;
|
||||
v8::HandleScope handle_scope_;
|
||||
v8::UniquePersistent<v8::Context> context_;
|
||||
v8::Context::Scope context_scope_;
|
||||
scoped_ptr<AtomBindings> atom_bindings_;
|
||||
|
||||
static AtomBrowserMainParts* self_;
|
||||
|
||||
|
||||
50
atom/browser/atom_resource_dispatcher_host_delegate.cc
Normal file
50
atom/browser/atom_resource_dispatcher_host_delegate.cc
Normal file
@@ -0,0 +1,50 @@
|
||||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/atom_resource_dispatcher_host_delegate.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "content/public/browser/render_frame_host.h"
|
||||
#include "content/public/browser/resource_request_info.h"
|
||||
#include "net/http/http_response_headers.h"
|
||||
#include "net/url_request/url_request.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
const char* kDisableXFrameOptions = "disable-x-frame-options";
|
||||
|
||||
} // namespace
|
||||
|
||||
AtomResourceDispatcherHostDelegate::AtomResourceDispatcherHostDelegate() {
|
||||
}
|
||||
|
||||
AtomResourceDispatcherHostDelegate::~AtomResourceDispatcherHostDelegate() {
|
||||
}
|
||||
|
||||
void AtomResourceDispatcherHostDelegate::OnResponseStarted(
|
||||
net::URLRequest* request,
|
||||
content::ResourceContext* resource_context,
|
||||
content::ResourceResponse* response,
|
||||
IPC::Sender* sender) {
|
||||
// Check if frame's name contains "disable-x-frame-options"
|
||||
int p, f;
|
||||
if (!content::ResourceRequestInfo::GetRenderFrameForRequest(request, &p, &f))
|
||||
return;
|
||||
content::RenderFrameHost* frame = content::RenderFrameHost::FromID(p, f);
|
||||
if (!frame)
|
||||
return;
|
||||
if (frame->GetFrameName().find(kDisableXFrameOptions) == std::string::npos)
|
||||
return;
|
||||
|
||||
// Remove the "X-Frame-Options" from response headers.
|
||||
net::HttpResponseHeaders* response_headers = request->response_headers();
|
||||
if (response_headers && response_headers->HasHeader("x-frame-options"))
|
||||
response_headers->RemoveHeader("x-frame-options");
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
31
atom/browser/atom_resource_dispatcher_host_delegate.h
Normal file
31
atom/browser/atom_resource_dispatcher_host_delegate.h
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_ATOM_RESOURCE_DISPATCHER_HOST_DELEGATE_H_
|
||||
#define ATOM_BROWSER_ATOM_RESOURCE_DISPATCHER_HOST_DELEGATE_H_
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
#include "content/public/browser/resource_dispatcher_host_delegate.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomResourceDispatcherHostDelegate
|
||||
: public content::ResourceDispatcherHostDelegate {
|
||||
public:
|
||||
AtomResourceDispatcherHostDelegate();
|
||||
virtual ~AtomResourceDispatcherHostDelegate();
|
||||
|
||||
// content::ResourceDispatcherHostDelegate:
|
||||
virtual void OnResponseStarted(net::URLRequest* request,
|
||||
content::ResourceContext* resource_context,
|
||||
content::ResourceResponse* response,
|
||||
IPC::Sender* sender) OVERRIDE;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomResourceDispatcherHostDelegate);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_ATOM_RESOURCE_DISPATCHER_HOST_DELEGATE_H_
|
||||
@@ -48,11 +48,13 @@ void AutoUpdater::SetFeedURL(const std::string& feed) {
|
||||
[[g_updater rac_valuesForKeyPath:@"state" observer:g_updater]
|
||||
subscribeNext:^(NSNumber *stateNumber) {
|
||||
int state = [stateNumber integerValue];
|
||||
if (state == SQRLUpdaterStateCheckingForUpdate) {
|
||||
delegate->OnCheckingForUpdate();
|
||||
} else if (state == SQRLUpdaterStateDownloadingUpdate) {
|
||||
delegate->OnUpdateAvailable();
|
||||
}
|
||||
// Dispatching the event on main thread.
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (state == SQRLUpdaterStateCheckingForUpdate)
|
||||
delegate->OnCheckingForUpdate();
|
||||
else if (state == SQRLUpdaterStateDownloadingUpdate)
|
||||
delegate->OnUpdateAvailable();
|
||||
});
|
||||
}];
|
||||
}
|
||||
}
|
||||
@@ -89,4 +91,5 @@ void AutoUpdater::CheckForUpdates() {
|
||||
delegate->OnError(base::SysNSStringToUTF8(error.localizedDescription));
|
||||
}];
|
||||
}
|
||||
|
||||
} // namespace auto_updater
|
||||
|
||||
17
atom/browser/javascript_environment.cc
Normal file
17
atom/browser/javascript_environment.cc
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/javascript_environment.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
JavascriptEnvironment::JavascriptEnvironment()
|
||||
: isolate_(v8::Isolate::GetCurrent()),
|
||||
locker_(isolate_),
|
||||
handle_scope_(isolate_),
|
||||
context_(isolate_, v8::Context::New(isolate_)),
|
||||
context_scope_(v8::Local<v8::Context>::New(isolate_, context_)) {
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
34
atom/browser/javascript_environment.h
Normal file
34
atom/browser/javascript_environment.h
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_JAVASCRIPT_ENVIRONMENT_H_
|
||||
#define ATOM_BROWSER_JAVASCRIPT_ENVIRONMENT_H_
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "v8/include/v8.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class JavascriptEnvironment {
|
||||
public:
|
||||
JavascriptEnvironment();
|
||||
|
||||
v8::Isolate* isolate() const { return isolate_; }
|
||||
v8::Local<v8::Context> context() const {
|
||||
return v8::Local<v8::Context>::New(isolate_, context_);
|
||||
}
|
||||
|
||||
private:
|
||||
v8::Isolate* isolate_;
|
||||
v8::Locker locker_;
|
||||
v8::HandleScope handle_scope_;
|
||||
v8::UniquePersistent<v8::Context> context_;
|
||||
v8::Context::Scope context_scope_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(JavascriptEnvironment);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_JAVASCRIPT_ENVIRONMENT_H_
|
||||
@@ -14,7 +14,7 @@ process.argv.splice 1, 1
|
||||
# Pick out switches appended by atom-shell.
|
||||
startMark = process.argv.indexOf '--atom-shell-switches-start'
|
||||
endMark = process.argv.indexOf '--atom-shell-switches-end'
|
||||
process.execArgv = process.argv.splice startMark, endMark - startMark + 1
|
||||
process.argv.splice startMark, endMark - startMark + 1
|
||||
|
||||
# Add browser/api/lib to require's search paths,
|
||||
# which contains javascript part of Atom's built-in libraries.
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "brightray/browser/inspectable_web_contents.h"
|
||||
#include "brightray/browser/inspectable_web_contents_view.h"
|
||||
#include "content/public/browser/devtools_agent_host.h"
|
||||
#include "content/public/browser/invalidate_type.h"
|
||||
#include "content/public/browser/navigation_entry.h"
|
||||
@@ -38,19 +40,14 @@
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#include "content/public/browser/render_widget_host_view.h"
|
||||
#include "content/public/browser/web_contents_view.h"
|
||||
#include "content/public/common/renderer_preferences.h"
|
||||
#include "content/public/common/user_agent.h"
|
||||
#include "ipc/ipc_message_macros.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "ui/gfx/codec/png_codec.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
#include "ui/gfx/image/image_skia.h"
|
||||
#include "ui/gfx/point.h"
|
||||
#include "ui/gfx/rect.h"
|
||||
#include "ui/gfx/size.h"
|
||||
#include "vendor/brightray/browser/inspectable_web_contents.h"
|
||||
#include "vendor/brightray/browser/inspectable_web_contents_view.h"
|
||||
#include "webkit/common/webpreferences.h"
|
||||
|
||||
using content::NavigationEntry;
|
||||
@@ -61,6 +58,7 @@ NativeWindow::NativeWindow(content::WebContents* web_contents,
|
||||
const mate::Dictionary& options)
|
||||
: content::WebContentsObserver(web_contents),
|
||||
has_frame_(true),
|
||||
enable_larger_than_screen_(false),
|
||||
is_closed_(false),
|
||||
node_integration_("except-iframe"),
|
||||
has_dialog_attached_(false),
|
||||
@@ -69,11 +67,10 @@ NativeWindow::NativeWindow(content::WebContents* web_contents,
|
||||
inspectable_web_contents_(
|
||||
brightray::InspectableWebContents::Create(web_contents)) {
|
||||
options.Get(switches::kFrame, &has_frame_);
|
||||
options.Get(switches::kEnableLargerThanScreen, &enable_larger_than_screen_);
|
||||
|
||||
// Read icon before window is created.
|
||||
gfx::ImageSkia icon;
|
||||
if (options.Get(switches::kIcon, &icon))
|
||||
icon_.reset(new gfx::Image(icon));
|
||||
options.Get(switches::kIcon, &icon_);
|
||||
|
||||
// Read iframe security before any navigation.
|
||||
options.Get(switches::kNodeIntegration, &node_integration_);
|
||||
@@ -105,10 +102,6 @@ NativeWindow::NativeWindow(content::WebContents* web_contents,
|
||||
}
|
||||
|
||||
NativeWindow::~NativeWindow() {
|
||||
// Make sure we have the OnRenderViewDeleted message sent even when the window
|
||||
// is destroyed directly.
|
||||
DestroyWebContents();
|
||||
|
||||
// It's possible that the windows gets destroyed before it's closed, in that
|
||||
// case we need to ensure the OnWindowClosed message is still notified.
|
||||
NotifyWindowClosed();
|
||||
@@ -305,7 +298,7 @@ void NativeWindow::CloseWebContents() {
|
||||
ScheduleUnresponsiveEvent(5000);
|
||||
|
||||
if (web_contents->NeedToFireBeforeUnload())
|
||||
web_contents->GetMainFrame()->DispatchBeforeUnload(false);
|
||||
web_contents->DispatchBeforeUnload(false);
|
||||
else
|
||||
web_contents->Close();
|
||||
}
|
||||
@@ -356,8 +349,6 @@ void NativeWindow::OverrideWebkitPrefs(const GURL& url, WebPreferences* prefs) {
|
||||
prefs->experimental_webgl_enabled = b;
|
||||
if (web_preferences.Get("webaudio", &b))
|
||||
prefs->webaudio_enabled = b;
|
||||
if (web_preferences.Get("accelerated-compositing", &b))
|
||||
prefs->accelerated_compositing_enabled = b;
|
||||
if (web_preferences.Get("plugins", &b))
|
||||
prefs->plugins_enabled = b;
|
||||
if (web_preferences.Get("extra-plugin-dirs", &list))
|
||||
@@ -535,8 +526,9 @@ void NativeWindow::DevToolsSaveToFile(const std::string& url,
|
||||
if (it != saved_files_.end() && !save_as) {
|
||||
path = it->second;
|
||||
} else {
|
||||
file_dialog::Filters filters;
|
||||
base::FilePath default_path(base::FilePath::FromUTF8Unsafe(url));
|
||||
if (!file_dialog::ShowSaveDialog(this, url, default_path, &path)) {
|
||||
if (!file_dialog::ShowSaveDialog(this, url, default_path, filters, &path)) {
|
||||
base::StringValue url_value(url);
|
||||
CallDevToolsFunction("InspectorFrontendAPI.canceledSaveURL", &url_value);
|
||||
return;
|
||||
|
||||
@@ -9,20 +9,19 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "atom/browser/native_window_observer.h"
|
||||
#include "atom/browser/ui/accelerator_util.h"
|
||||
#include "base/cancelable_callback.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/observer_list.h"
|
||||
#include "atom/browser/native_window_observer.h"
|
||||
#include "atom/browser/ui/accelerator_util.h"
|
||||
#include "brightray/browser/default_web_contents_delegate.h"
|
||||
#include "brightray/browser/inspectable_web_contents_delegate.h"
|
||||
#include "brightray/browser/inspectable_web_contents_impl.h"
|
||||
#include "content/public/browser/notification_registrar.h"
|
||||
#include "content/public/browser/notification_observer.h"
|
||||
#include "native_mate/scoped_persistent.h"
|
||||
#include "vendor/brightray/browser/default_web_contents_delegate.h"
|
||||
#include "vendor/brightray/browser/inspectable_web_contents_delegate.h"
|
||||
#include "vendor/brightray/browser/inspectable_web_contents_impl.h"
|
||||
#include "ui/gfx/image/image_skia.h"
|
||||
|
||||
struct WebPreferences;
|
||||
|
||||
@@ -36,7 +35,6 @@ class WebContents;
|
||||
}
|
||||
|
||||
namespace gfx {
|
||||
class Image;
|
||||
class Point;
|
||||
class Rect;
|
||||
class Size;
|
||||
@@ -111,6 +109,7 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
virtual bool IsMaximized() = 0;
|
||||
virtual void Minimize() = 0;
|
||||
virtual void Restore() = 0;
|
||||
virtual bool IsMinimized() = 0;
|
||||
virtual void SetFullscreen(bool fullscreen) = 0;
|
||||
virtual bool IsFullscreen() = 0;
|
||||
virtual void SetSize(const gfx::Size& size) = 0;
|
||||
@@ -252,8 +251,11 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
// Whether window has standard frame.
|
||||
bool has_frame_;
|
||||
|
||||
// Whether window can be resized larger than screen.
|
||||
bool enable_larger_than_screen_;
|
||||
|
||||
// Window icon.
|
||||
scoped_ptr<gfx::Image> icon_;
|
||||
gfx::ImageSkia icon_;
|
||||
|
||||
private:
|
||||
// Schedule a notification unresponsive event.
|
||||
|
||||
@@ -35,6 +35,7 @@ class NativeWindowMac : public NativeWindow {
|
||||
virtual bool IsMaximized() OVERRIDE;
|
||||
virtual void Minimize() OVERRIDE;
|
||||
virtual void Restore() OVERRIDE;
|
||||
virtual bool IsMinimized() OVERRIDE;
|
||||
virtual void SetFullscreen(bool fullscreen) OVERRIDE;
|
||||
virtual bool IsFullscreen() OVERRIDE;
|
||||
virtual void SetSize(const gfx::Size& size) OVERRIDE;
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "content/public/browser/native_web_keyboard_event.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/browser/web_contents_view.h"
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#include "content/public/browser/render_widget_host_view.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
@@ -50,31 +49,31 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
|
||||
}
|
||||
|
||||
- (void)windowDidBecomeMain:(NSNotification*)notification {
|
||||
shell_->NotifyWindowFocus();
|
||||
|
||||
content::WebContents* web_contents = shell_->GetWebContents();
|
||||
if (!web_contents)
|
||||
return;
|
||||
|
||||
web_contents->GetView()->RestoreFocus();
|
||||
web_contents->RestoreFocus();
|
||||
|
||||
content::RenderWidgetHostView* rwhv = web_contents->GetRenderWidgetHostView();
|
||||
if (rwhv)
|
||||
rwhv->SetActive(true);
|
||||
|
||||
shell_->NotifyWindowFocus();
|
||||
}
|
||||
|
||||
- (void)windowDidResignMain:(NSNotification*)notification {
|
||||
shell_->NotifyWindowBlur();
|
||||
|
||||
content::WebContents* web_contents = shell_->GetWebContents();
|
||||
if (!web_contents)
|
||||
return;
|
||||
|
||||
web_contents->GetView()->StoreFocus();
|
||||
web_contents->StoreFocus();
|
||||
|
||||
content::RenderWidgetHostView* rwhv = web_contents->GetRenderWidgetHostView();
|
||||
if (rwhv)
|
||||
rwhv->SetActive(false);
|
||||
|
||||
shell_->NotifyWindowBlur();
|
||||
}
|
||||
|
||||
- (void)windowDidResize:(NSNotification*)otification {
|
||||
@@ -109,10 +108,12 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
|
||||
@end
|
||||
|
||||
@interface AtomNSWindow : EventProcessingWindow {
|
||||
@protected
|
||||
@private
|
||||
atom::NativeWindowMac* shell_;
|
||||
bool enable_larger_than_screen_;
|
||||
}
|
||||
- (void)setShell:(atom::NativeWindowMac*)shell;
|
||||
- (void)setEnableLargerThanScreen:(bool)enable;
|
||||
@end
|
||||
|
||||
@implementation AtomNSWindow
|
||||
@@ -121,6 +122,18 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
|
||||
shell_ = shell;
|
||||
}
|
||||
|
||||
- (void)setEnableLargerThanScreen:(bool)enable {
|
||||
enable_larger_than_screen_ = enable;
|
||||
}
|
||||
|
||||
// Enable the window to be larger than screen.
|
||||
- (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen*)screen {
|
||||
if (enable_larger_than_screen_)
|
||||
return frameRect;
|
||||
else
|
||||
return [super constrainFrameRect:frameRect toScreen:screen];
|
||||
}
|
||||
|
||||
- (IBAction)reload:(id)sender {
|
||||
shell_->GetWebContents()->GetController().ReloadIgnoringCache(false);
|
||||
}
|
||||
@@ -129,6 +142,20 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
|
||||
shell_->OpenDevTools();
|
||||
}
|
||||
|
||||
// Returns an empty array for AXChildren attribute, this will force the
|
||||
// SpeechSynthesisServer to use its classical way of speaking the selected text:
|
||||
// by invoking the "Command+C" for current application and then speak out
|
||||
// what's in the clipboard. Otherwise the "Text to Speech" would always speak
|
||||
// out window's title.
|
||||
// This behavior is taken by both FireFox and Chrome, see also FireFox's bug on
|
||||
// more of how SpeechSynthesisServer chose which text to read:
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=674612
|
||||
- (id)accessibilityAttributeValue:(NSString*)attribute {
|
||||
if ([attribute isEqualToString:@"AXChildren"])
|
||||
return [NSArray array];
|
||||
return [super accessibilityAttributeValue:attribute];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface ControlRegionView : NSView {
|
||||
@@ -195,6 +222,7 @@ NativeWindowMac::NativeWindowMac(content::WebContents* web_contents,
|
||||
defer:YES];
|
||||
|
||||
[atomWindow setShell:this];
|
||||
[atomWindow setEnableLargerThanScreen:enable_larger_than_screen_];
|
||||
window_.reset(atomWindow);
|
||||
|
||||
AtomNSWindowDelegate* delegate =
|
||||
@@ -304,6 +332,10 @@ void NativeWindowMac::Restore() {
|
||||
[window_ deminiaturize:nil];
|
||||
}
|
||||
|
||||
bool NativeWindowMac::IsMinimized() {
|
||||
return [window_ isMiniaturized];
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetFullscreen(bool fullscreen) {
|
||||
if (fullscreen == IsFullscreen())
|
||||
return;
|
||||
@@ -488,7 +520,7 @@ gfx::NativeWindow NativeWindowMac::GetNativeWindow() {
|
||||
bool NativeWindowMac::IsWithinDraggableRegion(NSPoint point) const {
|
||||
if (!draggable_region_)
|
||||
return false;
|
||||
NSView* webView = GetWebContents()->GetView()->GetNativeView();
|
||||
NSView* webView = GetWebContents()->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
|
||||
@@ -553,8 +585,6 @@ void NativeWindowMac::InstallView() {
|
||||
base::scoped_nsobject<CALayer> layer([[CALayer alloc] init]);
|
||||
[layer setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)];
|
||||
[view setLayer:layer];
|
||||
[view setWantsLayer:YES];
|
||||
|
||||
[view setFrame:[[window_ contentView] bounds]];
|
||||
[[window_ contentView] addSubview:view];
|
||||
} else {
|
||||
@@ -577,9 +607,7 @@ void NativeWindowMac::UninstallView() {
|
||||
}
|
||||
|
||||
void NativeWindowMac::ClipWebView() {
|
||||
NSView* view = GetWebContents()->GetView()->GetNativeView();
|
||||
|
||||
view.wantsLayer = YES;
|
||||
NSView* view = GetWebContents()->GetNativeView();
|
||||
view.layer.masksToBounds = YES;
|
||||
view.layer.cornerRadius = kAtomWindowCornerRadius;
|
||||
}
|
||||
@@ -590,7 +618,7 @@ void NativeWindowMac::InstallDraggableRegionViews() {
|
||||
// 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 = GetWebContents()->GetView()->GetNativeView();
|
||||
NSView* webView = GetWebContents()->GetNativeView();
|
||||
NSInteger webViewHeight = NSHeight([webView bounds]);
|
||||
|
||||
// Remove all ControlRegionViews that are added last time.
|
||||
@@ -622,7 +650,7 @@ void NativeWindowMac::UpdateDraggableRegionsForCustomDrag(
|
||||
const std::vector<DraggableRegion>& regions) {
|
||||
// We still need one ControlRegionView to cover the whole window such that
|
||||
// mouse events could be captured.
|
||||
NSView* web_view = GetWebContents()->GetView()->GetNativeView();
|
||||
NSView* web_view = GetWebContents()->GetNativeView();
|
||||
gfx::Rect window_bounds(
|
||||
0, 0, NSWidth([web_view bounds]), NSHeight([web_view bounds]));
|
||||
system_drag_exclude_areas_.clear();
|
||||
|
||||
@@ -24,13 +24,10 @@
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "browser/inspectable_web_contents_view.h"
|
||||
#include "content/public/browser/native_web_keyboard_event.h"
|
||||
#include "content/public/browser/web_contents_view.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "ui/aura/window.h"
|
||||
#include "ui/aura/window_tree_host.h"
|
||||
#include "ui/base/hit_test.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
#include "ui/gfx/image/image_skia.h"
|
||||
#include "ui/views/background.h"
|
||||
#include "ui/views/controls/webview/unhandled_keyboard_event_handler.h"
|
||||
#include "ui/views/controls/webview/webview.h"
|
||||
@@ -40,11 +37,15 @@
|
||||
#if defined(USE_X11)
|
||||
#include "atom/browser/ui/views/global_menu_bar_x11.h"
|
||||
#include "atom/browser/ui/views/frameless_view.h"
|
||||
#include "base/environment.h"
|
||||
#include "base/nix/xdg_util.h"
|
||||
#include "chrome/browser/ui/libgtk2ui/unity_service.h"
|
||||
#include "ui/gfx/x/x11_types.h"
|
||||
#include "ui/views/window/native_frame_view.h"
|
||||
#elif defined(OS_WIN)
|
||||
#include "atom/browser/ui/views/win_frame_view.h"
|
||||
#include "base/win/scoped_comptr.h"
|
||||
#include "ui/base/win/shell.h"
|
||||
#endif
|
||||
|
||||
namespace atom {
|
||||
@@ -58,6 +59,32 @@ const int kMenuBarHeight = 20;
|
||||
const int kMenuBarHeight = 25;
|
||||
#endif
|
||||
|
||||
#if defined(USE_X11)
|
||||
bool ShouldUseGlobalMenuBar() {
|
||||
// Some DE would pretend to be Unity but don't have global application menu,
|
||||
// so we can not trust unity::IsRunning().
|
||||
scoped_ptr<base::Environment> env(base::Environment::Create());
|
||||
return unity::IsRunning() && (base::nix::GetDesktopEnvironment(env.get()) ==
|
||||
base::nix::DESKTOP_ENVIRONMENT_UNITY);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool IsAltKey(const content::NativeWebKeyboardEvent& event) {
|
||||
#if defined(USE_X11)
|
||||
// 164 and 165 represent VK_LALT and VK_RALT.
|
||||
return event.windowsKeyCode == 164 || event.windowsKeyCode == 165;
|
||||
#else
|
||||
return event.windowsKeyCode == ui::VKEY_MENU;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IsAltModifier(const content::NativeWebKeyboardEvent& event) {
|
||||
typedef content::NativeWebKeyboardEvent::Modifiers Modifiers;
|
||||
return (event.modifiers == Modifiers::AltKey) ||
|
||||
(event.modifiers == (Modifiers::AltKey | Modifiers::IsLeft)) ||
|
||||
(event.modifiers == (Modifiers::AltKey | Modifiers::IsRight));
|
||||
}
|
||||
|
||||
class NativeWindowClientView : public views::ClientView {
|
||||
public:
|
||||
NativeWindowClientView(views::Widget* widget,
|
||||
@@ -81,13 +108,23 @@ NativeWindowViews::NativeWindowViews(content::WebContents* web_contents,
|
||||
const mate::Dictionary& options)
|
||||
: NativeWindow(web_contents, options),
|
||||
window_(new views::Widget),
|
||||
menu_bar_(NULL),
|
||||
web_view_(inspectable_web_contents()->GetView()->GetView()),
|
||||
menu_bar_autohide_(false),
|
||||
menu_bar_visible_(false),
|
||||
menu_bar_alt_pressed_(false),
|
||||
keyboard_event_handler_(new views::UnhandledKeyboardEventHandler),
|
||||
use_content_size_(false),
|
||||
resizable_(true) {
|
||||
options.Get(switches::kResizable, &resizable_);
|
||||
options.Get(switches::kTitle, &title_);
|
||||
options.Get(switches::kAutoHideMenuBar, &menu_bar_autohide_);
|
||||
|
||||
if (enable_larger_than_screen_)
|
||||
// We need to set a default maximum window size here otherwise Windows
|
||||
// will not allow us to resize the window larger than scree.
|
||||
// Setting directly to INT_MAX somehow doesn't work, so we just devide
|
||||
// by 10, which should still be large enough.
|
||||
maximum_size_.SetSize(INT_MAX / 10, INT_MAX / 10);
|
||||
|
||||
int width = 800, height = 600;
|
||||
options.Get(switches::kWidth, &width);
|
||||
@@ -123,6 +160,7 @@ NativeWindowViews::NativeWindowViews(content::WebContents* web_contents,
|
||||
use_content_size_)
|
||||
bounds = ContentBoundsToWindowBounds(bounds);
|
||||
|
||||
window_->UpdateWindowIcon();
|
||||
window_->CenterWindow(bounds.size());
|
||||
Layout();
|
||||
}
|
||||
@@ -186,6 +224,10 @@ void NativeWindowViews::Restore() {
|
||||
window_->Restore();
|
||||
}
|
||||
|
||||
bool NativeWindowViews::IsMinimized() {
|
||||
return window_->IsMinimized();
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetFullscreen(bool fullscreen) {
|
||||
window_->SetFullscreen(fullscreen);
|
||||
}
|
||||
@@ -199,6 +241,11 @@ void NativeWindowViews::SetSize(const gfx::Size& size) {
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowViews::GetSize() {
|
||||
#if defined(OS_WIN)
|
||||
if (IsMinimized())
|
||||
return window_->GetRestoredBounds().size();
|
||||
#endif
|
||||
|
||||
return window_->GetWindowBoundsInScreen().size();
|
||||
}
|
||||
|
||||
@@ -219,7 +266,7 @@ gfx::Size NativeWindowViews::GetContentSize() {
|
||||
|
||||
gfx::Size content_size =
|
||||
window_->non_client_view()->frame_view()->GetBoundsForClientView().size();
|
||||
if (menu_bar_)
|
||||
if (menu_bar_ && menu_bar_visible_)
|
||||
content_size.set_height(content_size.height() - kMenuBarHeight);
|
||||
return content_size;
|
||||
}
|
||||
@@ -258,6 +305,21 @@ gfx::Size NativeWindowViews::GetMaximumSize() {
|
||||
|
||||
void NativeWindowViews::SetResizable(bool resizable) {
|
||||
resizable_ = resizable;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
if (has_frame_) {
|
||||
// WS_MAXIMIZEBOX => Maximize button
|
||||
// WS_MINIMIZEBOX => Minimize button
|
||||
// WS_THICKFRAME => Resize handle
|
||||
DWORD style = ::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE);
|
||||
if (resizable)
|
||||
style |= WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_THICKFRAME;
|
||||
else
|
||||
style = (style & ~(WS_MAXIMIZEBOX | WS_THICKFRAME)) | WS_MINIMIZEBOX;
|
||||
::SetWindowLong(GetAcceleratedWidget(), GWL_STYLE, style);
|
||||
}
|
||||
#endif
|
||||
|
||||
// FIXME Implement me for X11.
|
||||
}
|
||||
|
||||
@@ -282,6 +344,11 @@ void NativeWindowViews::SetPosition(const gfx::Point& position) {
|
||||
}
|
||||
|
||||
gfx::Point NativeWindowViews::GetPosition() {
|
||||
#if defined(OS_WIN)
|
||||
if (IsMinimized())
|
||||
return window_->GetRestoredBounds().origin();
|
||||
#endif
|
||||
|
||||
return window_->GetWindowBoundsInScreen().origin();
|
||||
}
|
||||
|
||||
@@ -324,11 +391,11 @@ void NativeWindowViews::SetMenu(ui::MenuModel* menu_model) {
|
||||
RegisterAccelerators(menu_model);
|
||||
|
||||
#if defined(USE_X11)
|
||||
if (!global_menu_bar_)
|
||||
if (!global_menu_bar_ && ShouldUseGlobalMenuBar())
|
||||
global_menu_bar_.reset(new GlobalMenuBarX11(this));
|
||||
|
||||
// Use global application menu bar when possible.
|
||||
if (global_menu_bar_->IsServerStarted()) {
|
||||
if (global_menu_bar_ && global_menu_bar_->IsServerStarted()) {
|
||||
global_menu_bar_->SetMenu(menu_model);
|
||||
return;
|
||||
}
|
||||
@@ -340,11 +407,14 @@ void NativeWindowViews::SetMenu(ui::MenuModel* menu_model) {
|
||||
|
||||
if (!menu_bar_) {
|
||||
gfx::Size content_size = GetContentSize();
|
||||
menu_bar_ = new MenuBar;
|
||||
AddChildViewAt(menu_bar_, 0);
|
||||
menu_bar_.reset(new MenuBar);
|
||||
menu_bar_->set_owned_by_client();
|
||||
|
||||
if (use_content_size_)
|
||||
SetContentSize(content_size);
|
||||
if (!menu_bar_autohide_) {
|
||||
SetMenuBarVisibility(true);
|
||||
if (use_content_size_)
|
||||
SetContentSize(content_size);
|
||||
}
|
||||
}
|
||||
|
||||
menu_bar_->SetMenu(menu_model);
|
||||
@@ -391,6 +461,15 @@ void NativeWindowViews::OnWidgetActivationChanged(
|
||||
NotifyWindowFocus();
|
||||
else
|
||||
NotifyWindowBlur();
|
||||
|
||||
if (active && GetWebContents() && !IsDevToolsOpened())
|
||||
GetWebContents()->Focus();
|
||||
|
||||
// Hide menu bar when window is blured.
|
||||
if (!active && menu_bar_autohide_ && menu_bar_visible_) {
|
||||
SetMenuBarVisibility(false);
|
||||
Layout();
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowViews::DeleteDelegate() {
|
||||
@@ -418,10 +497,7 @@ bool NativeWindowViews::ShouldHandleSystemCommands() const {
|
||||
}
|
||||
|
||||
gfx::ImageSkia NativeWindowViews::GetWindowAppIcon() {
|
||||
if (icon_)
|
||||
return *(icon_->ToImageSkia());
|
||||
else
|
||||
return gfx::ImageSkia();
|
||||
return icon_;
|
||||
}
|
||||
|
||||
gfx::ImageSkia NativeWindowViews::GetWindowIcon() {
|
||||
@@ -465,9 +541,11 @@ views::ClientView* NativeWindowViews::CreateClientView(views::Widget* widget) {
|
||||
views::NonClientFrameView* NativeWindowViews::CreateNonClientFrameView(
|
||||
views::Widget* widget) {
|
||||
#if defined(OS_WIN)
|
||||
WinFrameView* frame_view = new WinFrameView;
|
||||
frame_view->Init(this, widget);
|
||||
return frame_view;
|
||||
if (ui::win::IsAeroGlassEnabled()) {
|
||||
WinFrameView* frame_view = new WinFrameView;
|
||||
frame_view->Init(this, widget);
|
||||
return frame_view;
|
||||
}
|
||||
#elif defined(OS_LINUX)
|
||||
if (has_frame_) {
|
||||
return new views::NativeFrameView(widget);
|
||||
@@ -476,15 +554,62 @@ views::NonClientFrameView* NativeWindowViews::CreateNonClientFrameView(
|
||||
frame_view->Init(this, widget);
|
||||
return frame_view;
|
||||
}
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void NativeWindowViews::HandleMouseDown() {
|
||||
// Hide menu bar when web view is clicked.
|
||||
if (menu_bar_autohide_ && menu_bar_visible_) {
|
||||
SetMenuBarVisibility(false);
|
||||
Layout();
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowViews::HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent& event) {
|
||||
keyboard_event_handler_->HandleKeyboardEvent(event, GetFocusManager());
|
||||
|
||||
if (!menu_bar_)
|
||||
return;
|
||||
|
||||
// Show accelerator when "Alt" is pressed.
|
||||
if (menu_bar_visible_ && IsAltKey(event))
|
||||
menu_bar_->SetAcceleratorVisibility(
|
||||
event.type == blink::WebInputEvent::RawKeyDown);
|
||||
|
||||
// Show the submenu when "Alt+Key" is pressed.
|
||||
if (event.type == blink::WebInputEvent::RawKeyDown && !IsAltKey(event) &&
|
||||
IsAltModifier(event)) {
|
||||
if (!menu_bar_visible_ &&
|
||||
(menu_bar_->GetAcceleratorIndex(event.windowsKeyCode) != -1)) {
|
||||
SetMenuBarVisibility(true);
|
||||
Layout();
|
||||
}
|
||||
menu_bar_->ActivateAccelerator(event.windowsKeyCode);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!menu_bar_autohide_)
|
||||
return;
|
||||
|
||||
// Toggle the menu bar only when a single Alt is released.
|
||||
if (event.type == blink::WebInputEvent::RawKeyDown && IsAltKey(event) &&
|
||||
IsAltModifier(event)) {
|
||||
// When a single Alt is pressed:
|
||||
menu_bar_alt_pressed_ = true;
|
||||
} else if (event.type == blink::WebInputEvent::KeyUp && IsAltKey(event) &&
|
||||
event.modifiers == 0 && menu_bar_alt_pressed_) {
|
||||
// When a single Alt is released right after a Alt is pressed:
|
||||
menu_bar_alt_pressed_ = false;
|
||||
SetMenuBarVisibility(!menu_bar_visible_);
|
||||
Layout();
|
||||
} else {
|
||||
// When any other keys except single Alt have been pressed/released:
|
||||
menu_bar_alt_pressed_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool NativeWindowViews::AcceleratorPressed(const ui::Accelerator& accelerator) {
|
||||
@@ -513,11 +638,29 @@ gfx::Rect NativeWindowViews::ContentBoundsToWindowBounds(
|
||||
const gfx::Rect& bounds) {
|
||||
gfx::Rect window_bounds =
|
||||
window_->non_client_view()->GetWindowBoundsForClientBounds(bounds);
|
||||
if (menu_bar_)
|
||||
if (menu_bar_ && menu_bar_visible_)
|
||||
window_bounds.set_height(window_bounds.height() + kMenuBarHeight);
|
||||
return window_bounds;
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetMenuBarVisibility(bool visible) {
|
||||
if (!menu_bar_)
|
||||
return;
|
||||
|
||||
// Always show the accelerator when the auto-hide menu bar shows.
|
||||
if (menu_bar_autohide_)
|
||||
menu_bar_->SetAcceleratorVisibility(visible);
|
||||
|
||||
menu_bar_visible_ = visible;
|
||||
if (visible) {
|
||||
DCHECK_EQ(child_count(), 1);
|
||||
AddChildView(menu_bar_.get());
|
||||
} else {
|
||||
DCHECK_EQ(child_count(), 2);
|
||||
RemoveChildView(menu_bar_.get());
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
NativeWindow* NativeWindow::Create(content::WebContents* web_contents,
|
||||
const mate::Dictionary& options) {
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
namespace views {
|
||||
class UnhandledKeyboardEventHandler;
|
||||
class Widget;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
@@ -46,6 +45,7 @@ class NativeWindowViews : public NativeWindow,
|
||||
virtual bool IsMaximized() OVERRIDE;
|
||||
virtual void Minimize() OVERRIDE;
|
||||
virtual void Restore() OVERRIDE;
|
||||
virtual bool IsMinimized() OVERRIDE;
|
||||
virtual void SetFullscreen(bool fullscreen) OVERRIDE;
|
||||
virtual bool IsFullscreen() OVERRIDE;
|
||||
virtual void SetSize(const gfx::Size& size) OVERRIDE;
|
||||
@@ -106,6 +106,7 @@ class NativeWindowViews : public NativeWindow,
|
||||
views::Widget* widget) OVERRIDE;
|
||||
|
||||
// content::WebContentsDelegate:
|
||||
virtual void HandleMouseDown() OVERRIDE;
|
||||
virtual void HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent& event) OVERRIDE;
|
||||
@@ -120,10 +121,17 @@ class NativeWindowViews : public NativeWindow,
|
||||
// in client area we need to substract/add menu bar's height in convertions.
|
||||
gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& content_bounds);
|
||||
|
||||
// Show/Hide the menu bar.
|
||||
void SetMenuBarVisibility(bool visible);
|
||||
|
||||
scoped_ptr<views::Widget> window_;
|
||||
MenuBar* menu_bar_;
|
||||
views::View* web_view_; // Managed by inspectable_web_contents_.
|
||||
|
||||
scoped_ptr<MenuBar> menu_bar_;
|
||||
bool menu_bar_autohide_;
|
||||
bool menu_bar_visible_;
|
||||
bool menu_bar_alt_pressed_;
|
||||
|
||||
#if defined(USE_X11)
|
||||
scoped_ptr<GlobalMenuBarX11> global_menu_bar_;
|
||||
#endif
|
||||
|
||||
@@ -1,186 +0,0 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/net/atom_url_request_context_getter.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "atom/browser/net/atom_url_request_job_factory.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/threading/sequenced_worker_pool.h"
|
||||
#include "base/threading/worker_pool.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/cookie_store_factory.h"
|
||||
#include "content/public/common/url_constants.h"
|
||||
#include "net/cert/cert_verifier.h"
|
||||
#include "net/cookies/cookie_monster.h"
|
||||
#include "net/http/http_auth_handler_factory.h"
|
||||
#include "net/http/http_cache.h"
|
||||
#include "net/http/http_server_properties_impl.h"
|
||||
#include "net/proxy/dhcp_proxy_script_fetcher_factory.h"
|
||||
#include "net/proxy/proxy_config_service.h"
|
||||
#include "net/proxy/proxy_script_fetcher_impl.h"
|
||||
#include "net/proxy/proxy_service.h"
|
||||
#include "net/proxy/proxy_service_v8.h"
|
||||
#include "net/ssl/default_server_bound_cert_store.h"
|
||||
#include "net/ssl/server_bound_cert_service.h"
|
||||
#include "net/ssl/ssl_config_service_defaults.h"
|
||||
#include "net/url_request/data_protocol_handler.h"
|
||||
#include "net/url_request/file_protocol_handler.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_storage.h"
|
||||
#include "vendor/brightray/browser/network_delegate.h"
|
||||
#include "webkit/browser/quota/special_storage_policy.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
using content::BrowserThread;
|
||||
|
||||
AtomURLRequestContextGetter::AtomURLRequestContextGetter(
|
||||
const base::FilePath& base_path,
|
||||
base::MessageLoop* io_loop,
|
||||
base::MessageLoop* file_loop,
|
||||
base::Callback<scoped_ptr<brightray::NetworkDelegate>(void)> factory,
|
||||
content::ProtocolHandlerMap* protocol_handlers)
|
||||
: base_path_(base_path),
|
||||
io_loop_(io_loop),
|
||||
file_loop_(file_loop),
|
||||
job_factory_(NULL),
|
||||
network_delegate_factory_(factory) {
|
||||
// Must first be created on the UI thread.
|
||||
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||
|
||||
std::swap(protocol_handlers_, *protocol_handlers);
|
||||
|
||||
// We must create the proxy config service on the UI loop on Linux because it
|
||||
// must synchronously run on the glib message loop. This will be passed to
|
||||
// the URLRequestContextStorage on the IO thread in GetURLRequestContext().
|
||||
proxy_config_service_.reset(
|
||||
net::ProxyService::CreateSystemProxyConfigService(
|
||||
io_loop_->message_loop_proxy(),
|
||||
file_loop_));
|
||||
}
|
||||
|
||||
AtomURLRequestContextGetter::~AtomURLRequestContextGetter() {
|
||||
}
|
||||
|
||||
net::URLRequestContext* AtomURLRequestContextGetter::GetURLRequestContext() {
|
||||
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
||||
|
||||
base::AutoLock auto_lock(lock_);
|
||||
if (!url_request_context_.get()) {
|
||||
url_request_context_.reset(new net::URLRequestContext());
|
||||
network_delegate_ = network_delegate_factory_.Run().Pass();
|
||||
url_request_context_->set_network_delegate(network_delegate_.get());
|
||||
storage_.reset(
|
||||
new net::URLRequestContextStorage(url_request_context_.get()));
|
||||
auto cookie_config = content::CookieStoreConfig(
|
||||
base_path_.Append(FILE_PATH_LITERAL("Cookies")),
|
||||
content::CookieStoreConfig::EPHEMERAL_SESSION_COOKIES,
|
||||
nullptr,
|
||||
nullptr);
|
||||
storage_->set_cookie_store(content::CreateCookieStore(cookie_config));
|
||||
storage_->set_server_bound_cert_service(new net::ServerBoundCertService(
|
||||
new net::DefaultServerBoundCertStore(NULL),
|
||||
base::WorkerPool::GetTaskRunner(true)));
|
||||
storage_->set_http_user_agent_settings(
|
||||
new net::StaticHttpUserAgentSettings(
|
||||
"en-us,en", base::EmptyString()));
|
||||
|
||||
scoped_ptr<net::HostResolver> host_resolver(
|
||||
net::HostResolver::CreateDefaultResolver(NULL));
|
||||
net::DhcpProxyScriptFetcherFactory dhcp_factory;
|
||||
|
||||
storage_->set_cert_verifier(net::CertVerifier::CreateDefault());
|
||||
storage_->set_transport_security_state(new net::TransportSecurityState);
|
||||
storage_->set_proxy_service(
|
||||
net::CreateProxyServiceUsingV8ProxyResolver(
|
||||
proxy_config_service_.release(),
|
||||
new net::ProxyScriptFetcherImpl(url_request_context_.get()),
|
||||
dhcp_factory.Create(url_request_context_.get()),
|
||||
host_resolver.get(),
|
||||
NULL,
|
||||
url_request_context_->network_delegate()));
|
||||
storage_->set_ssl_config_service(new net::SSLConfigServiceDefaults);
|
||||
storage_->set_http_auth_handler_factory(
|
||||
net::HttpAuthHandlerFactory::CreateDefault(host_resolver.get()));
|
||||
scoped_ptr<net::HttpServerProperties> server_properties(
|
||||
new net::HttpServerPropertiesImpl);
|
||||
storage_->set_http_server_properties(server_properties.Pass());
|
||||
|
||||
base::FilePath cache_path = base_path_.Append(FILE_PATH_LITERAL("Cache"));
|
||||
net::HttpCache::DefaultBackend* main_backend =
|
||||
new net::HttpCache::DefaultBackend(
|
||||
net::DISK_CACHE,
|
||||
net::CACHE_BACKEND_DEFAULT,
|
||||
cache_path,
|
||||
0,
|
||||
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE));
|
||||
|
||||
net::HttpNetworkSession::Params network_session_params;
|
||||
network_session_params.cert_verifier =
|
||||
url_request_context_->cert_verifier();
|
||||
network_session_params.transport_security_state =
|
||||
url_request_context_->transport_security_state();
|
||||
network_session_params.server_bound_cert_service =
|
||||
url_request_context_->server_bound_cert_service();
|
||||
network_session_params.proxy_service =
|
||||
url_request_context_->proxy_service();
|
||||
network_session_params.ssl_config_service =
|
||||
url_request_context_->ssl_config_service();
|
||||
network_session_params.http_auth_handler_factory =
|
||||
url_request_context_->http_auth_handler_factory();
|
||||
network_session_params.network_delegate =
|
||||
url_request_context_->network_delegate();
|
||||
network_session_params.http_server_properties =
|
||||
url_request_context_->http_server_properties();
|
||||
network_session_params.ignore_certificate_errors = false;
|
||||
|
||||
// Give |storage_| ownership at the end in case it's |mapped_host_resolver|.
|
||||
storage_->set_host_resolver(host_resolver.Pass());
|
||||
network_session_params.host_resolver =
|
||||
url_request_context_->host_resolver();
|
||||
|
||||
net::HttpCache* main_cache = new net::HttpCache(
|
||||
network_session_params, main_backend);
|
||||
storage_->set_http_transaction_factory(main_cache);
|
||||
|
||||
DCHECK(!job_factory_);
|
||||
job_factory_ = new AtomURLRequestJobFactory;
|
||||
for (content::ProtocolHandlerMap::iterator it = protocol_handlers_.begin();
|
||||
it != protocol_handlers_.end();
|
||||
++it) {
|
||||
bool set_protocol = job_factory_->SetProtocolHandler(
|
||||
it->first,
|
||||
it->second.release());
|
||||
DCHECK(set_protocol);
|
||||
}
|
||||
protocol_handlers_.clear();
|
||||
|
||||
scoped_ptr<net::FileProtocolHandler> file_protocol_handler(
|
||||
new net::FileProtocolHandler(
|
||||
content::BrowserThread::GetBlockingPool()->
|
||||
GetTaskRunnerWithShutdownBehavior(
|
||||
base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)));
|
||||
job_factory_->SetProtocolHandler(content::kDataScheme,
|
||||
new net::DataProtocolHandler);
|
||||
job_factory_->SetProtocolHandler(content::kFileScheme,
|
||||
file_protocol_handler.release());
|
||||
storage_->set_job_factory(job_factory_);
|
||||
}
|
||||
|
||||
return url_request_context_.get();
|
||||
}
|
||||
|
||||
scoped_refptr<base::SingleThreadTaskRunner>
|
||||
AtomURLRequestContextGetter::GetNetworkTaskRunner() const {
|
||||
return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
|
||||
}
|
||||
|
||||
net::HostResolver* AtomURLRequestContextGetter::host_resolver() {
|
||||
return url_request_context_->host_resolver();
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
@@ -1,76 +0,0 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_NET_ATOM_URL_REQUEST_CONTEXT_GETTER_H_
|
||||
#define ATOM_BROWSER_NET_ATOM_URL_REQUEST_CONTEXT_GETTER_H_
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/synchronization/lock.h"
|
||||
#include "content/public/browser/content_browser_client.h"
|
||||
#include "net/url_request/url_request_context_getter.h"
|
||||
|
||||
namespace base {
|
||||
class MessageLoop;
|
||||
}
|
||||
|
||||
namespace brightray {
|
||||
class NetworkDelegate;
|
||||
}
|
||||
|
||||
namespace net {
|
||||
class HostResolver;
|
||||
class ProxyConfigService;
|
||||
class URLRequestContextStorage;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomURLRequestJobFactory;
|
||||
|
||||
class AtomURLRequestContextGetter : public net::URLRequestContextGetter {
|
||||
public:
|
||||
AtomURLRequestContextGetter(
|
||||
const base::FilePath& base_path,
|
||||
base::MessageLoop* io_loop,
|
||||
base::MessageLoop* file_loop,
|
||||
base::Callback<scoped_ptr<brightray::NetworkDelegate>(void)>,
|
||||
content::ProtocolHandlerMap* protocol_handlers);
|
||||
|
||||
// net::URLRequestContextGetter implementations:
|
||||
virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE;
|
||||
virtual scoped_refptr<base::SingleThreadTaskRunner>
|
||||
GetNetworkTaskRunner() const OVERRIDE;
|
||||
|
||||
net::HostResolver* host_resolver();
|
||||
net::URLRequestContextStorage* storage() const { return storage_.get(); }
|
||||
AtomURLRequestJobFactory* job_factory() const { return job_factory_; }
|
||||
|
||||
protected:
|
||||
virtual ~AtomURLRequestContextGetter();
|
||||
|
||||
private:
|
||||
base::FilePath base_path_;
|
||||
base::MessageLoop* io_loop_;
|
||||
base::MessageLoop* file_loop_;
|
||||
|
||||
AtomURLRequestJobFactory* job_factory_;
|
||||
base::Callback<scoped_ptr<brightray::NetworkDelegate>(void)>
|
||||
network_delegate_factory_;
|
||||
|
||||
base::Lock lock_;
|
||||
|
||||
scoped_ptr<net::ProxyConfigService> proxy_config_service_;
|
||||
scoped_ptr<brightray::NetworkDelegate> network_delegate_;
|
||||
scoped_ptr<net::URLRequestContextStorage> storage_;
|
||||
scoped_ptr<net::URLRequestContext> url_request_context_;
|
||||
content::ProtocolHandlerMap protocol_handlers_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomURLRequestContextGetter);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_NET_ATOM_URL_REQUEST_CONTEXT_GETTER_H_
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>atom.icns</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.14.2</string>
|
||||
<string>0.15.8</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.8.0</string>
|
||||
<key>NSMainNibFile</key>
|
||||
|
||||
@@ -50,8 +50,8 @@ END
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 0,14,2,0
|
||||
PRODUCTVERSION 0,14,2,0
|
||||
FILEVERSION 0,15,8,0
|
||||
PRODUCTVERSION 0,15,8,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -68,12 +68,12 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "GitHub, Inc."
|
||||
VALUE "FileDescription", "Atom-Shell"
|
||||
VALUE "FileVersion", "0.14.2"
|
||||
VALUE "FileVersion", "0.15.8"
|
||||
VALUE "InternalName", "atom.exe"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2013 GitHub, Inc. All rights reserved."
|
||||
VALUE "OriginalFilename", "atom.exe"
|
||||
VALUE "ProductName", "Atom-Shell"
|
||||
VALUE "ProductVersion", "0.14.2"
|
||||
VALUE "ProductVersion", "0.15.8"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -87,7 +87,7 @@ ui::KeyboardCode KeyboardCodeFromCharCode(char c, bool* shifted) {
|
||||
|
||||
bool StringToAccelerator(const std::string& description,
|
||||
ui::Accelerator* accelerator) {
|
||||
if (!IsStringASCII(description)) {
|
||||
if (!base::IsStringASCII(description)) {
|
||||
LOG(ERROR) << "The accelerator string can only contain ASCII characters";
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#define ATOM_BROWSER_UI_FILE_DIALOG_H_
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/callback_forward.h"
|
||||
@@ -17,11 +18,15 @@ class NativeWindow;
|
||||
|
||||
namespace file_dialog {
|
||||
|
||||
// <description, extensions>
|
||||
typedef std::pair<std::string, std::vector<std::string> > Filter;
|
||||
typedef std::vector<Filter> Filters;
|
||||
|
||||
enum FileDialogProperty {
|
||||
FILE_DIALOG_OPEN_FILE = 1,
|
||||
FILE_DIALOG_OPEN_DIRECTORY = 2,
|
||||
FILE_DIALOG_MULTI_SELECTIONS = 4,
|
||||
FILE_DIALOG_CREATE_DIRECTORY = 8,
|
||||
FILE_DIALOG_OPEN_FILE = 1 << 0,
|
||||
FILE_DIALOG_OPEN_DIRECTORY = 1 << 1,
|
||||
FILE_DIALOG_MULTI_SELECTIONS = 1 << 2,
|
||||
FILE_DIALOG_CREATE_DIRECTORY = 1 << 3,
|
||||
};
|
||||
|
||||
typedef base::Callback<void(
|
||||
@@ -33,23 +38,27 @@ typedef base::Callback<void(
|
||||
bool ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
int properties,
|
||||
std::vector<base::FilePath>* paths);
|
||||
|
||||
void ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
int properties,
|
||||
const OpenDialogCallback& callback);
|
||||
|
||||
bool ShowSaveDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
base::FilePath* path);
|
||||
|
||||
void ShowSaveDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
const SaveDialogCallback& callback);
|
||||
|
||||
} // namespace file_dialog
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/file_util.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "chrome/browser/ui/libgtk2ui/gtk2_signal.h"
|
||||
#include "ui/aura/window.h"
|
||||
#include "ui/aura/window_tree_host.h"
|
||||
@@ -45,12 +46,24 @@ void SetGtkTransientForAura(GtkWidget* dialog, aura::Window* parent) {
|
||||
g_object_set_data(G_OBJECT(dialog), kAuraTransientParent, parent);
|
||||
}
|
||||
|
||||
// Makes sure that .jpg also shows .JPG.
|
||||
gboolean FileFilterCaseInsensitive(const GtkFileFilterInfo* file_info,
|
||||
std::string* file_extension) {
|
||||
return EndsWith(file_info->filename, *file_extension, false);
|
||||
}
|
||||
|
||||
// Deletes |data| when gtk_file_filter_add_custom() is done with it.
|
||||
void OnFileFilterDataDestroyed(std::string* file_extension) {
|
||||
delete file_extension;
|
||||
}
|
||||
|
||||
class FileChooserDialog {
|
||||
public:
|
||||
FileChooserDialog(GtkFileChooserAction action,
|
||||
atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path)
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters)
|
||||
: dialog_scope_(new atom::NativeWindow::DialogScope(parent_window)) {
|
||||
const char* confirm_text = GTK_STOCK_OK;
|
||||
if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
|
||||
@@ -86,6 +99,9 @@ class FileChooserDialog {
|
||||
gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog_),
|
||||
default_path.value().c_str());
|
||||
}
|
||||
|
||||
if (!filters.empty())
|
||||
AddFilters(filters);
|
||||
}
|
||||
|
||||
virtual ~FileChooserDialog() {
|
||||
@@ -135,6 +151,8 @@ class FileChooserDialog {
|
||||
GtkWidget* dialog() const { return dialog_; }
|
||||
|
||||
private:
|
||||
void AddFilters(const Filters& filters);
|
||||
|
||||
GtkWidget* dialog_;
|
||||
|
||||
SaveDialogCallback save_callback_;
|
||||
@@ -162,17 +180,40 @@ void FileChooserDialog::OnFileDialogResponse(GtkWidget* widget, int response) {
|
||||
delete this;
|
||||
}
|
||||
|
||||
void FileChooserDialog::AddFilters(const Filters& filters) {
|
||||
for (size_t i = 0; i < filters.size(); ++i) {
|
||||
const Filter& filter = filters[i];
|
||||
GtkFileFilter* gtk_filter = gtk_file_filter_new();
|
||||
|
||||
for (size_t j = 0; j < filter.second.size(); ++j) {
|
||||
scoped_ptr<std::string> file_extension(
|
||||
new std::string("." + filter.second[j]));
|
||||
gtk_file_filter_add_custom(
|
||||
gtk_filter,
|
||||
GTK_FILE_FILTER_FILENAME,
|
||||
reinterpret_cast<GtkFileFilterFunc>(FileFilterCaseInsensitive),
|
||||
file_extension.release(),
|
||||
reinterpret_cast<GDestroyNotify>(OnFileFilterDataDestroyed));
|
||||
}
|
||||
|
||||
gtk_file_filter_set_name(gtk_filter, filter.first.c_str());
|
||||
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog_), gtk_filter);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
int properties,
|
||||
std::vector<base::FilePath>* paths) {
|
||||
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
|
||||
if (properties & FILE_DIALOG_OPEN_DIRECTORY)
|
||||
action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
|
||||
FileChooserDialog open_dialog(action, parent_window, title, default_path);
|
||||
FileChooserDialog open_dialog(action, parent_window, title, default_path,
|
||||
filters);
|
||||
if (properties & FILE_DIALOG_MULTI_SELECTIONS)
|
||||
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(open_dialog.dialog()),
|
||||
TRUE);
|
||||
@@ -190,13 +231,14 @@ bool ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
void ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
int properties,
|
||||
const OpenDialogCallback& callback) {
|
||||
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
|
||||
if (properties & FILE_DIALOG_OPEN_DIRECTORY)
|
||||
action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
|
||||
FileChooserDialog* open_dialog = new FileChooserDialog(
|
||||
action, parent_window, title, default_path);
|
||||
action, parent_window, title, default_path, filters);
|
||||
if (properties & FILE_DIALOG_MULTI_SELECTIONS)
|
||||
gtk_file_chooser_set_select_multiple(
|
||||
GTK_FILE_CHOOSER(open_dialog->dialog()), TRUE);
|
||||
@@ -207,9 +249,10 @@ void ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
bool ShowSaveDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
base::FilePath* path) {
|
||||
FileChooserDialog save_dialog(
|
||||
GTK_FILE_CHOOSER_ACTION_SAVE, parent_window, title, default_path);
|
||||
FileChooserDialog save_dialog(GTK_FILE_CHOOSER_ACTION_SAVE, parent_window,
|
||||
title, default_path, filters);
|
||||
gtk_widget_show_all(save_dialog.dialog());
|
||||
int response = gtk_dialog_run(GTK_DIALOG(save_dialog.dialog()));
|
||||
if (response == GTK_RESPONSE_ACCEPT) {
|
||||
@@ -223,9 +266,11 @@ bool ShowSaveDialog(atom::NativeWindow* parent_window,
|
||||
void ShowSaveDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
const SaveDialogCallback& callback) {
|
||||
FileChooserDialog* save_dialog = new FileChooserDialog(
|
||||
GTK_FILE_CHOOSER_ACTION_SAVE, parent_window, title, default_path);
|
||||
GTK_FILE_CHOOSER_ACTION_SAVE, parent_window, title, default_path,
|
||||
filters);
|
||||
save_dialog->RunSaveAsynchronous(callback);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,15 +9,45 @@
|
||||
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "base/file_util.h"
|
||||
#include "base/mac/mac_util.h"
|
||||
#include "base/mac/scoped_cftyperef.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
|
||||
namespace file_dialog {
|
||||
|
||||
namespace {
|
||||
|
||||
CFStringRef CreateUTIFromExtension(const std::string& ext) {
|
||||
base::ScopedCFTypeRef<CFStringRef> ext_cf(base::SysUTF8ToCFStringRef(ext));
|
||||
return UTTypeCreatePreferredIdentifierForTag(
|
||||
kUTTagClassFilenameExtension, ext_cf.get(), NULL);
|
||||
}
|
||||
|
||||
void SetAllowedFileTypes(NSSavePanel* dialog, const Filters& filters) {
|
||||
NSMutableSet* file_type_set = [NSMutableSet set];
|
||||
for (size_t i = 0; i < filters.size(); ++i) {
|
||||
const Filter& filter = filters[i];
|
||||
for (size_t j = 0; j < filter.second.size(); ++j) {
|
||||
base::ScopedCFTypeRef<CFStringRef> uti(
|
||||
CreateUTIFromExtension(filter.second[j]));
|
||||
[file_type_set addObject:base::mac::CFToNSCast(uti.get())];
|
||||
|
||||
// Always allow the extension itself, in case the UTI doesn't map
|
||||
// back to the original extension correctly. This occurs with dynamic
|
||||
// UTIs on 10.7 and 10.8.
|
||||
// See http://crbug.com/148840, http://openradar.me/12316273
|
||||
base::ScopedCFTypeRef<CFStringRef> ext_cf(
|
||||
base::SysUTF8ToCFStringRef(filter.second[j]));
|
||||
[file_type_set addObject:base::mac::CFToNSCast(ext_cf.get())];
|
||||
}
|
||||
}
|
||||
[dialog setAllowedFileTypes:[file_type_set allObjects]];
|
||||
}
|
||||
|
||||
void SetupDialog(NSSavePanel* dialog,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path) {
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters) {
|
||||
if (!title.empty())
|
||||
[dialog setTitle:base::SysUTF8ToNSString(title)];
|
||||
|
||||
@@ -39,7 +69,10 @@ void SetupDialog(NSSavePanel* dialog,
|
||||
[dialog setNameFieldStringValue:default_filename];
|
||||
|
||||
[dialog setCanSelectHiddenExtension:YES];
|
||||
[dialog setAllowsOtherFileTypes:YES];
|
||||
if (filters.empty())
|
||||
[dialog setAllowsOtherFileTypes:YES];
|
||||
else
|
||||
SetAllowedFileTypes(dialog, filters);
|
||||
}
|
||||
|
||||
void SetupDialogForProperties(NSOpenPanel* dialog, int properties) {
|
||||
@@ -55,7 +88,7 @@ void SetupDialogForProperties(NSOpenPanel* dialog, int properties) {
|
||||
// Run modal dialog with parent window and return user's choice.
|
||||
int RunModalDialog(NSSavePanel* dialog, atom::NativeWindow* parent_window) {
|
||||
__block int chosen = NSFileHandlingPanelCancelButton;
|
||||
if (parent_window == NULL) {
|
||||
if (!parent_window || !parent_window->GetNativeWindow()) {
|
||||
chosen = [dialog runModal];
|
||||
} else {
|
||||
NSWindow* window = parent_window->GetNativeWindow();
|
||||
@@ -83,12 +116,13 @@ void ReadDialogPaths(NSOpenPanel* dialog, std::vector<base::FilePath>* paths) {
|
||||
bool ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
int properties,
|
||||
std::vector<base::FilePath>* paths) {
|
||||
DCHECK(paths);
|
||||
NSOpenPanel* dialog = [NSOpenPanel openPanel];
|
||||
|
||||
SetupDialog(dialog, title, default_path);
|
||||
SetupDialog(dialog, title, default_path, filters);
|
||||
SetupDialogForProperties(dialog, properties);
|
||||
|
||||
int chosen = RunModalDialog(dialog, parent_window);
|
||||
@@ -102,11 +136,12 @@ bool ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
void ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
int properties,
|
||||
const OpenDialogCallback& c) {
|
||||
NSOpenPanel* dialog = [NSOpenPanel openPanel];
|
||||
|
||||
SetupDialog(dialog, title, default_path);
|
||||
SetupDialog(dialog, title, default_path, filters);
|
||||
SetupDialogForProperties(dialog, properties);
|
||||
|
||||
// Duplicate the callback object here since c is a reference and gcd would
|
||||
@@ -129,11 +164,12 @@ void ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
bool ShowSaveDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
base::FilePath* path) {
|
||||
DCHECK(path);
|
||||
NSSavePanel* dialog = [NSSavePanel savePanel];
|
||||
|
||||
SetupDialog(dialog, title, default_path);
|
||||
SetupDialog(dialog, title, default_path, filters);
|
||||
|
||||
int chosen = RunModalDialog(dialog, parent_window);
|
||||
if (chosen == NSFileHandlingPanelCancelButton || ![[dialog URL] isFileURL])
|
||||
@@ -146,10 +182,11 @@ bool ShowSaveDialog(atom::NativeWindow* parent_window,
|
||||
void ShowSaveDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
const SaveDialogCallback& c) {
|
||||
NSSavePanel* dialog = [NSSavePanel savePanel];
|
||||
|
||||
SetupDialog(dialog, title, default_path);
|
||||
SetupDialog(dialog, title, default_path, filters);
|
||||
|
||||
__block SaveDialogCallback callback = c;
|
||||
|
||||
|
||||
@@ -30,103 +30,30 @@ bool IsDirectory(const base::FilePath& path) {
|
||||
file_info.is_directory : path.EndsWithSeparator();
|
||||
}
|
||||
|
||||
// Get the file type description from the registry. This will be "Text Document"
|
||||
// for .txt files, "JPEG Image" for .jpg files, etc. If the registry doesn't
|
||||
// have an entry for the file type, we return false, true if the description was
|
||||
// found. 'file_ext' must be in form ".txt".
|
||||
static bool GetRegistryDescriptionFromExtension(const std::wstring& file_ext,
|
||||
std::wstring* reg_description) {
|
||||
DCHECK(reg_description);
|
||||
base::win::RegKey reg_ext(HKEY_CLASSES_ROOT, file_ext.c_str(), KEY_READ);
|
||||
std::wstring reg_app;
|
||||
if (reg_ext.ReadValue(NULL, ®_app) == ERROR_SUCCESS && !reg_app.empty()) {
|
||||
base::win::RegKey reg_link(HKEY_CLASSES_ROOT, reg_app.c_str(), KEY_READ);
|
||||
if (reg_link.ReadValue(NULL, reg_description) == ERROR_SUCCESS)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set up a filter for a Save/Open dialog, which will consist of |file_ext| file
|
||||
// extensions (internally separated by semicolons), |ext_desc| as the text
|
||||
// descriptions of the |file_ext| types (optional), and (optionally) the default
|
||||
// 'All Files' view. The purpose of the filter is to show only files of a
|
||||
// particular type in a Windows Save/Open dialog box. The resulting filter is
|
||||
// returned. The filters created here are:
|
||||
// 1. only files that have 'file_ext' as their extension
|
||||
// 2. all files (only added if 'include_all_files' is true)
|
||||
// Example:
|
||||
// file_ext: { "*.txt", "*.htm;*.html" }
|
||||
// ext_desc: { "Text Document" }
|
||||
// returned: "Text Document\0*.txt\0HTML Document\0*.htm;*.html\0"
|
||||
// "All Files\0*.*\0\0" (in one big string)
|
||||
// If a description is not provided for a file extension, it will be retrieved
|
||||
// from the registry. If the file extension does not exist in the registry, it
|
||||
// will be omitted from the filter, as it is likely a bogus extension.
|
||||
void FormatFilterForExtensions(
|
||||
std::vector<std::wstring>* file_ext,
|
||||
std::vector<std::wstring>* ext_desc,
|
||||
bool include_all_files,
|
||||
std::vector<COMDLG_FILTERSPEC>* file_types) {
|
||||
DCHECK(file_ext->size() >= ext_desc->size());
|
||||
|
||||
if (file_ext->empty())
|
||||
include_all_files = true;
|
||||
|
||||
for (size_t i = 0; i < file_ext->size(); ++i) {
|
||||
std::wstring ext = (*file_ext)[i];
|
||||
std::wstring desc;
|
||||
if (i < ext_desc->size())
|
||||
desc = (*ext_desc)[i];
|
||||
|
||||
if (ext.empty()) {
|
||||
// Force something reasonable to appear in the dialog box if there is no
|
||||
// extension provided.
|
||||
include_all_files = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (desc.empty()) {
|
||||
DCHECK(ext.find(L'.') != std::wstring::npos);
|
||||
std::wstring first_extension = ext.substr(ext.find(L'.'));
|
||||
size_t first_separator_index = first_extension.find(L';');
|
||||
if (first_separator_index != std::wstring::npos)
|
||||
first_extension = first_extension.substr(0, first_separator_index);
|
||||
|
||||
// Find the extension name without the preceeding '.' character.
|
||||
std::wstring ext_name = first_extension;
|
||||
size_t ext_index = ext_name.find_first_not_of(L'.');
|
||||
if (ext_index != std::wstring::npos)
|
||||
ext_name = ext_name.substr(ext_index);
|
||||
|
||||
if (!GetRegistryDescriptionFromExtension(first_extension, &desc)) {
|
||||
// The extension doesn't exist in the registry. Create a description
|
||||
// based on the unknown extension type (i.e. if the extension is .qqq,
|
||||
// the we create a description "QQQ File (.qqq)").
|
||||
include_all_files = true;
|
||||
// TODO(zcbenz): should be localized.
|
||||
desc = base::i18n::ToUpper(base::WideToUTF16(ext_name)) + L" File";
|
||||
}
|
||||
desc += L" (*." + ext_name + L")";
|
||||
|
||||
// Store the description.
|
||||
ext_desc->push_back(desc);
|
||||
}
|
||||
|
||||
COMDLG_FILTERSPEC spec = { (*ext_desc)[i].c_str(), (*file_ext)[i].c_str() };
|
||||
file_types->push_back(spec);
|
||||
void ConvertFilters(const Filters& filters,
|
||||
std::vector<std::wstring>* buffer,
|
||||
std::vector<COMDLG_FILTERSPEC>* filterspec) {
|
||||
if (filters.empty()) {
|
||||
COMDLG_FILTERSPEC spec = { L"All Files (*.*)", L"*.*" };
|
||||
filterspec->push_back(spec);
|
||||
return;
|
||||
}
|
||||
|
||||
if (include_all_files) {
|
||||
// TODO(zcbenz): Should be localized.
|
||||
ext_desc->push_back(L"All Files (*.*)");
|
||||
file_ext->push_back(L"*.*");
|
||||
buffer->reserve(filters.size() * 2);
|
||||
for (size_t i = 0; i < filters.size(); ++i) {
|
||||
const Filter& filter = filters[i];
|
||||
|
||||
COMDLG_FILTERSPEC spec = {
|
||||
(*ext_desc)[ext_desc->size() - 1].c_str(),
|
||||
(*file_ext)[file_ext->size() - 1].c_str(),
|
||||
};
|
||||
file_types->push_back(spec);
|
||||
COMDLG_FILTERSPEC spec;
|
||||
buffer->push_back(base::UTF8ToWide(filter.first));
|
||||
spec.pszName = buffer->back().c_str();
|
||||
|
||||
std::vector<std::string> extensions(filter.second);
|
||||
for (size_t j = 0; j < extensions.size(); ++j)
|
||||
extensions[j].insert(0, "*.");
|
||||
buffer->push_back(base::UTF8ToWide(JoinString(extensions, ";")));
|
||||
spec.pszSpec = buffer->back().c_str();
|
||||
|
||||
filterspec->push_back(spec);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,26 +62,18 @@ void FormatFilterForExtensions(
|
||||
template <typename T>
|
||||
class FileDialog {
|
||||
public:
|
||||
FileDialog(const base::FilePath& default_path,
|
||||
const std::string title,
|
||||
int options,
|
||||
const std::vector<std::wstring>& file_ext,
|
||||
const std::vector<std::wstring>& desc_ext)
|
||||
: file_ext_(file_ext),
|
||||
desc_ext_(desc_ext) {
|
||||
std::vector<COMDLG_FILTERSPEC> filters;
|
||||
FormatFilterForExtensions(&file_ext_, &desc_ext_, true, &filters);
|
||||
|
||||
FileDialog(const base::FilePath& default_path, const std::string& title,
|
||||
const Filters& filters, int options) {
|
||||
std::wstring file_part;
|
||||
if (!IsDirectory(default_path))
|
||||
file_part = default_path.BaseName().value();
|
||||
|
||||
dialog_.reset(new T(
|
||||
file_part.c_str(),
|
||||
options,
|
||||
NULL,
|
||||
filters.data(),
|
||||
filters.size()));
|
||||
std::vector<std::wstring> buffer;
|
||||
std::vector<COMDLG_FILTERSPEC> filterspec;
|
||||
ConvertFilters(filters, &buffer, &filterspec);
|
||||
|
||||
dialog_.reset(new T(file_part.c_str(), options, NULL,
|
||||
filterspec.data(), filterspec.size()));
|
||||
|
||||
if (!title.empty())
|
||||
GetPtr()->SetTitle(base::UTF8ToUTF16(title).c_str());
|
||||
@@ -174,8 +93,6 @@ class FileDialog {
|
||||
|
||||
IFileDialog* GetPtr() const { return dialog_->GetPtr(); }
|
||||
|
||||
const std::vector<std::wstring> file_ext() const { return file_ext_; }
|
||||
|
||||
private:
|
||||
// Set up the initial directory for the dialog.
|
||||
void SetDefaultFolder(const base::FilePath file_path) {
|
||||
@@ -193,10 +110,6 @@ class FileDialog {
|
||||
|
||||
scoped_ptr<T> dialog_;
|
||||
|
||||
std::vector<std::wstring> file_ext_;
|
||||
std::vector<std::wstring> desc_ext_;
|
||||
std::vector<COMDLG_FILTERSPEC> filters_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(FileDialog);
|
||||
};
|
||||
|
||||
@@ -205,6 +118,7 @@ class FileDialog {
|
||||
bool ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
int properties,
|
||||
std::vector<base::FilePath>* paths) {
|
||||
int options = FOS_FORCEFILESYSTEM | FOS_FILEMUSTEXIST;
|
||||
@@ -214,11 +128,7 @@ bool ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
options |= FOS_ALLOWMULTISELECT;
|
||||
|
||||
FileDialog<CShellFileOpenDialog> open_dialog(
|
||||
default_path,
|
||||
title,
|
||||
options,
|
||||
std::vector<std::wstring>(),
|
||||
std::vector<std::wstring>());
|
||||
default_path, title, filters, options);
|
||||
if (!open_dialog.Show(parent_window))
|
||||
return false;
|
||||
|
||||
@@ -255,12 +165,14 @@ bool ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
void ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
int properties,
|
||||
const OpenDialogCallback& callback) {
|
||||
std::vector<base::FilePath> paths;
|
||||
bool result = ShowOpenDialog(parent_window,
|
||||
title,
|
||||
default_path,
|
||||
filters,
|
||||
properties,
|
||||
&paths);
|
||||
callback.Run(result, paths);
|
||||
@@ -269,52 +181,51 @@ void ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
bool ShowSaveDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
base::FilePath* path) {
|
||||
// TODO(zcbenz): Accept custom filters from caller.
|
||||
std::vector<std::wstring> file_ext;
|
||||
std::wstring extension = default_path.Extension();
|
||||
if (!extension.empty())
|
||||
file_ext.push_back(extension.insert(0, L"*"));
|
||||
|
||||
FileDialog<CShellFileSaveDialog> save_dialog(
|
||||
default_path,
|
||||
title,
|
||||
FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT,
|
||||
file_ext,
|
||||
std::vector<std::wstring>());
|
||||
default_path, title, filters,
|
||||
FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT);
|
||||
if (!save_dialog.Show(parent_window))
|
||||
return false;
|
||||
|
||||
wchar_t file_name[MAX_PATH];
|
||||
HRESULT hr = save_dialog.GetDialog()->GetFilePath(file_name, MAX_PATH);
|
||||
wchar_t buffer[MAX_PATH];
|
||||
HRESULT hr = save_dialog.GetDialog()->GetFilePath(buffer, MAX_PATH);
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
std::string file_name = base::WideToUTF8(std::wstring(buffer));
|
||||
|
||||
// Append extension according to selected filter.
|
||||
UINT filter_index = 1;
|
||||
save_dialog.GetPtr()->GetFileTypeIndex(&filter_index);
|
||||
std::wstring selected_filter = save_dialog.file_ext()[filter_index - 1];
|
||||
if (selected_filter != L"*.*") {
|
||||
std::wstring result = file_name;
|
||||
if (!EndsWith(result, selected_filter.substr(1), false)) {
|
||||
if (result[result.length() - 1] != L'.')
|
||||
result.push_back(L'.');
|
||||
result.append(selected_filter.substr(2));
|
||||
*path = base::FilePath(result);
|
||||
return true;
|
||||
if (!filters.empty()) {
|
||||
UINT filter_index = 1;
|
||||
save_dialog.GetPtr()->GetFileTypeIndex(&filter_index);
|
||||
const Filter& filter = filters[filter_index - 1];
|
||||
|
||||
bool matched = false;
|
||||
for (size_t i = 0; i < filter.second.size(); ++i) {
|
||||
if (EndsWith(file_name, filter.second[i], false)) {
|
||||
matched = true;
|
||||
break;;
|
||||
}
|
||||
}
|
||||
|
||||
if (!matched && !filter.second.empty())
|
||||
file_name += ("." + filter.second[0]);
|
||||
}
|
||||
|
||||
*path = base::FilePath(file_name);
|
||||
*path = base::FilePath(base::UTF8ToUTF16(file_name));
|
||||
return true;
|
||||
}
|
||||
|
||||
void ShowSaveDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters,
|
||||
const SaveDialogCallback& callback) {
|
||||
base::FilePath path;
|
||||
bool result = ShowSaveDialog(parent_window, title, default_path, &path);
|
||||
bool result = ShowSaveDialog(parent_window, title, default_path, filters,
|
||||
&path);
|
||||
callback.Run(result, path);
|
||||
}
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ int ShowMessageBox(NativeWindow* parent_window,
|
||||
|
||||
// Use runModal for synchronous alert without parent, since we don't have a
|
||||
// window to wait for.
|
||||
if (!parent_window)
|
||||
if (!parent_window || !parent_window->GetNativeWindow())
|
||||
return [[alert autorelease] runModal];
|
||||
|
||||
int ret_code = -1;
|
||||
|
||||
@@ -4,16 +4,21 @@
|
||||
|
||||
#include "atom/browser/ui/views/menu_bar.h"
|
||||
|
||||
#if defined(USE_X11)
|
||||
#include "gtk/gtk.h"
|
||||
#endif
|
||||
|
||||
#include "atom/browser/ui/views/menu_delegate.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "atom/browser/ui/views/submenu_button.h"
|
||||
#include "ui/base/models/menu_model.h"
|
||||
#include "ui/views/background.h"
|
||||
#include "ui/views/controls/button/menu_button.h"
|
||||
#include "ui/views/layout/box_layout.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "ui/gfx/color_utils.h"
|
||||
#elif defined(USE_X11)
|
||||
#include "chrome/browser/ui/libgtk2ui/owned_widget_gtk2.h"
|
||||
#include "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h"
|
||||
#endif
|
||||
|
||||
namespace atom {
|
||||
@@ -25,24 +30,34 @@ const char kViewClassName[] = "AtomMenuBar";
|
||||
// Default color of the menu bar.
|
||||
const SkColor kDefaultColor = SkColorSetARGB(255, 233, 233, 233);
|
||||
|
||||
// Filter out the "&" in menu label.
|
||||
base::string16 FilterMenuButtonLabel(const base::string16& label) {
|
||||
base::string16 out;
|
||||
base::RemoveChars(label, base::ASCIIToUTF16("&").c_str(), &out);
|
||||
return out;
|
||||
#if defined(USE_X11)
|
||||
void GetMenuBarColor(SkColor* enabled, SkColor* disabled, SkColor* highlight,
|
||||
SkColor* hover, SkColor* background) {
|
||||
libgtk2ui::OwnedWidgetGtk fake_menu_bar;
|
||||
fake_menu_bar.Own(gtk_menu_bar_new());
|
||||
|
||||
GtkStyle* style = gtk_rc_get_style(fake_menu_bar.get());
|
||||
*enabled = libgtk2ui::GdkColorToSkColor(style->fg[GTK_STATE_NORMAL]);
|
||||
*disabled = libgtk2ui::GdkColorToSkColor(style->fg[GTK_STATE_INSENSITIVE]);
|
||||
*highlight = libgtk2ui::GdkColorToSkColor(style->fg[GTK_STATE_SELECTED]);
|
||||
*hover = libgtk2ui::GdkColorToSkColor(style->fg[GTK_STATE_PRELIGHT]);
|
||||
*background = libgtk2ui::GdkColorToSkColor(style->bg[GTK_STATE_NORMAL]);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
MenuBar::MenuBar()
|
||||
: menu_model_(NULL) {
|
||||
: background_color_(kDefaultColor),
|
||||
menu_model_(NULL) {
|
||||
#if defined(OS_WIN)
|
||||
SkColor background_color = color_utils::GetSysSkColor(COLOR_MENUBAR);
|
||||
#else
|
||||
SkColor background_color = kDefaultColor;
|
||||
background_color_ = color_utils::GetSysSkColor(COLOR_MENUBAR);
|
||||
#elif defined(USE_X11)
|
||||
GetMenuBarColor(&enabled_color_, &disabled_color_, &highlight_color_,
|
||||
&hover_color_, &background_color_);
|
||||
#endif
|
||||
set_background(views::Background::CreateSolidBackground(background_color));
|
||||
|
||||
set_background(views::Background::CreateSolidBackground(background_color_));
|
||||
SetLayoutManager(new views::BoxLayout(
|
||||
views::BoxLayout::kHorizontal, 0, 0, 0));
|
||||
}
|
||||
@@ -55,13 +70,43 @@ void MenuBar::SetMenu(ui::MenuModel* model) {
|
||||
RemoveAllChildViews(true);
|
||||
|
||||
for (int i = 0; i < model->GetItemCount(); ++i) {
|
||||
views::MenuButton* button = new views::MenuButton(
|
||||
this, FilterMenuButtonLabel(model->GetLabelAt(i)), this, false);
|
||||
SubmenuButton* button = new SubmenuButton(this, model->GetLabelAt(i), this);
|
||||
button->set_tag(i);
|
||||
|
||||
#if defined(USE_X11)
|
||||
button->SetEnabledColor(enabled_color_);
|
||||
button->SetDisabledColor(disabled_color_);
|
||||
button->SetHighlightColor(highlight_color_);
|
||||
button->SetHoverColor(hover_color_);
|
||||
button->SetUnderlineColor(enabled_color_);
|
||||
#elif defined(OS_WIN)
|
||||
button->SetUnderlineColor(color_utils::GetSysSkColor(COLOR_GRAYTEXT));
|
||||
#endif
|
||||
|
||||
AddChildView(button);
|
||||
}
|
||||
}
|
||||
|
||||
void MenuBar::SetAcceleratorVisibility(bool visible) {
|
||||
for (int i = 0; i < child_count(); ++i)
|
||||
static_cast<SubmenuButton*>(child_at(i))->SetAcceleratorVisibility(visible);
|
||||
}
|
||||
|
||||
int MenuBar::GetAcceleratorIndex(base::char16 key) {
|
||||
for (int i = 0; i < child_count(); ++i) {
|
||||
SubmenuButton* button = static_cast<SubmenuButton*>(child_at(i));
|
||||
if (button->accelerator() == key)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void MenuBar::ActivateAccelerator(base::char16 key) {
|
||||
int i = GetAcceleratorIndex(key);
|
||||
if (i != -1)
|
||||
static_cast<SubmenuButton*>(child_at(i))->Activate();
|
||||
}
|
||||
|
||||
int MenuBar::GetItemCount() const {
|
||||
return menu_model_->GetItemCount();
|
||||
}
|
||||
@@ -98,6 +143,9 @@ void MenuBar::ButtonPressed(views::Button* sender, const ui::Event& event) {
|
||||
|
||||
void MenuBar::OnMenuButtonClicked(views::View* source,
|
||||
const gfx::Point& point) {
|
||||
// Hide the accelerator when a submenu is activated.
|
||||
SetAcceleratorVisibility(false);
|
||||
|
||||
if (!menu_model_)
|
||||
return;
|
||||
|
||||
|
||||
@@ -31,6 +31,16 @@ class MenuBar : public views::View,
|
||||
// Replaces current menu with a new one.
|
||||
void SetMenu(ui::MenuModel* menu_model);
|
||||
|
||||
// Shows underline under accelerators.
|
||||
void SetAcceleratorVisibility(bool visible);
|
||||
|
||||
// Returns which submenu has accelerator |key|, -1 would be returned when
|
||||
// there is no matching submenu.
|
||||
int GetAcceleratorIndex(base::char16 key);
|
||||
|
||||
// Shows the submenu whose accelerator is |key|.
|
||||
void ActivateAccelerator(base::char16 key);
|
||||
|
||||
// Returns there are how many items in the root menu.
|
||||
int GetItemCount() const;
|
||||
|
||||
@@ -52,6 +62,15 @@ class MenuBar : public views::View,
|
||||
const gfx::Point& point) OVERRIDE;
|
||||
|
||||
private:
|
||||
SkColor background_color_;
|
||||
|
||||
#if defined(USE_X11)
|
||||
SkColor enabled_color_;
|
||||
SkColor disabled_color_;
|
||||
SkColor highlight_color_;
|
||||
SkColor hover_color_;
|
||||
#endif
|
||||
|
||||
ui::MenuModel* menu_model_;
|
||||
scoped_ptr<MenuDelegate> menu_delegate_;
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "atom/browser/ui/views/menu_bar.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "ui/views/controls/button/menu_button.h"
|
||||
#include "ui/views/controls/menu/menu_item_view.h"
|
||||
#include "ui/views/controls/menu/menu_model_adapter.h"
|
||||
#include "ui/views/controls/menu/menu_runner.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
@@ -39,7 +40,7 @@ void MenuDelegate::RunMenu(ui::MenuModel* model, views::MenuButton* button) {
|
||||
button->GetWidget()->GetTopLevelWidget(),
|
||||
button,
|
||||
bounds,
|
||||
views::MenuItemView::TOPRIGHT,
|
||||
views::MENU_ANCHOR_TOPRIGHT,
|
||||
ui::MENU_SOURCE_MOUSE,
|
||||
views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU));
|
||||
}
|
||||
@@ -107,14 +108,14 @@ void MenuDelegate::WillHideMenu(views::MenuItemView* menu) {
|
||||
views::MenuItemView* MenuDelegate::GetSiblingMenu(
|
||||
views::MenuItemView* menu,
|
||||
const gfx::Point& screen_point,
|
||||
views::MenuItemView::AnchorPosition* anchor,
|
||||
views::MenuAnchorPosition* anchor,
|
||||
bool* has_mnemonics,
|
||||
views::MenuButton** button) {
|
||||
ui::MenuModel* model;
|
||||
if (!menu_bar_->GetMenuButtonFromScreenPoint(screen_point, &model, button))
|
||||
return NULL;
|
||||
|
||||
*anchor = views::MenuItemView::TOPLEFT;
|
||||
*anchor = views::MENU_ANCHOR_TOPLEFT;
|
||||
*has_mnemonics = true;
|
||||
|
||||
id_ = (*button)->tag();
|
||||
|
||||
@@ -46,7 +46,7 @@ class MenuDelegate : public views::MenuDelegate {
|
||||
virtual views::MenuItemView* GetSiblingMenu(
|
||||
views::MenuItemView* menu,
|
||||
const gfx::Point& screen_point,
|
||||
views::MenuItemView::AnchorPosition* anchor,
|
||||
views::MenuAnchorPosition* anchor,
|
||||
bool* has_mnemonics,
|
||||
views::MenuButton** button);
|
||||
|
||||
|
||||
@@ -24,10 +24,10 @@ void MenuLayout::Layout(views::View* host) {
|
||||
gfx::Rect web_view_bounds = gfx::Rect(
|
||||
0, menu_height_, size.width(), size.height() - menu_height_);
|
||||
|
||||
views::View* menu_bar = host->child_at(0);
|
||||
views::View* web_view = host->child_at(1);
|
||||
menu_bar->SetBoundsRect(menu_Bar_bounds);
|
||||
views::View* web_view = host->child_at(0);
|
||||
views::View* menu_bar = host->child_at(1);
|
||||
web_view->SetBoundsRect(web_view_bounds);
|
||||
menu_bar->SetBoundsRect(menu_Bar_bounds);
|
||||
}
|
||||
|
||||
gfx::Size MenuLayout::GetPreferredSize(views::View* host) {
|
||||
|
||||
92
atom/browser/ui/views/submenu_button.cc
Normal file
92
atom/browser/ui/views/submenu_button.cc
Normal file
@@ -0,0 +1,92 @@
|
||||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/ui/views/submenu_button.h"
|
||||
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "ui/gfx/canvas.h"
|
||||
#include "ui/gfx/text_utils.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
// Filter out the "&" in menu label.
|
||||
base::string16 FilterAccecelator(const base::string16& label) {
|
||||
base::string16 out;
|
||||
base::RemoveChars(label, base::ASCIIToUTF16("&").c_str(), &out);
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
SubmenuButton::SubmenuButton(views::ButtonListener* listener,
|
||||
const base::string16& title,
|
||||
views::MenuButtonListener* menu_button_listener)
|
||||
: views::MenuButton(listener, FilterAccecelator(title),
|
||||
menu_button_listener, false),
|
||||
accelerator_(0),
|
||||
show_underline_(false),
|
||||
underline_start_(-1),
|
||||
underline_end_(-1),
|
||||
text_width_(0),
|
||||
text_height_(0),
|
||||
underline_color_(SK_ColorBLACK) {
|
||||
if (GetUnderlinePosition(title, &accelerator_, &underline_start_,
|
||||
&underline_end_))
|
||||
gfx::Canvas::SizeStringInt(text(), font_list(), &text_width_,
|
||||
&text_height_, 0, 0);
|
||||
}
|
||||
|
||||
SubmenuButton::~SubmenuButton() {
|
||||
}
|
||||
|
||||
void SubmenuButton::SetAcceleratorVisibility(bool visible) {
|
||||
if (visible == show_underline_)
|
||||
return;
|
||||
|
||||
show_underline_ = visible;
|
||||
SchedulePaint();
|
||||
}
|
||||
|
||||
void SubmenuButton::SetUnderlineColor(SkColor color) {
|
||||
underline_color_ = color;
|
||||
}
|
||||
|
||||
void SubmenuButton::OnPaint(gfx::Canvas* canvas) {
|
||||
views::MenuButton::OnPaint(canvas);
|
||||
|
||||
if (show_underline_ && (underline_start_ != underline_end_)) {
|
||||
int padding = (width() - text_width_) / 2;
|
||||
int underline_height = (height() + text_height_) / 2 - 2;
|
||||
canvas->DrawLine(gfx::Point(underline_start_ + padding, underline_height),
|
||||
gfx::Point(underline_end_ + padding, underline_height),
|
||||
underline_color_);
|
||||
}
|
||||
}
|
||||
|
||||
bool SubmenuButton::GetUnderlinePosition(const base::string16& text,
|
||||
base::char16* accelerator,
|
||||
int* start, int* end) {
|
||||
int pos, span;
|
||||
base::string16 trimmed = gfx::RemoveAcceleratorChar(text, '&', &pos, &span);
|
||||
if (pos > -1 && span != 0) {
|
||||
*accelerator = base::ToUpperASCII(trimmed[pos]);
|
||||
GetCharacterPosition(trimmed, pos, start);
|
||||
GetCharacterPosition(trimmed, pos + span, end);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SubmenuButton::GetCharacterPosition(
|
||||
const base::string16& text, int index, int* pos) {
|
||||
int height;
|
||||
gfx::Canvas::SizeStringInt(text.substr(0, index), font_list(), pos, &height,
|
||||
0, 0);
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
50
atom/browser/ui/views/submenu_button.h
Normal file
50
atom/browser/ui/views/submenu_button.h
Normal file
@@ -0,0 +1,50 @@
|
||||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_UI_VIEWS_SUBMENU_BUTTON_H_
|
||||
#define ATOM_BROWSER_UI_VIEWS_SUBMENU_BUTTON_H_
|
||||
|
||||
#include "ui/views/controls/button/menu_button.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
// Special button that used by menu bar to show submenus.
|
||||
class SubmenuButton : public views::MenuButton {
|
||||
public:
|
||||
SubmenuButton(views::ButtonListener* listener,
|
||||
const base::string16& title,
|
||||
views::MenuButtonListener* menu_button_listener);
|
||||
virtual ~SubmenuButton();
|
||||
|
||||
void SetAcceleratorVisibility(bool visible);
|
||||
void SetUnderlineColor(SkColor color);
|
||||
|
||||
base::char16 accelerator() const { return accelerator_; }
|
||||
|
||||
// views::MenuButton:
|
||||
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
|
||||
|
||||
private:
|
||||
bool GetUnderlinePosition(const base::string16& text,
|
||||
base::char16* accelerator,
|
||||
int* start, int* end);
|
||||
void GetCharacterPosition(
|
||||
const base::string16& text, int index, int* pos);
|
||||
|
||||
base::char16 accelerator_;
|
||||
|
||||
bool show_underline_;
|
||||
|
||||
int underline_start_;
|
||||
int underline_end_;
|
||||
int text_width_;
|
||||
int text_height_;
|
||||
SkColor underline_color_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SubmenuButton);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_UI_VIEWS_SUBMENU_BUTTON_H_
|
||||
@@ -60,16 +60,14 @@ void NotifyIcon::HandleClickEvent(const gfx::Point& cursor_pos,
|
||||
if (!SetForegroundWindow(window_))
|
||||
return;
|
||||
|
||||
menu_runner_.reset(new views::MenuRunner(menu_model_));
|
||||
views::MenuRunner::RunResult result = menu_runner_->RunMenuAt(
|
||||
views::MenuRunner menu_runner(menu_model_);
|
||||
ignore_result(menu_runner.RunMenuAt(
|
||||
NULL,
|
||||
NULL,
|
||||
gfx::Rect(cursor_pos, gfx::Size()),
|
||||
views::MenuItemView::TOPLEFT,
|
||||
views::MENU_ANCHOR_TOPLEFT,
|
||||
ui::MENU_SOURCE_MOUSE,
|
||||
views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU);
|
||||
if (result == views::MenuRunner::MENU_DELETED)
|
||||
LOG(ERROR) << "Menu deleted when running";
|
||||
views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU));
|
||||
}
|
||||
|
||||
void NotifyIcon::ResetIcon() {
|
||||
|
||||
@@ -20,10 +20,6 @@ namespace gfx {
|
||||
class Point;
|
||||
}
|
||||
|
||||
namespace views {
|
||||
class MenuRunner;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class NotifyIconHost;
|
||||
@@ -72,7 +68,6 @@ class NotifyIcon : public TrayIcon {
|
||||
|
||||
// The context menu.
|
||||
ui::SimpleMenuModel* menu_model_;
|
||||
scoped_ptr<views::MenuRunner> menu_runner_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NotifyIcon);
|
||||
};
|
||||
|
||||
@@ -28,7 +28,7 @@ int32_t IDWeakMap::Add(v8::Isolate* isolate, v8::Handle<v8::Object> object) {
|
||||
object->SetHiddenValue(mate::StringToV8(isolate, "IDWeakMapKey"),
|
||||
mate::Converter<int32_t>::ToV8(isolate, key));
|
||||
|
||||
map_[key] = new mate::RefCountedPersistent<v8::Object>(object);
|
||||
map_[key] = new mate::RefCountedPersistent<v8::Object>(isolate, object);
|
||||
map_[key]->SetWeak(this, WeakCallback);
|
||||
return key;
|
||||
}
|
||||
|
||||
@@ -7,10 +7,9 @@
|
||||
#include <string>
|
||||
|
||||
#include "atom/common/atom_version.h"
|
||||
#include "atom/common/native_mate_converters/function_converter.h"
|
||||
#include "atom/common/native_mate_converters/string16_converter.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/logging.h"
|
||||
#include "native_mate/callback.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
@@ -16,7 +16,7 @@ void ObjectLifeMonitor::BindTo(v8::Isolate* isolate,
|
||||
target->SetHiddenValue(MATE_STRING_NEW(isolate, "destructor"), destructor);
|
||||
|
||||
ObjectLifeMonitor* olm = new ObjectLifeMonitor();
|
||||
olm->handle_.reset(target);
|
||||
olm->handle_.reset(isolate, target);
|
||||
olm->handle_.SetWeak(olm, WeakCallback);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
#define ATOM_VERSION_H
|
||||
|
||||
#define ATOM_MAJOR_VERSION 0
|
||||
#define ATOM_MINOR_VERSION 14
|
||||
#define ATOM_PATCH_VERSION 2
|
||||
#define ATOM_MINOR_VERSION 15
|
||||
#define ATOM_PATCH_VERSION 8
|
||||
|
||||
#define ATOM_VERSION_IS_RELEASE 1
|
||||
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/common/browser_v8_locker.h"
|
||||
|
||||
namespace node {
|
||||
extern bool g_standalone_mode;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
BrowserV8Locker::BrowserV8Locker(v8::Isolate* isolate) {
|
||||
if (node::g_standalone_mode)
|
||||
locker_.reset(new v8::Locker(isolate));
|
||||
}
|
||||
|
||||
BrowserV8Locker::~BrowserV8Locker() {
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
@@ -1,28 +0,0 @@
|
||||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_COMMON_BROWSER_V8_LOCKER_H_
|
||||
#define ATOM_COMMON_BROWSER_V8_LOCKER_H_
|
||||
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "v8/include/v8.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
// Like v8::Locker, but only do lock when in browser process.
|
||||
class BrowserV8Locker {
|
||||
public:
|
||||
explicit BrowserV8Locker(v8::Isolate* isolate);
|
||||
~BrowserV8Locker();
|
||||
|
||||
private:
|
||||
void* operator new(size_t size);
|
||||
void operator delete(void*, size_t);
|
||||
|
||||
scoped_ptr<v8::Locker> locker_;
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_COMMON_BROWSER_V8_LOCKER_H_
|
||||
@@ -8,7 +8,7 @@
|
||||
#ifndef ATOM_COMMON_CHROME_VERSION_H_
|
||||
#define ATOM_COMMON_CHROME_VERSION_H_
|
||||
|
||||
#define CHROME_VERSION_STRING "35.0.1916.153"
|
||||
#define CHROME_VERSION_STRING "36.0.1985.125"
|
||||
#define CHROME_VERSION "v" CHROME_VERSION_STRING
|
||||
|
||||
#endif // ATOM_COMMON_CHROME_VERSION_H_
|
||||
|
||||
@@ -54,12 +54,14 @@ void CrashReporterWin::InitBreakpad(const std::string& product_name,
|
||||
if (waiting_event != INVALID_HANDLE_VALUE)
|
||||
WaitForSingleObject(waiting_event, 1000);
|
||||
|
||||
int handler_types = google_breakpad::ExceptionHandler::HANDLER_EXCEPTION |
|
||||
google_breakpad::ExceptionHandler::HANDLER_PURECALL;
|
||||
breakpad_.reset(new google_breakpad::ExceptionHandler(
|
||||
temp_dir.value(),
|
||||
FilterCallback,
|
||||
MinidumpCallback,
|
||||
this,
|
||||
google_breakpad::ExceptionHandler::HANDLER_ALL,
|
||||
handler_types,
|
||||
kSmallDumpType,
|
||||
pipe_name.c_str(),
|
||||
GetCustomInfo(product_name, version, company_name)));
|
||||
|
||||
@@ -350,6 +350,8 @@ void ExecUploadProcessOrTerminate(const BreakpadInfo& info,
|
||||
"--timeout=60", // Set a timeout so we don't hang forever.
|
||||
"--tries=1", // Don't retry if the upload fails.
|
||||
"--quiet", // Be silent.
|
||||
"-O", // output reply to /dev/null.
|
||||
"/dev/null",
|
||||
NULL,
|
||||
};
|
||||
static const char msg[] = "Cannot upload crash dump: cannot exec "
|
||||
|
||||
@@ -25,3 +25,11 @@ wrapWithActivateUvLoop = (func) ->
|
||||
process.nextTick = wrapWithActivateUvLoop process.nextTick
|
||||
global.setImmediate = wrapWithActivateUvLoop timers.setImmediate
|
||||
global.clearImmediate = timers.clearImmediate
|
||||
|
||||
# setTimeout needs to update the polling timeout of the event loop, when called
|
||||
# under Chromium's event loop the node's event loop won't get a chance to update
|
||||
# the timeout, so we have to force the node's event loop to recalculate the
|
||||
# timeout in browser process.
|
||||
if process.type is 'browser'
|
||||
global.setTimeout = wrapWithActivateUvLoop timers.setTimeout
|
||||
global.setInterval = wrapWithActivateUvLoop timers.setInterval
|
||||
|
||||
22
atom/common/native_mate_converters/accelerator_converter.cc
Normal file
22
atom/common/native_mate_converters/accelerator_converter.cc
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/common/native_mate_converters/accelerator_converter.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/ui/accelerator_util.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
// static
|
||||
bool Converter<ui::Accelerator>::FromV8(
|
||||
v8::Isolate* isolate, v8::Handle<v8::Value> val, ui::Accelerator* out) {
|
||||
std::string keycode;
|
||||
if (!ConvertFromV8(isolate, val, &keycode))
|
||||
return false;
|
||||
return accelerator_util::StringToAccelerator(keycode, out);
|
||||
}
|
||||
|
||||
} // namespace mate
|
||||
24
atom/common/native_mate_converters/accelerator_converter.h
Normal file
24
atom/common/native_mate_converters/accelerator_converter.h
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_ACCELERATOR_CONVERTER_H_
|
||||
#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_ACCELERATOR_CONVERTER_H_
|
||||
|
||||
#include "native_mate/converter.h"
|
||||
|
||||
namespace ui {
|
||||
class Accelerator;
|
||||
}
|
||||
|
||||
namespace mate {
|
||||
|
||||
template<>
|
||||
struct Converter<ui::Accelerator> {
|
||||
static bool FromV8(v8::Isolate* isolate, v8::Handle<v8::Value> val,
|
||||
ui::Accelerator* out);
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_ACCELERATOR_CONVERTER_H_
|
||||
@@ -1,209 +0,0 @@
|
||||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_FUNCTION_CONVERTER_H_
|
||||
#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_FUNCTION_CONVERTER_H_
|
||||
|
||||
#include "atom/common/browser_v8_locker.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/callback.h"
|
||||
#include "native_mate/constructor.h"
|
||||
#include "native_mate/scoped_persistent.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
namespace internal {
|
||||
|
||||
typedef scoped_refptr<RefCountedPersistent<v8::Function> > SafeV8Function;
|
||||
|
||||
// Helper to convert type to V8 with storage type (const T& to T).
|
||||
template<typename T>
|
||||
v8::Handle<v8::Value> ConvertToV8(v8::Isolate* isolate, T a) {
|
||||
return Converter<typename base::internal::CallbackParamTraits<T>::StorageType>
|
||||
::ToV8(isolate, a);
|
||||
}
|
||||
|
||||
// This set of templates invokes a V8::Function by converting the C++ types.
|
||||
template<typename Sig>
|
||||
struct V8FunctionInvoker;
|
||||
|
||||
template<typename R>
|
||||
struct V8FunctionInvoker<R()> {
|
||||
static R Go(v8::Isolate* isolate, SafeV8Function function) {
|
||||
R ret;
|
||||
atom::BrowserV8Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Handle<v8::Function> holder = function->NewHandle();
|
||||
v8::Handle<v8::Value> val(holder->Call(holder, 0, NULL));
|
||||
Converter<R>::FromV8(isolate, val, &ret);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct V8FunctionInvoker<void()> {
|
||||
static void Go(v8::Isolate* isolate, SafeV8Function function) {
|
||||
atom::BrowserV8Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Handle<v8::Function> holder = function->NewHandle();
|
||||
holder->Call(holder, 0, NULL);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename R, typename P1>
|
||||
struct V8FunctionInvoker<R(P1)> {
|
||||
static R Go(v8::Isolate* isolate, SafeV8Function function, P1 a1) {
|
||||
R ret;
|
||||
atom::BrowserV8Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Handle<v8::Function> holder = function->NewHandle();
|
||||
v8::Handle<v8::Value> args[] = {
|
||||
ConvertToV8(isolate, a1),
|
||||
};
|
||||
v8::Handle<v8::Value> val(holder->Call(holder, arraysize(args), args));
|
||||
Converter<R>::FromV8(isolate, val, &ret);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename P1>
|
||||
struct V8FunctionInvoker<void(P1)> {
|
||||
static void Go(v8::Isolate* isolate, SafeV8Function function, P1 a1) {
|
||||
atom::BrowserV8Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Handle<v8::Function> holder = function->NewHandle();
|
||||
v8::Handle<v8::Value> args[] = {
|
||||
ConvertToV8(isolate, a1),
|
||||
};
|
||||
holder->Call(holder, arraysize(args), args);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename R, typename P1, typename P2>
|
||||
struct V8FunctionInvoker<R(P1, P2)> {
|
||||
static R Go(v8::Isolate* isolate, SafeV8Function function, P1 a1, P2 a2) {
|
||||
R ret;
|
||||
atom::BrowserV8Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Handle<v8::Function> holder = function->NewHandle();
|
||||
v8::Handle<v8::Value> args[] = {
|
||||
ConvertToV8(isolate, a1),
|
||||
ConvertToV8(isolate, a2),
|
||||
};
|
||||
v8::Handle<v8::Value> val(holder->Call(holder, arraysize(args), args));
|
||||
Converter<R>::FromV8(isolate, val, &ret);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename P1, typename P2>
|
||||
struct V8FunctionInvoker<void(P1, P2)> {
|
||||
static void Go(v8::Isolate* isolate, SafeV8Function function, P1 a1, P2 a2) {
|
||||
atom::BrowserV8Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Handle<v8::Function> holder = function->NewHandle();
|
||||
v8::Handle<v8::Value> args[] = {
|
||||
ConvertToV8(isolate, a1),
|
||||
ConvertToV8(isolate, a2),
|
||||
};
|
||||
holder->Call(holder, arraysize(args), args);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename R, typename P1, typename P2, typename P3>
|
||||
struct V8FunctionInvoker<R(P1, P2, P3)> {
|
||||
static R Go(v8::Isolate* isolate, SafeV8Function function, P1 a1, P2 a2,
|
||||
P3 a3) {
|
||||
R ret;
|
||||
atom::BrowserV8Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Handle<v8::Function> holder = function->NewHandle();
|
||||
v8::Handle<v8::Value> args[] = {
|
||||
ConvertToV8(isolate, a1),
|
||||
ConvertToV8(isolate, a2),
|
||||
ConvertToV8(isolate, a3),
|
||||
};
|
||||
v8::Handle<v8::Value> val(holder->Call(holder, arraysize(args), args));
|
||||
Converter<R>::FromV8(isolate, val, &ret);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename P1, typename P2, typename P3>
|
||||
struct V8FunctionInvoker<void(P1, P2, P3)> {
|
||||
static void Go(v8::Isolate* isolate, SafeV8Function function, P1 a1, P2 a2,
|
||||
P3 a3) {
|
||||
atom::BrowserV8Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Handle<v8::Function> holder = function->NewHandle();
|
||||
v8::Handle<v8::Value> args[] = {
|
||||
ConvertToV8(isolate, a1),
|
||||
ConvertToV8(isolate, a2),
|
||||
ConvertToV8(isolate, a3),
|
||||
};
|
||||
holder->Call(holder, arraysize(args), args);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename R, typename P1, typename P2, typename P3, typename P4>
|
||||
struct V8FunctionInvoker<R(P1, P2, P3, P4)> {
|
||||
static R Go(v8::Isolate* isolate, SafeV8Function function, P1 a1, P2 a2,
|
||||
P3 a3, P4 a4) {
|
||||
R ret;
|
||||
atom::BrowserV8Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Handle<v8::Function> holder = function->NewHandle();
|
||||
v8::Handle<v8::Value> args[] = {
|
||||
ConvertToV8(isolate, a1),
|
||||
ConvertToV8(isolate, a2),
|
||||
ConvertToV8(isolate, a3),
|
||||
ConvertToV8(isolate, a4),
|
||||
};
|
||||
v8::Handle<v8::Value> val(holder->Call(holder, arraysize(args), args));
|
||||
Converter<R>::FromV8(isolate, val, &ret);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename P1, typename P2, typename P3, typename P4>
|
||||
struct V8FunctionInvoker<void(P1, P2, P3, P4)> {
|
||||
static void Go(v8::Isolate* isolate, SafeV8Function function, P1 a1, P2 a2,
|
||||
P3 a3, P4 a4) {
|
||||
atom::BrowserV8Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Handle<v8::Function> holder = function->NewHandle();
|
||||
v8::Handle<v8::Value> args[] = {
|
||||
ConvertToV8(isolate, a1),
|
||||
ConvertToV8(isolate, a2),
|
||||
ConvertToV8(isolate, a3),
|
||||
ConvertToV8(isolate, a4),
|
||||
};
|
||||
holder->Call(holder, arraysize(args), args);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template<typename Sig>
|
||||
struct Converter<base::Callback<Sig> > {
|
||||
static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const base::Callback<Sig>& val) {
|
||||
return CreateFunctionTemplate(isolate, val)->GetFunction();
|
||||
}
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Handle<v8::Value> val,
|
||||
base::Callback<Sig>* out) {
|
||||
if (!val->IsFunction())
|
||||
return false;
|
||||
|
||||
internal::SafeV8Function function(
|
||||
new RefCountedPersistent<v8::Function>(val));
|
||||
*out = base::Bind(&internal::V8FunctionInvoker<Sig>::Go, isolate, function);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_FUNCTION_CONVERTER_H_
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "atom/common/native_mate_converters/image_converter.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "base/file_util.h"
|
||||
@@ -18,12 +19,83 @@ namespace mate {
|
||||
|
||||
namespace {
|
||||
|
||||
ui::ScaleFactor GetScaleFactorFromFileName(const base::FilePath& path) {
|
||||
struct ScaleFactorPair {
|
||||
const char* name;
|
||||
float scale;
|
||||
};
|
||||
|
||||
ScaleFactorPair kScaleFactorPairs[] = {
|
||||
// The "@2x" is put as first one to make scale matching faster.
|
||||
{ "@2x" , 2.0f },
|
||||
{ "@3x" , 3.0f },
|
||||
{ "@1x" , 1.0f },
|
||||
{ "@1.25x" , 1.25f },
|
||||
{ "@1.33x" , 1.33f },
|
||||
{ "@1.4x" , 1.4f },
|
||||
{ "@1.5x" , 1.5f },
|
||||
{ "@1.8x" , 1.8f },
|
||||
{ "@2.5x" , 2.5f },
|
||||
};
|
||||
|
||||
float GetScaleFactorFromPath(const base::FilePath& path) {
|
||||
std::string filename(path.BaseName().RemoveExtension().AsUTF8Unsafe());
|
||||
if (EndsWith(filename, "@2x", true))
|
||||
return ui::SCALE_FACTOR_200P;
|
||||
else
|
||||
return ui::SCALE_FACTOR_100P;
|
||||
|
||||
// There is no scale info in the file path.
|
||||
if (!EndsWith(filename, "x", true))
|
||||
return 1.0f;
|
||||
|
||||
// We don't try to convert string to float here because it is very very
|
||||
// expensive.
|
||||
for (unsigned i = 0; i < arraysize(kScaleFactorPairs); ++i) {
|
||||
if (EndsWith(filename, kScaleFactorPairs[i].name, true))
|
||||
return kScaleFactorPairs[i].scale;
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
void AppendIfExists(std::vector<base::FilePath>* paths,
|
||||
const base::FilePath& path) {
|
||||
if (base::PathExists(path))
|
||||
paths->push_back(path);
|
||||
}
|
||||
|
||||
void PopulatePossibleFilePaths(std::vector<base::FilePath>* paths,
|
||||
const base::FilePath& path) {
|
||||
AppendIfExists(paths, path);
|
||||
|
||||
std::string filename(path.BaseName().RemoveExtension().AsUTF8Unsafe());
|
||||
if (MatchPattern(filename, "*@*x"))
|
||||
return;
|
||||
|
||||
for (unsigned i = 0; i < arraysize(kScaleFactorPairs); ++i)
|
||||
AppendIfExists(paths,
|
||||
path.InsertBeforeExtensionASCII(kScaleFactorPairs[i].name));
|
||||
}
|
||||
|
||||
bool AddImageSkiaRepFromPath(gfx::ImageSkia* image,
|
||||
const base::FilePath& path) {
|
||||
std::string file_contents;
|
||||
if (!base::ReadFileToString(path, &file_contents))
|
||||
return false;
|
||||
|
||||
const unsigned char* data =
|
||||
reinterpret_cast<const unsigned char*>(file_contents.data());
|
||||
size_t size = file_contents.size();
|
||||
scoped_ptr<SkBitmap> decoded(new SkBitmap());
|
||||
|
||||
// Try PNG first.
|
||||
if (!gfx::PNGCodec::Decode(data, size, decoded.get()))
|
||||
// Try JPEG.
|
||||
decoded.reset(gfx::JPEGCodec::Decode(data, size));
|
||||
|
||||
if (decoded) {
|
||||
image->AddRepresentation(gfx::ImageSkiaRep(
|
||||
*decoded.release(), GetScaleFactorFromPath(path)));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -33,25 +105,16 @@ bool Converter<gfx::ImageSkia>::FromV8(v8::Isolate* isolate,
|
||||
gfx::ImageSkia* out) {
|
||||
base::FilePath path;
|
||||
if (Converter<base::FilePath>::FromV8(isolate, val, &path)) {
|
||||
std::string file_contents;
|
||||
if (!base::ReadFileToString(path, &file_contents))
|
||||
std::vector<base::FilePath> paths;
|
||||
PopulatePossibleFilePaths(&paths, path);
|
||||
if (paths.empty())
|
||||
return false;
|
||||
|
||||
const unsigned char* data =
|
||||
reinterpret_cast<const unsigned char*>(file_contents.data());
|
||||
size_t size = file_contents.size();
|
||||
scoped_ptr<SkBitmap> decoded(new SkBitmap());
|
||||
|
||||
// Try PNG first.
|
||||
if (!gfx::PNGCodec::Decode(data, size, decoded.get()))
|
||||
// Try JPEG.
|
||||
decoded.reset(gfx::JPEGCodec::Decode(data, size));
|
||||
|
||||
if (decoded) {
|
||||
*out = gfx::ImageSkia(gfx::ImageSkiaRep(*decoded.release(),
|
||||
GetScaleFactorFromFileName(path)));
|
||||
return true;
|
||||
for (size_t i = 0; i < paths.size(); ++i) {
|
||||
if (!AddImageSkiaRepFromPath(out, paths[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/common/browser_v8_locker.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/base_paths.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/message_loop/message_loop.h"
|
||||
#include "base/path_service.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "native_mate/locker.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
@@ -61,10 +61,12 @@ REFERENCE_MODULE(uv);
|
||||
// Atom Shell's builtin modules.
|
||||
REFERENCE_MODULE(atom_browser_app);
|
||||
REFERENCE_MODULE(atom_browser_auto_updater);
|
||||
REFERENCE_MODULE(atom_browser_content_tracing);
|
||||
REFERENCE_MODULE(atom_browser_dialog);
|
||||
REFERENCE_MODULE(atom_browser_menu);
|
||||
REFERENCE_MODULE(atom_browser_power_monitor);
|
||||
REFERENCE_MODULE(atom_browser_protocol);
|
||||
REFERENCE_MODULE(atom_browser_global_shortcut);
|
||||
REFERENCE_MODULE(atom_browser_tray);
|
||||
REFERENCE_MODULE(atom_browser_window);
|
||||
REFERENCE_MODULE(atom_common_clipboard);
|
||||
@@ -244,7 +246,7 @@ void NodeBindings::UvRunOnce() {
|
||||
node::Environment* env = uv_env() ? uv_env() : global_env;
|
||||
|
||||
// Use Locker in browser process.
|
||||
BrowserV8Locker locker(env->isolate());
|
||||
mate::Locker locker(env->isolate());
|
||||
v8::HandleScope handle_scope(env->isolate());
|
||||
|
||||
// Enter node context while dealing with uv events.
|
||||
|
||||
@@ -48,6 +48,12 @@ const char kWebPreferences[] = "web-preferences";
|
||||
// The factor of which page should be zoomed.
|
||||
const char kZoomFactor[] = "zoom-factor";
|
||||
|
||||
// The menu bar is hidden unless "Alt" is pressed.
|
||||
const char kAutoHideMenuBar[] = "auto-hide-menu-bar";
|
||||
|
||||
// Enable window to be resized larger than screen.
|
||||
const char kEnableLargerThanScreen[] = "enable-larger-than-screen";
|
||||
|
||||
} // namespace switches
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -32,6 +32,8 @@ extern const char kAcceptFirstMouse[];
|
||||
extern const char kUseContentSize[];
|
||||
extern const char kWebPreferences[];
|
||||
extern const char kZoomFactor[];
|
||||
extern const char kAutoHideMenuBar[];
|
||||
extern const char kEnableLargerThanScreen[];
|
||||
|
||||
} // namespace switches
|
||||
|
||||
|
||||
@@ -7,19 +7,19 @@
|
||||
#include "atom/common/native_mate_converters/value_converter.h"
|
||||
#include "content/public/renderer/render_view.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "third_party/WebKit/public/web/WebFrame.h"
|
||||
#include "third_party/WebKit/public/web/WebLocalFrame.h"
|
||||
#include "third_party/WebKit/public/web/WebView.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
using content::RenderView;
|
||||
using blink::WebFrame;
|
||||
using blink::WebLocalFrame;
|
||||
using blink::WebView;
|
||||
|
||||
namespace {
|
||||
|
||||
RenderView* GetCurrentRenderView() {
|
||||
WebFrame* frame = WebFrame::frameForCurrentContext();
|
||||
WebLocalFrame* frame = WebLocalFrame::frameForCurrentContext();
|
||||
if (!frame)
|
||||
return NULL;
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/object_template_builder.h"
|
||||
#include "third_party/WebKit/public/web/WebFrame.h"
|
||||
#include "third_party/WebKit/public/web/WebLocalFrame.h"
|
||||
#include "third_party/WebKit/public/web/WebView.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
@@ -18,7 +18,7 @@ namespace api {
|
||||
namespace {
|
||||
|
||||
blink::WebView* GetCurrentWebView() {
|
||||
blink::WebFrame* frame = blink::WebFrame::frameForCurrentContext();
|
||||
blink::WebLocalFrame* frame = blink::WebLocalFrame::frameForCurrentContext();
|
||||
if (!frame)
|
||||
return NULL;
|
||||
return frame->view();
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "third_party/WebKit/public/web/WebDraggableRegion.h"
|
||||
#include "third_party/WebKit/public/web/WebDocument.h"
|
||||
#include "third_party/WebKit/public/web/WebFrame.h"
|
||||
#include "third_party/WebKit/public/web/WebLocalFrame.h"
|
||||
#include "third_party/WebKit/public/web/WebView.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
@@ -36,7 +37,8 @@ AtomRenderViewObserver::AtomRenderViewObserver(
|
||||
AtomRenderViewObserver::~AtomRenderViewObserver() {
|
||||
}
|
||||
|
||||
void AtomRenderViewObserver::DidCreateDocumentElement(blink::WebFrame* frame) {
|
||||
void AtomRenderViewObserver::DidCreateDocumentElement(
|
||||
blink::WebLocalFrame* frame) {
|
||||
// Read --zoom-factor from command line.
|
||||
std::string zoom_factor_str = CommandLine::ForCurrentProcess()->
|
||||
GetSwitchValueASCII(switches::kZoomFactor);;
|
||||
|
||||
@@ -25,7 +25,7 @@ class AtomRenderViewObserver : public content::RenderViewObserver {
|
||||
|
||||
private:
|
||||
// content::RenderViewObserver implementation.
|
||||
virtual void DidCreateDocumentElement(blink::WebFrame* frame) OVERRIDE;
|
||||
virtual void DidCreateDocumentElement(blink::WebLocalFrame* frame) OVERRIDE;
|
||||
virtual void DraggableRegionsChanged(blink::WebFrame* frame) OVERRIDE;
|
||||
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
|
||||
|
||||
|
||||
@@ -70,6 +70,10 @@ AtomRendererClient::AtomRendererClient()
|
||||
node_integration_ = ALL;
|
||||
|
||||
if (IsNodeBindingEnabled()) {
|
||||
// Always enable harmony when node binding is on.
|
||||
std::string flags("--harmony");
|
||||
v8::V8::SetFlagsFromString(flags.c_str(), static_cast<int>(flags.size()));
|
||||
|
||||
node_bindings_.reset(NodeBindings::Create(false));
|
||||
atom_bindings_.reset(new AtomRendererBindings);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/extensions/global_shortcut_listener.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "ui/base/accelerators/accelerator.h"
|
||||
|
||||
using content::BrowserThread;
|
||||
|
||||
namespace extensions {
|
||||
|
||||
GlobalShortcutListener::GlobalShortcutListener()
|
||||
: shortcut_handling_suspended_(false) {
|
||||
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||
}
|
||||
|
||||
GlobalShortcutListener::~GlobalShortcutListener() {
|
||||
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||
DCHECK(accelerator_map_.empty()); // Make sure we've cleaned up.
|
||||
}
|
||||
|
||||
bool GlobalShortcutListener::RegisterAccelerator(
|
||||
const ui::Accelerator& accelerator, Observer* observer) {
|
||||
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||
if (IsShortcutHandlingSuspended())
|
||||
return false;
|
||||
|
||||
AcceleratorMap::const_iterator it = accelerator_map_.find(accelerator);
|
||||
if (it != accelerator_map_.end()) {
|
||||
// The accelerator has been registered.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!RegisterAcceleratorImpl(accelerator)) {
|
||||
// If the platform-specific registration fails, mostly likely the shortcut
|
||||
// has been registered by other native applications.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (accelerator_map_.empty())
|
||||
StartListening();
|
||||
|
||||
accelerator_map_[accelerator] = observer;
|
||||
return true;
|
||||
}
|
||||
|
||||
void GlobalShortcutListener::UnregisterAccelerator(
|
||||
const ui::Accelerator& accelerator, Observer* observer) {
|
||||
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||
if (IsShortcutHandlingSuspended())
|
||||
return;
|
||||
|
||||
AcceleratorMap::iterator it = accelerator_map_.find(accelerator);
|
||||
// We should never get asked to unregister something that we didn't register.
|
||||
DCHECK(it != accelerator_map_.end());
|
||||
// The caller should call this function with the right observer.
|
||||
DCHECK(it->second == observer);
|
||||
|
||||
UnregisterAcceleratorImpl(accelerator);
|
||||
accelerator_map_.erase(it);
|
||||
if (accelerator_map_.empty())
|
||||
StopListening();
|
||||
}
|
||||
|
||||
void GlobalShortcutListener::UnregisterAccelerators(Observer* observer) {
|
||||
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||
if (IsShortcutHandlingSuspended())
|
||||
return;
|
||||
|
||||
AcceleratorMap::iterator it = accelerator_map_.begin();
|
||||
while (it != accelerator_map_.end()) {
|
||||
if (it->second == observer) {
|
||||
AcceleratorMap::iterator to_remove = it++;
|
||||
UnregisterAccelerator(to_remove->first, observer);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GlobalShortcutListener::SetShortcutHandlingSuspended(bool suspended) {
|
||||
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||
if (shortcut_handling_suspended_ == suspended)
|
||||
return;
|
||||
|
||||
shortcut_handling_suspended_ = suspended;
|
||||
for (AcceleratorMap::iterator it = accelerator_map_.begin();
|
||||
it != accelerator_map_.end();
|
||||
++it) {
|
||||
// On Linux, when shortcut handling is suspended we cannot simply early
|
||||
// return in NotifyKeyPressed (similar to what we do for non-global
|
||||
// shortcuts) because we'd eat the keyboard event thereby preventing the
|
||||
// user from setting the shortcut. Therefore we must unregister while
|
||||
// handling is suspended and register when handling resumes.
|
||||
if (shortcut_handling_suspended_)
|
||||
UnregisterAcceleratorImpl(it->first);
|
||||
else
|
||||
RegisterAcceleratorImpl(it->first);
|
||||
}
|
||||
}
|
||||
|
||||
bool GlobalShortcutListener::IsShortcutHandlingSuspended() const {
|
||||
return shortcut_handling_suspended_;
|
||||
}
|
||||
|
||||
void GlobalShortcutListener::NotifyKeyPressed(
|
||||
const ui::Accelerator& accelerator) {
|
||||
AcceleratorMap::iterator iter = accelerator_map_.find(accelerator);
|
||||
if (iter == accelerator_map_.end()) {
|
||||
// This should never occur, because if it does, we have failed to unregister
|
||||
// or failed to clean up the map after unregistering the shortcut.
|
||||
NOTREACHED();
|
||||
return; // No-one is listening to this key.
|
||||
}
|
||||
|
||||
iter->second->OnKeyPressed(accelerator);
|
||||
}
|
||||
|
||||
} // namespace extensions
|
||||
@@ -0,0 +1,99 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_H_
|
||||
#define CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_H_
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "ui/events/keycodes/keyboard_codes.h"
|
||||
|
||||
namespace ui {
|
||||
class Accelerator;
|
||||
}
|
||||
|
||||
namespace extensions {
|
||||
|
||||
// Platform-neutral implementation of a class that keeps track of observers and
|
||||
// monitors keystrokes. It relays messages to the appropriate observer when a
|
||||
// global shortcut has been struck by the user.
|
||||
class GlobalShortcutListener {
|
||||
public:
|
||||
class Observer {
|
||||
public:
|
||||
// Called when your global shortcut (|accelerator|) is struck.
|
||||
virtual void OnKeyPressed(const ui::Accelerator& accelerator) = 0;
|
||||
};
|
||||
|
||||
virtual ~GlobalShortcutListener();
|
||||
|
||||
static GlobalShortcutListener* GetInstance();
|
||||
|
||||
// Register an observer for when a certain |accelerator| is struck. Returns
|
||||
// true if register successfully, or false if 1) the specificied |accelerator|
|
||||
// has been registered by another caller or other native applications, or
|
||||
// 2) shortcut handling is suspended.
|
||||
//
|
||||
// Note that we do not support recognizing that an accelerator has been
|
||||
// registered by another application on all platforms. This is a per-platform
|
||||
// consideration.
|
||||
bool RegisterAccelerator(const ui::Accelerator& accelerator,
|
||||
Observer* observer);
|
||||
|
||||
// Stop listening for the given |accelerator|, does nothing if shortcut
|
||||
// handling is suspended.
|
||||
void UnregisterAccelerator(const ui::Accelerator& accelerator,
|
||||
Observer* observer);
|
||||
|
||||
// Stop listening for all accelerators of the given |observer|, does nothing
|
||||
// if shortcut handling is suspended.
|
||||
void UnregisterAccelerators(Observer* observer);
|
||||
|
||||
// Suspend/Resume global shortcut handling. Note that when suspending,
|
||||
// RegisterAccelerator/UnregisterAccelerator/UnregisterAccelerators are not
|
||||
// allowed to be called until shortcut handling has been resumed.
|
||||
void SetShortcutHandlingSuspended(bool suspended);
|
||||
|
||||
// Returns whether shortcut handling is currently suspended.
|
||||
bool IsShortcutHandlingSuspended() const;
|
||||
|
||||
protected:
|
||||
GlobalShortcutListener();
|
||||
|
||||
// Called by platform specific implementations of this class whenever a key
|
||||
// is struck. Only called for keys that have an observer registered.
|
||||
void NotifyKeyPressed(const ui::Accelerator& accelerator);
|
||||
|
||||
private:
|
||||
// The following methods are implemented by platform-specific implementations
|
||||
// of this class.
|
||||
//
|
||||
// Start/StopListening are called when transitioning between zero and nonzero
|
||||
// registered accelerators. StartListening will be called after
|
||||
// RegisterAcceleratorImpl and StopListening will be called after
|
||||
// UnregisterAcceleratorImpl.
|
||||
//
|
||||
// For RegisterAcceleratorImpl, implementations return false if registration
|
||||
// did not complete successfully.
|
||||
virtual void StartListening() = 0;
|
||||
virtual void StopListening() = 0;
|
||||
virtual bool RegisterAcceleratorImpl(const ui::Accelerator& accelerator) = 0;
|
||||
virtual void UnregisterAcceleratorImpl(
|
||||
const ui::Accelerator& accelerator) = 0;
|
||||
|
||||
// The map of accelerators that have been successfully registered as global
|
||||
// shortcuts and their observer.
|
||||
typedef std::map<ui::Accelerator, Observer*> AcceleratorMap;
|
||||
AcceleratorMap accelerator_map_;
|
||||
|
||||
// Keeps track of whether shortcut handling is currently suspended.
|
||||
bool shortcut_handling_suspended_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(GlobalShortcutListener);
|
||||
};
|
||||
|
||||
} // namespace extensions
|
||||
|
||||
#endif // CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_H_
|
||||
@@ -0,0 +1,106 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_MAC_H_
|
||||
#define CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_MAC_H_
|
||||
|
||||
#include "chrome/browser/extensions/global_shortcut_listener.h"
|
||||
|
||||
#include <Carbon/Carbon.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "base/mac/scoped_nsobject.h"
|
||||
|
||||
namespace extensions {
|
||||
|
||||
// Mac-specific implementation of the GlobalShortcutListener class that
|
||||
// listens for global shortcuts. Handles basic keyboard intercepting and
|
||||
// forwards its output to the base class for processing.
|
||||
//
|
||||
// This class does two things:
|
||||
// 1. Intercepts media keys. Uses an event tap for intercepting media keys
|
||||
// (PlayPause, NextTrack, PreviousTrack).
|
||||
// 2. Binds keyboard shortcuts (hot keys). Carbon RegisterEventHotKey API for
|
||||
// binding to non-media key global hot keys (eg. Command-Shift-1).
|
||||
class GlobalShortcutListenerMac : public GlobalShortcutListener {
|
||||
public:
|
||||
GlobalShortcutListenerMac();
|
||||
virtual ~GlobalShortcutListenerMac();
|
||||
|
||||
private:
|
||||
typedef int KeyId;
|
||||
typedef std::map<ui::Accelerator, KeyId> AcceleratorIdMap;
|
||||
typedef std::map<KeyId, ui::Accelerator> IdAcceleratorMap;
|
||||
typedef std::map<KeyId, EventHotKeyRef> IdHotKeyRefMap;
|
||||
|
||||
// Keyboard event callbacks.
|
||||
void OnHotKeyEvent(EventHotKeyID hot_key_id);
|
||||
bool OnMediaKeyEvent(int key_code);
|
||||
|
||||
// GlobalShortcutListener implementation.
|
||||
virtual void StartListening() OVERRIDE;
|
||||
virtual void StopListening() OVERRIDE;
|
||||
virtual bool RegisterAcceleratorImpl(
|
||||
const ui::Accelerator& accelerator) OVERRIDE;
|
||||
virtual void UnregisterAcceleratorImpl(
|
||||
const ui::Accelerator& accelerator) OVERRIDE;
|
||||
|
||||
// Mac-specific functions for registering hot keys with modifiers.
|
||||
bool RegisterHotKey(const ui::Accelerator& accelerator, KeyId hot_key_id);
|
||||
void UnregisterHotKey(const ui::Accelerator& accelerator);
|
||||
|
||||
// Enable and disable the media key event tap.
|
||||
void StartWatchingMediaKeys();
|
||||
void StopWatchingMediaKeys();
|
||||
|
||||
// Enable and disable the hot key event handler.
|
||||
void StartWatchingHotKeys();
|
||||
void StopWatchingHotKeys();
|
||||
|
||||
// Whether or not any media keys are currently registered.
|
||||
bool IsAnyMediaKeyRegistered();
|
||||
|
||||
// Whether or not any hot keys are currently registered.
|
||||
bool IsAnyHotKeyRegistered();
|
||||
|
||||
// The callback for when an event tap happens.
|
||||
static CGEventRef EventTapCallback(
|
||||
CGEventTapProxy proxy, CGEventType type, CGEventRef event, void* refcon);
|
||||
|
||||
// The callback for when a hot key event happens.
|
||||
static OSStatus HotKeyHandler(
|
||||
EventHandlerCallRef next_handler, EventRef event, void* user_data);
|
||||
|
||||
// Whether this object is listening for global shortcuts.
|
||||
bool is_listening_;
|
||||
|
||||
// The hotkey identifier for the next global shortcut that is added.
|
||||
KeyId hot_key_id_;
|
||||
|
||||
// A map of all hotkeys (media keys and shortcuts) mapping to their
|
||||
// corresponding hotkey IDs. For quickly finding if an accelerator is
|
||||
// registered.
|
||||
AcceleratorIdMap accelerator_ids_;
|
||||
|
||||
// The inverse map for quickly looking up accelerators by hotkey id.
|
||||
IdAcceleratorMap id_accelerators_;
|
||||
|
||||
// Keyboard shortcut IDs to hotkeys map for unregistration.
|
||||
IdHotKeyRefMap id_hot_key_refs_;
|
||||
|
||||
// Event tap for intercepting mac media keys.
|
||||
CFMachPortRef event_tap_;
|
||||
CFRunLoopSourceRef event_tap_source_;
|
||||
|
||||
// Event handler for keyboard shortcut hot keys.
|
||||
EventHandlerRef event_handler_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(GlobalShortcutListenerMac);
|
||||
};
|
||||
|
||||
} // namespace extensions
|
||||
|
||||
#endif // CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_MAC_H_
|
||||
@@ -0,0 +1,383 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/extensions/global_shortcut_listener_mac.h"
|
||||
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#include <IOKit/hidsystem/ev_keymap.h>
|
||||
|
||||
#import "base/mac/foundation_util.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "ui/base/accelerators/accelerator.h"
|
||||
#include "ui/events/event.h"
|
||||
#import "ui/events/keycodes/keyboard_code_conversion_mac.h"
|
||||
|
||||
using content::BrowserThread;
|
||||
using extensions::GlobalShortcutListenerMac;
|
||||
|
||||
namespace {
|
||||
|
||||
// The media keys subtype. No official docs found, but widely known.
|
||||
// http://lists.apple.com/archives/cocoa-dev/2007/Aug/msg00499.html
|
||||
const int kSystemDefinedEventMediaKeysSubtype = 8;
|
||||
|
||||
ui::KeyboardCode MediaKeyCodeToKeyboardCode(int key_code) {
|
||||
switch (key_code) {
|
||||
case NX_KEYTYPE_PLAY:
|
||||
return ui::VKEY_MEDIA_PLAY_PAUSE;
|
||||
case NX_KEYTYPE_PREVIOUS:
|
||||
case NX_KEYTYPE_REWIND:
|
||||
return ui::VKEY_MEDIA_PREV_TRACK;
|
||||
case NX_KEYTYPE_NEXT:
|
||||
case NX_KEYTYPE_FAST:
|
||||
return ui::VKEY_MEDIA_NEXT_TRACK;
|
||||
}
|
||||
return ui::VKEY_UNKNOWN;
|
||||
}
|
||||
|
||||
bool IsMediaKey(const ui::Accelerator& accelerator) {
|
||||
if (accelerator.modifiers() != 0)
|
||||
return false;
|
||||
return (accelerator.key_code() == ui::VKEY_MEDIA_NEXT_TRACK ||
|
||||
accelerator.key_code() == ui::VKEY_MEDIA_PREV_TRACK ||
|
||||
accelerator.key_code() == ui::VKEY_MEDIA_PLAY_PAUSE ||
|
||||
accelerator.key_code() == ui::VKEY_MEDIA_STOP);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace extensions {
|
||||
|
||||
// static
|
||||
GlobalShortcutListener* GlobalShortcutListener::GetInstance() {
|
||||
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||
static GlobalShortcutListenerMac* instance =
|
||||
new GlobalShortcutListenerMac();
|
||||
return instance;
|
||||
}
|
||||
|
||||
GlobalShortcutListenerMac::GlobalShortcutListenerMac()
|
||||
: is_listening_(false),
|
||||
hot_key_id_(0),
|
||||
event_tap_(NULL),
|
||||
event_tap_source_(NULL),
|
||||
event_handler_(NULL) {
|
||||
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||
}
|
||||
|
||||
GlobalShortcutListenerMac::~GlobalShortcutListenerMac() {
|
||||
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||
|
||||
// By this point, UnregisterAccelerator should have been called for all
|
||||
// keyboard shortcuts. Still we should clean up.
|
||||
if (is_listening_)
|
||||
StopListening();
|
||||
|
||||
// If keys are still registered, make sure we stop the tap. Again, this
|
||||
// should never happen.
|
||||
if (IsAnyMediaKeyRegistered())
|
||||
StopWatchingMediaKeys();
|
||||
|
||||
if (IsAnyHotKeyRegistered())
|
||||
StopWatchingHotKeys();
|
||||
}
|
||||
|
||||
void GlobalShortcutListenerMac::StartListening() {
|
||||
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||
|
||||
DCHECK(!accelerator_ids_.empty());
|
||||
DCHECK(!id_accelerators_.empty());
|
||||
DCHECK(!is_listening_);
|
||||
|
||||
is_listening_ = true;
|
||||
}
|
||||
|
||||
void GlobalShortcutListenerMac::StopListening() {
|
||||
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||
|
||||
DCHECK(accelerator_ids_.empty()); // Make sure the set is clean.
|
||||
DCHECK(id_accelerators_.empty());
|
||||
DCHECK(is_listening_);
|
||||
|
||||
is_listening_ = false;
|
||||
}
|
||||
|
||||
void GlobalShortcutListenerMac::OnHotKeyEvent(EventHotKeyID hot_key_id) {
|
||||
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||
|
||||
// This hot key should be registered.
|
||||
DCHECK(id_accelerators_.find(hot_key_id.id) != id_accelerators_.end());
|
||||
// Look up the accelerator based on this hot key ID.
|
||||
const ui::Accelerator& accelerator = id_accelerators_[hot_key_id.id];
|
||||
NotifyKeyPressed(accelerator);
|
||||
}
|
||||
|
||||
bool GlobalShortcutListenerMac::OnMediaKeyEvent(int media_key_code) {
|
||||
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||
ui::KeyboardCode key_code = MediaKeyCodeToKeyboardCode(media_key_code);
|
||||
// Create an accelerator corresponding to the keyCode.
|
||||
ui::Accelerator accelerator(key_code, 0);
|
||||
// Look for a match with a bound hot_key.
|
||||
if (accelerator_ids_.find(accelerator) != accelerator_ids_.end()) {
|
||||
// If matched, callback to the event handling system.
|
||||
NotifyKeyPressed(accelerator);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GlobalShortcutListenerMac::RegisterAcceleratorImpl(
|
||||
const ui::Accelerator& accelerator) {
|
||||
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||
DCHECK(accelerator_ids_.find(accelerator) == accelerator_ids_.end());
|
||||
|
||||
if (IsMediaKey(accelerator)) {
|
||||
if (!IsAnyMediaKeyRegistered()) {
|
||||
// If this is the first media key registered, start the event tap.
|
||||
StartWatchingMediaKeys();
|
||||
}
|
||||
} else {
|
||||
// Register hot_key if they are non-media keyboard shortcuts.
|
||||
if (!RegisterHotKey(accelerator, hot_key_id_))
|
||||
return false;
|
||||
|
||||
if (!IsAnyHotKeyRegistered()) {
|
||||
StartWatchingHotKeys();
|
||||
}
|
||||
}
|
||||
|
||||
// Store the hotkey-ID mappings we will need for lookup later.
|
||||
id_accelerators_[hot_key_id_] = accelerator;
|
||||
accelerator_ids_[accelerator] = hot_key_id_;
|
||||
++hot_key_id_;
|
||||
return true;
|
||||
}
|
||||
|
||||
void GlobalShortcutListenerMac::UnregisterAcceleratorImpl(
|
||||
const ui::Accelerator& accelerator) {
|
||||
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||
DCHECK(accelerator_ids_.find(accelerator) != accelerator_ids_.end());
|
||||
|
||||
// Unregister the hot_key if it's a keyboard shortcut.
|
||||
if (!IsMediaKey(accelerator))
|
||||
UnregisterHotKey(accelerator);
|
||||
|
||||
// Remove hot_key from the mappings.
|
||||
KeyId key_id = accelerator_ids_[accelerator];
|
||||
id_accelerators_.erase(key_id);
|
||||
accelerator_ids_.erase(accelerator);
|
||||
|
||||
if (IsMediaKey(accelerator)) {
|
||||
// If we unregistered a media key, and now no media keys are registered,
|
||||
// stop the media key tap.
|
||||
if (!IsAnyMediaKeyRegistered())
|
||||
StopWatchingMediaKeys();
|
||||
} else {
|
||||
// If we unregistered a hot key, and no more hot keys are registered, remove
|
||||
// the hot key handler.
|
||||
if (!IsAnyHotKeyRegistered()) {
|
||||
StopWatchingHotKeys();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GlobalShortcutListenerMac::RegisterHotKey(
|
||||
const ui::Accelerator& accelerator, KeyId hot_key_id) {
|
||||
EventHotKeyID event_hot_key_id;
|
||||
|
||||
// Signature uniquely identifies the application that owns this hot_key.
|
||||
event_hot_key_id.signature = base::mac::CreatorCodeForApplication();
|
||||
event_hot_key_id.id = hot_key_id;
|
||||
|
||||
// Translate ui::Accelerator modifiers to cmdKey, altKey, etc.
|
||||
int modifiers = 0;
|
||||
modifiers |= (accelerator.IsShiftDown() ? shiftKey : 0);
|
||||
modifiers |= (accelerator.IsCtrlDown() ? controlKey : 0);
|
||||
modifiers |= (accelerator.IsAltDown() ? optionKey : 0);
|
||||
modifiers |= (accelerator.IsCmdDown() ? cmdKey : 0);
|
||||
|
||||
int key_code = ui::MacKeyCodeForWindowsKeyCode(accelerator.key_code(), 0,
|
||||
NULL, NULL);
|
||||
|
||||
// Register the event hot key.
|
||||
EventHotKeyRef hot_key_ref;
|
||||
OSStatus status = RegisterEventHotKey(key_code, modifiers, event_hot_key_id,
|
||||
GetApplicationEventTarget(), 0, &hot_key_ref);
|
||||
if (status != noErr)
|
||||
return false;
|
||||
|
||||
id_hot_key_refs_[hot_key_id] = hot_key_ref;
|
||||
return true;
|
||||
}
|
||||
|
||||
void GlobalShortcutListenerMac::UnregisterHotKey(
|
||||
const ui::Accelerator& accelerator) {
|
||||
// Ensure this accelerator is already registered.
|
||||
DCHECK(accelerator_ids_.find(accelerator) != accelerator_ids_.end());
|
||||
// Get the ref corresponding to this accelerator.
|
||||
KeyId key_id = accelerator_ids_[accelerator];
|
||||
EventHotKeyRef ref = id_hot_key_refs_[key_id];
|
||||
// Unregister the event hot key.
|
||||
UnregisterEventHotKey(ref);
|
||||
|
||||
// Remove the event from the mapping.
|
||||
id_hot_key_refs_.erase(key_id);
|
||||
}
|
||||
|
||||
void GlobalShortcutListenerMac::StartWatchingMediaKeys() {
|
||||
// Make sure there's no existing event tap.
|
||||
DCHECK(event_tap_ == NULL);
|
||||
DCHECK(event_tap_source_ == NULL);
|
||||
|
||||
// Add an event tap to intercept the system defined media key events.
|
||||
event_tap_ = CGEventTapCreate(kCGSessionEventTap,
|
||||
kCGHeadInsertEventTap,
|
||||
kCGEventTapOptionDefault,
|
||||
CGEventMaskBit(NX_SYSDEFINED),
|
||||
EventTapCallback,
|
||||
this);
|
||||
if (event_tap_ == NULL) {
|
||||
LOG(ERROR) << "Error: failed to create event tap.";
|
||||
return;
|
||||
}
|
||||
|
||||
event_tap_source_ = CFMachPortCreateRunLoopSource(kCFAllocatorSystemDefault,
|
||||
event_tap_, 0);
|
||||
if (event_tap_source_ == NULL) {
|
||||
LOG(ERROR) << "Error: failed to create new run loop source.";
|
||||
return;
|
||||
}
|
||||
|
||||
CFRunLoopAddSource(CFRunLoopGetCurrent(), event_tap_source_,
|
||||
kCFRunLoopCommonModes);
|
||||
}
|
||||
|
||||
void GlobalShortcutListenerMac::StopWatchingMediaKeys() {
|
||||
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), event_tap_source_,
|
||||
kCFRunLoopCommonModes);
|
||||
// Ensure both event tap and source are initialized.
|
||||
DCHECK(event_tap_ != NULL);
|
||||
DCHECK(event_tap_source_ != NULL);
|
||||
|
||||
// Invalidate the event tap.
|
||||
CFMachPortInvalidate(event_tap_);
|
||||
CFRelease(event_tap_);
|
||||
event_tap_ = NULL;
|
||||
|
||||
// Release the event tap source.
|
||||
CFRelease(event_tap_source_);
|
||||
event_tap_source_ = NULL;
|
||||
}
|
||||
|
||||
void GlobalShortcutListenerMac::StartWatchingHotKeys() {
|
||||
DCHECK(!event_handler_);
|
||||
EventHandlerUPP hot_key_function = NewEventHandlerUPP(HotKeyHandler);
|
||||
EventTypeSpec event_type;
|
||||
event_type.eventClass = kEventClassKeyboard;
|
||||
event_type.eventKind = kEventHotKeyPressed;
|
||||
InstallApplicationEventHandler(
|
||||
hot_key_function, 1, &event_type, this, &event_handler_);
|
||||
}
|
||||
|
||||
void GlobalShortcutListenerMac::StopWatchingHotKeys() {
|
||||
DCHECK(event_handler_);
|
||||
RemoveEventHandler(event_handler_);
|
||||
event_handler_ = NULL;
|
||||
}
|
||||
|
||||
bool GlobalShortcutListenerMac::IsAnyMediaKeyRegistered() {
|
||||
// Iterate through registered accelerators, looking for media keys.
|
||||
AcceleratorIdMap::iterator it;
|
||||
for (it = accelerator_ids_.begin(); it != accelerator_ids_.end(); ++it) {
|
||||
if (IsMediaKey(it->first))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GlobalShortcutListenerMac::IsAnyHotKeyRegistered() {
|
||||
AcceleratorIdMap::iterator it;
|
||||
for (it = accelerator_ids_.begin(); it != accelerator_ids_.end(); ++it) {
|
||||
if (!IsMediaKey(it->first))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Processed events should propagate if they aren't handled by any listeners.
|
||||
// For events that don't matter, this handler should return as quickly as
|
||||
// possible.
|
||||
// Returning event causes the event to propagate to other applications.
|
||||
// Returning NULL prevents the event from propagating.
|
||||
// static
|
||||
CGEventRef GlobalShortcutListenerMac::EventTapCallback(
|
||||
CGEventTapProxy proxy, CGEventType type, CGEventRef event, void* refcon) {
|
||||
GlobalShortcutListenerMac* shortcut_listener =
|
||||
static_cast<GlobalShortcutListenerMac*>(refcon);
|
||||
|
||||
// Handle the timeout case by re-enabling the tap.
|
||||
if (type == kCGEventTapDisabledByTimeout) {
|
||||
CGEventTapEnable(shortcut_listener->event_tap_, TRUE);
|
||||
return event;
|
||||
}
|
||||
|
||||
// Convert the CGEvent to an NSEvent for access to the data1 field.
|
||||
NSEvent* ns_event = [NSEvent eventWithCGEvent:event];
|
||||
if (ns_event == nil) {
|
||||
return event;
|
||||
}
|
||||
|
||||
// Ignore events that are not system defined media keys.
|
||||
if (type != NX_SYSDEFINED ||
|
||||
[ns_event type] != NSSystemDefined ||
|
||||
[ns_event subtype] != kSystemDefinedEventMediaKeysSubtype) {
|
||||
return event;
|
||||
}
|
||||
|
||||
NSInteger data1 = [ns_event data1];
|
||||
// Ignore media keys that aren't previous, next and play/pause.
|
||||
// Magical constants are from http://weblog.rogueamoeba.com/2007/09/29/
|
||||
int key_code = (data1 & 0xFFFF0000) >> 16;
|
||||
if (key_code != NX_KEYTYPE_PLAY && key_code != NX_KEYTYPE_NEXT &&
|
||||
key_code != NX_KEYTYPE_PREVIOUS && key_code != NX_KEYTYPE_FAST &&
|
||||
key_code != NX_KEYTYPE_REWIND) {
|
||||
return event;
|
||||
}
|
||||
|
||||
int key_flags = data1 & 0x0000FFFF;
|
||||
bool is_key_pressed = ((key_flags & 0xFF00) >> 8) == 0xA;
|
||||
|
||||
// If the key wasn't pressed (eg. was released), ignore this event.
|
||||
if (!is_key_pressed)
|
||||
return event;
|
||||
|
||||
// Now we have a media key that we care about. Send it to the caller.
|
||||
bool was_handled = shortcut_listener->OnMediaKeyEvent(key_code);
|
||||
|
||||
// Prevent event from proagating to other apps if handled by Chrome.
|
||||
if (was_handled)
|
||||
return NULL;
|
||||
|
||||
// By default, pass the event through.
|
||||
return event;
|
||||
}
|
||||
|
||||
// static
|
||||
OSStatus GlobalShortcutListenerMac::HotKeyHandler(
|
||||
EventHandlerCallRef next_handler, EventRef event, void* user_data) {
|
||||
// Extract the hotkey from the event.
|
||||
EventHotKeyID hot_key_id;
|
||||
OSStatus result = GetEventParameter(event, kEventParamDirectObject,
|
||||
typeEventHotKeyID, NULL, sizeof(hot_key_id), NULL, &hot_key_id);
|
||||
if (result != noErr)
|
||||
return result;
|
||||
|
||||
GlobalShortcutListenerMac* shortcut_listener =
|
||||
static_cast<GlobalShortcutListenerMac*>(user_data);
|
||||
shortcut_listener->OnHotKeyEvent(hot_key_id);
|
||||
return noErr;
|
||||
}
|
||||
|
||||
} // namespace extensions
|
||||
@@ -0,0 +1,105 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/extensions/global_shortcut_listener_win.h"
|
||||
|
||||
#include "base/win/win_util.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "ui/base/accelerators/accelerator.h"
|
||||
#include "ui/events/event_constants.h"
|
||||
#include "ui/events/keycodes/keyboard_code_conversion_win.h"
|
||||
|
||||
using content::BrowserThread;
|
||||
|
||||
namespace extensions {
|
||||
|
||||
// static
|
||||
GlobalShortcutListener* GlobalShortcutListener::GetInstance() {
|
||||
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||
static GlobalShortcutListenerWin* instance =
|
||||
new GlobalShortcutListenerWin();
|
||||
return instance;
|
||||
}
|
||||
|
||||
GlobalShortcutListenerWin::GlobalShortcutListenerWin()
|
||||
: is_listening_(false) {
|
||||
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||
}
|
||||
|
||||
GlobalShortcutListenerWin::~GlobalShortcutListenerWin() {
|
||||
if (is_listening_)
|
||||
StopListening();
|
||||
}
|
||||
|
||||
void GlobalShortcutListenerWin::StartListening() {
|
||||
DCHECK(!is_listening_); // Don't start twice.
|
||||
DCHECK(!hotkey_ids_.empty()); // Also don't start if no hotkey is registered.
|
||||
gfx::SingletonHwnd::GetInstance()->AddObserver(this);
|
||||
is_listening_ = true;
|
||||
}
|
||||
|
||||
void GlobalShortcutListenerWin::StopListening() {
|
||||
DCHECK(is_listening_); // No point if we are not already listening.
|
||||
DCHECK(hotkey_ids_.empty()); // Make sure the map is clean before ending.
|
||||
gfx::SingletonHwnd::GetInstance()->RemoveObserver(this);
|
||||
is_listening_ = false;
|
||||
}
|
||||
|
||||
void GlobalShortcutListenerWin::OnWndProc(HWND hwnd,
|
||||
UINT message,
|
||||
WPARAM wparam,
|
||||
LPARAM lparam) {
|
||||
if (message != WM_HOTKEY)
|
||||
return;
|
||||
|
||||
int key_code = HIWORD(lparam);
|
||||
int modifiers = 0;
|
||||
modifiers |= (LOWORD(lparam) & MOD_SHIFT) ? ui::EF_SHIFT_DOWN : 0;
|
||||
modifiers |= (LOWORD(lparam) & MOD_ALT) ? ui::EF_ALT_DOWN : 0;
|
||||
modifiers |= (LOWORD(lparam) & MOD_CONTROL) ? ui::EF_CONTROL_DOWN : 0;
|
||||
ui::Accelerator accelerator(
|
||||
ui::KeyboardCodeForWindowsKeyCode(key_code), modifiers);
|
||||
|
||||
NotifyKeyPressed(accelerator);
|
||||
}
|
||||
|
||||
bool GlobalShortcutListenerWin::RegisterAcceleratorImpl(
|
||||
const ui::Accelerator& accelerator) {
|
||||
DCHECK(hotkey_ids_.find(accelerator) == hotkey_ids_.end());
|
||||
|
||||
int modifiers = 0;
|
||||
modifiers |= accelerator.IsShiftDown() ? MOD_SHIFT : 0;
|
||||
modifiers |= accelerator.IsCtrlDown() ? MOD_CONTROL : 0;
|
||||
modifiers |= accelerator.IsAltDown() ? MOD_ALT : 0;
|
||||
static int hotkey_id = 0;
|
||||
bool success = !!RegisterHotKey(
|
||||
gfx::SingletonHwnd::GetInstance()->hwnd(),
|
||||
hotkey_id,
|
||||
modifiers,
|
||||
accelerator.key_code());
|
||||
|
||||
if (!success) {
|
||||
// Most likely error: 1409 (Hotkey already registered).
|
||||
return false;
|
||||
}
|
||||
|
||||
hotkey_ids_[accelerator] = hotkey_id++;
|
||||
return true;
|
||||
}
|
||||
|
||||
void GlobalShortcutListenerWin::UnregisterAcceleratorImpl(
|
||||
const ui::Accelerator& accelerator) {
|
||||
HotkeyIdMap::iterator it = hotkey_ids_.find(accelerator);
|
||||
DCHECK(it != hotkey_ids_.end());
|
||||
|
||||
bool success = !!UnregisterHotKey(
|
||||
gfx::SingletonHwnd::GetInstance()->hwnd(), it->second);
|
||||
// This call should always succeed, as long as we pass in the right HWND and
|
||||
// an id we've used to register before.
|
||||
DCHECK(success);
|
||||
|
||||
hotkey_ids_.erase(it);
|
||||
}
|
||||
|
||||
} // namespace extensions
|
||||
@@ -0,0 +1,51 @@
|
||||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_WIN_H_
|
||||
#define CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_WIN_H_
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "chrome/browser/extensions/global_shortcut_listener.h"
|
||||
#include "ui/gfx/win/singleton_hwnd.h"
|
||||
|
||||
namespace extensions {
|
||||
|
||||
// Windows-specific implementation of the GlobalShortcutListener class that
|
||||
// listens for global shortcuts. Handles setting up a keyboard hook and
|
||||
// forwarding its output to the base class for processing.
|
||||
class GlobalShortcutListenerWin : public GlobalShortcutListener,
|
||||
public gfx::SingletonHwnd::Observer {
|
||||
public:
|
||||
GlobalShortcutListenerWin();
|
||||
virtual ~GlobalShortcutListenerWin();
|
||||
|
||||
private:
|
||||
// The implementation of our Window Proc, called by SingletonHwnd.
|
||||
virtual void OnWndProc(HWND hwnd,
|
||||
UINT message,
|
||||
WPARAM wparam,
|
||||
LPARAM lparam) OVERRIDE;
|
||||
|
||||
// GlobalShortcutListener implementation.
|
||||
virtual void StartListening() OVERRIDE;
|
||||
virtual void StopListening() OVERRIDE;
|
||||
virtual bool RegisterAcceleratorImpl(
|
||||
const ui::Accelerator& accelerator) OVERRIDE;
|
||||
virtual void UnregisterAcceleratorImpl(
|
||||
const ui::Accelerator& accelerator) OVERRIDE;
|
||||
|
||||
// Whether this object is listening for global shortcuts.
|
||||
bool is_listening_;
|
||||
|
||||
// A map of registered accelerators and their registration ids.
|
||||
typedef std::map<ui::Accelerator, int> HotkeyIdMap;
|
||||
HotkeyIdMap hotkey_ids_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(GlobalShortcutListenerWin);
|
||||
};
|
||||
|
||||
} // namespace extensions
|
||||
|
||||
#endif // CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_WIN_H_
|
||||
@@ -0,0 +1,158 @@
|
||||
// Copyright 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/extensions/global_shortcut_listener_x11.h"
|
||||
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "ui/base/accelerators/accelerator.h"
|
||||
#include "ui/events/keycodes/keyboard_code_conversion_x.h"
|
||||
#include "ui/events/platform/x11/x11_event_source.h"
|
||||
#include "ui/gfx/x/x11_error_tracker.h"
|
||||
#include "ui/gfx/x/x11_types.h"
|
||||
|
||||
using content::BrowserThread;
|
||||
|
||||
namespace {
|
||||
|
||||
// The modifiers masks used for grabing keys. Due to XGrabKey only working on
|
||||
// exact modifiers, we need to grab all key combination including zero or more
|
||||
// of the following: Num lock, Caps lock and Scroll lock. So that we can make
|
||||
// sure the behavior of global shortcuts is consistent on all platforms.
|
||||
const unsigned int kModifiersMasks[] = {
|
||||
0, // No additional modifier.
|
||||
Mod2Mask, // Num lock
|
||||
LockMask, // Caps lock
|
||||
Mod5Mask, // Scroll lock
|
||||
Mod2Mask | LockMask,
|
||||
Mod2Mask | Mod5Mask,
|
||||
LockMask | Mod5Mask,
|
||||
Mod2Mask | LockMask | Mod5Mask
|
||||
};
|
||||
|
||||
int GetNativeModifiers(const ui::Accelerator& accelerator) {
|
||||
int modifiers = 0;
|
||||
modifiers |= accelerator.IsShiftDown() ? ShiftMask : 0;
|
||||
modifiers |= accelerator.IsCtrlDown() ? ControlMask : 0;
|
||||
modifiers |= accelerator.IsAltDown() ? Mod1Mask : 0;
|
||||
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace extensions {
|
||||
|
||||
// static
|
||||
GlobalShortcutListener* GlobalShortcutListener::GetInstance() {
|
||||
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||
static GlobalShortcutListenerX11* instance =
|
||||
new GlobalShortcutListenerX11();
|
||||
return instance;
|
||||
}
|
||||
|
||||
GlobalShortcutListenerX11::GlobalShortcutListenerX11()
|
||||
: is_listening_(false),
|
||||
x_display_(gfx::GetXDisplay()),
|
||||
x_root_window_(DefaultRootWindow(x_display_)) {
|
||||
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||
}
|
||||
|
||||
GlobalShortcutListenerX11::~GlobalShortcutListenerX11() {
|
||||
if (is_listening_)
|
||||
StopListening();
|
||||
}
|
||||
|
||||
void GlobalShortcutListenerX11::StartListening() {
|
||||
DCHECK(!is_listening_); // Don't start twice.
|
||||
DCHECK(!registered_hot_keys_.empty()); // Also don't start if no hotkey is
|
||||
// registered.
|
||||
|
||||
ui::X11EventSource::GetInstance()->AddPlatformEventDispatcher(this);
|
||||
|
||||
is_listening_ = true;
|
||||
}
|
||||
|
||||
void GlobalShortcutListenerX11::StopListening() {
|
||||
DCHECK(is_listening_); // No point if we are not already listening.
|
||||
DCHECK(registered_hot_keys_.empty()); // Make sure the set is clean before
|
||||
// ending.
|
||||
|
||||
ui::X11EventSource::GetInstance()->RemovePlatformEventDispatcher(this);
|
||||
|
||||
is_listening_ = false;
|
||||
}
|
||||
|
||||
bool GlobalShortcutListenerX11::CanDispatchEvent(
|
||||
const ui::PlatformEvent& event) {
|
||||
return event->type == KeyPress;
|
||||
}
|
||||
|
||||
uint32_t GlobalShortcutListenerX11::DispatchEvent(
|
||||
const ui::PlatformEvent& event) {
|
||||
CHECK_EQ(KeyPress, event->type);
|
||||
OnXKeyPressEvent(event);
|
||||
|
||||
return ui::POST_DISPATCH_NONE;
|
||||
}
|
||||
|
||||
bool GlobalShortcutListenerX11::RegisterAcceleratorImpl(
|
||||
const ui::Accelerator& accelerator) {
|
||||
DCHECK(registered_hot_keys_.find(accelerator) == registered_hot_keys_.end());
|
||||
|
||||
int modifiers = GetNativeModifiers(accelerator);
|
||||
KeyCode keycode = XKeysymToKeycode(x_display_,
|
||||
XKeysymForWindowsKeyCode(accelerator.key_code(), false));
|
||||
gfx::X11ErrorTracker err_tracker;
|
||||
|
||||
// Because XGrabKey only works on the exact modifiers mask, we should register
|
||||
// our hot keys with modifiers that we want to ignore, including Num lock,
|
||||
// Caps lock, Scroll lock. See comment about |kModifiersMasks|.
|
||||
for (size_t i = 0; i < arraysize(kModifiersMasks); ++i) {
|
||||
XGrabKey(x_display_, keycode, modifiers | kModifiersMasks[i],
|
||||
x_root_window_, False, GrabModeAsync, GrabModeAsync);
|
||||
}
|
||||
|
||||
if (err_tracker.FoundNewError()) {
|
||||
// We may have part of the hotkeys registered, clean up.
|
||||
for (size_t i = 0; i < arraysize(kModifiersMasks); ++i) {
|
||||
XUngrabKey(x_display_, keycode, modifiers | kModifiersMasks[i],
|
||||
x_root_window_);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
registered_hot_keys_.insert(accelerator);
|
||||
return true;
|
||||
}
|
||||
|
||||
void GlobalShortcutListenerX11::UnregisterAcceleratorImpl(
|
||||
const ui::Accelerator& accelerator) {
|
||||
DCHECK(registered_hot_keys_.find(accelerator) != registered_hot_keys_.end());
|
||||
|
||||
int modifiers = GetNativeModifiers(accelerator);
|
||||
KeyCode keycode = XKeysymToKeycode(x_display_,
|
||||
XKeysymForWindowsKeyCode(accelerator.key_code(), false));
|
||||
|
||||
for (size_t i = 0; i < arraysize(kModifiersMasks); ++i) {
|
||||
XUngrabKey(x_display_, keycode, modifiers | kModifiersMasks[i],
|
||||
x_root_window_);
|
||||
}
|
||||
registered_hot_keys_.erase(accelerator);
|
||||
}
|
||||
|
||||
void GlobalShortcutListenerX11::OnXKeyPressEvent(::XEvent* x_event) {
|
||||
DCHECK(x_event->type == KeyPress);
|
||||
int modifiers = 0;
|
||||
modifiers |= (x_event->xkey.state & ShiftMask) ? ui::EF_SHIFT_DOWN : 0;
|
||||
modifiers |= (x_event->xkey.state & ControlMask) ? ui::EF_CONTROL_DOWN : 0;
|
||||
modifiers |= (x_event->xkey.state & Mod1Mask) ? ui::EF_ALT_DOWN : 0;
|
||||
|
||||
ui::Accelerator accelerator(
|
||||
ui::KeyboardCodeFromXKeyEvent(x_event), modifiers);
|
||||
if (registered_hot_keys_.find(accelerator) != registered_hot_keys_.end())
|
||||
NotifyKeyPressed(accelerator);
|
||||
}
|
||||
|
||||
} // namespace extensions
|
||||
@@ -0,0 +1,57 @@
|
||||
// Copyright 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_X11_H_
|
||||
#define CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_X11_H_
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <set>
|
||||
|
||||
#include "chrome/browser/extensions/global_shortcut_listener.h"
|
||||
#include "ui/events/platform/platform_event_dispatcher.h"
|
||||
|
||||
namespace extensions {
|
||||
|
||||
// X11-specific implementation of the GlobalShortcutListener class that
|
||||
// listens for global shortcuts. Handles basic keyboard intercepting and
|
||||
// forwards its output to the base class for processing.
|
||||
class GlobalShortcutListenerX11 : public GlobalShortcutListener,
|
||||
public ui::PlatformEventDispatcher {
|
||||
public:
|
||||
GlobalShortcutListenerX11();
|
||||
virtual ~GlobalShortcutListenerX11();
|
||||
|
||||
// ui::PlatformEventDispatcher implementation.
|
||||
virtual bool CanDispatchEvent(const ui::PlatformEvent& event) OVERRIDE;
|
||||
virtual uint32_t DispatchEvent(const ui::PlatformEvent& event) OVERRIDE;
|
||||
|
||||
private:
|
||||
// GlobalShortcutListener implementation.
|
||||
virtual void StartListening() OVERRIDE;
|
||||
virtual void StopListening() OVERRIDE;
|
||||
virtual bool RegisterAcceleratorImpl(
|
||||
const ui::Accelerator& accelerator) OVERRIDE;
|
||||
virtual void UnregisterAcceleratorImpl(
|
||||
const ui::Accelerator& accelerator) OVERRIDE;
|
||||
|
||||
// Invoked when a global shortcut is pressed.
|
||||
void OnXKeyPressEvent(::XEvent* x_event);
|
||||
|
||||
// Whether this object is listening for global shortcuts.
|
||||
bool is_listening_;
|
||||
|
||||
// The x11 default display and the native root window.
|
||||
::Display* x_display_;
|
||||
::Window x_root_window_;
|
||||
|
||||
// A set of registered accelerators.
|
||||
typedef std::set<ui::Accelerator> RegisteredHotKeys;
|
||||
RegisteredHotKeys registered_hot_keys_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(GlobalShortcutListenerX11);
|
||||
};
|
||||
|
||||
} // namespace extensions
|
||||
|
||||
#endif // CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_X11_H_
|
||||
28
common.gypi
28
common.gypi
@@ -7,7 +7,6 @@
|
||||
}],
|
||||
['OS=="win" and (MSVS_VERSION=="2013e" or MSVS_VERSION=="2012e" or MSVS_VERSION=="2010e")', {
|
||||
'msvs_express': 1,
|
||||
'windows_driver_kit_path%': 'C:/WinDDK/7600.16385.1',
|
||||
},{
|
||||
'msvs_express': 0,
|
||||
}],
|
||||
@@ -202,33 +201,6 @@
|
||||
},
|
||||
},
|
||||
}], # clang==1
|
||||
# Using Visual Studio Express.
|
||||
['msvs_express==1', {
|
||||
'target_defaults': {
|
||||
'defines!': [
|
||||
'_SECURE_ATL',
|
||||
],
|
||||
'msvs_settings': {
|
||||
'VCLibrarianTool': {
|
||||
'AdditionalLibraryDirectories': [
|
||||
'<(windows_driver_kit_path)/lib/ATL/i386',
|
||||
],
|
||||
},
|
||||
'VCLinkerTool': {
|
||||
'AdditionalLibraryDirectories': [
|
||||
'<(windows_driver_kit_path)/lib/ATL/i386',
|
||||
],
|
||||
'AdditionalDependencies': [
|
||||
'atlthunk.lib',
|
||||
],
|
||||
},
|
||||
},
|
||||
'msvs_system_include_dirs': [
|
||||
'<(windows_driver_kit_path)/inc/atl71',
|
||||
'<(windows_driver_kit_path)/inc/mfc42',
|
||||
],
|
||||
},
|
||||
}], # msvs_express==1
|
||||
# The breakdpad on Windows assumes Debug_x64 and Release_x64 configurations.
|
||||
['OS=="win"', {
|
||||
'target_defaults': {
|
||||
|
||||
@@ -8,13 +8,16 @@
|
||||
|
||||
* [Synopsis](api/synopsis.md)
|
||||
* [Process object](api/process.md)
|
||||
* [Supported Chrome command line switches](api/chrome-command-line-switches.md)
|
||||
|
||||
Modules for browser side:
|
||||
|
||||
* [app](api/app.md)
|
||||
* [auto-updater](api/auto-updater.md)
|
||||
* [browser-window](api/browser-window.md)
|
||||
* [content-tracing](api/content-tracing.md)
|
||||
* [dialog](api/dialog.md)
|
||||
* [global-shortcut](api/global-shortcut.md)
|
||||
* [ipc (browser)](api/ipc-browser.md)
|
||||
* [menu](api/menu.md)
|
||||
* [menu-item](api/menu-item.md)
|
||||
|
||||
41
docs/api/accelerator.md
Normal file
41
docs/api/accelerator.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Accelerator
|
||||
|
||||
An accelerator is string that represents a keyboard shortcut, it can contain
|
||||
multiple modifiers and key codes, combined by the `+` character.
|
||||
|
||||
Examples:
|
||||
|
||||
* `Command+A`
|
||||
* `Ctrl+Shift+Z`
|
||||
|
||||
## Platform notice
|
||||
|
||||
On Linux and Windows, the `Command` key would not have any effect, you can
|
||||
use `CommandOrControl` which represents `Command` on OS X and `Control` on
|
||||
Linux and Windows to define some accelerators.
|
||||
|
||||
## Available modifiers
|
||||
|
||||
* `Command` (or `Cmd` for short)
|
||||
* `Control` (or `Ctrl` for short)
|
||||
* `CommandOrControl` (or `CmdOrCtrl` for short)
|
||||
* `Alt`
|
||||
* `Shift`
|
||||
|
||||
## Available key codes
|
||||
|
||||
* `0` to `9`
|
||||
* `A` to `Z`
|
||||
* `F1` to `F24`
|
||||
* Punctuations like `~`, `!`, `@`, `#`, `$`, etc.
|
||||
* `Space`
|
||||
* `Backspace`
|
||||
* `Delete`
|
||||
* `Insert`
|
||||
* `Return` (or `Enter` as alias)
|
||||
* `Up`, `Down`, `Left` and `Right`
|
||||
* `Home` and `End`
|
||||
* `PageUp` and `PageDown`
|
||||
* `Escape` (or `Esc` for short)
|
||||
* `VolumeUp`, `VolumeDown` and `VolumeMute`
|
||||
* `MediaNextTrack`, `MediaPreviousTrack`, `MediaStop` and `MediaPlayPause`
|
||||
@@ -87,6 +87,14 @@ executed. It is possible that a window cancels the quitting by returning
|
||||
Quit the application directly, it will not try to close all windows so cleanup
|
||||
code will not run.
|
||||
|
||||
## app.getDataPath()
|
||||
|
||||
Returns the path for storing configuration files, with app name appended.
|
||||
|
||||
* `%APPDATA%\MyAppName` on Windows
|
||||
* `~/.config/MyAppName` on Linux
|
||||
* `~/Library/Application Support/MyAppName` on OS X
|
||||
|
||||
## app.getVersion()
|
||||
|
||||
Returns the version of loaded application, if no version is found in
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
The `auto-updater` module is a simple wrap around the
|
||||
[Squirrel.Mac](https://github.com/Squirrel/Squirrel.Mac) framework.
|
||||
|
||||
Squirrel.Mac requires that your `.app` folder is signed using the
|
||||
[codesign](https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/codesign.1.html)
|
||||
utility for updates to be installed.
|
||||
|
||||
## Squirrel
|
||||
|
||||
Squirrel is an OS X framework focused on making application updates **as safe
|
||||
|
||||
@@ -18,6 +18,9 @@ win.show();
|
||||
You can also create a window without chrome by using
|
||||
[Frameless Window](frameless-window.md) API.
|
||||
|
||||
Security strategy of web pages showed by `BrowserWindow` is a bit different from
|
||||
normal browsers, see [Web Security](web-security.md) for more.
|
||||
|
||||
## Class: BrowserWindow
|
||||
|
||||
`BrowserWindow` is an
|
||||
@@ -51,10 +54,15 @@ You can also create a window without chrome by using
|
||||
* `show` Boolean - Whether window should be shown when created
|
||||
* `frame` Boolean - Specify `false` to create a
|
||||
[Frameless Window](frameless-window.md)
|
||||
* `node-integration` String - Can be `all`, `except-iframe`,
|
||||
`manual-enable-iframe` or `disable`.
|
||||
* `node-integration` String - Default value is `except-iframe`, can also be
|
||||
`all`, `manual-enable-iframe` or `disable`, see
|
||||
[Web Security](web-security.md) for more informations.
|
||||
* `accept-first-mouse` Boolean - Whether the web view accepts a single
|
||||
mouse-down event that simultaneously activates the window
|
||||
* `auto-hide-menu-bar` Boolean - Auto hide the menu bar unless the `Alt`
|
||||
key is pressed.
|
||||
* `enable-larger-than-screen` Boolean - Enable the window to be resized larger
|
||||
than screen.
|
||||
* `web-preferences` Object - Settings of web page's features
|
||||
* `javascript` Boolean
|
||||
* `web-security` Boolean
|
||||
@@ -63,7 +71,6 @@ You can also create a window without chrome by using
|
||||
* `text-areas-are-resizable` Boolean
|
||||
* `webgl` Boolean
|
||||
* `webaudio` Boolean
|
||||
* `accelerated-compositing` Boolean
|
||||
* `plugins` Boolean - Whether plugins should be enabled, currently only
|
||||
`NPAPI` plugins are supported.
|
||||
* `extra-plugin-dirs` Array - Array of paths that would be searched for
|
||||
@@ -76,35 +83,6 @@ Creates a new `BrowserWindow` with native properties set by the `options`.
|
||||
Usually you only need to set the `width` and `height`, other properties will
|
||||
have decent default values.
|
||||
|
||||
By default the `node-integration` option is `except-iframe`, which means node
|
||||
integration is disabled in all iframes, . You can also set it to `all`, with
|
||||
which node integration is available to the main page and all its iframes, or
|
||||
`manual-enable-iframe`, which is like `except-iframe`, but would enable iframes
|
||||
whose name is suffixed by `-enable-node-integration`. And setting to `disable`
|
||||
would disable the node integration in both the main page and its iframes.
|
||||
|
||||
An example of enable node integration in iframe with `node-integration` set to
|
||||
`manual-enable-iframe`:
|
||||
|
||||
```html
|
||||
<!-- iframe with node integration enabled -->
|
||||
<iframe name="gh-enable-node-integration" src="https://github.com"></iframe>
|
||||
|
||||
<!-- iframe with node integration disabled -->
|
||||
<iframe src="http://jandan.net"></iframe>
|
||||
```
|
||||
|
||||
And in atom-shell, the security limitation of iframe is stricter than normal
|
||||
browser, by default iframe is sandboxed with all permissions except the
|
||||
`allow-same-origin`, which means iframe could not access parent's js context.
|
||||
|
||||
If you want to enable things like `parent.window.process.exit()` in iframe,
|
||||
you should explicitly set `sandbox` to `none`:
|
||||
|
||||
```html
|
||||
<iframe sandbox="none" src="https://github.com"></iframe>
|
||||
```
|
||||
|
||||
### Event: 'page-title-updated'
|
||||
|
||||
* `event` Event
|
||||
@@ -252,6 +230,10 @@ the Dock.
|
||||
|
||||
Restores the window from minimized state to its previous state.
|
||||
|
||||
### BrowserWindow.isMinimized()
|
||||
|
||||
Returns whether the window is minimized.
|
||||
|
||||
### BrowserWindow.setFullScreen(flag)
|
||||
|
||||
* `flag` Boolean
|
||||
|
||||
45
docs/api/chrome-command-line-switches.md
Normal file
45
docs/api/chrome-command-line-switches.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# Supported Chrome command line switches
|
||||
|
||||
Following command lines switches in Chrome browser are also Supported in
|
||||
atom-shell, you can use [app.commandLine.appendSwitch](append-switch) to append
|
||||
them in your app's main script before the [ready](ready) event of [app](app)
|
||||
module is emitted:
|
||||
|
||||
```javascript
|
||||
var app = require('app');
|
||||
app.commandLine.appendSwitch('remote-debugging-port', '88315');
|
||||
app.commandLine.appendSwitch('host-rules', 'MAP * 127.0.0.1');
|
||||
|
||||
app.on('ready', function() {
|
||||
});
|
||||
```
|
||||
|
||||
## --remote-debugging-port=`port`
|
||||
|
||||
Enables remote debug over HTTP on the specified `port`.
|
||||
|
||||
## --host-rules=`rules`
|
||||
|
||||
Comma-separated list of `rules` that control how hostnames are mapped.
|
||||
|
||||
For example:
|
||||
|
||||
* `MAP * 127.0.0.1` Forces all hostnames to be mapped to 127.0.0.1
|
||||
* `MAP *.google.com proxy` Forces all google.com subdomains to be resolved to
|
||||
"proxy".
|
||||
* `MAP test.com [::1]:77` Forces "test.com" to resolve to IPv6 loopback. Will
|
||||
also force the port of the resulting socket address to be 77.
|
||||
* `MAP * baz, EXCLUDE www.google.com` Remaps everything to "baz", except for
|
||||
"www.google.com".
|
||||
|
||||
These mappings apply to the endpoint host in a net request (the TCP connect
|
||||
and host resolver in a direct connection, and the `CONNECT` in an http proxy
|
||||
connection, and the endpoint host in a `SOCKS` proxy connection).
|
||||
|
||||
## --host-resolver-rules=`rules`
|
||||
|
||||
Like `--host-rules` but these `rules` only apply to the host resolver.
|
||||
|
||||
[app](app.md)
|
||||
[append-switch](app.md#appcommandlineappendswitchswitch-value)
|
||||
[ready](app.md##event-ready)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user