mirror of
https://github.com/electron/electron.git
synced 2026-02-19 03:14:51 -05:00
Compare commits
299 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd081e162b | ||
|
|
30be4a847f | ||
|
|
0d77ba5222 | ||
|
|
94569f7f8c | ||
|
|
fdfff63119 | ||
|
|
da03784610 | ||
|
|
deef68bcf9 | ||
|
|
6393e2e1e5 | ||
|
|
bf77fcc03e | ||
|
|
386b921914 | ||
|
|
401fe76acd | ||
|
|
2fd3616ef3 | ||
|
|
ffaf535d00 | ||
|
|
9ac5ea5a6c | ||
|
|
edf7496443 | ||
|
|
151b2b5ad5 | ||
|
|
1fc9ef33db | ||
|
|
858f21a69c | ||
|
|
3a4835ff1c | ||
|
|
47d37cc1e3 | ||
|
|
a5224f705d | ||
|
|
b737e602b7 | ||
|
|
59f586ba59 | ||
|
|
70b7659893 | ||
|
|
717b664802 | ||
|
|
75e1fb63c8 | ||
|
|
a9c20dc42f | ||
|
|
dce7e50636 | ||
|
|
edd2bd74c9 | ||
|
|
6f8c46d2f4 | ||
|
|
4bab284f2e | ||
|
|
59b3e74542 | ||
|
|
4af646b760 | ||
|
|
5720d4f802 | ||
|
|
80824b13c6 | ||
|
|
33ad68f7a7 | ||
|
|
4af802f215 | ||
|
|
3b4a45ac65 | ||
|
|
a0548530e7 | ||
|
|
8d6764e0a0 | ||
|
|
36ecb35cb1 | ||
|
|
9ad3b7939f | ||
|
|
8493975840 | ||
|
|
ec880d64bf | ||
|
|
113d644615 | ||
|
|
4105527d07 | ||
|
|
2228184066 | ||
|
|
1af4ecfc26 | ||
|
|
9981fd51da | ||
|
|
458ff5c41f | ||
|
|
7735d8fbfd | ||
|
|
20e368eb89 | ||
|
|
ed3358e501 | ||
|
|
d181ff4e7f | ||
|
|
f8f09eb974 | ||
|
|
28b692aeaa | ||
|
|
aef6d44a01 | ||
|
|
e4b4087fdb | ||
|
|
1d2de6d1fb | ||
|
|
67dd596386 | ||
|
|
bd0836581b | ||
|
|
cdb5e24d2f | ||
|
|
6b02be6da8 | ||
|
|
d1a5c49843 | ||
|
|
dd4e43eb02 | ||
|
|
9007a45051 | ||
|
|
801a19504a | ||
|
|
a6989847ea | ||
|
|
e7d25385b0 | ||
|
|
62f200d252 | ||
|
|
374cf948e4 | ||
|
|
8f558fb252 | ||
|
|
8f2dd91e34 | ||
|
|
896c1793d3 | ||
|
|
85428d8eb3 | ||
|
|
57bee8b788 | ||
|
|
0ad51c394b | ||
|
|
e8455d5c9a | ||
|
|
2768eaa676 | ||
|
|
6c0621fe05 | ||
|
|
baa6d9730c | ||
|
|
d5ffa4dc77 | ||
|
|
01dd5638d0 | ||
|
|
ec5cd2fb1c | ||
|
|
44c0dc9104 | ||
|
|
7324f0468b | ||
|
|
64e3a6b437 | ||
|
|
690ab7d4ae | ||
|
|
48a0ac9a96 | ||
|
|
7212fa1056 | ||
|
|
8d710609fd | ||
|
|
7dcbd11863 | ||
|
|
e075a8b49e | ||
|
|
d1dc041aaf | ||
|
|
85243edf4e | ||
|
|
faeea88b16 | ||
|
|
139d581e5b | ||
|
|
64b2d0da36 | ||
|
|
dc1a8b644a | ||
|
|
8bb3b53833 | ||
|
|
8112fe741e | ||
|
|
60f24eb22b | ||
|
|
fd20050fc9 | ||
|
|
c5946bf977 | ||
|
|
618d0c6397 | ||
|
|
362bb6e68b | ||
|
|
b88168c0d2 | ||
|
|
df919a4be8 | ||
|
|
45f864d2b4 | ||
|
|
602f02b867 | ||
|
|
5cf61c9ab4 | ||
|
|
49a7954824 | ||
|
|
198b52bf40 | ||
|
|
cb31140d3a | ||
|
|
f2c1d8f4b2 | ||
|
|
3ddba90d94 | ||
|
|
887a2a3c00 | ||
|
|
585777e62d | ||
|
|
640f45a5b3 | ||
|
|
8bcb545119 | ||
|
|
aa911cdb2e | ||
|
|
27be89d39a | ||
|
|
5ce66fca5c | ||
|
|
94e4044160 | ||
|
|
30eabfb9f6 | ||
|
|
a6eb261af0 | ||
|
|
6e4f74ae35 | ||
|
|
f091352c56 | ||
|
|
534ff5efdb | ||
|
|
51d92454ce | ||
|
|
af413b2d97 | ||
|
|
7c30d037a3 | ||
|
|
acda56210b | ||
|
|
61b2377cf2 | ||
|
|
7fa6407f65 | ||
|
|
41de0b420a | ||
|
|
0ad1fc842d | ||
|
|
7f0e7f3835 | ||
|
|
6ff644fe60 | ||
|
|
92c68797d0 | ||
|
|
9a2fc8f4ea | ||
|
|
6a712d4db4 | ||
|
|
a182de20a4 | ||
|
|
caaab22841 | ||
|
|
1e1fec15b6 | ||
|
|
1524ced816 | ||
|
|
93f1a3dbd5 | ||
|
|
666f6b3a01 | ||
|
|
61cc0bba25 | ||
|
|
587484a5d0 | ||
|
|
defb6c9882 | ||
|
|
55a35d473d | ||
|
|
d86172cc87 | ||
|
|
32432cc770 | ||
|
|
ae98d9c8b6 | ||
|
|
4e2d3f3d12 | ||
|
|
a2f679e4bd | ||
|
|
06ae5c06b8 | ||
|
|
0483871388 | ||
|
|
7f7e13edc3 | ||
|
|
bbb9c37f70 | ||
|
|
88ce2a5390 | ||
|
|
6748573dee | ||
|
|
5c8566e0d4 | ||
|
|
5a6ff0f80d | ||
|
|
2024ae5dba | ||
|
|
aa6d5a3ff6 | ||
|
|
419da689c9 | ||
|
|
709563c090 | ||
|
|
b50a2c9dc1 | ||
|
|
43a5453de5 | ||
|
|
87d94ff1ae | ||
|
|
8b4414345b | ||
|
|
6e43074586 | ||
|
|
99d901bc9a | ||
|
|
95e79124eb | ||
|
|
54b0d0c9c0 | ||
|
|
10a46b4229 | ||
|
|
af3f07f4cc | ||
|
|
f4f42b30ee | ||
|
|
f3eef6cc2e | ||
|
|
11f387743f | ||
|
|
561857d640 | ||
|
|
3b3585f575 | ||
|
|
6be716c6e8 | ||
|
|
2b923b988c | ||
|
|
ef8a05be38 | ||
|
|
c029ff2055 | ||
|
|
e376850552 | ||
|
|
1ce61c7845 | ||
|
|
68a3fd6f05 | ||
|
|
ce012043fa | ||
|
|
ae70d5cb64 | ||
|
|
db359ae75c | ||
|
|
3586565bba | ||
|
|
fe67ecd7fd | ||
|
|
33c509b867 | ||
|
|
3edfb7d5c3 | ||
|
|
eed2b0fd81 | ||
|
|
4c4b8a8486 | ||
|
|
2b9a533d1d | ||
|
|
b3a2302283 | ||
|
|
6bee435170 | ||
|
|
5480cf58c2 | ||
|
|
65176761f4 | ||
|
|
cf75e4ac49 | ||
|
|
ac68589291 | ||
|
|
bc95cac3ed | ||
|
|
eed8f6cabc | ||
|
|
6aefb0f76f | ||
|
|
14de58a6b7 | ||
|
|
085f0a2544 | ||
|
|
4000734504 | ||
|
|
1b5e22f9c4 | ||
|
|
53c6d51d56 | ||
|
|
ac76017702 | ||
|
|
9927b4bf4c | ||
|
|
11ca836afc | ||
|
|
a824c88352 | ||
|
|
8fdd3b3044 | ||
|
|
1e5e0194bd | ||
|
|
a0d1a7620c | ||
|
|
770a0068a3 | ||
|
|
26f0e49c9a | ||
|
|
c7637c78d1 | ||
|
|
30ca085fd8 | ||
|
|
e824b6c910 | ||
|
|
43b492c641 | ||
|
|
c95cfc9540 | ||
|
|
d3dd2b4332 | ||
|
|
7e86ee37f3 | ||
|
|
f444e9dc74 | ||
|
|
76ac8f2719 | ||
|
|
a4262bc39d | ||
|
|
85d6588661 | ||
|
|
b70722feb6 | ||
|
|
bfe59480e3 | ||
|
|
68bdad9a23 | ||
|
|
761b9d22c8 | ||
|
|
1e4762ce92 | ||
|
|
d443b36446 | ||
|
|
ef4b36d621 | ||
|
|
ef5a4b5fe0 | ||
|
|
07b5039c64 | ||
|
|
a9c824eba1 | ||
|
|
b225a59a15 | ||
|
|
50b5272354 | ||
|
|
8879334468 | ||
|
|
2be1145a9e | ||
|
|
e65220adb0 | ||
|
|
92e157de30 | ||
|
|
c908cae72c | ||
|
|
3f357f184d | ||
|
|
3fdec5c6e3 | ||
|
|
6fced224c7 | ||
|
|
9ed64548d4 | ||
|
|
575fe06f29 | ||
|
|
6cb2ece285 | ||
|
|
29e071a1ad | ||
|
|
9e9579a858 | ||
|
|
9849844e89 | ||
|
|
c578a2cbc2 | ||
|
|
583d34b9f7 | ||
|
|
a2c3690592 | ||
|
|
7a21ae831f | ||
|
|
8708d0611a | ||
|
|
ef92cd8b45 | ||
|
|
8cb624d828 | ||
|
|
cec640f572 | ||
|
|
7a1365673e | ||
|
|
6c098deb57 | ||
|
|
cf4a566290 | ||
|
|
aabba3c641 | ||
|
|
8f31bf8615 | ||
|
|
5d49fc4bee | ||
|
|
f38eb1b66f | ||
|
|
a567ba08ea | ||
|
|
91d54a74e1 | ||
|
|
da9cce3f2d | ||
|
|
92241b91ce | ||
|
|
6b81070f67 | ||
|
|
3715dd2a20 | ||
|
|
eb6fa98ed0 | ||
|
|
8ddb85774a | ||
|
|
8caf5fac06 | ||
|
|
cc62978ac3 | ||
|
|
f833423a2f | ||
|
|
3c0671c179 | ||
|
|
a00bf3e1e1 | ||
|
|
ce487fe1da | ||
|
|
a73aea3bda | ||
|
|
b9d994dca2 | ||
|
|
b7c2295a1c | ||
|
|
da2ded5453 | ||
|
|
a5eb9ea08f | ||
|
|
4223867dbc | ||
|
|
40273cf37d | ||
|
|
bc9c95d77d | ||
|
|
6a322f8bd6 |
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -13,3 +13,6 @@
|
||||
[submodule "vendor/apm"]
|
||||
path = vendor/apm
|
||||
url = https://github.com/atom/apm.git
|
||||
[submodule "vendor/breakpad"]
|
||||
path = vendor/breakpad
|
||||
url = https://github.com/atom/chromium-breakpad.git
|
||||
|
||||
@@ -2,31 +2,53 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "app/atom_main.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "content/public/app/content_main.h"
|
||||
#if defined(OS_WIN)
|
||||
#include <stdio.h>
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
|
||||
#include "app/atom_main_delegate.h"
|
||||
#include "base/environment.h"
|
||||
#include "common/crash_reporter/win/crash_service_main.h"
|
||||
#include "content/public/app/startup_helper_win.h"
|
||||
#include "sandbox/win/src/sandbox_types.h"
|
||||
#else // defined(OS_WIN)
|
||||
#include "app/atom_library_main.h"
|
||||
#endif // defined(OS_MACOSX) || defined(OS_LINUX)
|
||||
|
||||
// Declaration of node::Start.
|
||||
namespace node {
|
||||
int Start(int argc, char *argv[]);
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
|
||||
#include <windows.h> // NOLINT
|
||||
#include <shellapi.h> // NOLINT
|
||||
|
||||
#include "app/atom_main_delegate.h"
|
||||
#include "base/environment.h"
|
||||
#include "content/public/app/startup_helper_win.h"
|
||||
#include "sandbox/win/src/sandbox_types.h"
|
||||
|
||||
int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
|
||||
int argc = 0;
|
||||
wchar_t** wargv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
|
||||
|
||||
scoped_ptr<base::Environment> env(base::Environment::Create());
|
||||
std::string node_indicator;
|
||||
|
||||
// Make output work in console if we are not in cygiwn.
|
||||
std::string os;
|
||||
if (env->GetVar("OS", &os) && os != "cygwin") {
|
||||
AttachConsole(ATTACH_PARENT_PROCESS);
|
||||
|
||||
FILE* dontcare;
|
||||
freopen_s(&dontcare, "CON", "w", stdout);
|
||||
freopen_s(&dontcare, "CON", "w", stderr);
|
||||
freopen_s(&dontcare, "CON", "r", stdin);
|
||||
}
|
||||
|
||||
std::string node_indicator, crash_service_indicator;
|
||||
if (env->GetVar("ATOM_SHELL_INTERNAL_RUN_AS_NODE", &node_indicator) &&
|
||||
node_indicator == "1") {
|
||||
// Convert argv to to UTF8
|
||||
@@ -64,6 +86,10 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
|
||||
}
|
||||
// Now that conversion is done, we can finally start.
|
||||
return node::Start(argc, argv);
|
||||
} else if (env->GetVar("ATOM_SHELL_INTERNAL_CRASH_SERVICE",
|
||||
&crash_service_indicator) &&
|
||||
crash_service_indicator == "1") {
|
||||
return crash_service::Main(cmd);
|
||||
}
|
||||
|
||||
sandbox::SandboxInterfaceInfo sandbox_info = {0};
|
||||
@@ -74,8 +100,6 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
|
||||
|
||||
#else // defined(OS_WIN)
|
||||
|
||||
#include "app/atom_library_main.h"
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
char* node_indicator = getenv("ATOM_SHELL_INTERNAL_RUN_AS_NODE");
|
||||
if (node_indicator != NULL && strcmp(node_indicator, "1") == 0)
|
||||
@@ -84,4 +108,4 @@ int main(int argc, const char* argv[]) {
|
||||
return AtomMain(argc, argv);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // defined(OS_MACOSX) || defined(OS_LINUX)
|
||||
|
||||
5
app/atom_main.h
Normal file
5
app/atom_main.h
Normal file
@@ -0,0 +1,5 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "content/public/app/content_main.h"
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "browser/atom_browser_client.h"
|
||||
#include "content/public/common/content_switches.h"
|
||||
#include "renderer/atom_renderer_client.h"
|
||||
#include "ui/base/resource/resource_bundle.h"
|
||||
#include "base/path_service.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
@@ -38,13 +40,31 @@ bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
|
||||
}
|
||||
|
||||
void AtomMainDelegate::PreSandboxStartup() {
|
||||
brightray::MainDelegate::PreSandboxStartup();
|
||||
#if defined(OS_MACOSX)
|
||||
OverrideChildProcessPath();
|
||||
OverrideFrameworkBundlePath();
|
||||
SetProcessName();
|
||||
#endif
|
||||
InitializeResourceBundle();
|
||||
|
||||
// Disable renderer sandbox for most of node's functions.
|
||||
CommandLine* command_line = CommandLine::ForCurrentProcess();
|
||||
command_line->AppendSwitch(switches::kNoSandbox);
|
||||
}
|
||||
|
||||
void AtomMainDelegate::InitializeResourceBundle() {
|
||||
base::FilePath path;
|
||||
#if defined(OS_MACOSX)
|
||||
path = GetResourcesPakFilePath();
|
||||
#else
|
||||
base::FilePath pak_dir;
|
||||
PathService::Get(base::DIR_MODULE, &pak_dir);
|
||||
path = pak_dir.Append(FILE_PATH_LITERAL("content_shell.pak"));
|
||||
#endif
|
||||
|
||||
ui::ResourceBundle::InitSharedInstanceWithPakPath(path);
|
||||
}
|
||||
|
||||
content::ContentBrowserClient* AtomMainDelegate::CreateContentBrowserClient() {
|
||||
browser_client_.reset(new AtomBrowserClient);
|
||||
return browser_client_.get();
|
||||
|
||||
@@ -17,6 +17,14 @@ class AtomMainDelegate : public brightray::MainDelegate {
|
||||
protected:
|
||||
virtual bool BasicStartupComplete(int* exit_code) OVERRIDE;
|
||||
virtual void PreSandboxStartup() OVERRIDE;
|
||||
virtual void InitializeResourceBundle();
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
virtual base::FilePath GetResourcesPakFilePath();
|
||||
virtual void OverrideChildProcessPath();
|
||||
virtual void OverrideFrameworkBundlePath();
|
||||
virtual void SetProcessName();
|
||||
#endif
|
||||
|
||||
private:
|
||||
virtual content::ContentBrowserClient* CreateContentBrowserClient() OVERRIDE;
|
||||
|
||||
66
app/atom_main_delegate_mac.mm
Normal file
66
app/atom_main_delegate_mac.mm
Normal file
@@ -0,0 +1,66 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "app/atom_main_delegate.h"
|
||||
|
||||
#import "base/mac/bundle_locations.h"
|
||||
#import "base/mac/foundation_util.h"
|
||||
#import "base/mac/mac_util.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/path_service.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "content/public/common/content_paths.h"
|
||||
#include "content/public/common/content_switches.h"
|
||||
#include "vendor/brightray/common/application_info.h"
|
||||
#include "vendor/brightray/common/mac/main_application_bundle.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
base::FilePath GetFrameworksPath() {
|
||||
return brightray::MainApplicationBundlePath().Append("Contents")
|
||||
.Append("Frameworks");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
base::FilePath AtomMainDelegate::GetResourcesPakFilePath() {
|
||||
NSString* path = [base::mac::FrameworkBundle()
|
||||
pathForResource:@"content_shell" ofType:@"pak"];
|
||||
return base::mac::NSStringToFilePath(path);
|
||||
}
|
||||
|
||||
void AtomMainDelegate::OverrideFrameworkBundlePath() {
|
||||
base::mac::SetOverrideFrameworkBundlePath(
|
||||
GetFrameworksPath().Append("Atom Framework.framework"));
|
||||
}
|
||||
|
||||
void AtomMainDelegate::OverrideChildProcessPath() {
|
||||
base::FilePath helper_path = GetFrameworksPath().Append("Atom Helper.app")
|
||||
.Append("Contents")
|
||||
.Append("MacOS")
|
||||
.Append("Atom Helper");
|
||||
PathService::Override(content::CHILD_PROCESS_EXE, helper_path);
|
||||
}
|
||||
|
||||
void AtomMainDelegate::SetProcessName() {
|
||||
const auto& command_line = *CommandLine::ForCurrentProcess();
|
||||
auto process_type = command_line.GetSwitchValueASCII(switches::kProcessType);
|
||||
std::string suffix;
|
||||
if (process_type == switches::kRendererProcess)
|
||||
suffix = "Renderer";
|
||||
else if (process_type == switches::kPluginProcess ||
|
||||
process_type == switches::kPpapiPluginProcess)
|
||||
suffix = "Plug-In Host";
|
||||
else if (process_type == switches::kUtilityProcess)
|
||||
suffix = "Utility";
|
||||
else
|
||||
return;
|
||||
|
||||
base::mac::SetProcessName(base::mac::NSToCFCast(base::SysUTF8ToNSString(
|
||||
brightray::GetApplicationName() + " " + suffix)));
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
BIN
app/win/atom.ico
Normal file
BIN
app/win/atom.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 345 KiB |
BIN
app/win/atom.rc
BIN
app/win/atom.rc
Binary file not shown.
@@ -1,9 +1,10 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by brightray_example.rc
|
||||
|
||||
#define IDR_MAINFRAME 1
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 101
|
||||
|
||||
126
atom.gyp
126
atom.gyp
@@ -2,8 +2,10 @@
|
||||
'variables': {
|
||||
'project_name': 'atom',
|
||||
'product_name': 'Atom',
|
||||
'framework_name': 'Atom Framework',
|
||||
'app_sources': [
|
||||
'app/atom_main.cc',
|
||||
'app/atom_main.h',
|
||||
],
|
||||
'bundle_sources': [
|
||||
'browser/mac/atom.icns',
|
||||
@@ -13,7 +15,6 @@
|
||||
'browser/api/lib/atom-delegate.coffee',
|
||||
'browser/api/lib/auto-updater.coffee',
|
||||
'browser/api/lib/browser-window.coffee',
|
||||
'browser/api/lib/crash-reporter.coffee',
|
||||
'browser/api/lib/dialog.coffee',
|
||||
'browser/api/lib/ipc.coffee',
|
||||
'browser/api/lib/menu.coffee',
|
||||
@@ -25,6 +26,7 @@
|
||||
'browser/atom/rpc-server.coffee',
|
||||
'common/api/lib/callbacks-registry.coffee',
|
||||
'common/api/lib/clipboard.coffee',
|
||||
'common/api/lib/crash-reporter.coffee',
|
||||
'common/api/lib/id-weak-map.coffee',
|
||||
'common/api/lib/shell.coffee',
|
||||
'renderer/api/lib/ipc.coffee',
|
||||
@@ -33,14 +35,13 @@
|
||||
'lib_sources': [
|
||||
'app/atom_main_delegate.cc',
|
||||
'app/atom_main_delegate.h',
|
||||
'app/atom_main_delegate_mac.mm',
|
||||
'browser/api/atom_api_app.cc',
|
||||
'browser/api/atom_api_app.h',
|
||||
'browser/api/atom_api_auto_updater.cc',
|
||||
'browser/api/atom_api_auto_updater.h',
|
||||
'browser/api/atom_api_browser_ipc.cc',
|
||||
'browser/api/atom_api_browser_ipc.h',
|
||||
'browser/api/atom_api_crash_reporter.h',
|
||||
'browser/api/atom_api_crash_reporter.cc',
|
||||
'browser/api/atom_api_dialog.cc',
|
||||
'browser/api/atom_api_dialog.h',
|
||||
'browser/api/atom_api_event.cc',
|
||||
@@ -78,8 +79,6 @@
|
||||
'browser/atom_browser_main_parts.cc',
|
||||
'browser/atom_browser_main_parts.h',
|
||||
'browser/atom_browser_main_parts_mac.mm',
|
||||
'browser/atom_event_processing_window.h',
|
||||
'browser/atom_event_processing_window.mm',
|
||||
'browser/atom_javascript_dialog_manager.cc',
|
||||
'browser/atom_javascript_dialog_manager.h',
|
||||
'browser/browser.cc',
|
||||
@@ -87,9 +86,6 @@
|
||||
'browser/browser_mac.mm',
|
||||
'browser/browser_win.cc',
|
||||
'browser/browser_observer.h',
|
||||
'browser/crash_reporter.h',
|
||||
'browser/crash_reporter_mac.mm',
|
||||
'browser/crash_reporter_win.cc',
|
||||
'browser/native_window.cc',
|
||||
'browser/native_window.h',
|
||||
'browser/native_window_mac.h',
|
||||
@@ -99,6 +95,8 @@
|
||||
'browser/native_window_observer.h',
|
||||
'browser/net/adapter_request_job.cc',
|
||||
'browser/net/adapter_request_job.h',
|
||||
'browser/net/atom_url_request_context_getter.cc',
|
||||
'browser/net/atom_url_request_context_getter.h',
|
||||
'browser/net/atom_url_request_job_factory.cc',
|
||||
'browser/net/atom_url_request_job_factory.h',
|
||||
'browser/net/url_request_string_job.cc',
|
||||
@@ -107,6 +105,8 @@
|
||||
'browser/ui/accelerator_util.h',
|
||||
'browser/ui/accelerator_util_mac.mm',
|
||||
'browser/ui/accelerator_util_win.cc',
|
||||
'browser/ui/atom_event_processing_window.h',
|
||||
'browser/ui/atom_event_processing_window.mm',
|
||||
'browser/ui/atom_menu_controller_mac.h',
|
||||
'browser/ui/atom_menu_controller_mac.mm',
|
||||
'browser/ui/file_dialog.h',
|
||||
@@ -128,6 +128,8 @@
|
||||
'common/api/api_messages.h',
|
||||
'common/api/atom_api_clipboard.cc',
|
||||
'common/api/atom_api_clipboard.h',
|
||||
'common/api/atom_api_crash_reporter.cc',
|
||||
'common/api/atom_api_crash_reporter.h',
|
||||
'common/api/atom_api_id_weak_map.cc',
|
||||
'common/api/atom_api_id_weak_map.h',
|
||||
'common/api/atom_api_shell.cc',
|
||||
@@ -139,6 +141,18 @@
|
||||
'common/api/atom_extensions.h',
|
||||
'common/api/object_life_monitor.cc',
|
||||
'common/api/object_life_monitor.h',
|
||||
'common/crash_reporter/crash_reporter.cc',
|
||||
'common/crash_reporter/crash_reporter.h',
|
||||
'common/crash_reporter/crash_reporter_mac.h',
|
||||
'common/crash_reporter/crash_reporter_mac.mm',
|
||||
'common/crash_reporter/crash_reporter_win.cc',
|
||||
'common/crash_reporter/crash_reporter_win.h',
|
||||
'common/crash_reporter/win/crash_service.cc',
|
||||
'common/crash_reporter/win/crash_service.h',
|
||||
'common/crash_reporter/win/crash_service_main.cc',
|
||||
'common/crash_reporter/win/crash_service_main.h',
|
||||
'common/draggable_region.cc',
|
||||
'common/draggable_region.h',
|
||||
'common/node_bindings.cc',
|
||||
'common/node_bindings.h',
|
||||
'common/node_bindings_mac.cc',
|
||||
@@ -150,6 +164,7 @@
|
||||
'common/platform_util.h',
|
||||
'common/platform_util_mac.mm',
|
||||
'common/platform_util_win.cc',
|
||||
'common/v8_conversions.h',
|
||||
'common/v8_value_converter_impl.cc',
|
||||
'common/v8_value_converter_impl.h',
|
||||
'renderer/api/atom_api_renderer_ipc.cc',
|
||||
@@ -169,6 +184,7 @@
|
||||
['OS=="win"', {
|
||||
'app_sources': [
|
||||
'app/win/resource.h',
|
||||
'app/win/atom.ico',
|
||||
'app/win/atom.rc',
|
||||
'<(libchromiumcontent_src_dir)/content/app/startup_helper_win.cc',
|
||||
],
|
||||
@@ -179,9 +195,6 @@
|
||||
'-change',
|
||||
'@loader_path/../Frameworks/Sparkle.framework/Versions/A/Sparkle',
|
||||
'@rpath/Sparkle.framework/Versions/A/Sparkle',
|
||||
'-change',
|
||||
'@executable_path/../Frameworks/Quincy.framework/Versions/A/Quincy',
|
||||
'@rpath/Quincy.framework/Versions/A/Quincy',
|
||||
'${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}'
|
||||
],
|
||||
'atom_source_root': '<!(python tools/atom_source_root.py)',
|
||||
@@ -241,9 +254,8 @@
|
||||
'destination': '<(PRODUCT_DIR)/<(product_name).app/Contents/Frameworks',
|
||||
'files': [
|
||||
'<(PRODUCT_DIR)/<(product_name) Helper.app',
|
||||
'<(PRODUCT_DIR)/<(product_name).framework',
|
||||
'<(PRODUCT_DIR)/<(framework_name).framework',
|
||||
'frameworks/Sparkle.framework',
|
||||
'frameworks/Quincy.framework',
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -299,7 +311,7 @@
|
||||
],
|
||||
}], # OS=="win"
|
||||
],
|
||||
},
|
||||
}, # target <(project_name)
|
||||
{
|
||||
'target_name': '<(project_name)_lib',
|
||||
'type': 'static_library',
|
||||
@@ -329,12 +341,22 @@
|
||||
'-limm32.lib',
|
||||
'-loleacc.lib',
|
||||
'-lComdlg32.lib',
|
||||
'-lWininet.lib',
|
||||
'<(atom_source_root)/<(libchromiumcontent_library_dir)/chromiumviews.lib',
|
||||
],
|
||||
},
|
||||
'dependencies': [
|
||||
'vendor/breakpad/breakpad.gyp:breakpad_handler',
|
||||
'vendor/breakpad/breakpad.gyp:breakpad_sender',
|
||||
],
|
||||
}],
|
||||
['OS=="mac"', {
|
||||
'dependencies': [
|
||||
'vendor/breakpad/breakpad.gyp:breakpad',
|
||||
],
|
||||
}],
|
||||
],
|
||||
},
|
||||
}, # target <(product_name)_lib
|
||||
{
|
||||
'target_name': 'generated_sources',
|
||||
'type': 'none',
|
||||
@@ -374,14 +396,70 @@
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
}, # target generated_sources
|
||||
{
|
||||
'target_name': '<(project_name)_dump_symbols',
|
||||
'type': 'none',
|
||||
'dependencies': [
|
||||
'<(project_name)',
|
||||
],
|
||||
'conditions': [
|
||||
['OS=="mac"', {
|
||||
'dependencies': [
|
||||
'vendor/breakpad/breakpad.gyp:dump_syms',
|
||||
],
|
||||
'actions': [
|
||||
{
|
||||
'action_name': 'Dump Symbols',
|
||||
'inputs': [
|
||||
'<(PRODUCT_DIR)/<(product_name).app/Contents/MacOS/<(product_name)',
|
||||
],
|
||||
'outputs': [
|
||||
'<(PRODUCT_DIR)/Atom-Shell.breakpad.syms',
|
||||
],
|
||||
'action': [
|
||||
'python',
|
||||
'tools/mac/generate_breakpad_symbols.py',
|
||||
'--build-dir=<(PRODUCT_DIR)',
|
||||
'--binary=<(PRODUCT_DIR)/<(product_name).app/Contents/MacOS/<(product_name)',
|
||||
'--symbols-dir=<(PRODUCT_DIR)/Atom-Shell.breakpad.syms',
|
||||
'--libchromiumcontent-dir=<(libchromiumcontent_library_dir)',
|
||||
'--clear',
|
||||
'--jobs=16',
|
||||
],
|
||||
},
|
||||
],
|
||||
}], # OS=="mac"
|
||||
['OS=="win"', {
|
||||
'actions': [
|
||||
{
|
||||
'action_name': 'Dump Symbols',
|
||||
'inputs': [
|
||||
'<(PRODUCT_DIR)/<(project_name).exe',
|
||||
],
|
||||
'outputs': [
|
||||
'<(PRODUCT_DIR)/Atom-Shell.breakpad.syms',
|
||||
],
|
||||
'action': [
|
||||
'python',
|
||||
'tools/win/generate_breakpad_symbols.py',
|
||||
'--symbols-dir=<(PRODUCT_DIR)/Atom-Shell.breakpad.syms',
|
||||
'--jobs=16',
|
||||
'<(PRODUCT_DIR)',
|
||||
'<(libchromiumcontent_library_dir)',
|
||||
],
|
||||
},
|
||||
],
|
||||
}], # OS=="win"
|
||||
],
|
||||
}, # target <(project_name>_dump_symbols
|
||||
],
|
||||
'conditions': [
|
||||
['OS=="mac"', {
|
||||
'targets': [
|
||||
{
|
||||
'target_name': '<(project_name)_framework',
|
||||
'product_name': '<(product_name)',
|
||||
'product_name': '<(framework_name)',
|
||||
'type': 'shared_library',
|
||||
'dependencies': [
|
||||
'<(project_name)_lib',
|
||||
@@ -401,7 +479,6 @@
|
||||
'libraries': [
|
||||
'$(SDKROOT)/System/Library/Frameworks/Carbon.framework',
|
||||
'frameworks/Sparkle.framework',
|
||||
'frameworks/Quincy.framework',
|
||||
],
|
||||
},
|
||||
'mac_bundle': 1,
|
||||
@@ -413,7 +490,7 @@
|
||||
'LIBRARY_SEARCH_PATHS': [
|
||||
'<(libchromiumcontent_library_dir)',
|
||||
],
|
||||
'LD_DYLIB_INSTALL_NAME': '@rpath/<(product_name).framework/<(product_name)',
|
||||
'LD_DYLIB_INSTALL_NAME': '@rpath/<(framework_name).framework/<(framework_name)',
|
||||
'LD_RUNPATH_SEARCH_PATHS': [
|
||||
'@loader_path/Libraries',
|
||||
],
|
||||
@@ -423,12 +500,19 @@
|
||||
},
|
||||
'copies': [
|
||||
{
|
||||
'destination': '<(PRODUCT_DIR)/<(product_name).framework/Versions/A/Libraries',
|
||||
'destination': '<(PRODUCT_DIR)/<(framework_name).framework/Versions/A/Libraries',
|
||||
'files': [
|
||||
'<(libchromiumcontent_library_dir)/ffmpegsumo.so',
|
||||
'<(libchromiumcontent_library_dir)/libchromiumcontent.dylib',
|
||||
],
|
||||
},
|
||||
{
|
||||
'destination': '<(PRODUCT_DIR)/<(framework_name).framework/Versions/A/Resources',
|
||||
'files': [
|
||||
'<(PRODUCT_DIR)/Inspector',
|
||||
'<(PRODUCT_DIR)/crash_report_sender.app',
|
||||
],
|
||||
},
|
||||
],
|
||||
'postbuilds': [
|
||||
{
|
||||
@@ -441,7 +525,7 @@
|
||||
'postbuild_name': 'Add symlinks for framework subdirectories',
|
||||
'action': [
|
||||
'tools/mac/create-framework-subdir-symlinks.sh',
|
||||
'<(product_name)',
|
||||
'<(framework_name)',
|
||||
'Libraries',
|
||||
'Frameworks',
|
||||
],
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "base/values.h"
|
||||
#include "base/command_line.h"
|
||||
#include "browser/browser.h"
|
||||
#include "common/v8_conversions.h"
|
||||
#include "vendor/node/src/node.h"
|
||||
|
||||
namespace atom {
|
||||
@@ -111,14 +112,14 @@ v8::Handle<v8::Value> App::GetVersion(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> App::AppendSwitch(const v8::Arguments &args) {
|
||||
v8::HandleScope scope;
|
||||
|
||||
if (!args[0]->IsString())
|
||||
std::string switch_string;
|
||||
if (!FromV8Arguments(args, &switch_string))
|
||||
return node::ThrowError("Bad argument");
|
||||
|
||||
std::string switch_string(*v8::String::Utf8Value(args[0]));
|
||||
if (args.Length() == 1) {
|
||||
CommandLine::ForCurrentProcess()->AppendSwitch(switch_string);
|
||||
} else {
|
||||
std::string value(*v8::String::Utf8Value(args[1]));
|
||||
std::string value = FromV8Value(args[1]);
|
||||
CommandLine::ForCurrentProcess()->AppendSwitchASCII(
|
||||
switch_string, value);
|
||||
}
|
||||
@@ -130,10 +131,10 @@ v8::Handle<v8::Value> App::AppendSwitch(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> App::AppendArgument(const v8::Arguments &args) {
|
||||
v8::HandleScope scope;
|
||||
|
||||
if (!args[0]->IsString())
|
||||
std::string value;
|
||||
if (!FromV8Arguments(args, &value))
|
||||
return node::ThrowError("Bad argument");
|
||||
|
||||
std::string value(*v8::String::Utf8Value(args[0]));
|
||||
CommandLine::ForCurrentProcess()->AppendArg(value);
|
||||
|
||||
return v8::Undefined();
|
||||
@@ -143,7 +144,7 @@ v8::Handle<v8::Value> App::AppendArgument(const v8::Arguments &args) {
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> App::DockBounce(const v8::Arguments& args) {
|
||||
std::string type(*v8::String::Utf8Value(args[0]));
|
||||
std::string type = FromV8Value(args[0]);
|
||||
int request_id = -1;
|
||||
|
||||
if (type == "critical")
|
||||
@@ -158,21 +159,20 @@ v8::Handle<v8::Value> App::DockBounce(const v8::Arguments& args) {
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> App::DockCancelBounce(const v8::Arguments& args) {
|
||||
Browser::Get()->DockCancelBounce(args[0]->IntegerValue());
|
||||
Browser::Get()->DockCancelBounce(FromV8Value(args[0]));
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> App::DockSetBadgeText(const v8::Arguments& args) {
|
||||
std::string label(*v8::String::Utf8Value(args[0]));
|
||||
Browser::Get()->DockSetBadgeText(label);
|
||||
Browser::Get()->DockSetBadgeText(FromV8Value(args[0]));
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> App::DockGetBadgeText(const v8::Arguments& args) {
|
||||
std::string text(Browser::Get()->DockGetBadgeText());
|
||||
return v8::String::New(text.data(), text.size());
|
||||
return ToV8Value(text);
|
||||
}
|
||||
|
||||
#endif // defined(OS_MACOSX)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "base/values.h"
|
||||
#include "browser/auto_updater.h"
|
||||
#include "common/v8_conversions.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
@@ -56,7 +57,7 @@ v8::Handle<v8::Value> AutoUpdater::New(const v8::Arguments &args) {
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> AutoUpdater::SetFeedURL(const v8::Arguments &args) {
|
||||
auto_updater::AutoUpdater::SetFeedURL(*v8::String::Utf8Value(args[0]));
|
||||
auto_updater::AutoUpdater::SetFeedURL(FromV8Value(args[0]));
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "base/values.h"
|
||||
#include "common/api/api_messages.h"
|
||||
#include "common/v8_conversions.h"
|
||||
#include "common/v8_value_converter_impl.h"
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#include "vendor/node/src/node.h"
|
||||
@@ -22,13 +23,11 @@ namespace api {
|
||||
v8::Handle<v8::Value> BrowserIPC::Send(const v8::Arguments &args) {
|
||||
v8::HandleScope scope;
|
||||
|
||||
if (!args[0]->IsString() || !args[1]->IsNumber() || !args[2]->IsNumber())
|
||||
string16 channel;
|
||||
int process_id, routing_id;
|
||||
if (!FromV8Arguments(args, &channel, &process_id, &routing_id))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
std::string channel(*v8::String::Utf8Value(args[0]));
|
||||
int process_id = args[1]->IntegerValue();
|
||||
int routing_id = args[2]->IntegerValue();
|
||||
|
||||
RenderViewHost* render_view_host(RenderViewHost::FromID(
|
||||
process_id, routing_id));
|
||||
if (!render_view_host)
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "browser/api/atom_api_crash_reporter.h"
|
||||
|
||||
#include "browser/crash_reporter.h"
|
||||
#include "vendor/node/src/node.h"
|
||||
#include "vendor/node/src/node_internals.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> CrashReporter::SetCompanyName(const v8::Arguments &args) {
|
||||
std::string name(*v8::String::Utf8Value(args[0]));
|
||||
crash_reporter::CrashReporter::SetCompanyName(name);
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> CrashReporter::SetSubmissionURL(
|
||||
const v8::Arguments &args) {
|
||||
std::string url(*v8::String::Utf8Value(args[0]));
|
||||
crash_reporter::CrashReporter::SetSubmissionURL(url);
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> CrashReporter::SetAutoSubmit(const v8::Arguments &args) {
|
||||
crash_reporter::CrashReporter::SetAutoSubmit(args[0]->BooleanValue());
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
// static
|
||||
void CrashReporter::Initialize(v8::Handle<v8::Object> target) {
|
||||
node::SetMethod(target, "setCompanyName", SetCompanyName);
|
||||
node::SetMethod(target, "setSubmissionUrl", SetSubmissionURL);
|
||||
node::SetMethod(target, "setAutoSubmit", SetAutoSubmit);
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
||||
|
||||
NODE_MODULE(atom_browser_crash_reporter, atom::api::CrashReporter::Initialize)
|
||||
@@ -4,14 +4,14 @@
|
||||
|
||||
#include "browser/api/atom_api_dialog.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/utf_string_conversions.h"
|
||||
#include "base/values.h"
|
||||
#include "browser/api/atom_api_window.h"
|
||||
#include "base/bind.h"
|
||||
#include "browser/native_window.h"
|
||||
#include "browser/ui/file_dialog.h"
|
||||
#include "browser/ui/message_box.h"
|
||||
#include "common/v8_conversions.h"
|
||||
#include "vendor/node/src/node_internals.h"
|
||||
|
||||
using node::node_isolate;
|
||||
|
||||
namespace atom {
|
||||
|
||||
@@ -19,14 +19,24 @@ namespace api {
|
||||
|
||||
namespace {
|
||||
|
||||
base::FilePath V8ValueToFilePath(v8::Handle<v8::Value> path) {
|
||||
std::string path_string(*v8::String::Utf8Value(path));
|
||||
return base::FilePath::FromUTF8Unsafe(path_string);
|
||||
template<typename T>
|
||||
void CallV8Function(v8::Persistent<v8::Function> callback, T arg) {
|
||||
DCHECK(!callback.IsEmpty());
|
||||
|
||||
v8::HandleScope scope;
|
||||
v8::Handle<v8::Value> value = ToV8Value(arg);
|
||||
callback->Call(callback, 1, &value);
|
||||
callback.Dispose(node_isolate);
|
||||
}
|
||||
|
||||
v8::Handle<v8::Value> FilePathToV8Value(const base::FilePath path) {
|
||||
std::string path_string(path.AsUTF8Unsafe());
|
||||
return v8::String::New(path_string.data(), path_string.size());
|
||||
template<typename T>
|
||||
void CallV8Function2(v8::Persistent<v8::Function> callback,
|
||||
bool result,
|
||||
T arg) {
|
||||
if (result)
|
||||
return CallV8Function<T>(callback, arg);
|
||||
else
|
||||
return CallV8Function<void*>(callback, NULL);
|
||||
}
|
||||
|
||||
void Initialize(v8::Handle<v8::Object> target) {
|
||||
@@ -42,84 +52,103 @@ void Initialize(v8::Handle<v8::Object> target) {
|
||||
v8::Handle<v8::Value> ShowMessageBox(const v8::Arguments &args) {
|
||||
v8::HandleScope scope;
|
||||
|
||||
if (!args[0]->IsNumber() || // type
|
||||
!args[1]->IsArray() || // buttons
|
||||
!args[2]->IsString() || // title
|
||||
!args[3]->IsString() || // message
|
||||
!args[4]->IsString()) // detail
|
||||
int type;
|
||||
std::vector<std::string> buttons;
|
||||
std::string title, message, detail;
|
||||
if (!FromV8Arguments(args, &type, &buttons, &title, &message, &detail))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
NativeWindow* native_window = NULL;
|
||||
if (args[5]->IsObject()) {
|
||||
Window* window = Window::Unwrap<Window>(args[5]->ToObject());
|
||||
if (!window || !window->window())
|
||||
return node::ThrowError("Invalid window");
|
||||
NativeWindow* native_window = FromV8Value(args[5]);
|
||||
v8::Persistent<v8::Function> callback = FromV8Value(args[6]);
|
||||
|
||||
native_window = window->window();
|
||||
if (callback.IsEmpty()) {
|
||||
int chosen = atom::ShowMessageBox(
|
||||
native_window,
|
||||
(MessageBoxType)type,
|
||||
buttons,
|
||||
title,
|
||||
message,
|
||||
detail);
|
||||
return scope.Close(v8::Integer::New(chosen));
|
||||
} else {
|
||||
atom::ShowMessageBox(
|
||||
native_window,
|
||||
(MessageBoxType)type,
|
||||
buttons,
|
||||
title,
|
||||
message,
|
||||
detail,
|
||||
base::Bind(&CallV8Function<int>, callback));
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
MessageBoxType type = (MessageBoxType)(args[0]->IntegerValue());
|
||||
|
||||
std::vector<std::string> buttons;
|
||||
v8::Handle<v8::Array> v8_buttons = v8::Handle<v8::Array>::Cast(args[1]);
|
||||
for (uint32_t i = 0; i < v8_buttons->Length(); ++i)
|
||||
buttons.push_back(*v8::String::Utf8Value(v8_buttons->Get(i)));
|
||||
|
||||
std::string title(*v8::String::Utf8Value(args[2]));
|
||||
std::string message(*v8::String::Utf8Value(args[3]));
|
||||
std::string detail(*v8::String::Utf8Value(args[4]));
|
||||
|
||||
int chosen = atom::ShowMessageBox(
|
||||
native_window, type, buttons, title, message, detail);
|
||||
return scope.Close(v8::Integer::New(chosen));
|
||||
}
|
||||
|
||||
v8::Handle<v8::Value> ShowOpenDialog(const v8::Arguments &args) {
|
||||
v8::HandleScope scope;
|
||||
|
||||
if (!args[0]->IsString() || // title
|
||||
!args[1]->IsString() || // default_path
|
||||
!args[2]->IsNumber()) // properties
|
||||
std::string title;
|
||||
base::FilePath default_path;
|
||||
int properties;
|
||||
if (!FromV8Arguments(args, &title, &default_path, &properties))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
std::string title(*v8::String::Utf8Value(args[0]));
|
||||
base::FilePath default_path(V8ValueToFilePath(args[1]));
|
||||
int properties = args[2]->IntegerValue();
|
||||
NativeWindow* native_window = FromV8Value(args[3]);
|
||||
v8::Persistent<v8::Function> callback = FromV8Value(args[4]);
|
||||
|
||||
std::vector<base::FilePath> paths;
|
||||
if (!file_dialog::ShowOpenDialog(title, default_path, properties, &paths))
|
||||
if (callback.IsEmpty()) {
|
||||
std::vector<base::FilePath> paths;
|
||||
if (!file_dialog::ShowOpenDialog(native_window,
|
||||
title,
|
||||
default_path,
|
||||
properties,
|
||||
&paths))
|
||||
return v8::Undefined();
|
||||
|
||||
v8::Handle<v8::Array> result = v8::Array::New(paths.size());
|
||||
for (size_t i = 0; i < paths.size(); ++i)
|
||||
result->Set(i, ToV8Value(paths[i]));
|
||||
|
||||
return scope.Close(result);
|
||||
} else {
|
||||
file_dialog::ShowOpenDialog(
|
||||
native_window,
|
||||
title,
|
||||
default_path,
|
||||
properties,
|
||||
base::Bind(&CallV8Function2<const std::vector<base::FilePath>&>,
|
||||
callback));
|
||||
return v8::Undefined();
|
||||
|
||||
v8::Handle<v8::Array> result = v8::Array::New(paths.size());
|
||||
for (size_t i = 0; i < paths.size(); ++i)
|
||||
result->Set(i, FilePathToV8Value(paths[i]));
|
||||
|
||||
return scope.Close(result);
|
||||
}
|
||||
}
|
||||
|
||||
v8::Handle<v8::Value> ShowSaveDialog(const v8::Arguments &args) {
|
||||
v8::HandleScope scope;
|
||||
|
||||
if (!args[0]->IsObject() || // window
|
||||
!args[1]->IsString() || // title
|
||||
!args[2]->IsString()) // default_path
|
||||
std::string title;
|
||||
base::FilePath default_path;
|
||||
if (!FromV8Arguments(args, &title, &default_path))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
Window* window = Window::Unwrap<Window>(args[0]->ToObject());
|
||||
if (!window || !window->window())
|
||||
return node::ThrowError("Invalid window");
|
||||
NativeWindow* native_window = FromV8Value(args[2]);
|
||||
v8::Persistent<v8::Function> callback = FromV8Value(args[3]);
|
||||
|
||||
std::string title(*v8::String::Utf8Value(args[1]));
|
||||
base::FilePath default_path(V8ValueToFilePath(args[2]));
|
||||
if (callback.IsEmpty()) {
|
||||
base::FilePath path;
|
||||
if (!file_dialog::ShowSaveDialog(native_window,
|
||||
title,
|
||||
default_path,
|
||||
&path))
|
||||
return v8::Undefined();
|
||||
|
||||
base::FilePath path;
|
||||
if (!file_dialog::ShowSaveDialog(window->window(),
|
||||
title,
|
||||
default_path,
|
||||
&path))
|
||||
return scope.Close(ToV8Value(path));
|
||||
} else {
|
||||
file_dialog::ShowSaveDialog(
|
||||
native_window,
|
||||
title,
|
||||
default_path,
|
||||
base::Bind(&CallV8Function2<const base::FilePath&>, callback));
|
||||
return v8::Undefined();
|
||||
|
||||
return scope.Close(FilePathToV8Value(path));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
|
||||
#include "browser/api/atom_api_event.h"
|
||||
|
||||
#include "browser/native_window.h"
|
||||
#include "common/api/api_messages.h"
|
||||
#include "common/v8_conversions.h"
|
||||
|
||||
using node::node_isolate;
|
||||
|
||||
namespace atom {
|
||||
@@ -13,10 +17,14 @@ namespace api {
|
||||
v8::Persistent<v8::FunctionTemplate> Event::constructor_template_;
|
||||
|
||||
Event::Event()
|
||||
: prevent_default_(false) {
|
||||
: sender_(NULL),
|
||||
message_(NULL),
|
||||
prevent_default_(false) {
|
||||
}
|
||||
|
||||
Event::~Event() {
|
||||
if (sender_ != NULL)
|
||||
sender_->RemoveObserver(this);
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -31,6 +39,8 @@ v8::Handle<v8::Object> Event::CreateV8Object() {
|
||||
constructor_template_->SetClassName(v8::String::NewSymbol("Event"));
|
||||
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "preventDefault", PreventDefault);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "sendReply", SendReply);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "destroy", Destroy);
|
||||
}
|
||||
|
||||
v8::Handle<v8::Object> v8_event =
|
||||
@@ -39,14 +49,30 @@ v8::Handle<v8::Object> Event::CreateV8Object() {
|
||||
return scope.Close(v8_event);
|
||||
}
|
||||
|
||||
v8::Handle<v8::Value> Event::New(const v8::Arguments &args) {
|
||||
void Event::SetSenderAndMessage(NativeWindow* sender, IPC::Message* message) {
|
||||
DCHECK(!sender_);
|
||||
DCHECK(!message_);
|
||||
sender_ = sender;
|
||||
message_ = message;
|
||||
|
||||
sender_->AddObserver(this);
|
||||
}
|
||||
|
||||
void Event::OnWindowClosed() {
|
||||
sender_ = NULL;
|
||||
message_ = NULL;
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Event::New(const v8::Arguments& args) {
|
||||
Event* event = new Event;
|
||||
event->Wrap(args.This());
|
||||
|
||||
return args.This();
|
||||
}
|
||||
|
||||
v8::Handle<v8::Value> Event::PreventDefault(const v8::Arguments &args) {
|
||||
// static
|
||||
v8::Handle<v8::Value> Event::PreventDefault(const v8::Arguments& args) {
|
||||
Event* event = Unwrap<Event>(args.This());
|
||||
if (event == NULL)
|
||||
return node::ThrowError("Event is already destroyed");
|
||||
@@ -56,6 +82,31 @@ v8::Handle<v8::Value> Event::PreventDefault(const v8::Arguments &args) {
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Event::SendReply(const v8::Arguments& args) {
|
||||
Event* event = Unwrap<Event>(args.This());
|
||||
if (event == NULL)
|
||||
return node::ThrowError("Event is already destroyed");
|
||||
|
||||
if (event->message_ == NULL || event->sender_ == NULL)
|
||||
return node::ThrowError("Can only send reply to synchronous events");
|
||||
|
||||
string16 json = FromV8Value(args[0]);
|
||||
|
||||
AtomViewHostMsg_Message_Sync::WriteReplyParams(event->message_, json);
|
||||
event->sender_->Send(event->message_);
|
||||
|
||||
delete event;
|
||||
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Event::Destroy(const v8::Arguments& args) {
|
||||
delete Unwrap<Event>(args.This());
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -6,19 +6,32 @@
|
||||
#define ATOM_BROWSER_ATOM_API_EVENT_H_
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/string16.h"
|
||||
#include "browser/native_window_observer.h"
|
||||
#include "vendor/node/src/node_object_wrap.h"
|
||||
|
||||
namespace IPC {
|
||||
class Message;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class NativeWindow;
|
||||
|
||||
namespace api {
|
||||
|
||||
class Event : public node::ObjectWrap {
|
||||
class Event : public node::ObjectWrap,
|
||||
public NativeWindowObserver {
|
||||
public:
|
||||
virtual ~Event();
|
||||
|
||||
// Create a V8 Event object.
|
||||
static v8::Handle<v8::Object> CreateV8Object();
|
||||
|
||||
// Pass the sender and message to be replied.
|
||||
void SetSenderAndMessage(NativeWindow* sender, IPC::Message* message);
|
||||
|
||||
// Accessor to return handle_, this follows Google C++ Style.
|
||||
v8::Persistent<v8::Object>& handle() { return handle_; }
|
||||
|
||||
@@ -28,12 +41,22 @@ class Event : public node::ObjectWrap {
|
||||
protected:
|
||||
Event();
|
||||
|
||||
// NativeWindowObserver implementations:
|
||||
virtual void OnWindowClosed() OVERRIDE;
|
||||
|
||||
private:
|
||||
static v8::Handle<v8::Value> New(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> PreventDefault(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> New(const v8::Arguments& args);
|
||||
|
||||
static v8::Handle<v8::Value> PreventDefault(const v8::Arguments& args);
|
||||
static v8::Handle<v8::Value> SendReply(const v8::Arguments& args);
|
||||
static v8::Handle<v8::Value> Destroy(const v8::Arguments& args);
|
||||
|
||||
static v8::Persistent<v8::FunctionTemplate> constructor_template_;
|
||||
|
||||
// Replyer for the synchronous messages.
|
||||
NativeWindow* sender_;
|
||||
IPC::Message* message_;
|
||||
|
||||
bool prevent_default_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Event);
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include "browser/api/atom_api_menu.h"
|
||||
|
||||
#include "browser/api/atom_api_window.h"
|
||||
#include "browser/ui/accelerator_util.h"
|
||||
#include "common/v8_conversions.h"
|
||||
|
||||
#define UNWRAP_MEMNU_AND_CHECK \
|
||||
Menu* self = ObjectWrap::Unwrap<Menu>(args.This()); \
|
||||
@@ -18,17 +18,6 @@ namespace api {
|
||||
|
||||
namespace {
|
||||
|
||||
// Converts a V8 value to a string16.
|
||||
string16 V8ValueToUTF16(v8::Handle<v8::Value> value) {
|
||||
v8::String::Value s(value);
|
||||
return string16(reinterpret_cast<const char16*>(*s), s.length());
|
||||
}
|
||||
|
||||
// Converts string16 to V8 String.
|
||||
v8::Handle<v8::Value> UTF16ToV8Value(const string16& s) {
|
||||
return v8::String::New(reinterpret_cast<const uint16_t*>(s.data()), s.size());
|
||||
}
|
||||
|
||||
// Call method of delegate object.
|
||||
v8::Handle<v8::Value> CallDelegate(v8::Handle<v8::Value> default_value,
|
||||
v8::Handle<v8::Object> menu,
|
||||
@@ -93,7 +82,7 @@ bool Menu::GetAcceleratorForCommandId(int command_id,
|
||||
"getAcceleratorForCommandId",
|
||||
command_id);
|
||||
if (shortcut->IsString()) {
|
||||
std::string shortcut_str(*v8::String::Utf8Value(shortcut));
|
||||
std::string shortcut_str = FromV8Value(shortcut);
|
||||
return accelerator_util::StringToAccelerator(shortcut_str, accelerator);
|
||||
}
|
||||
|
||||
@@ -110,18 +99,18 @@ bool Menu::IsItemForCommandIdDynamic(int command_id) const {
|
||||
|
||||
string16 Menu::GetLabelForCommandId(int command_id) const {
|
||||
v8::HandleScope scope;
|
||||
return V8ValueToUTF16(CallDelegate(v8::False(),
|
||||
handle(),
|
||||
"getLabelForCommandId",
|
||||
command_id));
|
||||
return FromV8Value(CallDelegate(v8::False(),
|
||||
handle(),
|
||||
"getLabelForCommandId",
|
||||
command_id));
|
||||
}
|
||||
|
||||
string16 Menu::GetSublabelForCommandId(int command_id) const {
|
||||
v8::HandleScope scope;
|
||||
return V8ValueToUTF16(CallDelegate(v8::False(),
|
||||
handle(),
|
||||
"getSubLabelForCommandId",
|
||||
command_id));
|
||||
return FromV8Value(CallDelegate(v8::False(),
|
||||
handle(),
|
||||
"getSubLabelForCommandId",
|
||||
command_id));
|
||||
}
|
||||
|
||||
void Menu::ExecuteCommand(int command_id, int event_flags) {
|
||||
@@ -145,16 +134,15 @@ v8::Handle<v8::Value> Menu::New(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Menu::InsertItem(const v8::Arguments &args) {
|
||||
UNWRAP_MEMNU_AND_CHECK;
|
||||
|
||||
if (!args[0]->IsNumber() || !args[1]->IsNumber() || !args[2]->IsString())
|
||||
int index, command_id;
|
||||
string16 label;
|
||||
if (!FromV8Arguments(args, &index, &command_id, &label))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
int index = args[0]->IntegerValue();
|
||||
|
||||
if (index < 0)
|
||||
self->model_->AddItem(args[1]->IntegerValue(), V8ValueToUTF16(args[2]));
|
||||
self->model_->AddItem(command_id, label);
|
||||
else
|
||||
self->model_->InsertItemAt(
|
||||
index, args[1]->IntegerValue(), V8ValueToUTF16(args[2]));
|
||||
self->model_->InsertItemAt(index, command_id, label);
|
||||
|
||||
return v8::Undefined();
|
||||
}
|
||||
@@ -163,16 +151,15 @@ v8::Handle<v8::Value> Menu::InsertItem(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Menu::InsertCheckItem(const v8::Arguments &args) {
|
||||
UNWRAP_MEMNU_AND_CHECK;
|
||||
|
||||
if (!args[0]->IsNumber() || !args[1]->IsNumber() || !args[2]->IsString())
|
||||
int index, command_id;
|
||||
string16 label;
|
||||
if (!FromV8Arguments(args, &index, &command_id, &label))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
int index = args[0]->IntegerValue();
|
||||
int command_id = args[1]->IntegerValue();
|
||||
|
||||
if (index < 0)
|
||||
self->model_->AddCheckItem(command_id, V8ValueToUTF16(args[2]));
|
||||
self->model_->AddCheckItem(command_id, label);
|
||||
else
|
||||
self->model_->InsertCheckItemAt(index, command_id, V8ValueToUTF16(args[2]));
|
||||
self->model_->InsertCheckItemAt(index, command_id, label);
|
||||
|
||||
return v8::Undefined();
|
||||
}
|
||||
@@ -181,21 +168,15 @@ v8::Handle<v8::Value> Menu::InsertCheckItem(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Menu::InsertRadioItem(const v8::Arguments &args) {
|
||||
UNWRAP_MEMNU_AND_CHECK;
|
||||
|
||||
if (!args[0]->IsNumber() ||
|
||||
!args[1]->IsNumber() ||
|
||||
!args[2]->IsString() ||
|
||||
!args[3]->IsNumber())
|
||||
int index, command_id, group_id;
|
||||
string16 label;
|
||||
if (!FromV8Arguments(args, &index, &command_id, &label, &group_id))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
int index = args[0]->IntegerValue();
|
||||
int command_id = args[1]->IntegerValue();
|
||||
int group_id = args[3]->IntegerValue();
|
||||
|
||||
if (index < 0)
|
||||
self->model_->AddRadioItem(command_id, V8ValueToUTF16(args[2]), group_id);
|
||||
self->model_->AddRadioItem(command_id, label, group_id);
|
||||
else
|
||||
self->model_->InsertRadioItemAt(
|
||||
index, command_id, V8ValueToUTF16(args[2]), group_id);
|
||||
self->model_->InsertRadioItemAt(index, command_id, label, group_id);
|
||||
|
||||
return v8::Undefined();
|
||||
}
|
||||
@@ -204,11 +185,10 @@ v8::Handle<v8::Value> Menu::InsertRadioItem(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Menu::InsertSeparator(const v8::Arguments &args) {
|
||||
UNWRAP_MEMNU_AND_CHECK;
|
||||
|
||||
if (!args[0]->IsNumber())
|
||||
int index;
|
||||
if (!FromV8Arguments(args, &index))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
int index = args[0]->IntegerValue();
|
||||
|
||||
if (index < 0)
|
||||
self->model_->AddSeparator(ui::NORMAL_SEPARATOR);
|
||||
else
|
||||
@@ -221,25 +201,20 @@ v8::Handle<v8::Value> Menu::InsertSeparator(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Menu::InsertSubMenu(const v8::Arguments &args) {
|
||||
UNWRAP_MEMNU_AND_CHECK;
|
||||
|
||||
if (!args[0]->IsNumber() ||
|
||||
!args[1]->IsNumber() ||
|
||||
!args[2]->IsString() ||
|
||||
!args[3]->IsObject())
|
||||
int index, command_id;
|
||||
string16 label;
|
||||
if (!FromV8Arguments(args, &index, &command_id, &label))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
Menu* submenu = ObjectWrap::Unwrap<Menu>(args[3]->ToObject());
|
||||
if (!submenu)
|
||||
return node::ThrowTypeError("The submenu is already destroyed");
|
||||
|
||||
int index = args[0]->IntegerValue();
|
||||
int command_id = args[1]->IntegerValue();
|
||||
|
||||
if (index < 0)
|
||||
self->model_->AddSubMenu(
|
||||
command_id, V8ValueToUTF16(args[2]), submenu->model_.get());
|
||||
self->model_->AddSubMenu(command_id, label, submenu->model_.get());
|
||||
else
|
||||
self->model_->InsertSubMenuAt(
|
||||
index, command_id, V8ValueToUTF16(args[2]), submenu->model_.get());
|
||||
index, command_id, label, submenu->model_.get());
|
||||
|
||||
return v8::Undefined();
|
||||
}
|
||||
@@ -248,7 +223,9 @@ v8::Handle<v8::Value> Menu::InsertSubMenu(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Menu::SetIcon(const v8::Arguments &args) {
|
||||
UNWRAP_MEMNU_AND_CHECK;
|
||||
|
||||
if (!args[0]->IsNumber() || !args[1]->IsString())
|
||||
int index;
|
||||
base::FilePath path;
|
||||
if (!FromV8Arguments(args, &index, &path))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
// FIXME use webkit_glue's image decoder here.
|
||||
@@ -260,10 +237,12 @@ v8::Handle<v8::Value> Menu::SetIcon(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Menu::SetSublabel(const v8::Arguments &args) {
|
||||
UNWRAP_MEMNU_AND_CHECK;
|
||||
|
||||
if (!args[0]->IsNumber() || !args[1]->IsString())
|
||||
int index;
|
||||
string16 label;
|
||||
if (!FromV8Arguments(args, &index, &label))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
self->model_->SetSublabel(args[0]->IntegerValue(), V8ValueToUTF16(args[1]));
|
||||
self->model_->SetSublabel(index, label);
|
||||
|
||||
return v8::Undefined();
|
||||
}
|
||||
@@ -301,14 +280,14 @@ v8::Handle<v8::Value> Menu::GetCommandIdAt(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Menu::GetLabelAt(const v8::Arguments &args) {
|
||||
UNWRAP_MEMNU_AND_CHECK;
|
||||
int index = args[0]->IntegerValue();
|
||||
return UTF16ToV8Value(self->model_->GetLabelAt(index));
|
||||
return ToV8Value(self->model_->GetLabelAt(index));
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Menu::GetSublabelAt(const v8::Arguments &args) {
|
||||
UNWRAP_MEMNU_AND_CHECK;
|
||||
int index = args[0]->IntegerValue();
|
||||
return UTF16ToV8Value(self->model_->GetSublabelAt(index));
|
||||
return ToV8Value(self->model_->GetSublabelAt(index));
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -334,11 +313,11 @@ v8::Handle<v8::Value> Menu::IsVisibleAt(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Menu::Popup(const v8::Arguments &args) {
|
||||
UNWRAP_MEMNU_AND_CHECK;
|
||||
|
||||
Window* window = Window::Unwrap<Window>(args[0]->ToObject());
|
||||
if (!window)
|
||||
return node::ThrowTypeError("Invalid window");
|
||||
atom::NativeWindow* window;
|
||||
if (!FromV8Arguments(args, &window))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
self->Popup(window->window());
|
||||
self->Popup(window);
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
@@ -372,6 +351,10 @@ void Menu::Initialize(v8::Handle<v8::Object> target) {
|
||||
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "popup", Popup);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "attachToWindow", AttachToWindow);
|
||||
#endif
|
||||
|
||||
target->Set(v8::String::NewSymbol("Menu"), t->GetFunction());
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
|
||||
@@ -68,7 +68,9 @@ class Menu : public EventEmitter,
|
||||
|
||||
static v8::Handle<v8::Value> Popup(const v8::Arguments &args);
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
#if defined(OS_WIN)
|
||||
static v8::Handle<v8::Value> AttachToWindow(const v8::Arguments &args);
|
||||
#elif defined(OS_MACOSX)
|
||||
static v8::Handle<v8::Value> SetApplicationMenu(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> SendActionToFirstResponder(
|
||||
const v8::Arguments &args);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "base/mac/scoped_sending_event.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "browser/native_window.h"
|
||||
#include "common/v8_conversions.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/browser/web_contents_view.h"
|
||||
|
||||
@@ -95,10 +96,10 @@ v8::Handle<v8::Value> Menu::SendActionToFirstResponder(
|
||||
const v8::Arguments &args) {
|
||||
v8::HandleScope scope;
|
||||
|
||||
if (!args[0]->IsString())
|
||||
std::string action;
|
||||
if (!FromV8Arguments(args, &action))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
std::string action(*v8::String::Utf8Value(args[0]));
|
||||
MenuMac::SendActionToFirstResponder(action);
|
||||
|
||||
return v8::Undefined();
|
||||
|
||||
@@ -4,8 +4,11 @@
|
||||
|
||||
#include "browser/api/atom_api_menu_win.h"
|
||||
|
||||
#include "browser/native_window_win.h"
|
||||
#include "browser/ui/win/menu_2.h"
|
||||
#include "common/v8_conversions.h"
|
||||
#include "ui/gfx/point.h"
|
||||
#include "ui/gfx/screen.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
@@ -19,8 +22,26 @@ MenuWin::~MenuWin() {
|
||||
}
|
||||
|
||||
void MenuWin::Popup(NativeWindow* native_window) {
|
||||
gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
|
||||
menu_.reset(new atom::Menu2(model_.get()));
|
||||
menu_->RunContextMenuAt(gfx::Point(0, 0));
|
||||
menu_->RunContextMenuAt(cursor);
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Menu::AttachToWindow(const v8::Arguments& args) {
|
||||
v8::HandleScope scope;
|
||||
|
||||
Menu* self = ObjectWrap::Unwrap<Menu>(args.This());
|
||||
if (self == NULL)
|
||||
return node::ThrowError("Menu is already destroyed");
|
||||
|
||||
NativeWindow* native_window;
|
||||
if (!FromV8Arguments(args, &native_window))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
static_cast<NativeWindowWin*>(native_window)->SetMenu(self->model_.get());
|
||||
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
@@ -7,10 +7,11 @@
|
||||
#include "base/stl_util.h"
|
||||
#include "browser/atom_browser_context.h"
|
||||
#include "browser/net/adapter_request_job.h"
|
||||
#include "browser/net/atom_url_request_context_getter.h"
|
||||
#include "browser/net/atom_url_request_job_factory.h"
|
||||
#include "common/v8_conversions.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "net/url_request/url_request_context.h"
|
||||
#include "net/url_request/url_request_context_getter.h"
|
||||
#include "vendor/node/src/node.h"
|
||||
#include "vendor/node/src/node_internals.h"
|
||||
|
||||
@@ -29,13 +30,16 @@ v8::Persistent<v8::Object> g_protocol_object;
|
||||
typedef std::map<std::string, v8::Persistent<v8::Function>> HandlersMap;
|
||||
static HandlersMap g_handlers;
|
||||
|
||||
static const char* kEarlyUseProtocolError = "This method can only be used"
|
||||
"after the application has finished launching.";
|
||||
|
||||
// Emit an event for the protocol module.
|
||||
void EmitEventInUI(const std::string& event, const std::string& parameter) {
|
||||
v8::HandleScope scope;
|
||||
|
||||
v8::Local<v8::Value> argv[] = {
|
||||
v8::String::New(event.data(), event.size()),
|
||||
v8::String::New(parameter.data(), parameter.size()),
|
||||
v8::Handle<v8::Value> argv[] = {
|
||||
ToV8Value(event),
|
||||
ToV8Value(parameter),
|
||||
};
|
||||
node::MakeCallback(g_protocol_object, "emit", arraysize(argv), argv);
|
||||
}
|
||||
@@ -55,10 +59,7 @@ v8::Handle<v8::Object> ConvertURLRequestToV8Object(
|
||||
|
||||
// Get the job factory.
|
||||
AtomURLRequestJobFactory* GetRequestJobFactory() {
|
||||
return static_cast<AtomURLRequestJobFactory*>(
|
||||
const_cast<net::URLRequestJobFactory*>(
|
||||
static_cast<content::BrowserContext*>(AtomBrowserContext::Get())->
|
||||
GetRequestContext()->GetURLRequestContext()->job_factory()));
|
||||
return AtomBrowserContext::Get()->url_request_context_getter()->job_factory();
|
||||
}
|
||||
|
||||
class CustomProtocolRequestJob : public AdapterRequestJob {
|
||||
@@ -83,7 +84,7 @@ class CustomProtocolRequestJob : public AdapterRequestJob {
|
||||
|
||||
// Determine the type of the job we are going to create.
|
||||
if (result->IsString()) {
|
||||
std::string data = *v8::String::Utf8Value(result);
|
||||
std::string data = FromV8Value(result);
|
||||
content::BrowserThread::PostTask(
|
||||
content::BrowserThread::IO,
|
||||
FROM_HERE,
|
||||
@@ -95,14 +96,12 @@ class CustomProtocolRequestJob : public AdapterRequestJob {
|
||||
return;
|
||||
} else if (result->IsObject()) {
|
||||
v8::Handle<v8::Object> obj = result->ToObject();
|
||||
std::string name = *v8::String::Utf8Value(obj->GetConstructorName());
|
||||
std::string name = FromV8Value(obj->GetConstructorName());
|
||||
if (name == "RequestStringJob") {
|
||||
std::string mime_type = *v8::String::Utf8Value(obj->Get(
|
||||
std::string mime_type = FromV8Value(obj->Get(
|
||||
v8::String::New("mimeType")));
|
||||
std::string charset = *v8::String::Utf8Value(obj->Get(
|
||||
v8::String::New("charset")));
|
||||
std::string data = *v8::String::Utf8Value(obj->Get(
|
||||
v8::String::New("data")));
|
||||
std::string charset = FromV8Value(obj->Get(v8::String::New("charset")));
|
||||
std::string data = FromV8Value(obj->Get(v8::String::New("data")));
|
||||
|
||||
content::BrowserThread::PostTask(
|
||||
content::BrowserThread::IO,
|
||||
@@ -114,8 +113,7 @@ class CustomProtocolRequestJob : public AdapterRequestJob {
|
||||
data));
|
||||
return;
|
||||
} else if (name == "RequestFileJob") {
|
||||
base::FilePath path = base::FilePath::FromUTF8Unsafe(
|
||||
*v8::String::Utf8Value(obj->Get(v8::String::New("path"))));
|
||||
base::FilePath path = FromV8Value(obj->Get(v8::String::New("path")));
|
||||
|
||||
content::BrowserThread::PostTask(
|
||||
content::BrowserThread::IO,
|
||||
@@ -183,16 +181,20 @@ class CustomProtocolHandler : public ProtocolHandler {
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Protocol::RegisterProtocol(const v8::Arguments& args) {
|
||||
std::string scheme(*v8::String::Utf8Value(args[0]));
|
||||
std::string scheme;
|
||||
v8::Persistent<v8::Function> callback;
|
||||
if (!FromV8Arguments(args, &scheme, &callback))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
if (g_handlers.find(scheme) != g_handlers.end() ||
|
||||
net::URLRequest::IsHandledProtocol(scheme))
|
||||
return node::ThrowError("The scheme is already registered");
|
||||
|
||||
if (AtomBrowserContext::Get()->url_request_context_getter() == NULL)
|
||||
return node::ThrowError(kEarlyUseProtocolError);
|
||||
|
||||
// Store the handler in a map.
|
||||
if (!args[1]->IsFunction())
|
||||
return node::ThrowError("Handler must be a function");
|
||||
g_handlers[scheme] = v8::Persistent<v8::Function>::New(
|
||||
node::node_isolate, v8::Handle<v8::Function>::Cast(args[1]));
|
||||
g_handlers[scheme] = callback;
|
||||
|
||||
content::BrowserThread::PostTask(content::BrowserThread::IO,
|
||||
FROM_HERE,
|
||||
@@ -203,7 +205,12 @@ v8::Handle<v8::Value> Protocol::RegisterProtocol(const v8::Arguments& args) {
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Protocol::UnregisterProtocol(const v8::Arguments& args) {
|
||||
std::string scheme(*v8::String::Utf8Value(args[0]));
|
||||
std::string scheme;
|
||||
if (!FromV8Arguments(args, &scheme))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
if (AtomBrowserContext::Get()->url_request_context_getter() == NULL)
|
||||
return node::ThrowError(kEarlyUseProtocolError);
|
||||
|
||||
// Erase the handler from map.
|
||||
HandlersMap::iterator it(g_handlers.find(scheme));
|
||||
@@ -220,24 +227,27 @@ v8::Handle<v8::Value> Protocol::UnregisterProtocol(const v8::Arguments& args) {
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Protocol::IsHandledProtocol(const v8::Arguments& args) {
|
||||
return v8::Boolean::New(net::URLRequest::IsHandledProtocol(
|
||||
*v8::String::Utf8Value(args[0])));
|
||||
return ToV8Value(net::URLRequest::IsHandledProtocol(FromV8Value(args[0])));
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Protocol::InterceptProtocol(const v8::Arguments& args) {
|
||||
std::string scheme(*v8::String::Utf8Value(args[0]));
|
||||
std::string scheme;
|
||||
v8::Persistent<v8::Function> callback;
|
||||
if (!FromV8Arguments(args, &scheme, &callback))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
if (!GetRequestJobFactory()->HasProtocolHandler(scheme))
|
||||
return node::ThrowError("Cannot intercept procotol");
|
||||
|
||||
if (ContainsKey(g_handlers, scheme))
|
||||
return node::ThrowError("Cannot intercept custom procotols");
|
||||
|
||||
if (AtomBrowserContext::Get()->url_request_context_getter() == NULL)
|
||||
return node::ThrowError(kEarlyUseProtocolError);
|
||||
|
||||
// Store the handler in a map.
|
||||
if (!args[1]->IsFunction())
|
||||
return node::ThrowError("Handler must be a function");
|
||||
g_handlers[scheme] = v8::Persistent<v8::Function>::New(
|
||||
node::node_isolate, v8::Handle<v8::Function>::Cast(args[1]));
|
||||
g_handlers[scheme] = callback;
|
||||
|
||||
content::BrowserThread::PostTask(content::BrowserThread::IO,
|
||||
FROM_HERE,
|
||||
@@ -247,7 +257,12 @@ v8::Handle<v8::Value> Protocol::InterceptProtocol(const v8::Arguments& args) {
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Protocol::UninterceptProtocol(const v8::Arguments& args) {
|
||||
std::string scheme(*v8::String::Utf8Value(args[0]));
|
||||
std::string scheme;
|
||||
if (!FromV8Arguments(args, &scheme))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
if (AtomBrowserContext::Get()->url_request_context_getter() == NULL)
|
||||
return node::ThrowError(kEarlyUseProtocolError);
|
||||
|
||||
// Erase the handler from map.
|
||||
HandlersMap::iterator it(g_handlers.find(scheme));
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "base/values.h"
|
||||
#include "browser/native_window.h"
|
||||
#include "common/v8_conversions.h"
|
||||
#include "common/v8_value_converter_impl.h"
|
||||
#include "content/public/browser/navigation_entry.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
@@ -13,6 +14,7 @@
|
||||
#include "ui/gfx/point.h"
|
||||
#include "ui/gfx/rect.h"
|
||||
#include "ui/gfx/size.h"
|
||||
#include "vendor/node/src/node_buffer.h"
|
||||
|
||||
using content::V8ValueConverter;
|
||||
using content::NavigationController;
|
||||
@@ -27,15 +29,6 @@ namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
namespace {
|
||||
|
||||
// Converts string16 to V8 String.
|
||||
v8::Handle<v8::String> UTF16ToV8String(const string16& s) {
|
||||
return v8::String::New(reinterpret_cast<const uint16_t*>(s.data()), s.size());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Window::Window(v8::Handle<v8::Object> wrapper, base::DictionaryValue* options)
|
||||
: EventEmitter(wrapper),
|
||||
window_(NativeWindow::Create(options)) {
|
||||
@@ -69,8 +62,9 @@ void Window::WillCloseWindow(bool* prevent_default) {
|
||||
void Window::OnWindowClosed() {
|
||||
Emit("closed");
|
||||
|
||||
// Free memory immediately when window is closed.
|
||||
delete this;
|
||||
// Free memory when native window is closed, the delete is delayed so other
|
||||
// observers would not get a invalid pointer of NativeWindow.
|
||||
base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
|
||||
}
|
||||
|
||||
void Window::OnWindowBlur() {
|
||||
@@ -89,6 +83,20 @@ void Window::OnRendererCrashed() {
|
||||
Emit("crashed");
|
||||
}
|
||||
|
||||
void Window::OnCapturePageDone(v8::Persistent<v8::Function> callback,
|
||||
const std::vector<unsigned char>& data) {
|
||||
v8::HandleScope scope;
|
||||
|
||||
// TODO(zcbenz): Use new Buffer API when we updated to node v0.12.x.
|
||||
node::Buffer* buffer = node::Buffer::New(
|
||||
reinterpret_cast<const char*>(data.data()),
|
||||
data.size());
|
||||
|
||||
v8::Handle<v8::Value> arg = buffer->handle_;
|
||||
callback->Call(v8::Context::GetCurrent()->Global(), 1, &arg);
|
||||
callback.Dispose(v8::Isolate::GetCurrent());
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::New(const v8::Arguments &args) {
|
||||
v8::HandleScope scope;
|
||||
@@ -108,6 +116,9 @@ v8::Handle<v8::Value> Window::New(const v8::Arguments &args) {
|
||||
|
||||
new Window(args.This(), static_cast<base::DictionaryValue*>(options.get()));
|
||||
|
||||
// Give js code a chance to do initialization.
|
||||
node::MakeCallback(args.This(), "_init", 0, NULL);
|
||||
|
||||
return args.This();
|
||||
}
|
||||
|
||||
@@ -141,7 +152,7 @@ v8::Handle<v8::Value> Window::Focus(const v8::Arguments &args) {
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::IsFocused(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
return v8::Boolean::New(self->window_->IsFocused());
|
||||
return ToV8Value(self->window_->IsFocused());
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -162,6 +173,12 @@ v8::Handle<v8::Value> Window::Hide(const v8::Arguments &args) {
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::IsVisible(const v8::Arguments& args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
return ToV8Value(self->window_->IsVisible());
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::Maximize(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
@@ -202,10 +219,11 @@ v8::Handle<v8::Value> Window::Restore(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::SetFullscreen(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
if (args.Length() < 1 || !args[0]->IsBoolean())
|
||||
bool fs;
|
||||
if (!FromV8Arguments(args, &fs))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
self->window_->SetFullscreen(args[0]->BooleanValue());
|
||||
|
||||
self->window_->SetFullscreen(fs);
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
@@ -213,18 +231,18 @@ v8::Handle<v8::Value> Window::SetFullscreen(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::IsFullscreen(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
return v8::Boolean::New(self->window_->IsFullscreen());
|
||||
return ToV8Value(self->window_->IsFullscreen());
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::SetSize(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
if (args.Length() < 2)
|
||||
int width, height;
|
||||
if (!FromV8Arguments(args, &width, &height))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
self->window_->SetSize(
|
||||
gfx::Size(args[0]->IntegerValue(), args[1]->IntegerValue()));
|
||||
|
||||
self->window_->SetSize(gfx::Size(width, height));
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
@@ -234,8 +252,8 @@ v8::Handle<v8::Value> Window::GetSize(const v8::Arguments &args) {
|
||||
|
||||
gfx::Size size = self->window_->GetSize();
|
||||
v8::Handle<v8::Array> ret = v8::Array::New(2);
|
||||
ret->Set(0, v8::Integer::New(size.width()));
|
||||
ret->Set(1, v8::Integer::New(size.height()));
|
||||
ret->Set(0, ToV8Value(size.width()));
|
||||
ret->Set(1, ToV8Value(size.height()));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -244,11 +262,11 @@ v8::Handle<v8::Value> Window::GetSize(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::SetMinimumSize(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
if (args.Length() < 2)
|
||||
int width, height;
|
||||
if (!FromV8Arguments(args, &width, &height))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
self->window_->SetMinimumSize(
|
||||
gfx::Size(args[0]->IntegerValue(), args[1]->IntegerValue()));
|
||||
|
||||
self->window_->SetMinimumSize(gfx::Size(width, height));
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
@@ -258,8 +276,8 @@ v8::Handle<v8::Value> Window::GetMinimumSize(const v8::Arguments &args) {
|
||||
|
||||
gfx::Size size = self->window_->GetMinimumSize();
|
||||
v8::Handle<v8::Array> ret = v8::Array::New(2);
|
||||
ret->Set(0, v8::Integer::New(size.width()));
|
||||
ret->Set(1, v8::Integer::New(size.height()));
|
||||
ret->Set(0, ToV8Value(size.width()));
|
||||
ret->Set(1, ToV8Value(size.height()));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -268,11 +286,12 @@ v8::Handle<v8::Value> Window::GetMinimumSize(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::SetMaximumSize(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
if (args.Length() < 2)
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
self->window_->SetMaximumSize(
|
||||
gfx::Size(args[0]->IntegerValue(), args[1]->IntegerValue()));
|
||||
|
||||
int width, height;
|
||||
if (!FromV8Arguments(args, &width, &height))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
self->window_->SetMaximumSize(gfx::Size(width, height));
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
@@ -282,8 +301,8 @@ v8::Handle<v8::Value> Window::GetMaximumSize(const v8::Arguments &args) {
|
||||
|
||||
gfx::Size size = self->window_->GetMaximumSize();
|
||||
v8::Handle<v8::Array> ret = v8::Array::New(2);
|
||||
ret->Set(0, v8::Integer::New(size.width()));
|
||||
ret->Set(1, v8::Integer::New(size.height()));
|
||||
ret->Set(0, ToV8Value(size.width()));
|
||||
ret->Set(1, ToV8Value(size.height()));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -292,10 +311,11 @@ v8::Handle<v8::Value> Window::GetMaximumSize(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::SetResizable(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
if (args.Length() < 1 || !args[0]->IsBoolean())
|
||||
bool resizable;
|
||||
if (!FromV8Arguments(args, &resizable))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
self->window_->SetResizable(args[0]->BooleanValue());
|
||||
|
||||
self->window_->SetResizable(resizable);
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
@@ -303,17 +323,18 @@ v8::Handle<v8::Value> Window::SetResizable(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::IsResizable(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
return v8::Boolean::New(self->window_->IsResizable());
|
||||
return ToV8Value(self->window_->IsResizable());
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::SetAlwaysOnTop(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
if (args.Length() < 1 || !args[0]->IsBoolean())
|
||||
bool top;
|
||||
if (!FromV8Arguments(args, &top))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
self->window_->SetAlwaysOnTop(args[0]->BooleanValue());
|
||||
|
||||
self->window_->SetAlwaysOnTop(top);
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
@@ -321,7 +342,7 @@ v8::Handle<v8::Value> Window::SetAlwaysOnTop(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::IsAlwaysOnTop(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
return v8::Boolean::New(self->window_->IsAlwaysOnTop());
|
||||
return ToV8Value(self->window_->IsAlwaysOnTop());
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -337,11 +358,11 @@ v8::Handle<v8::Value> Window::Center(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::SetPosition(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
if (args.Length() < 2)
|
||||
int x, y;
|
||||
if (!FromV8Arguments(args, &x, &y))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
self->window_->SetPosition(
|
||||
gfx::Point(args[0]->IntegerValue(), args[1]->IntegerValue()));
|
||||
|
||||
self->window_->SetPosition(gfx::Point(x, y));
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
@@ -351,8 +372,8 @@ v8::Handle<v8::Value> Window::GetPosition(const v8::Arguments &args) {
|
||||
|
||||
gfx::Point pos = self->window_->GetPosition();
|
||||
v8::Handle<v8::Array> ret = v8::Array::New(2);
|
||||
ret->Set(0, v8::Integer::New(pos.x()));
|
||||
ret->Set(1, v8::Integer::New(pos.y()));
|
||||
ret->Set(0, ToV8Value(pos.x()));
|
||||
ret->Set(1, ToV8Value(pos.y()));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -361,20 +382,18 @@ v8::Handle<v8::Value> Window::GetPosition(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::SetTitle(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
if (args.Length() < 1 || !args[0]->IsString())
|
||||
std::string title;
|
||||
if (!FromV8Arguments(args, &title))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
self->window_->SetTitle(*v8::String::Utf8Value(args[0]));
|
||||
|
||||
self->window_->SetTitle(title);
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::GetTitle(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
std::string title = self->window_->GetTitle();
|
||||
|
||||
return v8::String::New(title.c_str(), title.size());
|
||||
return ToV8Value(self->window_->GetTitle());
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -391,10 +410,11 @@ v8::Handle<v8::Value> Window::FlashFrame(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::SetKiosk(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
if (args.Length() < 1 || !args[0]->IsBoolean())
|
||||
bool kiosk;
|
||||
if (!FromV8Arguments(args, &kiosk))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
self->window_->SetKiosk(args[0]->BooleanValue());
|
||||
|
||||
self->window_->SetKiosk(kiosk);
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
@@ -402,7 +422,7 @@ v8::Handle<v8::Value> Window::SetKiosk(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::IsKiosk(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
return v8::Boolean::New(self->window_->IsKiosk());
|
||||
return ToV8Value(self->window_->IsKiosk());
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -423,13 +443,21 @@ v8::Handle<v8::Value> Window::CloseDevTools(const v8::Arguments &args) {
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::IsDevToolsOpened(const v8::Arguments& args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
return ToV8Value(self->window_->IsDevToolsOpened());
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::InspectElement(const v8::Arguments& args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
self->window_->InspectElement(args[0]->IntegerValue(),
|
||||
args[1]->IntegerValue());
|
||||
int x, y;
|
||||
if (!FromV8Arguments(args, &x, &y))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
self->window_->InspectElement(x, y);
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
@@ -454,7 +482,7 @@ v8::Handle<v8::Value> Window::BlurWebView(const v8::Arguments &args) {
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::IsWebViewFocused(const v8::Arguments& args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
return v8::Boolean::New(self->window_->IsWebViewFocused());
|
||||
return ToV8Value(self->window_->IsWebViewFocused());
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -467,28 +495,42 @@ v8::Handle<v8::Value> Window::RestartHangMonitorTimeout(
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::CapturePage(const v8::Arguments& args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
gfx::Rect rect;
|
||||
v8::Persistent<v8::Function> callback;
|
||||
if (!FromV8Arguments(args, &rect, &callback) &&
|
||||
!FromV8Arguments(args, &callback))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
self->window_->CapturePage(rect, base::Bind(&Window::OnCapturePageDone,
|
||||
base::Unretained(self),
|
||||
callback));
|
||||
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::GetPageTitle(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
string16 title = self->window_->GetWebContents()->GetTitle();
|
||||
|
||||
return UTF16ToV8String(title);
|
||||
return ToV8Value(self->window_->GetWebContents()->GetTitle());
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::IsLoading(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
return v8::Boolean::New(self->window_->GetWebContents()->IsLoading());
|
||||
return ToV8Value(self->window_->GetWebContents()->IsLoading());
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::IsWaitingForResponse(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
return v8::Boolean::New(
|
||||
self->window_->GetWebContents()->IsWaitingForResponse());
|
||||
return ToV8Value(self->window_->GetWebContents()->IsWaitingForResponse());
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -504,14 +546,14 @@ v8::Handle<v8::Value> Window::Stop(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::GetRoutingID(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
return v8::Integer::New(self->window_->GetWebContents()->GetRoutingID());
|
||||
return ToV8Value(self->window_->GetWebContents()->GetRoutingID());
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::GetProcessID(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
return v8::Integer::New(
|
||||
return ToV8Value(
|
||||
self->window_->GetWebContents()->GetRenderProcessHost()->GetID());
|
||||
}
|
||||
|
||||
@@ -519,19 +561,20 @@ v8::Handle<v8::Value> Window::GetProcessID(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::IsCrashed(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
return v8::Boolean::New(self->window_->GetWebContents()->IsCrashed());
|
||||
return ToV8Value(self->window_->GetWebContents()->IsCrashed());
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::LoadURL(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
if (args.Length() < 1 || !args[0]->IsString())
|
||||
std::string url;
|
||||
if (!FromV8Arguments(args, &url))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
NavigationController& controller =
|
||||
self->window_->GetWebContents()->GetController();
|
||||
controller.LoadURL(GURL(*v8::String::Utf8Value(args[0])),
|
||||
controller.LoadURL(GURL(url),
|
||||
content::Referrer(),
|
||||
content::PAGE_TRANSITION_AUTO_TOPLEVEL,
|
||||
std::string());
|
||||
@@ -549,7 +592,7 @@ v8::Handle<v8::Value> Window::GetURL(const v8::Arguments &args) {
|
||||
if (controller.GetActiveEntry())
|
||||
url = controller.GetActiveEntry()->GetVirtualURL().spec();
|
||||
|
||||
return v8::String::New(url.c_str(), url.size());
|
||||
return ToV8Value(url);
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -559,7 +602,7 @@ v8::Handle<v8::Value> Window::CanGoBack(const v8::Arguments &args) {
|
||||
NavigationController& controller =
|
||||
self->window_->GetWebContents()->GetController();
|
||||
|
||||
return v8::Boolean::New(controller.CanGoBack());
|
||||
return ToV8Value(controller.CanGoBack());
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -569,21 +612,21 @@ v8::Handle<v8::Value> Window::CanGoForward(const v8::Arguments &args) {
|
||||
NavigationController& controller =
|
||||
self->window_->GetWebContents()->GetController();
|
||||
|
||||
return v8::Boolean::New(controller.CanGoForward());
|
||||
return ToV8Value(controller.CanGoForward());
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::CanGoToOffset(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
if (args.Length() < 1)
|
||||
int offset;
|
||||
if (!FromV8Arguments(args, &offset))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
NavigationController& controller =
|
||||
self->window_->GetWebContents()->GetController();
|
||||
int offset = args[0]->IntegerValue();
|
||||
|
||||
return v8::Boolean::New(controller.CanGoToOffset(offset));
|
||||
return ToV8Value(controller.CanGoToOffset(offset));
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -612,12 +655,13 @@ v8::Handle<v8::Value> Window::GoForward(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::GoToIndex(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
if (args.Length() < 1)
|
||||
int index;
|
||||
if (!FromV8Arguments(args, &index))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
NavigationController& controller =
|
||||
self->window_->GetWebContents()->GetController();
|
||||
controller.GoToIndex(args[0]->IntegerValue());
|
||||
controller.GoToIndex(index);
|
||||
|
||||
return v8::Undefined();
|
||||
}
|
||||
@@ -626,12 +670,13 @@ v8::Handle<v8::Value> Window::GoToIndex(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::GoToOffset(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
if (args.Length() < 1)
|
||||
int offset;
|
||||
if (!FromV8Arguments(args, &offset))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
NavigationController& controller =
|
||||
self->window_->GetWebContents()->GetController();
|
||||
controller.GoToOffset(args[0]->IntegerValue());
|
||||
controller.GoToOffset(offset);
|
||||
|
||||
return v8::Undefined();
|
||||
}
|
||||
@@ -673,6 +718,7 @@ void Window::Initialize(v8::Handle<v8::Object> target) {
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "isFocused", IsFocused);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "show", Show);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "hide", Hide);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "isVisible", IsVisible);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "maximize", Maximize);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "unmaximize", Unmaximize);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "minimize", Minimize);
|
||||
@@ -699,6 +745,7 @@ void Window::Initialize(v8::Handle<v8::Object> target) {
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "isKiosk", IsKiosk);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "openDevTools", OpenDevTools);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "closeDevTools", CloseDevTools);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "isDevToolsOpened", IsDevToolsOpened);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "inspectElement", InspectElement);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "focusOnWebView", FocusOnWebView);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "blurWebView", BlurWebView);
|
||||
@@ -706,6 +753,7 @@ void Window::Initialize(v8::Handle<v8::Object> target) {
|
||||
NODE_SET_PROTOTYPE_METHOD(t,
|
||||
"restartHangMonitorTimeout",
|
||||
RestartHangMonitorTimeout);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "capturePage", CapturePage);
|
||||
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "getPageTitle", GetPageTitle);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "isLoading", IsLoading);
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#ifndef ATOM_BROWSER_API_ATOM_API_WINDOW_H_
|
||||
#define ATOM_BROWSER_API_ATOM_API_WINDOW_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "browser/api/atom_api_event_emitter.h"
|
||||
#include "browser/native_window_observer.h"
|
||||
@@ -53,6 +55,7 @@ class Window : public EventEmitter,
|
||||
static v8::Handle<v8::Value> IsFocused(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> Show(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> Hide(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> IsVisible(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> Maximize(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> Unmaximize(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> Minimize(const v8::Arguments &args);
|
||||
@@ -79,12 +82,14 @@ class Window : public EventEmitter,
|
||||
static v8::Handle<v8::Value> IsKiosk(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> OpenDevTools(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> CloseDevTools(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> IsDevToolsOpened(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> InspectElement(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> FocusOnWebView(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> BlurWebView(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> IsWebViewFocused(const v8::Arguments& args);
|
||||
static v8::Handle<v8::Value> RestartHangMonitorTimeout(
|
||||
const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> CapturePage(const v8::Arguments& args);
|
||||
|
||||
// APIs for WebContents.
|
||||
static v8::Handle<v8::Value> GetPageTitle(const v8::Arguments &args);
|
||||
@@ -108,6 +113,10 @@ class Window : public EventEmitter,
|
||||
static v8::Handle<v8::Value> Reload(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> ReloadIgnoringCache(const v8::Arguments &args);
|
||||
|
||||
// Called when capturePage is done.
|
||||
void OnCapturePageDone(v8::Persistent<v8::Function> callback,
|
||||
const std::vector<unsigned char>& data);
|
||||
|
||||
scoped_ptr<NativeWindow> window_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Window);
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/values.h"
|
||||
#include "browser/api/atom_api_event.h"
|
||||
#include "common/v8_conversions.h"
|
||||
#include "common/v8_value_converter_impl.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "vendor/node/src/node.h"
|
||||
@@ -42,7 +44,7 @@ void AtomBrowserBindings::AfterLoad() {
|
||||
|
||||
void AtomBrowserBindings::OnRendererMessage(int process_id,
|
||||
int routing_id,
|
||||
const std::string& channel,
|
||||
const string16& channel,
|
||||
const base::ListValue& args) {
|
||||
v8::HandleScope scope;
|
||||
|
||||
@@ -53,7 +55,7 @@ void AtomBrowserBindings::OnRendererMessage(int process_id,
|
||||
// process.emit(channel, 'message', process_id, routing_id);
|
||||
std::vector<v8::Handle<v8::Value>> arguments;
|
||||
arguments.reserve(3 + args.GetSize());
|
||||
arguments.push_back(v8::String::New(channel.c_str(), channel.size()));
|
||||
arguments.push_back(ToV8Value(channel));
|
||||
const base::Value* value;
|
||||
if (args.Get(0, &value))
|
||||
arguments.push_back(converter->ToV8Value(value, context));
|
||||
@@ -72,21 +74,24 @@ void AtomBrowserBindings::OnRendererMessage(int process_id,
|
||||
void AtomBrowserBindings::OnRendererMessageSync(
|
||||
int process_id,
|
||||
int routing_id,
|
||||
const std::string& channel,
|
||||
const string16& channel,
|
||||
const base::ListValue& args,
|
||||
base::DictionaryValue* result) {
|
||||
NativeWindow* sender,
|
||||
IPC::Message* message) {
|
||||
v8::HandleScope scope;
|
||||
|
||||
v8::Handle<v8::Context> context = v8::Context::GetCurrent();
|
||||
|
||||
scoped_ptr<V8ValueConverter> converter(new V8ValueConverterImpl());
|
||||
|
||||
v8::Handle<v8::Object> event = v8::Object::New();
|
||||
// Create the event object.
|
||||
v8::Handle<v8::Object> event = api::Event::CreateV8Object();
|
||||
api::Event::Unwrap<api::Event>(event)->SetSenderAndMessage(sender, message);
|
||||
|
||||
// process.emit(channel, 'sync-message', event, process_id, routing_id);
|
||||
std::vector<v8::Handle<v8::Value>> arguments;
|
||||
arguments.reserve(3 + args.GetSize());
|
||||
arguments.push_back(v8::String::New(channel.c_str(), channel.size()));
|
||||
arguments.push_back(ToV8Value(channel));
|
||||
const base::Value* value;
|
||||
if (args.Get(0, &value))
|
||||
arguments.push_back(converter->ToV8Value(value, context));
|
||||
@@ -101,11 +106,6 @@ void AtomBrowserBindings::OnRendererMessageSync(
|
||||
}
|
||||
|
||||
node::MakeCallback(node::process, "emit", arguments.size(), &arguments[0]);
|
||||
|
||||
scoped_ptr<base::Value> base_event(converter->FromV8Value(event, context));
|
||||
DCHECK(base_event && base_event->IsType(base::Value::TYPE_DICTIONARY));
|
||||
|
||||
result->Swap(static_cast<base::DictionaryValue*>(base_event.get()));
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -5,17 +5,21 @@
|
||||
#ifndef ATOM_BROWSER_API_ATOM_BROWSER_BINDINGS_
|
||||
#define ATOM_BROWSER_API_ATOM_BROWSER_BINDINGS_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/string16.h"
|
||||
#include "common/api/atom_bindings.h"
|
||||
|
||||
namespace base {
|
||||
class DictionaryValue;
|
||||
class ListValue;
|
||||
}
|
||||
|
||||
namespace IPC {
|
||||
class Message;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class NativeWindow;
|
||||
|
||||
class AtomBrowserBindings : public AtomBindings {
|
||||
public:
|
||||
AtomBrowserBindings();
|
||||
@@ -27,15 +31,16 @@ class AtomBrowserBindings : public AtomBindings {
|
||||
// Called when received a message from renderer.
|
||||
void OnRendererMessage(int process_id,
|
||||
int routing_id,
|
||||
const std::string& channel,
|
||||
const string16& channel,
|
||||
const base::ListValue& args);
|
||||
|
||||
// Called when received a synchronous message from renderer.
|
||||
void OnRendererMessageSync(int process_id,
|
||||
int routing_id,
|
||||
const std::string& channel,
|
||||
const string16& channel,
|
||||
const base::ListValue& args,
|
||||
base::DictionaryValue* result);
|
||||
NativeWindow* sender,
|
||||
IPC::Message* message);
|
||||
|
||||
// The require('atom').browserMainParts object.
|
||||
v8::Handle<v8::Object> browser_main_parts() {
|
||||
|
||||
@@ -9,6 +9,15 @@ app = new Application
|
||||
app.getHomeDir = ->
|
||||
process.env[if process.platform is 'win32' then 'USERPROFILE' else 'HOME']
|
||||
|
||||
app.getBrowserWindows = ->
|
||||
require('../../atom/objects-registry.js').getAllWindows()
|
||||
|
||||
app.setApplicationMenu = (menu) ->
|
||||
require('menu').setApplicationMenu menu
|
||||
|
||||
app.getApplicationMenu = ->
|
||||
require('menu').getApplicationMenu()
|
||||
|
||||
app.commandLine =
|
||||
appendSwitch: bindings.appendSwitch,
|
||||
appendArgument: bindings.appendArgument
|
||||
|
||||
@@ -1,28 +1,36 @@
|
||||
EventEmitter = require('events').EventEmitter
|
||||
app = require 'app'
|
||||
v8Util = process.atomBinding 'v8_util'
|
||||
objectsRegistry = require '../../atom/objects-registry.js'
|
||||
|
||||
BrowserWindow = process.atomBinding('window').BrowserWindow
|
||||
BrowserWindow::__proto__ = EventEmitter.prototype
|
||||
|
||||
BrowserWindow::_init = ->
|
||||
# Simulate the application menu on platforms other than OS X.
|
||||
if process.platform isnt 'darwin'
|
||||
menu = app.getApplicationMenu()
|
||||
@setMenu menu if menu?
|
||||
|
||||
BrowserWindow::toggleDevTools = ->
|
||||
opened = v8Util.getHiddenValue this, 'devtoolsOpened'
|
||||
if opened
|
||||
@closeDevTools()
|
||||
v8Util.setHiddenValue this, 'devtoolsOpened', false
|
||||
else
|
||||
@openDevTools()
|
||||
v8Util.setHiddenValue this, 'devtoolsOpened', true
|
||||
if @isDevToolsOpened() then @closeDevTools() else @openDevTools()
|
||||
|
||||
BrowserWindow::restart = ->
|
||||
@loadUrl(@getUrl())
|
||||
|
||||
BrowserWindow::setMenu = (menu) ->
|
||||
throw new Error('BrowserWindow.setMenu is only available on Windows') unless process.platform is 'win32'
|
||||
|
||||
throw new TypeError('Invalid menu') unless menu?.constructor?.name is 'Menu'
|
||||
|
||||
@menu = menu # Keep a reference of menu in case of GC.
|
||||
@menu.attachToWindow this
|
||||
|
||||
BrowserWindow.getFocusedWindow = ->
|
||||
windows = objectsRegistry.getAllWindows()
|
||||
windows = app.getBrowserWindows()
|
||||
return window for window in windows when window.isFocused()
|
||||
|
||||
BrowserWindow.fromProcessIdAndRoutingId = (processId, routingId) ->
|
||||
windows = objectsRegistry.getAllWindows()
|
||||
windows = app.getBrowserWindows()
|
||||
return window for window in windows when window.getProcessId() == processId and
|
||||
window.getRoutingId() == routingId
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
module.exports = process.atomBinding 'crash_reporter'
|
||||
@@ -1,4 +1,5 @@
|
||||
binding = process.atomBinding 'dialog'
|
||||
v8Util = process.atomBinding 'v8_util'
|
||||
BrowserWindow = require 'browser-window'
|
||||
|
||||
fileDialogProperties =
|
||||
@@ -7,48 +8,71 @@ fileDialogProperties =
|
||||
messageBoxTypes = ['none', 'info', 'warning']
|
||||
|
||||
module.exports =
|
||||
showOpenDialog: (options) ->
|
||||
options = title: 'Open', properties: ['openFile'] unless options?
|
||||
options.properties = options.properties ? ['openFile']
|
||||
showOpenDialog: (window, options, callback) ->
|
||||
unless window?.constructor is BrowserWindow
|
||||
# Shift.
|
||||
callback = options
|
||||
options = window
|
||||
window = null
|
||||
|
||||
options ?= title: 'Open', properties: ['openFile']
|
||||
options.properties ?= ['openFile']
|
||||
throw new TypeError('Properties need to be array') unless Array.isArray options.properties
|
||||
|
||||
properties = 0
|
||||
for prop, value of fileDialogProperties
|
||||
properties |= value if prop in options.properties
|
||||
|
||||
options.title = options.title ? ''
|
||||
options.defaultPath = options.defaultPath ? ''
|
||||
options.title ?= ''
|
||||
options.defaultPath ?= ''
|
||||
|
||||
binding.showOpenDialog options.title, options.defaultPath, properties
|
||||
binding.showOpenDialog String(options.title),
|
||||
String(options.defaultPath),
|
||||
properties,
|
||||
window,
|
||||
callback
|
||||
|
||||
showSaveDialog: (window, options) ->
|
||||
throw new TypeError('Invalid window') unless window?.constructor is BrowserWindow
|
||||
options = title: 'Save' unless options?
|
||||
|
||||
options.title = options.title ? ''
|
||||
options.defaultPath = options.defaultPath ? ''
|
||||
|
||||
binding.showSaveDialog window, options.title, options.defaultPath
|
||||
|
||||
showMessageBox: (window, options) ->
|
||||
if window? and window.constructor isnt BrowserWindow
|
||||
showSaveDialog: (window, options, callback) ->
|
||||
unless window?.constructor is BrowserWindow
|
||||
# Shift.
|
||||
callback = options
|
||||
options = window
|
||||
window = null
|
||||
|
||||
options = type: 'none' unless options?
|
||||
options.type = options.type ? 'none'
|
||||
options ?= title: 'Save'
|
||||
options.title ?= ''
|
||||
options.defaultPath ?= ''
|
||||
|
||||
binding.showSaveDialog String(options.title),
|
||||
String(options.defaultPath),
|
||||
window,
|
||||
callback
|
||||
|
||||
showMessageBox: (window, options, callback) ->
|
||||
unless window?.constructor is BrowserWindow
|
||||
# Shift.
|
||||
callback = options
|
||||
options = window
|
||||
window = null
|
||||
|
||||
options ?= type: 'none'
|
||||
options.type ?= 'none'
|
||||
options.type = messageBoxTypes.indexOf options.type
|
||||
throw new TypeError('Invalid message box type') unless options.type > -1
|
||||
|
||||
throw new TypeError('Buttons need to be array') unless Array.isArray options.buttons
|
||||
|
||||
options.title = options.title ? ''
|
||||
options.message = options.message ? ''
|
||||
options.detail = options.detail ? ''
|
||||
options.title ?= ''
|
||||
options.message ?= ''
|
||||
options.detail ?= ''
|
||||
|
||||
binding.showMessageBox options.type,
|
||||
options.buttons,
|
||||
String(options.title),
|
||||
String(options.message),
|
||||
String(options.detail),
|
||||
window
|
||||
window,
|
||||
callback
|
||||
|
||||
# Mark standard asynchronous functions.
|
||||
v8Util.setHiddenValue f, 'asynchronous', true for k, f of module.exports
|
||||
|
||||
@@ -14,8 +14,13 @@ class Ipc extends EventEmitter
|
||||
constructor: ->
|
||||
process.on 'ATOM_INTERNAL_MESSAGE', (args...) =>
|
||||
@emit(args...)
|
||||
process.on 'ATOM_INTERNAL_MESSAGE_SYNC', (args...) =>
|
||||
@emit(args...)
|
||||
process.on 'ATOM_INTERNAL_MESSAGE_SYNC', (channel, event, args...) =>
|
||||
set = (value) -> event.sendReply JSON.stringify(value)
|
||||
|
||||
Object.defineProperty event, 'returnValue', {set}
|
||||
Object.defineProperty event, 'result', {set}
|
||||
|
||||
@emit(channel, event, args...)
|
||||
|
||||
send: (processId, routingId, args...) ->
|
||||
@sendChannel(processId, routingId, 'message', args...)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
BrowserWindow = require 'browser-window'
|
||||
|
||||
nextCommandId = 0
|
||||
|
||||
class MenuItem
|
||||
@@ -26,7 +28,7 @@ class MenuItem
|
||||
@commandId = ++nextCommandId
|
||||
@click = =>
|
||||
if typeof click is 'function'
|
||||
click.apply this, arguments
|
||||
click this, BrowserWindow.getFocusedWindow()
|
||||
else if typeof @selector is 'string'
|
||||
Menu.sendActionToFirstResponder @selector
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ EventEmitter = require('events').EventEmitter
|
||||
IDWeakMap = require 'id-weak-map'
|
||||
MenuItem = require 'menu-item'
|
||||
|
||||
app = require 'app'
|
||||
bindings = process.atomBinding 'menu'
|
||||
|
||||
Menu = bindings.Menu
|
||||
@@ -39,13 +40,22 @@ Menu::insert = (pos, item) ->
|
||||
getAcceleratorForCommandId: (commandId) => @commandsMap[commandId]?.accelerator
|
||||
executeCommand: (commandId) =>
|
||||
activeItem = @commandsMap[commandId]
|
||||
activeItem.click(activeItem) if activeItem?
|
||||
activeItem.click() if activeItem?
|
||||
@items.splice pos, 0, item
|
||||
@commandsMap[item.commandId] = item
|
||||
|
||||
applicationMenu = null
|
||||
Menu.setApplicationMenu = (menu) ->
|
||||
throw new TypeError('Invalid menu') unless menu?.constructor is Menu
|
||||
bindings.setApplicationMenu menu
|
||||
applicationMenu = menu # Keep a reference.
|
||||
|
||||
if process.platform is 'darwin'
|
||||
bindings.setApplicationMenu menu
|
||||
else
|
||||
windows = app.getBrowserWindows()
|
||||
w.setMenu menu for w in windows
|
||||
|
||||
Menu.getApplicationMenu = -> applicationMenu
|
||||
|
||||
Menu.sendActionToFirstResponder = bindings.sendActionToFirstResponder
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ atom.browserMainParts =
|
||||
global.__atom = atom
|
||||
|
||||
# Add browser/api/lib to require's search paths,
|
||||
# which contains javascript part of Atom's built-in libraries.
|
||||
# which contains javascript part of Atom's built-in libraries.
|
||||
globalPaths = require('module').globalPaths
|
||||
globalPaths.push path.join process.resourcesPath, 'browser', 'api', 'lib'
|
||||
|
||||
@@ -38,11 +38,11 @@ process.on 'uncaughtException', (error) ->
|
||||
# Show error in GUI.
|
||||
message = error.stack ? "#{error.name}: #{error.message}"
|
||||
require('dialog').showMessageBox
|
||||
type: 'warning'
|
||||
title: 'An javascript error occured in the browser'
|
||||
message: 'uncaughtException'
|
||||
detail: message
|
||||
buttons: ['OK']
|
||||
type: 'warning'
|
||||
title: 'An javascript error occured in the browser'
|
||||
message: 'uncaughtException'
|
||||
detail: message
|
||||
buttons: ['OK']
|
||||
|
||||
# Load the RPC server.
|
||||
require './rpc-server.js'
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
BrowserWindow = require 'browser-window'
|
||||
EventEmitter = require('events').EventEmitter
|
||||
IDWeakMap = require 'id-weak-map'
|
||||
v8Util = process.atomBinding 'v8_util'
|
||||
|
||||
# Class to reference all objects.
|
||||
class ObjectsStore
|
||||
@stores = {}
|
||||
|
||||
@@ -37,46 +39,57 @@ class ObjectsStore
|
||||
key = "#{processId}_#{routingId}"
|
||||
delete @stores[key]
|
||||
|
||||
# Objects in weak map will be not referenced (so we won't leak memory), and
|
||||
# every object created in browser will have a unique id in weak map.
|
||||
objectsWeakMap = new IDWeakMap
|
||||
objectsWeakMap.add = (obj) ->
|
||||
id = IDWeakMap::add.call this, obj
|
||||
v8Util.setHiddenValue obj, 'atomId', id
|
||||
id
|
||||
class ObjectsRegistry extends EventEmitter
|
||||
constructor: ->
|
||||
# Objects in weak map will be not referenced (so we won't leak memory), and
|
||||
# every object created in browser will have a unique id in weak map.
|
||||
@objectsWeakMap = new IDWeakMap
|
||||
@objectsWeakMap.add = (obj) ->
|
||||
id = IDWeakMap::add.call this, obj
|
||||
v8Util.setHiddenValue obj, 'atomId', id
|
||||
id
|
||||
|
||||
windowsWeakMap = new IDWeakMap
|
||||
# Remember all windows in the weak map.
|
||||
@windowsWeakMap = new IDWeakMap
|
||||
process.on 'ATOM_BROWSER_INTERNAL_NEW', (obj) =>
|
||||
if obj.constructor is BrowserWindow
|
||||
id = @windowsWeakMap.add obj
|
||||
obj.on 'destroyed', => @windowsWeakMap.remove id
|
||||
|
||||
process.on 'ATOM_BROWSER_INTERNAL_NEW', (obj) ->
|
||||
# Remember all windows.
|
||||
if obj.constructor is BrowserWindow
|
||||
id = windowsWeakMap.add obj
|
||||
obj.on 'destroyed', ->
|
||||
windowsWeakMap.remove id
|
||||
# Register a new object, the object would be kept referenced until you release
|
||||
# it explicitly.
|
||||
add: (processId, routingId, obj) ->
|
||||
# Some native objects may already been added to objectsWeakMap, be care not
|
||||
# to add it twice.
|
||||
@objectsWeakMap.add obj unless v8Util.getHiddenValue obj, 'atomId'
|
||||
id = v8Util.getHiddenValue obj, 'atomId'
|
||||
|
||||
exports.add = (processId, routingId, obj) ->
|
||||
# Some native objects may already been added to objectsWeakMap, be care not
|
||||
# to add it twice.
|
||||
objectsWeakMap.add obj unless v8Util.getHiddenValue obj, 'atomId'
|
||||
id = v8Util.getHiddenValue obj, 'atomId'
|
||||
# Store and reference the object, then return the storeId which points to
|
||||
# where the object is stored. The caller can later dereference the object
|
||||
# with the storeId.
|
||||
# We use a difference key because the same object can be referenced for
|
||||
# multiple times by the same renderer view.
|
||||
store = ObjectsStore.forRenderView processId, routingId
|
||||
storeId = store.add obj
|
||||
|
||||
# Store and reference the object, then return the storeId which points to
|
||||
# where the object is stored. The caller can later dereference the object
|
||||
# with the storeId.
|
||||
store = ObjectsStore.forRenderView processId, routingId
|
||||
storeId = store.add obj
|
||||
[id, storeId]
|
||||
|
||||
[id, storeId]
|
||||
# Get an object according to its id.
|
||||
get: (id) ->
|
||||
@objectsWeakMap.get id
|
||||
|
||||
exports.get = (id) ->
|
||||
objectsWeakMap.get id
|
||||
# Remove an object according to its storeId.
|
||||
remove: (processId, routingId, storeId) ->
|
||||
ObjectsStore.forRenderView(processId, routingId).remove storeId
|
||||
|
||||
exports.getAllWindows = () ->
|
||||
keys = windowsWeakMap.keys()
|
||||
windowsWeakMap.get key for key in keys
|
||||
# Clear all references to objects from renderer view.
|
||||
clear: (processId, routingId) ->
|
||||
@emit "release-renderer-view-#{processId}-#{routingId}"
|
||||
ObjectsStore.releaseForRenderView processId, routingId
|
||||
|
||||
exports.remove = (processId, routingId, storeId) ->
|
||||
ObjectsStore.forRenderView(processId, routingId).remove storeId
|
||||
# Return an array of all browser windows.
|
||||
getAllWindows: ->
|
||||
keys = @windowsWeakMap.keys()
|
||||
@windowsWeakMap.get key for key in keys
|
||||
|
||||
exports.clear = (processId, routingId) ->
|
||||
ObjectsStore.releaseForRenderView processId, routingId
|
||||
module.exports = new ObjectsRegistry
|
||||
|
||||
@@ -52,37 +52,55 @@ unwrapArgs = (processId, routingId, args) ->
|
||||
returnValue = metaToValue meta.value
|
||||
-> returnValue
|
||||
when 'function'
|
||||
rendererReleased = false
|
||||
objectsRegistry.once "release-renderer-view-#{processId}-#{routingId}", ->
|
||||
rendererReleased = true
|
||||
|
||||
ret = ->
|
||||
throw new Error('Calling a callback of released renderer view') if rendererReleased
|
||||
ipc.sendChannel processId, routingId, 'ATOM_RENDERER_CALLBACK', meta.id, valueToMeta(processId, routingId, arguments)
|
||||
v8Util.setDestructor ret, ->
|
||||
return if rendererReleased
|
||||
ipc.sendChannel processId, routingId, 'ATOM_RENDERER_RELEASE_CALLBACK', meta.id
|
||||
ret
|
||||
else throw new TypeError("Unknown type: #{meta.type}")
|
||||
|
||||
args.map metaToValue
|
||||
|
||||
# Call a function and send reply asynchronously if it's a an asynchronous
|
||||
# style function and the caller didn't pass a callback.
|
||||
callFunction = (event, processId, routingId, func, caller, args) ->
|
||||
if v8Util.getHiddenValue(func, 'asynchronous') and typeof args[args.length - 1] isnt 'function'
|
||||
args.push (ret) ->
|
||||
event.returnValue = valueToMeta processId, routingId, ret
|
||||
func.apply caller, args
|
||||
else
|
||||
ret = func.apply caller, args
|
||||
event.returnValue = valueToMeta processId, routingId, ret
|
||||
|
||||
ipc.on 'ATOM_BROWSER_REQUIRE', (event, processId, routingId, module) ->
|
||||
try
|
||||
event.result = valueToMeta processId, routingId, require(module)
|
||||
event.returnValue = valueToMeta processId, routingId, require(module)
|
||||
catch e
|
||||
event.result = errorToMeta e
|
||||
event.returnValue = errorToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_GLOBAL', (event, processId, routingId, name) ->
|
||||
try
|
||||
event.result = valueToMeta processId, routingId, global[name]
|
||||
event.returnValue = valueToMeta processId, routingId, global[name]
|
||||
catch e
|
||||
event.result = errorToMeta e
|
||||
event.returnValue = errorToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_RELEASE_RENDER_VIEW', (event, processId, routingId) ->
|
||||
objectsRegistry.clear processId, routingId
|
||||
event.returnValue = null
|
||||
|
||||
ipc.on 'ATOM_BROWSER_CURRENT_WINDOW', (event, processId, routingId) ->
|
||||
try
|
||||
BrowserWindow = require 'browser-window'
|
||||
window = BrowserWindow.fromProcessIdAndRoutingId processId, routingId
|
||||
event.result = valueToMeta processId, routingId, window
|
||||
event.returnValue = valueToMeta processId, routingId, window
|
||||
catch e
|
||||
event.result = errorToMeta e
|
||||
event.returnValue = errorToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_CONSTRUCTOR', (event, processId, routingId, id, args) ->
|
||||
try
|
||||
@@ -91,18 +109,17 @@ ipc.on 'ATOM_BROWSER_CONSTRUCTOR', (event, processId, routingId, id, args) ->
|
||||
# Call new with array of arguments.
|
||||
# http://stackoverflow.com/questions/1606797/use-of-apply-with-new-operator-is-this-possible
|
||||
obj = new (Function::bind.apply(constructor, [null].concat(args)))
|
||||
event.result = valueToMeta processId, routingId, obj
|
||||
event.returnValue = valueToMeta processId, routingId, obj
|
||||
catch e
|
||||
event.result = errorToMeta e
|
||||
event.returnValue = errorToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_FUNCTION_CALL', (event, processId, routingId, id, args) ->
|
||||
try
|
||||
args = unwrapArgs processId, routingId, args
|
||||
func = objectsRegistry.get id
|
||||
ret = func.apply global, args
|
||||
event.result = valueToMeta processId, routingId, ret
|
||||
callFunction event, processId, routingId, func, global, args
|
||||
catch e
|
||||
event.result = errorToMeta e
|
||||
event.returnValue = errorToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', (event, processId, routingId, id, method, args) ->
|
||||
try
|
||||
@@ -110,32 +127,32 @@ ipc.on 'ATOM_BROWSER_MEMBER_CONSTRUCTOR', (event, processId, routingId, id, meth
|
||||
constructor = objectsRegistry.get(id)[method]
|
||||
# Call new with array of arguments.
|
||||
obj = new (Function::bind.apply(constructor, [null].concat(args)))
|
||||
event.result = valueToMeta processId, routingId, obj
|
||||
event.returnValue = valueToMeta processId, routingId, obj
|
||||
catch e
|
||||
event.result = errorToMeta e
|
||||
event.returnValue = errorToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_MEMBER_CALL', (event, processId, routingId, id, method, args) ->
|
||||
try
|
||||
args = unwrapArgs processId, routingId, args
|
||||
obj = objectsRegistry.get id
|
||||
ret = obj[method].apply(obj, args)
|
||||
event.result = valueToMeta processId, routingId, ret
|
||||
callFunction event, processId, routingId, obj[method], obj, args
|
||||
catch e
|
||||
event.result = errorToMeta e
|
||||
event.returnValue = errorToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_MEMBER_SET', (event, processId, routingId, id, name, value) ->
|
||||
try
|
||||
obj = objectsRegistry.get id
|
||||
obj[name] = value
|
||||
event.returnValue = null
|
||||
catch e
|
||||
event.result = errorToMeta e
|
||||
event.returnValue = errorToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_MEMBER_GET', (event, processId, routingId, id, name) ->
|
||||
try
|
||||
obj = objectsRegistry.get id
|
||||
event.result = valueToMeta processId, routingId, obj[name]
|
||||
event.returnValue = valueToMeta processId, routingId, obj[name]
|
||||
catch e
|
||||
event.result = errorToMeta e
|
||||
event.returnValue = errorToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_DEREFERENCE', (processId, routingId, storeId) ->
|
||||
objectsRegistry.remove processId, routingId, storeId
|
||||
|
||||
@@ -4,14 +4,9 @@
|
||||
|
||||
#include "browser/atom_browser_client.h"
|
||||
|
||||
#include "browser/atom_browser_context.h"
|
||||
#include "browser/atom_browser_main_parts.h"
|
||||
#include "browser/net/atom_url_request_job_factory.h"
|
||||
#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/url_request_context.h"
|
||||
#include "net/url_request/url_request_context_storage.h"
|
||||
#include "vendor/brightray/browser/url_request_context_getter.h"
|
||||
#include "browser/net/atom_url_request_context_getter.h"
|
||||
#include "webkit/glue/webpreferences.h"
|
||||
|
||||
namespace atom {
|
||||
@@ -25,31 +20,8 @@ AtomBrowserClient::~AtomBrowserClient() {
|
||||
net::URLRequestContextGetter* AtomBrowserClient::CreateRequestContext(
|
||||
content::BrowserContext* browser_context,
|
||||
content::ProtocolHandlerMap* protocol_handlers) {
|
||||
content::ProtocolHandlerMap preset_handlers;
|
||||
std::swap(preset_handlers, *protocol_handlers);
|
||||
|
||||
// Create our implementaton of job factory.
|
||||
AtomURLRequestJobFactory* job_factory = new AtomURLRequestJobFactory;
|
||||
content::ProtocolHandlerMap::iterator it;
|
||||
for (it = preset_handlers.begin(); it != preset_handlers.end(); ++it)
|
||||
job_factory->SetProtocolHandler(it->first, it->second.release());
|
||||
job_factory->SetProtocolHandler(chrome::kDataScheme,
|
||||
new net::DataProtocolHandler);
|
||||
job_factory->SetProtocolHandler(chrome::kFileScheme,
|
||||
new net::FileProtocolHandler);
|
||||
|
||||
// Go through default procedure.
|
||||
net::URLRequestContextGetter* request_context_getter =
|
||||
brightray::BrowserClient::CreateRequestContext(browser_context,
|
||||
protocol_handlers);
|
||||
net::URLRequestContext* request_context =
|
||||
request_context_getter->GetURLRequestContext();
|
||||
|
||||
// Replace default job factory.
|
||||
storage_.reset(new net::URLRequestContextStorage(request_context));
|
||||
storage_->set_job_factory(job_factory);
|
||||
|
||||
return request_context_getter;
|
||||
return static_cast<AtomBrowserContext*>(browser_context)->
|
||||
CreateRequestContext(protocol_handlers);
|
||||
}
|
||||
|
||||
void AtomBrowserClient::OverrideWebkitPrefs(
|
||||
|
||||
@@ -7,10 +7,6 @@
|
||||
|
||||
#include "brightray/browser/browser_client.h"
|
||||
|
||||
namespace net {
|
||||
class URLRequestContextStorage;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomBrowserClient : public brightray::BrowserClient {
|
||||
@@ -34,8 +30,6 @@ class AtomBrowserClient : public brightray::BrowserClient {
|
||||
virtual brightray::BrowserMainParts* OverrideCreateBrowserMainParts(
|
||||
const content::MainFunctionParams&) OVERRIDE;
|
||||
|
||||
scoped_ptr<net::URLRequestContextStorage> storage_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomBrowserClient);
|
||||
};
|
||||
|
||||
|
||||
@@ -5,15 +5,65 @@
|
||||
#include "browser/atom_browser_context.h"
|
||||
|
||||
#include "browser/atom_browser_main_parts.h"
|
||||
#include "browser/net/atom_url_request_context_getter.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/resource_context.h"
|
||||
#include "vendor/brightray/browser/network_delegate.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
AtomBrowserContext::AtomBrowserContext() {
|
||||
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();
|
||||
}
|
||||
|
||||
private:
|
||||
AtomURLRequestContextGetter* getter_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomResourceContext);
|
||||
};
|
||||
|
||||
AtomBrowserContext::AtomBrowserContext()
|
||||
: resource_context_(new AtomResourceContext) {
|
||||
}
|
||||
|
||||
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),
|
||||
CreateNetworkDelegate().Pass(),
|
||||
protocol_handlers);
|
||||
|
||||
resource_context_->set_url_request_context_getter(url_request_getter_.get());
|
||||
return url_request_getter_.get();
|
||||
}
|
||||
|
||||
content::ResourceContext* AtomBrowserContext::GetResourceContext() {
|
||||
return resource_context_.get();
|
||||
}
|
||||
|
||||
// static
|
||||
AtomBrowserContext* AtomBrowserContext::Get() {
|
||||
return static_cast<AtomBrowserContext*>(
|
||||
|
||||
@@ -10,14 +10,34 @@
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomResourceContext;
|
||||
class AtomURLRequestContextGetter;
|
||||
|
||||
class AtomBrowserContext : public brightray::BrowserContext {
|
||||
public:
|
||||
AtomBrowserContext();
|
||||
virtual ~AtomBrowserContext();
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
protected:
|
||||
// content::BrowserContext implementations:
|
||||
virtual content::ResourceContext* GetResourceContext() OVERRIDE;
|
||||
|
||||
private:
|
||||
scoped_ptr<AtomResourceContext> resource_context_;
|
||||
scoped_refptr<AtomURLRequestContextGetter> url_request_getter_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomBrowserContext);
|
||||
};
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "browser/atom_browser_context.h"
|
||||
#include "browser/browser.h"
|
||||
#include "common/node_bindings.h"
|
||||
#include "net/proxy/proxy_resolver_v8.h"
|
||||
#include "vendor/node/src/node.h"
|
||||
#include "vendor/node/src/node_internals.h"
|
||||
|
||||
@@ -75,6 +76,11 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() {
|
||||
|
||||
node_bindings_->RunMessageLoop();
|
||||
|
||||
// Make sure the url request job factory is created before the
|
||||
// will-finish-launching event.
|
||||
static_cast<content::BrowserContext*>(AtomBrowserContext::Get())->
|
||||
GetRequestContext();
|
||||
|
||||
#if !defined(OS_MACOSX)
|
||||
// The corresponding call in OS X is in AtomApplicationDelegate.
|
||||
Browser::Get()->WillFinishLaunching();
|
||||
@@ -82,4 +88,10 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() {
|
||||
#endif
|
||||
}
|
||||
|
||||
int AtomBrowserMainParts::PreCreateThreads() {
|
||||
// TODO(zcbenz): Calling CreateIsolate() on Windows when updated to Chrome30.
|
||||
net::ProxyResolverV8::RememberDefaultIsolate();
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -30,6 +30,7 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
|
||||
// Implementations of content::BrowserMainParts.
|
||||
virtual void PostEarlyInitialization() OVERRIDE;
|
||||
virtual void PreMainMessageLoopRun() OVERRIDE;
|
||||
virtual int PreCreateThreads() OVERRIDE;
|
||||
#if defined(OS_MACOSX)
|
||||
virtual void PreMainMessageLoopStart() OVERRIDE;
|
||||
virtual void PostDestroyThreads() OVERRIDE;
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
|
||||
#include "browser/atom_browser_main_parts.h"
|
||||
|
||||
#import "base/mac/bundle_locations.h"
|
||||
#include "base/files/file_path.h"
|
||||
#import "base/mac/foundation_util.h"
|
||||
#import "browser/atom_application_mac.h"
|
||||
#import "browser/atom_application_delegate_mac.h"
|
||||
#import "vendor/brightray/common/mac/main_application_bundle.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
@@ -17,10 +19,14 @@ void AtomBrowserMainParts::PreMainMessageLoopStart() {
|
||||
AtomApplicationDelegate* delegate = [AtomApplicationDelegate alloc];
|
||||
[NSApp setDelegate:delegate];
|
||||
|
||||
auto infoDictionary = base::mac::OuterBundle().infoDictionary;
|
||||
|
||||
NSString *mainNibName = [infoDictionary objectForKey:@"NSMainNibFile"];
|
||||
auto mainNib = [[NSNib alloc] initWithNibNamed:mainNibName bundle:base::mac::FrameworkBundle()];
|
||||
base::FilePath frameworkPath = brightray::MainApplicationBundlePath()
|
||||
.Append("Contents")
|
||||
.Append("Frameworks")
|
||||
.Append("Atom Framework.framework");
|
||||
NSBundle* frameworkBundle = [NSBundle
|
||||
bundleWithPath:base::mac::FilePathToNSString(frameworkPath)];
|
||||
NSNib* mainNib = [[NSNib alloc] initWithNibNamed:@"MainMenu"
|
||||
bundle:frameworkBundle];
|
||||
[mainNib instantiateWithOwner:application topLevelObjects:nil];
|
||||
[mainNib release];
|
||||
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_CRASH_REPORTER_H_
|
||||
#define ATOM_BROWSER_CRASH_REPORTER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
|
||||
namespace crash_reporter {
|
||||
|
||||
class CrashReporter {
|
||||
public:
|
||||
static void SetCompanyName(const std::string& name);
|
||||
static void SetSubmissionURL(const std::string& url);
|
||||
static void SetAutoSubmit(bool yes);
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(CrashReporter);
|
||||
};
|
||||
|
||||
} // namespace crash_reporter
|
||||
|
||||
#endif // ATOM_BROWSER_CRASH_REPORTER_H_
|
||||
@@ -1,31 +0,0 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "browser/crash_reporter.h"
|
||||
|
||||
#import <Quincy/BWQuincyManager.h>
|
||||
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
|
||||
namespace crash_reporter {
|
||||
|
||||
// static
|
||||
void CrashReporter::SetCompanyName(const std::string& name) {
|
||||
BWQuincyManager *manager = [BWQuincyManager sharedQuincyManager];
|
||||
[manager setCompanyName:base::SysUTF8ToNSString(name)];
|
||||
}
|
||||
|
||||
// static
|
||||
void CrashReporter::SetSubmissionURL(const std::string& url) {
|
||||
BWQuincyManager *manager = [BWQuincyManager sharedQuincyManager];
|
||||
[manager setSubmissionURL:base::SysUTF8ToNSString(url)];
|
||||
}
|
||||
|
||||
// static
|
||||
void CrashReporter::SetAutoSubmit(bool yes) {
|
||||
BWQuincyManager *manager = [BWQuincyManager sharedQuincyManager];
|
||||
[manager setAutoSubmitCrashReport:yes];
|
||||
}
|
||||
|
||||
} // namespace crash_reporter
|
||||
@@ -1,22 +0,0 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "browser/crash_reporter.h"
|
||||
|
||||
namespace crash_reporter {
|
||||
|
||||
// static
|
||||
void CrashReporter::SetCompanyName(const std::string& name) {
|
||||
}
|
||||
|
||||
// static
|
||||
void CrashReporter::SetSubmissionURL(const std::string& url) {
|
||||
}
|
||||
|
||||
// static
|
||||
void CrashReporter::SetAutoSubmit(bool yes) {
|
||||
}
|
||||
|
||||
} // namespace crash_reporter
|
||||
|
||||
@@ -31,7 +31,6 @@ app.on('finish-launching', function() {
|
||||
});
|
||||
|
||||
mainWindow.on('closed', function() {
|
||||
console.log('closed');
|
||||
mainWindow = null;
|
||||
});
|
||||
|
||||
@@ -39,129 +38,167 @@ app.on('finish-launching', function() {
|
||||
console.log('unresponsive');
|
||||
});
|
||||
|
||||
var template = [
|
||||
{
|
||||
label: 'Atom Shell',
|
||||
submenu: [
|
||||
{
|
||||
label: 'About Atom Shell',
|
||||
selector: 'orderFrontStandardAboutPanel:'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Hide Atom Shell',
|
||||
accelerator: 'Command+H',
|
||||
selector: 'hide:'
|
||||
},
|
||||
{
|
||||
label: 'Hide Others',
|
||||
accelerator: 'Command+Shift+H',
|
||||
selector: 'hideOtherApplications:'
|
||||
},
|
||||
{
|
||||
label: 'Show All',
|
||||
selector: 'unhideAllApplications:'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Quit',
|
||||
accelerator: 'Command+Q',
|
||||
click: function() { app.quit(); }
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Edit',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Undo',
|
||||
accelerator: 'Command+Z',
|
||||
selector: 'undo:'
|
||||
},
|
||||
{
|
||||
label: 'Redo',
|
||||
accelerator: 'Shift+Command+Z',
|
||||
selector: 'redo:'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Cut',
|
||||
accelerator: 'Command+X',
|
||||
selector: 'cut:'
|
||||
},
|
||||
{
|
||||
label: 'Copy',
|
||||
accelerator: 'Command+C',
|
||||
selector: 'copy:'
|
||||
},
|
||||
{
|
||||
label: 'Paste',
|
||||
accelerator: 'Command+V',
|
||||
selector: 'paste:'
|
||||
},
|
||||
{
|
||||
label: 'Select All',
|
||||
accelerator: 'Command+A',
|
||||
selector: 'selectAll:'
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'View',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Reload',
|
||||
accelerator: 'Command+R',
|
||||
click: function() { BrowserWindow.getFocusedWindow().restart(); }
|
||||
},
|
||||
{
|
||||
label: 'Enter Fullscreen',
|
||||
click: function() { BrowserWindow.getFocusedWindow().setFullscreen(true); }
|
||||
},
|
||||
{
|
||||
label: 'Toggle DevTools',
|
||||
accelerator: 'Alt+Command+I',
|
||||
click: function() { BrowserWindow.getFocusedWindow().toggleDevTools(); }
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Window',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Minimize',
|
||||
accelerator: 'Command+M',
|
||||
selector: 'performMiniaturize:'
|
||||
},
|
||||
{
|
||||
label: 'Close',
|
||||
accelerator: 'Command+W',
|
||||
selector: 'performClose:'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Bring All to Front',
|
||||
selector: 'arrangeInFront:'
|
||||
},
|
||||
]
|
||||
},
|
||||
];
|
||||
if (process.platform == 'darwin') {
|
||||
var template = [
|
||||
{
|
||||
label: 'Atom Shell',
|
||||
submenu: [
|
||||
{
|
||||
label: 'About Atom Shell',
|
||||
selector: 'orderFrontStandardAboutPanel:'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Hide Atom Shell',
|
||||
accelerator: 'Command+H',
|
||||
selector: 'hide:'
|
||||
},
|
||||
{
|
||||
label: 'Hide Others',
|
||||
accelerator: 'Command+Shift+H',
|
||||
selector: 'hideOtherApplications:'
|
||||
},
|
||||
{
|
||||
label: 'Show All',
|
||||
selector: 'unhideAllApplications:'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Quit',
|
||||
accelerator: 'Command+Q',
|
||||
click: function() { app.quit(); }
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Edit',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Undo',
|
||||
accelerator: 'Command+Z',
|
||||
selector: 'undo:'
|
||||
},
|
||||
{
|
||||
label: 'Redo',
|
||||
accelerator: 'Shift+Command+Z',
|
||||
selector: 'redo:'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Cut',
|
||||
accelerator: 'Command+X',
|
||||
selector: 'cut:'
|
||||
},
|
||||
{
|
||||
label: 'Copy',
|
||||
accelerator: 'Command+C',
|
||||
selector: 'copy:'
|
||||
},
|
||||
{
|
||||
label: 'Paste',
|
||||
accelerator: 'Command+V',
|
||||
selector: 'paste:'
|
||||
},
|
||||
{
|
||||
label: 'Select All',
|
||||
accelerator: 'Command+A',
|
||||
selector: 'selectAll:'
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'View',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Reload',
|
||||
accelerator: 'Command+R',
|
||||
click: function() { BrowserWindow.getFocusedWindow().restart(); }
|
||||
},
|
||||
{
|
||||
label: 'Enter Fullscreen',
|
||||
click: function() { BrowserWindow.getFocusedWindow().setFullscreen(true); }
|
||||
},
|
||||
{
|
||||
label: 'Toggle DevTools',
|
||||
accelerator: 'Alt+Command+I',
|
||||
click: function() { BrowserWindow.getFocusedWindow().toggleDevTools(); }
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Window',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Minimize',
|
||||
accelerator: 'Command+M',
|
||||
selector: 'performMiniaturize:'
|
||||
},
|
||||
{
|
||||
label: 'Close',
|
||||
accelerator: 'Command+W',
|
||||
selector: 'performClose:'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Bring All to Front',
|
||||
selector: 'arrangeInFront:'
|
||||
},
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
menu = Menu.buildFromTemplate(template);
|
||||
|
||||
if (process.platform == 'darwin')
|
||||
menu = Menu.buildFromTemplate(template);
|
||||
Menu.setApplicationMenu(menu);
|
||||
} else {
|
||||
var template = [
|
||||
{
|
||||
label: 'File',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Open',
|
||||
accelerator: 'Command+O',
|
||||
},
|
||||
{
|
||||
label: 'Close',
|
||||
accelerator: 'Command+W',
|
||||
click: function() { mainWindow.close(); }
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'View',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Reload',
|
||||
accelerator: 'Command+R',
|
||||
click: function() { mainWindow.restart(); }
|
||||
},
|
||||
{
|
||||
label: 'Enter Fullscreen',
|
||||
click: function() { mainWindow.setFullscreen(true); }
|
||||
},
|
||||
{
|
||||
label: 'Toggle DevTools',
|
||||
accelerator: 'Alt+Command+I',
|
||||
click: function() { mainWindow.toggleDevTools(); }
|
||||
},
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
menu = Menu.buildFromTemplate(template);
|
||||
mainWindow.setMenu(menu);
|
||||
}
|
||||
|
||||
ipc.on('message', function(processId, routingId, type) {
|
||||
console.log(type);
|
||||
if (type == 'menu')
|
||||
menu.popup(mainWindow);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
var argv = require('optimist').argv;
|
||||
var app = require('app');
|
||||
var dialog = require('dialog');
|
||||
var path = require('path');
|
||||
var optimist = require('optimist');
|
||||
|
||||
// Quit when all windows are closed and no other one is listening to this.
|
||||
app.on('window-all-closed', function() {
|
||||
if (app.listeners('window-all-closed').length == 1)
|
||||
app.quit();
|
||||
});
|
||||
|
||||
var argv = optimist(process.argv.slice(1)).argv;
|
||||
|
||||
// Start the specified app if there is one specified in command line, otherwise
|
||||
// start the default app.
|
||||
@@ -9,12 +18,16 @@ if (argv._.length > 0) {
|
||||
require(path.resolve(argv._[0]));
|
||||
} catch(e) {
|
||||
if (e.code == 'MODULE_NOT_FOUND') {
|
||||
console.error(e.stack);
|
||||
console.error('Specified app is invalid');
|
||||
process.exit(1);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
} else if (argv.version) {
|
||||
console.log('v' + process.versions['atom-shell']);
|
||||
process.exit(0);
|
||||
} else {
|
||||
require('./default_app.js');
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>atom.icns</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<string>0.7.2</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/file_util.h"
|
||||
#include "base/message_loop.h"
|
||||
#include "base/utf_string_conversions.h"
|
||||
#include "base/values.h"
|
||||
@@ -28,9 +29,11 @@
|
||||
#include "common/api/api_messages.h"
|
||||
#include "common/options_switches.h"
|
||||
#include "ipc/ipc_message_macros.h"
|
||||
#include "ui/gfx/codec/png_codec.h"
|
||||
#include "ui/gfx/point.h"
|
||||
#include "ui/gfx/rect.h"
|
||||
#include "ui/gfx/size.h"
|
||||
#include "webkit/glue/image_decoder.h"
|
||||
|
||||
using content::NavigationEntry;
|
||||
|
||||
@@ -39,10 +42,19 @@ namespace atom {
|
||||
NativeWindow::NativeWindow(content::WebContents* web_contents,
|
||||
base::DictionaryValue* options)
|
||||
: content::WebContentsObserver(web_contents),
|
||||
has_frame_(true),
|
||||
is_closed_(false),
|
||||
not_responding_(false),
|
||||
inspectable_web_contents_(
|
||||
brightray::InspectableWebContents::Create(web_contents)) {
|
||||
options->GetBoolean(switches::kFrame, &has_frame_);
|
||||
|
||||
std::string icon;
|
||||
if (options->GetString(switches::kIcon, &icon)) {
|
||||
if (!SetIcon(icon))
|
||||
LOG(ERROR) << "Failed to set icon to " << icon;
|
||||
}
|
||||
|
||||
web_contents->SetDelegate(this);
|
||||
|
||||
WindowList::AddWindow(this);
|
||||
@@ -138,6 +150,10 @@ void NativeWindow::CloseDevTools() {
|
||||
inspectable_web_contents()->GetView()->CloseDevTools();
|
||||
}
|
||||
|
||||
bool NativeWindow::IsDevToolsOpened() {
|
||||
return inspectable_web_contents()->IsDevToolsOpened();
|
||||
}
|
||||
|
||||
void NativeWindow::InspectElement(int x, int y) {
|
||||
OpenDevTools();
|
||||
content::RenderViewHost* rvh = GetWebContents()->GetRenderViewHost();
|
||||
@@ -162,6 +178,37 @@ void NativeWindow::RestartHangMonitorTimeout() {
|
||||
GetWebContents()->GetRenderViewHost()->RestartHangMonitorTimeout();
|
||||
}
|
||||
|
||||
bool NativeWindow::SetIcon(const std::string& str_path) {
|
||||
base::FilePath path = base::FilePath::FromUTF8Unsafe(str_path);
|
||||
|
||||
// Read the file from disk.
|
||||
std::string file_contents;
|
||||
if (path.empty() || !file_util::ReadFileToString(path, &file_contents))
|
||||
return false;
|
||||
|
||||
// Decode the bitmap using WebKit's image decoder.
|
||||
const unsigned char* data =
|
||||
reinterpret_cast<const unsigned char*>(file_contents.data());
|
||||
webkit_glue::ImageDecoder decoder;
|
||||
scoped_ptr<SkBitmap> decoded(new SkBitmap());
|
||||
*decoded = decoder.Decode(data, file_contents.length());
|
||||
if (decoded->empty())
|
||||
return false; // Unable to decode.
|
||||
|
||||
icon_ = gfx::Image::CreateFrom1xBitmap(*decoded.release());
|
||||
return true;
|
||||
}
|
||||
|
||||
void NativeWindow::CapturePage(const gfx::Rect& rect,
|
||||
const CapturePageCallback& callback) {
|
||||
GetWebContents()->GetRenderViewHost()->CopyFromBackingStore(
|
||||
rect,
|
||||
gfx::Size(),
|
||||
base::Bind(&NativeWindow::OnCapturePageDone,
|
||||
base::Unretained(this),
|
||||
callback));
|
||||
}
|
||||
|
||||
void NativeWindow::CloseWebContents() {
|
||||
bool prevent_default = false;
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver,
|
||||
@@ -297,7 +344,10 @@ bool NativeWindow::OnMessageReceived(const IPC::Message& message) {
|
||||
bool handled = true;
|
||||
IPC_BEGIN_MESSAGE_MAP(NativeWindow, message)
|
||||
IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message, OnRendererMessage)
|
||||
IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message_Sync, OnRendererMessageSync)
|
||||
IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_Message_Sync,
|
||||
OnRendererMessageSync)
|
||||
IPC_MESSAGE_HANDLER(AtomViewHostMsg_UpdateDraggableRegions,
|
||||
UpdateDraggableRegions)
|
||||
IPC_MESSAGE_UNHANDLED(handled = false)
|
||||
IPC_END_MESSAGE_MAP()
|
||||
|
||||
@@ -335,7 +385,16 @@ void NativeWindow::Observe(int type,
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindow::OnRendererMessage(const std::string& channel,
|
||||
void NativeWindow::OnCapturePageDone(const CapturePageCallback& callback,
|
||||
bool succeed,
|
||||
const SkBitmap& bitmap) {
|
||||
std::vector<unsigned char> data;
|
||||
if (succeed)
|
||||
gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, true, &data);
|
||||
callback.Run(data);
|
||||
}
|
||||
|
||||
void NativeWindow::OnRendererMessage(const string16& channel,
|
||||
const base::ListValue& args) {
|
||||
AtomBrowserMainParts::Get()->atom_bindings()->OnRendererMessage(
|
||||
GetWebContents()->GetRenderProcessHost()->GetID(),
|
||||
@@ -344,15 +403,16 @@ void NativeWindow::OnRendererMessage(const std::string& channel,
|
||||
args);
|
||||
}
|
||||
|
||||
void NativeWindow::OnRendererMessageSync(const std::string& channel,
|
||||
void NativeWindow::OnRendererMessageSync(const string16& channel,
|
||||
const base::ListValue& args,
|
||||
base::DictionaryValue* result) {
|
||||
IPC::Message* reply_msg) {
|
||||
AtomBrowserMainParts::Get()->atom_bindings()->OnRendererMessageSync(
|
||||
GetWebContents()->GetRenderProcessHost()->GetID(),
|
||||
GetWebContents()->GetRoutingID(),
|
||||
channel,
|
||||
args,
|
||||
result);
|
||||
this,
|
||||
reply_msg);
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "content/public/browser/notification_registrar.h"
|
||||
#include "content/public/browser/notification_observer.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
#include "vendor/brightray/browser/default_web_contents_delegate.h"
|
||||
|
||||
namespace base {
|
||||
@@ -35,14 +36,22 @@ class Rect;
|
||||
class Size;
|
||||
}
|
||||
|
||||
namespace IPC {
|
||||
class Message;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomJavaScriptDialogManager;
|
||||
struct DraggableRegion;
|
||||
|
||||
class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
public content::WebContentsObserver,
|
||||
public content::NotificationObserver {
|
||||
public:
|
||||
typedef base::Callback<void(const std::vector<unsigned char>& buffer)>
|
||||
CapturePageCallback;
|
||||
|
||||
virtual ~NativeWindow();
|
||||
|
||||
// Create window with existing WebContents.
|
||||
@@ -64,6 +73,7 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
virtual bool IsFocused() = 0;
|
||||
virtual void Show() = 0;
|
||||
virtual void Hide() = 0;
|
||||
virtual bool IsVisible() = 0;
|
||||
virtual void Maximize() = 0;
|
||||
virtual void Unmaximize() = 0;
|
||||
virtual void Minimize() = 0;
|
||||
@@ -93,11 +103,18 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
virtual bool IsClosed() const { return is_closed_; }
|
||||
virtual void OpenDevTools();
|
||||
virtual void CloseDevTools();
|
||||
virtual bool IsDevToolsOpened();
|
||||
virtual void InspectElement(int x, int y);
|
||||
virtual void FocusOnWebView();
|
||||
virtual void BlurWebView();
|
||||
virtual bool IsWebViewFocused();
|
||||
virtual void RestartHangMonitorTimeout();
|
||||
virtual bool SetIcon(const std::string& path);
|
||||
|
||||
// Captures the page with |rect|, |callback| would be called when capturing is
|
||||
// done.
|
||||
virtual void CapturePage(const gfx::Rect& rect,
|
||||
const CapturePageCallback& callback);
|
||||
|
||||
// The same with closing a tab in a real browser.
|
||||
//
|
||||
@@ -114,6 +131,8 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
observers_.RemoveObserver(obs);
|
||||
}
|
||||
|
||||
bool has_frame() const { return has_frame_; }
|
||||
|
||||
protected:
|
||||
explicit NativeWindow(content::WebContents* web_contents,
|
||||
base::DictionaryValue* options);
|
||||
@@ -125,6 +144,10 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
void NotifyWindowClosed();
|
||||
void NotifyWindowBlur();
|
||||
|
||||
// Called when the window needs to update its draggable region.
|
||||
virtual void UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions) = 0;
|
||||
|
||||
// Implementations of content::WebContentsDelegate.
|
||||
virtual void WebContentsCreated(content::WebContents* source_contents,
|
||||
int64 source_frame_id,
|
||||
@@ -160,15 +183,26 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
const content::NotificationSource& source,
|
||||
const content::NotificationDetails& details) OVERRIDE;
|
||||
|
||||
// Whether window has standard frame.
|
||||
bool has_frame_;
|
||||
|
||||
// Window icon.
|
||||
gfx::Image icon_;
|
||||
|
||||
private:
|
||||
void RendererUnresponsiveDelayed();
|
||||
|
||||
void OnRendererMessage(const std::string& channel,
|
||||
// Called when CapturePage has done.
|
||||
void OnCapturePageDone(const CapturePageCallback& callback,
|
||||
bool succeed,
|
||||
const SkBitmap& bitmap);
|
||||
|
||||
void OnRendererMessage(const string16& channel,
|
||||
const base::ListValue& args);
|
||||
|
||||
void OnRendererMessageSync(const std::string& channel,
|
||||
void OnRendererMessageSync(const string16& channel,
|
||||
const base::ListValue& args,
|
||||
base::DictionaryValue* result);
|
||||
IPC::Message* reply_msg);
|
||||
|
||||
// Notification manager.
|
||||
content::NotificationRegistrar registrar_;
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "browser/native_window.h"
|
||||
|
||||
class SkRegion;
|
||||
|
||||
namespace atom {
|
||||
|
||||
class NativeWindowMac : public NativeWindow {
|
||||
@@ -26,6 +28,7 @@ class NativeWindowMac : public NativeWindow {
|
||||
virtual bool IsFocused() OVERRIDE;
|
||||
virtual void Show() OVERRIDE;
|
||||
virtual void Hide() OVERRIDE;
|
||||
virtual bool IsVisible() OVERRIDE;
|
||||
virtual void Maximize() OVERRIDE;
|
||||
virtual void Unmaximize() OVERRIDE;
|
||||
virtual void Minimize() OVERRIDE;
|
||||
@@ -52,11 +55,25 @@ class NativeWindowMac : public NativeWindow {
|
||||
virtual bool IsKiosk() OVERRIDE;
|
||||
virtual gfx::NativeWindow GetNativeWindow() OVERRIDE;
|
||||
|
||||
NSWindow*& window() { return window_; }
|
||||
|
||||
void NotifyWindowBlur() { NativeWindow::NotifyWindowBlur(); }
|
||||
|
||||
// Returns true if |point| in local Cocoa coordinate system falls within
|
||||
// the draggable region.
|
||||
bool IsWithinDraggableRegion(NSPoint point) const;
|
||||
|
||||
// Called to handle a mouse event.
|
||||
void HandleMouseEvent(NSEvent* event);
|
||||
|
||||
// Clip web view to rounded corner.
|
||||
void ClipWebView();
|
||||
|
||||
NSWindow*& window() { return window_; }
|
||||
SkRegion* draggable_region() const { return draggable_region_.get(); }
|
||||
|
||||
protected:
|
||||
virtual void UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions) OVERRIDE;
|
||||
|
||||
// Implementations of content::WebContentsDelegate.
|
||||
virtual void HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
@@ -65,6 +82,9 @@ class NativeWindowMac : public NativeWindow {
|
||||
private:
|
||||
void InstallView();
|
||||
void UninstallView();
|
||||
void InstallDraggableRegionViews();
|
||||
void UpdateDraggableRegionsForCustomDrag(
|
||||
const std::vector<DraggableRegion>& regions);
|
||||
|
||||
NSWindow* window_;
|
||||
|
||||
@@ -72,6 +92,18 @@ class NativeWindowMac : public NativeWindow {
|
||||
|
||||
NSInteger attention_request_id_; // identifier from requestUserAttention
|
||||
|
||||
// For system drag, the whole window is draggable and the non-draggable areas
|
||||
// have to been explicitly excluded.
|
||||
std::vector<gfx::Rect> system_drag_exclude_areas_;
|
||||
|
||||
// For custom drag, the whole window is non-draggable and the draggable region
|
||||
// has to been explicitly provided.
|
||||
scoped_ptr<SkRegion> draggable_region_; // used in custom drag.
|
||||
|
||||
// Mouse location since the last mouse event, in screen coordinates. This is
|
||||
// used in custom drag to compute the window movement.
|
||||
NSPoint last_mouse_offset_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NativeWindowMac);
|
||||
};
|
||||
|
||||
|
||||
@@ -13,15 +13,22 @@
|
||||
#include "base/mac/mac_util.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "base/values.h"
|
||||
#import "browser/atom_event_processing_window.h"
|
||||
#import "browser/ui/atom_event_processing_window.h"
|
||||
#include "brightray/browser/inspectable_web_contents.h"
|
||||
#include "brightray/browser/inspectable_web_contents_view.h"
|
||||
#include "common/draggable_region.h"
|
||||
#include "common/options_switches.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"
|
||||
|
||||
static const CGFloat kAtomWindowCornerRadius = 4.0;
|
||||
|
||||
@interface NSView (PrivateMethods)
|
||||
- (CGFloat)roundedCornerRadius;
|
||||
@end
|
||||
|
||||
@interface AtomNSWindowDelegate : NSObject<NSWindowDelegate> {
|
||||
@private
|
||||
atom::NativeWindowMac* shell_;
|
||||
@@ -41,6 +48,11 @@
|
||||
shell_->NotifyWindowBlur();
|
||||
}
|
||||
|
||||
- (void)windowDidResize:(NSNotification*)otification {
|
||||
if (!shell_->has_frame())
|
||||
shell_->ClipWebView();
|
||||
}
|
||||
|
||||
- (void)windowWillClose:(NSNotification*)notification {
|
||||
shell_->window() = nil;
|
||||
[self autorelease];
|
||||
@@ -54,10 +66,17 @@
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)windowDidExitFullScreen:(NSNotification*)notification {
|
||||
if (!shell_->has_frame()) {
|
||||
NSWindow* window = shell_->GetNativeWindow();
|
||||
[[window standardWindowButton:NSWindowFullScreenButton] setHidden:YES];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface AtomNSWindow : AtomEventProcessingWindow {
|
||||
@private
|
||||
@protected
|
||||
atom::NativeWindowMac* shell_;
|
||||
}
|
||||
- (void)setShell:(atom::NativeWindowMac*)shell;
|
||||
@@ -80,6 +99,41 @@
|
||||
|
||||
@end
|
||||
|
||||
@interface ControlRegionView : NSView {
|
||||
@private
|
||||
atom::NativeWindowMac* shellWindow_; // Weak; owns self.
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation ControlRegionView
|
||||
|
||||
- (id)initWithShellWindow:(atom::NativeWindowMac*)shellWindow {
|
||||
if ((self = [super init]))
|
||||
shellWindow_ = shellWindow;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)mouseDownCanMoveWindow {
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSView*)hitTest:(NSPoint)aPoint {
|
||||
if (!shellWindow_->IsWithinDraggableRegion(aPoint)) {
|
||||
return nil;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)mouseDown:(NSEvent*)event {
|
||||
shellWindow_->HandleMouseEvent(event);
|
||||
}
|
||||
|
||||
- (void)mouseDragged:(NSEvent*)event {
|
||||
shellWindow_->HandleMouseEvent(event);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
namespace atom {
|
||||
|
||||
NativeWindowMac::NativeWindowMac(content::WebContents* web_contents,
|
||||
@@ -93,21 +147,24 @@ NativeWindowMac::NativeWindowMac(content::WebContents* web_contents,
|
||||
|
||||
NSRect main_screen_rect = [[[NSScreen screens] objectAtIndex:0] frame];
|
||||
NSRect cocoa_bounds = NSMakeRect(
|
||||
(NSWidth(main_screen_rect) - width) / 2,
|
||||
(NSHeight(main_screen_rect) - height) / 2,
|
||||
round((NSWidth(main_screen_rect) - width) / 2) ,
|
||||
round((NSHeight(main_screen_rect) - height) / 2),
|
||||
width,
|
||||
height);
|
||||
NSUInteger style_mask = NSTitledWindowMask | NSClosableWindowMask |
|
||||
NSMiniaturizableWindowMask | NSResizableWindowMask |
|
||||
NSTexturedBackgroundWindowMask;
|
||||
AtomNSWindow* atom_window = [[AtomNSWindow alloc]
|
||||
|
||||
AtomNSWindow* atomWindow;
|
||||
|
||||
atomWindow = [[AtomNSWindow alloc]
|
||||
initWithContentRect:cocoa_bounds
|
||||
styleMask:style_mask
|
||||
styleMask:NSTitledWindowMask | NSClosableWindowMask |
|
||||
NSMiniaturizableWindowMask | NSResizableWindowMask |
|
||||
NSTexturedBackgroundWindowMask
|
||||
backing:NSBackingStoreBuffered
|
||||
defer:YES];
|
||||
[atom_window setShell:this];
|
||||
|
||||
window_ = atom_window;
|
||||
[atomWindow setShell:this];
|
||||
window_ = atomWindow;
|
||||
|
||||
[window() setDelegate:[[AtomNSWindowDelegate alloc] initWithShell:this]];
|
||||
|
||||
// Disable fullscreen button when 'fullscreen' is specified to false.
|
||||
@@ -119,6 +176,9 @@ NativeWindowMac::NativeWindowMac(content::WebContents* web_contents,
|
||||
[window() setCollectionBehavior:collectionBehavior];
|
||||
}
|
||||
|
||||
NSView* view = inspectable_web_contents()->GetView()->GetNativeView();
|
||||
[view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
|
||||
|
||||
InstallView();
|
||||
}
|
||||
|
||||
@@ -149,7 +209,10 @@ void NativeWindowMac::Move(const gfx::Rect& pos) {
|
||||
}
|
||||
|
||||
void NativeWindowMac::Focus(bool focus) {
|
||||
if (focus && [window() isVisible]) {
|
||||
if (!IsVisible())
|
||||
return;
|
||||
|
||||
if (focus) {
|
||||
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
|
||||
[window() makeKeyAndOrderFront:nil];
|
||||
} else {
|
||||
@@ -169,6 +232,10 @@ void NativeWindowMac::Hide() {
|
||||
[window() orderOut:nil];
|
||||
}
|
||||
|
||||
bool NativeWindowMac::IsVisible() {
|
||||
return [window() isVisible];
|
||||
}
|
||||
|
||||
void NativeWindowMac::Maximize() {
|
||||
[window() zoom:nil];
|
||||
}
|
||||
@@ -300,7 +367,7 @@ void NativeWindowMac::SetKiosk(bool kiosk) {
|
||||
if (kiosk) {
|
||||
NSApplicationPresentationOptions options =
|
||||
NSApplicationPresentationHideDock +
|
||||
NSApplicationPresentationHideMenuBar +
|
||||
NSApplicationPresentationHideMenuBar +
|
||||
NSApplicationPresentationDisableAppleMenu +
|
||||
NSApplicationPresentationDisableProcessSwitching +
|
||||
NSApplicationPresentationDisableForceQuit +
|
||||
@@ -324,6 +391,43 @@ gfx::NativeWindow NativeWindowMac::GetNativeWindow() {
|
||||
return window();
|
||||
}
|
||||
|
||||
bool NativeWindowMac::IsWithinDraggableRegion(NSPoint point) const {
|
||||
if (!draggable_region_)
|
||||
return false;
|
||||
NSView* webView = GetWebContents()->GetView()->GetNativeView();
|
||||
NSInteger webViewHeight = NSHeight([webView bounds]);
|
||||
// |draggable_region_| is stored in local platform-indepdent coordiate system
|
||||
// while |point| is in local Cocoa coordinate system. Do the conversion
|
||||
// to match these two.
|
||||
return draggable_region_->contains(point.x, webViewHeight - point.y);
|
||||
}
|
||||
|
||||
void NativeWindowMac::HandleMouseEvent(NSEvent* event) {
|
||||
NSPoint current_mouse_location =
|
||||
[window() convertBaseToScreen:[event locationInWindow]];
|
||||
|
||||
if ([event type] == NSLeftMouseDown) {
|
||||
NSPoint frame_origin = [window() frame].origin;
|
||||
last_mouse_offset_ = NSMakePoint(
|
||||
frame_origin.x - current_mouse_location.x,
|
||||
frame_origin.y - current_mouse_location.y);
|
||||
} else if ([event type] == NSLeftMouseDragged) {
|
||||
[window() setFrameOrigin:NSMakePoint(
|
||||
current_mouse_location.x + last_mouse_offset_.x,
|
||||
current_mouse_location.y + last_mouse_offset_.y)];
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowMac::UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions) {
|
||||
// Draggable region is not supported for non-frameless window.
|
||||
if (has_frame_)
|
||||
return;
|
||||
|
||||
UpdateDraggableRegionsForCustomDrag(regions);
|
||||
InstallDraggableRegionViews();
|
||||
}
|
||||
|
||||
void NativeWindowMac::HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent& event) {
|
||||
@@ -339,16 +443,97 @@ void NativeWindowMac::HandleKeyboardEvent(
|
||||
|
||||
void NativeWindowMac::InstallView() {
|
||||
NSView* view = inspectable_web_contents()->GetView()->GetNativeView();
|
||||
[view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
|
||||
[view setFrame:[[window() contentView] bounds]];
|
||||
[[window() contentView] addSubview:view];
|
||||
if (has_frame_) {
|
||||
[view setFrame:[[window() contentView] bounds]];
|
||||
[[window() contentView] addSubview:view];
|
||||
} else {
|
||||
NSView* frameView = [[window() contentView] superview];
|
||||
[view setFrame:[frameView bounds]];
|
||||
[frameView addSubview:view];
|
||||
|
||||
ClipWebView();
|
||||
|
||||
[[window() standardWindowButton:NSWindowZoomButton] setHidden:YES];
|
||||
[[window() standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
|
||||
[[window() standardWindowButton:NSWindowCloseButton] setHidden:YES];
|
||||
[[window() standardWindowButton:NSWindowFullScreenButton] setHidden:YES];
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowMac::UninstallView() {
|
||||
NSView* view = GetWebContents()->GetView()->GetNativeView();
|
||||
NSView* view = inspectable_web_contents()->GetView()->GetNativeView();
|
||||
[view removeFromSuperview];
|
||||
}
|
||||
|
||||
void NativeWindowMac::ClipWebView() {
|
||||
NSView* view = GetWebContents()->GetView()->GetNativeView();
|
||||
|
||||
view.wantsLayer = YES;
|
||||
view.layer.masksToBounds = YES;
|
||||
view.layer.cornerRadius = kAtomWindowCornerRadius;
|
||||
}
|
||||
|
||||
void NativeWindowMac::InstallDraggableRegionViews() {
|
||||
DCHECK(!has_frame_);
|
||||
|
||||
// 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();
|
||||
NSInteger webViewHeight = NSHeight([webView bounds]);
|
||||
|
||||
// Remove all ControlRegionViews that are added last time.
|
||||
// Note that [webView subviews] returns the view's mutable internal array and
|
||||
// it should be copied to avoid mutating the original array while enumerating
|
||||
// it.
|
||||
scoped_nsobject<NSArray> subviews([[webView subviews] copy]);
|
||||
for (NSView* subview in subviews.get())
|
||||
if ([subview isKindOfClass:[ControlRegionView class]])
|
||||
[subview removeFromSuperview];
|
||||
|
||||
// Create and add ControlRegionView for each region that needs to be excluded
|
||||
// from the dragging.
|
||||
for (std::vector<gfx::Rect>::const_iterator iter =
|
||||
system_drag_exclude_areas_.begin();
|
||||
iter != system_drag_exclude_areas_.end();
|
||||
++iter) {
|
||||
scoped_nsobject<NSView> controlRegion(
|
||||
[[ControlRegionView alloc] initWithShellWindow:this]);
|
||||
[controlRegion setFrame:NSMakeRect(iter->x(),
|
||||
webViewHeight - iter->bottom(),
|
||||
iter->width(),
|
||||
iter->height())];
|
||||
[webView addSubview:controlRegion];
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
gfx::Rect window_bounds(
|
||||
0, 0, NSWidth([web_view bounds]), NSHeight([web_view bounds]));
|
||||
system_drag_exclude_areas_.clear();
|
||||
system_drag_exclude_areas_.push_back(window_bounds);
|
||||
|
||||
// Aggregate the draggable areas and non-draggable areas such that hit test
|
||||
// could be performed easily.
|
||||
SkRegion* draggable_region = new SkRegion;
|
||||
for (std::vector<DraggableRegion>::const_iterator iter = regions.begin();
|
||||
iter != regions.end();
|
||||
++iter) {
|
||||
const DraggableRegion& region = *iter;
|
||||
draggable_region->op(
|
||||
region.bounds.x(),
|
||||
region.bounds.y(),
|
||||
region.bounds.right(),
|
||||
region.bounds.bottom(),
|
||||
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
|
||||
}
|
||||
draggable_region_.reset(draggable_region);
|
||||
}
|
||||
|
||||
// static
|
||||
NativeWindow* NativeWindow::Create(content::WebContents* web_contents,
|
||||
base::DictionaryValue* options) {
|
||||
|
||||
@@ -4,12 +4,24 @@
|
||||
|
||||
#include "browser/native_window_win.h"
|
||||
|
||||
#include "base/stl_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/values.h"
|
||||
#include "browser/api/atom_api_menu.h"
|
||||
#include "browser/ui/win/menu_2.h"
|
||||
#include "browser/ui/win/native_menu_win.h"
|
||||
#include "common/draggable_region.h"
|
||||
#include "common/options_switches.h"
|
||||
#include "content/public/browser/native_web_keyboard_event.h"
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#include "content/public/browser/render_widget_host_view.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/browser/web_contents_view.h"
|
||||
#include "ui/gfx/path.h"
|
||||
#include "ui/base/models/simple_menu_model.h"
|
||||
#include "ui/views/controls/webview/webview.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
#include "ui/views/widget/native_widget_win.h"
|
||||
#include "ui/views/window/client_view.h"
|
||||
#include "ui/views/window/native_frame_view.h"
|
||||
|
||||
@@ -17,24 +29,52 @@ namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
const int kResizeInsideBoundsSize = 5;
|
||||
const int kResizeAreaCornerSize = 16;
|
||||
|
||||
// Wrapper of NativeWidgetWin to handle WM_MENUCOMMAND messages, which are
|
||||
// triggered by window menus.
|
||||
class MenuCommandNativeWidget : public views::NativeWidgetWin {
|
||||
public:
|
||||
explicit MenuCommandNativeWidget(NativeWindowWin* delegate)
|
||||
: views::NativeWidgetWin(delegate->window()),
|
||||
delegate_(delegate) {}
|
||||
virtual ~MenuCommandNativeWidget() {}
|
||||
|
||||
protected:
|
||||
virtual bool PreHandleMSG(UINT message,
|
||||
WPARAM w_param,
|
||||
LPARAM l_param,
|
||||
LRESULT* result) OVERRIDE {
|
||||
if (message == WM_MENUCOMMAND) {
|
||||
delegate_->OnMenuCommand(w_param, reinterpret_cast<HMENU>(l_param));
|
||||
*result = 0;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
NativeWindowWin* delegate_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MenuCommandNativeWidget);
|
||||
};
|
||||
|
||||
class NativeWindowClientView : public views::ClientView {
|
||||
public:
|
||||
NativeWindowClientView(views::Widget* widget,
|
||||
views::View* contents_view,
|
||||
NativeWindowWin* shell)
|
||||
: views::ClientView(widget, contents_view),
|
||||
shell_(shell) {
|
||||
NativeWindowWin* contents_view)
|
||||
: views::ClientView(widget, contents_view) {
|
||||
}
|
||||
virtual ~NativeWindowClientView() {}
|
||||
|
||||
virtual bool CanClose() OVERRIDE {
|
||||
shell_->CloseWebContents();
|
||||
static_cast<NativeWindowWin*>(contents_view())->CloseWebContents();
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
NativeWindowWin* shell_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NativeWindowClientView);
|
||||
};
|
||||
|
||||
@@ -60,6 +100,99 @@ class NativeWindowFrameView : public views::NativeFrameView {
|
||||
DISALLOW_COPY_AND_ASSIGN(NativeWindowFrameView);
|
||||
};
|
||||
|
||||
class NativeWindowFramelessView : public views::NonClientFrameView {
|
||||
public:
|
||||
explicit NativeWindowFramelessView(views::Widget* frame,
|
||||
NativeWindowWin* shell)
|
||||
: frame_(frame),
|
||||
shell_(shell) {
|
||||
}
|
||||
virtual ~NativeWindowFramelessView() {}
|
||||
|
||||
// views::NonClientFrameView implementations:
|
||||
virtual gfx::Rect NativeWindowFramelessView::GetBoundsForClientView() const
|
||||
OVERRIDE {
|
||||
return bounds();
|
||||
}
|
||||
|
||||
virtual gfx::Rect NativeWindowFramelessView::GetWindowBoundsForClientBounds(
|
||||
const gfx::Rect& client_bounds) const OVERRIDE {
|
||||
gfx::Rect window_bounds = client_bounds;
|
||||
// Enforce minimum size (1, 1) in case that client_bounds is passed with
|
||||
// empty size. This could occur when the frameless window is being
|
||||
// initialized.
|
||||
if (window_bounds.IsEmpty()) {
|
||||
window_bounds.set_width(1);
|
||||
window_bounds.set_height(1);
|
||||
}
|
||||
return window_bounds;
|
||||
}
|
||||
|
||||
virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE {
|
||||
if (frame_->IsFullscreen())
|
||||
return HTCLIENT;
|
||||
|
||||
// Check the frame first, as we allow a small area overlapping the contents
|
||||
// to be used for resize handles.
|
||||
bool can_ever_resize = frame_->widget_delegate() ?
|
||||
frame_->widget_delegate()->CanResize() :
|
||||
false;
|
||||
// Don't allow overlapping resize handles when the window is maximized or
|
||||
// fullscreen, as it can't be resized in those states.
|
||||
int resize_border =
|
||||
frame_->IsMaximized() || frame_->IsFullscreen() ? 0 :
|
||||
kResizeInsideBoundsSize;
|
||||
int frame_component = GetHTComponentForFrame(point,
|
||||
resize_border,
|
||||
resize_border,
|
||||
kResizeAreaCornerSize,
|
||||
kResizeAreaCornerSize,
|
||||
can_ever_resize);
|
||||
if (frame_component != HTNOWHERE)
|
||||
return frame_component;
|
||||
|
||||
// Check for possible draggable region in the client area for the frameless
|
||||
// window.
|
||||
if (shell_->draggable_region() &&
|
||||
shell_->draggable_region()->contains(point.x(), point.y()))
|
||||
return HTCAPTION;
|
||||
|
||||
int client_component = frame_->client_view()->NonClientHitTest(point);
|
||||
if (client_component != HTNOWHERE)
|
||||
return client_component;
|
||||
|
||||
// Caption is a safe default.
|
||||
return HTCAPTION;
|
||||
}
|
||||
|
||||
virtual void GetWindowMask(const gfx::Size& size,
|
||||
gfx::Path* window_mask) OVERRIDE {}
|
||||
virtual void ResetWindowControls() OVERRIDE {}
|
||||
virtual void UpdateWindowIcon() OVERRIDE {}
|
||||
virtual void UpdateWindowTitle() OVERRIDE {}
|
||||
|
||||
// views::View implementations:
|
||||
virtual gfx::Size NativeWindowFramelessView::GetPreferredSize() OVERRIDE {
|
||||
gfx::Size pref = frame_->client_view()->GetPreferredSize();
|
||||
gfx::Rect bounds(0, 0, pref.width(), pref.height());
|
||||
return frame_->non_client_view()->GetWindowBoundsForClientBounds(
|
||||
bounds).size();
|
||||
}
|
||||
|
||||
virtual gfx::Size GetMinimumSize() OVERRIDE {
|
||||
return shell_->GetMinimumSize();
|
||||
}
|
||||
|
||||
virtual gfx::Size GetMaximumSize() OVERRIDE {
|
||||
return shell_->GetMaximumSize();
|
||||
}
|
||||
|
||||
private:
|
||||
views::Widget* frame_;
|
||||
NativeWindowWin* shell_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NativeWindowFramelessView);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -71,6 +204,8 @@ NativeWindowWin::NativeWindowWin(content::WebContents* web_contents,
|
||||
resizable_(true) {
|
||||
views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
|
||||
params.delegate = this;
|
||||
params.native_widget = new MenuCommandNativeWidget(this);
|
||||
params.remove_standard_frame = !has_frame_;
|
||||
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
|
||||
window_->set_frame_type(views::Widget::FRAME_TYPE_FORCE_NATIVE);
|
||||
window_->Init(params);
|
||||
@@ -82,7 +217,10 @@ NativeWindowWin::NativeWindowWin(content::WebContents* web_contents,
|
||||
gfx::Size size(width, height);
|
||||
window_->CenterWindow(size);
|
||||
|
||||
window_->UpdateWindowIcon();
|
||||
|
||||
web_view_->SetWebContents(web_contents);
|
||||
OnViewWasResized();
|
||||
}
|
||||
|
||||
NativeWindowWin::~NativeWindowWin() {
|
||||
@@ -127,6 +265,10 @@ void NativeWindowWin::Unmaximize() {
|
||||
window_->Restore();
|
||||
}
|
||||
|
||||
bool NativeWindowWin::IsVisible() {
|
||||
return window_->IsVisible();
|
||||
}
|
||||
|
||||
void NativeWindowWin::Minimize() {
|
||||
window_->Minimize();
|
||||
}
|
||||
@@ -221,15 +363,92 @@ gfx::NativeWindow NativeWindowWin::GetNativeWindow() {
|
||||
return window_->GetNativeView();
|
||||
}
|
||||
|
||||
void NativeWindowWin::OnMenuCommand(int position, HMENU menu) {
|
||||
DCHECK(menu_);
|
||||
menu_->wrapper()->OnMenuCommand(position, menu);
|
||||
}
|
||||
|
||||
void NativeWindowWin::SetMenu(ui::MenuModel* menu_model) {
|
||||
menu_.reset(new atom::Menu2(menu_model, true));
|
||||
::SetMenu(GetNativeWindow(), menu_->GetNativeMenu());
|
||||
RegisterAccelerators();
|
||||
}
|
||||
|
||||
void NativeWindowWin::UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions) {
|
||||
if (has_frame_)
|
||||
return;
|
||||
|
||||
SkRegion* draggable_region = new SkRegion;
|
||||
|
||||
// By default, the whole window is non-draggable. We need to explicitly
|
||||
// include those draggable regions.
|
||||
for (std::vector<DraggableRegion>::const_iterator iter = regions.begin();
|
||||
iter != regions.end(); ++iter) {
|
||||
const DraggableRegion& region = *iter;
|
||||
draggable_region->op(
|
||||
region.bounds.x(),
|
||||
region.bounds.y(),
|
||||
region.bounds.right(),
|
||||
region.bounds.bottom(),
|
||||
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
|
||||
}
|
||||
|
||||
draggable_region_.reset(draggable_region);
|
||||
OnViewWasResized();
|
||||
}
|
||||
|
||||
void NativeWindowWin::HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent& event) {
|
||||
if (event.type == WebKit::WebInputEvent::KeyUp) {
|
||||
ui::Accelerator accelerator(
|
||||
static_cast<ui::KeyboardCode>(event.windowsKeyCode),
|
||||
content::GetModifiersFromNativeWebKeyboardEvent(event));
|
||||
|
||||
if (GetFocusManager()->ProcessAccelerator(accelerator)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Any unhandled keyboard/character messages should be defproced.
|
||||
// This allows stuff like F10, etc to work correctly.
|
||||
DefWindowProc(event.os_event.hwnd, event.os_event.message,
|
||||
event.os_event.wParam, event.os_event.lParam);
|
||||
}
|
||||
|
||||
void NativeWindowWin::Layout() {
|
||||
DCHECK(web_view_);
|
||||
web_view_->SetBounds(0, 0, width(), height());
|
||||
OnViewWasResized();
|
||||
}
|
||||
|
||||
void NativeWindowWin::ViewHierarchyChanged(bool is_add,
|
||||
views::View* parent,
|
||||
views::View* child) {
|
||||
if (is_add && child == this)
|
||||
AddChildView(web_view_);
|
||||
}
|
||||
|
||||
bool NativeWindowWin::AcceleratorPressed(
|
||||
const ui::Accelerator& accelerator) {
|
||||
if (ContainsKey(accelerator_table_, accelerator)) {
|
||||
const MenuItem& item = accelerator_table_[accelerator];
|
||||
item.model->ActivatedAt(item.position);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowWin::DeleteDelegate() {
|
||||
// Do nothing, window is managed by users.
|
||||
}
|
||||
|
||||
views::View* NativeWindowWin::GetInitiallyFocusedView() {
|
||||
return web_view_;
|
||||
}
|
||||
|
||||
bool NativeWindowWin::CanResize() const {
|
||||
return resizable_;
|
||||
}
|
||||
@@ -246,8 +465,15 @@ bool NativeWindowWin::ShouldHandleSystemCommands() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NativeWindowWin::ShouldShowWindowIcon() const {
|
||||
return true;
|
||||
gfx::ImageSkia NativeWindowWin::GetWindowAppIcon() {
|
||||
if (icon_.IsEmpty())
|
||||
return gfx::ImageSkia();
|
||||
else
|
||||
return *icon_.ToImageSkia();
|
||||
}
|
||||
|
||||
gfx::ImageSkia NativeWindowWin::GetWindowIcon() {
|
||||
return GetWindowAppIcon();
|
||||
}
|
||||
|
||||
views::Widget* NativeWindowWin::GetWidget() {
|
||||
@@ -259,12 +485,83 @@ const views::Widget* NativeWindowWin::GetWidget() const {
|
||||
}
|
||||
|
||||
views::ClientView* NativeWindowWin::CreateClientView(views::Widget* widget) {
|
||||
return new NativeWindowClientView(widget, web_view_, this);
|
||||
return new NativeWindowClientView(widget, this);
|
||||
}
|
||||
|
||||
views::NonClientFrameView* NativeWindowWin::CreateNonClientFrameView(
|
||||
views::Widget* widget) {
|
||||
return new NativeWindowFrameView(widget, this);
|
||||
if (has_frame_)
|
||||
return new NativeWindowFrameView(widget, this);
|
||||
|
||||
return new NativeWindowFramelessView(widget, this);
|
||||
}
|
||||
|
||||
void NativeWindowWin::OnViewWasResized() {
|
||||
// Set the window shape of the RWHV.
|
||||
gfx::Size sz = web_view_->size();
|
||||
int height = sz.height(), width = sz.width();
|
||||
gfx::Path path;
|
||||
path.addRect(0, 0, width, height);
|
||||
SetWindowRgn(web_contents()->GetView()->GetNativeView(),
|
||||
path.CreateNativeRegion(),
|
||||
1);
|
||||
|
||||
SkRegion* rgn = new SkRegion;
|
||||
if (!window_->IsFullscreen() && !window_->IsMaximized()) {
|
||||
if (draggable_region())
|
||||
rgn->op(*draggable_region(), SkRegion::kUnion_Op);
|
||||
|
||||
if (!has_frame_ && CanResize()) {
|
||||
rgn->op(0, 0, width, kResizeInsideBoundsSize, SkRegion::kUnion_Op);
|
||||
rgn->op(0, 0, kResizeInsideBoundsSize, height, SkRegion::kUnion_Op);
|
||||
rgn->op(width - kResizeInsideBoundsSize, 0, width, height,
|
||||
SkRegion::kUnion_Op);
|
||||
rgn->op(0, height - kResizeInsideBoundsSize, width, height,
|
||||
SkRegion::kUnion_Op);
|
||||
}
|
||||
}
|
||||
|
||||
content::WebContents* web_contents = GetWebContents();
|
||||
if (web_contents->GetRenderViewHost()->GetView())
|
||||
web_contents->GetRenderViewHost()->GetView()->SetClickthroughRegion(rgn);
|
||||
}
|
||||
|
||||
void NativeWindowWin::RegisterAccelerators() {
|
||||
views::FocusManager* focus_manager = GetFocusManager();
|
||||
accelerator_table_.clear();
|
||||
focus_manager->UnregisterAccelerators(this);
|
||||
|
||||
GenerateAcceleratorTable();
|
||||
for (AcceleratorTable::const_iterator iter = accelerator_table_.begin();
|
||||
iter != accelerator_table_.end(); ++iter) {
|
||||
focus_manager->RegisterAccelerator(
|
||||
iter->first, ui::AcceleratorManager::kNormalPriority, this);
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowWin::GenerateAcceleratorTable() {
|
||||
DCHECK(menu_);
|
||||
ui::SimpleMenuModel* model = static_cast<ui::SimpleMenuModel*>(
|
||||
menu_->model());
|
||||
FillAcceleratorTable(&accelerator_table_, model);
|
||||
}
|
||||
|
||||
void NativeWindowWin::FillAcceleratorTable(AcceleratorTable* table,
|
||||
ui::MenuModel* model) {
|
||||
int count = model->GetItemCount();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
ui::MenuModel::ItemType type = model->GetTypeAt(i);
|
||||
if (type == ui::MenuModel::TYPE_SUBMENU) {
|
||||
ui::MenuModel* submodel = model->GetSubmenuModelAt(i);
|
||||
FillAcceleratorTable(table, submodel);
|
||||
} else {
|
||||
ui::Accelerator accelerator;
|
||||
if (model->GetAcceleratorAt(i, &accelerator)) {
|
||||
MenuItem item = { i, model };
|
||||
(*table)[accelerator] = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
#include "ui/gfx/size.h"
|
||||
#include "ui/views/widget/widget_delegate.h"
|
||||
|
||||
namespace ui {
|
||||
class MenuModel;
|
||||
}
|
||||
|
||||
namespace views {
|
||||
class WebView;
|
||||
class Widget;
|
||||
@@ -19,8 +23,10 @@ class Widget;
|
||||
|
||||
namespace atom {
|
||||
|
||||
class Menu2;
|
||||
|
||||
class NativeWindowWin : public NativeWindow,
|
||||
public views::WidgetDelegate {
|
||||
public views::WidgetDelegateView {
|
||||
public:
|
||||
explicit NativeWindowWin(content::WebContents* web_contents,
|
||||
base::DictionaryValue* options);
|
||||
@@ -34,6 +40,7 @@ class NativeWindowWin : public NativeWindow,
|
||||
virtual bool IsFocused() OVERRIDE;
|
||||
virtual void Show() OVERRIDE;
|
||||
virtual void Hide() OVERRIDE;
|
||||
virtual bool IsVisible() OVERRIDE;
|
||||
virtual void Maximize() OVERRIDE;
|
||||
virtual void Unmaximize() OVERRIDE;
|
||||
virtual void Minimize() OVERRIDE;
|
||||
@@ -60,18 +67,39 @@ class NativeWindowWin : public NativeWindow,
|
||||
virtual bool IsKiosk() OVERRIDE;
|
||||
virtual gfx::NativeWindow GetNativeWindow() OVERRIDE;
|
||||
|
||||
void OnMenuCommand(int position, HMENU menu);
|
||||
|
||||
// Set the native window menu.
|
||||
void SetMenu(ui::MenuModel* menu_model);
|
||||
|
||||
views::Widget* window() const { return window_.get(); }
|
||||
SkRegion* draggable_region() { return draggable_region_.get(); }
|
||||
|
||||
protected:
|
||||
virtual void UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions) OVERRIDE;
|
||||
|
||||
// Overridden from content::WebContentsDelegate:
|
||||
virtual void HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent&) OVERRIDE;
|
||||
|
||||
// Overridden from views::View:
|
||||
virtual void Layout() OVERRIDE;
|
||||
virtual void ViewHierarchyChanged(bool is_add,
|
||||
views::View* parent,
|
||||
views::View* child) OVERRIDE;
|
||||
virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
|
||||
|
||||
// Overridden from views::WidgetDelegate:
|
||||
virtual void DeleteDelegate() OVERRIDE;
|
||||
virtual views::View* GetInitiallyFocusedView() OVERRIDE;
|
||||
virtual bool CanResize() const OVERRIDE;
|
||||
virtual bool CanMaximize() const OVERRIDE;
|
||||
virtual string16 GetWindowTitle() const OVERRIDE;
|
||||
virtual bool ShouldHandleSystemCommands() const OVERRIDE;
|
||||
virtual bool ShouldShowWindowIcon() const OVERRIDE;
|
||||
virtual gfx::ImageSkia GetWindowAppIcon() OVERRIDE;
|
||||
virtual gfx::ImageSkia GetWindowIcon() OVERRIDE;
|
||||
virtual views::Widget* GetWidget() OVERRIDE;
|
||||
virtual const views::Widget* GetWidget() const OVERRIDE;
|
||||
virtual views::ClientView* CreateClientView(views::Widget* widget) OVERRIDE;
|
||||
@@ -79,9 +107,32 @@ class NativeWindowWin : public NativeWindow,
|
||||
views::Widget* widget) OVERRIDE;
|
||||
|
||||
private:
|
||||
typedef struct { int position; ui::MenuModel* model; } MenuItem;
|
||||
typedef std::map<ui::Accelerator, MenuItem> AcceleratorTable;
|
||||
|
||||
void OnViewWasResized();
|
||||
|
||||
// Register accelerators supported by the menu model.
|
||||
void RegisterAccelerators();
|
||||
|
||||
// Generate a table that contains memu model's accelerators and command ids.
|
||||
void GenerateAcceleratorTable();
|
||||
|
||||
// Helper to fill the accelerator table from the model.
|
||||
void FillAcceleratorTable(AcceleratorTable* table,
|
||||
ui::MenuModel* model);
|
||||
|
||||
scoped_ptr<views::Widget> window_;
|
||||
views::WebView* web_view_; // managed by window_.
|
||||
|
||||
// The window menu.
|
||||
scoped_ptr<atom::Menu2> menu_;
|
||||
|
||||
// Map from accelerator to menu item's command id.
|
||||
AcceleratorTable accelerator_table_;
|
||||
|
||||
scoped_ptr<SkRegion> draggable_region_;
|
||||
|
||||
bool resizable_;
|
||||
string16 title_;
|
||||
gfx::Size minimum_size_;
|
||||
|
||||
@@ -30,8 +30,8 @@ void AdapterRequestJob::Start() {
|
||||
}
|
||||
|
||||
void AdapterRequestJob::Kill() {
|
||||
DCHECK(real_job_);
|
||||
real_job_->Kill();
|
||||
if (real_job_) // Kill could happen when real_job_ is created.
|
||||
real_job_->Kill();
|
||||
}
|
||||
|
||||
bool AdapterRequestJob::ReadRawData(net::IOBuffer* buf,
|
||||
|
||||
169
browser/net/atom_url_request_context_getter.cc
Normal file
169
browser/net/atom_url_request_context_getter.cc
Normal file
@@ -0,0 +1,169 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "browser/net/atom_url_request_context_getter.h"
|
||||
|
||||
#include "base/string_util.h"
|
||||
#include "base/threading/worker_pool.h"
|
||||
#include "browser/net/atom_url_request_job_factory.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"
|
||||
|
||||
namespace atom {
|
||||
|
||||
using content::BrowserThread;
|
||||
|
||||
AtomURLRequestContextGetter::AtomURLRequestContextGetter(
|
||||
const base::FilePath& base_path,
|
||||
MessageLoop* io_loop,
|
||||
MessageLoop* file_loop,
|
||||
scoped_ptr<brightray::NetworkDelegate> network_delegate,
|
||||
content::ProtocolHandlerMap* protocol_handlers)
|
||||
: base_path_(base_path),
|
||||
io_loop_(io_loop),
|
||||
file_loop_(file_loop),
|
||||
job_factory_(NULL),
|
||||
network_delegate_(network_delegate.Pass()) {
|
||||
// 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));
|
||||
|
||||
if (!url_request_context_.get()) {
|
||||
url_request_context_.reset(new net::URLRequestContext());
|
||||
url_request_context_->set_network_delegate(network_delegate_.get());
|
||||
storage_.reset(
|
||||
new net::URLRequestContextStorage(url_request_context_.get()));
|
||||
storage_->set_cookie_store(content::CreatePersistentCookieStore(
|
||||
base_path_.Append(FILE_PATH_LITERAL("Cookies")),
|
||||
false,
|
||||
nullptr,
|
||||
nullptr));
|
||||
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", EmptyString()));
|
||||
|
||||
scoped_ptr<net::HostResolver> host_resolver(
|
||||
net::HostResolver::CreateDefaultResolver(NULL));
|
||||
net::DhcpProxyScriptFetcherFactory dhcp_factory;
|
||||
|
||||
storage_->set_cert_verifier(net::CertVerifier::CreateDefault());
|
||||
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()));
|
||||
storage_->set_http_server_properties(new net::HttpServerPropertiesImpl);
|
||||
|
||||
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.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();
|
||||
|
||||
job_factory_->SetProtocolHandler(chrome::kDataScheme,
|
||||
new net::DataProtocolHandler);
|
||||
job_factory_->SetProtocolHandler(chrome::kFileScheme,
|
||||
new net::FileProtocolHandler);
|
||||
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
|
||||
69
browser/net/atom_url_request_context_getter.h
Normal file
69
browser/net/atom_url_request_context_getter.h
Normal file
@@ -0,0 +1,69 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style 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/files/file_path.h"
|
||||
#include "base/memory/scoped_ptr.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,
|
||||
scoped_ptr<brightray::NetworkDelegate> network_delegate,
|
||||
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_;
|
||||
|
||||
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_
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include "browser/ui/accelerator_util.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/string_util.h"
|
||||
@@ -15,67 +17,152 @@ namespace accelerator_util {
|
||||
|
||||
namespace {
|
||||
|
||||
// For Mac, we convert "Ctrl" to "Command" and "MacCtrl" to "Ctrl". Other
|
||||
// platforms leave the shortcut untouched.
|
||||
std::string NormalizeShortcutSuggestion(const std::string& suggestion) {
|
||||
#if !defined(OS_MACOSX)
|
||||
return suggestion;
|
||||
#endif
|
||||
// Return key code of the char.
|
||||
ui::KeyboardCode KeyboardCodeFromCharCode(char c, bool* shifted) {
|
||||
*shifted = false;
|
||||
switch (c) {
|
||||
case 8: case 0x7F: return ui::VKEY_BACK;
|
||||
case 9: return ui::VKEY_TAB;
|
||||
case 0xD: case 3: return ui::VKEY_RETURN;
|
||||
case 0x1B: return ui::VKEY_ESCAPE;
|
||||
case ' ': return ui::VKEY_SPACE;
|
||||
|
||||
std::string key;
|
||||
std::vector<std::string> tokens;
|
||||
base::SplitString(suggestion, '+', &tokens);
|
||||
for (size_t i = 0; i < tokens.size(); i++) {
|
||||
if (tokens[i] == "Ctrl")
|
||||
tokens[i] = "Command";
|
||||
else if (tokens[i] == "MacCtrl")
|
||||
tokens[i] = "Ctrl";
|
||||
case 'a': return ui::VKEY_A;
|
||||
case 'b': return ui::VKEY_B;
|
||||
case 'c': return ui::VKEY_C;
|
||||
case 'd': return ui::VKEY_D;
|
||||
case 'e': return ui::VKEY_E;
|
||||
case 'f': return ui::VKEY_F;
|
||||
case 'g': return ui::VKEY_G;
|
||||
case 'h': return ui::VKEY_H;
|
||||
case 'i': return ui::VKEY_I;
|
||||
case 'j': return ui::VKEY_J;
|
||||
case 'k': return ui::VKEY_K;
|
||||
case 'l': return ui::VKEY_L;
|
||||
case 'm': return ui::VKEY_M;
|
||||
case 'n': return ui::VKEY_N;
|
||||
case 'o': return ui::VKEY_O;
|
||||
case 'p': return ui::VKEY_P;
|
||||
case 'q': return ui::VKEY_Q;
|
||||
case 'r': return ui::VKEY_R;
|
||||
case 's': return ui::VKEY_S;
|
||||
case 't': return ui::VKEY_T;
|
||||
case 'u': return ui::VKEY_U;
|
||||
case 'v': return ui::VKEY_V;
|
||||
case 'w': return ui::VKEY_W;
|
||||
case 'x': return ui::VKEY_X;
|
||||
case 'y': return ui::VKEY_Y;
|
||||
case 'z': return ui::VKEY_Z;
|
||||
|
||||
case ')': *shifted = true; case '0': return ui::VKEY_0;
|
||||
case '!': *shifted = true; case '1': return ui::VKEY_1;
|
||||
case '@': *shifted = true; case '2': return ui::VKEY_2;
|
||||
case '#': *shifted = true; case '3': return ui::VKEY_3;
|
||||
case '$': *shifted = true; case '4': return ui::VKEY_4;
|
||||
case '%': *shifted = true; case '5': return ui::VKEY_5;
|
||||
case '^': *shifted = true; case '6': return ui::VKEY_6;
|
||||
case '&': *shifted = true; case '7': return ui::VKEY_7;
|
||||
case '*': *shifted = true; case '8': return ui::VKEY_8;
|
||||
case '(': *shifted = true; case '9': return ui::VKEY_9;
|
||||
|
||||
case ':': *shifted = true; case ';': return ui::VKEY_OEM_1;
|
||||
case '+': *shifted = true; case '=': return ui::VKEY_OEM_PLUS;
|
||||
case '<': *shifted = true; case ',': return ui::VKEY_OEM_COMMA;
|
||||
case '_': *shifted = true; case '-': return ui::VKEY_OEM_MINUS;
|
||||
case '>': *shifted = true; case '.': return ui::VKEY_OEM_PERIOD;
|
||||
case '?': *shifted = true; case '/': return ui::VKEY_OEM_2;
|
||||
case '~': *shifted = true; case '`': return ui::VKEY_OEM_3;
|
||||
case '{': *shifted = true; case '[': return ui::VKEY_OEM_4;
|
||||
case '|': *shifted = true; case '\\': return ui::VKEY_OEM_5;
|
||||
case '}': *shifted = true; case ']': return ui::VKEY_OEM_6;
|
||||
case '"': *shifted = true; case '\'': return ui::VKEY_OEM_7;
|
||||
|
||||
default: return ui::VKEY_UNKNOWN;
|
||||
}
|
||||
return JoinString(tokens, '+');
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool StringToAccelerator(const std::string& description,
|
||||
ui::Accelerator* accelerator) {
|
||||
std::string shortcut(NormalizeShortcutSuggestion(description));
|
||||
if (!IsStringASCII(description)) {
|
||||
LOG(ERROR) << "The accelerator string can only contain ASCII characters";
|
||||
return false;
|
||||
}
|
||||
std::string shortcut(StringToLowerASCII(description));
|
||||
|
||||
std::vector<std::string> tokens;
|
||||
base::SplitString(shortcut, '+', &tokens);
|
||||
if (tokens.size() < 2 || tokens.size() > 4) {
|
||||
LOG(WARNING) << "Invalid accelerator description: " << description;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now, parse it into an accelerator.
|
||||
int modifiers = ui::EF_NONE;
|
||||
ui::KeyboardCode key = ui::VKEY_UNKNOWN;
|
||||
for (size_t i = 0; i < tokens.size(); i++) {
|
||||
if (tokens[i] == "Ctrl") {
|
||||
// We use straight comparing instead of map because the accelerator tends
|
||||
// to be correct and usually only uses few special tokens.
|
||||
if (tokens[i].size() == 1) {
|
||||
bool shifted = false;
|
||||
key = KeyboardCodeFromCharCode(tokens[i][0], &shifted);
|
||||
if (shifted)
|
||||
modifiers |= ui::EF_SHIFT_DOWN;
|
||||
} else if (tokens[i] == "ctrl") {
|
||||
modifiers |= ui::EF_CONTROL_DOWN;
|
||||
} else if (tokens[i] == "Command") {
|
||||
} else if (tokens[i] == "command") {
|
||||
modifiers |= ui::EF_COMMAND_DOWN;
|
||||
} else if (tokens[i] == "Alt") {
|
||||
} else if (tokens[i] == "alt") {
|
||||
modifiers |= ui::EF_ALT_DOWN;
|
||||
} else if (tokens[i] == "Shift") {
|
||||
} else if (tokens[i] == "shift") {
|
||||
modifiers |= ui::EF_SHIFT_DOWN;
|
||||
} else if (tokens[i].size() == 1) {
|
||||
if (key != ui::VKEY_UNKNOWN) {
|
||||
// Multiple key assignments.
|
||||
key = ui::VKEY_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
if (tokens[i][0] >= 'A' && tokens[i][0] <= 'Z') {
|
||||
key = static_cast<ui::KeyboardCode>(ui::VKEY_A + (tokens[i][0] - 'A'));
|
||||
} else if (tokens[i][0] >= '0' && tokens[i][0] <= '9') {
|
||||
key = static_cast<ui::KeyboardCode>(ui::VKEY_0 + (tokens[i][0] - '0'));
|
||||
} else if (tokens[i][0] >= '+' && tokens[i][0] <= '.') {
|
||||
key = static_cast<ui::KeyboardCode>(
|
||||
ui::VKEY_OEM_PLUS + (tokens[i][0] - '+'));
|
||||
} else if (tokens[i] == "tab") {
|
||||
key = ui::VKEY_TAB;
|
||||
} else if (tokens[i] == "space") {
|
||||
key = ui::VKEY_SPACE;
|
||||
} else if (tokens[i] == "backspace") {
|
||||
key = ui::VKEY_BACK;
|
||||
} else if (tokens[i] == "delete") {
|
||||
key = ui::VKEY_DELETE;
|
||||
} else if (tokens[i] == "enter" || tokens[i] == "return") {
|
||||
key = ui::VKEY_RETURN;
|
||||
} else if (tokens[i] == "up") {
|
||||
key = ui::VKEY_UP;
|
||||
} else if (tokens[i] == "down") {
|
||||
key = ui::VKEY_DOWN;
|
||||
} else if (tokens[i] == "left") {
|
||||
key = ui::VKEY_LEFT;
|
||||
} else if (tokens[i] == "right") {
|
||||
key = ui::VKEY_RIGHT;
|
||||
} else if (tokens[i] == "home") {
|
||||
key = ui::VKEY_HOME;
|
||||
} else if (tokens[i] == "end") {
|
||||
key = ui::VKEY_END;
|
||||
} else if (tokens[i] == "pagedown") {
|
||||
key = ui::VKEY_PRIOR;
|
||||
} else if (tokens[i] == "pageup") {
|
||||
key = ui::VKEY_NEXT;
|
||||
} else if (tokens[i] == "esc") {
|
||||
key = ui::VKEY_ESCAPE;
|
||||
} else if (tokens[i] == "volumemute") {
|
||||
key = ui::VKEY_VOLUME_MUTE;
|
||||
} else if (tokens[i] == "volumeup") {
|
||||
key = ui::VKEY_VOLUME_UP;
|
||||
} else if (tokens[i] == "volumedown") {
|
||||
key = ui::VKEY_VOLUME_DOWN;
|
||||
} else if (tokens[i] == "medianexttrack") {
|
||||
key = ui::VKEY_MEDIA_NEXT_TRACK;
|
||||
} else if (tokens[i] == "mediaprevioustrack") {
|
||||
key = ui::VKEY_MEDIA_PREV_TRACK;
|
||||
} else if (tokens[i] == "mediastop") {
|
||||
key = ui::VKEY_MEDIA_STOP;
|
||||
} else if (tokens[i] == "mediaplaypause") {
|
||||
key = ui::VKEY_MEDIA_PLAY_PAUSE;
|
||||
} else if (tokens[i].size() > 1 && tokens[i][0] == 'f') {
|
||||
// F1 - F24.
|
||||
int n;
|
||||
if (base::StringToInt(tokens[i].c_str() + 1, &n)) {
|
||||
key = static_cast<ui::KeyboardCode>(ui::VKEY_F1 + n - 1);
|
||||
} else {
|
||||
LOG(WARNING) << "Invalid accelerator character: " << tokens[i];
|
||||
key = ui::VKEY_UNKNOWN;
|
||||
break;
|
||||
LOG(WARNING) << tokens[i] << "is not available on keyboard";
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
LOG(WARNING) << "Invalid accelerator token: " << tokens[i];
|
||||
@@ -83,6 +170,11 @@ bool StringToAccelerator(const std::string& description,
|
||||
}
|
||||
}
|
||||
|
||||
if (key == ui::VKEY_UNKNOWN) {
|
||||
LOG(WARNING) << "The accelerator doesn't contain a valid key";
|
||||
return false;
|
||||
}
|
||||
|
||||
*accelerator = ui::Accelerator(key, modifiers);
|
||||
SetPlatformAccelerator(accelerator);
|
||||
return true;
|
||||
|
||||
@@ -2,18 +2,17 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_ATOM_EVENT_PROCESSING_WINDOW_H_
|
||||
#define ATOM_BROWSER_ATOM_EVENT_PROCESSING_WINDOW_H_
|
||||
#ifndef ATOM_BROWSER_UI_ATOM_EVENT_PROCESSING_WINDOW_H_
|
||||
#define ATOM_BROWSER_UI_ATOM_EVENT_PROCESSING_WINDOW_H_
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include "base/memory/scoped_nsobject.h"
|
||||
#import "ui/base/cocoa/underlay_opengl_hosting_window.h"
|
||||
|
||||
// Override NSWindow to access unhandled keyboard events (for command
|
||||
// processing); subclassing NSWindow is the only method to do
|
||||
// this.
|
||||
@interface AtomEventProcessingWindow : UnderlayOpenGLHostingWindow {
|
||||
@interface AtomEventProcessingWindow : NSWindow {
|
||||
@private
|
||||
BOOL redispatchingEvent_;
|
||||
BOOL eventHandled_;
|
||||
@@ -30,4 +29,4 @@
|
||||
- (BOOL)performKeyEquivalent:(NSEvent*)theEvent;
|
||||
@end
|
||||
|
||||
#endif // ATOM_BROWSER_ATOM_EVENT_PROCESSING_WINDOW_H_
|
||||
#endif // ATOM_BROWSER_UI_ATOM_EVENT_PROCESSING_WINDOW_H_
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#import "browser/atom_event_processing_window.h"
|
||||
#import "browser/ui/atom_event_processing_window.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#import "content/public/browser/render_widget_host_view_mac_base.h"
|
||||
@@ -154,9 +154,11 @@ int EventFlagsFromNSEvent(NSEvent* event) {
|
||||
[submenu setTitle:[item title]];
|
||||
[item setSubmenu:submenu];
|
||||
|
||||
// Hack to set window menu.
|
||||
// Hack to set window and help menu.
|
||||
if ([[item title] isEqualToString:@"Window"] && [submenu numberOfItems] > 0)
|
||||
[NSApp setWindowsMenu:submenu];
|
||||
else if ([[item title] isEqualToString:@"Help"])
|
||||
[NSApp setHelpMenu:submenu];
|
||||
} else {
|
||||
// The MenuModel works on indexes so we can't just set the command id as the
|
||||
// tag like we do in other menus. Also set the represented object to be
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/callback_forward.h"
|
||||
#include "base/files/file_path.h"
|
||||
|
||||
namespace atom {
|
||||
@@ -23,16 +24,34 @@ enum FileDialogProperty {
|
||||
FILE_DIALOG_CREATE_DIRECTORY = 8,
|
||||
};
|
||||
|
||||
bool ShowOpenDialog(const std::string& title,
|
||||
typedef base::Callback<void(
|
||||
bool result, const std::vector<base::FilePath>& paths)> OpenDialogCallback;
|
||||
|
||||
typedef base::Callback<void(
|
||||
bool result, const base::FilePath& path)> SaveDialogCallback;
|
||||
|
||||
bool ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
int properties,
|
||||
std::vector<base::FilePath>* paths);
|
||||
|
||||
bool ShowSaveDialog(atom::NativeWindow* window,
|
||||
void ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
int properties,
|
||||
const OpenDialogCallback& callback);
|
||||
|
||||
bool ShowSaveDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
base::FilePath* path);
|
||||
|
||||
void ShowSaveDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
const SaveDialogCallback& callback);
|
||||
|
||||
} // namespace file_dialog
|
||||
|
||||
#endif // BROWSER_UI_FILE_DIALOG_H_
|
||||
|
||||
@@ -38,20 +38,11 @@ void SetupDialog(NSSavePanel* dialog,
|
||||
if (default_filename)
|
||||
[dialog setNameFieldStringValue:default_filename];
|
||||
|
||||
[dialog setCanSelectHiddenExtension:YES];
|
||||
[dialog setAllowsOtherFileTypes:YES];
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool ShowOpenDialog(const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
int properties,
|
||||
std::vector<base::FilePath>* paths) {
|
||||
DCHECK(paths);
|
||||
NSOpenPanel* dialog = [NSOpenPanel openPanel];
|
||||
|
||||
SetupDialog(dialog, title, default_path);
|
||||
|
||||
void SetupDialogForProperties(NSOpenPanel* dialog, int properties) {
|
||||
[dialog setCanChooseFiles:(properties & FILE_DIALOG_OPEN_FILE)];
|
||||
if (properties & FILE_DIALOG_OPEN_DIRECTORY)
|
||||
[dialog setCanChooseDirectories:YES];
|
||||
@@ -59,49 +50,119 @@ bool ShowOpenDialog(const std::string& title,
|
||||
[dialog setCanCreateDirectories:YES];
|
||||
if (properties & FILE_DIALOG_MULTI_SELECTIONS)
|
||||
[dialog setAllowsMultipleSelection:YES];
|
||||
}
|
||||
|
||||
if ([dialog runModal] == NSFileHandlingPanelCancelButton)
|
||||
return false;
|
||||
// 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) {
|
||||
chosen = [dialog runModal];
|
||||
} else {
|
||||
NSWindow* window = parent_window->GetNativeWindow();
|
||||
|
||||
[dialog beginSheetModalForWindow:window
|
||||
completionHandler:^(NSInteger c) {
|
||||
chosen = c;
|
||||
[NSApp stopModal];
|
||||
}];
|
||||
[NSApp runModalForWindow:window];
|
||||
}
|
||||
|
||||
return chosen;
|
||||
}
|
||||
|
||||
void ReadDialogPaths(NSOpenPanel* dialog, std::vector<base::FilePath>* paths) {
|
||||
NSArray* urls = [dialog URLs];
|
||||
for (NSURL* url in urls)
|
||||
if ([url isFileURL])
|
||||
paths->push_back(base::FilePath(base::SysNSStringToUTF8([url path])));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
int properties,
|
||||
std::vector<base::FilePath>* paths) {
|
||||
DCHECK(paths);
|
||||
NSOpenPanel* dialog = [NSOpenPanel openPanel];
|
||||
|
||||
SetupDialog(dialog, title, default_path);
|
||||
SetupDialogForProperties(dialog, properties);
|
||||
|
||||
int chosen = RunModalDialog(dialog, parent_window);
|
||||
if (chosen == NSFileHandlingPanelCancelButton)
|
||||
return false;
|
||||
|
||||
ReadDialogPaths(dialog, paths);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ShowSaveDialog(atom::NativeWindow* window,
|
||||
void ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
int properties,
|
||||
const OpenDialogCallback& c) {
|
||||
NSOpenPanel* dialog = [NSOpenPanel openPanel];
|
||||
|
||||
SetupDialog(dialog, title, default_path);
|
||||
SetupDialogForProperties(dialog, properties);
|
||||
|
||||
// Duplicate the callback object here since c is a reference and gcd would
|
||||
// only store the pointer, by duplication we can force gcd to store a copy.
|
||||
__block OpenDialogCallback callback = c;
|
||||
|
||||
NSWindow* window = parent_window ? parent_window->GetNativeWindow() : NULL;
|
||||
[dialog beginSheetModalForWindow:window
|
||||
completionHandler:^(NSInteger chosen) {
|
||||
if (chosen == NSFileHandlingPanelCancelButton) {
|
||||
callback.Run(false, std::vector<base::FilePath>());
|
||||
} else {
|
||||
std::vector<base::FilePath> paths;
|
||||
ReadDialogPaths(dialog, &paths);
|
||||
callback.Run(true, paths);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
bool ShowSaveDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
base::FilePath* path) {
|
||||
DCHECK(window);
|
||||
DCHECK(path);
|
||||
NSSavePanel* dialog = [NSSavePanel savePanel];
|
||||
|
||||
SetupDialog(dialog, title, default_path);
|
||||
|
||||
[dialog setCanSelectHiddenExtension:YES];
|
||||
int chosen = RunModalDialog(dialog, parent_window);
|
||||
if (chosen == NSFileHandlingPanelCancelButton || ![[dialog URL] isFileURL])
|
||||
return false;
|
||||
|
||||
__block bool result = false;
|
||||
__block base::FilePath ret_path;
|
||||
[dialog beginSheetModalForWindow:window->GetNativeWindow()
|
||||
*path = base::FilePath(base::SysNSStringToUTF8([[dialog URL] path]));
|
||||
return true;
|
||||
}
|
||||
|
||||
void ShowSaveDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
const SaveDialogCallback& c) {
|
||||
NSSavePanel* dialog = [NSSavePanel savePanel];
|
||||
|
||||
SetupDialog(dialog, title, default_path);
|
||||
|
||||
__block SaveDialogCallback callback = c;
|
||||
|
||||
NSWindow* window = parent_window ? parent_window->GetNativeWindow() : NULL;
|
||||
[dialog beginSheetModalForWindow:window
|
||||
completionHandler:^(NSInteger chosen) {
|
||||
if (chosen == NSFileHandlingPanelCancelButton ||
|
||||
![[dialog URL] isFileURL]) {
|
||||
result = false;
|
||||
if (chosen == NSFileHandlingPanelCancelButton) {
|
||||
callback.Run(false, base::FilePath());
|
||||
} else {
|
||||
result = true;
|
||||
ret_path = base::FilePath(base::SysNSStringToUTF8([[dialog URL] path]));
|
||||
std::string path = base::SysNSStringToUTF8([[dialog URL] path]);
|
||||
callback.Run(true, base::FilePath(path));
|
||||
}
|
||||
|
||||
[NSApp stopModal];
|
||||
}];
|
||||
|
||||
[NSApp runModalForWindow:window->GetNativeWindow()];
|
||||
|
||||
*path = ret_path;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace file_dialog
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "browser/ui/file_dialog.h"
|
||||
|
||||
#include <atlbase.h>
|
||||
#include <windows.h>
|
||||
#include <commdlg.h>
|
||||
#include <shlobj.h>
|
||||
@@ -14,19 +15,14 @@
|
||||
#include "base/strings/string_split.h"
|
||||
#include "base/utf_string_conversions.h"
|
||||
#include "base/win/registry.h"
|
||||
#include "base/win/windows_version.h"
|
||||
#include "browser/native_window.h"
|
||||
#include "third_party/wtl/include/atlapp.h"
|
||||
#include "third_party/wtl/include/atldlgs.h"
|
||||
|
||||
namespace file_dialog {
|
||||
|
||||
namespace {
|
||||
|
||||
// Given |extension|, if it's not empty, then remove the leading dot.
|
||||
std::wstring GetExtensionWithoutLeadingDot(const std::wstring& extension) {
|
||||
DCHECK(extension.empty() || extension[0] == L'.');
|
||||
return extension.empty() ? extension : extension.substr(1);
|
||||
}
|
||||
|
||||
// Distinguish directories from regular files.
|
||||
bool IsDirectory(const base::FilePath& path) {
|
||||
base::PlatformFileInfo file_info;
|
||||
@@ -67,26 +63,21 @@ static bool GetRegistryDescriptionFromExtension(const std::wstring& file_ext,
|
||||
// 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.
|
||||
std::wstring FormatFilterForExtensions(
|
||||
const std::vector<std::wstring>& file_ext,
|
||||
const std::vector<std::wstring>& ext_desc,
|
||||
bool include_all_files) {
|
||||
const std::wstring all_ext = L"*.*";
|
||||
// TODO(zcbenz): Should be localized.
|
||||
const std::wstring all_desc = L"All Files";
|
||||
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());
|
||||
|
||||
DCHECK(file_ext.size() >= ext_desc.size());
|
||||
|
||||
if (file_ext.empty())
|
||||
if (file_ext->empty())
|
||||
include_all_files = true;
|
||||
|
||||
std::wstring result;
|
||||
|
||||
for (size_t i = 0; i < file_ext.size(); ++i) {
|
||||
std::wstring ext = file_ext[i];
|
||||
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 (i < ext_desc->size())
|
||||
desc = (*ext_desc)[i];
|
||||
|
||||
if (ext.empty()) {
|
||||
// Force something reasonable to appear in the dialog box if there is no
|
||||
@@ -114,231 +105,214 @@ std::wstring FormatFilterForExtensions(
|
||||
// the we create a description "QQQ File (.qqq)").
|
||||
include_all_files = true;
|
||||
// TODO(zcbenz): should be localized.
|
||||
desc = base::i18n::ToUpper(WideToUTF16(ext_name)) + L" File (."
|
||||
+ ext_name
|
||||
+ L")";
|
||||
desc = base::i18n::ToUpper(WideToUTF16(ext_name)) + L" File";
|
||||
}
|
||||
if (desc.empty())
|
||||
desc = L"*." + ext_name;
|
||||
desc += L" (*." + ext_name + L")";
|
||||
|
||||
// Store the description.
|
||||
ext_desc->push_back(desc);
|
||||
}
|
||||
|
||||
result.append(desc.c_str(), desc.size() + 1); // Append NULL too.
|
||||
result.append(ext.c_str(), ext.size() + 1);
|
||||
COMDLG_FILTERSPEC spec = { (*ext_desc)[i].c_str(), (*file_ext)[i].c_str() };
|
||||
file_types->push_back(spec);
|
||||
}
|
||||
|
||||
if (include_all_files) {
|
||||
result.append(all_desc.c_str(), all_desc.size() + 1);
|
||||
result.append(all_ext.c_str(), all_ext.size() + 1);
|
||||
}
|
||||
// TODO(zcbenz): Should be localized.
|
||||
ext_desc->push_back(L"All Files (*.*)");
|
||||
file_ext->push_back(L"*.*");
|
||||
|
||||
result.append(1, '\0'); // Double NULL required.
|
||||
return result;
|
||||
COMDLG_FILTERSPEC spec = {
|
||||
(*ext_desc)[ext_desc->size() - 1].c_str(),
|
||||
(*file_ext)[file_ext->size() - 1].c_str(),
|
||||
};
|
||||
file_types->push_back(spec);
|
||||
}
|
||||
}
|
||||
|
||||
// This function takes the output of a SaveAs dialog: a filename, a filter and
|
||||
// the extension originally suggested to the user (shown in the dialog box) and
|
||||
// returns back the filename with the appropriate extension tacked on. If the
|
||||
// user requests an unknown extension and is not using the 'All files' filter,
|
||||
// the suggested extension will be appended, otherwise we will leave the
|
||||
// filename unmodified. |filename| should contain the filename selected in the
|
||||
// SaveAs dialog box and may include the path, |filter_selected| should be
|
||||
// '*.something', for example '*.*' or it can be blank (which is treated as
|
||||
// *.*). |suggested_ext| should contain the extension without the dot (.) in
|
||||
// front, for example 'jpg'.
|
||||
std::wstring AppendExtensionIfNeeded(
|
||||
const std::wstring& filename,
|
||||
const std::wstring& filter_selected,
|
||||
const std::wstring& suggested_ext) {
|
||||
DCHECK(!filename.empty());
|
||||
std::wstring return_value = filename;
|
||||
// Generic class to delegate common open/save dialog's behaviours, users need to
|
||||
// call interface methods via GetPtr().
|
||||
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);
|
||||
|
||||
// If we wanted a specific extension, but the user's filename deleted it or
|
||||
// changed it to something that the system doesn't understand, re-append.
|
||||
// Careful: Checking net::GetMimeTypeFromExtension() will only find
|
||||
// extensions with a known MIME type, which many "known" extensions on Windows
|
||||
// don't have. So we check directly for the "known extension" registry key.
|
||||
std::wstring file_extension(
|
||||
GetExtensionWithoutLeadingDot(base::FilePath(filename).Extension()));
|
||||
std::wstring key(L"." + file_extension);
|
||||
if (!(filter_selected.empty() || filter_selected == L"*.*") &&
|
||||
!base::win::RegKey(HKEY_CLASSES_ROOT, key.c_str(), KEY_READ).Valid() &&
|
||||
file_extension != suggested_ext) {
|
||||
if (return_value[return_value.length() - 1] != L'.')
|
||||
return_value.append(L".");
|
||||
return_value.append(suggested_ext);
|
||||
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()));
|
||||
|
||||
if (!title.empty())
|
||||
GetPtr()->SetTitle(UTF8ToUTF16(title).c_str());
|
||||
|
||||
SetDefaultFolder(default_path);
|
||||
}
|
||||
|
||||
// Strip any trailing dots, which Windows doesn't allow.
|
||||
size_t index = return_value.find_last_not_of(L'.');
|
||||
if (index < return_value.size() - 1)
|
||||
return_value.resize(index + 1);
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
// Enforce visible dialog box.
|
||||
UINT_PTR CALLBACK SaveAsDialogHook(HWND dialog, UINT message,
|
||||
WPARAM wparam, LPARAM lparam) {
|
||||
static const UINT kPrivateMessage = 0x2F3F;
|
||||
switch (message) {
|
||||
case WM_INITDIALOG: {
|
||||
// Do nothing here. Just post a message to defer actual processing.
|
||||
PostMessage(dialog, kPrivateMessage, 0, 0);
|
||||
return TRUE;
|
||||
}
|
||||
case kPrivateMessage: {
|
||||
// The dialog box is the parent of the current handle.
|
||||
HWND real_dialog = GetParent(dialog);
|
||||
|
||||
// Retrieve the final size.
|
||||
RECT dialog_rect;
|
||||
GetWindowRect(real_dialog, &dialog_rect);
|
||||
|
||||
// Verify that the upper left corner is visible.
|
||||
POINT point = { dialog_rect.left, dialog_rect.top };
|
||||
HMONITOR monitor1 = MonitorFromPoint(point, MONITOR_DEFAULTTONULL);
|
||||
point.x = dialog_rect.right;
|
||||
point.y = dialog_rect.bottom;
|
||||
|
||||
// Verify that the lower right corner is visible.
|
||||
HMONITOR monitor2 = MonitorFromPoint(point, MONITOR_DEFAULTTONULL);
|
||||
if (monitor1 && monitor2)
|
||||
return 0;
|
||||
|
||||
// Some part of the dialog box is not visible, fix it by moving is to the
|
||||
// client rect position of the browser window.
|
||||
HWND parent_window = GetParent(real_dialog);
|
||||
if (!parent_window)
|
||||
return 0;
|
||||
WINDOWINFO parent_info;
|
||||
parent_info.cbSize = sizeof(WINDOWINFO);
|
||||
GetWindowInfo(parent_window, &parent_info);
|
||||
SetWindowPos(real_dialog, NULL,
|
||||
parent_info.rcClient.left,
|
||||
parent_info.rcClient.top,
|
||||
0, 0, // Size.
|
||||
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE |
|
||||
SWP_NOZORDER);
|
||||
|
||||
return 0;
|
||||
}
|
||||
bool Show(atom::NativeWindow* parent_window) {
|
||||
HWND window = parent_window ? parent_window->GetNativeWindow() : NULL;
|
||||
return dialog_->DoModal(window) == IDOK;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
T* GetDialog() { return dialog_.get(); }
|
||||
|
||||
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) {
|
||||
std::wstring directory = IsDirectory(file_path) ?
|
||||
file_path.value() :
|
||||
file_path.DirName().value();
|
||||
|
||||
ATL::CComPtr<IShellItem> folder_item;
|
||||
HRESULT hr = SHCreateItemFromParsingName(directory.c_str(),
|
||||
NULL,
|
||||
IID_PPV_ARGS(&folder_item));
|
||||
if (SUCCEEDED(hr))
|
||||
GetPtr()->SetDefaultFolder(folder_item);
|
||||
}
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
bool ShowOpenDialog(const std::string& title,
|
||||
bool ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
int properties,
|
||||
std::vector<base::FilePath>* paths) {
|
||||
return false;
|
||||
}
|
||||
int options = FOS_FORCEFILESYSTEM | FOS_FILEMUSTEXIST;
|
||||
if (properties & FILE_DIALOG_OPEN_DIRECTORY)
|
||||
options |= FOS_PICKFOLDERS;
|
||||
if (properties & FILE_DIALOG_MULTI_SELECTIONS)
|
||||
options |= FOS_ALLOWMULTISELECT;
|
||||
|
||||
bool ShowSaveDialog(atom::NativeWindow* window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
base::FilePath* path) {
|
||||
std::wstring file_ext = default_path.Extension().insert(0, L"*");
|
||||
std::wstring filter = FormatFilterForExtensions(
|
||||
std::vector<std::wstring>(1, file_ext),
|
||||
FileDialog<CShellFileOpenDialog> open_dialog(
|
||||
default_path,
|
||||
title,
|
||||
options,
|
||||
std::vector<std::wstring>(),
|
||||
true);
|
||||
|
||||
std::wstring file_part = default_path.BaseName().value();
|
||||
// If the default_path is a root directory, file_part will be '\', and the
|
||||
// call to GetSaveFileName below will fail.
|
||||
if (file_part.size() == 1 && file_part[0] == L'\\')
|
||||
file_part.clear();
|
||||
|
||||
// The size of the in/out buffer in number of characters we pass to win32
|
||||
// GetSaveFileName. From MSDN "The buffer must be large enough to store the
|
||||
// path and file name string or strings, including the terminating NULL
|
||||
// character. ... The buffer should be at least 256 characters long.".
|
||||
// _IsValidPathComDlg does a copy expecting at most MAX_PATH, otherwise will
|
||||
// result in an error of FNERR_INVALIDFILENAME. So we should only pass the
|
||||
// API a buffer of at most MAX_PATH.
|
||||
wchar_t file_name[MAX_PATH];
|
||||
base::wcslcpy(file_name, file_part.c_str(), arraysize(file_name));
|
||||
|
||||
OPENFILENAME save_as;
|
||||
// We must do this otherwise the ofn's FlagsEx may be initialized to random
|
||||
// junk in release builds which can cause the Places Bar not to show up!
|
||||
ZeroMemory(&save_as, sizeof(save_as));
|
||||
save_as.lStructSize = sizeof(OPENFILENAME);
|
||||
save_as.hwndOwner = window->GetNativeWindow();
|
||||
save_as.hInstance = NULL;
|
||||
|
||||
save_as.lpstrFilter = filter.empty() ? NULL : filter.c_str();
|
||||
|
||||
save_as.lpstrCustomFilter = NULL;
|
||||
save_as.nMaxCustFilter = 0;
|
||||
save_as.nFilterIndex = 1;
|
||||
save_as.lpstrFile = file_name;
|
||||
save_as.nMaxFile = arraysize(file_name);
|
||||
save_as.lpstrFileTitle = NULL;
|
||||
save_as.nMaxFileTitle = 0;
|
||||
|
||||
// Set up the initial directory for the dialog.
|
||||
std::wstring directory;
|
||||
if (IsDirectory(default_path)) {
|
||||
directory = default_path.value();
|
||||
file_part.clear();
|
||||
} else {
|
||||
directory = default_path.DirName().value();
|
||||
}
|
||||
|
||||
save_as.lpstrInitialDir = directory.c_str();
|
||||
save_as.lpstrTitle = NULL;
|
||||
save_as.Flags = OFN_OVERWRITEPROMPT | OFN_EXPLORER | OFN_ENABLESIZING |
|
||||
OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST;
|
||||
save_as.lpstrDefExt = NULL; // default extension, ignored for now.
|
||||
save_as.lCustData = NULL;
|
||||
|
||||
if (base::win::GetVersion() < base::win::VERSION_VISTA) {
|
||||
// The save as on Windows XP remembers its last position,
|
||||
// and if the screen resolution changed, it will be off screen.
|
||||
save_as.Flags |= OFN_ENABLEHOOK;
|
||||
save_as.lpfnHook = &SaveAsDialogHook;
|
||||
}
|
||||
|
||||
// Must be NULL or 0.
|
||||
save_as.pvReserved = NULL;
|
||||
save_as.dwReserved = 0;
|
||||
|
||||
if (!GetSaveFileName(&save_as)) {
|
||||
// Zero means the dialog was closed, otherwise we had an error.
|
||||
DWORD error_code = CommDlgExtendedError();
|
||||
if (error_code != 0) {
|
||||
NOTREACHED() << "GetSaveFileName failed with code: " << error_code;
|
||||
}
|
||||
std::vector<std::wstring>());
|
||||
if (!open_dialog.Show(parent_window))
|
||||
return false;
|
||||
|
||||
ATL::CComPtr<IShellItemArray> items;
|
||||
HRESULT hr = static_cast<IFileOpenDialog*>(open_dialog.GetPtr())->GetResults(
|
||||
&items);
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
ATL::CComPtr<IShellItem> item;
|
||||
DWORD count = 0;
|
||||
hr = items->GetCount(&count);
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
paths->reserve(count);
|
||||
for (DWORD i = 0; i < count; ++i) {
|
||||
hr = items->GetItemAt(i, &item);
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
wchar_t file_name[MAX_PATH];
|
||||
hr = CShellFileOpenDialog::GetFileNameFromShellItem(
|
||||
item, SIGDN_FILESYSPATH, file_name, MAX_PATH);
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
paths->push_back(base::FilePath(file_name));
|
||||
}
|
||||
|
||||
// Return the user's choice.
|
||||
*path = base::FilePath();
|
||||
|
||||
// Figure out what filter got selected from the vector with embedded nulls.
|
||||
// NOTE: The filter contains a string with embedded nulls, such as:
|
||||
// JPG Image\0*.jpg\0All files\0*.*\0\0
|
||||
// The filter index is 1-based index for which pair got selected. So, using
|
||||
// the example above, if the first index was selected we need to skip 1
|
||||
// instance of null to get to "*.jpg".
|
||||
std::vector<std::wstring> filters;
|
||||
if (!filter.empty() && save_as.nFilterIndex > 0)
|
||||
base::SplitString(filter, '\0', &filters);
|
||||
std::wstring filter_selected;
|
||||
if (!filters.empty())
|
||||
filter_selected = filters[(2 * (save_as.nFilterIndex - 1)) + 1];
|
||||
|
||||
// Get the extension that was suggested to the user (when the Save As dialog
|
||||
// was opened).
|
||||
std::wstring suggested_ext =
|
||||
GetExtensionWithoutLeadingDot(default_path.Extension());
|
||||
|
||||
*path = base::FilePath(AppendExtensionIfNeeded(
|
||||
save_as.lpstrFile, filter_selected, suggested_ext));
|
||||
return true;
|
||||
}
|
||||
|
||||
void ShowOpenDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
int properties,
|
||||
const OpenDialogCallback& callback) {
|
||||
std::vector<base::FilePath> paths;
|
||||
bool result = ShowOpenDialog(parent_window,
|
||||
title,
|
||||
default_path,
|
||||
properties,
|
||||
&paths);
|
||||
callback.Run(result, paths);
|
||||
}
|
||||
|
||||
bool ShowSaveDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
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>());
|
||||
if (!save_dialog.Show(parent_window))
|
||||
return false;
|
||||
|
||||
wchar_t file_name[MAX_PATH];
|
||||
HRESULT hr = save_dialog.GetDialog()->GetFilePath(file_name, MAX_PATH);
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
*path = base::FilePath(file_name);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ShowSaveDialog(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
const SaveDialogCallback& callback) {
|
||||
base::FilePath path;
|
||||
bool result = ShowSaveDialog(parent_window, title, default_path, &path);
|
||||
callback.Run(result, path);
|
||||
}
|
||||
|
||||
} // namespace file_dialog
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/callback_forward.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class NativeWindow;
|
||||
@@ -18,6 +20,8 @@ enum MessageBoxType {
|
||||
MESSAGE_BOX_TYPE_WARNING
|
||||
};
|
||||
|
||||
typedef base::Callback<void(int code)> MessageBoxCallback;
|
||||
|
||||
int ShowMessageBox(NativeWindow* parent_window,
|
||||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
@@ -25,6 +29,14 @@ int ShowMessageBox(NativeWindow* parent_window,
|
||||
const std::string& message,
|
||||
const std::string& detail);
|
||||
|
||||
void ShowMessageBox(NativeWindow* parent_window,
|
||||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
const MessageBoxCallback& callback);
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // BROWSER_UI_MESSAGE_BOX_H_
|
||||
|
||||
@@ -6,20 +6,53 @@
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "browser/native_window.h"
|
||||
#include "browser/ui/nsalert_synchronous_sheet_mac.h"
|
||||
|
||||
@interface ModalDelegate : NSObject {
|
||||
@private
|
||||
atom::MessageBoxCallback callback_;
|
||||
NSAlert* alert_;
|
||||
}
|
||||
- (id)initWithCallback:(const atom::MessageBoxCallback&)callback
|
||||
andAlert:(NSAlert*)alert;
|
||||
@end
|
||||
|
||||
@implementation ModalDelegate
|
||||
|
||||
- (id)initWithCallback:(const atom::MessageBoxCallback&)callback
|
||||
andAlert:(NSAlert*)alert {
|
||||
if ((self = [super init])) {
|
||||
callback_ = callback;
|
||||
alert_ = alert;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)alertDidEnd:(NSAlert*)alert
|
||||
returnCode:(NSInteger)returnCode
|
||||
contextInfo:(void*)contextInfo {
|
||||
callback_.Run(returnCode);
|
||||
[alert_ release];
|
||||
[self release];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
namespace atom {
|
||||
|
||||
int ShowMessageBox(NativeWindow* parent_window,
|
||||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail) {
|
||||
namespace {
|
||||
|
||||
NSAlert* CreateNSAlert(NativeWindow* parent_window,
|
||||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail) {
|
||||
// Ignore the title; it's the window title on other platforms and ignorable.
|
||||
NSAlert* alert = [[[NSAlert alloc] init] autorelease];
|
||||
NSAlert* alert = [[NSAlert alloc] init];
|
||||
[alert setMessageText:base::SysUTF8ToNSString(message)];
|
||||
[alert setInformativeText:base::SysUTF8ToNSString(detail)];
|
||||
|
||||
@@ -40,10 +73,44 @@ int ShowMessageBox(NativeWindow* parent_window,
|
||||
[button setTag:i];
|
||||
}
|
||||
|
||||
return alert;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int ShowMessageBox(NativeWindow* parent_window,
|
||||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail) {
|
||||
NSAlert* alert = CreateNSAlert(
|
||||
parent_window, type, buttons, title, message, detail);
|
||||
[alert autorelease];
|
||||
|
||||
if (parent_window)
|
||||
return [alert runModalSheetForWindow:parent_window->GetNativeWindow()];
|
||||
else
|
||||
return [alert runModal];
|
||||
}
|
||||
|
||||
void ShowMessageBox(NativeWindow* parent_window,
|
||||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
const MessageBoxCallback& callback) {
|
||||
NSAlert* alert = CreateNSAlert(
|
||||
parent_window, type, buttons, title, message, detail);
|
||||
ModalDelegate* delegate = [[ModalDelegate alloc] initWithCallback:callback
|
||||
andAlert:alert];
|
||||
|
||||
NSWindow* window = parent_window ? parent_window->GetNativeWindow() : nil;
|
||||
[alert beginSheetModalForWindow:window
|
||||
modalDelegate:delegate
|
||||
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
|
||||
contextInfo:nil];
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "browser/ui/message_box.h"
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/message_loop.h"
|
||||
#include "base/run_loop.h"
|
||||
#include "base/string_util.h"
|
||||
@@ -38,7 +39,14 @@ class MessageDialog : public base::MessageLoop::Dispatcher,
|
||||
const std::string& detail);
|
||||
virtual ~MessageDialog();
|
||||
|
||||
int result() const { return result_; }
|
||||
void Show();
|
||||
|
||||
int GetResult() const;
|
||||
|
||||
void set_callback(const MessageBoxCallback& callback) {
|
||||
delete_on_close_ = true;
|
||||
callback_ = callback;
|
||||
}
|
||||
|
||||
private:
|
||||
// Overridden from MessageLoop::Dispatcher:
|
||||
@@ -63,11 +71,13 @@ class MessageDialog : public base::MessageLoop::Dispatcher,
|
||||
const ui::Event& event) OVERRIDE;
|
||||
|
||||
bool should_close_;
|
||||
bool delete_on_close_;
|
||||
int result_;
|
||||
string16 title_;
|
||||
views::Widget* widget_;
|
||||
views::MessageBoxView* message_box_view_;
|
||||
std::vector<views::LabelButton*> buttons_;
|
||||
MessageBoxCallback callback_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MessageDialog);
|
||||
};
|
||||
@@ -82,6 +92,7 @@ MessageDialog::MessageDialog(NativeWindow* parent_window,
|
||||
const std::string& message,
|
||||
const std::string& detail)
|
||||
: should_close_(false),
|
||||
delete_on_close_(false),
|
||||
result_(-1),
|
||||
title_(UTF8ToUTF16(title)),
|
||||
widget_(NULL),
|
||||
@@ -124,12 +135,30 @@ MessageDialog::MessageDialog(NativeWindow* parent_window,
|
||||
|
||||
set_background(views::Background::CreateSolidBackground(
|
||||
skia::COLORREFToSkColor(GetSysColor(COLOR_WINDOW))));
|
||||
widget_->Show();
|
||||
}
|
||||
|
||||
MessageDialog::~MessageDialog() {
|
||||
}
|
||||
|
||||
void MessageDialog::Show() {
|
||||
widget_->Show();
|
||||
}
|
||||
|
||||
int MessageDialog::GetResult() const {
|
||||
// When the dialog is closed without choosing anything, we think the user
|
||||
// chose 'Cancel', otherwise we think the default behavior is chosen.
|
||||
if (result_ == -1) {
|
||||
for (size_t i = 0; i < buttons_.size(); ++i)
|
||||
if (LowerCaseEqualsASCII(buttons_[i]->GetText(), "cancel")) {
|
||||
return i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
return result_;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// MessageDialog, private:
|
||||
|
||||
@@ -145,6 +174,11 @@ string16 MessageDialog::GetWindowTitle() const {
|
||||
|
||||
void MessageDialog::WindowClosing() {
|
||||
should_close_ = true;
|
||||
|
||||
if (delete_on_close_) {
|
||||
callback_.Run(GetResult());
|
||||
base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
|
||||
}
|
||||
}
|
||||
|
||||
views::Widget* MessageDialog::GetWidget() {
|
||||
@@ -232,6 +266,7 @@ int ShowMessageBox(NativeWindow* parent_window,
|
||||
const std::string& message,
|
||||
const std::string& detail) {
|
||||
MessageDialog dialog(parent_window, type, buttons, title, message, detail);
|
||||
dialog.Show();
|
||||
{
|
||||
base::MessageLoop::ScopedNestableTaskAllower allow(
|
||||
base::MessageLoopForUI::current());
|
||||
@@ -239,18 +274,21 @@ int ShowMessageBox(NativeWindow* parent_window,
|
||||
run_loop.Run();
|
||||
}
|
||||
|
||||
// When the dialog is closed without choosing anything, we think the user
|
||||
// chose 'Cancel', otherwise we think the default behavior is chosen.
|
||||
if (dialog.result() == -1) {
|
||||
for (size_t i = 0; i < buttons.size(); ++i)
|
||||
if (LowerCaseEqualsASCII(buttons[i], "cancel")) {
|
||||
return i;
|
||||
}
|
||||
return dialog.GetResult();
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
return dialog.result();
|
||||
}
|
||||
void ShowMessageBox(NativeWindow* parent_window,
|
||||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
const MessageBoxCallback& callback) {
|
||||
// The dialog would be deleted when the dialog is closed.
|
||||
MessageDialog* dialog = new MessageDialog(
|
||||
parent_window, type, buttons, title, message, detail);
|
||||
dialog->set_callback(callback);
|
||||
dialog->Show();
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -77,6 +77,7 @@ class Menu2 {
|
||||
|
||||
// Accessors.
|
||||
ui::MenuModel* model() const { return model_; }
|
||||
NativeMenuWin* wrapper() const { return wrapper_.get(); }
|
||||
|
||||
// Sets the minimum width of the menu.
|
||||
void SetMinimumWidth(int width);
|
||||
|
||||
@@ -92,6 +92,20 @@ class NativeMenuWin::MenuHostWindow {
|
||||
DestroyWindow(hwnd_);
|
||||
}
|
||||
|
||||
// Called when the user selects a specific item.
|
||||
void OnMenuCommand(int position, HMENU menu) {
|
||||
NativeMenuWin* menu_win = GetNativeMenuWinFromHMENU(menu);
|
||||
ui::MenuModel* model = menu_win->model_;
|
||||
NativeMenuWin* root_menu = menu_win;
|
||||
while (root_menu->parent_)
|
||||
root_menu = root_menu->parent_;
|
||||
|
||||
// Only notify the model if it didn't already send out notification.
|
||||
// See comment in MenuMessageHook for details.
|
||||
if (root_menu->menu_action_ == MENU_ACTION_NONE)
|
||||
model->ActivatedAt(position);
|
||||
}
|
||||
|
||||
HWND hwnd() const { return hwnd_; }
|
||||
|
||||
private:
|
||||
@@ -146,20 +160,6 @@ class NativeMenuWin::MenuHostWindow {
|
||||
return reinterpret_cast<NativeMenuWin::ItemData*>(item_data);
|
||||
}
|
||||
|
||||
// Called when the user selects a specific item.
|
||||
void OnMenuCommand(int position, HMENU menu) {
|
||||
NativeMenuWin* menu_win = GetNativeMenuWinFromHMENU(menu);
|
||||
ui::MenuModel* model = menu_win->model_;
|
||||
NativeMenuWin* root_menu = menu_win;
|
||||
while (root_menu->parent_)
|
||||
root_menu = root_menu->parent_;
|
||||
|
||||
// Only notify the model if it didn't already send out notification.
|
||||
// See comment in MenuMessageHook for details.
|
||||
if (root_menu->menu_action_ == MENU_ACTION_NONE)
|
||||
model->ActivatedAt(position);
|
||||
}
|
||||
|
||||
// Called as the user moves their mouse or arrows through the contents of the
|
||||
// menu.
|
||||
void OnMenuSelect(WPARAM w_param, HMENU menu) {
|
||||
@@ -529,6 +529,10 @@ void NativeMenuWin::SetMinimumWidth(int width) {
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
|
||||
void NativeMenuWin::OnMenuCommand(int position, HMENU menu) {
|
||||
host_window_->OnMenuCommand(position, menu);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// NativeMenuWin, private:
|
||||
|
||||
|
||||
@@ -56,6 +56,9 @@ class NativeMenuWin {
|
||||
void RemoveMenuListener(views::MenuListener* listener);
|
||||
void SetMinimumWidth(int width);
|
||||
|
||||
// Called by user to generate a menu command event.
|
||||
void OnMenuCommand(int position, HMENU menu);
|
||||
|
||||
// Flag to create a window menu instead of popup menu.
|
||||
void set_create_as_window_menu(bool flag) { create_as_window_menu_ = flag; }
|
||||
bool create_as_window_menu() const { return create_as_window_menu_; }
|
||||
|
||||
87
common.gypi
87
common.gypi
@@ -4,7 +4,12 @@
|
||||
'conditions': [
|
||||
['OS=="mac"', {
|
||||
'clang': 1,
|
||||
'mac_sdk%': '<!(python tools/mac/find_sdk.py 10.8)',
|
||||
}],
|
||||
['OS=="win" and (MSVS_VERSION=="2012e" or MSVS_VERSION=="2010e")', {
|
||||
'msvs_express': 1,
|
||||
'windows_driver_kit_path%': 'C:/WinDDK/7600.16385.1',
|
||||
},{
|
||||
'msvs_express': 0,
|
||||
}],
|
||||
],
|
||||
# Reflects node's config.gypi.
|
||||
@@ -54,7 +59,36 @@
|
||||
},
|
||||
},
|
||||
'xcode_settings': {
|
||||
'GCC_TREAT_WARNINGS_AS_ERRORS': 'NO'
|
||||
'GCC_TREAT_WARNINGS_AS_ERRORS': 'NO',
|
||||
'WARNING_CFLAGS': [
|
||||
'-Wno-parentheses-equality',
|
||||
'-Wno-unused-function',
|
||||
'-Wno-sometimes-uninitialized',
|
||||
'-Wno-pointer-sign',
|
||||
'-Wno-string-plus-int',
|
||||
'-Wno-unused-variable',
|
||||
'-Wno-deprecated-declarations',
|
||||
'-Wno-return-type',
|
||||
],
|
||||
},
|
||||
}],
|
||||
['_target_name=="libuv"', {
|
||||
'conditions': [
|
||||
['OS=="win"', {
|
||||
# Expose libuv's symbols.
|
||||
'defines': [
|
||||
'BUILDING_UV_SHARED=1',
|
||||
],
|
||||
}], # OS=="win"
|
||||
],
|
||||
}],
|
||||
['_target_name.startswith("breakpad") or _target_name in ["crash_report_sender", "dump_syms"]', {
|
||||
'xcode_settings': {
|
||||
'WARNING_CFLAGS': [
|
||||
'-Wno-deprecated-declarations',
|
||||
'-Wno-unused-private-field',
|
||||
'-Wno-unused-function',
|
||||
],
|
||||
},
|
||||
}],
|
||||
],
|
||||
@@ -67,6 +101,12 @@
|
||||
4819, # The file contains a character that cannot be represented in the current code page
|
||||
],
|
||||
'msvs_settings': {
|
||||
'VCCLCompilerTool': {
|
||||
# Programs that use the Standard C++ library must be compiled with C++
|
||||
# exception handling enabled.
|
||||
# http://support.microsoft.com/kb/154419
|
||||
'ExceptionHandling': 1,
|
||||
},
|
||||
'VCLinkerTool': {
|
||||
'AdditionalOptions': [
|
||||
# ATL 8.0 included in WDK 7.1 makes the linker to generate following
|
||||
@@ -86,6 +126,9 @@
|
||||
],
|
||||
},
|
||||
},
|
||||
'xcode_settings': {
|
||||
'DEBUG_INFORMATION_FORMAT': 'dwarf-with-dsym',
|
||||
},
|
||||
},
|
||||
'conditions': [
|
||||
# Settings to compile with clang under OS X.
|
||||
@@ -112,20 +155,44 @@
|
||||
'-fcolor-diagnostics',
|
||||
],
|
||||
|
||||
'SDKROOT': 'macosx<(mac_sdk)', # -isysroot
|
||||
'GCC_C_LANGUAGE_STANDARD': 'c99', # -std=c99
|
||||
},
|
||||
},
|
||||
}], # clang==1
|
||||
# Windows specific settings.
|
||||
# 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': {
|
||||
'msvs_settings': {
|
||||
'VCCLCompilerTool': {
|
||||
# Programs that use the Standard C++ library must be compiled with C++
|
||||
# exception handling enabled.
|
||||
# http://support.microsoft.com/kb/154419
|
||||
'ExceptionHandling': 1,
|
||||
'configurations': {
|
||||
'Debug_x64': {
|
||||
},
|
||||
'Release_x64': {
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
|
||||
// Multiply-included file, no traditional include guard.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/string16.h"
|
||||
#include "base/values.h"
|
||||
#include "common/draggable_region.h"
|
||||
#include "content/public/common/common_param_traits.h"
|
||||
#include "ipc/ipc_message_macros.h"
|
||||
|
||||
@@ -15,15 +15,24 @@
|
||||
|
||||
#define IPC_MESSAGE_START ShellMsgStart
|
||||
|
||||
IPC_STRUCT_TRAITS_BEGIN(atom::DraggableRegion)
|
||||
IPC_STRUCT_TRAITS_MEMBER(draggable)
|
||||
IPC_STRUCT_TRAITS_MEMBER(bounds)
|
||||
IPC_STRUCT_TRAITS_END()
|
||||
|
||||
IPC_MESSAGE_ROUTED2(AtomViewHostMsg_Message,
|
||||
std::string /* channel */,
|
||||
string16 /* channel */,
|
||||
ListValue /* arguments */)
|
||||
|
||||
IPC_SYNC_MESSAGE_ROUTED2_1(AtomViewHostMsg_Message_Sync,
|
||||
std::string /* channel */,
|
||||
string16 /* channel */,
|
||||
ListValue /* arguments */,
|
||||
DictionaryValue /* result */)
|
||||
string16 /* result (in JSON) */)
|
||||
|
||||
IPC_MESSAGE_ROUTED2(AtomViewMsg_Message,
|
||||
std::string /* channel */,
|
||||
string16 /* channel */,
|
||||
ListValue /* arguments */)
|
||||
|
||||
// Sent by the renderer when the draggable regions are updated.
|
||||
IPC_MESSAGE_ROUTED1(AtomViewHostMsg_UpdateDraggableRegions,
|
||||
std::vector<atom::DraggableRegion> /* regions */)
|
||||
|
||||
40
common/api/atom_api_crash_reporter.cc
Normal file
40
common/api/atom_api_crash_reporter.cc
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "common/api/atom_api_crash_reporter.h"
|
||||
|
||||
#include "common/crash_reporter/crash_reporter.h"
|
||||
#include "common/v8_conversions.h"
|
||||
#include "vendor/node/src/node.h"
|
||||
#include "vendor/node/src/node_internals.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> CrashReporter::Start(const v8::Arguments& args) {
|
||||
std::string product_name, company_name, submit_url;
|
||||
bool auto_submit, skip_system;
|
||||
std::map<std::string, std::string> dict;
|
||||
if (!FromV8Arguments(args, &product_name, &company_name, &submit_url,
|
||||
&auto_submit, &skip_system, &dict))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
crash_reporter::CrashReporter::GetInstance()->Start(
|
||||
product_name, company_name, submit_url, auto_submit, skip_system, dict);
|
||||
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
// static
|
||||
void CrashReporter::Initialize(v8::Handle<v8::Object> target) {
|
||||
node::SetMethod(target, "start", Start);
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
||||
|
||||
NODE_MODULE(atom_common_crash_reporter, atom::api::CrashReporter::Initialize)
|
||||
@@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_API_ATOM_API_CRASH_REPORTER_H_
|
||||
#define ATOM_BROWSER_API_ATOM_API_CRASH_REPORTER_H_
|
||||
#ifndef ATOM_COMMON_API_ATOM_API_CRASH_REPORTER_H_
|
||||
#define ATOM_COMMON_API_ATOM_API_CRASH_REPORTER_H_
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "v8/include/v8.h"
|
||||
@@ -17,9 +17,7 @@ class CrashReporter {
|
||||
static void Initialize(v8::Handle<v8::Object> target);
|
||||
|
||||
private:
|
||||
static v8::Handle<v8::Value> SetCompanyName(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> SetSubmissionURL(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> SetAutoSubmit(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> Start(const v8::Arguments& args);
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(CrashReporter);
|
||||
};
|
||||
@@ -28,4 +26,4 @@ class CrashReporter {
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_API_ATOM_API_CRASH_REPORTER_H_
|
||||
#endif // ATOM_COMMON_API_ATOM_API_CRASH_REPORTER_H_
|
||||
@@ -4,20 +4,39 @@
|
||||
|
||||
#include "common/api/atom_bindings.h"
|
||||
|
||||
#include "base/debug/debugger.h"
|
||||
#include "base/logging.h"
|
||||
#include "common/atom_version.h"
|
||||
#include "common/v8_conversions.h"
|
||||
#include "vendor/node/src/node.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
static int kMaxCallStackSize = 200; // Same with WebKit.
|
||||
|
||||
static uv_async_t dummy_uv_handle;
|
||||
|
||||
struct DummyClass { bool crash; };
|
||||
|
||||
void UvNoOp(uv_async_t* handle, int status) {
|
||||
}
|
||||
|
||||
v8::Handle<v8::Object> DumpStackFrame(v8::Handle<v8::StackFrame> stack_frame) {
|
||||
v8::Local<v8::Object> result = v8::Object::New();
|
||||
result->Set(ToV8Value("line"), ToV8Value(stack_frame->GetLineNumber()));
|
||||
result->Set(ToV8Value("column"), ToV8Value(stack_frame->GetColumn()));
|
||||
|
||||
v8::Handle<v8::String> script = stack_frame->GetScriptName();
|
||||
if (!script.IsEmpty())
|
||||
result->Set(ToV8Value("script"), script);
|
||||
|
||||
v8::Handle<v8::String> function = stack_frame->GetScriptNameOrSourceURL();
|
||||
if (!function.IsEmpty())
|
||||
result->Set(ToV8Value("function"), function);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Defined in atom_extensions.cc.
|
||||
@@ -37,6 +56,7 @@ void AtomBindings::BindTo(v8::Handle<v8::Object> process) {
|
||||
node::SetMethod(process, "crash", Crash);
|
||||
node::SetMethod(process, "activateUvLoop", ActivateUVLoop);
|
||||
node::SetMethod(process, "log", Log);
|
||||
node::SetMethod(process, "getCurrentStackTrace", GetCurrentStackTrace);
|
||||
|
||||
process->Get(v8::String::New("versions"))->ToObject()->
|
||||
Set(v8::String::New("atom-shell"), v8::String::New(ATOM_VERSION_STRING));
|
||||
@@ -91,7 +111,7 @@ v8::Handle<v8::Value> AtomBindings::Binding(const v8::Arguments& args) {
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> AtomBindings::Crash(const v8::Arguments& args) {
|
||||
base::debug::BreakDebugger();
|
||||
static_cast<DummyClass*>(NULL)->crash = true;
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
@@ -111,4 +131,23 @@ v8::Handle<v8::Value> AtomBindings::Log(const v8::Arguments& args) {
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> AtomBindings::GetCurrentStackTrace(
|
||||
const v8::Arguments& args) {
|
||||
v8::HandleScope scope;
|
||||
|
||||
int stack_limit = kMaxCallStackSize;
|
||||
FromV8Arguments(args, &stack_limit);
|
||||
|
||||
v8::Local<v8::StackTrace> stack_trace = v8::StackTrace::CurrentStackTrace(
|
||||
stack_limit, v8::StackTrace::kDetailed);
|
||||
|
||||
int frame_count = stack_trace->GetFrameCount();
|
||||
v8::Local<v8::Array> result = v8::Array::New(frame_count);
|
||||
for (int i = 0; i < frame_count; ++i)
|
||||
result->Set(i, DumpStackFrame(stack_trace->GetFrame(i)));
|
||||
|
||||
return scope.Close(result);
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -24,6 +24,7 @@ class AtomBindings {
|
||||
static v8::Handle<v8::Value> Crash(const v8::Arguments& args);
|
||||
static v8::Handle<v8::Value> ActivateUVLoop(const v8::Arguments& args);
|
||||
static v8::Handle<v8::Value> Log(const v8::Arguments& args);
|
||||
static v8::Handle<v8::Value> GetCurrentStackTrace(const v8::Arguments& args);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomBindings);
|
||||
};
|
||||
|
||||
@@ -11,7 +11,6 @@ NODE_EXT_LIST_START
|
||||
// Module names start with `atom_browser_` can only be used by browser process.
|
||||
NODE_EXT_LIST_ITEM(atom_browser_app)
|
||||
NODE_EXT_LIST_ITEM(atom_browser_auto_updater)
|
||||
NODE_EXT_LIST_ITEM(atom_browser_crash_reporter)
|
||||
NODE_EXT_LIST_ITEM(atom_browser_dialog)
|
||||
NODE_EXT_LIST_ITEM(atom_browser_ipc)
|
||||
NODE_EXT_LIST_ITEM(atom_browser_menu)
|
||||
@@ -26,6 +25,7 @@ NODE_EXT_LIST_ITEM(atom_renderer_ipc)
|
||||
// Module names start with `atom_common_` can be used by both browser and
|
||||
// renderer processes.
|
||||
NODE_EXT_LIST_ITEM(atom_common_clipboard)
|
||||
NODE_EXT_LIST_ITEM(atom_common_crash_reporter)
|
||||
NODE_EXT_LIST_ITEM(atom_common_id_weak_map)
|
||||
NODE_EXT_LIST_ITEM(atom_common_shell)
|
||||
NODE_EXT_LIST_ITEM(atom_common_v8_util)
|
||||
|
||||
38
common/api/lib/crash-reporter.coffee
Normal file
38
common/api/lib/crash-reporter.coffee
Normal file
@@ -0,0 +1,38 @@
|
||||
{spawn} = require 'child_process'
|
||||
binding = process.atomBinding 'crash_reporter'
|
||||
|
||||
class CrashReporter
|
||||
start: (options={}) ->
|
||||
{productName, companyName, submitUrl, autoSubmit, ignoreSystemCrashHandler, extra} = options
|
||||
|
||||
productName ?= 'Atom-Shell'
|
||||
companyName ?= 'GitHub, Inc'
|
||||
submitUrl ?= 'http://54.249.141.255:1127/post'
|
||||
autoSubmit ?= true
|
||||
ignoreSystemCrashHandler ?= false
|
||||
extra ?= {}
|
||||
|
||||
extra._productName ?= productName
|
||||
extra._companyName ?= companyName
|
||||
extra._version ?=
|
||||
if process.__atom_type is 'browser'
|
||||
require('app').getVersion()
|
||||
else
|
||||
require('remote').require('app').getVersion()
|
||||
|
||||
start = -> binding.start productName, companyName, submitUrl, autoSubmit, ignoreSystemCrashHandler, extra
|
||||
|
||||
if process.platform is 'darwin'
|
||||
start()
|
||||
else
|
||||
args = [
|
||||
"--reporter-url=#{submitUrl}"
|
||||
"--application-name=#{productName}"
|
||||
"--v=1"
|
||||
]
|
||||
env = ATOM_SHELL_INTERNAL_CRASH_SERVICE: 1
|
||||
|
||||
spawn process.execPath, args, {env, detached: true}
|
||||
start()
|
||||
|
||||
module.exports = new CrashReporter
|
||||
@@ -6,8 +6,8 @@
|
||||
#define ATOM_VERSION_H
|
||||
|
||||
#define ATOM_MAJOR_VERSION 0
|
||||
#define ATOM_MINOR_VERSION 4
|
||||
#define ATOM_PATCH_VERSION 4
|
||||
#define ATOM_MINOR_VERSION 7
|
||||
#define ATOM_PATCH_VERSION 2
|
||||
|
||||
#define ATOM_VERSION_IS_RELEASE 1
|
||||
|
||||
|
||||
42
common/crash_reporter/crash_reporter.cc
Normal file
42
common/crash_reporter/crash_reporter.cc
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "common/crash_reporter/crash_reporter.h"
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "browser/browser.h"
|
||||
#include "common/atom_version.h"
|
||||
#include "content/public/common/content_switches.h"
|
||||
|
||||
namespace crash_reporter {
|
||||
|
||||
CrashReporter::CrashReporter() {
|
||||
const CommandLine& command = *CommandLine::ForCurrentProcess();
|
||||
is_browser_ = command.GetSwitchValueASCII(switches::kProcessType).empty();
|
||||
}
|
||||
|
||||
CrashReporter::~CrashReporter() {
|
||||
}
|
||||
|
||||
void CrashReporter::Start(const std::string& product_name,
|
||||
const std::string& company_name,
|
||||
const std::string& submit_url,
|
||||
bool auto_submit,
|
||||
bool skip_system_crash_handler,
|
||||
const StringMap& extra_parameters) {
|
||||
SetUploadParameters(extra_parameters);
|
||||
|
||||
InitBreakpad(product_name, ATOM_VERSION_STRING, company_name, submit_url,
|
||||
auto_submit, skip_system_crash_handler);
|
||||
}
|
||||
|
||||
void CrashReporter::SetUploadParameters(const StringMap& parameters) {
|
||||
upload_parameters_ = parameters;
|
||||
upload_parameters_["process_type"] = is_browser_ ? "browser" : "renderer";
|
||||
|
||||
// Setting platform dependent parameters.
|
||||
SetUploadParameters();
|
||||
}
|
||||
|
||||
} // namespace crash_reporter
|
||||
51
common/crash_reporter/crash_reporter.h
Normal file
51
common/crash_reporter/crash_reporter.h
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_H_
|
||||
#define ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
|
||||
namespace crash_reporter {
|
||||
|
||||
class CrashReporter {
|
||||
public:
|
||||
typedef std::map<std::string, std::string> StringMap;
|
||||
|
||||
static CrashReporter* GetInstance();
|
||||
|
||||
void Start(const std::string& product_name,
|
||||
const std::string& company_name,
|
||||
const std::string& submit_url,
|
||||
bool auto_submit,
|
||||
bool skip_system_crash_handler,
|
||||
const StringMap& extra_parameters);
|
||||
|
||||
protected:
|
||||
CrashReporter();
|
||||
virtual ~CrashReporter();
|
||||
|
||||
virtual void InitBreakpad(const std::string& product_name,
|
||||
const std::string& version,
|
||||
const std::string& company_name,
|
||||
const std::string& submit_url,
|
||||
bool auto_submit,
|
||||
bool skip_system_crash_handler) = 0;
|
||||
virtual void SetUploadParameters() = 0;
|
||||
|
||||
StringMap upload_parameters_;
|
||||
bool is_browser_;
|
||||
|
||||
private:
|
||||
void SetUploadParameters(const StringMap& parameters);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CrashReporter);
|
||||
};
|
||||
|
||||
} // namespace crash_reporter
|
||||
|
||||
#endif // ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_H_
|
||||
41
common/crash_reporter/crash_reporter_mac.h
Normal file
41
common/crash_reporter/crash_reporter_mac.h
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_MAC_H_
|
||||
#define ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_MAC_H_
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
#include "common/crash_reporter/crash_reporter.h"
|
||||
#import "vendor/breakpad/src/client/mac/Framework/Breakpad.h"
|
||||
|
||||
template <typename T> struct DefaultSingletonTraits;
|
||||
|
||||
namespace crash_reporter {
|
||||
|
||||
class CrashReporterMac : public CrashReporter {
|
||||
public:
|
||||
static CrashReporterMac* GetInstance();
|
||||
|
||||
virtual void InitBreakpad(const std::string& product_name,
|
||||
const std::string& version,
|
||||
const std::string& company_name,
|
||||
const std::string& submit_url,
|
||||
bool auto_submit,
|
||||
bool skip_system_crash_handler) OVERRIDE;
|
||||
virtual void SetUploadParameters() OVERRIDE;
|
||||
|
||||
private:
|
||||
friend struct DefaultSingletonTraits<CrashReporterMac>;
|
||||
|
||||
CrashReporterMac();
|
||||
virtual ~CrashReporterMac();
|
||||
|
||||
BreakpadRef breakpad_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CrashReporterMac);
|
||||
};
|
||||
|
||||
} // namespace crash_reporter
|
||||
|
||||
#endif // ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_MAC_H_
|
||||
81
common/crash_reporter/crash_reporter_mac.mm
Normal file
81
common/crash_reporter/crash_reporter_mac.mm
Normal file
@@ -0,0 +1,81 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "common/crash_reporter/crash_reporter_mac.h"
|
||||
|
||||
#include "base/memory/singleton.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#import "vendor/breakpad/src/client/apple/Framework/BreakpadDefines.h"
|
||||
|
||||
namespace crash_reporter {
|
||||
|
||||
CrashReporterMac::CrashReporterMac()
|
||||
: breakpad_(NULL) {
|
||||
}
|
||||
|
||||
CrashReporterMac::~CrashReporterMac() {
|
||||
if (breakpad_ != NULL)
|
||||
BreakpadRelease(breakpad_);
|
||||
}
|
||||
|
||||
void CrashReporterMac::InitBreakpad(const std::string& product_name,
|
||||
const std::string& version,
|
||||
const std::string& company_name,
|
||||
const std::string& submit_url,
|
||||
bool auto_submit,
|
||||
bool skip_system_crash_handler) {
|
||||
if (breakpad_ != NULL)
|
||||
BreakpadRelease(breakpad_);
|
||||
|
||||
NSMutableDictionary* parameters =
|
||||
[NSMutableDictionary dictionaryWithCapacity:4];
|
||||
|
||||
[parameters setValue:@"Atom-Shell"
|
||||
forKey:@BREAKPAD_PRODUCT];
|
||||
[parameters setValue:base::SysUTF8ToNSString(product_name)
|
||||
forKey:@BREAKPAD_PRODUCT_DISPLAY];
|
||||
[parameters setValue:base::SysUTF8ToNSString(version)
|
||||
forKey:@BREAKPAD_VERSION];
|
||||
[parameters setValue:base::SysUTF8ToNSString(company_name)
|
||||
forKey:@BREAKPAD_VENDOR];
|
||||
[parameters setValue:base::SysUTF8ToNSString(submit_url)
|
||||
forKey:@BREAKPAD_URL];
|
||||
[parameters setValue:(auto_submit ? @"YES" : @"NO")
|
||||
forKey:@BREAKPAD_SKIP_CONFIRM];
|
||||
[parameters setValue:(skip_system_crash_handler ? @"YES" : @"NO")
|
||||
forKey:@BREAKPAD_SEND_AND_EXIT];
|
||||
|
||||
// Report all crashes (important for testing the crash reporter).
|
||||
[parameters setValue:@"0" forKey:@BREAKPAD_REPORT_INTERVAL];
|
||||
|
||||
// Put dump files under "/tmp/ProductName Crashes".
|
||||
std::string dump_dir = "/tmp/" + product_name + " Crashes";
|
||||
[parameters setValue:base::SysUTF8ToNSString(dump_dir)
|
||||
forKey:@BREAKPAD_DUMP_DIRECTORY];
|
||||
|
||||
breakpad_ = BreakpadCreate(parameters);
|
||||
|
||||
for (StringMap::const_iterator iter = upload_parameters_.begin();
|
||||
iter != upload_parameters_.end(); ++iter) {
|
||||
BreakpadAddUploadParameter(breakpad_,
|
||||
base::SysUTF8ToNSString(iter->first),
|
||||
base::SysUTF8ToNSString(iter->second));
|
||||
}
|
||||
}
|
||||
|
||||
void CrashReporterMac::SetUploadParameters() {
|
||||
upload_parameters_["platform"] = "darwin";
|
||||
}
|
||||
|
||||
// static
|
||||
CrashReporterMac* CrashReporterMac::GetInstance() {
|
||||
return Singleton<CrashReporterMac>::get();
|
||||
}
|
||||
|
||||
// static
|
||||
CrashReporter* CrashReporter::GetInstance() {
|
||||
return CrashReporterMac::GetInstance();
|
||||
}
|
||||
|
||||
} // namespace crash_reporter
|
||||
129
common/crash_reporter/crash_reporter_win.cc
Normal file
129
common/crash_reporter/crash_reporter_win.cc
Normal file
@@ -0,0 +1,129 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "common/crash_reporter/crash_reporter_win.h"
|
||||
|
||||
#include "base/file_util.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/memory/singleton.h"
|
||||
#include "base/string_util.h"
|
||||
#include "base/utf_string_conversions.h"
|
||||
|
||||
namespace crash_reporter {
|
||||
|
||||
namespace {
|
||||
|
||||
// Minidump with stacks, PEB, TEB, and unloaded module list.
|
||||
const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>(
|
||||
MiniDumpWithProcessThreadData | // Get PEB and TEB.
|
||||
MiniDumpWithUnloadedModules); // Get unloaded modules when available.
|
||||
|
||||
const wchar_t kPipeNameFormat[] = L"\\\\.\\pipe\\$1 Crash Service";
|
||||
|
||||
} // namespace
|
||||
|
||||
CrashReporterWin::CrashReporterWin() {
|
||||
}
|
||||
|
||||
CrashReporterWin::~CrashReporterWin() {
|
||||
}
|
||||
|
||||
void CrashReporterWin::InitBreakpad(const std::string& product_name,
|
||||
const std::string& version,
|
||||
const std::string& company_name,
|
||||
const std::string& submit_url,
|
||||
bool auto_submit,
|
||||
bool skip_system_crash_handler) {
|
||||
skip_system_crash_handler_ = skip_system_crash_handler;
|
||||
|
||||
base::FilePath temp_dir;
|
||||
if (!file_util::GetTempDir(&temp_dir)) {
|
||||
LOG(ERROR) << "Cannot get temp directory";
|
||||
return;
|
||||
}
|
||||
|
||||
string16 pipe_name = ReplaceStringPlaceholders(kPipeNameFormat,
|
||||
UTF8ToUTF16(product_name),
|
||||
NULL);
|
||||
|
||||
// Wait until the crash service is started.
|
||||
HANDLE waiting_event =
|
||||
::CreateEventW(NULL, TRUE, FALSE, L"g_atom_shell_crash_service");
|
||||
if (waiting_event != INVALID_HANDLE_VALUE)
|
||||
WaitForSingleObject(waiting_event, 1000);
|
||||
|
||||
breakpad_.reset(new google_breakpad::ExceptionHandler(
|
||||
temp_dir.value(),
|
||||
FilterCallback,
|
||||
MinidumpCallback,
|
||||
this,
|
||||
google_breakpad::ExceptionHandler::HANDLER_ALL,
|
||||
kSmallDumpType,
|
||||
pipe_name.c_str(),
|
||||
GetCustomInfo(product_name, version, company_name)));
|
||||
|
||||
if (!breakpad_->IsOutOfProcess())
|
||||
LOG(ERROR) << "Cannot initialize out-of-process crash handler";
|
||||
}
|
||||
|
||||
void CrashReporterWin::SetUploadParameters() {
|
||||
upload_parameters_["platform"] = "win32";
|
||||
}
|
||||
|
||||
// static
|
||||
bool CrashReporterWin::FilterCallback(void* context,
|
||||
EXCEPTION_POINTERS* exinfo,
|
||||
MDRawAssertionInfo* assertion) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
bool CrashReporterWin::MinidumpCallback(const wchar_t* dump_path,
|
||||
const wchar_t* minidump_id,
|
||||
void* context,
|
||||
EXCEPTION_POINTERS* exinfo,
|
||||
MDRawAssertionInfo* assertion,
|
||||
bool succeeded) {
|
||||
CrashReporterWin* self = static_cast<CrashReporterWin*>(context);
|
||||
if (succeeded && !self->skip_system_crash_handler_)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
google_breakpad::CustomClientInfo* CrashReporterWin::GetCustomInfo(
|
||||
const std::string& product_name,
|
||||
const std::string& version,
|
||||
const std::string& company_name) {
|
||||
custom_info_entries_.clear();
|
||||
custom_info_entries_.reserve(2 + upload_parameters_.size());
|
||||
|
||||
custom_info_entries_.push_back(google_breakpad::CustomInfoEntry(
|
||||
L"prod", L"Atom-Shell"));
|
||||
custom_info_entries_.push_back(google_breakpad::CustomInfoEntry(
|
||||
L"ver", UTF8ToWide(version).c_str()));
|
||||
|
||||
for (StringMap::const_iterator iter = upload_parameters_.begin();
|
||||
iter != upload_parameters_.end(); ++iter) {
|
||||
custom_info_entries_.push_back(google_breakpad::CustomInfoEntry(
|
||||
UTF8ToWide(iter->first).c_str(),
|
||||
UTF8ToWide(iter->second).c_str()));
|
||||
}
|
||||
|
||||
custom_info_.entries = &custom_info_entries_.front();
|
||||
custom_info_.count = custom_info_entries_.size();
|
||||
return &custom_info_;
|
||||
}
|
||||
|
||||
// static
|
||||
CrashReporterWin* CrashReporterWin::GetInstance() {
|
||||
return Singleton<CrashReporterWin>::get();
|
||||
}
|
||||
|
||||
// static
|
||||
CrashReporter* CrashReporter::GetInstance() {
|
||||
return CrashReporterWin::GetInstance();
|
||||
}
|
||||
|
||||
} // namespace crash_reporter
|
||||
64
common/crash_reporter/crash_reporter_win.h
Normal file
64
common/crash_reporter/crash_reporter_win.h
Normal file
@@ -0,0 +1,64 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_WIN_H_
|
||||
#define ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_WIN_H_
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "common/crash_reporter/crash_reporter.h"
|
||||
#include "vendor/breakpad/src/client/windows/handler/exception_handler.h"
|
||||
|
||||
template <typename T> struct DefaultSingletonTraits;
|
||||
|
||||
namespace crash_reporter {
|
||||
|
||||
class CrashReporterWin : public CrashReporter {
|
||||
public:
|
||||
static CrashReporterWin* GetInstance();
|
||||
|
||||
virtual void InitBreakpad(const std::string& product_name,
|
||||
const std::string& version,
|
||||
const std::string& company_name,
|
||||
const std::string& submit_url,
|
||||
bool auto_submit,
|
||||
bool skip_system_crash_handler) OVERRIDE;
|
||||
virtual void SetUploadParameters() OVERRIDE;
|
||||
|
||||
private:
|
||||
friend struct DefaultSingletonTraits<CrashReporterWin>;
|
||||
|
||||
CrashReporterWin();
|
||||
virtual ~CrashReporterWin();
|
||||
|
||||
static bool FilterCallback(void* context,
|
||||
EXCEPTION_POINTERS* exinfo,
|
||||
MDRawAssertionInfo* assertion);
|
||||
|
||||
static bool MinidumpCallback(const wchar_t* dump_path,
|
||||
const wchar_t* minidump_id,
|
||||
void* context,
|
||||
EXCEPTION_POINTERS* exinfo,
|
||||
MDRawAssertionInfo* assertion,
|
||||
bool succeeded);
|
||||
|
||||
// Returns the custom info structure based on parameters.
|
||||
google_breakpad::CustomClientInfo* GetCustomInfo(
|
||||
const std::string& product_name,
|
||||
const std::string& version,
|
||||
const std::string& company_name);
|
||||
|
||||
// Custom information to be passed to crash handler.
|
||||
std::vector<google_breakpad::CustomInfoEntry> custom_info_entries_;
|
||||
google_breakpad::CustomClientInfo custom_info_;
|
||||
|
||||
bool skip_system_crash_handler_;
|
||||
scoped_ptr<google_breakpad::ExceptionHandler> breakpad_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CrashReporterWin);
|
||||
};
|
||||
|
||||
} // namespace crash_reporter
|
||||
|
||||
#endif // ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_WIN_H_
|
||||
490
common/crash_reporter/win/crash_service.cc
Normal file
490
common/crash_reporter/win/crash_service.cc
Normal file
@@ -0,0 +1,490 @@
|
||||
// Copyright (c) 2012 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 "common/crash_reporter/win/crash_service.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <sddl.h>
|
||||
#include <fstream> // NOLINT
|
||||
#include <map>
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "base/file_util.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/win/windows_version.h"
|
||||
#include "vendor/breakpad/src/client/windows/crash_generation/client_info.h"
|
||||
#include "vendor/breakpad/src/client/windows/crash_generation/crash_generation_server.h"
|
||||
#include "vendor/breakpad/src/client/windows/sender/crash_report_sender.h"
|
||||
|
||||
namespace breakpad {
|
||||
|
||||
namespace {
|
||||
|
||||
const wchar_t kTestPipeName[] = L"\\\\.\\pipe\\ChromeCrashServices";
|
||||
|
||||
const wchar_t kGoogleReportURL[] = L"https://clients2.google.com/cr/report";
|
||||
const wchar_t kCheckPointFile[] = L"crash_checkpoint.txt";
|
||||
|
||||
typedef std::map<std::wstring, std::wstring> CrashMap;
|
||||
|
||||
bool CustomInfoToMap(const google_breakpad::ClientInfo* client_info,
|
||||
const std::wstring& reporter_tag, CrashMap* map) {
|
||||
google_breakpad::CustomClientInfo info = client_info->GetCustomInfo();
|
||||
|
||||
for (uintptr_t i = 0; i < info.count; ++i) {
|
||||
(*map)[info.entries[i].name] = info.entries[i].value;
|
||||
}
|
||||
|
||||
(*map)[L"rept"] = reporter_tag;
|
||||
|
||||
return !map->empty();
|
||||
}
|
||||
|
||||
bool WriteCustomInfoToFile(const std::wstring& dump_path, const CrashMap& map) {
|
||||
std::wstring file_path(dump_path);
|
||||
size_t last_dot = file_path.rfind(L'.');
|
||||
if (last_dot == std::wstring::npos)
|
||||
return false;
|
||||
file_path.resize(last_dot);
|
||||
file_path += L".txt";
|
||||
|
||||
std::wofstream file(file_path.c_str(),
|
||||
std::ios_base::out | std::ios_base::app | std::ios::binary);
|
||||
if (!file.is_open())
|
||||
return false;
|
||||
|
||||
CrashMap::const_iterator pos;
|
||||
for (pos = map.begin(); pos != map.end(); ++pos) {
|
||||
std::wstring line = pos->first;
|
||||
line += L':';
|
||||
line += pos->second;
|
||||
line += L'\n';
|
||||
file.write(line.c_str(), static_cast<std::streamsize>(line.length()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// The window procedure task is to handle when a) the user logs off.
|
||||
// b) the system shuts down or c) when the user closes the window.
|
||||
LRESULT __stdcall CrashSvcWndProc(HWND hwnd, UINT message,
|
||||
WPARAM wparam, LPARAM lparam) {
|
||||
switch (message) {
|
||||
case WM_CLOSE:
|
||||
case WM_ENDSESSION:
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
default:
|
||||
return DefWindowProc(hwnd, message, wparam, lparam);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This is the main and only application window.
|
||||
HWND g_top_window = NULL;
|
||||
|
||||
bool CreateTopWindow(HINSTANCE instance, bool visible) {
|
||||
WNDCLASSEXW wcx = {0};
|
||||
wcx.cbSize = sizeof(wcx);
|
||||
wcx.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wcx.lpfnWndProc = CrashSvcWndProc;
|
||||
wcx.hInstance = instance;
|
||||
wcx.lpszClassName = L"crash_svc_class";
|
||||
ATOM atom = ::RegisterClassExW(&wcx);
|
||||
DWORD style = visible ? WS_POPUPWINDOW | WS_VISIBLE : WS_OVERLAPPED;
|
||||
|
||||
// The window size is zero but being a popup window still shows in the
|
||||
// task bar and can be closed using the system menu or using task manager.
|
||||
HWND window = CreateWindowExW(0, wcx.lpszClassName, L"crash service", style,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT, 0, 0,
|
||||
NULL, NULL, instance, NULL);
|
||||
if (!window)
|
||||
return false;
|
||||
|
||||
::UpdateWindow(window);
|
||||
VLOG(1) << "window handle is " << window;
|
||||
g_top_window = window;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Simple helper class to keep the process alive until the current request
|
||||
// finishes.
|
||||
class ProcessingLock {
|
||||
public:
|
||||
ProcessingLock() {
|
||||
::InterlockedIncrement(&op_count_);
|
||||
}
|
||||
~ProcessingLock() {
|
||||
::InterlockedDecrement(&op_count_);
|
||||
}
|
||||
static bool IsWorking() {
|
||||
return (op_count_ != 0);
|
||||
}
|
||||
private:
|
||||
static volatile LONG op_count_;
|
||||
};
|
||||
|
||||
volatile LONG ProcessingLock::op_count_ = 0;
|
||||
|
||||
// This structure contains the information that the worker thread needs to
|
||||
// send a crash dump to the server.
|
||||
struct DumpJobInfo {
|
||||
DWORD pid;
|
||||
CrashService* self;
|
||||
CrashMap map;
|
||||
std::wstring dump_path;
|
||||
|
||||
DumpJobInfo(DWORD process_id, CrashService* service,
|
||||
const CrashMap& crash_map, const std::wstring& path)
|
||||
: pid(process_id), self(service), map(crash_map), dump_path(path) {
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// Command line switches:
|
||||
const char CrashService::kMaxReports[] = "max-reports";
|
||||
const char CrashService::kNoWindow[] = "no-window";
|
||||
const char CrashService::kReporterTag[] = "reporter";
|
||||
const char CrashService::kDumpsDir[] = "dumps-dir";
|
||||
const char CrashService::kPipeName[] = "pipe-name";
|
||||
const char CrashService::kReporterURL[] = "reporter-url";
|
||||
|
||||
CrashService::CrashService()
|
||||
: sender_(NULL),
|
||||
dumper_(NULL),
|
||||
requests_handled_(0),
|
||||
requests_sent_(0),
|
||||
clients_connected_(0),
|
||||
clients_terminated_(0) {
|
||||
}
|
||||
|
||||
CrashService::~CrashService() {
|
||||
base::AutoLock lock(sending_);
|
||||
delete dumper_;
|
||||
delete sender_;
|
||||
}
|
||||
|
||||
bool CrashService::Initialize(const base::FilePath& operating_dir,
|
||||
const base::FilePath& dumps_path) {
|
||||
using google_breakpad::CrashReportSender;
|
||||
using google_breakpad::CrashGenerationServer;
|
||||
|
||||
std::wstring pipe_name = kTestPipeName;
|
||||
int max_reports = -1;
|
||||
|
||||
// The checkpoint file allows CrashReportSender to enforce the the maximum
|
||||
// reports per day quota. Does not seem to serve any other purpose.
|
||||
base::FilePath checkpoint_path = operating_dir.Append(kCheckPointFile);
|
||||
|
||||
CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
|
||||
|
||||
base::FilePath dumps_path_to_use = dumps_path;
|
||||
|
||||
if (cmd_line.HasSwitch(kDumpsDir)) {
|
||||
dumps_path_to_use =
|
||||
base::FilePath(cmd_line.GetSwitchValueNative(kDumpsDir));
|
||||
}
|
||||
|
||||
// We can override the send reports quota with a command line switch.
|
||||
if (cmd_line.HasSwitch(kMaxReports))
|
||||
max_reports = _wtoi(cmd_line.GetSwitchValueNative(kMaxReports).c_str());
|
||||
|
||||
// Allow the global pipe name to be overridden for better testability.
|
||||
if (cmd_line.HasSwitch(kPipeName))
|
||||
pipe_name = cmd_line.GetSwitchValueNative(kPipeName);
|
||||
|
||||
if (max_reports > 0) {
|
||||
// Create the http sender object.
|
||||
sender_ = new CrashReportSender(checkpoint_path.value());
|
||||
sender_->set_max_reports_per_day(max_reports);
|
||||
}
|
||||
|
||||
SECURITY_ATTRIBUTES security_attributes = {0};
|
||||
SECURITY_ATTRIBUTES* security_attributes_actual = NULL;
|
||||
|
||||
if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
|
||||
SECURITY_DESCRIPTOR* security_descriptor =
|
||||
reinterpret_cast<SECURITY_DESCRIPTOR*>(
|
||||
GetSecurityDescriptorForLowIntegrity());
|
||||
DCHECK(security_descriptor != NULL);
|
||||
|
||||
security_attributes.nLength = sizeof(security_attributes);
|
||||
security_attributes.lpSecurityDescriptor = security_descriptor;
|
||||
security_attributes.bInheritHandle = FALSE;
|
||||
|
||||
security_attributes_actual = &security_attributes;
|
||||
}
|
||||
|
||||
// Create the OOP crash generator object.
|
||||
dumper_ = new CrashGenerationServer(pipe_name, security_attributes_actual,
|
||||
&CrashService::OnClientConnected, this,
|
||||
&CrashService::OnClientDumpRequest, this,
|
||||
&CrashService::OnClientExited, this,
|
||||
NULL, NULL,
|
||||
true, &dumps_path_to_use.value());
|
||||
|
||||
if (!dumper_) {
|
||||
LOG(ERROR) << "could not create dumper";
|
||||
if (security_attributes.lpSecurityDescriptor)
|
||||
LocalFree(security_attributes.lpSecurityDescriptor);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CreateTopWindow(::GetModuleHandleW(NULL),
|
||||
!cmd_line.HasSwitch(kNoWindow))) {
|
||||
LOG(ERROR) << "could not create window";
|
||||
if (security_attributes.lpSecurityDescriptor)
|
||||
LocalFree(security_attributes.lpSecurityDescriptor);
|
||||
return false;
|
||||
}
|
||||
|
||||
reporter_tag_ = L"crash svc";
|
||||
if (cmd_line.HasSwitch(kReporterTag))
|
||||
reporter_tag_ = cmd_line.GetSwitchValueNative(kReporterTag);
|
||||
|
||||
reporter_url_ = kGoogleReportURL;
|
||||
if (cmd_line.HasSwitch(kReporterURL))
|
||||
reporter_url_ = cmd_line.GetSwitchValueNative(kReporterURL);
|
||||
|
||||
// Log basic information.
|
||||
VLOG(1) << "pipe name is " << pipe_name
|
||||
<< "\ndumps at " << dumps_path_to_use.value();
|
||||
|
||||
if (sender_) {
|
||||
VLOG(1) << "checkpoint is " << checkpoint_path.value()
|
||||
<< "\nserver is " << reporter_url_
|
||||
<< "\nmaximum " << sender_->max_reports_per_day() << " reports/day"
|
||||
<< "\nreporter is " << reporter_tag_;
|
||||
}
|
||||
// Start servicing clients.
|
||||
if (!dumper_->Start()) {
|
||||
LOG(ERROR) << "could not start dumper";
|
||||
if (security_attributes.lpSecurityDescriptor)
|
||||
LocalFree(security_attributes.lpSecurityDescriptor);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (security_attributes.lpSecurityDescriptor)
|
||||
LocalFree(security_attributes.lpSecurityDescriptor);
|
||||
|
||||
// Create or open an event to signal the browser process that the crash
|
||||
// service is initialized.
|
||||
HANDLE running_event =
|
||||
::CreateEventW(NULL, TRUE, TRUE, L"g_atom_shell_crash_service");
|
||||
// If the browser already had the event open, the CreateEvent call did not
|
||||
// signal it. We need to do it manually.
|
||||
::SetEvent(running_event);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CrashService::OnClientConnected(void* context,
|
||||
const google_breakpad::ClientInfo* client_info) {
|
||||
ProcessingLock lock;
|
||||
VLOG(1) << "client start. pid = " << client_info->pid();
|
||||
CrashService* self = static_cast<CrashService*>(context);
|
||||
::InterlockedIncrement(&self->clients_connected_);
|
||||
}
|
||||
|
||||
void CrashService::OnClientExited(void* context,
|
||||
const google_breakpad::ClientInfo* client_info) {
|
||||
ProcessingLock lock;
|
||||
VLOG(1) << "client end. pid = " << client_info->pid();
|
||||
CrashService* self = static_cast<CrashService*>(context);
|
||||
::InterlockedIncrement(&self->clients_terminated_);
|
||||
|
||||
if (!self->sender_)
|
||||
return;
|
||||
|
||||
// When we are instructed to send reports we need to exit if there are
|
||||
// no more clients to service. The next client that runs will start us.
|
||||
// Only chrome.exe starts crash_service with a non-zero max_reports.
|
||||
if (self->clients_connected_ > self->clients_terminated_)
|
||||
return;
|
||||
if (self->sender_->max_reports_per_day() > 0) {
|
||||
// Wait for the other thread to send crashes, if applicable. The sender
|
||||
// thread takes the sending_ lock, so the sleep is just to give it a
|
||||
// chance to start.
|
||||
::Sleep(1000);
|
||||
base::AutoLock lock(self->sending_);
|
||||
// Some people can restart chrome very fast, check again if we have
|
||||
// a new client before exiting for real.
|
||||
if (self->clients_connected_ == self->clients_terminated_) {
|
||||
VLOG(1) << "zero clients. exiting";
|
||||
::PostMessage(g_top_window, WM_CLOSE, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CrashService::OnClientDumpRequest(void* context,
|
||||
const google_breakpad::ClientInfo* client_info,
|
||||
const std::wstring* file_path) {
|
||||
ProcessingLock lock;
|
||||
|
||||
if (!file_path) {
|
||||
LOG(ERROR) << "dump with no file path";
|
||||
return;
|
||||
}
|
||||
if (!client_info) {
|
||||
LOG(ERROR) << "dump with no client info";
|
||||
return;
|
||||
}
|
||||
|
||||
CrashService* self = static_cast<CrashService*>(context);
|
||||
if (!self) {
|
||||
LOG(ERROR) << "dump with no context";
|
||||
return;
|
||||
}
|
||||
|
||||
CrashMap map;
|
||||
CustomInfoToMap(client_info, self->reporter_tag_, &map);
|
||||
|
||||
// Move dump file to the directory under client breakpad dump location.
|
||||
base::FilePath dump_location = base::FilePath(*file_path);
|
||||
CrashMap::const_iterator it = map.find(L"breakpad-dump-location");
|
||||
if (it != map.end()) {
|
||||
base::FilePath alternate_dump_location = base::FilePath(it->second);
|
||||
file_util::CreateDirectoryW(alternate_dump_location);
|
||||
alternate_dump_location = alternate_dump_location.Append(
|
||||
dump_location.BaseName());
|
||||
file_util::Move(dump_location, alternate_dump_location);
|
||||
dump_location = alternate_dump_location;
|
||||
}
|
||||
|
||||
DWORD pid = client_info->pid();
|
||||
VLOG(1) << "dump for pid = " << pid << " is " << dump_location.value();
|
||||
|
||||
if (!WriteCustomInfoToFile(dump_location.value(), map)) {
|
||||
LOG(ERROR) << "could not write custom info file";
|
||||
}
|
||||
|
||||
if (!self->sender_)
|
||||
return;
|
||||
|
||||
// Send the crash dump using a worker thread. This operation has retry
|
||||
// logic in case there is no internet connection at the time.
|
||||
DumpJobInfo* dump_job = new DumpJobInfo(pid, self, map,
|
||||
dump_location.value());
|
||||
if (!::QueueUserWorkItem(&CrashService::AsyncSendDump,
|
||||
dump_job, WT_EXECUTELONGFUNCTION)) {
|
||||
LOG(ERROR) << "could not queue job";
|
||||
}
|
||||
}
|
||||
|
||||
// We are going to try sending the report several times. If we can't send,
|
||||
// we sleep from one minute to several hours depending on the retry round.
|
||||
DWORD CrashService::AsyncSendDump(void* context) {
|
||||
if (!context)
|
||||
return 0;
|
||||
|
||||
DumpJobInfo* info = static_cast<DumpJobInfo*>(context);
|
||||
|
||||
std::wstring report_id = L"<unsent>";
|
||||
|
||||
const DWORD kOneMinute = 60*1000;
|
||||
const DWORD kOneHour = 60*kOneMinute;
|
||||
|
||||
const DWORD kSleepSchedule[] = {
|
||||
24*kOneHour,
|
||||
8*kOneHour,
|
||||
4*kOneHour,
|
||||
kOneHour,
|
||||
15*kOneMinute,
|
||||
0};
|
||||
|
||||
int retry_round = arraysize(kSleepSchedule) - 1;
|
||||
|
||||
do {
|
||||
::Sleep(kSleepSchedule[retry_round]);
|
||||
{
|
||||
// Take the server lock while sending. This also prevent early
|
||||
// termination of the service object.
|
||||
base::AutoLock lock(info->self->sending_);
|
||||
VLOG(1) << "trying to send report for pid = " << info->pid;
|
||||
google_breakpad::ReportResult send_result
|
||||
= info->self->sender_->SendCrashReport(info->self->reporter_url_,
|
||||
info->map,
|
||||
info->dump_path,
|
||||
&report_id);
|
||||
switch (send_result) {
|
||||
case google_breakpad::RESULT_FAILED:
|
||||
report_id = L"<network issue>";
|
||||
break;
|
||||
case google_breakpad::RESULT_REJECTED:
|
||||
report_id = L"<rejected>";
|
||||
++info->self->requests_handled_;
|
||||
retry_round = 0;
|
||||
break;
|
||||
case google_breakpad::RESULT_SUCCEEDED:
|
||||
++info->self->requests_sent_;
|
||||
++info->self->requests_handled_;
|
||||
retry_round = 0;
|
||||
break;
|
||||
case google_breakpad::RESULT_THROTTLED:
|
||||
report_id = L"<throttled>";
|
||||
break;
|
||||
default:
|
||||
report_id = L"<unknown>";
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
VLOG(1) << "dump for pid =" << info->pid << " crash2 id =" << report_id;
|
||||
--retry_round;
|
||||
} while (retry_round >= 0);
|
||||
|
||||
if (!::DeleteFileW(info->dump_path.c_str()))
|
||||
LOG(WARNING) << "could not delete " << info->dump_path;
|
||||
|
||||
delete info;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CrashService::ProcessingLoop() {
|
||||
MSG msg;
|
||||
while (GetMessage(&msg, NULL, 0, 0)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
VLOG(1) << "session ending..";
|
||||
while (ProcessingLock::IsWorking()) {
|
||||
::Sleep(50);
|
||||
}
|
||||
|
||||
VLOG(1) << "clients connected :" << clients_connected_
|
||||
<< "\nclients terminated :" << clients_terminated_
|
||||
<< "\ndumps serviced :" << requests_handled_
|
||||
<< "\ndumps reported :" << requests_sent_;
|
||||
|
||||
return static_cast<int>(msg.wParam);
|
||||
}
|
||||
|
||||
PSECURITY_DESCRIPTOR CrashService::GetSecurityDescriptorForLowIntegrity() {
|
||||
// Build the SDDL string for the label.
|
||||
std::wstring sddl = L"S:(ML;;NW;;;S-1-16-4096)";
|
||||
|
||||
DWORD error = ERROR_SUCCESS;
|
||||
PSECURITY_DESCRIPTOR sec_desc = NULL;
|
||||
|
||||
PACL sacl = NULL;
|
||||
BOOL sacl_present = FALSE;
|
||||
BOOL sacl_defaulted = FALSE;
|
||||
|
||||
if (::ConvertStringSecurityDescriptorToSecurityDescriptorW(sddl.c_str(),
|
||||
SDDL_REVISION,
|
||||
&sec_desc, NULL)) {
|
||||
if (::GetSecurityDescriptorSacl(sec_desc, &sacl_present, &sacl,
|
||||
&sacl_defaulted)) {
|
||||
return sec_desc;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} // namespace breakpad
|
||||
|
||||
131
common/crash_reporter/win/crash_service.h
Normal file
131
common/crash_reporter/win/crash_service.h
Normal file
@@ -0,0 +1,131 @@
|
||||
// Copyright (c) 2011 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 COMMON_CRASH_REPORTER_WIN_CRASH_SERVICE_H_
|
||||
#define COMMON_CRASH_REPORTER_WIN_CRASH_SERVICE_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/synchronization/lock.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
class CrashReportSender;
|
||||
class CrashGenerationServer;
|
||||
class ClientInfo;
|
||||
|
||||
}
|
||||
|
||||
namespace breakpad {
|
||||
|
||||
// This class implements an out-of-process crash server. It uses breakpad's
|
||||
// CrashGenerationServer and CrashReportSender to generate and then send the
|
||||
// crash dumps. Internally, it uses OS specific pipe to allow applications to
|
||||
// register for crash dumps and later on when a registered application crashes
|
||||
// it will signal an event that causes this code to wake up and perform a
|
||||
// crash dump on the signaling process. The dump is then stored on disk and
|
||||
// possibly sent to the crash2 servers.
|
||||
class CrashService {
|
||||
public:
|
||||
CrashService();
|
||||
~CrashService();
|
||||
|
||||
// Starts servicing crash dumps. Returns false if it failed. Do not use
|
||||
// other members in that case. |operating_dir| is where the CrashService
|
||||
// should store breakpad's checkpoint file. |dumps_path| is the directory
|
||||
// where the crash dumps should be stored.
|
||||
bool Initialize(const base::FilePath& operating_dir,
|
||||
const base::FilePath& dumps_path);
|
||||
|
||||
// Command line switches:
|
||||
//
|
||||
// --max-reports=<number>
|
||||
// Allows to override the maximum number for reports per day. Normally
|
||||
// the crash dumps are never sent so if you want to send any you must
|
||||
// specify a positive number here.
|
||||
static const char kMaxReports[];
|
||||
// --no-window
|
||||
// Does not create a visible window on the desktop. The window does not have
|
||||
// any other functionality other than allowing the crash service to be
|
||||
// gracefully closed.
|
||||
static const char kNoWindow[];
|
||||
// --reporter=<string>
|
||||
// Allows to specify a custom string that appears on the detail crash report
|
||||
// page in the crash server. This should be a 25 chars or less string.
|
||||
// The default tag if not specified is 'crash svc'.
|
||||
static const char kReporterTag[];
|
||||
// --dumps-dir=<directory-path>
|
||||
// Override the directory to which crash dump files will be written.
|
||||
static const char kDumpsDir[];
|
||||
// --pipe-name=<string>
|
||||
// Override the name of the Windows named pipe on which we will
|
||||
// listen for crash dump request messages.
|
||||
static const char kPipeName[];
|
||||
// --reporter-url=<string>
|
||||
// Override the URL to which crash reports will be sent to.
|
||||
static const char kReporterURL[];
|
||||
|
||||
// Returns number of crash dumps handled.
|
||||
int requests_handled() const {
|
||||
return requests_handled_;
|
||||
}
|
||||
// Returns number of crash clients registered.
|
||||
int clients_connected() const {
|
||||
return clients_connected_;
|
||||
}
|
||||
// Returns number of crash clients terminated.
|
||||
int clients_terminated() const {
|
||||
return clients_terminated_;
|
||||
}
|
||||
|
||||
// Starts the processing loop. This function does not return unless the
|
||||
// user is logging off or the user closes the crash service window. The
|
||||
// return value is a good number to pass in ExitProcess().
|
||||
int ProcessingLoop();
|
||||
|
||||
private:
|
||||
static void OnClientConnected(void* context,
|
||||
const google_breakpad::ClientInfo* client_info);
|
||||
|
||||
static void OnClientDumpRequest(
|
||||
void* context,
|
||||
const google_breakpad::ClientInfo* client_info,
|
||||
const std::wstring* file_path);
|
||||
|
||||
static void OnClientExited(void* context,
|
||||
const google_breakpad::ClientInfo* client_info);
|
||||
|
||||
// This routine sends the crash dump to the server. It takes the sending_
|
||||
// lock when it is performing the send.
|
||||
static DWORD __stdcall AsyncSendDump(void* context);
|
||||
|
||||
// Returns the security descriptor which access to low integrity processes
|
||||
// The caller is supposed to free the security descriptor by calling
|
||||
// LocalFree.
|
||||
PSECURITY_DESCRIPTOR GetSecurityDescriptorForLowIntegrity();
|
||||
|
||||
google_breakpad::CrashGenerationServer* dumper_;
|
||||
google_breakpad::CrashReportSender* sender_;
|
||||
|
||||
// the extra tag sent to the server with each dump.
|
||||
std::wstring reporter_tag_;
|
||||
|
||||
// receiver URL of crash reports.
|
||||
std::wstring reporter_url_;
|
||||
|
||||
// clients serviced statistics:
|
||||
int requests_handled_;
|
||||
int requests_sent_;
|
||||
volatile LONG clients_connected_;
|
||||
volatile LONG clients_terminated_;
|
||||
base::Lock sending_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CrashService);
|
||||
};
|
||||
|
||||
} // namespace breakpad
|
||||
|
||||
#endif // COMMON_CRASH_REPORTER_WIN_CRASH_SERVICE_H_
|
||||
92
common/crash_reporter/win/crash_service_main.cc
Normal file
92
common/crash_reporter/win/crash_service_main.cc
Normal file
@@ -0,0 +1,92 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "common/crash_reporter/win/crash_service_main.h"
|
||||
|
||||
#include "base/at_exit.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/file_util.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/string_util.h"
|
||||
#include "common/crash_reporter/win/crash_service.h"
|
||||
|
||||
namespace crash_service {
|
||||
|
||||
namespace {
|
||||
|
||||
const char kApplicationName[] = "application-name";
|
||||
|
||||
const wchar_t kPipeNameFormat[] = L"\\\\.\\pipe\\$1 Crash Service";
|
||||
const wchar_t kStandardLogFile[] = L"operation_log.txt";
|
||||
|
||||
bool GetCrashServiceDirectory(const std::wstring& application_name,
|
||||
base::FilePath* dir) {
|
||||
base::FilePath temp_dir;
|
||||
if (!file_util::GetTempDir(&temp_dir))
|
||||
return false;
|
||||
temp_dir = temp_dir.Append(application_name + L" Crashes");
|
||||
if (!file_util::PathExists(temp_dir)) {
|
||||
if (!file_util::CreateDirectory(temp_dir))
|
||||
return false;
|
||||
}
|
||||
*dir = temp_dir;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace.
|
||||
|
||||
int Main(const wchar_t* cmd) {
|
||||
// Initialize all Chromium things.
|
||||
base::AtExitManager exit_manager;
|
||||
CommandLine::Init(0, NULL);
|
||||
CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
|
||||
|
||||
// Use the application's name as pipe name and output directory.
|
||||
if (!cmd_line.HasSwitch(kApplicationName)) {
|
||||
LOG(ERROR) << "Application's name must be specified with --"
|
||||
<< kApplicationName;
|
||||
return 1;
|
||||
}
|
||||
std::wstring application_name = cmd_line.GetSwitchValueNative(
|
||||
kApplicationName);
|
||||
|
||||
// We use/create a directory under the user's temp folder, for logging.
|
||||
base::FilePath operating_dir;
|
||||
GetCrashServiceDirectory(application_name, &operating_dir);
|
||||
base::FilePath log_file = operating_dir.Append(kStandardLogFile);
|
||||
|
||||
// Logging out to a file.
|
||||
logging::InitLogging(
|
||||
log_file.value().c_str(),
|
||||
logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG ,
|
||||
logging::LOCK_LOG_FILE,
|
||||
logging::DELETE_OLD_LOG_FILE,
|
||||
logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS);
|
||||
logging::SetLogItems(true, false, true, false);
|
||||
|
||||
VLOG(1) << "Session start. cmdline is [" << cmd << "]";
|
||||
|
||||
// Setting the crash reporter.
|
||||
string16 pipe_name = ReplaceStringPlaceholders(kPipeNameFormat,
|
||||
application_name,
|
||||
NULL);
|
||||
cmd_line.AppendSwitch("no-window");
|
||||
cmd_line.AppendSwitchASCII("max-reports", "128");
|
||||
cmd_line.AppendSwitchASCII("reporter", "atom-shell-crash-service");
|
||||
cmd_line.AppendSwitchNative("pipe-name", pipe_name);
|
||||
|
||||
breakpad::CrashService crash_service;
|
||||
if (!crash_service.Initialize(operating_dir, operating_dir))
|
||||
return 2;
|
||||
|
||||
VLOG(1) << "Ready to process crash requests";
|
||||
|
||||
// Enter the message loop.
|
||||
int retv = crash_service.ProcessingLoop();
|
||||
// Time to exit.
|
||||
VLOG(1) << "Session end. return code is " << retv;
|
||||
return retv;
|
||||
}
|
||||
|
||||
} // namespace crash_service
|
||||
15
common/crash_reporter/win/crash_service_main.h
Normal file
15
common/crash_reporter/win/crash_service_main.h
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef COMMON_CRASH_REPORTER_WIN_CRASH_SERVICE_MAIN_H_
|
||||
#define COMMON_CRASH_REPORTER_WIN_CRASH_SERVICE_MAIN_H_
|
||||
|
||||
namespace crash_service {
|
||||
|
||||
// Program entry, should be called by main();
|
||||
int Main(const wchar_t* cmd_line);
|
||||
|
||||
} // namespace crash_service
|
||||
|
||||
#endif // COMMON_CRASH_REPORTER_WIN_CRASH_SERVICE_MAIN_H_
|
||||
13
common/draggable_region.cc
Normal file
13
common/draggable_region.cc
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright (c) 2012 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 "common/draggable_region.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
DraggableRegion::DraggableRegion()
|
||||
: draggable(false) {
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
21
common/draggable_region.h
Normal file
21
common/draggable_region.h
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) 2012 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 ATOM_COMMON_DRAGGABLE_REGION_H_
|
||||
#define ATOM_COMMON_DRAGGABLE_REGION_H_
|
||||
|
||||
#include "ui/gfx/rect.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
struct DraggableRegion {
|
||||
bool draggable;
|
||||
gfx::Rect bounds;
|
||||
|
||||
DraggableRegion();
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_COMMON_DRAGGABLE_REGION_H_
|
||||
@@ -7,7 +7,9 @@
|
||||
#include "base/command_line.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/message_loop.h"
|
||||
#include "common/v8_conversions.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "net/base/escape.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
|
||||
#include "vendor/node/src/node.h"
|
||||
@@ -37,10 +39,16 @@ NodeBindings::NodeBindings(bool is_browser)
|
||||
}
|
||||
|
||||
NodeBindings::~NodeBindings() {
|
||||
// Clear uv.
|
||||
// Quit the embed thread.
|
||||
embed_closed_ = true;
|
||||
uv_sem_post(&embed_sem_);
|
||||
WakeupEmbedThread();
|
||||
|
||||
// Wait for everything to be done.
|
||||
uv_thread_join(&embed_thread_);
|
||||
message_loop_->RunUntilIdle();
|
||||
|
||||
// Clear uv.
|
||||
uv_sem_destroy(&embed_sem_);
|
||||
uv_timer_stop(&idle_timer_);
|
||||
}
|
||||
@@ -116,9 +124,12 @@ void NodeBindings::BindTo(WebKit::WebFrame* frame) {
|
||||
|
||||
// Run the script of cefode.js.
|
||||
std::string script_path(GURL(frame->document().url()).path());
|
||||
script_path = net::UnescapeURLComponent(
|
||||
script_path,
|
||||
net::UnescapeRule::SPACES | net::UnescapeRule::URL_SPECIAL_CHARS);
|
||||
v8::Handle<v8::Value> args[2] = {
|
||||
v8::Local<v8::Value>::New(node::process),
|
||||
v8::String::New(script_path.c_str(), script_path.size())
|
||||
ToV8Value(script_path),
|
||||
};
|
||||
v8::Local<v8::Function>::Cast(result)->Call(context->Global(), 2, args);
|
||||
}
|
||||
|
||||
270
common/v8_conversions.h
Normal file
270
common/v8_conversions.h
Normal file
@@ -0,0 +1,270 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef COMMON_V8_CONVERSIONS_H_
|
||||
#define COMMON_V8_CONVERSIONS_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/string16.h"
|
||||
#include "browser/api/atom_api_window.h"
|
||||
#include "ui/gfx/rect.h"
|
||||
#include "v8/include/v8.h"
|
||||
|
||||
// Convert V8 value to arbitrary supported types.
|
||||
struct FromV8Value {
|
||||
explicit FromV8Value(v8::Handle<v8::Value> value) : value_(value) {}
|
||||
|
||||
operator int() {
|
||||
return value_->IntegerValue();
|
||||
}
|
||||
|
||||
operator bool() {
|
||||
return value_->BooleanValue();
|
||||
}
|
||||
|
||||
operator std::string() {
|
||||
return *v8::String::Utf8Value(value_);
|
||||
}
|
||||
|
||||
operator string16() {
|
||||
v8::String::Value s(value_);
|
||||
return string16(reinterpret_cast<const char16*>(*s), s.length());
|
||||
}
|
||||
|
||||
operator base::FilePath() {
|
||||
return base::FilePath::FromUTF8Unsafe(FromV8Value(value_));
|
||||
}
|
||||
|
||||
operator gfx::Rect() {
|
||||
v8::Handle<v8::Object> rect = value_->ToObject();
|
||||
v8::Handle<v8::Value> x = rect->Get(v8::String::New("x"));
|
||||
v8::Handle<v8::Value> y = rect->Get(v8::String::New("y"));
|
||||
v8::Handle<v8::Value> width = rect->Get(v8::String::New("width"));
|
||||
v8::Handle<v8::Value> height = rect->Get(v8::String::New("height"));
|
||||
if (!x->IsNumber() || !y->IsNumber() ||
|
||||
!width->IsNumber() || !height->IsNumber())
|
||||
return gfx::Rect();
|
||||
else
|
||||
return gfx::Rect(x->IntegerValue(), y->IntegerValue(),
|
||||
width->IntegerValue(), height->IntegerValue());
|
||||
}
|
||||
|
||||
operator std::vector<std::string>() {
|
||||
std::vector<std::string> array;
|
||||
v8::Handle<v8::Array> v8_array = v8::Handle<v8::Array>::Cast(value_);
|
||||
for (uint32_t i = 0; i < v8_array->Length(); ++i)
|
||||
array.push_back(FromV8Value(v8_array->Get(i)));
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
operator std::map<std::string, std::string>() {
|
||||
std::map<std::string, std::string> dict;
|
||||
v8::Handle<v8::Object> v8_dict = value_->ToObject();
|
||||
v8::Handle<v8::Array> v8_keys = v8_dict->GetOwnPropertyNames();
|
||||
for (uint32_t i = 0; i < v8_keys->Length(); ++i) {
|
||||
v8::Handle<v8::Value> v8_key = v8_keys->Get(i);
|
||||
std::string key = FromV8Value(v8_key);
|
||||
dict[key] = std::string(FromV8Value(v8_dict->Get(v8_key)));
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
operator atom::NativeWindow*() {
|
||||
using atom::api::Window;
|
||||
if (value_->IsObject()) {
|
||||
Window* window = Window::Unwrap<Window>(value_->ToObject());
|
||||
if (window && window->window())
|
||||
return window->window();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
operator v8::Persistent<v8::Function>() {
|
||||
return v8::Persistent<v8::Function>::New(
|
||||
node::node_isolate,
|
||||
v8::Handle<v8::Function>::Cast(value_));
|
||||
}
|
||||
|
||||
v8::Handle<v8::Value> value_;
|
||||
};
|
||||
|
||||
// Convert arbitrary supported native type to V8 value.
|
||||
inline v8::Handle<v8::Value> ToV8Value(int i) {
|
||||
return v8::Integer::New(i);
|
||||
}
|
||||
|
||||
inline v8::Handle<v8::Value> ToV8Value(bool b) {
|
||||
return v8::Boolean::New(b);
|
||||
}
|
||||
|
||||
inline v8::Handle<v8::Value> ToV8Value(const char* s) {
|
||||
return v8::String::New(s);
|
||||
}
|
||||
|
||||
inline v8::Handle<v8::Value> ToV8Value(const std::string& s) {
|
||||
return v8::String::New(s.data(), s.size());
|
||||
}
|
||||
|
||||
inline v8::Handle<v8::Value> ToV8Value(const string16& s) {
|
||||
return v8::String::New(reinterpret_cast<const uint16_t*>(s.data()), s.size());
|
||||
}
|
||||
|
||||
inline v8::Handle<v8::Value> ToV8Value(const base::FilePath& path) {
|
||||
std::string path_string(path.AsUTF8Unsafe());
|
||||
return v8::String::New(path_string.data(), path_string.size());
|
||||
}
|
||||
|
||||
inline v8::Handle<v8::Value> ToV8Value(void* whatever) {
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
inline
|
||||
v8::Handle<v8::Value> ToV8Value(const std::vector<base::FilePath>& paths) {
|
||||
v8::Handle<v8::Array> result = v8::Array::New(paths.size());
|
||||
for (size_t i = 0; i < paths.size(); ++i)
|
||||
result->Set(i, ToV8Value(paths[i]));
|
||||
return result;
|
||||
}
|
||||
|
||||
// Check if a V8 Value is of specified type.
|
||||
template<class T> inline
|
||||
bool V8ValueCanBeConvertedTo(v8::Handle<v8::Value> value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
template<> inline
|
||||
bool V8ValueCanBeConvertedTo<int>(v8::Handle<v8::Value> value) {
|
||||
return value->IsNumber();
|
||||
}
|
||||
|
||||
template<> inline
|
||||
bool V8ValueCanBeConvertedTo<bool>(v8::Handle<v8::Value> value) {
|
||||
return value->IsBoolean();
|
||||
}
|
||||
|
||||
template<> inline
|
||||
bool V8ValueCanBeConvertedTo<std::string>(v8::Handle<v8::Value> value) {
|
||||
return value->IsString();
|
||||
}
|
||||
|
||||
template<> inline
|
||||
bool V8ValueCanBeConvertedTo<string16>(v8::Handle<v8::Value> value) {
|
||||
return V8ValueCanBeConvertedTo<std::string>(value);
|
||||
}
|
||||
|
||||
template<> inline
|
||||
bool V8ValueCanBeConvertedTo<base::FilePath>(v8::Handle<v8::Value> value) {
|
||||
return V8ValueCanBeConvertedTo<std::string>(value);
|
||||
}
|
||||
|
||||
template<> inline
|
||||
bool V8ValueCanBeConvertedTo<gfx::Rect>(v8::Handle<v8::Value> value) {
|
||||
return value->IsObject();
|
||||
}
|
||||
|
||||
template<> inline
|
||||
bool V8ValueCanBeConvertedTo<std::vector<std::string>>(
|
||||
v8::Handle<v8::Value> value) {
|
||||
return value->IsArray();
|
||||
}
|
||||
|
||||
template<> inline
|
||||
bool V8ValueCanBeConvertedTo<std::map<std::string, std::string>>(
|
||||
v8::Handle<v8::Value> value) {
|
||||
return value->IsObject();
|
||||
}
|
||||
|
||||
template<> inline
|
||||
bool V8ValueCanBeConvertedTo<atom::NativeWindow*>(v8::Handle<v8::Value> value) {
|
||||
using atom::api::Window;
|
||||
if (value->IsObject()) {
|
||||
Window* window = Window::Unwrap<Window>(value->ToObject());
|
||||
if (window && window->window())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<> inline
|
||||
bool V8ValueCanBeConvertedTo<v8::Persistent<v8::Function>>(
|
||||
v8::Handle<v8::Value> value) {
|
||||
return value->IsFunction();
|
||||
}
|
||||
|
||||
// Check and convert V8's Arguments to native types.
|
||||
template<typename T1> inline
|
||||
bool FromV8Arguments(const v8::Arguments& args, T1* value, int index = 0) {
|
||||
if (!V8ValueCanBeConvertedTo<T1>(args[index]))
|
||||
return false;
|
||||
*value = static_cast<const T1&>(FromV8Value(args[index]));
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T1, typename T2> inline
|
||||
bool FromV8Arguments(const v8::Arguments& args, T1* a1, T2* a2) {
|
||||
return FromV8Arguments<T1>(args, a1) && FromV8Arguments<T2>(args, a2, 1);
|
||||
}
|
||||
|
||||
template<typename T1, typename T2, typename T3> inline
|
||||
bool FromV8Arguments(const v8::Arguments& args, T1* a1, T2* a2, T3* a3) {
|
||||
return FromV8Arguments<T1, T2>(args, a1, a2) &&
|
||||
FromV8Arguments<T3>(args, a3, 2);
|
||||
}
|
||||
|
||||
template<typename T1, typename T2, typename T3, typename T4> inline
|
||||
bool FromV8Arguments(const v8::Arguments& args,
|
||||
T1* a1,
|
||||
T2* a2,
|
||||
T3* a3,
|
||||
T4* a4) {
|
||||
return FromV8Arguments<T1, T2, T3>(args, a1, a2, a3) &&
|
||||
FromV8Arguments<T4>(args, a4, 3);
|
||||
}
|
||||
|
||||
template<typename T1, typename T2, typename T3, typename T4, typename T5> inline
|
||||
bool FromV8Arguments(const v8::Arguments& args,
|
||||
T1* a1,
|
||||
T2* a2,
|
||||
T3* a3,
|
||||
T4* a4,
|
||||
T5* a5) {
|
||||
return FromV8Arguments<T1, T2, T3, T4>(args, a1, a2, a3, a4) &&
|
||||
FromV8Arguments<T5>(args, a5, 4);
|
||||
}
|
||||
|
||||
template<typename T1, typename T2, typename T3, typename T4, typename T5,
|
||||
typename T6> inline
|
||||
bool FromV8Arguments(const v8::Arguments& args,
|
||||
T1* a1,
|
||||
T2* a2,
|
||||
T3* a3,
|
||||
T4* a4,
|
||||
T5* a5,
|
||||
T6* a6) {
|
||||
return FromV8Arguments<T1, T2, T3, T4, T5>(args, a1, a2, a3, a4, a5) &&
|
||||
FromV8Arguments<T6>(args, a6, 5);
|
||||
}
|
||||
|
||||
template<typename T1, typename T2, typename T3, typename T4, typename T5,
|
||||
typename T6, typename T7> inline
|
||||
bool FromV8Arguments(const v8::Arguments& args,
|
||||
T1* a1,
|
||||
T2* a2,
|
||||
T3* a3,
|
||||
T4* a4,
|
||||
T5* a5,
|
||||
T6* a6,
|
||||
T7* a7) {
|
||||
return
|
||||
FromV8Arguments<T1, T2, T3, T4, T5, T6>(args, a1, a2, a3, a4, a5, a6) &&
|
||||
FromV8Arguments<T7>(args, a7, 6);
|
||||
}
|
||||
|
||||
#endif // COMMON_V8_CONVERSIONS_H_
|
||||
@@ -7,33 +7,33 @@
|
||||
|
||||
## Development
|
||||
|
||||
* [Coding style](coding-style.md)
|
||||
* [Source code directory structure](source-code-directory-structure.md)
|
||||
* [Build instructions (Mac)](build-instructions-mac.md)
|
||||
* [Build instructions (Windows)](build-instructions-windows.md)
|
||||
* [Coding style](development/coding-style.md)
|
||||
* [Source code directory structure](development/source-code-directory-structure.md)
|
||||
* [Build instructions (Mac)](development/build-instructions-mac.md)
|
||||
* [Build instructions (Windows)](development/build-instructions-windows.md)
|
||||
|
||||
## API References
|
||||
|
||||
Renderer side modules:
|
||||
|
||||
* [ipc (renderer)](ipc-renderer.md)
|
||||
* [remote](remote.md)
|
||||
* [ipc (renderer)](api/renderer/ipc-renderer.md)
|
||||
* [remote](api/renderer/remote.md)
|
||||
|
||||
Browser side modules:
|
||||
|
||||
* [app](app.md)
|
||||
* [atom-delegate](atom-delegate.md)
|
||||
* [auto-updater](auto-updater.md)
|
||||
* [browser-window](browser-window.md)
|
||||
* [crash-reporter](crash-reporter.md)
|
||||
* [dialog](dialog.md)
|
||||
* [ipc (browser)](ipc-browser.md)
|
||||
* [menu](menu.md)
|
||||
* [menu-item](menu-item.md)
|
||||
* [power-monitor](power-monitor.md)
|
||||
* [protocol](protocol.md)
|
||||
* [app](api/browser/app.md)
|
||||
* [atom-delegate](api/browser/atom-delegate.md)
|
||||
* [auto-updater](api/browser/auto-updater.md)
|
||||
* [browser-window](api/browser/browser-window.md)
|
||||
* [dialog](api/browser/dialog.md)
|
||||
* [ipc (browser)](api/browser/ipc-browser.md)
|
||||
* [menu](api/browser/menu.md)
|
||||
* [menu-item](api/browser/menu-item.md)
|
||||
* [power-monitor](api/browser/power-monitor.md)
|
||||
* [protocol](api/browser/protocol.md)
|
||||
|
||||
Common modules:
|
||||
|
||||
* [clipboard](clipboard.md)
|
||||
* [shell](shell.md)
|
||||
* [clipboard](api/common/clipboard.md)
|
||||
* [crash-reporter](api/common/crash-reporter.md)
|
||||
* [shell](api/common/shell.md)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## Synopsis
|
||||
# app
|
||||
|
||||
The `app` module is responsible for controlling the application's life time.
|
||||
|
||||
@@ -79,12 +79,16 @@ code will not run.
|
||||
|
||||
Returns the version of current bundle or executable.
|
||||
|
||||
## app.getBrowserWindows()
|
||||
|
||||
Returns an array of all browser windows.
|
||||
|
||||
## app.commandLine.appendSwitch(switch, [value])
|
||||
|
||||
Append a switch [with optional value] to Chromium's command line.
|
||||
|
||||
**Note:** This will not affect `process.argv`, and is mainly used by
|
||||
**developers to control some low-level Chromium behaviors.
|
||||
**Note:** This will not affect `process.argv`, and is mainly used by developers
|
||||
to control some low-level Chromium behaviors.
|
||||
|
||||
## app.commandLine.appendArgument(value)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## Synopsis
|
||||
# atom-delegate
|
||||
|
||||
The `atom-delegate` returns the delegate object for Chrome Content API. The
|
||||
atom-shell would call methods of the delegate object when the corresponding
|
||||
@@ -1,4 +1,4 @@
|
||||
## Synopsis
|
||||
# auto-updater
|
||||
|
||||
`auto-updater` module is a simple wrap around the Sparkle framework, it
|
||||
provides auto update service for the application.
|
||||
@@ -1,4 +1,4 @@
|
||||
## Synopsis
|
||||
# browser-window
|
||||
|
||||
The `BrowserWindow` class gives you ability to create a browser window, an
|
||||
example is:
|
||||
@@ -15,6 +15,10 @@ win.loadUrl('https://github.com');
|
||||
win.show();
|
||||
```
|
||||
|
||||
You can also create a window without chrome by using
|
||||
[Frameless Window](frameless-window.md) API.
|
||||
|
||||
|
||||
**Note:** Be careful not to use `window` as the variable name.
|
||||
|
||||
## Class: BrowserWindow
|
||||
@@ -38,6 +42,8 @@ win.show();
|
||||
* `kiosk` Boolean - The kiosk mode
|
||||
* `title` String - Default window title
|
||||
* `show` Boolean - Whether window should be shown when created
|
||||
* `frame` Boolean - Specify `false` to create a
|
||||
[Frameless Window](frameless-window.md)
|
||||
|
||||
Creates a new `BrowserWindow` with native properties set by the `options`.
|
||||
Usually you only need to set the `width` and `height`, other properties will
|
||||
@@ -135,6 +141,10 @@ Shows the window.
|
||||
|
||||
Hides the window.
|
||||
|
||||
### BrowserWindow.isVisible()
|
||||
|
||||
Returns whether the window is visible to the user.
|
||||
|
||||
### BrowserWindow.maximize()
|
||||
|
||||
Maximizes the window.
|
||||
@@ -280,6 +290,23 @@ Starts inspecting element at position (`x`, `y`).
|
||||
|
||||
### BrowserWindow.restartHangMonitorTimeout()
|
||||
|
||||
### BrowserWindow.capturePage([rect, ]callback)
|
||||
|
||||
* `rect` Object - The area of page to be captured
|
||||
* `x`
|
||||
* `y`
|
||||
* `width`
|
||||
* `height`
|
||||
* `callback` Function
|
||||
|
||||
Captures the snapshot of page within `rect`, upon completion `callback` would be
|
||||
called with `callback(image)`, the `image` is a `Buffer` that stores the PNG
|
||||
encoded data of the snapshot. Omitting the `rect` would capture the whole
|
||||
visible page.
|
||||
|
||||
You can write received `image` directly to a `.png` file, or you can base64
|
||||
encode it and use data URL to embed the image in HTML.
|
||||
|
||||
### BrowserWindow.getPageTitle()
|
||||
|
||||
Returns the title of web page.
|
||||
@@ -1,4 +1,4 @@
|
||||
## Synopsis
|
||||
# dialog
|
||||
|
||||
The `dialog` module provides functions to show system dialogs, so web
|
||||
applications can get the same user experience with native applications.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user