mirror of
https://github.com/electron/electron.git
synced 2026-02-19 03:14:51 -05:00
Compare commits
320 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
e7bc368785 | ||
|
|
aad0c8e996 | ||
|
|
bf4756fdfb | ||
|
|
8acd6d6c8a | ||
|
|
256215b749 | ||
|
|
a3e5b21118 | ||
|
|
84a3eb5411 | ||
|
|
e17da272f4 | ||
|
|
88bdff5832 | ||
|
|
ae18a90f7e | ||
|
|
3b7dd85d3f | ||
|
|
128d9c78db | ||
|
|
c7fed48c4a | ||
|
|
7737708fdd | ||
|
|
9ba08d5e67 | ||
|
|
6c3dc9e526 | ||
|
|
75a24a2e67 | ||
|
|
893309aa8a | ||
|
|
f17864372e | ||
|
|
610ac5b045 | ||
|
|
cfb957a603 | ||
|
|
e423f601c0 | ||
|
|
504f96ae08 | ||
|
|
3b149945bf | ||
|
|
5fe9f281ac | ||
|
|
766347ffae | ||
|
|
a5bc2fdb44 | ||
|
|
e7d4b44d05 | ||
|
|
30c9cd4318 | ||
|
|
5787b4cd6f | ||
|
|
a26308d902 | ||
|
|
c2093946c8 | ||
|
|
0286379706 | ||
|
|
6765ec30f1 | ||
|
|
beba27ed1e | ||
|
|
24f510ca03 | ||
|
|
2cbe823773 | ||
|
|
790c53825b | ||
|
|
10bd2384d0 | ||
|
|
335db788a5 | ||
|
|
d8cd3d78ff | ||
|
|
2a462cc2b7 | ||
|
|
df30f130d3 | ||
|
|
24e613c827 | ||
|
|
7df256f8dc | ||
|
|
2000f88c84 | ||
|
|
db890feb51 | ||
|
|
738cbd4080 | ||
|
|
11221979e5 | ||
|
|
72c604f741 | ||
|
|
04910b8391 | ||
|
|
132eb09d96 | ||
|
|
38b37f2520 | ||
|
|
4bdd1b88ad | ||
|
|
abd3e86fb1 | ||
|
|
c2fd43c3e8 | ||
|
|
261f50701a | ||
|
|
bc4201f911 | ||
|
|
6915f020d9 | ||
|
|
f7de0e8d38 | ||
|
|
efd2bbbede | ||
|
|
b1f30c1eb6 | ||
|
|
34e1800716 | ||
|
|
e00d3d4b37 | ||
|
|
19aa2b7979 | ||
|
|
dbdf2d8d54 | ||
|
|
3be4a01963 | ||
|
|
d0ab7e2c1e | ||
|
|
566b8136c9 | ||
|
|
c8150e570b | ||
|
|
d2b4b761ba | ||
|
|
018a48770a | ||
|
|
799d9ada7d | ||
|
|
15ba32b489 | ||
|
|
0f6617ec26 | ||
|
|
9e16e41bb3 | ||
|
|
c86acc4cd7 | ||
|
|
d88676bf65 | ||
|
|
d56a7d75de | ||
|
|
244d7eaf17 | ||
|
|
1ed77371c0 | ||
|
|
912bac698c | ||
|
|
8464fb4f64 | ||
|
|
0b01e49cd3 | ||
|
|
8cd7ccdc0d | ||
|
|
214df5ef69 | ||
|
|
b7c9f8ba1c | ||
|
|
f63661256f | ||
|
|
33279b1a2f | ||
|
|
96c173217f | ||
|
|
b9cbfb8103 | ||
|
|
fd299cb3fe | ||
|
|
c87956ef4f | ||
|
|
833190e8fa | ||
|
|
7cc1589097 | ||
|
|
e8ecbec3a7 | ||
|
|
4914dd67b6 | ||
|
|
1e895bdf76 | ||
|
|
5b74dff8f1 | ||
|
|
5b862fdf60 | ||
|
|
b411657b76 | ||
|
|
d160da7752 | ||
|
|
0cd3f3cc40 | ||
|
|
9105914b9e | ||
|
|
dea52ae767 | ||
|
|
79d6e88d99 | ||
|
|
f63cf3f283 | ||
|
|
22c8b55cb9 | ||
|
|
7c85479e90 | ||
|
|
dde07f03ec | ||
|
|
738a929f8c | ||
|
|
6193a889ff | ||
|
|
ee10c469c8 | ||
|
|
cdbb16d8fe | ||
|
|
16d039ba47 | ||
|
|
beb62566e4 | ||
|
|
d0b4800282 | ||
|
|
91a9fe41c9 | ||
|
|
979ec05ed3 | ||
|
|
a949e9542d | ||
|
|
a33c068ed1 | ||
|
|
4a70077b10 | ||
|
|
437d8fdb24 | ||
|
|
fc3bad0d4f | ||
|
|
e648689981 | ||
|
|
c700d291e5 | ||
|
|
c858066709 | ||
|
|
44cd21f0fd | ||
|
|
41b57c673e | ||
|
|
6bc2a3a5e8 | ||
|
|
63b85bccab | ||
|
|
f908619630 | ||
|
|
22012d41d8 | ||
|
|
ee2c696577 | ||
|
|
2fd91e8c96 | ||
|
|
b39df5ea87 | ||
|
|
5189caa610 | ||
|
|
341f1be07f | ||
|
|
00d48b20bd | ||
|
|
0c31494ffa | ||
|
|
971b72c2b6 | ||
|
|
f267a7812f | ||
|
|
58bfa11f7d | ||
|
|
114d247efb | ||
|
|
d4a148ea52 | ||
|
|
c6f18f095e | ||
|
|
452c350798 | ||
|
|
f4425afb39 | ||
|
|
d2f1a03b51 | ||
|
|
97bf979b22 | ||
|
|
149e2a4680 | ||
|
|
543ed1de98 | ||
|
|
a27009f0a9 | ||
|
|
3da4736a2b | ||
|
|
3d9af77b37 | ||
|
|
f9750f9ea9 | ||
|
|
963b73a8aa | ||
|
|
dd05759c01 | ||
|
|
6684cdd72a | ||
|
|
47be87fe5f | ||
|
|
b0b6214416 | ||
|
|
317bd0debf | ||
|
|
574811fee0 | ||
|
|
216f5917bf | ||
|
|
c5d48607d9 | ||
|
|
beba4efc9f | ||
|
|
3b615d7fad | ||
|
|
b2872eaf60 | ||
|
|
286335c8f9 | ||
|
|
296feb1a50 | ||
|
|
f46d5eb651 | ||
|
|
c5e0ae6495 | ||
|
|
17a4842eaa | ||
|
|
ea1f81aa52 | ||
|
|
b1f88d680b | ||
|
|
6e90430df5 | ||
|
|
192216ea64 | ||
|
|
55034be104 | ||
|
|
79870494df | ||
|
|
394fb77ee0 | ||
|
|
d888f5cc31 | ||
|
|
51cf1db652 | ||
|
|
2c237e9d08 | ||
|
|
0acaff48b8 | ||
|
|
247f7a51eb | ||
|
|
52a3dc8c9d | ||
|
|
02de9c3b39 | ||
|
|
4acbbd1ad7 | ||
|
|
e995383401 | ||
|
|
402dc2f5d2 | ||
|
|
cd19666307 | ||
|
|
e1ac21aa7a |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,10 +1,7 @@
|
||||
.DS_Store
|
||||
atom-shell.zip
|
||||
version
|
||||
/build/
|
||||
/dist/
|
||||
/frameworks/
|
||||
/node/
|
||||
/out/
|
||||
/vendor/brightray/vendor/download/
|
||||
/vendor/python_26/
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -10,3 +10,6 @@
|
||||
[submodule "vendor/depot_tools"]
|
||||
path = vendor/depot_tools
|
||||
url = https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
[submodule "vendor/apm"]
|
||||
path = vendor/apm
|
||||
url = https://github.com/atom/apm.git
|
||||
|
||||
19
README.md
19
README.md
@@ -1,18 +1,19 @@
|
||||
# Atom Shell
|
||||
|
||||
Experimental native layer for the [Atom](https://github.com/github/atom).
|
||||
Native layer for the [Atom](https://github.com/github/atom).
|
||||
|
||||
## Development
|
||||
## Features
|
||||
|
||||
### One-time setup
|
||||
* Write desktop applications with web techniques
|
||||
* Support built-in and third-party modules of node.js
|
||||
* Support native node.js modules
|
||||
* Extended built-in modules for desktop programming
|
||||
* JavaScript on browser side
|
||||
* Easy API for cross-process communication
|
||||
|
||||
$ script/bootstrap
|
||||
## Usage & Development
|
||||
|
||||
### Building
|
||||
|
||||
$ script/build
|
||||
|
||||
This will build the app into the `build` directory.
|
||||
See the docs [here](https://github.com/atom/atom-shell/tree/master/docs).
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -2,27 +2,86 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "content/public/app/content_main.h"
|
||||
|
||||
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*, int) {
|
||||
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;
|
||||
if (env->GetVar("ATOM_SHELL_INTERNAL_RUN_AS_NODE", &node_indicator) &&
|
||||
node_indicator == "1") {
|
||||
// Convert argv to to UTF8
|
||||
char** argv = new char*[argc];
|
||||
for (int i = 0; i < argc; i++) {
|
||||
// Compute the size of the required buffer
|
||||
DWORD size = WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
wargv[i],
|
||||
-1,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
NULL);
|
||||
if (size == 0) {
|
||||
// This should never happen.
|
||||
fprintf(stderr, "Could not convert arguments to utf8.");
|
||||
exit(1);
|
||||
}
|
||||
// Do the actual conversion
|
||||
argv[i] = new char[size];
|
||||
DWORD result = WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
wargv[i],
|
||||
-1,
|
||||
argv[i],
|
||||
size,
|
||||
NULL,
|
||||
NULL);
|
||||
if (result == 0) {
|
||||
// This should never happen.
|
||||
fprintf(stderr, "Could not convert arguments to utf8.");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
// Now that conversion is done, we can finally start.
|
||||
return node::Start(argc, argv);
|
||||
}
|
||||
|
||||
sandbox::SandboxInterfaceInfo sandbox_info = {0};
|
||||
content::InitializeSandboxInfo(&sandbox_info);
|
||||
atom::AtomMainDelegate delegate;
|
||||
return content::ContentMain(instance, &sandbox_info, &delegate);
|
||||
}
|
||||
|
||||
#else
|
||||
#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)
|
||||
return node::Start(argc, const_cast<char**>(argv));
|
||||
|
||||
return AtomMain(argc, argv);
|
||||
}
|
||||
|
||||
#endif // OS_WIN
|
||||
#endif
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
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
|
||||
104
atom.gyp
104
atom.gyp
@@ -18,6 +18,8 @@
|
||||
'browser/api/lib/ipc.coffee',
|
||||
'browser/api/lib/menu.coffee',
|
||||
'browser/api/lib/menu-item.coffee',
|
||||
'browser/api/lib/power-monitor.coffee',
|
||||
'browser/api/lib/protocol.coffee',
|
||||
'browser/atom/atom.coffee',
|
||||
'browser/atom/objects-registry.coffee',
|
||||
'browser/atom/rpc-server.coffee',
|
||||
@@ -31,10 +33,7 @@
|
||||
'lib_sources': [
|
||||
'app/atom_main_delegate.cc',
|
||||
'app/atom_main_delegate.h',
|
||||
'browser/accelerator_util.cc',
|
||||
'browser/accelerator_util.h',
|
||||
'browser/accelerator_util_mac.mm',
|
||||
'browser/accelerator_util_win.cc',
|
||||
'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',
|
||||
@@ -55,6 +54,10 @@
|
||||
'browser/api/atom_api_menu_mac.mm',
|
||||
'browser/api/atom_api_menu_win.cc',
|
||||
'browser/api/atom_api_menu_win.h',
|
||||
'browser/api/atom_api_power_monitor.cc',
|
||||
'browser/api/atom_api_power_monitor.h',
|
||||
'browser/api/atom_api_protocol.cc',
|
||||
'browser/api/atom_api_protocol.h',
|
||||
'browser/api/atom_api_window.cc',
|
||||
'browser/api/atom_api_window.h',
|
||||
'browser/api/atom_browser_bindings.cc',
|
||||
@@ -76,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',
|
||||
@@ -88,16 +89,6 @@
|
||||
'browser/crash_reporter.h',
|
||||
'browser/crash_reporter_mac.mm',
|
||||
'browser/crash_reporter_win.cc',
|
||||
'browser/file_dialog.h',
|
||||
'browser/file_dialog_mac.mm',
|
||||
'browser/file_dialog_win.cc',
|
||||
'browser/media/media_capture_devices_dispatcher.cc',
|
||||
'browser/media/media_capture_devices_dispatcher.h',
|
||||
'browser/media/media_stream_devices_controller.cc',
|
||||
'browser/media/media_stream_devices_controller.h',
|
||||
'browser/message_box.h',
|
||||
'browser/message_box_mac.mm',
|
||||
'browser/message_box_win.cc',
|
||||
'browser/native_window.cc',
|
||||
'browser/native_window.h',
|
||||
'browser/native_window_mac.h',
|
||||
@@ -105,8 +96,34 @@
|
||||
'browser/native_window_win.cc',
|
||||
'browser/native_window_win.h',
|
||||
'browser/native_window_observer.h',
|
||||
'browser/nsalert_synchronous_sheet.h',
|
||||
'browser/nsalert_synchronous_sheet.mm',
|
||||
'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',
|
||||
'browser/net/url_request_string_job.h',
|
||||
'browser/ui/accelerator_util.cc',
|
||||
'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',
|
||||
'browser/ui/file_dialog_mac.mm',
|
||||
'browser/ui/file_dialog_win.cc',
|
||||
'browser/ui/message_box.h',
|
||||
'browser/ui/message_box_mac.mm',
|
||||
'browser/ui/message_box_win.cc',
|
||||
'browser/ui/nsalert_synchronous_sheet_mac.h',
|
||||
'browser/ui/nsalert_synchronous_sheet_mac.mm',
|
||||
'browser/ui/win/menu_2.cc',
|
||||
'browser/ui/win/menu_2.h',
|
||||
'browser/ui/win/native_menu_win.cc',
|
||||
'browser/ui/win/native_menu_win.h',
|
||||
'browser/window_list.cc',
|
||||
'browser/window_list.h',
|
||||
'browser/window_list_observer.h',
|
||||
@@ -114,7 +131,6 @@
|
||||
'common/api/api_messages.h',
|
||||
'common/api/atom_api_clipboard.cc',
|
||||
'common/api/atom_api_clipboard.h',
|
||||
'common/api/atom_api_idle_gc.cc',
|
||||
'common/api/atom_api_id_weak_map.cc',
|
||||
'common/api/atom_api_id_weak_map.h',
|
||||
'common/api/atom_api_shell.cc',
|
||||
@@ -126,6 +142,8 @@
|
||||
'common/api/atom_extensions.h',
|
||||
'common/api/object_life_monitor.cc',
|
||||
'common/api/object_life_monitor.h',
|
||||
'common/draggable_region.cc',
|
||||
'common/draggable_region.h',
|
||||
'common/node_bindings.cc',
|
||||
'common/node_bindings.h',
|
||||
'common/node_bindings_mac.cc',
|
||||
@@ -137,6 +155,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',
|
||||
@@ -239,13 +258,6 @@
|
||||
'browser/default_app',
|
||||
],
|
||||
},
|
||||
{
|
||||
# Copy node binary for worker process support.
|
||||
'destination': '<(PRODUCT_DIR)/<(product_name).app/Contents/Resources',
|
||||
'files': [
|
||||
'node/node',
|
||||
],
|
||||
},
|
||||
],
|
||||
'postbuilds': [
|
||||
{
|
||||
@@ -278,6 +290,7 @@
|
||||
'destination': '<(PRODUCT_DIR)',
|
||||
'files': [
|
||||
'<(libchromiumcontent_library_dir)/chromiumcontent.dll',
|
||||
'<(libchromiumcontent_library_dir)/ffmpegsumo.dll',
|
||||
'<(libchromiumcontent_library_dir)/icudt.dll',
|
||||
'<(libchromiumcontent_library_dir)/libGLESv2.dll',
|
||||
'<(libchromiumcontent_resources_dir)/content_shell.pak',
|
||||
@@ -289,12 +302,6 @@
|
||||
'browser/default_app',
|
||||
]
|
||||
},
|
||||
{
|
||||
'destination': '<(PRODUCT_DIR)/resources',
|
||||
'files': [
|
||||
'node/node.exe',
|
||||
]
|
||||
},
|
||||
],
|
||||
}], # OS=="win"
|
||||
],
|
||||
@@ -327,6 +334,7 @@
|
||||
'libraries': [
|
||||
'-limm32.lib',
|
||||
'-loleacc.lib',
|
||||
'-lComdlg32.lib',
|
||||
'<(atom_source_root)/<(libchromiumcontent_library_dir)/chromiumviews.lib',
|
||||
],
|
||||
},
|
||||
@@ -477,5 +485,37 @@
|
||||
}, # target helper
|
||||
],
|
||||
}], # OS==Mac
|
||||
['OS=="win"', {
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'generate_node_lib',
|
||||
'type': 'none',
|
||||
'dependencies': [
|
||||
'<(project_name)',
|
||||
],
|
||||
'actions': [
|
||||
{
|
||||
'action_name': 'Create node.lib',
|
||||
'inputs': [
|
||||
'<(PRODUCT_DIR)/atom.lib',
|
||||
'<(libchromiumcontent_library_dir)/chromiumcontent.dll.lib',
|
||||
],
|
||||
'outputs': [
|
||||
'<(PRODUCT_DIR)/node.lib',
|
||||
],
|
||||
'action': [
|
||||
'lib.exe',
|
||||
'/nologo',
|
||||
# We can't use <(_outputs) here because that escapes the
|
||||
# backslash in the path, which confuses lib.exe.
|
||||
'/OUT:<(PRODUCT_DIR)\\node.lib',
|
||||
'<@(_inputs)',
|
||||
],
|
||||
'msvs_cygwin_shell': 0,
|
||||
},
|
||||
],
|
||||
}, # target generate_node_lib
|
||||
],
|
||||
}], # OS==win
|
||||
],
|
||||
}
|
||||
|
||||
@@ -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,15 +131,52 @@ 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();
|
||||
}
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> App::DockBounce(const v8::Arguments& args) {
|
||||
std::string type = FromV8Value(args[0]);
|
||||
int request_id = -1;
|
||||
|
||||
if (type == "critical")
|
||||
request_id = Browser::Get()->DockBounce(Browser::BOUNCE_CRITICAL);
|
||||
else if (type == "informational")
|
||||
request_id = Browser::Get()->DockBounce(Browser::BOUNCE_INFORMATIONAL);
|
||||
else
|
||||
return node::ThrowTypeError("Invalid bounce type");
|
||||
|
||||
return v8::Integer::New(request_id);
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> App::DockCancelBounce(const v8::Arguments& args) {
|
||||
Browser::Get()->DockCancelBounce(FromV8Value(args[0]));
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> App::DockSetBadgeText(const v8::Arguments& args) {
|
||||
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 ToV8Value(text);
|
||||
}
|
||||
|
||||
#endif // defined(OS_MACOSX)
|
||||
|
||||
// static
|
||||
void App::Initialize(v8::Handle<v8::Object> target) {
|
||||
v8::HandleScope scope;
|
||||
@@ -157,6 +195,13 @@ void App::Initialize(v8::Handle<v8::Object> target) {
|
||||
|
||||
NODE_SET_METHOD(target, "appendSwitch", AppendSwitch);
|
||||
NODE_SET_METHOD(target, "appendArgument", AppendArgument);
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
NODE_SET_METHOD(target, "dockBounce", DockBounce);
|
||||
NODE_SET_METHOD(target, "dockCancelBounce", DockCancelBounce);
|
||||
NODE_SET_METHOD(target, "dockSetBadgeText", DockSetBadgeText);
|
||||
NODE_SET_METHOD(target, "dockGetBadgeText", DockGetBadgeText);
|
||||
#endif // defined(OS_MACOSX)
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
@@ -43,6 +43,13 @@ class App : public EventEmitter,
|
||||
static v8::Handle<v8::Value> AppendSwitch(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> AppendArgument(const v8::Arguments &args);
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
static v8::Handle<v8::Value> DockBounce(const v8::Arguments& args);
|
||||
static v8::Handle<v8::Value> DockCancelBounce(const v8::Arguments& args);
|
||||
static v8::Handle<v8::Value> DockSetBadgeText(const v8::Arguments& args);
|
||||
static v8::Handle<v8::Value> DockGetBadgeText(const v8::Arguments& args);
|
||||
#endif // defined(OS_MACOSX)
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(App);
|
||||
};
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "browser/api/atom_api_crash_reporter.h"
|
||||
|
||||
#include "browser/crash_reporter.h"
|
||||
#include "common/v8_conversions.h"
|
||||
#include "vendor/node/src/node.h"
|
||||
#include "vendor/node/src/node_internals.h"
|
||||
|
||||
@@ -14,22 +15,20 @@ 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);
|
||||
crash_reporter::CrashReporter::SetCompanyName(FromV8Value(args[0]));
|
||||
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);
|
||||
crash_reporter::CrashReporter::SetSubmissionURL(FromV8Value(args[0]));
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> CrashReporter::SetAutoSubmit(const v8::Arguments &args) {
|
||||
crash_reporter::CrashReporter::SetAutoSubmit(args[0]->BooleanValue());
|
||||
crash_reporter::CrashReporter::SetAutoSubmit(FromV8Value(args[0]));
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
|
||||
@@ -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 "browser/file_dialog.h"
|
||||
#include "browser/message_box.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/accelerator_util.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();
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include "browser/api/atom_api_menu.h"
|
||||
|
||||
#import "chrome/browser/ui/cocoa/menu_controller.h"
|
||||
#import "browser/ui/atom_menu_controller_mac.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
@@ -21,16 +21,11 @@ class MenuMac : public Menu {
|
||||
protected:
|
||||
virtual void Popup(NativeWindow* window) OVERRIDE;
|
||||
|
||||
scoped_nsobject<MenuController> menu_controller_;
|
||||
scoped_nsobject<AtomMenuController> menu_controller_;
|
||||
|
||||
private:
|
||||
friend class Menu;
|
||||
|
||||
// The MenuController doesn't set title for menus, however it's required by
|
||||
// application menu to show submenus correctly, fix it by iterating all
|
||||
// submenus and set their titles.
|
||||
static void FixMenuTitles(NSMenu* menu);
|
||||
|
||||
// Fake sending an action from the application menu.
|
||||
static void SendActionToFirstResponder(const std::string& action);
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -23,9 +24,8 @@ MenuMac::~MenuMac() {
|
||||
}
|
||||
|
||||
void MenuMac::Popup(NativeWindow* native_window) {
|
||||
scoped_nsobject<MenuController> menu_controller(
|
||||
[[MenuController alloc] initWithModel:model_.get()
|
||||
useWithPopUpButtonCell:NO]);
|
||||
scoped_nsobject<AtomMenuController> menu_controller(
|
||||
[[AtomMenuController alloc] initWithModel:model_.get()]);
|
||||
|
||||
NSWindow* window = native_window->GetNativeWindow();
|
||||
content::WebContents* web_contents = native_window->GetWebContents();
|
||||
@@ -62,22 +62,6 @@ void MenuMac::Popup(NativeWindow* native_window) {
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void MenuMac::FixMenuTitles(NSMenu* menu) {
|
||||
int size = [menu numberOfItems];
|
||||
for (int i = 0; i < size; ++i) {
|
||||
NSMenuItem* item = [menu itemAtIndex:i];
|
||||
if ([item hasSubmenu]) {
|
||||
NSString* title = [item title];
|
||||
NSMenu* submenu = [item submenu];
|
||||
[submenu setTitle:title];
|
||||
|
||||
if ([title isEqualToString:@"Window"] && [submenu numberOfItems] > 0)
|
||||
[NSApp setWindowsMenu:submenu];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void MenuMac::SendActionToFirstResponder(const std::string& action) {
|
||||
SEL selector = NSSelectorFromString(base::SysUTF8ToNSString(action));
|
||||
@@ -97,10 +81,8 @@ v8::Handle<v8::Value> Menu::SetApplicationMenu(const v8::Arguments &args) {
|
||||
if (!menu)
|
||||
return node::ThrowError("Menu is destroyed");
|
||||
|
||||
scoped_nsobject<MenuController> menu_controller(
|
||||
[[MenuController alloc] initWithModel:menu->model_.get()
|
||||
useWithPopUpButtonCell:NO]);
|
||||
MenuMac::FixMenuTitles([menu_controller menu]);
|
||||
scoped_nsobject<AtomMenuController> menu_controller(
|
||||
[[AtomMenuController alloc] initWithModel:menu->model_.get()]);
|
||||
[NSApp setMainMenu:[menu_controller menu]];
|
||||
|
||||
// Ensure the menu_controller_ is destroyed after main menu is set.
|
||||
@@ -114,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,6 +4,9 @@
|
||||
|
||||
#include "browser/api/atom_api_menu_win.h"
|
||||
|
||||
#include "browser/ui/win/menu_2.h"
|
||||
#include "ui/gfx/point.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
@@ -16,6 +19,8 @@ MenuWin::~MenuWin() {
|
||||
}
|
||||
|
||||
void MenuWin::Popup(NativeWindow* native_window) {
|
||||
menu_.reset(new atom::Menu2(model_.get()));
|
||||
menu_->RunContextMenuAt(gfx::Point(0, 0));
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
namespace atom {
|
||||
|
||||
class Menu2;
|
||||
|
||||
namespace api {
|
||||
|
||||
class MenuWin : public Menu {
|
||||
@@ -20,6 +22,8 @@ class MenuWin : public Menu {
|
||||
virtual void Popup(NativeWindow* window) OVERRIDE;
|
||||
|
||||
private:
|
||||
scoped_ptr<atom::Menu2> menu_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MenuWin);
|
||||
};
|
||||
|
||||
|
||||
66
browser/api/atom_api_power_monitor.cc
Normal file
66
browser/api/atom_api_power_monitor.cc
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 "browser/api/atom_api_power_monitor.h"
|
||||
|
||||
#include "base/power_monitor/power_monitor.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
PowerMonitor::PowerMonitor(v8::Handle<v8::Object> wrapper)
|
||||
: EventEmitter(wrapper) {
|
||||
base::PowerMonitor::Get()->AddObserver(this);
|
||||
}
|
||||
|
||||
PowerMonitor::~PowerMonitor() {
|
||||
base::PowerMonitor::Get()->RemoveObserver(this);
|
||||
}
|
||||
|
||||
void PowerMonitor::OnPowerStateChange(bool on_battery_power) {
|
||||
if (on_battery_power)
|
||||
Emit("on-battery");
|
||||
else
|
||||
Emit("on-ac");
|
||||
}
|
||||
|
||||
void PowerMonitor::OnSuspend() {
|
||||
Emit("suspend");
|
||||
}
|
||||
|
||||
void PowerMonitor::OnResume() {
|
||||
Emit("resume");
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> PowerMonitor::New(const v8::Arguments& args) {
|
||||
v8::HandleScope scope;
|
||||
|
||||
if (!args.IsConstructCall())
|
||||
return node::ThrowError("Require constructor call");
|
||||
|
||||
new PowerMonitor(args.This());
|
||||
|
||||
return args.This();
|
||||
}
|
||||
|
||||
// static
|
||||
void PowerMonitor::Initialize(v8::Handle<v8::Object> target) {
|
||||
v8::HandleScope scope;
|
||||
|
||||
v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(
|
||||
PowerMonitor::New);
|
||||
t->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
t->SetClassName(v8::String::NewSymbol("PowerMonitor"));
|
||||
|
||||
target->Set(v8::String::NewSymbol("PowerMonitor"), t->GetFunction());
|
||||
}
|
||||
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
||||
|
||||
NODE_MODULE(atom_browser_power_monitor, atom::api::PowerMonitor::Initialize)
|
||||
41
browser/api/atom_api_power_monitor.h
Normal file
41
browser/api/atom_api_power_monitor.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_BROWSER_API_ATOM_API_POWER_MONITOR_H_
|
||||
#define ATOM_BROWSER_API_ATOM_API_POWER_MONITOR_H_
|
||||
|
||||
#include "browser/api/atom_api_event_emitter.h"
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/power_monitor/power_observer.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
class PowerMonitor : public EventEmitter,
|
||||
public base::PowerObserver {
|
||||
public:
|
||||
virtual ~PowerMonitor();
|
||||
|
||||
static void Initialize(v8::Handle<v8::Object> target);
|
||||
|
||||
protected:
|
||||
explicit PowerMonitor(v8::Handle<v8::Object> wrapper);
|
||||
|
||||
virtual void OnPowerStateChange(bool on_battery_power) OVERRIDE;
|
||||
virtual void OnSuspend() OVERRIDE;
|
||||
virtual void OnResume() OVERRIDE;
|
||||
|
||||
private:
|
||||
static v8::Handle<v8::Value> New(const v8::Arguments &args);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(PowerMonitor);
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_API_ATOM_API_POWER_MONITOR_H_
|
||||
378
browser/api/atom_api_protocol.cc
Normal file
378
browser/api/atom_api_protocol.cc
Normal file
@@ -0,0 +1,378 @@
|
||||
// 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_protocol.h"
|
||||
|
||||
#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 "vendor/node/src/node.h"
|
||||
#include "vendor/node/src/node_internals.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
typedef net::URLRequestJobFactory::ProtocolHandler ProtocolHandler;
|
||||
|
||||
namespace {
|
||||
|
||||
// The protocol module object.
|
||||
v8::Persistent<v8::Object> g_protocol_object;
|
||||
|
||||
// Registered protocol handlers.
|
||||
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::Handle<v8::Value> argv[] = {
|
||||
ToV8Value(event),
|
||||
ToV8Value(parameter),
|
||||
};
|
||||
node::MakeCallback(g_protocol_object, "emit", arraysize(argv), argv);
|
||||
}
|
||||
|
||||
// Convert the URLRequest object to V8 object.
|
||||
v8::Handle<v8::Object> ConvertURLRequestToV8Object(
|
||||
const net::URLRequest* request) {
|
||||
v8::Local<v8::Object> obj = v8::Object::New();
|
||||
obj->Set(v8::String::New("method"),
|
||||
v8::String::New(request->method().c_str()));
|
||||
obj->Set(v8::String::New("url"),
|
||||
v8::String::New(request->url().spec().c_str()));
|
||||
obj->Set(v8::String::New("referrer"),
|
||||
v8::String::New(request->referrer().c_str()));
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Get the job factory.
|
||||
AtomURLRequestJobFactory* GetRequestJobFactory() {
|
||||
return AtomBrowserContext::Get()->url_request_context_getter()->job_factory();
|
||||
}
|
||||
|
||||
class CustomProtocolRequestJob : public AdapterRequestJob {
|
||||
public:
|
||||
CustomProtocolRequestJob(ProtocolHandler* protocol_handler,
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate)
|
||||
: AdapterRequestJob(protocol_handler, request, network_delegate) {
|
||||
}
|
||||
|
||||
// AdapterRequestJob:
|
||||
virtual void GetJobTypeInUI() OVERRIDE {
|
||||
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
||||
|
||||
// Call the JS handler.
|
||||
v8::HandleScope scope;
|
||||
v8::Handle<v8::Value> argv[] = {
|
||||
ConvertURLRequestToV8Object(request()),
|
||||
};
|
||||
v8::Handle<v8::Value> result = g_handlers[request()->url().scheme()]->Call(
|
||||
v8::Context::GetCurrent()->Global(), arraysize(argv), argv);
|
||||
|
||||
// Determine the type of the job we are going to create.
|
||||
if (result->IsString()) {
|
||||
std::string data = FromV8Value(result);
|
||||
content::BrowserThread::PostTask(
|
||||
content::BrowserThread::IO,
|
||||
FROM_HERE,
|
||||
base::Bind(&AdapterRequestJob::CreateStringJobAndStart,
|
||||
GetWeakPtr(),
|
||||
"text/plain",
|
||||
"UTF-8",
|
||||
data));
|
||||
return;
|
||||
} else if (result->IsObject()) {
|
||||
v8::Handle<v8::Object> obj = result->ToObject();
|
||||
std::string name = FromV8Value(obj->GetConstructorName());
|
||||
if (name == "RequestStringJob") {
|
||||
std::string mime_type = FromV8Value(obj->Get(
|
||||
v8::String::New("mimeType")));
|
||||
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,
|
||||
FROM_HERE,
|
||||
base::Bind(&AdapterRequestJob::CreateStringJobAndStart,
|
||||
GetWeakPtr(),
|
||||
mime_type,
|
||||
charset,
|
||||
data));
|
||||
return;
|
||||
} else if (name == "RequestFileJob") {
|
||||
base::FilePath path = FromV8Value(obj->Get(v8::String::New("path")));
|
||||
|
||||
content::BrowserThread::PostTask(
|
||||
content::BrowserThread::IO,
|
||||
FROM_HERE,
|
||||
base::Bind(&AdapterRequestJob::CreateFileJobAndStart,
|
||||
GetWeakPtr(),
|
||||
path));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Try the default protocol handler if we have.
|
||||
if (default_protocol_handler()) {
|
||||
content::BrowserThread::PostTask(
|
||||
content::BrowserThread::IO,
|
||||
FROM_HERE,
|
||||
base::Bind(&AdapterRequestJob::CreateJobFromProtocolHandlerAndStart,
|
||||
GetWeakPtr()));
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback to the not implemented error.
|
||||
content::BrowserThread::PostTask(
|
||||
content::BrowserThread::IO,
|
||||
FROM_HERE,
|
||||
base::Bind(&AdapterRequestJob::CreateErrorJobAndStart,
|
||||
GetWeakPtr(),
|
||||
net::ERR_NOT_IMPLEMENTED));
|
||||
}
|
||||
};
|
||||
|
||||
// Always return the same CustomProtocolRequestJob for all requests, because
|
||||
// the content API needs the ProtocolHandler to return a job immediately, and
|
||||
// getting the real job from the JS requires asynchronous calls, so we have
|
||||
// to create an adapter job first.
|
||||
// Users can also pass an extra ProtocolHandler as the fallback one when
|
||||
// registered handler doesn't want to deal with the request.
|
||||
class CustomProtocolHandler : public ProtocolHandler {
|
||||
public:
|
||||
explicit CustomProtocolHandler(ProtocolHandler* protocol_handler = NULL)
|
||||
: protocol_handler_(protocol_handler) {
|
||||
}
|
||||
|
||||
virtual net::URLRequestJob* MaybeCreateJob(
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate) const OVERRIDE {
|
||||
return new CustomProtocolRequestJob(protocol_handler_.get(),
|
||||
request,
|
||||
network_delegate);
|
||||
}
|
||||
|
||||
ProtocolHandler* ReleaseDefaultProtocolHandler() {
|
||||
return protocol_handler_.release();
|
||||
}
|
||||
|
||||
ProtocolHandler* original_handler() { return protocol_handler_.get(); }
|
||||
|
||||
private:
|
||||
scoped_ptr<ProtocolHandler> protocol_handler_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CustomProtocolHandler);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Protocol::RegisterProtocol(const v8::Arguments& args) {
|
||||
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.
|
||||
g_handlers[scheme] = callback;
|
||||
|
||||
content::BrowserThread::PostTask(content::BrowserThread::IO,
|
||||
FROM_HERE,
|
||||
base::Bind(&RegisterProtocolInIO, scheme));
|
||||
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Protocol::UnregisterProtocol(const v8::Arguments& args) {
|
||||
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));
|
||||
if (it == g_handlers.end())
|
||||
return node::ThrowError("The scheme has not been registered");
|
||||
g_handlers.erase(it);
|
||||
|
||||
content::BrowserThread::PostTask(content::BrowserThread::IO,
|
||||
FROM_HERE,
|
||||
base::Bind(&UnregisterProtocolInIO, scheme));
|
||||
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Protocol::IsHandledProtocol(const v8::Arguments& args) {
|
||||
return ToV8Value(net::URLRequest::IsHandledProtocol(FromV8Value(args[0])));
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Protocol::InterceptProtocol(const v8::Arguments& args) {
|
||||
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.
|
||||
g_handlers[scheme] = callback;
|
||||
|
||||
content::BrowserThread::PostTask(content::BrowserThread::IO,
|
||||
FROM_HERE,
|
||||
base::Bind(&InterceptProtocolInIO, scheme));
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Protocol::UninterceptProtocol(const v8::Arguments& args) {
|
||||
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));
|
||||
if (it == g_handlers.end())
|
||||
return node::ThrowError("The scheme has not been registered");
|
||||
g_handlers.erase(it);
|
||||
|
||||
content::BrowserThread::PostTask(content::BrowserThread::IO,
|
||||
FROM_HERE,
|
||||
base::Bind(&UninterceptProtocolInIO,
|
||||
scheme));
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
// static
|
||||
void Protocol::RegisterProtocolInIO(const std::string& scheme) {
|
||||
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
||||
AtomURLRequestJobFactory* job_factory(GetRequestJobFactory());
|
||||
job_factory->SetProtocolHandler(scheme, new CustomProtocolHandler);
|
||||
|
||||
content::BrowserThread::PostTask(content::BrowserThread::UI,
|
||||
FROM_HERE,
|
||||
base::Bind(&EmitEventInUI,
|
||||
"registered",
|
||||
scheme));
|
||||
}
|
||||
|
||||
// static
|
||||
void Protocol::UnregisterProtocolInIO(const std::string& scheme) {
|
||||
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
||||
AtomURLRequestJobFactory* job_factory(GetRequestJobFactory());
|
||||
job_factory->SetProtocolHandler(scheme, NULL);
|
||||
|
||||
content::BrowserThread::PostTask(content::BrowserThread::UI,
|
||||
FROM_HERE,
|
||||
base::Bind(&EmitEventInUI,
|
||||
"unregistered",
|
||||
scheme));
|
||||
}
|
||||
|
||||
// static
|
||||
void Protocol::InterceptProtocolInIO(const std::string& scheme) {
|
||||
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
||||
AtomURLRequestJobFactory* job_factory(GetRequestJobFactory());
|
||||
ProtocolHandler* original_handler = job_factory->GetProtocolHandler(scheme);
|
||||
if (original_handler == NULL) {
|
||||
content::BrowserThread::PostTask(
|
||||
content::BrowserThread::UI,
|
||||
FROM_HERE,
|
||||
base::Bind(&EmitEventInUI,
|
||||
"error",
|
||||
"There is no protocol handler to intercpet"));
|
||||
return;
|
||||
}
|
||||
|
||||
job_factory->ReplaceProtocol(scheme,
|
||||
new CustomProtocolHandler(original_handler));
|
||||
|
||||
content::BrowserThread::PostTask(content::BrowserThread::UI,
|
||||
FROM_HERE,
|
||||
base::Bind(&EmitEventInUI,
|
||||
"intercepted",
|
||||
scheme));
|
||||
}
|
||||
|
||||
// static
|
||||
void Protocol::UninterceptProtocolInIO(const std::string& scheme) {
|
||||
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
||||
AtomURLRequestJobFactory* job_factory(GetRequestJobFactory());
|
||||
|
||||
// Check if the protocol handler is intercepted.
|
||||
CustomProtocolHandler* handler = static_cast<CustomProtocolHandler*>(
|
||||
job_factory->GetProtocolHandler(scheme));
|
||||
if (handler->original_handler() == NULL) {
|
||||
content::BrowserThread::PostTask(
|
||||
content::BrowserThread::UI,
|
||||
FROM_HERE,
|
||||
base::Bind(&EmitEventInUI,
|
||||
"error",
|
||||
"The protocol is not intercpeted"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset the protocol handler to the orignal one and delete current
|
||||
// protocol handler.
|
||||
ProtocolHandler* original_handler = handler->ReleaseDefaultProtocolHandler();
|
||||
delete job_factory->ReplaceProtocol(scheme, original_handler);
|
||||
|
||||
content::BrowserThread::PostTask(content::BrowserThread::UI,
|
||||
FROM_HERE,
|
||||
base::Bind(&EmitEventInUI,
|
||||
"unintercepted",
|
||||
scheme));
|
||||
}
|
||||
|
||||
// static
|
||||
void Protocol::Initialize(v8::Handle<v8::Object> target) {
|
||||
// Remember the protocol object, used for emitting event later.
|
||||
g_protocol_object = v8::Persistent<v8::Object>::New(
|
||||
node::node_isolate, target);
|
||||
|
||||
node::SetMethod(target, "registerProtocol", RegisterProtocol);
|
||||
node::SetMethod(target, "unregisterProtocol", UnregisterProtocol);
|
||||
node::SetMethod(target, "isHandledProtocol", IsHandledProtocol);
|
||||
node::SetMethod(target, "interceptProtocol", InterceptProtocol);
|
||||
node::SetMethod(target, "uninterceptProtocol", UninterceptProtocol);
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
||||
|
||||
NODE_MODULE(atom_browser_protocol, atom::api::Protocol::Initialize)
|
||||
43
browser/api/atom_api_protocol.h
Normal file
43
browser/api/atom_api_protocol.h
Normal file
@@ -0,0 +1,43 @@
|
||||
// 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_API_ATOM_API_PROTOCOL_H_
|
||||
#define ATOM_BROWSER_API_ATOM_API_PROTOCOL_H_
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "v8/include/v8.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
class Protocol {
|
||||
public:
|
||||
static void Initialize(v8::Handle<v8::Object> target);
|
||||
|
||||
private:
|
||||
static v8::Handle<v8::Value> RegisterProtocol(const v8::Arguments& args);
|
||||
static v8::Handle<v8::Value> UnregisterProtocol(const v8::Arguments& args);
|
||||
static v8::Handle<v8::Value> IsHandledProtocol(const v8::Arguments& args);
|
||||
|
||||
static v8::Handle<v8::Value> InterceptProtocol(const v8::Arguments& args);
|
||||
static v8::Handle<v8::Value> UninterceptProtocol(const v8::Arguments& args);
|
||||
|
||||
static void RegisterProtocolInIO(const std::string& scheme);
|
||||
static void UnregisterProtocolInIO(const std::string& scheme);
|
||||
|
||||
static void InterceptProtocolInIO(const std::string& scheme);
|
||||
static void UninterceptProtocolInIO(const std::string& scheme);
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(Protocol);
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_API_ATOM_API_PROTOCOL_H_
|
||||
@@ -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"
|
||||
@@ -27,15 +28,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)) {
|
||||
@@ -56,6 +48,12 @@ void Window::OnPageTitleUpdated(bool* prevent_default,
|
||||
*prevent_default = Emit("page-title-updated", &args);
|
||||
}
|
||||
|
||||
void Window::OnLoadingStateChanged(bool is_loading) {
|
||||
base::ListValue args;
|
||||
args.AppendBoolean(is_loading);
|
||||
Emit("loading-state-changed", &args);
|
||||
}
|
||||
|
||||
void Window::WillCloseWindow(bool* prevent_default) {
|
||||
*prevent_default = Emit("close");
|
||||
}
|
||||
@@ -63,8 +61,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() {
|
||||
@@ -135,7 +134,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
|
||||
@@ -196,10 +195,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();
|
||||
}
|
||||
|
||||
@@ -207,18 +207,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();
|
||||
}
|
||||
|
||||
@@ -228,8 +228,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;
|
||||
}
|
||||
@@ -238,11 +238,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();
|
||||
}
|
||||
|
||||
@@ -252,8 +252,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;
|
||||
}
|
||||
@@ -262,11 +262,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();
|
||||
}
|
||||
|
||||
@@ -276,8 +277,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;
|
||||
}
|
||||
@@ -286,10 +287,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();
|
||||
}
|
||||
|
||||
@@ -297,17 +299,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();
|
||||
}
|
||||
|
||||
@@ -315,7 +318,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
|
||||
@@ -331,11 +334,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();
|
||||
}
|
||||
|
||||
@@ -345,8 +348,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;
|
||||
}
|
||||
@@ -355,20 +358,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
|
||||
@@ -385,10 +386,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();
|
||||
}
|
||||
|
||||
@@ -396,7 +398,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
|
||||
@@ -421,9 +423,11 @@ v8::Handle<v8::Value> Window::CloseDevTools(const v8::Arguments &args) {
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -445,6 +449,12 @@ v8::Handle<v8::Value> Window::BlurWebView(const v8::Arguments &args) {
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::IsWebViewFocused(const v8::Arguments& args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
return ToV8Value(self->window_->IsWebViewFocused());
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::RestartHangMonitorTimeout(
|
||||
const v8::Arguments &args) {
|
||||
@@ -459,24 +469,21 @@ v8::Handle<v8::Value> Window::RestartHangMonitorTimeout(
|
||||
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
|
||||
@@ -492,14 +499,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());
|
||||
}
|
||||
|
||||
@@ -507,19 +514,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());
|
||||
@@ -537,7 +545,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
|
||||
@@ -547,7 +555,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
|
||||
@@ -557,21 +565,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
|
||||
@@ -600,12 +608,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();
|
||||
}
|
||||
@@ -614,12 +623,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();
|
||||
}
|
||||
@@ -690,6 +700,7 @@ void Window::Initialize(v8::Handle<v8::Object> target) {
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "inspectElement", InspectElement);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "focusOnWebView", FocusOnWebView);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "blurWebView", BlurWebView);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "isWebViewFocused", IsWebViewFocused);
|
||||
NODE_SET_PROTOTYPE_METHOD(t,
|
||||
"restartHangMonitorTimeout",
|
||||
RestartHangMonitorTimeout);
|
||||
|
||||
@@ -35,6 +35,7 @@ class Window : public EventEmitter,
|
||||
// Implementations of NativeWindowObserver.
|
||||
virtual void OnPageTitleUpdated(bool* prevent_default,
|
||||
const std::string& title) OVERRIDE;
|
||||
virtual void OnLoadingStateChanged(bool is_loading) OVERRIDE;
|
||||
virtual void WillCloseWindow(bool* prevent_default) OVERRIDE;
|
||||
virtual void OnWindowClosed() OVERRIDE;
|
||||
virtual void OnWindowBlur() OVERRIDE;
|
||||
@@ -81,6 +82,7 @@ class Window : public EventEmitter,
|
||||
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);
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -13,5 +13,12 @@ app.commandLine =
|
||||
appendSwitch: bindings.appendSwitch,
|
||||
appendArgument: bindings.appendArgument
|
||||
|
||||
if process.platform is 'darwin'
|
||||
app.dock =
|
||||
bounce: (type = 'informational') -> bindings.dockBounce type
|
||||
cancelBounce: bindings.dockCancelBounce
|
||||
setBadge: bindings.dockSetBadgeText
|
||||
getBadge: bindings.dockGetBadgeText
|
||||
|
||||
# Only one App object pemitted.
|
||||
module.exports = app
|
||||
|
||||
@@ -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...)
|
||||
|
||||
@@ -6,7 +6,7 @@ class MenuItem
|
||||
constructor: (options) ->
|
||||
Menu = require 'menu'
|
||||
|
||||
{click, selector, @type, @label, @sublabel, @accelerator, @enabled, @visible, @checked, @groupId, @submenu} = options
|
||||
{click, @selector, @type, @label, @sublabel, @accelerator, @enabled, @visible, @checked, @groupId, @submenu} = options
|
||||
|
||||
@type = 'submenu' if not @type? and @submenu?
|
||||
throw new Error('Invalid submenu') if @type is 'submenu' and @submenu?.constructor isnt Menu
|
||||
@@ -14,16 +14,20 @@ class MenuItem
|
||||
@type = @type ? 'normal'
|
||||
@label = @label ? ''
|
||||
@sublabel = @sublabel ? ''
|
||||
@accelerator = @accelerator ? null
|
||||
@enabled = @enabled ? true
|
||||
@visible = @visible ? true
|
||||
@checked = @checked ? false
|
||||
@groupId = @groupId ? null
|
||||
@submenu = @submenu ? null
|
||||
|
||||
throw new Error('Unknown menu type') if MenuItem.types.indexOf(@type) is -1
|
||||
|
||||
@commandId = ++nextCommandId
|
||||
@click = ->
|
||||
@click = =>
|
||||
if typeof click is 'function'
|
||||
click()
|
||||
else if typeof selector is 'string'
|
||||
Menu.sendActionToFirstResponder selector
|
||||
click.apply this, arguments
|
||||
else if typeof @selector is 'string'
|
||||
Menu.sendActionToFirstResponder @selector
|
||||
|
||||
module.exports = MenuItem
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
EventEmitter = require('events').EventEmitter
|
||||
BrowserWindow = require 'browser-window'
|
||||
EventEmitter = require('events').EventEmitter
|
||||
IDWeakMap = require 'id-weak-map'
|
||||
MenuItem = require 'menu-item'
|
||||
|
||||
bindings = process.atomBinding 'menu'
|
||||
@@ -28,15 +29,19 @@ Menu::insert = (pos, item) ->
|
||||
|
||||
@setSublabel pos, item.sublabel if item.sublabel?
|
||||
|
||||
unless @items?
|
||||
@items = {}
|
||||
unless @delegate?
|
||||
@commandsMap = {}
|
||||
@items = []
|
||||
@delegate =
|
||||
isCommandIdChecked: (commandId) => @items[commandId]?.checked
|
||||
isCommandIdEnabled: (commandId) => @items[commandId]?.enabled
|
||||
isCommandIdVisible: (commandId) => @items[commandId]?.visible
|
||||
getAcceleratorForCommandId: (commandId) => @items[commandId]?.accelerator
|
||||
executeCommand: (commandId) => @items[commandId]?.click()
|
||||
@items[item.commandId] = item
|
||||
isCommandIdChecked: (commandId) => @commandsMap[commandId]?.checked
|
||||
isCommandIdEnabled: (commandId) => @commandsMap[commandId]?.enabled
|
||||
isCommandIdVisible: (commandId) => @commandsMap[commandId]?.visible
|
||||
getAcceleratorForCommandId: (commandId) => @commandsMap[commandId]?.accelerator
|
||||
executeCommand: (commandId) =>
|
||||
activeItem = @commandsMap[commandId]
|
||||
activeItem.click(activeItem) if activeItem?
|
||||
@items.splice pos, 0, item
|
||||
@commandsMap[item.commandId] = item
|
||||
|
||||
Menu.setApplicationMenu = (menu) ->
|
||||
throw new TypeError('Invalid menu') unless menu?.constructor is Menu
|
||||
@@ -52,7 +57,10 @@ Menu.buildFromTemplate = (template) ->
|
||||
throw new TypeError('Invalid template for MenuItem') unless typeof item is 'object'
|
||||
|
||||
item.submenu = Menu.buildFromTemplate item.submenu if item.submenu?
|
||||
menu.append new MenuItem(item)
|
||||
menuItem = new MenuItem(item)
|
||||
menuItem[key] = value for key, value of item when not menuItem[key]?
|
||||
|
||||
menu.append menuItem
|
||||
|
||||
menu
|
||||
|
||||
|
||||
7
browser/api/lib/power-monitor.coffee
Normal file
7
browser/api/lib/power-monitor.coffee
Normal file
@@ -0,0 +1,7 @@
|
||||
bindings = process.atomBinding 'power_monitor'
|
||||
EventEmitter = require('events').EventEmitter
|
||||
|
||||
PowerMonitor = bindings.PowerMonitor
|
||||
PowerMonitor::__proto__ = EventEmitter.prototype
|
||||
|
||||
module.exports = new PowerMonitor
|
||||
20
browser/api/lib/protocol.coffee
Normal file
20
browser/api/lib/protocol.coffee
Normal file
@@ -0,0 +1,20 @@
|
||||
protocol = process.atomBinding 'protocol'
|
||||
EventEmitter = require('events').EventEmitter
|
||||
|
||||
protocol[key] = value for key, value of EventEmitter.prototype
|
||||
|
||||
protocol.RequestStringJob =
|
||||
class RequestStringJob
|
||||
constructor: ({mimeType, charset, data}) ->
|
||||
if typeof data isnt 'string' and not data instanceof Buffer
|
||||
throw new TypeError('Data should be string or Buffer')
|
||||
|
||||
@mimeType = mimeType ? 'text/plain'
|
||||
@charset = charset ? 'UTF-8'
|
||||
@data = String data
|
||||
|
||||
protocol.RequestFileJob =
|
||||
class RequestFileJob
|
||||
constructor: (@path) ->
|
||||
|
||||
module.exports = protocol
|
||||
@@ -1,14 +1,17 @@
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
|
||||
# Redirect node's console to use our own implementations, since node can not
|
||||
# handle output when running as GUI program.
|
||||
if process.platform is 'win32'
|
||||
# Redirect node's console to use our own implementations, since node can not
|
||||
# handle output when running as GUI program.
|
||||
console.log = console.error = console.warn = process.log
|
||||
process.stdout.write = process.stderr.write = process.log
|
||||
|
||||
# Enable idle gc.
|
||||
process.atomBinding('idle_gc').start()
|
||||
# Always returns EOF for stdin stream.
|
||||
Readable = require('stream').Readable
|
||||
stdin = new Readable
|
||||
stdin.push null
|
||||
process.__defineGetter__ 'stdin', -> stdin
|
||||
|
||||
# Provide default Content API implementations.
|
||||
atom = {}
|
||||
@@ -23,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'
|
||||
|
||||
@@ -35,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'
|
||||
|
||||
@@ -6,7 +6,7 @@ class ObjectsStore
|
||||
@stores = {}
|
||||
|
||||
constructor: ->
|
||||
@nextId = 1
|
||||
@nextId = 0
|
||||
@objects = []
|
||||
|
||||
getNextId: ->
|
||||
@@ -48,13 +48,7 @@ objectsWeakMap.add = (obj) ->
|
||||
windowsWeakMap = new IDWeakMap
|
||||
|
||||
process.on 'ATOM_BROWSER_INTERNAL_NEW', (obj) ->
|
||||
# It's possible that user created a object in browser side and then want to
|
||||
# get it in renderer via remote.getObject. So we must add every native object
|
||||
# created in browser to the weak map even it may not be referenced by the
|
||||
# renderer.
|
||||
objectsWeakMap.add obj
|
||||
|
||||
# Also remember all windows.
|
||||
# Remember all windows.
|
||||
if obj.constructor is BrowserWindow
|
||||
id = windowsWeakMap.add obj
|
||||
obj.on 'destroyed', ->
|
||||
|
||||
@@ -38,10 +38,19 @@ errorToMeta = (error) ->
|
||||
|
||||
# Convert array of meta data from renderer into array of real values.
|
||||
unwrapArgs = (processId, routingId, args) ->
|
||||
args.map (meta) ->
|
||||
metaToValue = (meta) ->
|
||||
switch meta.type
|
||||
when 'value' then meta.value
|
||||
when 'object' then objectsRegistry.get meta.id
|
||||
when 'remote-object' then objectsRegistry.get meta.id
|
||||
when 'array' then unwrapArgs processId, routingId, meta.value
|
||||
when 'object'
|
||||
ret = v8Util.createObjectWithName meta.name
|
||||
for member in meta.members
|
||||
ret[member.name] = metaToValue(member.value)
|
||||
ret
|
||||
when 'function-with-return-value'
|
||||
returnValue = metaToValue meta.value
|
||||
-> returnValue
|
||||
when 'function'
|
||||
ret = ->
|
||||
ipc.sendChannel processId, routingId, 'ATOM_RENDERER_CALLBACK', meta.id, valueToMeta(processId, routingId, arguments)
|
||||
@@ -50,28 +59,42 @@ unwrapArgs = (processId, routingId, args) ->
|
||||
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
|
||||
@@ -80,48 +103,50 @@ 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
|
||||
args = unwrapArgs processId, routingId, args
|
||||
constructor = objectsRegistry.get(id)[method]
|
||||
# Call new with array of arguments.
|
||||
obj = new (Function::bind.apply(constructor, [null].concat(args)))
|
||||
event.returnValue = valueToMeta processId, routingId, obj
|
||||
catch 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
|
||||
|
||||
ipc.on 'ATOM_BROWSER_REFERENCE', (event, processId, routingId, id) ->
|
||||
try
|
||||
obj = objectsRegistry.get id
|
||||
event.result = valueToMeta processId, routingId, obj
|
||||
catch e
|
||||
event.result = errorToMeta e
|
||||
event.returnValue = errorToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_DEREFERENCE', (processId, routingId, storeId) ->
|
||||
objectsRegistry.remove processId, routingId, storeId
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
|
||||
#include "browser/atom_browser_client.h"
|
||||
|
||||
#include "browser/atom_browser_context.h"
|
||||
#include "browser/atom_browser_main_parts.h"
|
||||
#include "browser/media/media_capture_devices_dispatcher.h"
|
||||
#include "browser/net/atom_url_request_context_getter.h"
|
||||
#include "webkit/glue/webpreferences.h"
|
||||
|
||||
namespace atom {
|
||||
@@ -16,6 +17,13 @@ AtomBrowserClient::AtomBrowserClient() {
|
||||
AtomBrowserClient::~AtomBrowserClient() {
|
||||
}
|
||||
|
||||
net::URLRequestContextGetter* AtomBrowserClient::CreateRequestContext(
|
||||
content::BrowserContext* browser_context,
|
||||
content::ProtocolHandlerMap* protocol_handlers) {
|
||||
return static_cast<AtomBrowserContext*>(browser_context)->
|
||||
CreateRequestContext(protocol_handlers);
|
||||
}
|
||||
|
||||
void AtomBrowserClient::OverrideWebkitPrefs(
|
||||
content::RenderViewHost* render_view_host,
|
||||
const GURL& url,
|
||||
@@ -38,10 +46,6 @@ void AtomBrowserClient::OverrideWebkitPrefs(
|
||||
prefs->allow_running_insecure_content = true;
|
||||
}
|
||||
|
||||
content::MediaObserver* AtomBrowserClient::GetMediaObserver() {
|
||||
return MediaCaptureDevicesDispatcher::GetInstance();
|
||||
}
|
||||
|
||||
bool AtomBrowserClient::ShouldSwapProcessesForNavigation(
|
||||
content::SiteInstance* site_instance,
|
||||
const GURL& current_url,
|
||||
|
||||
@@ -15,10 +15,12 @@ class AtomBrowserClient : public brightray::BrowserClient {
|
||||
virtual ~AtomBrowserClient();
|
||||
|
||||
protected:
|
||||
net::URLRequestContextGetter* CreateRequestContext(
|
||||
content::BrowserContext* browser_context,
|
||||
content::ProtocolHandlerMap* protocol_handlers) OVERRIDE;
|
||||
virtual void OverrideWebkitPrefs(content::RenderViewHost* render_view_host,
|
||||
const GURL& url,
|
||||
WebPreferences* prefs) OVERRIDE;
|
||||
virtual content::MediaObserver* GetMediaObserver() OVERRIDE;
|
||||
virtual bool ShouldSwapProcessesForNavigation(
|
||||
content::SiteInstance* site_instance,
|
||||
const GURL& current_url,
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -4,11 +4,13 @@
|
||||
|
||||
#include "browser/atom_browser_main_parts.h"
|
||||
|
||||
#include "base/power_monitor/power_monitor.h"
|
||||
#include "browser/api/atom_browser_bindings.h"
|
||||
#include "browser/atom_browser_client.h"
|
||||
#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"
|
||||
|
||||
@@ -41,6 +43,10 @@ brightray::BrowserContext* AtomBrowserMainParts::CreateBrowserContext() {
|
||||
void AtomBrowserMainParts::PostEarlyInitialization() {
|
||||
brightray::BrowserMainParts::PostEarlyInitialization();
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
base::PowerMonitor::AllocateSystemIOPorts();
|
||||
#endif
|
||||
|
||||
node_bindings_->Initialize();
|
||||
|
||||
// Wrap whole process in one global context.
|
||||
@@ -70,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();
|
||||
@@ -77,4 +88,13 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() {
|
||||
#endif
|
||||
}
|
||||
|
||||
int AtomBrowserMainParts::PreCreateThreads() {
|
||||
#if defined(OS_WIN)
|
||||
net::ProxyResolverV8::CreateIsolate();
|
||||
#else
|
||||
net::ProxyResolverV8::RememberDefaultIsolate();
|
||||
#endif
|
||||
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,12 @@ 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");
|
||||
NSBundle* frameworkBundle = [NSBundle
|
||||
bundleWithPath:base::mac::FilePathToNSString(frameworkPath)];
|
||||
NSNib* mainNib = [[NSNib alloc] initWithNibNamed:@"MainMenu"
|
||||
bundle:frameworkBundle];
|
||||
[mainNib instantiateWithOwner:application topLevelObjects:nil];
|
||||
[mainNib release];
|
||||
|
||||
|
||||
@@ -33,6 +33,20 @@ class Browser : public WindowListObserver {
|
||||
// Returns the version of the executable (or bundle).
|
||||
std::string GetVersion();
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
// Bounce the dock icon.
|
||||
enum BounceType {
|
||||
BOUNCE_CRITICAL = 0,
|
||||
BOUNCE_INFORMATIONAL = 10,
|
||||
};
|
||||
int DockBounce(BounceType type);
|
||||
void DockCancelBounce(int request_id);
|
||||
|
||||
// Set/Get dock's badge text.
|
||||
void DockSetBadgeText(const std::string& label);
|
||||
std::string DockGetBadgeText();
|
||||
#endif // defined(OS_MACOSX)
|
||||
|
||||
// Tell the application to open a file.
|
||||
bool OpenFile(const std::string& file_path);
|
||||
|
||||
|
||||
@@ -29,4 +29,22 @@ void Browser::CancelQuit() {
|
||||
[[AtomApplication sharedApplication] replyToApplicationShouldTerminate:NO];
|
||||
}
|
||||
|
||||
int Browser::DockBounce(BounceType type) {
|
||||
return [[AtomApplication sharedApplication] requestUserAttention:type];
|
||||
}
|
||||
|
||||
void Browser::DockCancelBounce(int rid) {
|
||||
[[AtomApplication sharedApplication] cancelUserAttentionRequest:rid];
|
||||
}
|
||||
|
||||
void Browser::DockSetBadgeText(const std::string& label) {
|
||||
NSDockTile *tile = [[AtomApplication sharedApplication] dockTile];
|
||||
[tile setBadgeLabel:base::SysUTF8ToNSString(label)];
|
||||
}
|
||||
|
||||
std::string Browser::DockGetBadgeText() {
|
||||
NSDockTile *tile = [[AtomApplication sharedApplication] dockTile];
|
||||
return base::SysNSStringToUTF8([tile badgeLabel]);
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -156,9 +156,12 @@ app.on('finish-launching', function() {
|
||||
];
|
||||
|
||||
menu = Menu.buildFromTemplate(template);
|
||||
Menu.setApplicationMenu(menu);
|
||||
|
||||
if (process.platform == 'darwin')
|
||||
Menu.setApplicationMenu(menu);
|
||||
|
||||
ipc.on('message', function(processId, routingId, type) {
|
||||
console.log(type);
|
||||
if (type == 'menu')
|
||||
menu.popup(mainWindow);
|
||||
});
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
This is the default mode of Atom Shell, please follow the instructions in
|
||||
wiki to get started.
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
|
||||
var ipc = require('ipc');
|
||||
|
||||
window.addEventListener('contextmenu', function (e) {
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
var app = require('app');
|
||||
var argv = require('optimist').argv;
|
||||
var dialog = require('dialog');
|
||||
var path = require('path');
|
||||
|
||||
// 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();
|
||||
});
|
||||
|
||||
// Start the specified app if there is one specified in command line, otherwise
|
||||
// start the default app.
|
||||
if (argv._.length > 0) {
|
||||
@@ -9,6 +16,7 @@ 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 {
|
||||
|
||||
@@ -1,38 +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 BROWSER_FILE_DIALOG_H_
|
||||
#define BROWSER_FILE_DIALOG_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
|
||||
namespace atom {
|
||||
class NativeWindow;
|
||||
}
|
||||
|
||||
namespace file_dialog {
|
||||
|
||||
enum FileDialogProperty {
|
||||
FILE_DIALOG_OPEN_FILE = 1,
|
||||
FILE_DIALOG_OPEN_DIRECTORY = 2,
|
||||
FILE_DIALOG_MULTI_SELECTIONS = 4,
|
||||
FILE_DIALOG_CREATE_DIRECTORY = 8,
|
||||
};
|
||||
|
||||
bool ShowOpenDialog(const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
int properties,
|
||||
std::vector<base::FilePath>* paths);
|
||||
|
||||
bool ShowSaveDialog(atom::NativeWindow* window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
base::FilePath* path);
|
||||
|
||||
} // namespace file_dialog
|
||||
|
||||
#endif // BROWSER_FILE_DIALOG_H_
|
||||
@@ -1,107 +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/file_dialog.h"
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#include <CoreServices/CoreServices.h>
|
||||
|
||||
#include "base/file_util.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "browser/native_window.h"
|
||||
|
||||
namespace file_dialog {
|
||||
|
||||
namespace {
|
||||
|
||||
void SetupDialog(NSSavePanel* dialog,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path) {
|
||||
if (!title.empty())
|
||||
[dialog setTitle:base::SysUTF8ToNSString(title)];
|
||||
|
||||
NSString* default_dir = nil;
|
||||
NSString* default_filename = nil;
|
||||
if (!default_path.empty()) {
|
||||
if (file_util::DirectoryExists(default_path)) {
|
||||
default_dir = base::SysUTF8ToNSString(default_path.value());
|
||||
} else {
|
||||
default_dir = base::SysUTF8ToNSString(default_path.DirName().value());
|
||||
default_filename =
|
||||
base::SysUTF8ToNSString(default_path.BaseName().value());
|
||||
}
|
||||
}
|
||||
|
||||
if (default_dir)
|
||||
[dialog setDirectoryURL:[NSURL fileURLWithPath:default_dir]];
|
||||
if (default_filename)
|
||||
[dialog setNameFieldStringValue:default_filename];
|
||||
|
||||
[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);
|
||||
|
||||
[dialog setCanChooseFiles:(properties & FILE_DIALOG_OPEN_FILE)];
|
||||
if (properties & FILE_DIALOG_OPEN_DIRECTORY)
|
||||
[dialog setCanChooseDirectories:YES];
|
||||
if (properties & FILE_DIALOG_CREATE_DIRECTORY)
|
||||
[dialog setCanCreateDirectories:YES];
|
||||
if (properties & FILE_DIALOG_MULTI_SELECTIONS)
|
||||
[dialog setAllowsMultipleSelection:YES];
|
||||
|
||||
if ([dialog runModal] == NSFileHandlingPanelCancelButton)
|
||||
return false;
|
||||
|
||||
NSArray* urls = [dialog URLs];
|
||||
for (NSURL* url in urls)
|
||||
if ([url isFileURL])
|
||||
paths->push_back(base::FilePath(base::SysNSStringToUTF8([url path])));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ShowSaveDialog(atom::NativeWindow* 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];
|
||||
|
||||
__block bool result = false;
|
||||
__block base::FilePath ret_path;
|
||||
[dialog beginSheetModalForWindow:window->GetNativeWindow()
|
||||
completionHandler:^(NSInteger chosen) {
|
||||
if (chosen == NSFileHandlingPanelCancelButton ||
|
||||
![[dialog URL] isFileURL]) {
|
||||
result = false;
|
||||
} else {
|
||||
result = true;
|
||||
ret_path = base::FilePath(base::SysNSStringToUTF8([[dialog URL] path]));
|
||||
}
|
||||
|
||||
[NSApp stopModal];
|
||||
}];
|
||||
|
||||
[NSApp runModalForWindow:window->GetNativeWindow()];
|
||||
|
||||
*path = ret_path;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace file_dialog
|
||||
@@ -1,23 +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/file_dialog.h"
|
||||
|
||||
namespace file_dialog {
|
||||
|
||||
bool ShowOpenDialog(const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
int properties,
|
||||
std::vector<base::FilePath>* paths) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ShowSaveDialog(atom::NativeWindow* window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
base::FilePath* path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace file_dialog
|
||||
@@ -1,157 +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/media/media_capture_devices_dispatcher.h"
|
||||
|
||||
#include "base/prefs/pref_service.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/media_devices_monitor.h"
|
||||
#include "content/public/common/media_stream_request.h"
|
||||
|
||||
using content::BrowserThread;
|
||||
using content::MediaStreamDevices;
|
||||
|
||||
namespace {
|
||||
|
||||
const content::MediaStreamDevice* FindDefaultDeviceWithId(
|
||||
const content::MediaStreamDevices& devices,
|
||||
const std::string& device_id) {
|
||||
if (devices.empty())
|
||||
return NULL;
|
||||
|
||||
content::MediaStreamDevices::const_iterator iter = devices.begin();
|
||||
for (; iter != devices.end(); ++iter) {
|
||||
if (iter->id == device_id) {
|
||||
return &(*iter);
|
||||
}
|
||||
}
|
||||
|
||||
return &(*devices.begin());
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
MediaCaptureDevicesDispatcher* MediaCaptureDevicesDispatcher::GetInstance() {
|
||||
return Singleton<MediaCaptureDevicesDispatcher>::get();
|
||||
}
|
||||
|
||||
MediaCaptureDevicesDispatcher::MediaCaptureDevicesDispatcher()
|
||||
: devices_enumerated_(false) {}
|
||||
|
||||
MediaCaptureDevicesDispatcher::~MediaCaptureDevicesDispatcher() {}
|
||||
|
||||
const MediaStreamDevices&
|
||||
MediaCaptureDevicesDispatcher::GetAudioCaptureDevices() {
|
||||
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||
if (!devices_enumerated_) {
|
||||
BrowserThread::PostTask(
|
||||
BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&content::EnsureMonitorCaptureDevices));
|
||||
devices_enumerated_ = true;
|
||||
}
|
||||
return audio_devices_;
|
||||
}
|
||||
|
||||
const MediaStreamDevices&
|
||||
MediaCaptureDevicesDispatcher::GetVideoCaptureDevices() {
|
||||
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||
if (!devices_enumerated_) {
|
||||
BrowserThread::PostTask(
|
||||
BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&content::EnsureMonitorCaptureDevices));
|
||||
devices_enumerated_ = true;
|
||||
}
|
||||
return video_devices_;
|
||||
}
|
||||
|
||||
void MediaCaptureDevicesDispatcher::GetRequestedDevice(
|
||||
const std::string& requested_device_id,
|
||||
bool audio,
|
||||
bool video,
|
||||
content::MediaStreamDevices* devices) {
|
||||
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||
DCHECK(audio || video);
|
||||
|
||||
if (audio) {
|
||||
const content::MediaStreamDevices& audio_devices = GetAudioCaptureDevices();
|
||||
const content::MediaStreamDevice* const device =
|
||||
FindDefaultDeviceWithId(audio_devices, requested_device_id);
|
||||
if (device)
|
||||
devices->push_back(*device);
|
||||
}
|
||||
if (video) {
|
||||
const content::MediaStreamDevices& video_devices = GetVideoCaptureDevices();
|
||||
const content::MediaStreamDevice* const device =
|
||||
FindDefaultDeviceWithId(video_devices, requested_device_id);
|
||||
if (device)
|
||||
devices->push_back(*device);
|
||||
}
|
||||
}
|
||||
|
||||
void MediaCaptureDevicesDispatcher::GetDefaultDevices(
|
||||
bool audio,
|
||||
bool video,
|
||||
content::MediaStreamDevices* devices) {
|
||||
if (audio) {
|
||||
GetRequestedDevice(std::string(), true, false, devices);
|
||||
}
|
||||
|
||||
if (video) {
|
||||
GetRequestedDevice(std::string(), false, true, devices);
|
||||
}
|
||||
}
|
||||
|
||||
void MediaCaptureDevicesDispatcher::OnAudioCaptureDevicesChanged(
|
||||
const content::MediaStreamDevices& devices) {
|
||||
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
||||
BrowserThread::PostTask(
|
||||
BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(&MediaCaptureDevicesDispatcher::UpdateAudioDevicesOnUIThread,
|
||||
base::Unretained(this), devices));
|
||||
}
|
||||
|
||||
void MediaCaptureDevicesDispatcher::OnVideoCaptureDevicesChanged(
|
||||
const content::MediaStreamDevices& devices) {
|
||||
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
||||
BrowserThread::PostTask(
|
||||
BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(&MediaCaptureDevicesDispatcher::UpdateVideoDevicesOnUIThread,
|
||||
base::Unretained(this), devices));
|
||||
}
|
||||
|
||||
void MediaCaptureDevicesDispatcher::OnMediaRequestStateChanged(
|
||||
int render_process_id,
|
||||
int render_view_id,
|
||||
const content::MediaStreamDevice& device,
|
||||
content::MediaRequestState state) {
|
||||
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
||||
BrowserThread::PostTask(
|
||||
BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(
|
||||
&MediaCaptureDevicesDispatcher::UpdateMediaRequestStateOnUIThread,
|
||||
base::Unretained(this), render_process_id, render_view_id, device,
|
||||
state));
|
||||
}
|
||||
|
||||
void MediaCaptureDevicesDispatcher::UpdateAudioDevicesOnUIThread(
|
||||
const content::MediaStreamDevices& devices) {
|
||||
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||
devices_enumerated_ = true;
|
||||
audio_devices_ = devices;
|
||||
}
|
||||
|
||||
void MediaCaptureDevicesDispatcher::UpdateVideoDevicesOnUIThread(
|
||||
const content::MediaStreamDevices& devices) {
|
||||
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||
devices_enumerated_ = true;
|
||||
video_devices_ = devices;
|
||||
}
|
||||
|
||||
void MediaCaptureDevicesDispatcher::UpdateMediaRequestStateOnUIThread(
|
||||
int render_process_id,
|
||||
int render_view_id,
|
||||
const content::MediaStreamDevice& device,
|
||||
content::MediaRequestState state) {
|
||||
}
|
||||
@@ -1,78 +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 CHROME_BROWSER_MEDIA_MEDIA_CAPTURE_DEVICES_DISPATCHER_H_
|
||||
#define CHROME_BROWSER_MEDIA_MEDIA_CAPTURE_DEVICES_DISPATCHER_H_
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/memory/singleton.h"
|
||||
#include "base/observer_list.h"
|
||||
#include "content/public/browser/media_observer.h"
|
||||
#include "content/public/common/media_stream_request.h"
|
||||
|
||||
// This singleton is used to receive updates about media events from the content
|
||||
// layer.
|
||||
class MediaCaptureDevicesDispatcher : public content::MediaObserver {
|
||||
public:
|
||||
static MediaCaptureDevicesDispatcher* GetInstance();
|
||||
|
||||
// Helper for picking the device that was requested for an OpenDevice request.
|
||||
// If the device requested is not available it will revert to using the first
|
||||
// available one instead or will return an empty list if no devices of the
|
||||
// requested kind are present.
|
||||
void GetRequestedDevice(const std::string& requested_device_id,
|
||||
bool audio,
|
||||
bool video,
|
||||
content::MediaStreamDevices* devices);
|
||||
void GetDefaultDevices(bool audio,
|
||||
bool video,
|
||||
content::MediaStreamDevices* devices);
|
||||
|
||||
const content::MediaStreamDevices& GetAudioCaptureDevices();
|
||||
const content::MediaStreamDevices& GetVideoCaptureDevices();
|
||||
|
||||
// Overridden from content::MediaObserver:
|
||||
virtual void OnAudioCaptureDevicesChanged(
|
||||
const content::MediaStreamDevices& devices) OVERRIDE;
|
||||
virtual void OnVideoCaptureDevicesChanged(
|
||||
const content::MediaStreamDevices& devices) OVERRIDE;
|
||||
virtual void OnMediaRequestStateChanged(
|
||||
int render_process_id,
|
||||
int render_view_id,
|
||||
const content::MediaStreamDevice& device,
|
||||
content::MediaRequestState state) OVERRIDE;
|
||||
virtual void OnAudioStreamPlayingChanged(
|
||||
int render_process_id,
|
||||
int render_view_id,
|
||||
int stream_id,
|
||||
bool playing) OVERRIDE {}
|
||||
|
||||
private:
|
||||
friend struct DefaultSingletonTraits<MediaCaptureDevicesDispatcher>;
|
||||
|
||||
MediaCaptureDevicesDispatcher();
|
||||
virtual ~MediaCaptureDevicesDispatcher();
|
||||
|
||||
// Called by the MediaObserver() functions, executed on UI thread.
|
||||
void UpdateAudioDevicesOnUIThread(const content::MediaStreamDevices& devices);
|
||||
void UpdateVideoDevicesOnUIThread(const content::MediaStreamDevices& devices);
|
||||
void UpdateMediaRequestStateOnUIThread(
|
||||
int render_process_id,
|
||||
int render_view_id,
|
||||
const content::MediaStreamDevice& device,
|
||||
content::MediaRequestState state);
|
||||
|
||||
// A list of cached audio capture devices.
|
||||
content::MediaStreamDevices audio_devices_;
|
||||
|
||||
// A list of cached video capture devices.
|
||||
content::MediaStreamDevices video_devices_;
|
||||
|
||||
// Flag to indicate if device enumeration has been done/doing.
|
||||
// Only accessed on UI thread.
|
||||
bool devices_enumerated_;
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_MEDIA_MEDIA_CAPTURE_DEVICES_DISPATCHER_H_
|
||||
@@ -1,86 +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/media/media_stream_devices_controller.h"
|
||||
|
||||
#include "base/values.h"
|
||||
#include "browser/media/media_capture_devices_dispatcher.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/common/media_stream_request.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
bool HasAnyAvailableDevice() {
|
||||
const content::MediaStreamDevices& audio_devices =
|
||||
MediaCaptureDevicesDispatcher::GetInstance()->GetAudioCaptureDevices();
|
||||
const content::MediaStreamDevices& video_devices =
|
||||
MediaCaptureDevicesDispatcher::GetInstance()->GetVideoCaptureDevices();
|
||||
|
||||
return !audio_devices.empty() || !video_devices.empty();
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
MediaStreamDevicesController::MediaStreamDevicesController(
|
||||
const content::MediaStreamRequest& request,
|
||||
const content::MediaResponseCallback& callback)
|
||||
: request_(request),
|
||||
callback_(callback),
|
||||
microphone_requested_(
|
||||
request_.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE),
|
||||
webcam_requested_(
|
||||
request_.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE) {
|
||||
}
|
||||
|
||||
MediaStreamDevicesController::~MediaStreamDevicesController() {}
|
||||
|
||||
bool MediaStreamDevicesController::TakeAction() {
|
||||
// Deny the request if there is no device attached to the OS.
|
||||
if (!HasAnyAvailableDevice()) {
|
||||
Deny();
|
||||
return true;
|
||||
}
|
||||
|
||||
Accept();
|
||||
return true;
|
||||
}
|
||||
|
||||
void MediaStreamDevicesController::Accept() {
|
||||
// Get the default devices for the request.
|
||||
content::MediaStreamDevices devices;
|
||||
if (microphone_requested_ || webcam_requested_) {
|
||||
switch (request_.request_type) {
|
||||
case content::MEDIA_OPEN_DEVICE:
|
||||
// For open device request pick the desired device or fall back to the
|
||||
// first available of the given type.
|
||||
MediaCaptureDevicesDispatcher::GetInstance()->GetRequestedDevice(
|
||||
request_.requested_device_id,
|
||||
microphone_requested_,
|
||||
webcam_requested_,
|
||||
&devices);
|
||||
break;
|
||||
case content::MEDIA_DEVICE_ACCESS:
|
||||
case content::MEDIA_GENERATE_STREAM:
|
||||
case content::MEDIA_ENUMERATE_DEVICES:
|
||||
// Get the default devices for the request.
|
||||
MediaCaptureDevicesDispatcher::GetInstance()->
|
||||
GetDefaultDevices(microphone_requested_,
|
||||
webcam_requested_,
|
||||
&devices);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LOG(ERROR) << "Accept";
|
||||
callback_.Run(devices, scoped_ptr<content::MediaStreamUI>());
|
||||
}
|
||||
|
||||
void MediaStreamDevicesController::Deny() {
|
||||
callback_.Run(content::MediaStreamDevices(),
|
||||
scoped_ptr<content::MediaStreamUI>());
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
@@ -1,46 +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_MEDIA_MEDIA_STREAM_DEVICES_CONTROLLER_H_
|
||||
#define ATOM_BROWSER_MEDIA_MEDIA_STREAM_DEVICES_CONTROLLER_H_
|
||||
|
||||
#include "content/public/browser/web_contents_delegate.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class MediaStreamDevicesController {
|
||||
public:
|
||||
MediaStreamDevicesController(const content::MediaStreamRequest& request,
|
||||
const content::MediaResponseCallback& callback);
|
||||
|
||||
virtual ~MediaStreamDevicesController();
|
||||
|
||||
// Public method to be called before creating the MediaStreamInfoBarDelegate.
|
||||
// This function will check the content settings exceptions and take the
|
||||
// corresponding action on exception which matches the request.
|
||||
bool TakeAction();
|
||||
|
||||
// Public methods to be called by MediaStreamInfoBarDelegate;
|
||||
bool has_audio() const { return microphone_requested_; }
|
||||
bool has_video() const { return webcam_requested_; }
|
||||
void Accept();
|
||||
void Deny();
|
||||
|
||||
private:
|
||||
// The original request for access to devices.
|
||||
const content::MediaStreamRequest request_;
|
||||
|
||||
// The callback that needs to be Run to notify WebRTC of whether access to
|
||||
// audio/video devices was granted or not.
|
||||
content::MediaResponseCallback callback_;
|
||||
|
||||
bool microphone_requested_;
|
||||
bool webcam_requested_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MediaStreamDevicesController);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_MEDIA_MEDIA_STREAM_DEVICES_CONTROLLER_H_
|
||||
@@ -1,49 +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/message_box.h"
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "browser/native_window.h"
|
||||
#include "browser/nsalert_synchronous_sheet.h"
|
||||
|
||||
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) {
|
||||
// Ignore the title; it's the window title on other platforms and ignorable.
|
||||
NSAlert* alert = [[[NSAlert alloc] init] autorelease];
|
||||
[alert setMessageText:base::SysUTF8ToNSString(message)];
|
||||
[alert setInformativeText:base::SysUTF8ToNSString(detail)];
|
||||
|
||||
switch (type) {
|
||||
case MESSAGE_BOX_TYPE_INFORMATION:
|
||||
[alert setAlertStyle:NSInformationalAlertStyle];
|
||||
break;
|
||||
case MESSAGE_BOX_TYPE_WARNING:
|
||||
[alert setAlertStyle:NSWarningAlertStyle];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < buttons.size(); ++i) {
|
||||
NSString* title = base::SysUTF8ToNSString(buttons[i]);
|
||||
NSButton* button = [alert addButtonWithTitle:title];
|
||||
[button setTag:i];
|
||||
}
|
||||
|
||||
if (parent_window)
|
||||
return [alert runModalSheetForWindow:parent_window->GetNativeWindow()];
|
||||
else
|
||||
return [alert runModal];
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "browser/atom_browser_context.h"
|
||||
#include "browser/atom_browser_main_parts.h"
|
||||
#include "browser/atom_javascript_dialog_manager.h"
|
||||
#include "browser/media/media_stream_devices_controller.h"
|
||||
#include "browser/window_list.h"
|
||||
#include "content/public/browser/devtools_agent_host.h"
|
||||
#include "content/public/browser/invalidate_type.h"
|
||||
@@ -25,6 +24,7 @@
|
||||
#include "content/public/browser/notification_types.h"
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#include "content/public/browser/render_widget_host_view.h"
|
||||
#include "common/api/api_messages.h"
|
||||
#include "common/options_switches.h"
|
||||
#include "ipc/ipc_message_macros.h"
|
||||
@@ -39,10 +39,13 @@ 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_);
|
||||
|
||||
web_contents->SetDelegate(this);
|
||||
|
||||
WindowList::AddWindow(this);
|
||||
@@ -154,6 +157,10 @@ void NativeWindow::BlurWebView() {
|
||||
GetWebContents()->GetRenderViewHost()->Blur();
|
||||
}
|
||||
|
||||
bool NativeWindow::IsWebViewFocused() {
|
||||
return GetWebContents()->GetRenderViewHost()->GetView()->HasFocus();
|
||||
}
|
||||
|
||||
void NativeWindow::RestartHangMonitorTimeout() {
|
||||
GetWebContents()->GetRenderViewHost()->RestartHangMonitorTimeout();
|
||||
}
|
||||
@@ -234,14 +241,6 @@ void NativeWindow::RequestToLockMouse(content::WebContents* web_contents,
|
||||
GetWebContents()->GotResponseToLockMouseRequest(true);
|
||||
}
|
||||
|
||||
void NativeWindow::RequestMediaAccessPermission(
|
||||
content::WebContents* web_contents,
|
||||
const content::MediaStreamRequest& request,
|
||||
const content::MediaResponseCallback& callback) {
|
||||
MediaStreamDevicesController controller(request, callback);
|
||||
controller.TakeAction();
|
||||
}
|
||||
|
||||
bool NativeWindow::CanOverscrollContent() const {
|
||||
return false;
|
||||
}
|
||||
@@ -254,6 +253,13 @@ void NativeWindow::DeactivateContents(content::WebContents* contents) {
|
||||
BlurWebView();
|
||||
}
|
||||
|
||||
void NativeWindow::LoadingStateChanged(content::WebContents* source) {
|
||||
bool is_loading = source->IsLoading();
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver,
|
||||
observers_,
|
||||
OnLoadingStateChanged(is_loading));
|
||||
}
|
||||
|
||||
void NativeWindow::MoveContents(content::WebContents* source,
|
||||
const gfx::Rect& pos) {
|
||||
SetPosition(pos.origin());
|
||||
@@ -294,7 +300,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()
|
||||
|
||||
@@ -332,7 +341,7 @@ void NativeWindow::Observe(int type,
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindow::OnRendererMessage(const std::string& channel,
|
||||
void NativeWindow::OnRendererMessage(const string16& channel,
|
||||
const base::ListValue& args) {
|
||||
AtomBrowserMainParts::Get()->atom_bindings()->OnRendererMessage(
|
||||
GetWebContents()->GetRenderProcessHost()->GetID(),
|
||||
@@ -341,15 +350,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
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
#include "browser/native_window_observer.h"
|
||||
#include "content/public/browser/notification_registrar.h"
|
||||
#include "content/public/browser/notification_observer.h"
|
||||
#include "content/public/browser/web_contents_delegate.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
#include "vendor/brightray/browser/default_web_contents_delegate.h"
|
||||
|
||||
namespace base {
|
||||
class DictionaryValue;
|
||||
@@ -35,11 +35,16 @@ class Rect;
|
||||
class Size;
|
||||
}
|
||||
|
||||
namespace IPC {
|
||||
class Message;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomJavaScriptDialogManager;
|
||||
struct DraggableRegion;
|
||||
|
||||
class NativeWindow : public content::WebContentsDelegate,
|
||||
class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
public content::WebContentsObserver,
|
||||
public content::NotificationObserver {
|
||||
public:
|
||||
@@ -96,6 +101,7 @@ class NativeWindow : public content::WebContentsDelegate,
|
||||
virtual void InspectElement(int x, int y);
|
||||
virtual void FocusOnWebView();
|
||||
virtual void BlurWebView();
|
||||
virtual bool IsWebViewFocused();
|
||||
virtual void RestartHangMonitorTimeout();
|
||||
|
||||
// The same with closing a tab in a real browser.
|
||||
@@ -113,6 +119,8 @@ class NativeWindow : public content::WebContentsDelegate,
|
||||
observers_.RemoveObserver(obs);
|
||||
}
|
||||
|
||||
bool has_frame() const { return has_frame_; }
|
||||
|
||||
protected:
|
||||
explicit NativeWindow(content::WebContents* web_contents,
|
||||
base::DictionaryValue* options);
|
||||
@@ -124,6 +132,10 @@ class NativeWindow : public content::WebContentsDelegate,
|
||||
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,
|
||||
@@ -138,13 +150,10 @@ class NativeWindow : public content::WebContentsDelegate,
|
||||
virtual void RequestToLockMouse(content::WebContents* web_contents,
|
||||
bool user_gesture,
|
||||
bool last_unlocked_by_target) OVERRIDE;
|
||||
virtual void RequestMediaAccessPermission(
|
||||
content::WebContents* web_contents,
|
||||
const content::MediaStreamRequest& request,
|
||||
const content::MediaResponseCallback& callback) OVERRIDE;
|
||||
virtual bool CanOverscrollContent() const OVERRIDE;
|
||||
virtual void ActivateContents(content::WebContents* contents) OVERRIDE;
|
||||
virtual void DeactivateContents(content::WebContents* contents) OVERRIDE;
|
||||
virtual void LoadingStateChanged(content::WebContents* source) OVERRIDE;
|
||||
virtual void MoveContents(content::WebContents* source,
|
||||
const gfx::Rect& pos) OVERRIDE;
|
||||
virtual void CloseContents(content::WebContents* source) OVERRIDE;
|
||||
@@ -162,15 +171,18 @@ class NativeWindow : public content::WebContentsDelegate,
|
||||
const content::NotificationSource& source,
|
||||
const content::NotificationDetails& details) OVERRIDE;
|
||||
|
||||
// Whether window has standard frame.
|
||||
bool has_frame_;
|
||||
|
||||
private:
|
||||
void RendererUnresponsiveDelayed();
|
||||
|
||||
void OnRendererMessage(const std::string& channel,
|
||||
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 {
|
||||
@@ -52,11 +54,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 +81,9 @@ class NativeWindowMac : public NativeWindow {
|
||||
private:
|
||||
void InstallView();
|
||||
void UninstallView();
|
||||
void InstallDraggableRegionViews();
|
||||
void UpdateDraggableRegionsForCustomDrag(
|
||||
const std::vector<DraggableRegion>& regions);
|
||||
|
||||
NSWindow* window_;
|
||||
|
||||
@@ -72,6 +91,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();
|
||||
}
|
||||
|
||||
@@ -300,7 +360,7 @@ void NativeWindowMac::SetKiosk(bool kiosk) {
|
||||
if (kiosk) {
|
||||
NSApplicationPresentationOptions options =
|
||||
NSApplicationPresentationHideDock +
|
||||
NSApplicationPresentationHideMenuBar +
|
||||
NSApplicationPresentationHideMenuBar +
|
||||
NSApplicationPresentationDisableAppleMenu +
|
||||
NSApplicationPresentationDisableProcessSwitching +
|
||||
NSApplicationPresentationDisableForceQuit +
|
||||
@@ -324,6 +384,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 +436,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) {
|
||||
|
||||
@@ -17,6 +17,9 @@ class NativeWindowObserver {
|
||||
virtual void OnPageTitleUpdated(bool* prevent_default,
|
||||
const std::string& title) {}
|
||||
|
||||
// Called when the window is starting or is done loading a page.
|
||||
virtual void OnLoadingStateChanged(bool is_loading) {}
|
||||
|
||||
// Called when the window is gonna closed.
|
||||
virtual void WillCloseWindow(bool* prevent_default) {}
|
||||
|
||||
|
||||
@@ -6,8 +6,14 @@
|
||||
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/values.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/views/controls/webview/webview.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
#include "ui/views/window/client_view.h"
|
||||
@@ -17,6 +23,9 @@ namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
const int kResizeInsideBoundsSize = 5;
|
||||
const int kResizeAreaCornerSize = 16;
|
||||
|
||||
class NativeWindowClientView : public views::ClientView {
|
||||
public:
|
||||
NativeWindowClientView(views::Widget* widget,
|
||||
@@ -60,6 +69,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 +173,7 @@ NativeWindowWin::NativeWindowWin(content::WebContents* web_contents,
|
||||
resizable_(true) {
|
||||
views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
|
||||
params.delegate = 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);
|
||||
@@ -83,6 +186,7 @@ NativeWindowWin::NativeWindowWin(content::WebContents* web_contents,
|
||||
window_->CenterWindow(size);
|
||||
|
||||
web_view_->SetWebContents(web_contents);
|
||||
OnViewWasResized();
|
||||
}
|
||||
|
||||
NativeWindowWin::~NativeWindowWin() {
|
||||
@@ -221,6 +325,30 @@ gfx::NativeWindow NativeWindowWin::GetNativeWindow() {
|
||||
return window_->GetNativeView();
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -264,7 +392,40 @@ views::ClientView* NativeWindowWin::CreateClientView(views::Widget* widget) {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
@@ -60,7 +60,12 @@ class NativeWindowWin : public NativeWindow,
|
||||
virtual bool IsKiosk() OVERRIDE;
|
||||
virtual gfx::NativeWindow GetNativeWindow() OVERRIDE;
|
||||
|
||||
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*,
|
||||
@@ -79,9 +84,13 @@ class NativeWindowWin : public NativeWindow,
|
||||
views::Widget* widget) OVERRIDE;
|
||||
|
||||
private:
|
||||
void OnViewWasResized();
|
||||
|
||||
scoped_ptr<views::Widget> window_;
|
||||
views::WebView* web_view_; // managed by window_.
|
||||
|
||||
scoped_ptr<SkRegion> draggable_region_;
|
||||
|
||||
bool resizable_;
|
||||
string16 title_;
|
||||
gfx::Size minimum_size_;
|
||||
|
||||
105
browser/net/adapter_request_job.cc
Normal file
105
browser/net/adapter_request_job.cc
Normal file
@@ -0,0 +1,105 @@
|
||||
// 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/adapter_request_job.h"
|
||||
|
||||
#include "browser/net/url_request_string_job.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "net/base/net_errors.h"
|
||||
#include "net/url_request/url_request_error_job.h"
|
||||
#include "net/url_request/url_request_file_job.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
AdapterRequestJob::AdapterRequestJob(ProtocolHandler* protocol_handler,
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate)
|
||||
: URLRequestJob(request, network_delegate),
|
||||
protocol_handler_(protocol_handler),
|
||||
weak_factory_(this) {
|
||||
}
|
||||
|
||||
void AdapterRequestJob::Start() {
|
||||
DCHECK(!real_job_);
|
||||
content::BrowserThread::PostTask(
|
||||
content::BrowserThread::UI,
|
||||
FROM_HERE,
|
||||
base::Bind(&AdapterRequestJob::GetJobTypeInUI,
|
||||
weak_factory_.GetWeakPtr()));
|
||||
}
|
||||
|
||||
void AdapterRequestJob::Kill() {
|
||||
DCHECK(real_job_);
|
||||
real_job_->Kill();
|
||||
}
|
||||
|
||||
bool AdapterRequestJob::ReadRawData(net::IOBuffer* buf,
|
||||
int buf_size,
|
||||
int *bytes_read) {
|
||||
DCHECK(real_job_);
|
||||
return real_job_->ReadRawData(buf, buf_size, bytes_read);
|
||||
}
|
||||
|
||||
bool AdapterRequestJob::IsRedirectResponse(GURL* location,
|
||||
int* http_status_code) {
|
||||
DCHECK(real_job_);
|
||||
return real_job_->IsRedirectResponse(location, http_status_code);
|
||||
}
|
||||
|
||||
net::Filter* AdapterRequestJob::SetupFilter() const {
|
||||
DCHECK(real_job_);
|
||||
return real_job_->SetupFilter();
|
||||
}
|
||||
|
||||
bool AdapterRequestJob::GetMimeType(std::string* mime_type) const {
|
||||
DCHECK(real_job_);
|
||||
return real_job_->GetMimeType(mime_type);
|
||||
}
|
||||
|
||||
bool AdapterRequestJob::GetCharset(std::string* charset) {
|
||||
DCHECK(real_job_);
|
||||
return real_job_->GetCharset(charset);
|
||||
}
|
||||
|
||||
base::WeakPtr<AdapterRequestJob> AdapterRequestJob::GetWeakPtr() {
|
||||
return weak_factory_.GetWeakPtr();
|
||||
}
|
||||
|
||||
void AdapterRequestJob::CreateErrorJobAndStart(int error_code) {
|
||||
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
||||
|
||||
real_job_ = new net::URLRequestErrorJob(
|
||||
request(), network_delegate(), error_code);
|
||||
real_job_->Start();
|
||||
}
|
||||
|
||||
void AdapterRequestJob::CreateStringJobAndStart(const std::string& mime_type,
|
||||
const std::string& charset,
|
||||
const std::string& data) {
|
||||
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
||||
|
||||
real_job_ = new URLRequestStringJob(
|
||||
request(), network_delegate(), mime_type, charset, data);
|
||||
real_job_->Start();
|
||||
}
|
||||
|
||||
void AdapterRequestJob::CreateFileJobAndStart(const base::FilePath& path) {
|
||||
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
||||
|
||||
real_job_ = new net::URLRequestFileJob(request(), network_delegate(), path);
|
||||
real_job_->Start();
|
||||
}
|
||||
|
||||
void AdapterRequestJob::CreateJobFromProtocolHandlerAndStart() {
|
||||
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
||||
DCHECK(protocol_handler_);
|
||||
real_job_ = protocol_handler_->MaybeCreateJob(request(),
|
||||
network_delegate());
|
||||
if (!real_job_.get())
|
||||
CreateErrorJobAndStart(net::ERR_NOT_IMPLEMENTED);
|
||||
else
|
||||
real_job_->Start();
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
68
browser/net/adapter_request_job.h
Normal file
68
browser/net/adapter_request_job.h
Normal file
@@ -0,0 +1,68 @@
|
||||
// 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_ADAPTER_REQUEST_JOB_H_
|
||||
#define ATOM_BROWSER_NET_ADAPTER_REQUEST_JOB_H_
|
||||
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "net/url_request/url_request_job.h"
|
||||
#include "net/url_request/url_request_job_factory.h"
|
||||
|
||||
namespace base {
|
||||
class FilePath;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
// Ask JS which type of job it wants, and then delegate corresponding methods.
|
||||
class AdapterRequestJob : public net::URLRequestJob {
|
||||
public:
|
||||
typedef net::URLRequestJobFactory::ProtocolHandler ProtocolHandler;
|
||||
|
||||
AdapterRequestJob(ProtocolHandler* protocol_handler,
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate);
|
||||
|
||||
public:
|
||||
// net::URLRequestJob:
|
||||
virtual void Start() OVERRIDE;
|
||||
virtual void Kill() OVERRIDE;
|
||||
virtual bool ReadRawData(net::IOBuffer* buf,
|
||||
int buf_size,
|
||||
int *bytes_read) OVERRIDE;
|
||||
virtual bool IsRedirectResponse(GURL* location,
|
||||
int* http_status_code) OVERRIDE;
|
||||
virtual net::Filter* SetupFilter() const OVERRIDE;
|
||||
virtual bool GetMimeType(std::string* mime_type) const OVERRIDE;
|
||||
virtual bool GetCharset(std::string* charset) OVERRIDE;
|
||||
|
||||
base::WeakPtr<AdapterRequestJob> GetWeakPtr();
|
||||
|
||||
ProtocolHandler* default_protocol_handler() { return protocol_handler_; }
|
||||
|
||||
// Override this function to determine which job should be started.
|
||||
virtual void GetJobTypeInUI() = 0;
|
||||
|
||||
void CreateErrorJobAndStart(int error_code);
|
||||
void CreateStringJobAndStart(const std::string& mime_type,
|
||||
const std::string& charset,
|
||||
const std::string& data);
|
||||
void CreateFileJobAndStart(const base::FilePath& path);
|
||||
void CreateJobFromProtocolHandlerAndStart();
|
||||
|
||||
private:
|
||||
// The delegated request job.
|
||||
scoped_refptr<net::URLRequestJob> real_job_;
|
||||
|
||||
// Default protocol handler.
|
||||
ProtocolHandler* protocol_handler_;
|
||||
|
||||
base::WeakPtrFactory<AdapterRequestJob> weak_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AdapterRequestJob);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_NET_ADAPTER_REQUEST_JOB_H_
|
||||
170
browser/net/atom_url_request_context_getter.cc
Normal file
170
browser/net/atom_url_request_context_getter.cc
Normal file
@@ -0,0 +1,170 @@
|
||||
// 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));
|
||||
|
||||
storage_->set_cert_verifier(net::CertVerifier::CreateDefault());
|
||||
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::DhcpProxyScriptFetcherFactory dhcp_factory;
|
||||
storage_->set_proxy_service(
|
||||
net::CreateProxyServiceUsingV8ProxyResolver(
|
||||
proxy_config_service_.release(),
|
||||
new net::ProxyScriptFetcherImpl(url_request_context_.get()),
|
||||
dhcp_factory.Create(url_request_context_.get()),
|
||||
url_request_context_->host_resolver(),
|
||||
NULL,
|
||||
url_request_context_->network_delegate()));
|
||||
|
||||
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_
|
||||
105
browser/net/atom_url_request_job_factory.cc
Normal file
105
browser/net/atom_url_request_job_factory.cc
Normal file
@@ -0,0 +1,105 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
#include "browser/net/atom_url_request_job_factory.h"
|
||||
|
||||
#include "base/stl_util.h"
|
||||
#include "googleurl/src/gurl.h"
|
||||
#include "net/base/load_flags.h"
|
||||
#include "net/url_request/url_request.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
typedef net::URLRequestJobFactory::ProtocolHandler ProtocolHandler;
|
||||
|
||||
AtomURLRequestJobFactory::AtomURLRequestJobFactory() {}
|
||||
|
||||
AtomURLRequestJobFactory::~AtomURLRequestJobFactory() {
|
||||
STLDeleteValues(&protocol_handler_map_);
|
||||
}
|
||||
|
||||
bool AtomURLRequestJobFactory::SetProtocolHandler(
|
||||
const std::string& scheme,
|
||||
ProtocolHandler* protocol_handler) {
|
||||
DCHECK(CalledOnValidThread());
|
||||
|
||||
base::AutoLock locked(lock_);
|
||||
|
||||
if (!protocol_handler) {
|
||||
ProtocolHandlerMap::iterator it = protocol_handler_map_.find(scheme);
|
||||
if (it == protocol_handler_map_.end())
|
||||
return false;
|
||||
|
||||
delete it->second;
|
||||
protocol_handler_map_.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ContainsKey(protocol_handler_map_, scheme))
|
||||
return false;
|
||||
protocol_handler_map_[scheme] = protocol_handler;
|
||||
return true;
|
||||
}
|
||||
|
||||
ProtocolHandler* AtomURLRequestJobFactory::ReplaceProtocol(
|
||||
const std::string& scheme,
|
||||
ProtocolHandler* protocol_handler) {
|
||||
DCHECK(CalledOnValidThread());
|
||||
DCHECK(protocol_handler);
|
||||
|
||||
base::AutoLock locked(lock_);
|
||||
if (!ContainsKey(protocol_handler_map_, scheme))
|
||||
return NULL;
|
||||
ProtocolHandler* original_protocol_handler = protocol_handler_map_[scheme];
|
||||
protocol_handler_map_[scheme] = protocol_handler;
|
||||
return original_protocol_handler;
|
||||
}
|
||||
|
||||
ProtocolHandler* AtomURLRequestJobFactory::GetProtocolHandler(
|
||||
const std::string& scheme) const {
|
||||
DCHECK(CalledOnValidThread());
|
||||
|
||||
base::AutoLock locked(lock_);
|
||||
ProtocolHandlerMap::const_iterator it = protocol_handler_map_.find(scheme);
|
||||
if (it == protocol_handler_map_.end())
|
||||
return NULL;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
bool AtomURLRequestJobFactory::HasProtocolHandler(
|
||||
const std::string& scheme) const {
|
||||
base::AutoLock locked(lock_);
|
||||
return ContainsKey(protocol_handler_map_, scheme);
|
||||
}
|
||||
|
||||
net::URLRequestJob* AtomURLRequestJobFactory::MaybeCreateJobWithProtocolHandler(
|
||||
const std::string& scheme,
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate) const {
|
||||
DCHECK(CalledOnValidThread());
|
||||
|
||||
base::AutoLock locked(lock_);
|
||||
ProtocolHandlerMap::const_iterator it = protocol_handler_map_.find(scheme);
|
||||
if (it == protocol_handler_map_.end())
|
||||
return NULL;
|
||||
return it->second->MaybeCreateJob(request, network_delegate);
|
||||
}
|
||||
|
||||
bool AtomURLRequestJobFactory::IsHandledProtocol(
|
||||
const std::string& scheme) const {
|
||||
DCHECK(CalledOnValidThread());
|
||||
return HasProtocolHandler(scheme) ||
|
||||
net::URLRequest::IsHandledProtocol(scheme);
|
||||
}
|
||||
|
||||
bool AtomURLRequestJobFactory::IsHandledURL(const GURL& url) const {
|
||||
if (!url.is_valid()) {
|
||||
// We handle error cases.
|
||||
return true;
|
||||
}
|
||||
return IsHandledProtocol(url.scheme());
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
61
browser/net/atom_url_request_job_factory.h
Normal file
61
browser/net/atom_url_request_job_factory.h
Normal file
@@ -0,0 +1,61 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// 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 ATOM_BROWSER_NET_ATOM_URL_REQUEST_URL_REQUEST_JOB_FACTORY_H_
|
||||
#define ATOM_BROWSER_NET_ATOM_URL_REQUEST_URL_REQUEST_JOB_FACTORY_H_
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/synchronization/lock.h"
|
||||
#include "net/url_request/url_request_job_factory.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomURLRequestJobFactory : public net::URLRequestJobFactory {
|
||||
public:
|
||||
AtomURLRequestJobFactory();
|
||||
virtual ~AtomURLRequestJobFactory();
|
||||
|
||||
// Sets the ProtocolHandler for a scheme. Returns true on success, false on
|
||||
// failure (a ProtocolHandler already exists for |scheme|). On success,
|
||||
// URLRequestJobFactory takes ownership of |protocol_handler|.
|
||||
bool SetProtocolHandler(const std::string& scheme,
|
||||
ProtocolHandler* protocol_handler);
|
||||
|
||||
// Intercepts the ProtocolHandler for a scheme. Returns the original protocol
|
||||
// handler on success, otherwise returns NULL.
|
||||
ProtocolHandler* ReplaceProtocol(const std::string& scheme,
|
||||
ProtocolHandler* protocol_handler);
|
||||
|
||||
// Returns the protocol handler registered with scheme.
|
||||
ProtocolHandler* GetProtocolHandler(const std::string& scheme) const;
|
||||
|
||||
// Whether the protocol handler is registered by the job factory.
|
||||
bool HasProtocolHandler(const std::string& scheme) const;
|
||||
|
||||
// URLRequestJobFactory implementation
|
||||
virtual net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
|
||||
const std::string& scheme,
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate) const OVERRIDE;
|
||||
virtual bool IsHandledProtocol(const std::string& scheme) const OVERRIDE;
|
||||
virtual bool IsHandledURL(const GURL& url) const OVERRIDE;
|
||||
|
||||
private:
|
||||
typedef std::map<std::string, ProtocolHandler*> ProtocolHandlerMap;
|
||||
|
||||
ProtocolHandlerMap protocol_handler_map_;
|
||||
|
||||
mutable base::Lock lock_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomURLRequestJobFactory);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_NET_ATOM_URL_REQUEST_URL_REQUEST_JOB_FACTORY_H_
|
||||
33
browser/net/url_request_string_job.cc
Normal file
33
browser/net/url_request_string_job.cc
Normal file
@@ -0,0 +1,33 @@
|
||||
// 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/url_request_string_job.h"
|
||||
|
||||
#include "net/base/net_errors.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
URLRequestStringJob::URLRequestStringJob(net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate,
|
||||
const std::string& mime_type,
|
||||
const std::string& charset,
|
||||
const std::string& data)
|
||||
: net::URLRequestSimpleJob(request, network_delegate),
|
||||
mime_type_(mime_type),
|
||||
charset_(charset),
|
||||
data_(data) {
|
||||
}
|
||||
|
||||
int URLRequestStringJob::GetData(
|
||||
std::string* mime_type,
|
||||
std::string* charset,
|
||||
std::string* data,
|
||||
const net::CompletionCallback& callback) const {
|
||||
*mime_type = mime_type_;
|
||||
*charset = charset_;
|
||||
*data = data_;
|
||||
return net::OK;
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
36
browser/net/url_request_string_job.h
Normal file
36
browser/net/url_request_string_job.h
Normal file
@@ -0,0 +1,36 @@
|
||||
// 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_URL_REQUEST_STRING_JOB_H_
|
||||
#define ATOM_BROWSER_NET_URL_REQUEST_STRING_JOB_H_
|
||||
|
||||
#include "net/url_request/url_request_simple_job.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class URLRequestStringJob : public net::URLRequestSimpleJob {
|
||||
public:
|
||||
URLRequestStringJob(net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate,
|
||||
const std::string& mime_type,
|
||||
const std::string& charset,
|
||||
const std::string& data);
|
||||
|
||||
// URLRequestSimpleJob:
|
||||
virtual int GetData(std::string* mime_type,
|
||||
std::string* charset,
|
||||
std::string* data,
|
||||
const net::CompletionCallback& callback) const OVERRIDE;
|
||||
|
||||
private:
|
||||
std::string mime_type_;
|
||||
std::string charset_;
|
||||
std::string data_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(URLRequestStringJob);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_NET_URL_REQUEST_STRING_JOB_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.
|
||||
|
||||
#include "browser/accelerator_util.h"
|
||||
#include "browser/ui/accelerator_util.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
@@ -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 BROWSER_ACCELERATOR_UTIL_H_
|
||||
#define BROWSER_ACCELERATOR_UTIL_H_
|
||||
#ifndef BROWSER_UI_ACCELERATOR_UTIL_H_
|
||||
#define BROWSER_UI_ACCELERATOR_UTIL_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
@@ -22,4 +22,4 @@ void SetPlatformAccelerator(ui::Accelerator* accelerator);
|
||||
|
||||
} // namespace accelerator_util
|
||||
|
||||
#endif // BROWSER_ACCELERATOR_UTIL_H_
|
||||
#endif // BROWSER_UI_ACCELERATOR_UTIL_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.
|
||||
|
||||
#include "browser/accelerator_util.h"
|
||||
#include "browser/ui/accelerator_util.h"
|
||||
|
||||
#include "ui/base/accelerators/accelerator.h"
|
||||
#import "ui/base/accelerators/platform_accelerator_cocoa.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.
|
||||
|
||||
#include "browser/accelerator_util.h"
|
||||
#include "browser/ui/accelerator_util.h"
|
||||
|
||||
#include "ui/base/accelerators/accelerator.h"
|
||||
|
||||
@@ -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"
|
||||
72
browser/ui/atom_menu_controller_mac.h
Normal file
72
browser/ui/atom_menu_controller_mac.h
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// 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_BROWSER_UI_ATOM_MENU_CONTROLLER_MAC_H_
|
||||
#define ATOM_BROWSER_UI_ATOM_MENU_CONTROLLER_MAC_H_
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include "base/memory/scoped_nsobject.h"
|
||||
#include "base/string16.h"
|
||||
|
||||
namespace ui {
|
||||
class MenuModel;
|
||||
}
|
||||
|
||||
// A controller for the cross-platform menu model. The menu that's created
|
||||
// has the tag and represented object set for each menu item. The object is a
|
||||
// NSValue holding a pointer to the model for that level of the menu (to
|
||||
// allow for hierarchical menus). The tag is the index into that model for
|
||||
// that particular item. It is important that the model outlives this object
|
||||
// as it only maintains weak references.
|
||||
@interface AtomMenuController : NSObject<NSMenuDelegate> {
|
||||
@protected
|
||||
ui::MenuModel* model_; // weak
|
||||
scoped_nsobject<NSMenu> menu_;
|
||||
BOOL isMenuOpen_;
|
||||
}
|
||||
|
||||
@property(nonatomic, assign) ui::MenuModel* model;
|
||||
|
||||
// NIB-based initializer. This does not create a menu. Clients can set the
|
||||
// properties of the object and the menu will be created upon the first call to
|
||||
// |-menu|. Note that the menu will be immutable after creation.
|
||||
- (id)init;
|
||||
|
||||
// Builds a NSMenu from the pre-built model (must not be nil). Changes made
|
||||
// to the contents of the model after calling this will not be noticed.
|
||||
- (id)initWithModel:(ui::MenuModel*)model;
|
||||
|
||||
// Programmatically close the constructed menu.
|
||||
- (void)cancel;
|
||||
|
||||
// Access to the constructed menu if the complex initializer was used. If the
|
||||
// default initializer was used, then this will create the menu on first call.
|
||||
- (NSMenu*)menu;
|
||||
|
||||
// Whether the menu is currently open.
|
||||
- (BOOL)isMenuOpen;
|
||||
|
||||
// NSMenuDelegate methods this class implements. Subclasses should call super
|
||||
// if extending the behavior.
|
||||
- (void)menuWillOpen:(NSMenu*)menu;
|
||||
- (void)menuDidClose:(NSMenu*)menu;
|
||||
|
||||
@end
|
||||
|
||||
// Exposed only for unit testing, do not call directly.
|
||||
@interface AtomMenuController (PrivateExposedForTesting)
|
||||
- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item;
|
||||
@end
|
||||
|
||||
// Protected methods that subclassers can override.
|
||||
@interface AtomMenuController (Protected)
|
||||
- (void)addItemToMenu:(NSMenu*)menu
|
||||
atIndex:(NSInteger)index
|
||||
fromModel:(ui::MenuModel*)model;
|
||||
- (NSMenu*)menuFromModel:(ui::MenuModel*)model;
|
||||
@end
|
||||
|
||||
#endif // ATOM_BROWSER_UI_ATOM_MENU_CONTROLLER_MAC_H_
|
||||
256
browser/ui/atom_menu_controller_mac.mm
Normal file
256
browser/ui/atom_menu_controller_mac.mm
Normal file
@@ -0,0 +1,256 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
#import "browser/ui/atom_menu_controller_mac.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "ui/base/accelerators/accelerator.h"
|
||||
#include "ui/base/accelerators/platform_accelerator_cocoa.h"
|
||||
#include "ui/base/l10n/l10n_util_mac.h"
|
||||
#include "ui/base/models/simple_menu_model.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
|
||||
namespace {
|
||||
|
||||
bool isLeftButtonEvent(NSEvent* event) {
|
||||
NSEventType type = [event type];
|
||||
return type == NSLeftMouseDown ||
|
||||
type == NSLeftMouseDragged ||
|
||||
type == NSLeftMouseUp;
|
||||
}
|
||||
|
||||
bool isRightButtonEvent(NSEvent* event) {
|
||||
NSEventType type = [event type];
|
||||
return type == NSRightMouseDown ||
|
||||
type == NSRightMouseDragged ||
|
||||
type == NSRightMouseUp;
|
||||
}
|
||||
|
||||
bool isMiddleButtonEvent(NSEvent* event) {
|
||||
if ([event buttonNumber] != 2)
|
||||
return false;
|
||||
|
||||
NSEventType type = [event type];
|
||||
return type == NSOtherMouseDown ||
|
||||
type == NSOtherMouseDragged ||
|
||||
type == NSOtherMouseUp;
|
||||
}
|
||||
|
||||
int EventFlagsFromNSEventWithModifiers(NSEvent* event, NSUInteger modifiers) {
|
||||
int flags = 0;
|
||||
flags |= (modifiers & NSAlphaShiftKeyMask) ? ui::EF_CAPS_LOCK_DOWN : 0;
|
||||
flags |= (modifiers & NSShiftKeyMask) ? ui::EF_SHIFT_DOWN : 0;
|
||||
flags |= (modifiers & NSControlKeyMask) ? ui::EF_CONTROL_DOWN : 0;
|
||||
flags |= (modifiers & NSAlternateKeyMask) ? ui::EF_ALT_DOWN : 0;
|
||||
flags |= (modifiers & NSCommandKeyMask) ? ui::EF_COMMAND_DOWN : 0;
|
||||
flags |= isLeftButtonEvent(event) ? ui::EF_LEFT_MOUSE_BUTTON : 0;
|
||||
flags |= isRightButtonEvent(event) ? ui::EF_RIGHT_MOUSE_BUTTON : 0;
|
||||
flags |= isMiddleButtonEvent(event) ? ui::EF_MIDDLE_MOUSE_BUTTON : 0;
|
||||
return flags;
|
||||
}
|
||||
|
||||
// Retrieves a bitsum of ui::EventFlags from NSEvent.
|
||||
int EventFlagsFromNSEvent(NSEvent* event) {
|
||||
NSUInteger modifiers = [event modifierFlags];
|
||||
return EventFlagsFromNSEventWithModifiers(event, modifiers);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@interface AtomMenuController (Private)
|
||||
- (void)addSeparatorToMenu:(NSMenu*)menu
|
||||
atIndex:(int)index;
|
||||
@end
|
||||
|
||||
@implementation AtomMenuController
|
||||
|
||||
@synthesize model = model_;
|
||||
|
||||
- (id)init {
|
||||
self = [super init];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithModel:(ui::MenuModel*)model {
|
||||
if ((self = [super init])) {
|
||||
model_ = model;
|
||||
[self menu];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[menu_ setDelegate:nil];
|
||||
|
||||
// Close the menu if it is still open. This could happen if a tab gets closed
|
||||
// while its context menu is still open.
|
||||
[self cancel];
|
||||
|
||||
model_ = NULL;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)cancel {
|
||||
if (isMenuOpen_) {
|
||||
[menu_ cancelTracking];
|
||||
model_->MenuClosed();
|
||||
isMenuOpen_ = NO;
|
||||
}
|
||||
}
|
||||
|
||||
// Creates a NSMenu from the given model. If the model has submenus, this can
|
||||
// be invoked recursively.
|
||||
- (NSMenu*)menuFromModel:(ui::MenuModel*)model {
|
||||
NSMenu* menu = [[[NSMenu alloc] initWithTitle:@""] autorelease];
|
||||
|
||||
const int count = model->GetItemCount();
|
||||
for (int index = 0; index < count; index++) {
|
||||
if (model->GetTypeAt(index) == ui::MenuModel::TYPE_SEPARATOR)
|
||||
[self addSeparatorToMenu:menu atIndex:index];
|
||||
else
|
||||
[self addItemToMenu:menu atIndex:index fromModel:model];
|
||||
}
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
// Adds a separator item at the given index. As the separator doesn't need
|
||||
// anything from the model, this method doesn't need the model index as the
|
||||
// other method below does.
|
||||
- (void)addSeparatorToMenu:(NSMenu*)menu
|
||||
atIndex:(int)index {
|
||||
NSMenuItem* separator = [NSMenuItem separatorItem];
|
||||
[menu insertItem:separator atIndex:index];
|
||||
}
|
||||
|
||||
// Adds an item or a hierarchical menu to the item at the |index|,
|
||||
// associated with the entry in the model identified by |modelIndex|.
|
||||
- (void)addItemToMenu:(NSMenu*)menu
|
||||
atIndex:(NSInteger)index
|
||||
fromModel:(ui::MenuModel*)model {
|
||||
string16 label16 = model->GetLabelAt(index);
|
||||
NSString* label = l10n_util::FixUpWindowsStyleLabel(label16);
|
||||
scoped_nsobject<NSMenuItem> item(
|
||||
[[NSMenuItem alloc] initWithTitle:label
|
||||
action:@selector(itemSelected:)
|
||||
keyEquivalent:@""]);
|
||||
|
||||
// If the menu item has an icon, set it.
|
||||
gfx::Image icon;
|
||||
if (model->GetIconAt(index, &icon) && !icon.IsEmpty())
|
||||
[item setImage:icon.ToNSImage()];
|
||||
|
||||
ui::MenuModel::ItemType type = model->GetTypeAt(index);
|
||||
if (type == ui::MenuModel::TYPE_SUBMENU) {
|
||||
// Recursively build a submenu from the sub-model at this index.
|
||||
[item setTarget:nil];
|
||||
[item setAction:nil];
|
||||
ui::MenuModel* submenuModel = model->GetSubmenuModelAt(index);
|
||||
NSMenu* submenu =
|
||||
[self menuFromModel:(ui::SimpleMenuModel*)submenuModel];
|
||||
[submenu setTitle:[item title]];
|
||||
[item setSubmenu:submenu];
|
||||
|
||||
// Hack to set window menu.
|
||||
if ([[item title] isEqualToString:@"Window"] && [submenu numberOfItems] > 0)
|
||||
[NSApp setWindowsMenu: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
|
||||
// the model so hierarchical menus check the correct index in the correct
|
||||
// model. Setting the target to |self| allows this class to participate
|
||||
// in validation of the menu items.
|
||||
[item setTag:index];
|
||||
[item setTarget:self];
|
||||
NSValue* modelObject = [NSValue valueWithPointer:model];
|
||||
[item setRepresentedObject:modelObject]; // Retains |modelObject|.
|
||||
ui::Accelerator accelerator;
|
||||
if (model->GetAcceleratorAt(index, &accelerator)) {
|
||||
const ui::PlatformAcceleratorCocoa* platformAccelerator =
|
||||
static_cast<const ui::PlatformAcceleratorCocoa*>(
|
||||
accelerator.platform_accelerator());
|
||||
if (platformAccelerator) {
|
||||
[item setKeyEquivalent:platformAccelerator->characters()];
|
||||
[item setKeyEquivalentModifierMask:
|
||||
platformAccelerator->modifier_mask()];
|
||||
}
|
||||
}
|
||||
}
|
||||
[menu insertItem:item atIndex:index];
|
||||
}
|
||||
|
||||
// Called before the menu is to be displayed to update the state (enabled,
|
||||
// radio, etc) of each item in the menu. Also will update the title if
|
||||
// the item is marked as "dynamic".
|
||||
- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
|
||||
SEL action = [item action];
|
||||
if (action != @selector(itemSelected:))
|
||||
return NO;
|
||||
|
||||
NSInteger modelIndex = [item tag];
|
||||
ui::MenuModel* model =
|
||||
static_cast<ui::MenuModel*>(
|
||||
[[(id)item representedObject] pointerValue]);
|
||||
DCHECK(model);
|
||||
if (model) {
|
||||
BOOL checked = model->IsItemCheckedAt(modelIndex);
|
||||
DCHECK([(id)item isKindOfClass:[NSMenuItem class]]);
|
||||
[(id)item setState:(checked ? NSOnState : NSOffState)];
|
||||
[(id)item setHidden:(!model->IsVisibleAt(modelIndex))];
|
||||
if (model->IsItemDynamicAt(modelIndex)) {
|
||||
// Update the label and the icon.
|
||||
NSString* label =
|
||||
l10n_util::FixUpWindowsStyleLabel(model->GetLabelAt(modelIndex));
|
||||
[(id)item setTitle:label];
|
||||
|
||||
gfx::Image icon;
|
||||
model->GetIconAt(modelIndex, &icon);
|
||||
[(id)item setImage:icon.IsEmpty() ? nil : icon.ToNSImage()];
|
||||
}
|
||||
return model->IsEnabledAt(modelIndex);
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Called when the user chooses a particular menu item. |sender| is the menu
|
||||
// item chosen.
|
||||
- (void)itemSelected:(id)sender {
|
||||
NSInteger modelIndex = [sender tag];
|
||||
ui::MenuModel* model =
|
||||
static_cast<ui::MenuModel*>(
|
||||
[[sender representedObject] pointerValue]);
|
||||
DCHECK(model);
|
||||
if (model) {
|
||||
int event_flags = EventFlagsFromNSEvent([NSApp currentEvent]);
|
||||
model->ActivatedAt(modelIndex, event_flags);
|
||||
}
|
||||
}
|
||||
|
||||
- (NSMenu*)menu {
|
||||
if (!menu_ && model_) {
|
||||
menu_.reset([[self menuFromModel:model_] retain]);
|
||||
[menu_ setDelegate:self];
|
||||
}
|
||||
return menu_.get();
|
||||
}
|
||||
|
||||
- (BOOL)isMenuOpen {
|
||||
return isMenuOpen_;
|
||||
}
|
||||
|
||||
- (void)menuWillOpen:(NSMenu*)menu {
|
||||
isMenuOpen_ = YES;
|
||||
model_->MenuWillShow();
|
||||
}
|
||||
|
||||
- (void)menuDidClose:(NSMenu*)menu {
|
||||
if (isMenuOpen_) {
|
||||
model_->MenuClosed();
|
||||
isMenuOpen_ = NO;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
57
browser/ui/file_dialog.h
Normal file
57
browser/ui/file_dialog.h
Normal file
@@ -0,0 +1,57 @@
|
||||
// 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 BROWSER_UI_FILE_DIALOG_H_
|
||||
#define BROWSER_UI_FILE_DIALOG_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/callback_forward.h"
|
||||
#include "base/files/file_path.h"
|
||||
|
||||
namespace atom {
|
||||
class NativeWindow;
|
||||
}
|
||||
|
||||
namespace file_dialog {
|
||||
|
||||
enum FileDialogProperty {
|
||||
FILE_DIALOG_OPEN_FILE = 1,
|
||||
FILE_DIALOG_OPEN_DIRECTORY = 2,
|
||||
FILE_DIALOG_MULTI_SELECTIONS = 4,
|
||||
FILE_DIALOG_CREATE_DIRECTORY = 8,
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
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_
|
||||
168
browser/ui/file_dialog_mac.mm
Normal file
168
browser/ui/file_dialog_mac.mm
Normal file
@@ -0,0 +1,168 @@
|
||||
// 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/ui/file_dialog.h"
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#include <CoreServices/CoreServices.h>
|
||||
|
||||
#include "base/file_util.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "browser/native_window.h"
|
||||
|
||||
namespace file_dialog {
|
||||
|
||||
namespace {
|
||||
|
||||
void SetupDialog(NSSavePanel* dialog,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path) {
|
||||
if (!title.empty())
|
||||
[dialog setTitle:base::SysUTF8ToNSString(title)];
|
||||
|
||||
NSString* default_dir = nil;
|
||||
NSString* default_filename = nil;
|
||||
if (!default_path.empty()) {
|
||||
if (file_util::DirectoryExists(default_path)) {
|
||||
default_dir = base::SysUTF8ToNSString(default_path.value());
|
||||
} else {
|
||||
default_dir = base::SysUTF8ToNSString(default_path.DirName().value());
|
||||
default_filename =
|
||||
base::SysUTF8ToNSString(default_path.BaseName().value());
|
||||
}
|
||||
}
|
||||
|
||||
if (default_dir)
|
||||
[dialog setDirectoryURL:[NSURL fileURLWithPath:default_dir]];
|
||||
if (default_filename)
|
||||
[dialog setNameFieldStringValue:default_filename];
|
||||
|
||||
[dialog setCanSelectHiddenExtension:YES];
|
||||
[dialog setAllowsOtherFileTypes:YES];
|
||||
}
|
||||
|
||||
void SetupDialogForProperties(NSOpenPanel* dialog, int properties) {
|
||||
[dialog setCanChooseFiles:(properties & FILE_DIALOG_OPEN_FILE)];
|
||||
if (properties & FILE_DIALOG_OPEN_DIRECTORY)
|
||||
[dialog setCanChooseDirectories:YES];
|
||||
if (properties & FILE_DIALOG_CREATE_DIRECTORY)
|
||||
[dialog setCanCreateDirectories:YES];
|
||||
if (properties & FILE_DIALOG_MULTI_SELECTIONS)
|
||||
[dialog setAllowsMultipleSelection:YES];
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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(path);
|
||||
NSSavePanel* dialog = [NSSavePanel savePanel];
|
||||
|
||||
SetupDialog(dialog, title, default_path);
|
||||
|
||||
int chosen = RunModalDialog(dialog, parent_window);
|
||||
if (chosen == NSFileHandlingPanelCancelButton || ![[dialog URL] isFileURL])
|
||||
return false;
|
||||
|
||||
*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) {
|
||||
callback.Run(false, base::FilePath());
|
||||
} else {
|
||||
std::string path = base::SysNSStringToUTF8([[dialog URL] path]);
|
||||
callback.Run(true, base::FilePath(path));
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
} // namespace file_dialog
|
||||
318
browser/ui/file_dialog_win.cc
Normal file
318
browser/ui/file_dialog_win.cc
Normal file
@@ -0,0 +1,318 @@
|
||||
// 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/ui/file_dialog.h"
|
||||
|
||||
#include <atlbase.h>
|
||||
#include <windows.h>
|
||||
#include <commdlg.h>
|
||||
#include <shlobj.h>
|
||||
|
||||
#include "base/file_util.h"
|
||||
#include "base/i18n/case_conversion.h"
|
||||
#include "base/string_util.h"
|
||||
#include "base/strings/string_split.h"
|
||||
#include "base/utf_string_conversions.h"
|
||||
#include "base/win/registry.h"
|
||||
#include "browser/native_window.h"
|
||||
#include "third_party/wtl/include/atlapp.h"
|
||||
#include "third_party/wtl/include/atldlgs.h"
|
||||
|
||||
namespace file_dialog {
|
||||
|
||||
namespace {
|
||||
|
||||
// Distinguish directories from regular files.
|
||||
bool IsDirectory(const base::FilePath& path) {
|
||||
base::PlatformFileInfo file_info;
|
||||
return file_util::GetFileInfo(path, &file_info) ?
|
||||
file_info.is_directory : path.EndsWithSeparator();
|
||||
}
|
||||
|
||||
// Get the file type description from the registry. This will be "Text Document"
|
||||
// for .txt files, "JPEG Image" for .jpg files, etc. If the registry doesn't
|
||||
// have an entry for the file type, we return false, true if the description was
|
||||
// found. 'file_ext' must be in form ".txt".
|
||||
static bool GetRegistryDescriptionFromExtension(const std::wstring& file_ext,
|
||||
std::wstring* reg_description) {
|
||||
DCHECK(reg_description);
|
||||
base::win::RegKey reg_ext(HKEY_CLASSES_ROOT, file_ext.c_str(), KEY_READ);
|
||||
std::wstring reg_app;
|
||||
if (reg_ext.ReadValue(NULL, ®_app) == ERROR_SUCCESS && !reg_app.empty()) {
|
||||
base::win::RegKey reg_link(HKEY_CLASSES_ROOT, reg_app.c_str(), KEY_READ);
|
||||
if (reg_link.ReadValue(NULL, reg_description) == ERROR_SUCCESS)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set up a filter for a Save/Open dialog, which will consist of |file_ext| file
|
||||
// extensions (internally separated by semicolons), |ext_desc| as the text
|
||||
// descriptions of the |file_ext| types (optional), and (optionally) the default
|
||||
// 'All Files' view. The purpose of the filter is to show only files of a
|
||||
// particular type in a Windows Save/Open dialog box. The resulting filter is
|
||||
// returned. The filters created here are:
|
||||
// 1. only files that have 'file_ext' as their extension
|
||||
// 2. all files (only added if 'include_all_files' is true)
|
||||
// Example:
|
||||
// file_ext: { "*.txt", "*.htm;*.html" }
|
||||
// ext_desc: { "Text Document" }
|
||||
// returned: "Text Document\0*.txt\0HTML Document\0*.htm;*.html\0"
|
||||
// "All Files\0*.*\0\0" (in one big string)
|
||||
// If a description is not provided for a file extension, it will be retrieved
|
||||
// from the registry. If the file extension does not exist in the registry, it
|
||||
// will be omitted from the filter, as it is likely a bogus extension.
|
||||
void FormatFilterForExtensions(
|
||||
std::vector<std::wstring>* file_ext,
|
||||
std::vector<std::wstring>* ext_desc,
|
||||
bool include_all_files,
|
||||
std::vector<COMDLG_FILTERSPEC>* file_types) {
|
||||
DCHECK(file_ext->size() >= ext_desc->size());
|
||||
|
||||
if (file_ext->empty())
|
||||
include_all_files = true;
|
||||
|
||||
for (size_t i = 0; i < file_ext->size(); ++i) {
|
||||
std::wstring ext = (*file_ext)[i];
|
||||
std::wstring desc;
|
||||
if (i < ext_desc->size())
|
||||
desc = (*ext_desc)[i];
|
||||
|
||||
if (ext.empty()) {
|
||||
// Force something reasonable to appear in the dialog box if there is no
|
||||
// extension provided.
|
||||
include_all_files = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (desc.empty()) {
|
||||
DCHECK(ext.find(L'.') != std::wstring::npos);
|
||||
std::wstring first_extension = ext.substr(ext.find(L'.'));
|
||||
size_t first_separator_index = first_extension.find(L';');
|
||||
if (first_separator_index != std::wstring::npos)
|
||||
first_extension = first_extension.substr(0, first_separator_index);
|
||||
|
||||
// Find the extension name without the preceeding '.' character.
|
||||
std::wstring ext_name = first_extension;
|
||||
size_t ext_index = ext_name.find_first_not_of(L'.');
|
||||
if (ext_index != std::wstring::npos)
|
||||
ext_name = ext_name.substr(ext_index);
|
||||
|
||||
if (!GetRegistryDescriptionFromExtension(first_extension, &desc)) {
|
||||
// The extension doesn't exist in the registry. Create a description
|
||||
// based on the unknown extension type (i.e. if the extension is .qqq,
|
||||
// the we create a description "QQQ File (.qqq)").
|
||||
include_all_files = true;
|
||||
// TODO(zcbenz): should be localized.
|
||||
desc = base::i18n::ToUpper(WideToUTF16(ext_name)) + L" File";
|
||||
}
|
||||
desc += L" (*." + ext_name + L")";
|
||||
|
||||
// Store the description.
|
||||
ext_desc->push_back(desc);
|
||||
}
|
||||
|
||||
COMDLG_FILTERSPEC spec = { (*ext_desc)[i].c_str(), (*file_ext)[i].c_str() };
|
||||
file_types->push_back(spec);
|
||||
}
|
||||
|
||||
if (include_all_files) {
|
||||
// TODO(zcbenz): Should be localized.
|
||||
ext_desc->push_back(L"All Files (*.*)");
|
||||
file_ext->push_back(L"*.*");
|
||||
|
||||
COMDLG_FILTERSPEC spec = {
|
||||
(*ext_desc)[ext_desc->size() - 1].c_str(),
|
||||
(*file_ext)[file_ext->size() - 1].c_str(),
|
||||
};
|
||||
file_types->push_back(spec);
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
bool Show(atom::NativeWindow* parent_window) {
|
||||
HWND window = parent_window ? parent_window->GetNativeWindow() : NULL;
|
||||
return dialog_->DoModal(window) == IDOK;
|
||||
}
|
||||
|
||||
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(atom::NativeWindow* parent_window,
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
int properties,
|
||||
std::vector<base::FilePath>* paths) {
|
||||
int options = FOS_FORCEFILESYSTEM | FOS_FILEMUSTEXIST;
|
||||
if (properties & FILE_DIALOG_OPEN_DIRECTORY)
|
||||
options |= FOS_PICKFOLDERS;
|
||||
if (properties & FILE_DIALOG_MULTI_SELECTIONS)
|
||||
options |= FOS_ALLOWMULTISELECT;
|
||||
|
||||
FileDialog<CShellFileOpenDialog> open_dialog(
|
||||
default_path,
|
||||
title,
|
||||
options,
|
||||
std::vector<std::wstring>(),
|
||||
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 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
|
||||
@@ -2,12 +2,14 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BROWSER_MESSAGE_BOX_H_
|
||||
#define BROWSER_MESSAGE_BOX_H_
|
||||
#ifndef BROWSER_UI_MESSAGE_BOX_H_
|
||||
#define BROWSER_UI_MESSAGE_BOX_H_
|
||||
|
||||
#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_MESSAGE_BOX_H_
|
||||
#endif // BROWSER_UI_MESSAGE_BOX_H_
|
||||
116
browser/ui/message_box_mac.mm
Normal file
116
browser/ui/message_box_mac.mm
Normal file
@@ -0,0 +1,116 @@
|
||||
// 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/ui/message_box.h"
|
||||
|
||||
#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 {
|
||||
|
||||
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];
|
||||
[alert setMessageText:base::SysUTF8ToNSString(message)];
|
||||
[alert setInformativeText:base::SysUTF8ToNSString(detail)];
|
||||
|
||||
switch (type) {
|
||||
case MESSAGE_BOX_TYPE_INFORMATION:
|
||||
[alert setAlertStyle:NSInformationalAlertStyle];
|
||||
break;
|
||||
case MESSAGE_BOX_TYPE_WARNING:
|
||||
[alert setAlertStyle:NSWarningAlertStyle];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < buttons.size(); ++i) {
|
||||
NSString* title = base::SysUTF8ToNSString(buttons[i]);
|
||||
NSButton* button = [alert addButtonWithTitle:title];
|
||||
[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
|
||||
@@ -2,8 +2,9 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "browser/message_box.h"
|
||||
#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,11 +92,12 @@ 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),
|
||||
message_box_view_(NULL) {
|
||||
DCHECK(buttons.size() > 0);
|
||||
DCHECK_GT(buttons.size(), 0u);
|
||||
set_owned_by_client();
|
||||
|
||||
views::MessageBoxView::InitParams params(UTF8ToUTF16(title));
|
||||
@@ -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() {
|
||||
@@ -195,7 +229,10 @@ void MessageDialog::Layout() {
|
||||
int x = bounds.width();
|
||||
int height = buttons_[0]->GetPreferredSize().height() +
|
||||
views::kRelatedControlVerticalSpacing;
|
||||
for (size_t i = 0; i < buttons_.size(); ++i) {
|
||||
|
||||
// NB: We iterate through the buttons backwards here because
|
||||
// Mac and Windows buttons are laid out in opposite order.
|
||||
for (int i = buttons_.size() - 1; i >= 0; --i) {
|
||||
gfx::Size size = buttons_[i]->GetPreferredSize();
|
||||
x -= size.width() + views::kRelatedButtonHSpacing;
|
||||
|
||||
@@ -229,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());
|
||||
@@ -236,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
|
||||
@@ -1,7 +1,8 @@
|
||||
// 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.
|
||||
|
||||
#import "browser/nsalert_synchronous_sheet.h"
|
||||
#import "browser/ui/nsalert_synchronous_sheet_mac.h"
|
||||
|
||||
// Private methods -- use prefixes to avoid collisions with Apple's methods
|
||||
@interface NSAlert (SynchronousSheetPrivate)
|
||||
65
browser/ui/win/menu_2.cc
Normal file
65
browser/ui/win/menu_2.cc
Normal file
@@ -0,0 +1,65 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// 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 "browser/ui/win/menu_2.h"
|
||||
|
||||
#include "ui/base/models/menu_model.h"
|
||||
#include "ui/views/controls/menu/menu_listener.h"
|
||||
|
||||
// Really bad hack here, renaming all class names would be too much work.
|
||||
using namespace views; // NOLINT
|
||||
|
||||
namespace atom {
|
||||
|
||||
Menu2::Menu2(ui::MenuModel* model, bool as_window_menu)
|
||||
: model_(model),
|
||||
wrapper_(new NativeMenuWin(model, NULL)) {
|
||||
wrapper_->set_create_as_window_menu(as_window_menu);
|
||||
Rebuild();
|
||||
}
|
||||
|
||||
Menu2::~Menu2() {}
|
||||
|
||||
HMENU Menu2::GetNativeMenu() const {
|
||||
return wrapper_->GetNativeMenu();
|
||||
}
|
||||
|
||||
void Menu2::RunMenuAt(const gfx::Point& point, Alignment alignment) {
|
||||
wrapper_->RunMenuAt(point, alignment);
|
||||
}
|
||||
|
||||
void Menu2::RunContextMenuAt(const gfx::Point& point) {
|
||||
RunMenuAt(point, ALIGN_TOPLEFT);
|
||||
}
|
||||
|
||||
void Menu2::CancelMenu() {
|
||||
wrapper_->CancelMenu();
|
||||
}
|
||||
|
||||
void Menu2::Rebuild() {
|
||||
wrapper_->Rebuild(NULL);
|
||||
}
|
||||
|
||||
void Menu2::UpdateStates() {
|
||||
wrapper_->UpdateStates();
|
||||
}
|
||||
|
||||
NativeMenuWin::MenuAction Menu2::GetMenuAction() const {
|
||||
return wrapper_->GetMenuAction();
|
||||
}
|
||||
|
||||
void Menu2::AddMenuListener(MenuListener* listener) {
|
||||
wrapper_->AddMenuListener(listener);
|
||||
}
|
||||
|
||||
void Menu2::RemoveMenuListener(MenuListener* listener) {
|
||||
wrapper_->RemoveMenuListener(listener);
|
||||
}
|
||||
|
||||
void Menu2::SetMinimumWidth(int width) {
|
||||
wrapper_->SetMinimumWidth(width);
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
95
browser/ui/win/menu_2.h
Normal file
95
browser/ui/win/menu_2.h
Normal file
@@ -0,0 +1,95 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// 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 BROWSER_UI_WIN_MENU_2_H_
|
||||
#define BROWSER_UI_WIN_MENU_2_H_
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "browser/ui/win/native_menu_win.h"
|
||||
#include "ui/gfx/native_widget_types.h"
|
||||
|
||||
namespace gfx {
|
||||
class Point;
|
||||
}
|
||||
|
||||
namespace ui {
|
||||
class MenuModel;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
// A menu. Populated from a model, and relies on a delegate to execute commands.
|
||||
//
|
||||
// WARNING: do NOT create and use Menu2 on the stack. Menu2 notifies the model
|
||||
// of selection AFTER a delay. This means that if use a Menu2 on the stack
|
||||
// ActivatedAt is never invoked.
|
||||
class Menu2 {
|
||||
public:
|
||||
// How the menu is aligned relative to the point it is shown at.
|
||||
// The alignment is reversed by menu if text direction is right to left.
|
||||
enum Alignment {
|
||||
ALIGN_TOPLEFT,
|
||||
ALIGN_TOPRIGHT
|
||||
};
|
||||
|
||||
// Creates a new menu populated with the contents of |model|.
|
||||
// WARNING: this populates the menu on construction by invoking methods on
|
||||
// the model. As such, it is typically not safe to use this as the model
|
||||
// from the constructor. EG:
|
||||
// MyClass : menu_(this) {}
|
||||
// is likely to have problems.
|
||||
explicit Menu2(ui::MenuModel* model, bool as_window_menu = false);
|
||||
virtual ~Menu2();
|
||||
|
||||
// Runs the menu at the specified point. This method blocks until done.
|
||||
// RunContextMenuAt is the same, but the alignment is the default for a
|
||||
// context menu.
|
||||
void RunMenuAt(const gfx::Point& point, Alignment alignment);
|
||||
void RunContextMenuAt(const gfx::Point& point);
|
||||
|
||||
// Cancels the active menu.
|
||||
void CancelMenu();
|
||||
|
||||
// Called when the model supplying data to this menu has changed, and the menu
|
||||
// must be rebuilt.
|
||||
void Rebuild();
|
||||
|
||||
// Called when the states of the menu items in the menu should be refreshed
|
||||
// from the model.
|
||||
void UpdateStates();
|
||||
|
||||
// For submenus.
|
||||
HMENU GetNativeMenu() const;
|
||||
|
||||
// Get the result of the last call to RunMenuAt to determine whether an
|
||||
// item was selected, the user navigated to a next or previous menu, or
|
||||
// nothing.
|
||||
NativeMenuWin::MenuAction GetMenuAction() const;
|
||||
|
||||
// Add a listener to receive a callback when the menu opens.
|
||||
void AddMenuListener(views::MenuListener* listener);
|
||||
|
||||
// Remove a menu listener.
|
||||
void RemoveMenuListener(views::MenuListener* listener);
|
||||
|
||||
// Accessors.
|
||||
ui::MenuModel* model() const { return model_; }
|
||||
|
||||
// Sets the minimum width of the menu.
|
||||
void SetMinimumWidth(int width);
|
||||
|
||||
private:
|
||||
ui::MenuModel* model_;
|
||||
|
||||
// The object that actually implements the menu.
|
||||
scoped_ptr<NativeMenuWin> wrapper_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Menu2);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // BROWSER_UI_WIN_MENU_2_H_
|
||||
761
browser/ui/win/native_menu_win.cc
Normal file
761
browser/ui/win/native_menu_win.cc
Normal file
@@ -0,0 +1,761 @@
|
||||
// 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 "browser/ui/win/native_menu_win.h"
|
||||
|
||||
#include <Windowsx.h>
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/message_loop.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "base/string_util.h"
|
||||
#include "base/win/wrapped_window_proc.h"
|
||||
#include "browser/ui/win/menu_2.h"
|
||||
#include "ui/base/accelerators/accelerator.h"
|
||||
#include "ui/base/keycodes/keyboard_codes.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "ui/base/l10n/l10n_util_win.h"
|
||||
#include "ui/base/models/menu_model.h"
|
||||
#include "ui/base/win/hwnd_util.h"
|
||||
#include "ui/gfx/canvas.h"
|
||||
#include "ui/gfx/font.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
#include "ui/gfx/image/image_skia.h"
|
||||
#include "ui/gfx/rect.h"
|
||||
#include "ui/native_theme/native_theme.h"
|
||||
#include "ui/native_theme/native_theme_win.h"
|
||||
#include "ui/views/controls/menu/menu_config.h"
|
||||
#include "ui/views/controls/menu/menu_insertion_delegate_win.h"
|
||||
#include "ui/views/controls/menu/menu_listener.h"
|
||||
|
||||
using ui::NativeTheme;
|
||||
|
||||
// Really bad hack here, renaming all class names would be too much work.
|
||||
using namespace views; // NOLINT
|
||||
|
||||
namespace atom {
|
||||
|
||||
// The width of an icon, including the pixels between the icon and
|
||||
// the item label.
|
||||
static const int kIconWidth = 23;
|
||||
// Margins between the top of the item and the label.
|
||||
static const int kItemTopMargin = 3;
|
||||
// Margins between the bottom of the item and the label.
|
||||
static const int kItemBottomMargin = 4;
|
||||
// Margins between the left of the item and the icon.
|
||||
static const int kItemLeftMargin = 4;
|
||||
// Margins between the right of the item and the label.
|
||||
static const int kItemRightMargin = 10;
|
||||
// The width for displaying the sub-menu arrow.
|
||||
static const int kArrowWidth = 10;
|
||||
|
||||
struct NativeMenuWin::ItemData {
|
||||
// The Windows API requires that whoever creates the menus must own the
|
||||
// strings used for labels, and keep them around for the lifetime of the
|
||||
// created menu. So be it.
|
||||
string16 label;
|
||||
|
||||
// Someone needs to own submenus, it may as well be us.
|
||||
scoped_ptr<Menu2> submenu;
|
||||
|
||||
// We need a pointer back to the containing menu in various circumstances.
|
||||
NativeMenuWin* native_menu_win;
|
||||
|
||||
// The index of the item within the menu's model.
|
||||
int model_index;
|
||||
};
|
||||
|
||||
// Returns the NativeMenuWin for a particular HMENU.
|
||||
static NativeMenuWin* GetNativeMenuWinFromHMENU(HMENU hmenu) {
|
||||
MENUINFO mi = {0};
|
||||
mi.cbSize = sizeof(mi);
|
||||
mi.fMask = MIM_MENUDATA | MIM_STYLE;
|
||||
GetMenuInfo(hmenu, &mi);
|
||||
return reinterpret_cast<NativeMenuWin*>(mi.dwMenuData);
|
||||
}
|
||||
|
||||
// A window that receives messages from Windows relevant to the native menu
|
||||
// structure we have constructed in NativeMenuWin.
|
||||
class NativeMenuWin::MenuHostWindow {
|
||||
public:
|
||||
explicit MenuHostWindow(NativeMenuWin* parent) : parent_(parent) {
|
||||
RegisterClass();
|
||||
hwnd_ = CreateWindowEx(l10n_util::GetExtendedStyles(), kWindowClassName,
|
||||
L"", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
|
||||
ui::CheckWindowCreated(hwnd_);
|
||||
ui::SetWindowUserData(hwnd_, this);
|
||||
}
|
||||
|
||||
~MenuHostWindow() {
|
||||
DestroyWindow(hwnd_);
|
||||
}
|
||||
|
||||
HWND hwnd() const { return hwnd_; }
|
||||
|
||||
private:
|
||||
static const wchar_t* kWindowClassName;
|
||||
|
||||
void RegisterClass() {
|
||||
static bool registered = false;
|
||||
if (registered)
|
||||
return;
|
||||
|
||||
WNDCLASSEX window_class;
|
||||
base::win::InitializeWindowClass(
|
||||
kWindowClassName,
|
||||
&base::win::WrappedWindowProc<MenuHostWindowProc>,
|
||||
CS_DBLCLKS,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
reinterpret_cast<HBRUSH>(COLOR_WINDOW+1),
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&window_class);
|
||||
ATOM clazz = RegisterClassEx(&window_class);
|
||||
CHECK(clazz);
|
||||
registered = true;
|
||||
}
|
||||
|
||||
// Converts the WPARAM value passed to WM_MENUSELECT into an index
|
||||
// corresponding to the menu item that was selected.
|
||||
int GetMenuItemIndexFromWPARAM(HMENU menu, WPARAM w_param) const {
|
||||
int count = GetMenuItemCount(menu);
|
||||
// For normal command menu items, Windows passes a command id as the LOWORD
|
||||
// of WPARAM for WM_MENUSELECT. We need to walk forward through the menu
|
||||
// items to find an item with a matching ID. Ugh!
|
||||
for (int i = 0; i < count; ++i) {
|
||||
MENUITEMINFO mii = {0};
|
||||
mii.cbSize = sizeof(mii);
|
||||
mii.fMask = MIIM_ID;
|
||||
GetMenuItemInfo(menu, i, MF_BYPOSITION, &mii);
|
||||
if (mii.wID == w_param)
|
||||
return i;
|
||||
}
|
||||
// If we didn't find a matching command ID, this means a submenu has been
|
||||
// selected instead, and rather than passing a command ID in
|
||||
// LOWORD(w_param), Windows has actually passed us a position, so we just
|
||||
// return it.
|
||||
return w_param;
|
||||
}
|
||||
|
||||
NativeMenuWin::ItemData* GetItemData(ULONG_PTR item_data) {
|
||||
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) {
|
||||
if (!menu)
|
||||
return; // menu is null when closing on XP.
|
||||
|
||||
int position = GetMenuItemIndexFromWPARAM(menu, w_param);
|
||||
if (position >= 0)
|
||||
GetNativeMenuWinFromHMENU(menu)->model_->HighlightChangedTo(position);
|
||||
}
|
||||
|
||||
// Called by Windows to measure the size of an owner-drawn menu item.
|
||||
void OnMeasureItem(WPARAM w_param, MEASUREITEMSTRUCT* measure_item_struct) {
|
||||
NativeMenuWin::ItemData* data = GetItemData(measure_item_struct->itemData);
|
||||
if (data) {
|
||||
gfx::Font font;
|
||||
measure_item_struct->itemWidth = font.GetStringWidth(data->label) +
|
||||
kIconWidth + kItemLeftMargin + kItemRightMargin -
|
||||
GetSystemMetrics(SM_CXMENUCHECK);
|
||||
if (data->submenu.get())
|
||||
measure_item_struct->itemWidth += kArrowWidth;
|
||||
// If the label contains an accelerator, make room for tab.
|
||||
if (data->label.find(L'\t') != string16::npos)
|
||||
measure_item_struct->itemWidth += font.GetStringWidth(L" ");
|
||||
measure_item_struct->itemHeight =
|
||||
font.GetHeight() + kItemBottomMargin + kItemTopMargin;
|
||||
} else {
|
||||
// Measure separator size.
|
||||
measure_item_struct->itemHeight = GetSystemMetrics(SM_CYMENU) / 2;
|
||||
measure_item_struct->itemWidth = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Called by Windows to paint an owner-drawn menu item.
|
||||
void OnDrawItem(UINT w_param, DRAWITEMSTRUCT* draw_item_struct) {
|
||||
HDC dc = draw_item_struct->hDC;
|
||||
COLORREF prev_bg_color, prev_text_color;
|
||||
|
||||
// Set background color and text color
|
||||
if (draw_item_struct->itemState & ODS_SELECTED) {
|
||||
prev_bg_color = SetBkColor(dc, GetSysColor(COLOR_HIGHLIGHT));
|
||||
prev_text_color = SetTextColor(dc, GetSysColor(COLOR_HIGHLIGHTTEXT));
|
||||
} else {
|
||||
prev_bg_color = SetBkColor(dc, GetSysColor(COLOR_MENU));
|
||||
if (draw_item_struct->itemState & ODS_DISABLED)
|
||||
prev_text_color = SetTextColor(dc, GetSysColor(COLOR_GRAYTEXT));
|
||||
else
|
||||
prev_text_color = SetTextColor(dc, GetSysColor(COLOR_MENUTEXT));
|
||||
}
|
||||
|
||||
if (draw_item_struct->itemData) {
|
||||
NativeMenuWin::ItemData* data = GetItemData(draw_item_struct->itemData);
|
||||
// Draw the background.
|
||||
HBRUSH hbr = CreateSolidBrush(GetBkColor(dc));
|
||||
FillRect(dc, &draw_item_struct->rcItem, hbr);
|
||||
DeleteObject(hbr);
|
||||
|
||||
// Draw the label.
|
||||
RECT rect = draw_item_struct->rcItem;
|
||||
rect.top += kItemTopMargin;
|
||||
// Should we add kIconWidth only when icon.width() != 0 ?
|
||||
rect.left += kItemLeftMargin + kIconWidth;
|
||||
rect.right -= kItemRightMargin;
|
||||
UINT format = DT_TOP | DT_SINGLELINE;
|
||||
// Check whether the mnemonics should be underlined.
|
||||
BOOL underline_mnemonics;
|
||||
SystemParametersInfo(SPI_GETKEYBOARDCUES, 0, &underline_mnemonics, 0);
|
||||
if (!underline_mnemonics)
|
||||
format |= DT_HIDEPREFIX;
|
||||
gfx::Font font;
|
||||
HGDIOBJ old_font =
|
||||
static_cast<HFONT>(SelectObject(dc, font.GetNativeFont()));
|
||||
|
||||
// If an accelerator is specified (with a tab delimiting the rest of the
|
||||
// label from the accelerator), we have to justify the fist part on the
|
||||
// left and the accelerator on the right.
|
||||
// TODO(jungshik): This will break in RTL UI. Currently, he/ar use the
|
||||
// window system UI font and will not hit here.
|
||||
string16 label = data->label;
|
||||
string16 accel;
|
||||
string16::size_type tab_pos = label.find(L'\t');
|
||||
if (tab_pos != string16::npos) {
|
||||
accel = label.substr(tab_pos);
|
||||
label = label.substr(0, tab_pos);
|
||||
}
|
||||
DrawTextEx(dc, const_cast<wchar_t*>(label.data()),
|
||||
static_cast<int>(label.size()), &rect, format | DT_LEFT, NULL);
|
||||
if (!accel.empty())
|
||||
DrawTextEx(dc, const_cast<wchar_t*>(accel.data()),
|
||||
static_cast<int>(accel.size()), &rect,
|
||||
format | DT_RIGHT, NULL);
|
||||
SelectObject(dc, old_font);
|
||||
|
||||
ui::MenuModel::ItemType type =
|
||||
data->native_menu_win->model_->GetTypeAt(data->model_index);
|
||||
|
||||
// Draw the icon after the label, otherwise it would be covered
|
||||
// by the label.
|
||||
gfx::Image icon;
|
||||
if (data->native_menu_win->model_->GetIconAt(data->model_index, &icon)) {
|
||||
// We currently don't support items with both icons and checkboxes.
|
||||
const gfx::ImageSkia* skia_icon = icon.ToImageSkia();
|
||||
DCHECK(type != ui::MenuModel::TYPE_CHECK);
|
||||
gfx::Canvas canvas(
|
||||
skia_icon->GetRepresentation(ui::SCALE_FACTOR_100P),
|
||||
false);
|
||||
skia::DrawToNativeContext(
|
||||
canvas.sk_canvas(), dc,
|
||||
draw_item_struct->rcItem.left + kItemLeftMargin,
|
||||
draw_item_struct->rcItem.top + (draw_item_struct->rcItem.bottom -
|
||||
draw_item_struct->rcItem.top - skia_icon->height()) / 2, NULL);
|
||||
} else if (type == ui::MenuModel::TYPE_CHECK &&
|
||||
data->native_menu_win->model_->IsItemCheckedAt(
|
||||
data->model_index)) {
|
||||
// Manually render a checkbox.
|
||||
ui::NativeThemeWin* native_theme = ui::NativeThemeWin::instance();
|
||||
const MenuConfig& config = MenuConfig::instance(native_theme);
|
||||
NativeTheme::State state;
|
||||
if (draw_item_struct->itemState & ODS_DISABLED) {
|
||||
state = NativeTheme::kDisabled;
|
||||
} else {
|
||||
state = draw_item_struct->itemState & ODS_SELECTED ?
|
||||
NativeTheme::kHovered : NativeTheme::kNormal;
|
||||
}
|
||||
int height =
|
||||
draw_item_struct->rcItem.bottom - draw_item_struct->rcItem.top;
|
||||
int icon_y = kItemTopMargin +
|
||||
(height - kItemTopMargin - kItemBottomMargin -
|
||||
config.check_height) / 2;
|
||||
gfx::Canvas canvas(gfx::Size(config.check_width, config.check_height),
|
||||
ui::SCALE_FACTOR_100P,
|
||||
false);
|
||||
NativeTheme::ExtraParams extra;
|
||||
extra.menu_check.is_radio = false;
|
||||
gfx::Rect bounds(0, 0, config.check_width, config.check_height);
|
||||
|
||||
// Draw the background and the check.
|
||||
native_theme->Paint(
|
||||
canvas.sk_canvas(), NativeTheme::kMenuCheckBackground,
|
||||
state, bounds, extra);
|
||||
native_theme->Paint(
|
||||
canvas.sk_canvas(), NativeTheme::kMenuCheck, state, bounds, extra);
|
||||
|
||||
// Draw checkbox to menu.
|
||||
skia::DrawToNativeContext(canvas.sk_canvas(), dc,
|
||||
draw_item_struct->rcItem.left + kItemLeftMargin,
|
||||
draw_item_struct->rcItem.top + (draw_item_struct->rcItem.bottom -
|
||||
draw_item_struct->rcItem.top - config.check_height) / 2, NULL);
|
||||
}
|
||||
|
||||
} else {
|
||||
// Draw the separator
|
||||
draw_item_struct->rcItem.top +=
|
||||
(draw_item_struct->rcItem.bottom - draw_item_struct->rcItem.top) / 3;
|
||||
DrawEdge(dc, &draw_item_struct->rcItem, EDGE_ETCHED, BF_TOP);
|
||||
}
|
||||
|
||||
SetBkColor(dc, prev_bg_color);
|
||||
SetTextColor(dc, prev_text_color);
|
||||
}
|
||||
|
||||
bool ProcessWindowMessage(HWND window,
|
||||
UINT message,
|
||||
WPARAM w_param,
|
||||
LPARAM l_param,
|
||||
LRESULT* l_result) {
|
||||
switch (message) {
|
||||
case WM_MENUCOMMAND:
|
||||
OnMenuCommand(w_param, reinterpret_cast<HMENU>(l_param));
|
||||
*l_result = 0;
|
||||
return true;
|
||||
case WM_MENUSELECT:
|
||||
OnMenuSelect(LOWORD(w_param), reinterpret_cast<HMENU>(l_param));
|
||||
*l_result = 0;
|
||||
return true;
|
||||
case WM_MEASUREITEM:
|
||||
OnMeasureItem(w_param, reinterpret_cast<MEASUREITEMSTRUCT*>(l_param));
|
||||
*l_result = 0;
|
||||
return true;
|
||||
case WM_DRAWITEM:
|
||||
OnDrawItem(w_param, reinterpret_cast<DRAWITEMSTRUCT*>(l_param));
|
||||
*l_result = 0;
|
||||
return true;
|
||||
// TODO(beng): bring over owner draw from old menu system.
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK MenuHostWindowProc(HWND window,
|
||||
UINT message,
|
||||
WPARAM w_param,
|
||||
LPARAM l_param) {
|
||||
MenuHostWindow* host =
|
||||
reinterpret_cast<MenuHostWindow*>(ui::GetWindowUserData(window));
|
||||
// host is null during initial construction.
|
||||
LRESULT l_result = 0;
|
||||
if (!host || !host->ProcessWindowMessage(window, message, w_param, l_param,
|
||||
&l_result)) {
|
||||
return DefWindowProc(window, message, w_param, l_param);
|
||||
}
|
||||
return l_result;
|
||||
}
|
||||
|
||||
HWND hwnd_;
|
||||
NativeMenuWin* parent_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MenuHostWindow);
|
||||
};
|
||||
|
||||
struct NativeMenuWin::HighlightedMenuItemInfo {
|
||||
HighlightedMenuItemInfo()
|
||||
: has_parent(false),
|
||||
has_submenu(false),
|
||||
menu(NULL),
|
||||
position(-1) {
|
||||
}
|
||||
|
||||
bool has_parent;
|
||||
bool has_submenu;
|
||||
|
||||
// The menu and position. These are only set for non-disabled menu items.
|
||||
NativeMenuWin* menu;
|
||||
int position;
|
||||
};
|
||||
|
||||
// static
|
||||
const wchar_t* NativeMenuWin::MenuHostWindow::kWindowClassName =
|
||||
L"ViewsMenuHostWindow";
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// NativeMenuWin, public:
|
||||
|
||||
NativeMenuWin::NativeMenuWin(ui::MenuModel* model, HWND system_menu_for)
|
||||
: model_(model),
|
||||
menu_(NULL),
|
||||
owner_draw_(l10n_util::NeedOverrideDefaultUIFont(NULL, NULL) &&
|
||||
!system_menu_for),
|
||||
system_menu_for_(system_menu_for),
|
||||
first_item_index_(0),
|
||||
menu_action_(MENU_ACTION_NONE),
|
||||
menu_to_select_(NULL),
|
||||
position_to_select_(-1),
|
||||
menu_to_select_factory_(this),
|
||||
parent_(NULL),
|
||||
destroyed_flag_(NULL),
|
||||
create_as_window_menu_(false) {
|
||||
}
|
||||
|
||||
NativeMenuWin::~NativeMenuWin() {
|
||||
if (destroyed_flag_)
|
||||
*destroyed_flag_ = true;
|
||||
STLDeleteContainerPointers(items_.begin(), items_.end());
|
||||
DestroyMenu(menu_);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// NativeMenuWin, MenuWrapper implementation:
|
||||
|
||||
void NativeMenuWin::RunMenuAt(const gfx::Point& point, int alignment) {
|
||||
CreateHostWindow();
|
||||
UpdateStates();
|
||||
UINT flags = TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RECURSE;
|
||||
flags |= GetAlignmentFlags(alignment);
|
||||
menu_action_ = MENU_ACTION_NONE;
|
||||
|
||||
// Set a hook function so we can listen for keyboard events while the
|
||||
// menu is open, and store a pointer to this object in a static
|
||||
// variable so the hook has access to it (ugly, but it's the
|
||||
// only way).
|
||||
open_native_menu_win_ = this;
|
||||
HHOOK hhook = SetWindowsHookEx(WH_MSGFILTER, MenuMessageHook,
|
||||
GetModuleHandle(NULL), ::GetCurrentThreadId());
|
||||
|
||||
// Mark that any registered listeners have not been called for this particular
|
||||
// opening of the menu.
|
||||
listeners_called_ = false;
|
||||
|
||||
// Command dispatch is done through WM_MENUCOMMAND, handled by the host
|
||||
// window.
|
||||
HWND hwnd = host_window_->hwnd();
|
||||
menu_to_select_ = NULL;
|
||||
position_to_select_ = -1;
|
||||
menu_to_select_factory_.InvalidateWeakPtrs();
|
||||
bool destroyed = false;
|
||||
destroyed_flag_ = &destroyed;
|
||||
model_->MenuWillShow();
|
||||
TrackPopupMenu(menu_, flags, point.x(), point.y(), 0, host_window_->hwnd(),
|
||||
NULL);
|
||||
UnhookWindowsHookEx(hhook);
|
||||
open_native_menu_win_ = NULL;
|
||||
if (destroyed)
|
||||
return;
|
||||
destroyed_flag_ = NULL;
|
||||
if (menu_to_select_) {
|
||||
// Folks aren't too happy if we notify immediately. In particular, notifying
|
||||
// the delegate can cause destruction leaving the stack in a weird
|
||||
// state. Instead post a task, then notify. This mirrors what WM_MENUCOMMAND
|
||||
// does.
|
||||
menu_to_select_factory_.InvalidateWeakPtrs();
|
||||
base::MessageLoop::current()->PostTask(
|
||||
FROM_HERE,
|
||||
base::Bind(&NativeMenuWin::DelayedSelect,
|
||||
menu_to_select_factory_.GetWeakPtr()));
|
||||
menu_action_ = MENU_ACTION_SELECTED;
|
||||
}
|
||||
// Send MenuClosed after we schedule the select, otherwise MenuClosed is
|
||||
// processed after the select (MenuClosed posts a delayed task too).
|
||||
model_->MenuClosed();
|
||||
}
|
||||
|
||||
void NativeMenuWin::CancelMenu() {
|
||||
EndMenu();
|
||||
}
|
||||
|
||||
void NativeMenuWin::Rebuild(MenuInsertionDelegateWin* delegate) {
|
||||
ResetNativeMenu();
|
||||
items_.clear();
|
||||
|
||||
owner_draw_ = model_->HasIcons() || owner_draw_;
|
||||
first_item_index_ = delegate ? delegate->GetInsertionIndex(menu_) : 0;
|
||||
for (int menu_index = first_item_index_;
|
||||
menu_index < first_item_index_ + model_->GetItemCount(); ++menu_index) {
|
||||
int model_index = menu_index - first_item_index_;
|
||||
if (model_->GetTypeAt(model_index) == ui::MenuModel::TYPE_SEPARATOR)
|
||||
AddSeparatorItemAt(menu_index, model_index);
|
||||
else
|
||||
AddMenuItemAt(menu_index, model_index);
|
||||
}
|
||||
}
|
||||
|
||||
void NativeMenuWin::UpdateStates() {
|
||||
// A depth-first walk of the menu items, updating states.
|
||||
int model_index = 0;
|
||||
std::vector<ItemData*>::const_iterator it;
|
||||
for (it = items_.begin(); it != items_.end(); ++it, ++model_index) {
|
||||
int menu_index = model_index + first_item_index_;
|
||||
SetMenuItemState(menu_index, model_->IsEnabledAt(model_index),
|
||||
model_->IsItemCheckedAt(model_index), false);
|
||||
if (model_->IsItemDynamicAt(model_index)) {
|
||||
// TODO(atwilson): Update the icon as well (http://crbug.com/66508).
|
||||
SetMenuItemLabel(menu_index, model_index,
|
||||
model_->GetLabelAt(model_index));
|
||||
}
|
||||
Menu2* submenu = (*it)->submenu.get();
|
||||
if (submenu)
|
||||
submenu->UpdateStates();
|
||||
}
|
||||
}
|
||||
|
||||
HMENU NativeMenuWin::GetNativeMenu() const {
|
||||
return menu_;
|
||||
}
|
||||
|
||||
NativeMenuWin::MenuAction NativeMenuWin::GetMenuAction() const {
|
||||
return menu_action_;
|
||||
}
|
||||
|
||||
void NativeMenuWin::AddMenuListener(MenuListener* listener) {
|
||||
listeners_.AddObserver(listener);
|
||||
}
|
||||
|
||||
void NativeMenuWin::RemoveMenuListener(MenuListener* listener) {
|
||||
listeners_.RemoveObserver(listener);
|
||||
}
|
||||
|
||||
void NativeMenuWin::SetMinimumWidth(int width) {
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// NativeMenuWin, private:
|
||||
|
||||
// static
|
||||
NativeMenuWin* NativeMenuWin::open_native_menu_win_ = NULL;
|
||||
|
||||
void NativeMenuWin::DelayedSelect() {
|
||||
if (menu_to_select_)
|
||||
menu_to_select_->model_->ActivatedAt(position_to_select_);
|
||||
}
|
||||
|
||||
// static
|
||||
bool NativeMenuWin::GetHighlightedMenuItemInfo(
|
||||
HMENU menu,
|
||||
HighlightedMenuItemInfo* info) {
|
||||
for (int i = 0; i < ::GetMenuItemCount(menu); i++) {
|
||||
UINT state = ::GetMenuState(menu, i, MF_BYPOSITION);
|
||||
if (state & MF_HILITE) {
|
||||
if (state & MF_POPUP) {
|
||||
HMENU submenu = GetSubMenu(menu, i);
|
||||
if (GetHighlightedMenuItemInfo(submenu, info))
|
||||
info->has_parent = true;
|
||||
else
|
||||
info->has_submenu = true;
|
||||
} else if (!(state & MF_SEPARATOR) && !(state & MF_DISABLED)) {
|
||||
info->menu = GetNativeMenuWinFromHMENU(menu);
|
||||
info->position = i;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
LRESULT CALLBACK NativeMenuWin::MenuMessageHook(
|
||||
int n_code, WPARAM w_param, LPARAM l_param) {
|
||||
LRESULT result = CallNextHookEx(NULL, n_code, w_param, l_param);
|
||||
|
||||
NativeMenuWin* this_ptr = open_native_menu_win_;
|
||||
if (!this_ptr)
|
||||
return result;
|
||||
|
||||
// The first time this hook is called, that means the menu has successfully
|
||||
// opened, so call the callback function on all of our listeners.
|
||||
if (!this_ptr->listeners_called_) {
|
||||
FOR_EACH_OBSERVER(MenuListener, this_ptr->listeners_, OnMenuOpened());
|
||||
this_ptr->listeners_called_ = true;
|
||||
}
|
||||
|
||||
MSG* msg = reinterpret_cast<MSG*>(l_param);
|
||||
if (msg->message == WM_LBUTTONUP || msg->message == WM_RBUTTONUP) {
|
||||
HighlightedMenuItemInfo info;
|
||||
if (GetHighlightedMenuItemInfo(this_ptr->menu_, &info) && info.menu) {
|
||||
// It appears that when running a menu by way of TrackPopupMenu(Ex) win32
|
||||
// gets confused if the underlying window paints itself. As its very easy
|
||||
// for the underlying window to repaint itself (especially since some menu
|
||||
// items trigger painting of the tabstrip on mouse over) we have this
|
||||
// workaround. When the mouse is released on a menu item we remember the
|
||||
// menu item and end the menu. When the nested message loop returns we
|
||||
// schedule a task to notify the model. It's still possible to get a
|
||||
// WM_MENUCOMMAND, so we have to be careful that we don't notify the model
|
||||
// twice.
|
||||
this_ptr->menu_to_select_ = info.menu;
|
||||
this_ptr->position_to_select_ = info.position;
|
||||
EndMenu();
|
||||
}
|
||||
} else if (msg->message == WM_KEYDOWN) {
|
||||
HighlightedMenuItemInfo info;
|
||||
if (GetHighlightedMenuItemInfo(this_ptr->menu_, &info)) {
|
||||
if (msg->wParam == VK_LEFT && !info.has_parent) {
|
||||
this_ptr->menu_action_ = MENU_ACTION_PREVIOUS;
|
||||
::EndMenu();
|
||||
} else if (msg->wParam == VK_RIGHT && !info.has_parent &&
|
||||
!info.has_submenu) {
|
||||
this_ptr->menu_action_ = MENU_ACTION_NEXT;
|
||||
::EndMenu();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool NativeMenuWin::IsSeparatorItemAt(int menu_index) const {
|
||||
MENUITEMINFO mii = {0};
|
||||
mii.cbSize = sizeof(mii);
|
||||
mii.fMask = MIIM_FTYPE;
|
||||
GetMenuItemInfo(menu_, menu_index, MF_BYPOSITION, &mii);
|
||||
return !!(mii.fType & MF_SEPARATOR);
|
||||
}
|
||||
|
||||
void NativeMenuWin::AddMenuItemAt(int menu_index, int model_index) {
|
||||
MENUITEMINFO mii = {0};
|
||||
mii.cbSize = sizeof(mii);
|
||||
mii.fMask = MIIM_FTYPE | MIIM_ID | MIIM_DATA;
|
||||
if (!owner_draw_)
|
||||
mii.fType = MFT_STRING;
|
||||
else
|
||||
mii.fType = MFT_OWNERDRAW;
|
||||
|
||||
ItemData* item_data = new ItemData;
|
||||
item_data->label = string16();
|
||||
ui::MenuModel::ItemType type = model_->GetTypeAt(model_index);
|
||||
if (type == ui::MenuModel::TYPE_SUBMENU) {
|
||||
item_data->submenu.reset(new Menu2(model_->GetSubmenuModelAt(model_index)));
|
||||
mii.fMask |= MIIM_SUBMENU;
|
||||
mii.hSubMenu = item_data->submenu->GetNativeMenu();
|
||||
GetNativeMenuWinFromHMENU(mii.hSubMenu)->parent_ = this;
|
||||
} else {
|
||||
if (type == ui::MenuModel::TYPE_RADIO)
|
||||
mii.fType |= MFT_RADIOCHECK;
|
||||
mii.wID = model_->GetCommandIdAt(model_index);
|
||||
}
|
||||
item_data->native_menu_win = this;
|
||||
item_data->model_index = model_index;
|
||||
items_.insert(items_.begin() + model_index, item_data);
|
||||
mii.dwItemData = reinterpret_cast<ULONG_PTR>(item_data);
|
||||
UpdateMenuItemInfoForString(&mii, model_index,
|
||||
model_->GetLabelAt(model_index));
|
||||
InsertMenuItem(menu_, menu_index, TRUE, &mii);
|
||||
}
|
||||
|
||||
void NativeMenuWin::AddSeparatorItemAt(int menu_index, int model_index) {
|
||||
MENUITEMINFO mii = {0};
|
||||
mii.cbSize = sizeof(mii);
|
||||
mii.fMask = MIIM_FTYPE;
|
||||
mii.fType = MFT_SEPARATOR;
|
||||
// Insert a dummy entry into our label list so we can index directly into it
|
||||
// using item indices if need be.
|
||||
items_.insert(items_.begin() + model_index, new ItemData);
|
||||
InsertMenuItem(menu_, menu_index, TRUE, &mii);
|
||||
}
|
||||
|
||||
void NativeMenuWin::SetMenuItemState(int menu_index, bool enabled, bool checked,
|
||||
bool is_default) {
|
||||
if (IsSeparatorItemAt(menu_index))
|
||||
return;
|
||||
|
||||
UINT state = enabled ? MFS_ENABLED : MFS_DISABLED;
|
||||
if (checked)
|
||||
state |= MFS_CHECKED;
|
||||
if (is_default)
|
||||
state |= MFS_DEFAULT;
|
||||
|
||||
MENUITEMINFO mii = {0};
|
||||
mii.cbSize = sizeof(mii);
|
||||
mii.fMask = MIIM_STATE;
|
||||
mii.fState = state;
|
||||
SetMenuItemInfo(menu_, menu_index, MF_BYPOSITION, &mii);
|
||||
}
|
||||
|
||||
void NativeMenuWin::SetMenuItemLabel(int menu_index,
|
||||
int model_index,
|
||||
const string16& label) {
|
||||
if (IsSeparatorItemAt(menu_index))
|
||||
return;
|
||||
|
||||
MENUITEMINFO mii = {0};
|
||||
mii.cbSize = sizeof(mii);
|
||||
UpdateMenuItemInfoForString(&mii, model_index, label);
|
||||
SetMenuItemInfo(menu_, menu_index, MF_BYPOSITION, &mii);
|
||||
}
|
||||
|
||||
void NativeMenuWin::UpdateMenuItemInfoForString(MENUITEMINFO* mii,
|
||||
int model_index,
|
||||
const string16& label) {
|
||||
string16 formatted = label;
|
||||
ui::MenuModel::ItemType type = model_->GetTypeAt(model_index);
|
||||
// Strip out any tabs, otherwise they get interpreted as accelerators and can
|
||||
// lead to weird behavior.
|
||||
ReplaceSubstringsAfterOffset(&formatted, 0, L"\t", L" ");
|
||||
if (type != ui::MenuModel::TYPE_SUBMENU) {
|
||||
// Add accelerator details to the label if provided.
|
||||
ui::Accelerator accelerator(ui::VKEY_UNKNOWN, ui::EF_NONE);
|
||||
if (model_->GetAcceleratorAt(model_index, &accelerator)) {
|
||||
formatted += L"\t";
|
||||
formatted += accelerator.GetShortcutText();
|
||||
}
|
||||
}
|
||||
|
||||
// Update the owned string, since Windows will want us to keep this new
|
||||
// version around.
|
||||
items_[model_index]->label = formatted;
|
||||
|
||||
// Give Windows a pointer to the label string.
|
||||
mii->fMask |= MIIM_STRING;
|
||||
mii->dwTypeData =
|
||||
const_cast<wchar_t*>(items_[model_index]->label.c_str());
|
||||
}
|
||||
|
||||
UINT NativeMenuWin::GetAlignmentFlags(int alignment) const {
|
||||
UINT alignment_flags = TPM_TOPALIGN;
|
||||
if (alignment == Menu2::ALIGN_TOPLEFT)
|
||||
alignment_flags |= TPM_LEFTALIGN;
|
||||
else if (alignment == Menu2::ALIGN_TOPRIGHT)
|
||||
alignment_flags |= TPM_RIGHTALIGN;
|
||||
return alignment_flags;
|
||||
}
|
||||
|
||||
void NativeMenuWin::ResetNativeMenu() {
|
||||
if (IsWindow(system_menu_for_)) {
|
||||
if (menu_)
|
||||
GetSystemMenu(system_menu_for_, TRUE);
|
||||
menu_ = GetSystemMenu(system_menu_for_, FALSE);
|
||||
} else {
|
||||
if (menu_)
|
||||
DestroyMenu(menu_);
|
||||
menu_ = create_as_window_menu_ ? CreateMenu() : CreatePopupMenu();
|
||||
// Rather than relying on the return value of TrackPopupMenuEx, which is
|
||||
// always a command identifier, instead we tell the menu to notify us via
|
||||
// our host window and the WM_MENUCOMMAND message.
|
||||
MENUINFO mi = {0};
|
||||
mi.cbSize = sizeof(mi);
|
||||
mi.fMask = MIM_STYLE | MIM_MENUDATA;
|
||||
mi.dwStyle = MNS_NOTIFYBYPOS;
|
||||
mi.dwMenuData = reinterpret_cast<ULONG_PTR>(this);
|
||||
SetMenuInfo(menu_, &mi);
|
||||
}
|
||||
}
|
||||
|
||||
void NativeMenuWin::CreateHostWindow() {
|
||||
// This only gets called from RunMenuAt, and as such there is only ever one
|
||||
// host window per menu hierarchy, no matter how many NativeMenuWin objects
|
||||
// exist wrapping submenus.
|
||||
if (!host_window_.get())
|
||||
host_window_.reset(new MenuHostWindow(this));
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
189
browser/ui/win/native_menu_win.h
Normal file
189
browser/ui/win/native_menu_win.h
Normal file
@@ -0,0 +1,189 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// 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 BROWSER_UI_WIN_NATIVE_MENU_WIN_H_
|
||||
#define BROWSER_UI_WIN_NATIVE_MENU_WIN_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/observer_list.h"
|
||||
#include "base/string16.h"
|
||||
|
||||
namespace gfx {
|
||||
class Point;
|
||||
}
|
||||
|
||||
namespace ui {
|
||||
class MenuModel;
|
||||
}
|
||||
|
||||
namespace views {
|
||||
class MenuInsertionDelegateWin;
|
||||
class MenuListener;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class NativeMenuWin {
|
||||
public:
|
||||
// All of the possible actions that can result from RunMenuAt.
|
||||
enum MenuAction {
|
||||
MENU_ACTION_NONE, // Menu cancelled, or never opened.
|
||||
MENU_ACTION_SELECTED, // An item was selected.
|
||||
MENU_ACTION_PREVIOUS, // User wants to navigate to the previous menu.
|
||||
MENU_ACTION_NEXT, // User wants to navigate to the next menu.
|
||||
};
|
||||
|
||||
// Construct a NativeMenuWin, with a model and delegate. If |system_menu_for|
|
||||
// is non-NULL, the NativeMenuWin wraps the system menu for that window.
|
||||
// The caller owns the model and the delegate.
|
||||
NativeMenuWin(ui::MenuModel* model, HWND system_menu_for);
|
||||
virtual ~NativeMenuWin();
|
||||
|
||||
void RunMenuAt(const gfx::Point& point, int alignment);
|
||||
void CancelMenu();
|
||||
void Rebuild(views::MenuInsertionDelegateWin* delegate);
|
||||
void UpdateStates();
|
||||
HMENU GetNativeMenu() const;
|
||||
MenuAction GetMenuAction() const;
|
||||
void AddMenuListener(views::MenuListener* listener);
|
||||
void RemoveMenuListener(views::MenuListener* listener);
|
||||
void SetMinimumWidth(int width);
|
||||
|
||||
// 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_; }
|
||||
|
||||
private:
|
||||
// IMPORTANT: Note about indices.
|
||||
// Functions in this class deal in two index spaces:
|
||||
// 1. menu_index - the index of an item within the actual Windows
|
||||
// native menu.
|
||||
// 2. model_index - the index of the item within our model.
|
||||
// These two are most often but not always the same value! The
|
||||
// notable exception is when this object is used to wrap the
|
||||
// Windows System Menu. In this instance, the model indices start
|
||||
// at 0, but the insertion index into the existing menu is not.
|
||||
// It is important to take this into consideration when editing the
|
||||
// code in the functions in this class.
|
||||
|
||||
struct HighlightedMenuItemInfo;
|
||||
|
||||
// Returns true if the item at the specified index is a separator.
|
||||
bool IsSeparatorItemAt(int menu_index) const;
|
||||
|
||||
// Add items. See note above about indices.
|
||||
void AddMenuItemAt(int menu_index, int model_index);
|
||||
void AddSeparatorItemAt(int menu_index, int model_index);
|
||||
|
||||
// Sets the state of the item at the specified index.
|
||||
void SetMenuItemState(int menu_index,
|
||||
bool enabled,
|
||||
bool checked,
|
||||
bool is_default);
|
||||
|
||||
// Sets the label of the item at the specified index.
|
||||
void SetMenuItemLabel(int menu_index,
|
||||
int model_index,
|
||||
const string16& label);
|
||||
|
||||
// Updates the local data structure with the correctly formatted version of
|
||||
// |label| at the specified model_index, and adds string data to |mii| if
|
||||
// the menu is not owner-draw. That's a mouthful. This function exists because
|
||||
// of the peculiarities of the Windows menu API.
|
||||
void UpdateMenuItemInfoForString(MENUITEMINFO* mii,
|
||||
int model_index,
|
||||
const string16& label);
|
||||
|
||||
// Returns the alignment flags to be passed to TrackPopupMenuEx, based on the
|
||||
// supplied alignment and the UI text direction.
|
||||
UINT GetAlignmentFlags(int alignment) const;
|
||||
|
||||
// Resets the native menu stored in |menu_| by destroying any old menu then
|
||||
// creating a new empty one.
|
||||
void ResetNativeMenu();
|
||||
|
||||
// Creates the host window that receives notifications from the menu.
|
||||
void CreateHostWindow();
|
||||
|
||||
// Callback from task to notify menu it was selected.
|
||||
void DelayedSelect();
|
||||
|
||||
// Given a menu that's currently popped-up, find the currently highlighted
|
||||
// item. Returns true if a highlighted item was found.
|
||||
static bool GetHighlightedMenuItemInfo(HMENU menu,
|
||||
HighlightedMenuItemInfo* info);
|
||||
|
||||
// Hook to receive keyboard events while the menu is open.
|
||||
static LRESULT CALLBACK MenuMessageHook(
|
||||
int n_code, WPARAM w_param, LPARAM l_param);
|
||||
|
||||
// Our attached model and delegate.
|
||||
ui::MenuModel* model_;
|
||||
|
||||
HMENU menu_;
|
||||
|
||||
// True if the contents of menu items in this menu are drawn by the menu host
|
||||
// window, rather than Windows.
|
||||
bool owner_draw_;
|
||||
|
||||
// An object that collects all of the data associated with an individual menu
|
||||
// item.
|
||||
struct ItemData;
|
||||
std::vector<ItemData*> items_;
|
||||
|
||||
// The window that receives notifications from the menu.
|
||||
class MenuHostWindow;
|
||||
friend MenuHostWindow;
|
||||
scoped_ptr<MenuHostWindow> host_window_;
|
||||
|
||||
// The HWND this menu is the system menu for, or NULL if the menu is not a
|
||||
// system menu.
|
||||
HWND system_menu_for_;
|
||||
|
||||
// The index of the first item in the model in the menu.
|
||||
int first_item_index_;
|
||||
|
||||
// The action that took place during the call to RunMenuAt.
|
||||
MenuAction menu_action_;
|
||||
|
||||
// A list of listeners to call when the menu opens.
|
||||
ObserverList<views::MenuListener> listeners_;
|
||||
|
||||
// Keep track of whether the listeners have already been called at least
|
||||
// once.
|
||||
bool listeners_called_;
|
||||
|
||||
// See comment in MenuMessageHook for details on these.
|
||||
NativeMenuWin* menu_to_select_;
|
||||
int position_to_select_;
|
||||
base::WeakPtrFactory<NativeMenuWin> menu_to_select_factory_;
|
||||
|
||||
// If we're a submenu, this is our parent.
|
||||
NativeMenuWin* parent_;
|
||||
|
||||
// If non-null the destructor sets this to true. This is set to non-null while
|
||||
// the menu is showing. It is used to detect if the menu was deleted while
|
||||
// running.
|
||||
bool* destroyed_flag_;
|
||||
|
||||
// Ugly: a static pointer to the instance of this class that currently
|
||||
// has a menu open, because our hook function that receives keyboard
|
||||
// events doesn't have a mechanism to get a user data pointer.
|
||||
static NativeMenuWin* open_native_menu_win_;
|
||||
|
||||
// Create as window menu.
|
||||
bool create_as_window_menu_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NativeMenuWin);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // BROWSER_UI_WIN_NATIVE_MENU_WIN_H_
|
||||
@@ -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 */)
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
#include "common/api/atom_api_id_weak_map.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
@@ -26,6 +28,11 @@ bool IDWeakMap::Has(int key) const {
|
||||
}
|
||||
|
||||
void IDWeakMap::Erase(v8::Isolate* isolate, int key) {
|
||||
if (!Has(key)) {
|
||||
LOG(WARNING) << "Object with key " << key << " is being GCed for twice.";
|
||||
return;
|
||||
}
|
||||
|
||||
v8::Persistent<v8::Value> value = map_[key];
|
||||
value.ClearWeak(isolate);
|
||||
value.Dispose(isolate);
|
||||
@@ -47,6 +54,7 @@ void IDWeakMap::WeakCallback(v8::Isolate* isolate,
|
||||
IDWeakMap* obj = static_cast<IDWeakMap*>(data);
|
||||
int key = value->ToObject()->GetHiddenValue(
|
||||
v8::String::New("IDWeakMapKey"))->IntegerValue();
|
||||
|
||||
obj->Erase(isolate, key);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Copyright (c) 2012, Ben Noordhuis <info@bnoordhuis.nl>.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "vendor/node/src/node.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using v8::Arguments;
|
||||
using v8::FunctionTemplate;
|
||||
using v8::Handle;
|
||||
using v8::HandleScope;
|
||||
using v8::Object;
|
||||
using v8::String;
|
||||
using v8::Undefined;
|
||||
using v8::V8;
|
||||
using v8::Value;
|
||||
|
||||
typedef enum { STOP, RUN, PAUSE } gc_state_t;
|
||||
|
||||
int64_t interval;
|
||||
gc_state_t state;
|
||||
gc_state_t prev_state;
|
||||
uv_timer_t timer_handle;
|
||||
uv_check_t check_handle;
|
||||
uv_prepare_t prepare_handle;
|
||||
|
||||
void Timer(uv_timer_t*, int) {
|
||||
if (V8::IdleNotification()) state = PAUSE;
|
||||
}
|
||||
|
||||
void Check(uv_check_t*, int) {
|
||||
prev_state = state;
|
||||
}
|
||||
|
||||
void Prepare(uv_prepare_t*, int) {
|
||||
if (state == PAUSE && prev_state == PAUSE) state = RUN;
|
||||
if (state == RUN) uv_timer_start(&timer_handle, Timer, interval, 0);
|
||||
}
|
||||
|
||||
Handle<Value> Stop(const Arguments& args) {
|
||||
state = STOP;
|
||||
uv_timer_stop(&timer_handle);
|
||||
uv_check_stop(&check_handle);
|
||||
uv_prepare_stop(&prepare_handle);
|
||||
return Undefined();
|
||||
}
|
||||
|
||||
Handle<Value> Start(const Arguments& args) {
|
||||
HandleScope scope;
|
||||
Stop(args);
|
||||
|
||||
interval = args[0]->IsNumber() ? args[0]->IntegerValue() : 0;
|
||||
if (interval <= 0) interval = 5000; // Default to 5 seconds.
|
||||
|
||||
state = RUN;
|
||||
uv_check_start(&check_handle, Check);
|
||||
uv_prepare_start(&prepare_handle, Prepare);
|
||||
|
||||
return Undefined();
|
||||
}
|
||||
|
||||
void Init(Handle<Object> obj) {
|
||||
HandleScope scope;
|
||||
|
||||
uv_timer_init(uv_default_loop(), &timer_handle);
|
||||
uv_check_init(uv_default_loop(), &check_handle);
|
||||
uv_prepare_init(uv_default_loop(), &prepare_handle);
|
||||
uv_unref(reinterpret_cast<uv_handle_t*>(&timer_handle));
|
||||
uv_unref(reinterpret_cast<uv_handle_t*>(&check_handle));
|
||||
uv_unref(reinterpret_cast<uv_handle_t*>(&prepare_handle));
|
||||
|
||||
obj->Set(String::New("stop"), FunctionTemplate::New(Stop)->GetFunction());
|
||||
obj->Set(String::New("start"), FunctionTemplate::New(Start)->GetFunction());
|
||||
}
|
||||
|
||||
NODE_MODULE(atom_common_idle_gc, Init)
|
||||
|
||||
} // namespace
|
||||
@@ -3,7 +3,9 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "common/api/object_life_monitor.h"
|
||||
#include "v8/include/v8-profiler.h"
|
||||
#include "vendor/node/src/node.h"
|
||||
#include "vendor/node/src/node_internals.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
@@ -44,6 +46,12 @@ v8::Handle<v8::Value> SetDestructor(const v8::Arguments& args) {
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
v8::Handle<v8::Value> TakeHeapSnapshot(const v8::Arguments& args) {
|
||||
node::node_isolate->GetHeapProfiler()->TakeHeapSnapshot(
|
||||
v8::String::New("test"));
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void InitializeV8Util(v8::Handle<v8::Object> target) {
|
||||
@@ -52,6 +60,7 @@ void InitializeV8Util(v8::Handle<v8::Object> target) {
|
||||
NODE_SET_METHOD(target, "setHiddenValue", SetHiddenValue);
|
||||
NODE_SET_METHOD(target, "getObjectHash", GetObjectHash);
|
||||
NODE_SET_METHOD(target, "setDestructor", SetDestructor);
|
||||
NODE_SET_METHOD(target, "takeHeapSnapshot", TakeHeapSnapshot);
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
@@ -6,17 +6,36 @@
|
||||
|
||||
#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;
|
||||
|
||||
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.
|
||||
@@ -36,6 +55,10 @@ 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));
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -107,4 +130,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);
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user