mirror of
https://github.com/electron/electron.git
synced 2026-02-26 03:01:17 -05:00
Compare commits
471 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4af646b760 | ||
|
|
5720d4f802 | ||
|
|
80824b13c6 | ||
|
|
33ad68f7a7 | ||
|
|
4af802f215 | ||
|
|
3b4a45ac65 | ||
|
|
a0548530e7 | ||
|
|
8d6764e0a0 | ||
|
|
36ecb35cb1 | ||
|
|
9ad3b7939f | ||
|
|
8493975840 | ||
|
|
ec880d64bf | ||
|
|
113d644615 | ||
|
|
6c0621fe05 | ||
|
|
baa6d9730c | ||
|
|
d5ffa4dc77 | ||
|
|
01dd5638d0 | ||
|
|
ec5cd2fb1c | ||
|
|
44c0dc9104 | ||
|
|
7324f0468b | ||
|
|
64e3a6b437 | ||
|
|
690ab7d4ae | ||
|
|
48a0ac9a96 | ||
|
|
7212fa1056 | ||
|
|
8d710609fd | ||
|
|
7dcbd11863 | ||
|
|
e075a8b49e | ||
|
|
d1dc041aaf | ||
|
|
85243edf4e | ||
|
|
faeea88b16 | ||
|
|
139d581e5b | ||
|
|
64b2d0da36 | ||
|
|
dc1a8b644a | ||
|
|
8bb3b53833 | ||
|
|
8112fe741e | ||
|
|
60f24eb22b | ||
|
|
fd20050fc9 | ||
|
|
c5946bf977 | ||
|
|
618d0c6397 | ||
|
|
362bb6e68b | ||
|
|
b88168c0d2 | ||
|
|
df919a4be8 | ||
|
|
45f864d2b4 | ||
|
|
602f02b867 | ||
|
|
5cf61c9ab4 | ||
|
|
49a7954824 | ||
|
|
198b52bf40 | ||
|
|
cb31140d3a | ||
|
|
f2c1d8f4b2 | ||
|
|
3ddba90d94 | ||
|
|
887a2a3c00 | ||
|
|
585777e62d | ||
|
|
640f45a5b3 | ||
|
|
8bcb545119 | ||
|
|
aa911cdb2e | ||
|
|
27be89d39a | ||
|
|
5ce66fca5c | ||
|
|
94e4044160 | ||
|
|
30eabfb9f6 | ||
|
|
a6eb261af0 | ||
|
|
6e4f74ae35 | ||
|
|
f091352c56 | ||
|
|
534ff5efdb | ||
|
|
51d92454ce | ||
|
|
af413b2d97 | ||
|
|
7c30d037a3 | ||
|
|
acda56210b | ||
|
|
61b2377cf2 | ||
|
|
7fa6407f65 | ||
|
|
41de0b420a | ||
|
|
0ad1fc842d | ||
|
|
7f0e7f3835 | ||
|
|
6ff644fe60 | ||
|
|
92c68797d0 | ||
|
|
9a2fc8f4ea | ||
|
|
6a712d4db4 | ||
|
|
a182de20a4 | ||
|
|
caaab22841 | ||
|
|
1e1fec15b6 | ||
|
|
1524ced816 | ||
|
|
93f1a3dbd5 | ||
|
|
666f6b3a01 | ||
|
|
61cc0bba25 | ||
|
|
587484a5d0 | ||
|
|
defb6c9882 | ||
|
|
55a35d473d | ||
|
|
d86172cc87 | ||
|
|
32432cc770 | ||
|
|
ae98d9c8b6 | ||
|
|
4e2d3f3d12 | ||
|
|
a2f679e4bd | ||
|
|
06ae5c06b8 | ||
|
|
0483871388 | ||
|
|
7f7e13edc3 | ||
|
|
bbb9c37f70 | ||
|
|
88ce2a5390 | ||
|
|
6748573dee | ||
|
|
5c8566e0d4 | ||
|
|
5a6ff0f80d | ||
|
|
2024ae5dba | ||
|
|
aa6d5a3ff6 | ||
|
|
419da689c9 | ||
|
|
709563c090 | ||
|
|
b50a2c9dc1 | ||
|
|
43a5453de5 | ||
|
|
87d94ff1ae | ||
|
|
8b4414345b | ||
|
|
6e43074586 | ||
|
|
99d901bc9a | ||
|
|
95e79124eb | ||
|
|
54b0d0c9c0 | ||
|
|
10a46b4229 | ||
|
|
af3f07f4cc | ||
|
|
f4f42b30ee | ||
|
|
f3eef6cc2e | ||
|
|
11f387743f | ||
|
|
561857d640 | ||
|
|
3b3585f575 | ||
|
|
6be716c6e8 | ||
|
|
2b923b988c | ||
|
|
ef8a05be38 | ||
|
|
c029ff2055 | ||
|
|
e376850552 | ||
|
|
1ce61c7845 | ||
|
|
68a3fd6f05 | ||
|
|
ce012043fa | ||
|
|
ae70d5cb64 | ||
|
|
db359ae75c | ||
|
|
3586565bba | ||
|
|
fe67ecd7fd | ||
|
|
33c509b867 | ||
|
|
3edfb7d5c3 | ||
|
|
eed2b0fd81 | ||
|
|
4c4b8a8486 | ||
|
|
2b9a533d1d | ||
|
|
b3a2302283 | ||
|
|
6bee435170 | ||
|
|
5480cf58c2 | ||
|
|
65176761f4 | ||
|
|
cf75e4ac49 | ||
|
|
ac68589291 | ||
|
|
bc95cac3ed | ||
|
|
eed8f6cabc | ||
|
|
6aefb0f76f | ||
|
|
14de58a6b7 | ||
|
|
085f0a2544 | ||
|
|
4000734504 | ||
|
|
1b5e22f9c4 | ||
|
|
53c6d51d56 | ||
|
|
ac76017702 | ||
|
|
9927b4bf4c | ||
|
|
11ca836afc | ||
|
|
a824c88352 | ||
|
|
8fdd3b3044 | ||
|
|
1e5e0194bd | ||
|
|
a0d1a7620c | ||
|
|
770a0068a3 | ||
|
|
26f0e49c9a | ||
|
|
c7637c78d1 | ||
|
|
30ca085fd8 | ||
|
|
e824b6c910 | ||
|
|
43b492c641 | ||
|
|
c95cfc9540 | ||
|
|
d3dd2b4332 | ||
|
|
7e86ee37f3 | ||
|
|
f444e9dc74 | ||
|
|
76ac8f2719 | ||
|
|
a4262bc39d | ||
|
|
85d6588661 | ||
|
|
b70722feb6 | ||
|
|
bfe59480e3 | ||
|
|
68bdad9a23 | ||
|
|
761b9d22c8 | ||
|
|
1e4762ce92 | ||
|
|
d443b36446 | ||
|
|
ef4b36d621 | ||
|
|
ef5a4b5fe0 | ||
|
|
07b5039c64 | ||
|
|
a9c824eba1 | ||
|
|
b225a59a15 | ||
|
|
50b5272354 | ||
|
|
8879334468 | ||
|
|
2be1145a9e | ||
|
|
e65220adb0 | ||
|
|
92e157de30 | ||
|
|
c908cae72c | ||
|
|
3f357f184d | ||
|
|
3fdec5c6e3 | ||
|
|
6fced224c7 | ||
|
|
9ed64548d4 | ||
|
|
575fe06f29 | ||
|
|
6cb2ece285 | ||
|
|
29e071a1ad | ||
|
|
9e9579a858 | ||
|
|
9849844e89 | ||
|
|
c578a2cbc2 | ||
|
|
583d34b9f7 | ||
|
|
a2c3690592 | ||
|
|
7a21ae831f | ||
|
|
8708d0611a | ||
|
|
ef92cd8b45 | ||
|
|
8cb624d828 | ||
|
|
cec640f572 | ||
|
|
7a1365673e | ||
|
|
6c098deb57 | ||
|
|
cf4a566290 | ||
|
|
aabba3c641 | ||
|
|
8f31bf8615 | ||
|
|
5d49fc4bee | ||
|
|
f38eb1b66f | ||
|
|
a567ba08ea | ||
|
|
91d54a74e1 | ||
|
|
da9cce3f2d | ||
|
|
92241b91ce | ||
|
|
6b81070f67 | ||
|
|
3715dd2a20 | ||
|
|
eb6fa98ed0 | ||
|
|
8ddb85774a | ||
|
|
8caf5fac06 | ||
|
|
cc62978ac3 | ||
|
|
f833423a2f | ||
|
|
3c0671c179 | ||
|
|
a00bf3e1e1 | ||
|
|
ce487fe1da | ||
|
|
a73aea3bda | ||
|
|
b9d994dca2 | ||
|
|
b7c2295a1c | ||
|
|
da2ded5453 | ||
|
|
a5eb9ea08f | ||
|
|
4223867dbc | ||
|
|
40273cf37d | ||
|
|
bc9c95d77d | ||
|
|
6a322f8bd6 | ||
|
|
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 | ||
|
|
f8090dc010 | ||
|
|
d7351f102f | ||
|
|
64b68add3d | ||
|
|
51a632d7d9 | ||
|
|
511b2a4422 | ||
|
|
47686b3233 | ||
|
|
2f2cbce9b9 | ||
|
|
a163b148ce | ||
|
|
21f59ec730 | ||
|
|
e2898d4f2a | ||
|
|
da2a21f97d | ||
|
|
23452172ed | ||
|
|
489c5daff5 | ||
|
|
2e7dcade25 | ||
|
|
8d41c27a8c | ||
|
|
b91f29429e | ||
|
|
41f0f9bcf3 | ||
|
|
bbc049ba3a | ||
|
|
a7557a9626 | ||
|
|
85e4e99e7f | ||
|
|
767354476b | ||
|
|
7d61dcdde1 | ||
|
|
e248e2ffc8 | ||
|
|
9efde9577a | ||
|
|
620c9fa109 | ||
|
|
2f9c30dd50 | ||
|
|
7ad8c3b569 | ||
|
|
008b8d404d | ||
|
|
bc62d8c2c5 | ||
|
|
fa9e939745 | ||
|
|
1f019b36d2 | ||
|
|
00fda0e778 | ||
|
|
41ff753339 | ||
|
|
5bbb41415a | ||
|
|
99c37fc902 | ||
|
|
d59fb55a81 | ||
|
|
4ddd1bccb4 | ||
|
|
36f125f3d3 | ||
|
|
42a6a7d0d3 | ||
|
|
ec33b4d579 | ||
|
|
1d9fca25dc | ||
|
|
5f443ebbb0 | ||
|
|
2af41ae56d | ||
|
|
45285c8c9c | ||
|
|
2560782d54 | ||
|
|
9b828ce39a |
15
.gitignore
vendored
15
.gitignore
vendored
@@ -1,14 +1,11 @@
|
||||
.DS_Store
|
||||
atom-shell.zip
|
||||
version
|
||||
build/
|
||||
dist/
|
||||
frameworks/
|
||||
node/
|
||||
/build/
|
||||
/dist/
|
||||
/frameworks/
|
||||
/out/
|
||||
/vendor/brightray/vendor/download/
|
||||
/vendor/python_26/
|
||||
node_modules/
|
||||
out/
|
||||
vendor/brightray/vendor/download/
|
||||
vendor/python_26/
|
||||
*.xcodeproj
|
||||
*.swp
|
||||
*.pyc
|
||||
|
||||
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,101 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "content/public/app/content_main.h"
|
||||
#include "app/atom_main.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <stdio.h>
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
|
||||
#include "app/atom_main_delegate.h"
|
||||
#include "base/environment.h"
|
||||
#include "content/public/app/startup_helper_win.h"
|
||||
#include "sandbox/win/src/sandbox_types.h"
|
||||
#else // defined(OS_WIN)
|
||||
#include "app/atom_library_main.h"
|
||||
#endif // defined(OS_MACOSX) || defined(OS_LINUX)
|
||||
|
||||
// Declaration of node::Start.
|
||||
namespace node {
|
||||
int Start(int argc, char *argv[]);
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
|
||||
#include "app/atom_main_delegate.h"
|
||||
#include "content/public/app/startup_helper_win.h"
|
||||
#include "sandbox/win/src/sandbox_types.h"
|
||||
int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
|
||||
int argc = 0;
|
||||
wchar_t** wargv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
|
||||
|
||||
// Attach to the parent console if we've got one so that stdio works
|
||||
AttachConsole(ATTACH_PARENT_PROCESS);
|
||||
|
||||
FILE* dontcare;
|
||||
freopen_s(&dontcare, "CON", "w", stdout);
|
||||
freopen_s(&dontcare, "CON", "w", stderr);
|
||||
freopen_s(&dontcare, "CON", "r", stdin);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t*, int) {
|
||||
sandbox::SandboxInterfaceInfo sandbox_info = {0};
|
||||
content::InitializeSandboxInfo(&sandbox_info);
|
||||
atom::AtomMainDelegate delegate;
|
||||
return content::ContentMain(instance, &sandbox_info, &delegate);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include "app/atom_library_main.h"
|
||||
#else // defined(OS_WIN)
|
||||
|
||||
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 // defined(OS_MACOSX) || defined(OS_LINUX)
|
||||
|
||||
5
app/atom_main.h
Normal file
5
app/atom_main.h
Normal file
@@ -0,0 +1,5 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "content/public/app/content_main.h"
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "browser/atom_browser_client.h"
|
||||
#include "content/public/common/content_switches.h"
|
||||
#include "renderer/atom_renderer_client.h"
|
||||
#include "ui/base/resource/resource_bundle.h"
|
||||
#include "base/path_service.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
@@ -23,24 +25,46 @@ bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
|
||||
#if defined(OS_WIN)
|
||||
logging::InitLogging(
|
||||
L"debug.log",
|
||||
#if defined(DEBUG)
|
||||
logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG ,
|
||||
#else
|
||||
logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG,
|
||||
#endif // defined(NDEBUG)
|
||||
logging::LOCK_LOG_FILE,
|
||||
logging::DELETE_OLD_LOG_FILE,
|
||||
logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS);
|
||||
logging::SetLogItems(true, false, true, false);
|
||||
#endif
|
||||
#endif // defined(OS_WIN)
|
||||
|
||||
return brightray::MainDelegate::BasicStartupComplete(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
|
||||
BIN
app/win/atom.ico
Normal file
BIN
app/win/atom.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 345 KiB |
BIN
app/win/atom.rc
BIN
app/win/atom.rc
Binary file not shown.
@@ -1,9 +1,10 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by brightray_example.rc
|
||||
|
||||
#define IDR_MAINFRAME 1
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 101
|
||||
|
||||
125
atom.gyp
125
atom.gyp
@@ -4,6 +4,7 @@
|
||||
'product_name': 'Atom',
|
||||
'app_sources': [
|
||||
'app/atom_main.cc',
|
||||
'app/atom_main.h',
|
||||
],
|
||||
'bundle_sources': [
|
||||
'browser/mac/atom.icns',
|
||||
@@ -18,6 +19,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 +34,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 +55,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 +80,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 +90,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,10 +97,34 @@
|
||||
'browser/native_window_win.cc',
|
||||
'browser/native_window_win.h',
|
||||
'browser/native_window_observer.h',
|
||||
'browser/node_bindings_browser_win.cc',
|
||||
'browser/node_bindings_browser_win.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',
|
||||
@@ -116,7 +132,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',
|
||||
@@ -128,15 +143,20 @@
|
||||
'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',
|
||||
'common/node_bindings_mac.h',
|
||||
'common/node_bindings_mac.mm',
|
||||
'common/node_bindings_win.cc',
|
||||
'common/node_bindings_win.h',
|
||||
'common/options_switches.cc',
|
||||
'common/options_switches.h',
|
||||
'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',
|
||||
@@ -147,8 +167,6 @@
|
||||
'renderer/atom_render_view_observer.h',
|
||||
'renderer/atom_renderer_client.cc',
|
||||
'renderer/atom_renderer_client.h',
|
||||
'renderer/node_bindings_renderer_win.cc',
|
||||
'renderer/node_bindings_renderer_win.h',
|
||||
],
|
||||
'framework_sources': [
|
||||
'app/atom_library_main.cc',
|
||||
@@ -158,6 +176,7 @@
|
||||
['OS=="win"', {
|
||||
'app_sources': [
|
||||
'app/win/resource.h',
|
||||
'app/win/atom.ico',
|
||||
'app/win/atom.rc',
|
||||
'<(libchromiumcontent_src_dir)/content/app/startup_helper_win.cc',
|
||||
],
|
||||
@@ -179,6 +198,17 @@
|
||||
'mac_framework_dirs': [
|
||||
'<(atom_source_root)/frameworks',
|
||||
],
|
||||
'includes': [
|
||||
# Rules for excluding e.g. foo_win.cc from the build on non-Windows.
|
||||
'filename_rules.gypi',
|
||||
],
|
||||
'configurations': {
|
||||
'Debug': {
|
||||
'defines': [
|
||||
'DEBUG',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
'targets': [
|
||||
{
|
||||
@@ -230,13 +260,6 @@
|
||||
'browser/default_app',
|
||||
],
|
||||
},
|
||||
{
|
||||
# Copy node binary for worker process support.
|
||||
'destination': '<(PRODUCT_DIR)/<(product_name).app/Contents/Resources',
|
||||
'files': [
|
||||
'node/node',
|
||||
],
|
||||
},
|
||||
],
|
||||
'postbuilds': [
|
||||
{
|
||||
@@ -269,6 +292,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',
|
||||
@@ -280,12 +304,6 @@
|
||||
'browser/default_app',
|
||||
]
|
||||
},
|
||||
{
|
||||
'destination': '<(PRODUCT_DIR)/resources',
|
||||
'files': [
|
||||
'node/node.exe',
|
||||
]
|
||||
},
|
||||
],
|
||||
}], # OS=="win"
|
||||
],
|
||||
@@ -318,6 +336,7 @@
|
||||
'libraries': [
|
||||
'-limm32.lib',
|
||||
'-loleacc.lib',
|
||||
'-lComdlg32.lib',
|
||||
'<(atom_source_root)/<(libchromiumcontent_library_dir)/chromiumviews.lib',
|
||||
],
|
||||
},
|
||||
@@ -468,5 +487,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
|
||||
],
|
||||
}
|
||||
|
||||
@@ -1,91 +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/accelerator_util.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/string_util.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/string_split.h"
|
||||
#include "ui/base/accelerators/accelerator.h"
|
||||
|
||||
namespace accelerator_util {
|
||||
|
||||
namespace {
|
||||
|
||||
// For Mac, we convert "Ctrl" to "Command" and "MacCtrl" to "Ctrl". Other
|
||||
// platforms leave the shortcut untouched.
|
||||
std::string NormalizeShortcutSuggestion(const std::string& suggestion) {
|
||||
#if !defined(OS_MACOSX)
|
||||
return suggestion;
|
||||
#endif
|
||||
|
||||
std::string key;
|
||||
std::vector<std::string> tokens;
|
||||
base::SplitString(suggestion, '+', &tokens);
|
||||
for (size_t i = 0; i < tokens.size(); i++) {
|
||||
if (tokens[i] == "Ctrl")
|
||||
tokens[i] = "Command";
|
||||
else if (tokens[i] == "MacCtrl")
|
||||
tokens[i] = "Ctrl";
|
||||
}
|
||||
return JoinString(tokens, '+');
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool StringToAccelerator(const std::string& description,
|
||||
ui::Accelerator* accelerator) {
|
||||
std::string shortcut(NormalizeShortcutSuggestion(description));
|
||||
|
||||
std::vector<std::string> tokens;
|
||||
base::SplitString(shortcut, '+', &tokens);
|
||||
if (tokens.size() < 2 || tokens.size() > 4) {
|
||||
LOG(WARNING) << "Invalid accelerator description: " << description;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now, parse it into an accelerator.
|
||||
int modifiers = ui::EF_NONE;
|
||||
ui::KeyboardCode key = ui::VKEY_UNKNOWN;
|
||||
for (size_t i = 0; i < tokens.size(); i++) {
|
||||
if (tokens[i] == "Ctrl") {
|
||||
modifiers |= ui::EF_CONTROL_DOWN;
|
||||
} else if (tokens[i] == "Command") {
|
||||
modifiers |= ui::EF_COMMAND_DOWN;
|
||||
} else if (tokens[i] == "Alt") {
|
||||
modifiers |= ui::EF_ALT_DOWN;
|
||||
} else if (tokens[i] == "Shift") {
|
||||
modifiers |= ui::EF_SHIFT_DOWN;
|
||||
} else if (tokens[i].size() == 1) {
|
||||
if (key != ui::VKEY_UNKNOWN) {
|
||||
// Multiple key assignments.
|
||||
key = ui::VKEY_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
if (tokens[i][0] >= 'A' && tokens[i][0] <= 'Z') {
|
||||
key = static_cast<ui::KeyboardCode>(ui::VKEY_A + (tokens[i][0] - 'A'));
|
||||
} else if (tokens[i][0] >= '0' && tokens[i][0] <= '9') {
|
||||
key = static_cast<ui::KeyboardCode>(ui::VKEY_0 + (tokens[i][0] - '0'));
|
||||
} else if (tokens[i][0] >= '+' && tokens[i][0] <= '.') {
|
||||
key = static_cast<ui::KeyboardCode>(
|
||||
ui::VKEY_OEM_PLUS + (tokens[i][0] - '+'));
|
||||
} else {
|
||||
LOG(WARNING) << "Invalid accelerator character: " << tokens[i];
|
||||
key = ui::VKEY_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
LOG(WARNING) << "Invalid accelerator token: " << tokens[i];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
*accelerator = ui::Accelerator(key, modifiers);
|
||||
SetPlatformAccelerator(accelerator);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace accelerator_util
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -372,6 +351,10 @@ void Menu::Initialize(v8::Handle<v8::Object> target) {
|
||||
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "popup", Popup);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "attachToWindow", AttachToWindow);
|
||||
#endif
|
||||
|
||||
target->Set(v8::String::NewSymbol("Menu"), t->GetFunction());
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
|
||||
@@ -68,7 +68,9 @@ class Menu : public EventEmitter,
|
||||
|
||||
static v8::Handle<v8::Value> Popup(const v8::Arguments &args);
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
#if defined(OS_WIN)
|
||||
static v8::Handle<v8::Value> AttachToWindow(const v8::Arguments &args);
|
||||
#elif defined(OS_MACOSX)
|
||||
static v8::Handle<v8::Value> SetApplicationMenu(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> SendActionToFirstResponder(
|
||||
const v8::Arguments &args);
|
||||
|
||||
@@ -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,12 @@
|
||||
|
||||
#include "browser/api/atom_api_menu_win.h"
|
||||
|
||||
#include "browser/native_window_win.h"
|
||||
#include "browser/ui/win/menu_2.h"
|
||||
#include "common/v8_conversions.h"
|
||||
#include "ui/gfx/point.h"
|
||||
#include "ui/gfx/screen.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
@@ -16,6 +22,26 @@ MenuWin::~MenuWin() {
|
||||
}
|
||||
|
||||
void MenuWin::Popup(NativeWindow* native_window) {
|
||||
gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
|
||||
menu_.reset(new atom::Menu2(model_.get()));
|
||||
menu_->RunContextMenuAt(cursor);
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Menu::AttachToWindow(const v8::Arguments& args) {
|
||||
v8::HandleScope scope;
|
||||
|
||||
Menu* self = ObjectWrap::Unwrap<Menu>(args.This());
|
||||
if (self == NULL)
|
||||
return node::ThrowError("Menu is already destroyed");
|
||||
|
||||
NativeWindow* native_window;
|
||||
if (!FromV8Arguments(args, &native_window))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
static_cast<NativeWindowWin*>(native_window)->SetMenu(self->model_.get());
|
||||
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
@@ -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"
|
||||
@@ -13,6 +14,7 @@
|
||||
#include "ui/gfx/point.h"
|
||||
#include "ui/gfx/rect.h"
|
||||
#include "ui/gfx/size.h"
|
||||
#include "vendor/node/src/node_buffer.h"
|
||||
|
||||
using content::V8ValueConverter;
|
||||
using content::NavigationController;
|
||||
@@ -27,15 +29,6 @@ namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
namespace {
|
||||
|
||||
// Converts string16 to V8 String.
|
||||
v8::Handle<v8::String> UTF16ToV8String(const string16& s) {
|
||||
return v8::String::New(reinterpret_cast<const uint16_t*>(s.data()), s.size());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Window::Window(v8::Handle<v8::Object> wrapper, base::DictionaryValue* options)
|
||||
: EventEmitter(wrapper),
|
||||
window_(NativeWindow::Create(options)) {
|
||||
@@ -56,6 +49,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 +62,9 @@ void Window::WillCloseWindow(bool* prevent_default) {
|
||||
void Window::OnWindowClosed() {
|
||||
Emit("closed");
|
||||
|
||||
// Free memory immediately when window is closed.
|
||||
delete this;
|
||||
// Free memory when native window is closed, the delete is delayed so other
|
||||
// observers would not get a invalid pointer of NativeWindow.
|
||||
base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
|
||||
}
|
||||
|
||||
void Window::OnWindowBlur() {
|
||||
@@ -83,6 +83,20 @@ void Window::OnRendererCrashed() {
|
||||
Emit("crashed");
|
||||
}
|
||||
|
||||
void Window::OnCapturePageDone(v8::Persistent<v8::Function> callback,
|
||||
const std::vector<unsigned char>& data) {
|
||||
v8::HandleScope scope;
|
||||
|
||||
// TODO(zcbenz): Use new Buffer API when we updated to node v0.12.x.
|
||||
node::Buffer* buffer = node::Buffer::New(
|
||||
reinterpret_cast<const char*>(data.data()),
|
||||
data.size());
|
||||
|
||||
v8::Handle<v8::Value> arg = buffer->handle_;
|
||||
callback->Call(v8::Context::GetCurrent()->Global(), 1, &arg);
|
||||
callback.Dispose(v8::Isolate::GetCurrent());
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::New(const v8::Arguments &args) {
|
||||
v8::HandleScope scope;
|
||||
@@ -102,6 +116,9 @@ v8::Handle<v8::Value> Window::New(const v8::Arguments &args) {
|
||||
|
||||
new Window(args.This(), static_cast<base::DictionaryValue*>(options.get()));
|
||||
|
||||
// Give js code a chance to do initialization.
|
||||
node::MakeCallback(args.This(), "_init", 0, NULL);
|
||||
|
||||
return args.This();
|
||||
}
|
||||
|
||||
@@ -135,7 +152,7 @@ v8::Handle<v8::Value> Window::Focus(const v8::Arguments &args) {
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::IsFocused(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
return v8::Boolean::New(self->window_->IsFocused());
|
||||
return ToV8Value(self->window_->IsFocused());
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -156,6 +173,12 @@ v8::Handle<v8::Value> Window::Hide(const v8::Arguments &args) {
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::IsVisible(const v8::Arguments& args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
return ToV8Value(self->window_->IsVisible());
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::Maximize(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
@@ -196,10 +219,11 @@ v8::Handle<v8::Value> Window::Restore(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::SetFullscreen(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
if (args.Length() < 1 || !args[0]->IsBoolean())
|
||||
bool fs;
|
||||
if (!FromV8Arguments(args, &fs))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
self->window_->SetFullscreen(args[0]->BooleanValue());
|
||||
|
||||
self->window_->SetFullscreen(fs);
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
@@ -207,18 +231,18 @@ v8::Handle<v8::Value> Window::SetFullscreen(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::IsFullscreen(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
return v8::Boolean::New(self->window_->IsFullscreen());
|
||||
return ToV8Value(self->window_->IsFullscreen());
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::SetSize(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
if (args.Length() < 2)
|
||||
int width, height;
|
||||
if (!FromV8Arguments(args, &width, &height))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
self->window_->SetSize(
|
||||
gfx::Size(args[0]->IntegerValue(), args[1]->IntegerValue()));
|
||||
|
||||
self->window_->SetSize(gfx::Size(width, height));
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
@@ -228,8 +252,8 @@ v8::Handle<v8::Value> Window::GetSize(const v8::Arguments &args) {
|
||||
|
||||
gfx::Size size = self->window_->GetSize();
|
||||
v8::Handle<v8::Array> ret = v8::Array::New(2);
|
||||
ret->Set(0, v8::Integer::New(size.width()));
|
||||
ret->Set(1, v8::Integer::New(size.height()));
|
||||
ret->Set(0, ToV8Value(size.width()));
|
||||
ret->Set(1, ToV8Value(size.height()));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -238,11 +262,11 @@ v8::Handle<v8::Value> Window::GetSize(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::SetMinimumSize(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
if (args.Length() < 2)
|
||||
int width, height;
|
||||
if (!FromV8Arguments(args, &width, &height))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
self->window_->SetMinimumSize(
|
||||
gfx::Size(args[0]->IntegerValue(), args[1]->IntegerValue()));
|
||||
|
||||
self->window_->SetMinimumSize(gfx::Size(width, height));
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
@@ -252,8 +276,8 @@ v8::Handle<v8::Value> Window::GetMinimumSize(const v8::Arguments &args) {
|
||||
|
||||
gfx::Size size = self->window_->GetMinimumSize();
|
||||
v8::Handle<v8::Array> ret = v8::Array::New(2);
|
||||
ret->Set(0, v8::Integer::New(size.width()));
|
||||
ret->Set(1, v8::Integer::New(size.height()));
|
||||
ret->Set(0, ToV8Value(size.width()));
|
||||
ret->Set(1, ToV8Value(size.height()));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -262,11 +286,12 @@ v8::Handle<v8::Value> Window::GetMinimumSize(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::SetMaximumSize(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
if (args.Length() < 2)
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
self->window_->SetMaximumSize(
|
||||
gfx::Size(args[0]->IntegerValue(), args[1]->IntegerValue()));
|
||||
|
||||
int width, height;
|
||||
if (!FromV8Arguments(args, &width, &height))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
self->window_->SetMaximumSize(gfx::Size(width, height));
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
@@ -276,8 +301,8 @@ v8::Handle<v8::Value> Window::GetMaximumSize(const v8::Arguments &args) {
|
||||
|
||||
gfx::Size size = self->window_->GetMaximumSize();
|
||||
v8::Handle<v8::Array> ret = v8::Array::New(2);
|
||||
ret->Set(0, v8::Integer::New(size.width()));
|
||||
ret->Set(1, v8::Integer::New(size.height()));
|
||||
ret->Set(0, ToV8Value(size.width()));
|
||||
ret->Set(1, ToV8Value(size.height()));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -286,10 +311,11 @@ v8::Handle<v8::Value> Window::GetMaximumSize(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::SetResizable(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
if (args.Length() < 1 || !args[0]->IsBoolean())
|
||||
bool resizable;
|
||||
if (!FromV8Arguments(args, &resizable))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
self->window_->SetResizable(args[0]->BooleanValue());
|
||||
|
||||
self->window_->SetResizable(resizable);
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
@@ -297,17 +323,18 @@ v8::Handle<v8::Value> Window::SetResizable(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::IsResizable(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
return v8::Boolean::New(self->window_->IsResizable());
|
||||
return ToV8Value(self->window_->IsResizable());
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::SetAlwaysOnTop(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
if (args.Length() < 1 || !args[0]->IsBoolean())
|
||||
bool top;
|
||||
if (!FromV8Arguments(args, &top))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
self->window_->SetAlwaysOnTop(args[0]->BooleanValue());
|
||||
|
||||
self->window_->SetAlwaysOnTop(top);
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
@@ -315,7 +342,7 @@ v8::Handle<v8::Value> Window::SetAlwaysOnTop(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::IsAlwaysOnTop(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
return v8::Boolean::New(self->window_->IsAlwaysOnTop());
|
||||
return ToV8Value(self->window_->IsAlwaysOnTop());
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -331,11 +358,11 @@ v8::Handle<v8::Value> Window::Center(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::SetPosition(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
if (args.Length() < 2)
|
||||
int x, y;
|
||||
if (!FromV8Arguments(args, &x, &y))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
self->window_->SetPosition(
|
||||
gfx::Point(args[0]->IntegerValue(), args[1]->IntegerValue()));
|
||||
|
||||
self->window_->SetPosition(gfx::Point(x, y));
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
@@ -345,8 +372,8 @@ v8::Handle<v8::Value> Window::GetPosition(const v8::Arguments &args) {
|
||||
|
||||
gfx::Point pos = self->window_->GetPosition();
|
||||
v8::Handle<v8::Array> ret = v8::Array::New(2);
|
||||
ret->Set(0, v8::Integer::New(pos.x()));
|
||||
ret->Set(1, v8::Integer::New(pos.y()));
|
||||
ret->Set(0, ToV8Value(pos.x()));
|
||||
ret->Set(1, ToV8Value(pos.y()));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -355,20 +382,18 @@ v8::Handle<v8::Value> Window::GetPosition(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::SetTitle(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
if (args.Length() < 1 || !args[0]->IsString())
|
||||
std::string title;
|
||||
if (!FromV8Arguments(args, &title))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
self->window_->SetTitle(*v8::String::Utf8Value(args[0]));
|
||||
|
||||
self->window_->SetTitle(title);
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::GetTitle(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
std::string title = self->window_->GetTitle();
|
||||
|
||||
return v8::String::New(title.c_str(), title.size());
|
||||
return ToV8Value(self->window_->GetTitle());
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -385,10 +410,11 @@ v8::Handle<v8::Value> Window::FlashFrame(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::SetKiosk(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
if (args.Length() < 1 || !args[0]->IsBoolean())
|
||||
bool kiosk;
|
||||
if (!FromV8Arguments(args, &kiosk))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
self->window_->SetKiosk(args[0]->BooleanValue());
|
||||
|
||||
self->window_->SetKiosk(kiosk);
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
@@ -396,7 +422,7 @@ v8::Handle<v8::Value> Window::SetKiosk(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::IsKiosk(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
return v8::Boolean::New(self->window_->IsKiosk());
|
||||
return ToV8Value(self->window_->IsKiosk());
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -417,6 +443,24 @@ v8::Handle<v8::Value> Window::CloseDevTools(const v8::Arguments &args) {
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::IsDevToolsOpened(const v8::Arguments& args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
return ToV8Value(self->window_->IsDevToolsOpened());
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::InspectElement(const v8::Arguments& args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
int x, y;
|
||||
if (!FromV8Arguments(args, &x, &y))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
self->window_->InspectElement(x, y);
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::FocusOnWebView(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
@@ -435,6 +479,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) {
|
||||
@@ -445,28 +495,42 @@ v8::Handle<v8::Value> Window::RestartHangMonitorTimeout(
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::CapturePage(const v8::Arguments& args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
gfx::Rect rect;
|
||||
v8::Persistent<v8::Function> callback;
|
||||
if (!FromV8Arguments(args, &rect, &callback) &&
|
||||
!FromV8Arguments(args, &callback))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
self->window_->CapturePage(rect, base::Bind(&Window::OnCapturePageDone,
|
||||
base::Unretained(self),
|
||||
callback));
|
||||
|
||||
return v8::Undefined();
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::GetPageTitle(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
string16 title = self->window_->GetWebContents()->GetTitle();
|
||||
|
||||
return UTF16ToV8String(title);
|
||||
return ToV8Value(self->window_->GetWebContents()->GetTitle());
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::IsLoading(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
return v8::Boolean::New(self->window_->GetWebContents()->IsLoading());
|
||||
return ToV8Value(self->window_->GetWebContents()->IsLoading());
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::IsWaitingForResponse(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
return v8::Boolean::New(
|
||||
self->window_->GetWebContents()->IsWaitingForResponse());
|
||||
return ToV8Value(self->window_->GetWebContents()->IsWaitingForResponse());
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -482,14 +546,14 @@ v8::Handle<v8::Value> Window::Stop(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::GetRoutingID(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
return v8::Integer::New(self->window_->GetWebContents()->GetRoutingID());
|
||||
return ToV8Value(self->window_->GetWebContents()->GetRoutingID());
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::GetProcessID(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
return v8::Integer::New(
|
||||
return ToV8Value(
|
||||
self->window_->GetWebContents()->GetRenderProcessHost()->GetID());
|
||||
}
|
||||
|
||||
@@ -497,19 +561,20 @@ v8::Handle<v8::Value> Window::GetProcessID(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::IsCrashed(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
return v8::Boolean::New(self->window_->GetWebContents()->IsCrashed());
|
||||
return ToV8Value(self->window_->GetWebContents()->IsCrashed());
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::LoadURL(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
if (args.Length() < 1 || !args[0]->IsString())
|
||||
std::string url;
|
||||
if (!FromV8Arguments(args, &url))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
NavigationController& controller =
|
||||
self->window_->GetWebContents()->GetController();
|
||||
controller.LoadURL(GURL(*v8::String::Utf8Value(args[0])),
|
||||
controller.LoadURL(GURL(url),
|
||||
content::Referrer(),
|
||||
content::PAGE_TRANSITION_AUTO_TOPLEVEL,
|
||||
std::string());
|
||||
@@ -527,7 +592,7 @@ v8::Handle<v8::Value> Window::GetURL(const v8::Arguments &args) {
|
||||
if (controller.GetActiveEntry())
|
||||
url = controller.GetActiveEntry()->GetVirtualURL().spec();
|
||||
|
||||
return v8::String::New(url.c_str(), url.size());
|
||||
return ToV8Value(url);
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -537,7 +602,7 @@ v8::Handle<v8::Value> Window::CanGoBack(const v8::Arguments &args) {
|
||||
NavigationController& controller =
|
||||
self->window_->GetWebContents()->GetController();
|
||||
|
||||
return v8::Boolean::New(controller.CanGoBack());
|
||||
return ToV8Value(controller.CanGoBack());
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -547,21 +612,21 @@ v8::Handle<v8::Value> Window::CanGoForward(const v8::Arguments &args) {
|
||||
NavigationController& controller =
|
||||
self->window_->GetWebContents()->GetController();
|
||||
|
||||
return v8::Boolean::New(controller.CanGoForward());
|
||||
return ToV8Value(controller.CanGoForward());
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Handle<v8::Value> Window::CanGoToOffset(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
if (args.Length() < 1)
|
||||
int offset;
|
||||
if (!FromV8Arguments(args, &offset))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
NavigationController& controller =
|
||||
self->window_->GetWebContents()->GetController();
|
||||
int offset = args[0]->IntegerValue();
|
||||
|
||||
return v8::Boolean::New(controller.CanGoToOffset(offset));
|
||||
return ToV8Value(controller.CanGoToOffset(offset));
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -590,12 +655,13 @@ v8::Handle<v8::Value> Window::GoForward(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::GoToIndex(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
if (args.Length() < 1)
|
||||
int index;
|
||||
if (!FromV8Arguments(args, &index))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
NavigationController& controller =
|
||||
self->window_->GetWebContents()->GetController();
|
||||
controller.GoToIndex(args[0]->IntegerValue());
|
||||
controller.GoToIndex(index);
|
||||
|
||||
return v8::Undefined();
|
||||
}
|
||||
@@ -604,12 +670,13 @@ v8::Handle<v8::Value> Window::GoToIndex(const v8::Arguments &args) {
|
||||
v8::Handle<v8::Value> Window::GoToOffset(const v8::Arguments &args) {
|
||||
UNWRAP_WINDOW_AND_CHECK;
|
||||
|
||||
if (args.Length() < 1)
|
||||
int offset;
|
||||
if (!FromV8Arguments(args, &offset))
|
||||
return node::ThrowTypeError("Bad argument");
|
||||
|
||||
NavigationController& controller =
|
||||
self->window_->GetWebContents()->GetController();
|
||||
controller.GoToOffset(args[0]->IntegerValue());
|
||||
controller.GoToOffset(offset);
|
||||
|
||||
return v8::Undefined();
|
||||
}
|
||||
@@ -651,6 +718,7 @@ void Window::Initialize(v8::Handle<v8::Object> target) {
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "isFocused", IsFocused);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "show", Show);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "hide", Hide);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "isVisible", IsVisible);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "maximize", Maximize);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "unmaximize", Unmaximize);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "minimize", Minimize);
|
||||
@@ -677,11 +745,15 @@ void Window::Initialize(v8::Handle<v8::Object> target) {
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "isKiosk", IsKiosk);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "openDevTools", OpenDevTools);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "closeDevTools", CloseDevTools);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "isDevToolsOpened", IsDevToolsOpened);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "inspectElement", InspectElement);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "focusOnWebView", FocusOnWebView);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "blurWebView", BlurWebView);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "isWebViewFocused", IsWebViewFocused);
|
||||
NODE_SET_PROTOTYPE_METHOD(t,
|
||||
"restartHangMonitorTimeout",
|
||||
RestartHangMonitorTimeout);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "capturePage", CapturePage);
|
||||
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "getPageTitle", GetPageTitle);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "isLoading", IsLoading);
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#ifndef ATOM_BROWSER_API_ATOM_API_WINDOW_H_
|
||||
#define ATOM_BROWSER_API_ATOM_API_WINDOW_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "browser/api/atom_api_event_emitter.h"
|
||||
#include "browser/native_window_observer.h"
|
||||
@@ -35,6 +37,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;
|
||||
@@ -52,6 +55,7 @@ class Window : public EventEmitter,
|
||||
static v8::Handle<v8::Value> IsFocused(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> Show(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> Hide(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> IsVisible(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> Maximize(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> Unmaximize(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> Minimize(const v8::Arguments &args);
|
||||
@@ -78,10 +82,14 @@ class Window : public EventEmitter,
|
||||
static v8::Handle<v8::Value> IsKiosk(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> OpenDevTools(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> CloseDevTools(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> IsDevToolsOpened(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> InspectElement(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> FocusOnWebView(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> BlurWebView(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> IsWebViewFocused(const v8::Arguments& args);
|
||||
static v8::Handle<v8::Value> RestartHangMonitorTimeout(
|
||||
const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> CapturePage(const v8::Arguments& args);
|
||||
|
||||
// APIs for WebContents.
|
||||
static v8::Handle<v8::Value> GetPageTitle(const v8::Arguments &args);
|
||||
@@ -105,6 +113,10 @@ class Window : public EventEmitter,
|
||||
static v8::Handle<v8::Value> Reload(const v8::Arguments &args);
|
||||
static v8::Handle<v8::Value> ReloadIgnoringCache(const v8::Arguments &args);
|
||||
|
||||
// Called when capturePage is done.
|
||||
void OnCapturePageDone(v8::Persistent<v8::Function> callback,
|
||||
const std::vector<unsigned char>& data);
|
||||
|
||||
scoped_ptr<NativeWindow> window_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Window);
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/values.h"
|
||||
#include "browser/api/atom_api_event.h"
|
||||
#include "common/v8_conversions.h"
|
||||
#include "common/v8_value_converter_impl.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "vendor/node/src/node.h"
|
||||
@@ -42,7 +44,7 @@ void AtomBrowserBindings::AfterLoad() {
|
||||
|
||||
void AtomBrowserBindings::OnRendererMessage(int process_id,
|
||||
int routing_id,
|
||||
const std::string& channel,
|
||||
const string16& channel,
|
||||
const base::ListValue& args) {
|
||||
v8::HandleScope scope;
|
||||
|
||||
@@ -53,7 +55,7 @@ void AtomBrowserBindings::OnRendererMessage(int process_id,
|
||||
// process.emit(channel, 'message', process_id, routing_id);
|
||||
std::vector<v8::Handle<v8::Value>> arguments;
|
||||
arguments.reserve(3 + args.GetSize());
|
||||
arguments.push_back(v8::String::New(channel.c_str(), channel.size()));
|
||||
arguments.push_back(ToV8Value(channel));
|
||||
const base::Value* value;
|
||||
if (args.Get(0, &value))
|
||||
arguments.push_back(converter->ToV8Value(value, context));
|
||||
@@ -72,21 +74,24 @@ void AtomBrowserBindings::OnRendererMessage(int process_id,
|
||||
void AtomBrowserBindings::OnRendererMessageSync(
|
||||
int process_id,
|
||||
int routing_id,
|
||||
const std::string& channel,
|
||||
const string16& channel,
|
||||
const base::ListValue& args,
|
||||
base::DictionaryValue* result) {
|
||||
NativeWindow* sender,
|
||||
IPC::Message* message) {
|
||||
v8::HandleScope scope;
|
||||
|
||||
v8::Handle<v8::Context> context = v8::Context::GetCurrent();
|
||||
|
||||
scoped_ptr<V8ValueConverter> converter(new V8ValueConverterImpl());
|
||||
|
||||
v8::Handle<v8::Object> event = v8::Object::New();
|
||||
// Create the event object.
|
||||
v8::Handle<v8::Object> event = api::Event::CreateV8Object();
|
||||
api::Event::Unwrap<api::Event>(event)->SetSenderAndMessage(sender, message);
|
||||
|
||||
// process.emit(channel, 'sync-message', event, process_id, routing_id);
|
||||
std::vector<v8::Handle<v8::Value>> arguments;
|
||||
arguments.reserve(3 + args.GetSize());
|
||||
arguments.push_back(v8::String::New(channel.c_str(), channel.size()));
|
||||
arguments.push_back(ToV8Value(channel));
|
||||
const base::Value* value;
|
||||
if (args.Get(0, &value))
|
||||
arguments.push_back(converter->ToV8Value(value, context));
|
||||
@@ -101,11 +106,6 @@ void AtomBrowserBindings::OnRendererMessageSync(
|
||||
}
|
||||
|
||||
node::MakeCallback(node::process, "emit", arguments.size(), &arguments[0]);
|
||||
|
||||
scoped_ptr<base::Value> base_event(converter->FromV8Value(event, context));
|
||||
DCHECK(base_event && base_event->IsType(base::Value::TYPE_DICTIONARY));
|
||||
|
||||
result->Swap(static_cast<base::DictionaryValue*>(base_event.get()));
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -5,17 +5,21 @@
|
||||
#ifndef ATOM_BROWSER_API_ATOM_BROWSER_BINDINGS_
|
||||
#define ATOM_BROWSER_API_ATOM_BROWSER_BINDINGS_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/string16.h"
|
||||
#include "common/api/atom_bindings.h"
|
||||
|
||||
namespace base {
|
||||
class DictionaryValue;
|
||||
class ListValue;
|
||||
}
|
||||
|
||||
namespace IPC {
|
||||
class Message;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class NativeWindow;
|
||||
|
||||
class AtomBrowserBindings : public AtomBindings {
|
||||
public:
|
||||
AtomBrowserBindings();
|
||||
@@ -27,15 +31,16 @@ class AtomBrowserBindings : public AtomBindings {
|
||||
// Called when received a message from renderer.
|
||||
void OnRendererMessage(int process_id,
|
||||
int routing_id,
|
||||
const std::string& channel,
|
||||
const string16& channel,
|
||||
const base::ListValue& args);
|
||||
|
||||
// Called when received a synchronous message from renderer.
|
||||
void OnRendererMessageSync(int process_id,
|
||||
int routing_id,
|
||||
const std::string& channel,
|
||||
const string16& channel,
|
||||
const base::ListValue& args,
|
||||
base::DictionaryValue* result);
|
||||
NativeWindow* sender,
|
||||
IPC::Message* message);
|
||||
|
||||
// The require('atom').browserMainParts object.
|
||||
v8::Handle<v8::Object> browser_main_parts() {
|
||||
|
||||
@@ -9,9 +9,25 @@ app = new Application
|
||||
app.getHomeDir = ->
|
||||
process.env[if process.platform is 'win32' then 'USERPROFILE' else 'HOME']
|
||||
|
||||
app.getBrowserWindows = ->
|
||||
require('../../atom/objects-registry.js').getAllWindows()
|
||||
|
||||
app.setApplicationMenu = (menu) ->
|
||||
require('menu').setApplicationMenu menu
|
||||
|
||||
app.getApplicationMenu = ->
|
||||
require('menu').getApplicationMenu()
|
||||
|
||||
app.commandLine =
|
||||
appendSwitch: bindings.appendSwitch,
|
||||
appendArgument: bindings.appendArgument
|
||||
|
||||
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,28 +1,36 @@
|
||||
EventEmitter = require('events').EventEmitter
|
||||
app = require 'app'
|
||||
v8Util = process.atomBinding 'v8_util'
|
||||
objectsRegistry = require '../../atom/objects-registry.js'
|
||||
|
||||
BrowserWindow = process.atomBinding('window').BrowserWindow
|
||||
BrowserWindow::__proto__ = EventEmitter.prototype
|
||||
|
||||
BrowserWindow::_init = ->
|
||||
# Simulate the application menu on platforms other than OS X.
|
||||
if process.platform isnt 'darwin'
|
||||
menu = app.getApplicationMenu()
|
||||
@setMenu menu if menu?
|
||||
|
||||
BrowserWindow::toggleDevTools = ->
|
||||
opened = v8Util.getHiddenValue this, 'devtoolsOpened'
|
||||
if opened
|
||||
@closeDevTools()
|
||||
v8Util.setHiddenValue this, 'devtoolsOpened', false
|
||||
else
|
||||
@openDevTools()
|
||||
v8Util.setHiddenValue this, 'devtoolsOpened', true
|
||||
if @isDevToolsOpened() then @closeDevTools() else @openDevTools()
|
||||
|
||||
BrowserWindow::restart = ->
|
||||
@loadUrl(@getUrl())
|
||||
|
||||
BrowserWindow::setMenu = (menu) ->
|
||||
throw new Error('BrowserWindow.setMenu is only available on Windows') unless process.platform is 'win32'
|
||||
|
||||
throw new TypeError('Invalid menu') unless menu?.constructor?.name is 'Menu'
|
||||
|
||||
@menu = menu # Keep a reference of menu in case of GC.
|
||||
@menu.attachToWindow this
|
||||
|
||||
BrowserWindow.getFocusedWindow = ->
|
||||
windows = objectsRegistry.getAllWindows()
|
||||
windows = app.getBrowserWindows()
|
||||
return window for window in windows when window.isFocused()
|
||||
|
||||
BrowserWindow.fromProcessIdAndRoutingId = (processId, routingId) ->
|
||||
windows = objectsRegistry.getAllWindows()
|
||||
windows = app.getBrowserWindows()
|
||||
return window for window in windows when window.getProcessId() == processId and
|
||||
window.getRoutingId() == routingId
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
binding = process.atomBinding 'dialog'
|
||||
v8Util = process.atomBinding 'v8_util'
|
||||
BrowserWindow = require 'browser-window'
|
||||
|
||||
fileDialogProperties =
|
||||
@@ -7,48 +8,71 @@ fileDialogProperties =
|
||||
messageBoxTypes = ['none', 'info', 'warning']
|
||||
|
||||
module.exports =
|
||||
showOpenDialog: (options) ->
|
||||
options = title: 'Open', properties: ['openFile'] unless options?
|
||||
options.properties = options.properties ? ['openFile']
|
||||
showOpenDialog: (window, options, callback) ->
|
||||
unless window?.constructor is BrowserWindow
|
||||
# Shift.
|
||||
callback = options
|
||||
options = window
|
||||
window = null
|
||||
|
||||
options ?= title: 'Open', properties: ['openFile']
|
||||
options.properties ?= ['openFile']
|
||||
throw new TypeError('Properties need to be array') unless Array.isArray options.properties
|
||||
|
||||
properties = 0
|
||||
for prop, value of fileDialogProperties
|
||||
properties |= value if prop in options.properties
|
||||
|
||||
options.title = options.title ? ''
|
||||
options.defaultPath = options.defaultPath ? ''
|
||||
options.title ?= ''
|
||||
options.defaultPath ?= ''
|
||||
|
||||
binding.showOpenDialog options.title, options.defaultPath, properties
|
||||
binding.showOpenDialog String(options.title),
|
||||
String(options.defaultPath),
|
||||
properties,
|
||||
window,
|
||||
callback
|
||||
|
||||
showSaveDialog: (window, options) ->
|
||||
throw new TypeError('Invalid window') unless window?.constructor is BrowserWindow
|
||||
options = title: 'Save' unless options?
|
||||
|
||||
options.title = options.title ? ''
|
||||
options.defaultPath = options.defaultPath ? ''
|
||||
|
||||
binding.showSaveDialog window, options.title, options.defaultPath
|
||||
|
||||
showMessageBox: (window, options) ->
|
||||
if window? and window.constructor isnt BrowserWindow
|
||||
showSaveDialog: (window, options, callback) ->
|
||||
unless window?.constructor is BrowserWindow
|
||||
# Shift.
|
||||
callback = options
|
||||
options = window
|
||||
window = null
|
||||
|
||||
options = type: 'none' unless options?
|
||||
options.type = options.type ? 'none'
|
||||
options ?= title: 'Save'
|
||||
options.title ?= ''
|
||||
options.defaultPath ?= ''
|
||||
|
||||
binding.showSaveDialog String(options.title),
|
||||
String(options.defaultPath),
|
||||
window,
|
||||
callback
|
||||
|
||||
showMessageBox: (window, options, callback) ->
|
||||
unless window?.constructor is BrowserWindow
|
||||
# Shift.
|
||||
callback = options
|
||||
options = window
|
||||
window = null
|
||||
|
||||
options ?= type: 'none'
|
||||
options.type ?= 'none'
|
||||
options.type = messageBoxTypes.indexOf options.type
|
||||
throw new TypeError('Invalid message box type') unless options.type > -1
|
||||
|
||||
throw new TypeError('Buttons need to be array') unless Array.isArray options.buttons
|
||||
|
||||
options.title = options.title ? ''
|
||||
options.message = options.message ? ''
|
||||
options.detail = options.detail ? ''
|
||||
options.title ?= ''
|
||||
options.message ?= ''
|
||||
options.detail ?= ''
|
||||
|
||||
binding.showMessageBox options.type,
|
||||
options.buttons,
|
||||
String(options.title),
|
||||
String(options.message),
|
||||
String(options.detail),
|
||||
window
|
||||
window,
|
||||
callback
|
||||
|
||||
# Mark standard asynchronous functions.
|
||||
v8Util.setHiddenValue f, 'asynchronous', true for k, f of module.exports
|
||||
|
||||
@@ -14,8 +14,13 @@ class Ipc extends EventEmitter
|
||||
constructor: ->
|
||||
process.on 'ATOM_INTERNAL_MESSAGE', (args...) =>
|
||||
@emit(args...)
|
||||
process.on 'ATOM_INTERNAL_MESSAGE_SYNC', (args...) =>
|
||||
@emit(args...)
|
||||
process.on 'ATOM_INTERNAL_MESSAGE_SYNC', (channel, event, args...) =>
|
||||
set = (value) -> event.sendReply JSON.stringify(value)
|
||||
|
||||
Object.defineProperty event, 'returnValue', {set}
|
||||
Object.defineProperty event, 'result', {set}
|
||||
|
||||
@emit(channel, event, args...)
|
||||
|
||||
send: (processId, routingId, args...) ->
|
||||
@sendChannel(processId, routingId, 'message', args...)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
BrowserWindow = require 'browser-window'
|
||||
|
||||
nextCommandId = 0
|
||||
|
||||
class MenuItem
|
||||
@@ -6,7 +8,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 +16,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 this, BrowserWindow.getFocusedWindow()
|
||||
else if typeof @selector is 'string'
|
||||
Menu.sendActionToFirstResponder @selector
|
||||
|
||||
module.exports = MenuItem
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
EventEmitter = require('events').EventEmitter
|
||||
BrowserWindow = require 'browser-window'
|
||||
EventEmitter = require('events').EventEmitter
|
||||
IDWeakMap = require 'id-weak-map'
|
||||
MenuItem = require 'menu-item'
|
||||
|
||||
app = require 'app'
|
||||
bindings = process.atomBinding 'menu'
|
||||
|
||||
Menu = bindings.Menu
|
||||
@@ -28,19 +30,32 @@ 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() if activeItem?
|
||||
@items.splice pos, 0, item
|
||||
@commandsMap[item.commandId] = item
|
||||
|
||||
applicationMenu = null
|
||||
Menu.setApplicationMenu = (menu) ->
|
||||
throw new TypeError('Invalid menu') unless menu?.constructor is Menu
|
||||
bindings.setApplicationMenu menu
|
||||
applicationMenu = menu # Keep a reference.
|
||||
|
||||
if process.platform is 'darwin'
|
||||
bindings.setApplicationMenu menu
|
||||
else
|
||||
windows = app.getBrowserWindows()
|
||||
w.setMenu menu for w in windows
|
||||
|
||||
Menu.getApplicationMenu = -> applicationMenu
|
||||
|
||||
Menu.sendActionToFirstResponder = bindings.sendActionToFirstResponder
|
||||
|
||||
@@ -52,7 +67,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,8 +1,17 @@
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
|
||||
# Enable idle gc.
|
||||
process.atomBinding('idle_gc').start()
|
||||
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
|
||||
|
||||
# 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 = {}
|
||||
@@ -17,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'
|
||||
|
||||
@@ -29,11 +38,11 @@ process.on 'uncaughtException', (error) ->
|
||||
# Show error in GUI.
|
||||
message = error.stack ? "#{error.name}: #{error.message}"
|
||||
require('dialog').showMessageBox
|
||||
type: 'warning'
|
||||
title: 'An javascript error occured in the browser'
|
||||
message: 'uncaughtException'
|
||||
detail: message
|
||||
buttons: ['OK']
|
||||
type: 'warning'
|
||||
title: 'An javascript error occured in the browser'
|
||||
message: 'uncaughtException'
|
||||
detail: message
|
||||
buttons: ['OK']
|
||||
|
||||
# Load the RPC server.
|
||||
require './rpc-server.js'
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
BrowserWindow = require 'browser-window'
|
||||
EventEmitter = require('events').EventEmitter
|
||||
IDWeakMap = require 'id-weak-map'
|
||||
v8Util = process.atomBinding 'v8_util'
|
||||
|
||||
# Class to reference all objects.
|
||||
class ObjectsStore
|
||||
@stores = {}
|
||||
|
||||
@@ -36,50 +39,57 @@ class ObjectsStore
|
||||
key = "#{processId}_#{routingId}"
|
||||
delete @stores[key]
|
||||
|
||||
# Objects in weak map will be not referenced (so we won't leak memory), and
|
||||
# every object created in browser will have a unique id in weak map.
|
||||
objectsWeakMap = new IDWeakMap
|
||||
objectsWeakMap.add = (obj) ->
|
||||
id = IDWeakMap::add.call this, obj
|
||||
Object.defineProperty obj, 'id',
|
||||
enumerable: true, writable: false, value: id
|
||||
id
|
||||
class ObjectsRegistry extends EventEmitter
|
||||
constructor: ->
|
||||
# Objects in weak map will be not referenced (so we won't leak memory), and
|
||||
# every object created in browser will have a unique id in weak map.
|
||||
@objectsWeakMap = new IDWeakMap
|
||||
@objectsWeakMap.add = (obj) ->
|
||||
id = IDWeakMap::add.call this, obj
|
||||
v8Util.setHiddenValue obj, 'atomId', id
|
||||
id
|
||||
|
||||
windowsWeakMap = new IDWeakMap
|
||||
# Remember all windows in the weak map.
|
||||
@windowsWeakMap = new IDWeakMap
|
||||
process.on 'ATOM_BROWSER_INTERNAL_NEW', (obj) =>
|
||||
if obj.constructor is BrowserWindow
|
||||
id = @windowsWeakMap.add obj
|
||||
obj.on 'destroyed', => @windowsWeakMap.remove id
|
||||
|
||||
process.on 'ATOM_BROWSER_INTERNAL_NEW', (obj) ->
|
||||
# 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
|
||||
# Register a new object, the object would be kept referenced until you release
|
||||
# it explicitly.
|
||||
add: (processId, routingId, obj) ->
|
||||
# Some native objects may already been added to objectsWeakMap, be care not
|
||||
# to add it twice.
|
||||
@objectsWeakMap.add obj unless v8Util.getHiddenValue obj, 'atomId'
|
||||
id = v8Util.getHiddenValue obj, 'atomId'
|
||||
|
||||
# Also remember all windows.
|
||||
if obj.constructor is BrowserWindow
|
||||
id = windowsWeakMap.add obj
|
||||
obj.on 'destroyed', ->
|
||||
windowsWeakMap.remove id
|
||||
# Store and reference the object, then return the storeId which points to
|
||||
# where the object is stored. The caller can later dereference the object
|
||||
# with the storeId.
|
||||
# We use a difference key because the same object can be referenced for
|
||||
# multiple times by the same renderer view.
|
||||
store = ObjectsStore.forRenderView processId, routingId
|
||||
storeId = store.add obj
|
||||
|
||||
exports.add = (processId, routingId, obj) ->
|
||||
# Some native objects may already been added to objectsWeakMap, be care not
|
||||
# to add it twice.
|
||||
objectsWeakMap.add obj unless obj.id? and objectsWeakMap.has obj.id
|
||||
[id, storeId]
|
||||
|
||||
# Store and reference the object, then return the storeId which points to
|
||||
# where the object is stored. The caller can later dereference the object
|
||||
# with the storeId.
|
||||
store = ObjectsStore.forRenderView processId, routingId
|
||||
store.add obj
|
||||
# Get an object according to its id.
|
||||
get: (id) ->
|
||||
@objectsWeakMap.get id
|
||||
|
||||
exports.get = (id) ->
|
||||
objectsWeakMap.get id
|
||||
# Remove an object according to its storeId.
|
||||
remove: (processId, routingId, storeId) ->
|
||||
ObjectsStore.forRenderView(processId, routingId).remove storeId
|
||||
|
||||
exports.getAllWindows = () ->
|
||||
keys = windowsWeakMap.keys()
|
||||
windowsWeakMap.get key for key in keys
|
||||
# Clear all references to objects from renderer view.
|
||||
clear: (processId, routingId) ->
|
||||
@emit "release-renderer-view-#{processId}-#{routingId}"
|
||||
ObjectsStore.releaseForRenderView processId, routingId
|
||||
|
||||
exports.remove = (processId, routingId, storeId) ->
|
||||
ObjectsStore.forRenderView(processId, routingId).remove storeId
|
||||
# Return an array of all browser windows.
|
||||
getAllWindows: ->
|
||||
keys = @windowsWeakMap.keys()
|
||||
@windowsWeakMap.get key for key in keys
|
||||
|
||||
exports.clear = (processId, routingId) ->
|
||||
ObjectsStore.releaseForRenderView processId, routingId
|
||||
module.exports = new ObjectsRegistry
|
||||
|
||||
@@ -22,8 +22,7 @@ valueToMeta = (processId, routingId, value) ->
|
||||
# Reference the original value if it's an object, because when it's
|
||||
# passed to renderer we would assume the renderer keeps a reference of
|
||||
# it.
|
||||
meta.storeId = objectsRegistry.add processId, routingId, value
|
||||
meta.id = value.id
|
||||
[meta.id, meta.storeId] = objectsRegistry.add processId, routingId, value
|
||||
|
||||
meta.members = []
|
||||
meta.members.push {name: prop, type: typeof field} for prop, field of value
|
||||
@@ -39,40 +38,69 @@ 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'
|
||||
rendererReleased = false
|
||||
objectsRegistry.once "release-renderer-view-#{processId}-#{routingId}", ->
|
||||
rendererReleased = true
|
||||
|
||||
ret = ->
|
||||
throw new Error('Calling a callback of released renderer view') if rendererReleased
|
||||
ipc.sendChannel processId, routingId, 'ATOM_RENDERER_CALLBACK', meta.id, valueToMeta(processId, routingId, arguments)
|
||||
v8Util.setDestructor ret, ->
|
||||
return if rendererReleased
|
||||
ipc.sendChannel processId, routingId, 'ATOM_RENDERER_RELEASE_CALLBACK', meta.id
|
||||
ret
|
||||
else throw new TypeError("Unknown type: #{meta.type}")
|
||||
|
||||
args.map metaToValue
|
||||
|
||||
# Call a function and send reply asynchronously if it's a an asynchronous
|
||||
# style function and the caller didn't pass a callback.
|
||||
callFunction = (event, processId, routingId, func, caller, args) ->
|
||||
if v8Util.getHiddenValue(func, 'asynchronous') and typeof args[args.length - 1] isnt 'function'
|
||||
args.push (ret) ->
|
||||
event.returnValue = valueToMeta processId, routingId, ret
|
||||
func.apply caller, args
|
||||
else
|
||||
ret = func.apply caller, args
|
||||
event.returnValue = valueToMeta processId, routingId, ret
|
||||
|
||||
ipc.on 'ATOM_BROWSER_REQUIRE', (event, processId, routingId, module) ->
|
||||
try
|
||||
event.result = valueToMeta processId, routingId, require(module)
|
||||
event.returnValue = valueToMeta processId, routingId, require(module)
|
||||
catch e
|
||||
event.result = errorToMeta e
|
||||
event.returnValue = errorToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_GLOBAL', (event, processId, routingId, name) ->
|
||||
try
|
||||
event.result = valueToMeta processId, routingId, global[name]
|
||||
event.returnValue = valueToMeta processId, routingId, global[name]
|
||||
catch e
|
||||
event.result = errorToMeta e
|
||||
event.returnValue = errorToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_RELEASE_RENDER_VIEW', (event, processId, routingId) ->
|
||||
objectsRegistry.clear processId, routingId
|
||||
event.returnValue = null
|
||||
|
||||
ipc.on 'ATOM_BROWSER_CURRENT_WINDOW', (event, processId, routingId) ->
|
||||
try
|
||||
BrowserWindow = require 'browser-window'
|
||||
window = BrowserWindow.fromProcessIdAndRoutingId processId, routingId
|
||||
event.result = valueToMeta processId, routingId, window
|
||||
event.returnValue = valueToMeta processId, routingId, window
|
||||
catch e
|
||||
event.result = errorToMeta e
|
||||
event.returnValue = errorToMeta e
|
||||
|
||||
ipc.on 'ATOM_BROWSER_CONSTRUCTOR', (event, processId, routingId, id, args) ->
|
||||
try
|
||||
@@ -81,48 +109,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"
|
||||
|
||||
@@ -20,7 +22,7 @@ AtomBrowserMainParts* AtomBrowserMainParts::self_ = NULL;
|
||||
AtomBrowserMainParts::AtomBrowserMainParts()
|
||||
: atom_bindings_(new AtomBrowserBindings),
|
||||
browser_(new Browser),
|
||||
node_bindings_(NodeBindings::CreateInBrowser()) {
|
||||
node_bindings_(NodeBindings::Create(true)) {
|
||||
DCHECK(!self_) << "Cannot have two AtomBrowserMainParts";
|
||||
self_ = this;
|
||||
}
|
||||
@@ -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,10 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() {
|
||||
#endif
|
||||
}
|
||||
|
||||
int AtomBrowserMainParts::PreCreateThreads() {
|
||||
// TODO(zcbenz): Calling CreateIsolate() on Windows when updated to Chrome30.
|
||||
net::ProxyResolverV8::RememberDefaultIsolate();
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -30,6 +30,7 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
|
||||
// Implementations of content::BrowserMainParts.
|
||||
virtual void PostEarlyInitialization() OVERRIDE;
|
||||
virtual void PreMainMessageLoopRun() OVERRIDE;
|
||||
virtual int PreCreateThreads() OVERRIDE;
|
||||
#if defined(OS_MACOSX)
|
||||
virtual void PreMainMessageLoopStart() OVERRIDE;
|
||||
virtual void PostDestroyThreads() OVERRIDE;
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
|
||||
#include "browser/atom_browser_main_parts.h"
|
||||
|
||||
#import "base/mac/bundle_locations.h"
|
||||
#include "base/files/file_path.h"
|
||||
#import "base/mac/foundation_util.h"
|
||||
#import "browser/atom_application_mac.h"
|
||||
#import "browser/atom_application_delegate_mac.h"
|
||||
#import "vendor/brightray/common/mac/main_application_bundle.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
@@ -17,10 +19,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
|
||||
|
||||
205
browser/default_app/default_app.js
Normal file
205
browser/default_app/default_app.js
Normal file
@@ -0,0 +1,205 @@
|
||||
var app = require('app');
|
||||
var dialog = require('dialog');
|
||||
var delegate = require('atom-delegate');
|
||||
var ipc = require('ipc');
|
||||
var Menu = require('menu');
|
||||
var MenuItem = require('menu-item');
|
||||
var BrowserWindow = require('browser-window');
|
||||
|
||||
var mainWindow = null;
|
||||
var menu = null;
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function() {
|
||||
app.terminate();
|
||||
});
|
||||
|
||||
app.on('open-url', function(event, url) {
|
||||
dialog.showMessageBox({message: url, buttons: ['OK']});
|
||||
});
|
||||
|
||||
app.on('finish-launching', function() {
|
||||
app.commandLine.appendSwitch('js-flags', '--harmony_collections');
|
||||
|
||||
mainWindow = new BrowserWindow({ width: 800, height: 600 });
|
||||
mainWindow.loadUrl('file://' + __dirname + '/index.html');
|
||||
|
||||
mainWindow.on('page-title-updated', function(event, title) {
|
||||
event.preventDefault();
|
||||
|
||||
this.setTitle('Atom Shell - ' + title);
|
||||
});
|
||||
|
||||
mainWindow.on('closed', function() {
|
||||
mainWindow = null;
|
||||
});
|
||||
|
||||
mainWindow.on('unresponsive', function() {
|
||||
console.log('unresponsive');
|
||||
});
|
||||
|
||||
if (process.platform == 'darwin') {
|
||||
var template = [
|
||||
{
|
||||
label: 'Atom Shell',
|
||||
submenu: [
|
||||
{
|
||||
label: 'About Atom Shell',
|
||||
selector: 'orderFrontStandardAboutPanel:'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Hide Atom Shell',
|
||||
accelerator: 'Command+H',
|
||||
selector: 'hide:'
|
||||
},
|
||||
{
|
||||
label: 'Hide Others',
|
||||
accelerator: 'Command+Shift+H',
|
||||
selector: 'hideOtherApplications:'
|
||||
},
|
||||
{
|
||||
label: 'Show All',
|
||||
selector: 'unhideAllApplications:'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Quit',
|
||||
accelerator: 'Command+Q',
|
||||
click: function() { app.quit(); }
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Edit',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Undo',
|
||||
accelerator: 'Command+Z',
|
||||
selector: 'undo:'
|
||||
},
|
||||
{
|
||||
label: 'Redo',
|
||||
accelerator: 'Shift+Command+Z',
|
||||
selector: 'redo:'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Cut',
|
||||
accelerator: 'Command+X',
|
||||
selector: 'cut:'
|
||||
},
|
||||
{
|
||||
label: 'Copy',
|
||||
accelerator: 'Command+C',
|
||||
selector: 'copy:'
|
||||
},
|
||||
{
|
||||
label: 'Paste',
|
||||
accelerator: 'Command+V',
|
||||
selector: 'paste:'
|
||||
},
|
||||
{
|
||||
label: 'Select All',
|
||||
accelerator: 'Command+A',
|
||||
selector: 'selectAll:'
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'View',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Reload',
|
||||
accelerator: 'Command+R',
|
||||
click: function() { BrowserWindow.getFocusedWindow().restart(); }
|
||||
},
|
||||
{
|
||||
label: 'Enter Fullscreen',
|
||||
click: function() { BrowserWindow.getFocusedWindow().setFullscreen(true); }
|
||||
},
|
||||
{
|
||||
label: 'Toggle DevTools',
|
||||
accelerator: 'Alt+Command+I',
|
||||
click: function() { BrowserWindow.getFocusedWindow().toggleDevTools(); }
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Window',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Minimize',
|
||||
accelerator: 'Command+M',
|
||||
selector: 'performMiniaturize:'
|
||||
},
|
||||
{
|
||||
label: 'Close',
|
||||
accelerator: 'Command+W',
|
||||
selector: 'performClose:'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Bring All to Front',
|
||||
selector: 'arrangeInFront:'
|
||||
},
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
menu = Menu.buildFromTemplate(template);
|
||||
Menu.setApplicationMenu(menu);
|
||||
} else {
|
||||
var template = [
|
||||
{
|
||||
label: 'File',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Open',
|
||||
accelerator: 'Command+O',
|
||||
},
|
||||
{
|
||||
label: 'Close',
|
||||
accelerator: 'Command+W',
|
||||
click: function() { mainWindow.close(); }
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'View',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Reload',
|
||||
accelerator: 'Command+R',
|
||||
click: function() { mainWindow.restart(); }
|
||||
},
|
||||
{
|
||||
label: 'Enter Fullscreen',
|
||||
click: function() { mainWindow.setFullscreen(true); }
|
||||
},
|
||||
{
|
||||
label: 'Toggle DevTools',
|
||||
accelerator: 'Alt+Command+I',
|
||||
click: function() { mainWindow.toggleDevTools(); }
|
||||
},
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
menu = Menu.buildFromTemplate(template);
|
||||
mainWindow.setMenu(menu);
|
||||
}
|
||||
|
||||
ipc.on('message', function(processId, routingId, type) {
|
||||
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,165 +1,33 @@
|
||||
var app = require('app');
|
||||
var dialog = require('dialog');
|
||||
var delegate = require('atom-delegate');
|
||||
var ipc = require('ipc');
|
||||
var Menu = require('menu');
|
||||
var MenuItem = require('menu-item');
|
||||
var BrowserWindow = require('browser-window');
|
||||
var path = require('path');
|
||||
var optimist = require('optimist');
|
||||
|
||||
var mainWindow = null;
|
||||
var menu = null;
|
||||
|
||||
// Quit when all windows are closed.
|
||||
// Quit when all windows are closed and no other one is listening to this.
|
||||
app.on('window-all-closed', function() {
|
||||
app.terminate();
|
||||
if (app.listeners('window-all-closed').length == 1)
|
||||
app.quit();
|
||||
});
|
||||
|
||||
app.on('open-url', function(event, url) {
|
||||
dialog.showMessageBox({message: url, buttons: ['OK']});
|
||||
});
|
||||
var argv = optimist(process.argv.slice(1)).argv;
|
||||
|
||||
delegate.browserMainParts.preMainMessageLoopRun = function() {
|
||||
app.commandLine.appendSwitch('js-flags', '--harmony_collections');
|
||||
|
||||
mainWindow = new BrowserWindow({ width: 800, height: 600 });
|
||||
mainWindow.loadUrl('file://' + __dirname + '/index.html');
|
||||
|
||||
mainWindow.on('page-title-updated', function(event, title) {
|
||||
event.preventDefault();
|
||||
|
||||
this.setTitle('Atom Shell - ' + title);
|
||||
});
|
||||
|
||||
mainWindow.on('closed', function() {
|
||||
console.log('closed');
|
||||
mainWindow = null;
|
||||
});
|
||||
|
||||
mainWindow.on('unresponsive', function() {
|
||||
console.log('unresponsive');
|
||||
});
|
||||
|
||||
var template = [
|
||||
{
|
||||
label: 'Atom Shell',
|
||||
submenu: [
|
||||
{
|
||||
label: 'About Atom Shell',
|
||||
selector: 'orderFrontStandardAboutPanel:'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Hide Atom Shell',
|
||||
accelerator: 'Command+H',
|
||||
selector: 'hide:'
|
||||
},
|
||||
{
|
||||
label: 'Hide Others',
|
||||
accelerator: 'Command+Shift+H',
|
||||
selector: 'hideOtherApplications:'
|
||||
},
|
||||
{
|
||||
label: 'Show All',
|
||||
selector: 'unhideAllApplications:'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Quit',
|
||||
accelerator: 'Command+Q',
|
||||
click: function() { app.quit(); }
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Edit',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Undo',
|
||||
accelerator: 'Command+Z',
|
||||
selector: 'undo:'
|
||||
},
|
||||
{
|
||||
label: 'Redo',
|
||||
accelerator: 'Shift+Command+Z',
|
||||
selector: 'redo:'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Cut',
|
||||
accelerator: 'Command+X',
|
||||
selector: 'cut:'
|
||||
},
|
||||
{
|
||||
label: 'Copy',
|
||||
accelerator: 'Command+C',
|
||||
selector: 'copy:'
|
||||
},
|
||||
{
|
||||
label: 'Paste',
|
||||
accelerator: 'Command+V',
|
||||
selector: 'paste:'
|
||||
},
|
||||
{
|
||||
label: 'Select All',
|
||||
accelerator: 'Command+A',
|
||||
selector: 'selectAll:'
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'View',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Reload',
|
||||
accelerator: 'Command+R',
|
||||
click: function() { BrowserWindow.getFocusedWindow().restart(); }
|
||||
},
|
||||
{
|
||||
label: 'Enter Fullscreen',
|
||||
click: function() { BrowserWindow.getFocusedWindow().setFullscreen(true); }
|
||||
},
|
||||
{
|
||||
label: 'Toggle DevTools',
|
||||
accelerator: 'Alt+Command+I',
|
||||
click: function() { BrowserWindow.getFocusedWindow().toggleDevTools(); }
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Window',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Minimize',
|
||||
accelerator: 'Command+M',
|
||||
selector: 'performMiniaturize:'
|
||||
},
|
||||
{
|
||||
label: 'Close',
|
||||
accelerator: 'Command+W',
|
||||
selector: 'performClose:'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Bring All to Front',
|
||||
selector: 'arrangeInFront:'
|
||||
},
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
menu = Menu.buildFromTemplate(template);
|
||||
Menu.setApplicationMenu(menu);
|
||||
|
||||
ipc.on('message', function(processId, routingId, type) {
|
||||
if (type == 'menu')
|
||||
menu.popup(mainWindow);
|
||||
});
|
||||
// Start the specified app if there is one specified in command line, otherwise
|
||||
// start the default app.
|
||||
if (argv._.length > 0) {
|
||||
try {
|
||||
require(path.resolve(argv._[0]));
|
||||
} catch(e) {
|
||||
if (e.code == 'MODULE_NOT_FOUND') {
|
||||
console.error(e.stack);
|
||||
console.error('Specified app is invalid');
|
||||
process.exit(1);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
} else if (argv.version) {
|
||||
console.log('v' + process.versions['atom-shell']);
|
||||
process.exit(0);
|
||||
} else {
|
||||
require('./default_app.js');
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
{
|
||||
"name" : "atom",
|
||||
"version" : "0.1.0",
|
||||
"main" : "main.js"
|
||||
"name": "atom",
|
||||
"version": "0.1.0",
|
||||
"main": "main.js",
|
||||
"dependencies": {
|
||||
"optimist": "*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -11,7 +11,7 @@
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>atom.icns</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<string>0.6.12</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
|
||||
@@ -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
|
||||
@@ -1,18 +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"
|
||||
|
||||
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) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/file_util.h"
|
||||
#include "base/message_loop.h"
|
||||
#include "base/utf_string_conversions.h"
|
||||
#include "base/values.h"
|
||||
#include "brightray/browser/inspectable_web_contents.h"
|
||||
@@ -14,8 +16,8 @@
|
||||
#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"
|
||||
#include "content/public/browser/navigation_entry.h"
|
||||
#include "content/public/browser/notification_details.h"
|
||||
@@ -23,12 +25,15 @@
|
||||
#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"
|
||||
#include "ui/gfx/codec/png_codec.h"
|
||||
#include "ui/gfx/point.h"
|
||||
#include "ui/gfx/rect.h"
|
||||
#include "ui/gfx/size.h"
|
||||
#include "webkit/glue/image_decoder.h"
|
||||
|
||||
using content::NavigationEntry;
|
||||
|
||||
@@ -37,9 +42,19 @@ namespace atom {
|
||||
NativeWindow::NativeWindow(content::WebContents* web_contents,
|
||||
base::DictionaryValue* options)
|
||||
: content::WebContentsObserver(web_contents),
|
||||
has_frame_(true),
|
||||
is_closed_(false),
|
||||
not_responding_(false),
|
||||
inspectable_web_contents_(
|
||||
brightray::InspectableWebContents::Create(web_contents)) {
|
||||
options->GetBoolean(switches::kFrame, &has_frame_);
|
||||
|
||||
std::string icon;
|
||||
if (options->GetString(switches::kIcon, &icon)) {
|
||||
if (!SetIcon(icon))
|
||||
LOG(ERROR) << "Failed to set icon to " << icon;
|
||||
}
|
||||
|
||||
web_contents->SetDelegate(this);
|
||||
|
||||
WindowList::AddWindow(this);
|
||||
@@ -135,6 +150,18 @@ void NativeWindow::CloseDevTools() {
|
||||
inspectable_web_contents()->GetView()->CloseDevTools();
|
||||
}
|
||||
|
||||
bool NativeWindow::IsDevToolsOpened() {
|
||||
return inspectable_web_contents()->IsDevToolsOpened();
|
||||
}
|
||||
|
||||
void NativeWindow::InspectElement(int x, int y) {
|
||||
OpenDevTools();
|
||||
content::RenderViewHost* rvh = GetWebContents()->GetRenderViewHost();
|
||||
scoped_refptr<content::DevToolsAgentHost> agent(
|
||||
content::DevToolsAgentHost::GetOrCreateFor(rvh));
|
||||
agent->InspectElement(x, y);
|
||||
}
|
||||
|
||||
void NativeWindow::FocusOnWebView() {
|
||||
GetWebContents()->GetRenderViewHost()->Focus();
|
||||
}
|
||||
@@ -143,10 +170,45 @@ void NativeWindow::BlurWebView() {
|
||||
GetWebContents()->GetRenderViewHost()->Blur();
|
||||
}
|
||||
|
||||
bool NativeWindow::IsWebViewFocused() {
|
||||
return GetWebContents()->GetRenderViewHost()->GetView()->HasFocus();
|
||||
}
|
||||
|
||||
void NativeWindow::RestartHangMonitorTimeout() {
|
||||
GetWebContents()->GetRenderViewHost()->RestartHangMonitorTimeout();
|
||||
}
|
||||
|
||||
bool NativeWindow::SetIcon(const std::string& str_path) {
|
||||
base::FilePath path = base::FilePath::FromUTF8Unsafe(str_path);
|
||||
|
||||
// Read the file from disk.
|
||||
std::string file_contents;
|
||||
if (path.empty() || !file_util::ReadFileToString(path, &file_contents))
|
||||
return false;
|
||||
|
||||
// Decode the bitmap using WebKit's image decoder.
|
||||
const unsigned char* data =
|
||||
reinterpret_cast<const unsigned char*>(file_contents.data());
|
||||
webkit_glue::ImageDecoder decoder;
|
||||
scoped_ptr<SkBitmap> decoded(new SkBitmap());
|
||||
*decoded = decoder.Decode(data, file_contents.length());
|
||||
if (decoded->empty())
|
||||
return false; // Unable to decode.
|
||||
|
||||
icon_ = gfx::Image::CreateFrom1xBitmap(*decoded.release());
|
||||
return true;
|
||||
}
|
||||
|
||||
void NativeWindow::CapturePage(const gfx::Rect& rect,
|
||||
const CapturePageCallback& callback) {
|
||||
GetWebContents()->GetRenderViewHost()->CopyFromBackingStore(
|
||||
rect,
|
||||
gfx::Size(),
|
||||
base::Bind(&NativeWindow::OnCapturePageDone,
|
||||
base::Unretained(this),
|
||||
callback));
|
||||
}
|
||||
|
||||
void NativeWindow::CloseWebContents() {
|
||||
bool prevent_default = false;
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver,
|
||||
@@ -223,14 +285,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;
|
||||
}
|
||||
@@ -243,6 +297,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());
|
||||
@@ -266,31 +327,44 @@ bool NativeWindow::IsPopupOrPanel(const content::WebContents* source) const {
|
||||
}
|
||||
|
||||
void NativeWindow::RendererUnresponsive(content::WebContents* source) {
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnRendererUnresponsive());
|
||||
not_responding_ = true;
|
||||
base::MessageLoop::current()->PostDelayedTask(
|
||||
FROM_HERE,
|
||||
base::Bind(&NativeWindow::RendererUnresponsiveDelayed,
|
||||
base::Unretained(this)),
|
||||
base::TimeDelta::FromSeconds(1));
|
||||
}
|
||||
|
||||
void NativeWindow::RendererResponsive(content::WebContents* source) {
|
||||
not_responding_ = false;
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnRendererResponsive());
|
||||
}
|
||||
|
||||
void NativeWindow::NavigationStateChanged(const content::WebContents* source,
|
||||
unsigned changed_flags) {
|
||||
if (changed_flags == content::INVALIDATE_TYPE_TAB &&
|
||||
source->IsCrashed())
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnRendererCrashed());
|
||||
}
|
||||
|
||||
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()
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
void NativeWindow::RenderViewGone(base::TerminationStatus status) {
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnRendererCrashed());
|
||||
}
|
||||
|
||||
void NativeWindow::RendererUnresponsiveDelayed() {
|
||||
if (not_responding_)
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver,
|
||||
observers_,
|
||||
OnRendererUnresponsive());
|
||||
}
|
||||
|
||||
void NativeWindow::Observe(int type,
|
||||
const content::NotificationSource& source,
|
||||
const content::NotificationDetails& details) {
|
||||
@@ -311,7 +385,16 @@ void NativeWindow::Observe(int type,
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindow::OnRendererMessage(const std::string& channel,
|
||||
void NativeWindow::OnCapturePageDone(const CapturePageCallback& callback,
|
||||
bool succeed,
|
||||
const SkBitmap& bitmap) {
|
||||
std::vector<unsigned char> data;
|
||||
if (succeed)
|
||||
gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, true, &data);
|
||||
callback.Run(data);
|
||||
}
|
||||
|
||||
void NativeWindow::OnRendererMessage(const string16& channel,
|
||||
const base::ListValue& args) {
|
||||
AtomBrowserMainParts::Get()->atom_bindings()->OnRendererMessage(
|
||||
GetWebContents()->GetRenderProcessHost()->GetID(),
|
||||
@@ -320,15 +403,16 @@ void NativeWindow::OnRendererMessage(const std::string& channel,
|
||||
args);
|
||||
}
|
||||
|
||||
void NativeWindow::OnRendererMessageSync(const std::string& channel,
|
||||
void NativeWindow::OnRendererMessageSync(const string16& channel,
|
||||
const base::ListValue& args,
|
||||
base::DictionaryValue* result) {
|
||||
IPC::Message* reply_msg) {
|
||||
AtomBrowserMainParts::Get()->atom_bindings()->OnRendererMessageSync(
|
||||
GetWebContents()->GetRenderProcessHost()->GetID(),
|
||||
GetWebContents()->GetRoutingID(),
|
||||
channel,
|
||||
args,
|
||||
result);
|
||||
this,
|
||||
reply_msg);
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
#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 "ui/gfx/image/image.h"
|
||||
#include "vendor/brightray/browser/default_web_contents_delegate.h"
|
||||
|
||||
namespace base {
|
||||
class DictionaryValue;
|
||||
@@ -35,14 +36,22 @@ 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:
|
||||
typedef base::Callback<void(const std::vector<unsigned char>& buffer)>
|
||||
CapturePageCallback;
|
||||
|
||||
virtual ~NativeWindow();
|
||||
|
||||
// Create window with existing WebContents.
|
||||
@@ -64,6 +73,7 @@ class NativeWindow : public content::WebContentsDelegate,
|
||||
virtual bool IsFocused() = 0;
|
||||
virtual void Show() = 0;
|
||||
virtual void Hide() = 0;
|
||||
virtual bool IsVisible() = 0;
|
||||
virtual void Maximize() = 0;
|
||||
virtual void Unmaximize() = 0;
|
||||
virtual void Minimize() = 0;
|
||||
@@ -93,9 +103,18 @@ class NativeWindow : public content::WebContentsDelegate,
|
||||
virtual bool IsClosed() const { return is_closed_; }
|
||||
virtual void OpenDevTools();
|
||||
virtual void CloseDevTools();
|
||||
virtual bool IsDevToolsOpened();
|
||||
virtual void InspectElement(int x, int y);
|
||||
virtual void FocusOnWebView();
|
||||
virtual void BlurWebView();
|
||||
virtual bool IsWebViewFocused();
|
||||
virtual void RestartHangMonitorTimeout();
|
||||
virtual bool SetIcon(const std::string& path);
|
||||
|
||||
// Captures the page with |rect|, |callback| would be called when capturing is
|
||||
// done.
|
||||
virtual void CapturePage(const gfx::Rect& rect,
|
||||
const CapturePageCallback& callback);
|
||||
|
||||
// The same with closing a tab in a real browser.
|
||||
//
|
||||
@@ -112,6 +131,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);
|
||||
@@ -123,6 +144,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,
|
||||
@@ -137,13 +162,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;
|
||||
@@ -151,10 +173,9 @@ class NativeWindow : public content::WebContentsDelegate,
|
||||
const content::WebContents* source) const OVERRIDE;
|
||||
virtual void RendererUnresponsive(content::WebContents* source) OVERRIDE;
|
||||
virtual void RendererResponsive(content::WebContents* source) OVERRIDE;
|
||||
virtual void NavigationStateChanged(const content::WebContents* source,
|
||||
unsigned changed_flags) OVERRIDE;
|
||||
|
||||
// Implementations of content::WebContentsObserver.
|
||||
virtual void RenderViewGone(base::TerminationStatus status) OVERRIDE;
|
||||
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
|
||||
|
||||
// Implementations of content::NotificationObserver
|
||||
@@ -162,13 +183,26 @@ class NativeWindow : public content::WebContentsDelegate,
|
||||
const content::NotificationSource& source,
|
||||
const content::NotificationDetails& details) OVERRIDE;
|
||||
|
||||
// Whether window has standard frame.
|
||||
bool has_frame_;
|
||||
|
||||
// Window icon.
|
||||
gfx::Image icon_;
|
||||
|
||||
private:
|
||||
void OnRendererMessage(const std::string& channel,
|
||||
void RendererUnresponsiveDelayed();
|
||||
|
||||
// Called when CapturePage has done.
|
||||
void OnCapturePageDone(const CapturePageCallback& callback,
|
||||
bool succeed,
|
||||
const SkBitmap& bitmap);
|
||||
|
||||
void OnRendererMessage(const string16& channel,
|
||||
const base::ListValue& args);
|
||||
|
||||
void OnRendererMessageSync(const std::string& channel,
|
||||
void OnRendererMessageSync(const string16& channel,
|
||||
const base::ListValue& args,
|
||||
base::DictionaryValue* result);
|
||||
IPC::Message* reply_msg);
|
||||
|
||||
// Notification manager.
|
||||
content::NotificationRegistrar registrar_;
|
||||
@@ -176,8 +210,12 @@ class NativeWindow : public content::WebContentsDelegate,
|
||||
// Observers of this window.
|
||||
ObserverList<NativeWindowObserver> observers_;
|
||||
|
||||
// The windows has been closed.
|
||||
bool is_closed_;
|
||||
|
||||
// The window is not responding.
|
||||
bool not_responding_;
|
||||
|
||||
scoped_ptr<AtomJavaScriptDialogManager> dialog_manager_;
|
||||
scoped_ptr<brightray::InspectableWebContents> inspectable_web_contents_;
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "browser/native_window.h"
|
||||
|
||||
class SkRegion;
|
||||
|
||||
namespace atom {
|
||||
|
||||
class NativeWindowMac : public NativeWindow {
|
||||
@@ -26,6 +28,7 @@ class NativeWindowMac : public NativeWindow {
|
||||
virtual bool IsFocused() OVERRIDE;
|
||||
virtual void Show() OVERRIDE;
|
||||
virtual void Hide() OVERRIDE;
|
||||
virtual bool IsVisible() OVERRIDE;
|
||||
virtual void Maximize() OVERRIDE;
|
||||
virtual void Unmaximize() OVERRIDE;
|
||||
virtual void Minimize() OVERRIDE;
|
||||
@@ -52,11 +55,25 @@ class NativeWindowMac : public NativeWindow {
|
||||
virtual bool IsKiosk() OVERRIDE;
|
||||
virtual gfx::NativeWindow GetNativeWindow() OVERRIDE;
|
||||
|
||||
NSWindow*& window() { return window_; }
|
||||
|
||||
void NotifyWindowBlur() { NativeWindow::NotifyWindowBlur(); }
|
||||
|
||||
// Returns true if |point| in local Cocoa coordinate system falls within
|
||||
// the draggable region.
|
||||
bool IsWithinDraggableRegion(NSPoint point) const;
|
||||
|
||||
// Called to handle a mouse event.
|
||||
void HandleMouseEvent(NSEvent* event);
|
||||
|
||||
// Clip web view to rounded corner.
|
||||
void ClipWebView();
|
||||
|
||||
NSWindow*& window() { return window_; }
|
||||
SkRegion* draggable_region() const { return draggable_region_.get(); }
|
||||
|
||||
protected:
|
||||
virtual void UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions) OVERRIDE;
|
||||
|
||||
// Implementations of content::WebContentsDelegate.
|
||||
virtual void HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
@@ -65,6 +82,9 @@ class NativeWindowMac : public NativeWindow {
|
||||
private:
|
||||
void InstallView();
|
||||
void UninstallView();
|
||||
void InstallDraggableRegionViews();
|
||||
void UpdateDraggableRegionsForCustomDrag(
|
||||
const std::vector<DraggableRegion>& regions);
|
||||
|
||||
NSWindow* window_;
|
||||
|
||||
@@ -72,6 +92,18 @@ class NativeWindowMac : public NativeWindow {
|
||||
|
||||
NSInteger attention_request_id_; // identifier from requestUserAttention
|
||||
|
||||
// For system drag, the whole window is draggable and the non-draggable areas
|
||||
// have to been explicitly excluded.
|
||||
std::vector<gfx::Rect> system_drag_exclude_areas_;
|
||||
|
||||
// For custom drag, the whole window is non-draggable and the draggable region
|
||||
// has to been explicitly provided.
|
||||
scoped_ptr<SkRegion> draggable_region_; // used in custom drag.
|
||||
|
||||
// Mouse location since the last mouse event, in screen coordinates. This is
|
||||
// used in custom drag to compute the window movement.
|
||||
NSPoint last_mouse_offset_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NativeWindowMac);
|
||||
};
|
||||
|
||||
|
||||
@@ -13,15 +13,22 @@
|
||||
#include "base/mac/mac_util.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "base/values.h"
|
||||
#import "browser/atom_event_processing_window.h"
|
||||
#import "browser/ui/atom_event_processing_window.h"
|
||||
#include "brightray/browser/inspectable_web_contents.h"
|
||||
#include "brightray/browser/inspectable_web_contents_view.h"
|
||||
#include "common/draggable_region.h"
|
||||
#include "common/options_switches.h"
|
||||
#include "content/public/browser/native_web_keyboard_event.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/browser/web_contents_view.h"
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
|
||||
static const CGFloat kAtomWindowCornerRadius = 4.0;
|
||||
|
||||
@interface NSView (PrivateMethods)
|
||||
- (CGFloat)roundedCornerRadius;
|
||||
@end
|
||||
|
||||
@interface AtomNSWindowDelegate : NSObject<NSWindowDelegate> {
|
||||
@private
|
||||
atom::NativeWindowMac* shell_;
|
||||
@@ -41,6 +48,11 @@
|
||||
shell_->NotifyWindowBlur();
|
||||
}
|
||||
|
||||
- (void)windowDidResize:(NSNotification*)otification {
|
||||
if (!shell_->has_frame())
|
||||
shell_->ClipWebView();
|
||||
}
|
||||
|
||||
- (void)windowWillClose:(NSNotification*)notification {
|
||||
shell_->window() = nil;
|
||||
[self autorelease];
|
||||
@@ -54,10 +66,17 @@
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)windowDidExitFullScreen:(NSNotification*)notification {
|
||||
if (!shell_->has_frame()) {
|
||||
NSWindow* window = shell_->GetNativeWindow();
|
||||
[[window standardWindowButton:NSWindowFullScreenButton] setHidden:YES];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface AtomNSWindow : AtomEventProcessingWindow {
|
||||
@private
|
||||
@protected
|
||||
atom::NativeWindowMac* shell_;
|
||||
}
|
||||
- (void)setShell:(atom::NativeWindowMac*)shell;
|
||||
@@ -80,6 +99,41 @@
|
||||
|
||||
@end
|
||||
|
||||
@interface ControlRegionView : NSView {
|
||||
@private
|
||||
atom::NativeWindowMac* shellWindow_; // Weak; owns self.
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation ControlRegionView
|
||||
|
||||
- (id)initWithShellWindow:(atom::NativeWindowMac*)shellWindow {
|
||||
if ((self = [super init]))
|
||||
shellWindow_ = shellWindow;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)mouseDownCanMoveWindow {
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSView*)hitTest:(NSPoint)aPoint {
|
||||
if (!shellWindow_->IsWithinDraggableRegion(aPoint)) {
|
||||
return nil;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)mouseDown:(NSEvent*)event {
|
||||
shellWindow_->HandleMouseEvent(event);
|
||||
}
|
||||
|
||||
- (void)mouseDragged:(NSEvent*)event {
|
||||
shellWindow_->HandleMouseEvent(event);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
namespace atom {
|
||||
|
||||
NativeWindowMac::NativeWindowMac(content::WebContents* web_contents,
|
||||
@@ -93,21 +147,24 @@ NativeWindowMac::NativeWindowMac(content::WebContents* web_contents,
|
||||
|
||||
NSRect main_screen_rect = [[[NSScreen screens] objectAtIndex:0] frame];
|
||||
NSRect cocoa_bounds = NSMakeRect(
|
||||
(NSWidth(main_screen_rect) - width) / 2,
|
||||
(NSHeight(main_screen_rect) - height) / 2,
|
||||
round((NSWidth(main_screen_rect) - width) / 2) ,
|
||||
round((NSHeight(main_screen_rect) - height) / 2),
|
||||
width,
|
||||
height);
|
||||
NSUInteger style_mask = NSTitledWindowMask | NSClosableWindowMask |
|
||||
NSMiniaturizableWindowMask | NSResizableWindowMask |
|
||||
NSTexturedBackgroundWindowMask;
|
||||
AtomNSWindow* atom_window = [[AtomNSWindow alloc]
|
||||
|
||||
AtomNSWindow* atomWindow;
|
||||
|
||||
atomWindow = [[AtomNSWindow alloc]
|
||||
initWithContentRect:cocoa_bounds
|
||||
styleMask:style_mask
|
||||
styleMask:NSTitledWindowMask | NSClosableWindowMask |
|
||||
NSMiniaturizableWindowMask | NSResizableWindowMask |
|
||||
NSTexturedBackgroundWindowMask
|
||||
backing:NSBackingStoreBuffered
|
||||
defer:YES];
|
||||
[atom_window setShell:this];
|
||||
|
||||
window_ = atom_window;
|
||||
[atomWindow setShell:this];
|
||||
window_ = atomWindow;
|
||||
|
||||
[window() setDelegate:[[AtomNSWindowDelegate alloc] initWithShell:this]];
|
||||
|
||||
// Disable fullscreen button when 'fullscreen' is specified to false.
|
||||
@@ -119,6 +176,9 @@ NativeWindowMac::NativeWindowMac(content::WebContents* web_contents,
|
||||
[window() setCollectionBehavior:collectionBehavior];
|
||||
}
|
||||
|
||||
NSView* view = inspectable_web_contents()->GetView()->GetNativeView();
|
||||
[view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
|
||||
|
||||
InstallView();
|
||||
}
|
||||
|
||||
@@ -149,7 +209,10 @@ void NativeWindowMac::Move(const gfx::Rect& pos) {
|
||||
}
|
||||
|
||||
void NativeWindowMac::Focus(bool focus) {
|
||||
if (focus && [window() isVisible]) {
|
||||
if (!IsVisible())
|
||||
return;
|
||||
|
||||
if (focus) {
|
||||
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
|
||||
[window() makeKeyAndOrderFront:nil];
|
||||
} else {
|
||||
@@ -169,6 +232,10 @@ void NativeWindowMac::Hide() {
|
||||
[window() orderOut:nil];
|
||||
}
|
||||
|
||||
bool NativeWindowMac::IsVisible() {
|
||||
return [window() isVisible];
|
||||
}
|
||||
|
||||
void NativeWindowMac::Maximize() {
|
||||
[window() zoom:nil];
|
||||
}
|
||||
@@ -300,7 +367,7 @@ void NativeWindowMac::SetKiosk(bool kiosk) {
|
||||
if (kiosk) {
|
||||
NSApplicationPresentationOptions options =
|
||||
NSApplicationPresentationHideDock +
|
||||
NSApplicationPresentationHideMenuBar +
|
||||
NSApplicationPresentationHideMenuBar +
|
||||
NSApplicationPresentationDisableAppleMenu +
|
||||
NSApplicationPresentationDisableProcessSwitching +
|
||||
NSApplicationPresentationDisableForceQuit +
|
||||
@@ -324,6 +391,43 @@ gfx::NativeWindow NativeWindowMac::GetNativeWindow() {
|
||||
return window();
|
||||
}
|
||||
|
||||
bool NativeWindowMac::IsWithinDraggableRegion(NSPoint point) const {
|
||||
if (!draggable_region_)
|
||||
return false;
|
||||
NSView* webView = GetWebContents()->GetView()->GetNativeView();
|
||||
NSInteger webViewHeight = NSHeight([webView bounds]);
|
||||
// |draggable_region_| is stored in local platform-indepdent coordiate system
|
||||
// while |point| is in local Cocoa coordinate system. Do the conversion
|
||||
// to match these two.
|
||||
return draggable_region_->contains(point.x, webViewHeight - point.y);
|
||||
}
|
||||
|
||||
void NativeWindowMac::HandleMouseEvent(NSEvent* event) {
|
||||
NSPoint current_mouse_location =
|
||||
[window() convertBaseToScreen:[event locationInWindow]];
|
||||
|
||||
if ([event type] == NSLeftMouseDown) {
|
||||
NSPoint frame_origin = [window() frame].origin;
|
||||
last_mouse_offset_ = NSMakePoint(
|
||||
frame_origin.x - current_mouse_location.x,
|
||||
frame_origin.y - current_mouse_location.y);
|
||||
} else if ([event type] == NSLeftMouseDragged) {
|
||||
[window() setFrameOrigin:NSMakePoint(
|
||||
current_mouse_location.x + last_mouse_offset_.x,
|
||||
current_mouse_location.y + last_mouse_offset_.y)];
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowMac::UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions) {
|
||||
// Draggable region is not supported for non-frameless window.
|
||||
if (has_frame_)
|
||||
return;
|
||||
|
||||
UpdateDraggableRegionsForCustomDrag(regions);
|
||||
InstallDraggableRegionViews();
|
||||
}
|
||||
|
||||
void NativeWindowMac::HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent& event) {
|
||||
@@ -339,16 +443,97 @@ void NativeWindowMac::HandleKeyboardEvent(
|
||||
|
||||
void NativeWindowMac::InstallView() {
|
||||
NSView* view = inspectable_web_contents()->GetView()->GetNativeView();
|
||||
[view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
|
||||
[view setFrame:[[window() contentView] bounds]];
|
||||
[[window() contentView] addSubview:view];
|
||||
if (has_frame_) {
|
||||
[view setFrame:[[window() contentView] bounds]];
|
||||
[[window() contentView] addSubview:view];
|
||||
} else {
|
||||
NSView* frameView = [[window() contentView] superview];
|
||||
[view setFrame:[frameView bounds]];
|
||||
[frameView addSubview:view];
|
||||
|
||||
ClipWebView();
|
||||
|
||||
[[window() standardWindowButton:NSWindowZoomButton] setHidden:YES];
|
||||
[[window() standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
|
||||
[[window() standardWindowButton:NSWindowCloseButton] setHidden:YES];
|
||||
[[window() standardWindowButton:NSWindowFullScreenButton] setHidden:YES];
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowMac::UninstallView() {
|
||||
NSView* view = GetWebContents()->GetView()->GetNativeView();
|
||||
NSView* view = inspectable_web_contents()->GetView()->GetNativeView();
|
||||
[view removeFromSuperview];
|
||||
}
|
||||
|
||||
void NativeWindowMac::ClipWebView() {
|
||||
NSView* view = GetWebContents()->GetView()->GetNativeView();
|
||||
|
||||
view.wantsLayer = YES;
|
||||
view.layer.masksToBounds = YES;
|
||||
view.layer.cornerRadius = kAtomWindowCornerRadius;
|
||||
}
|
||||
|
||||
void NativeWindowMac::InstallDraggableRegionViews() {
|
||||
DCHECK(!has_frame_);
|
||||
|
||||
// All ControlRegionViews should be added as children of the WebContentsView,
|
||||
// because WebContentsView will be removed and re-added when entering and
|
||||
// leaving fullscreen mode.
|
||||
NSView* webView = GetWebContents()->GetView()->GetNativeView();
|
||||
NSInteger webViewHeight = NSHeight([webView bounds]);
|
||||
|
||||
// Remove all ControlRegionViews that are added last time.
|
||||
// Note that [webView subviews] returns the view's mutable internal array and
|
||||
// it should be copied to avoid mutating the original array while enumerating
|
||||
// it.
|
||||
scoped_nsobject<NSArray> subviews([[webView subviews] copy]);
|
||||
for (NSView* subview in subviews.get())
|
||||
if ([subview isKindOfClass:[ControlRegionView class]])
|
||||
[subview removeFromSuperview];
|
||||
|
||||
// Create and add ControlRegionView for each region that needs to be excluded
|
||||
// from the dragging.
|
||||
for (std::vector<gfx::Rect>::const_iterator iter =
|
||||
system_drag_exclude_areas_.begin();
|
||||
iter != system_drag_exclude_areas_.end();
|
||||
++iter) {
|
||||
scoped_nsobject<NSView> controlRegion(
|
||||
[[ControlRegionView alloc] initWithShellWindow:this]);
|
||||
[controlRegion setFrame:NSMakeRect(iter->x(),
|
||||
webViewHeight - iter->bottom(),
|
||||
iter->width(),
|
||||
iter->height())];
|
||||
[webView addSubview:controlRegion];
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowMac::UpdateDraggableRegionsForCustomDrag(
|
||||
const std::vector<DraggableRegion>& regions) {
|
||||
// We still need one ControlRegionView to cover the whole window such that
|
||||
// mouse events could be captured.
|
||||
NSView* web_view = GetWebContents()->GetView()->GetNativeView();
|
||||
gfx::Rect window_bounds(
|
||||
0, 0, NSWidth([web_view bounds]), NSHeight([web_view bounds]));
|
||||
system_drag_exclude_areas_.clear();
|
||||
system_drag_exclude_areas_.push_back(window_bounds);
|
||||
|
||||
// Aggregate the draggable areas and non-draggable areas such that hit test
|
||||
// could be performed easily.
|
||||
SkRegion* draggable_region = new SkRegion;
|
||||
for (std::vector<DraggableRegion>::const_iterator iter = regions.begin();
|
||||
iter != regions.end();
|
||||
++iter) {
|
||||
const DraggableRegion& region = *iter;
|
||||
draggable_region->op(
|
||||
region.bounds.x(),
|
||||
region.bounds.y(),
|
||||
region.bounds.right(),
|
||||
region.bounds.bottom(),
|
||||
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
|
||||
}
|
||||
draggable_region_.reset(draggable_region);
|
||||
}
|
||||
|
||||
// static
|
||||
NativeWindow* NativeWindow::Create(content::WebContents* web_contents,
|
||||
base::DictionaryValue* options) {
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
|
||||
@@ -4,12 +4,24 @@
|
||||
|
||||
#include "browser/native_window_win.h"
|
||||
|
||||
#include "base/stl_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/values.h"
|
||||
#include "browser/api/atom_api_menu.h"
|
||||
#include "browser/ui/win/menu_2.h"
|
||||
#include "browser/ui/win/native_menu_win.h"
|
||||
#include "common/draggable_region.h"
|
||||
#include "common/options_switches.h"
|
||||
#include "content/public/browser/native_web_keyboard_event.h"
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#include "content/public/browser/render_widget_host_view.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/browser/web_contents_view.h"
|
||||
#include "ui/gfx/path.h"
|
||||
#include "ui/base/models/simple_menu_model.h"
|
||||
#include "ui/views/controls/webview/webview.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
#include "ui/views/widget/native_widget_win.h"
|
||||
#include "ui/views/window/client_view.h"
|
||||
#include "ui/views/window/native_frame_view.h"
|
||||
|
||||
@@ -17,24 +29,52 @@ namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
const int kResizeInsideBoundsSize = 5;
|
||||
const int kResizeAreaCornerSize = 16;
|
||||
|
||||
// Wrapper of NativeWidgetWin to handle WM_MENUCOMMAND messages, which are
|
||||
// triggered by window menus.
|
||||
class MenuCommandNativeWidget : public views::NativeWidgetWin {
|
||||
public:
|
||||
explicit MenuCommandNativeWidget(NativeWindowWin* delegate)
|
||||
: views::NativeWidgetWin(delegate->window()),
|
||||
delegate_(delegate) {}
|
||||
virtual ~MenuCommandNativeWidget() {}
|
||||
|
||||
protected:
|
||||
virtual bool PreHandleMSG(UINT message,
|
||||
WPARAM w_param,
|
||||
LPARAM l_param,
|
||||
LRESULT* result) OVERRIDE {
|
||||
if (message == WM_MENUCOMMAND) {
|
||||
delegate_->OnMenuCommand(w_param, reinterpret_cast<HMENU>(l_param));
|
||||
*result = 0;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
NativeWindowWin* delegate_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MenuCommandNativeWidget);
|
||||
};
|
||||
|
||||
class NativeWindowClientView : public views::ClientView {
|
||||
public:
|
||||
NativeWindowClientView(views::Widget* widget,
|
||||
views::View* contents_view,
|
||||
NativeWindowWin* shell)
|
||||
: views::ClientView(widget, contents_view),
|
||||
shell_(shell) {
|
||||
NativeWindowWin* contents_view)
|
||||
: views::ClientView(widget, contents_view) {
|
||||
}
|
||||
virtual ~NativeWindowClientView() {}
|
||||
|
||||
virtual bool CanClose() OVERRIDE {
|
||||
shell_->CloseWebContents();
|
||||
static_cast<NativeWindowWin*>(contents_view())->CloseWebContents();
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
NativeWindowWin* shell_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NativeWindowClientView);
|
||||
};
|
||||
|
||||
@@ -60,6 +100,99 @@ class NativeWindowFrameView : public views::NativeFrameView {
|
||||
DISALLOW_COPY_AND_ASSIGN(NativeWindowFrameView);
|
||||
};
|
||||
|
||||
class NativeWindowFramelessView : public views::NonClientFrameView {
|
||||
public:
|
||||
explicit NativeWindowFramelessView(views::Widget* frame,
|
||||
NativeWindowWin* shell)
|
||||
: frame_(frame),
|
||||
shell_(shell) {
|
||||
}
|
||||
virtual ~NativeWindowFramelessView() {}
|
||||
|
||||
// views::NonClientFrameView implementations:
|
||||
virtual gfx::Rect NativeWindowFramelessView::GetBoundsForClientView() const
|
||||
OVERRIDE {
|
||||
return bounds();
|
||||
}
|
||||
|
||||
virtual gfx::Rect NativeWindowFramelessView::GetWindowBoundsForClientBounds(
|
||||
const gfx::Rect& client_bounds) const OVERRIDE {
|
||||
gfx::Rect window_bounds = client_bounds;
|
||||
// Enforce minimum size (1, 1) in case that client_bounds is passed with
|
||||
// empty size. This could occur when the frameless window is being
|
||||
// initialized.
|
||||
if (window_bounds.IsEmpty()) {
|
||||
window_bounds.set_width(1);
|
||||
window_bounds.set_height(1);
|
||||
}
|
||||
return window_bounds;
|
||||
}
|
||||
|
||||
virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE {
|
||||
if (frame_->IsFullscreen())
|
||||
return HTCLIENT;
|
||||
|
||||
// Check the frame first, as we allow a small area overlapping the contents
|
||||
// to be used for resize handles.
|
||||
bool can_ever_resize = frame_->widget_delegate() ?
|
||||
frame_->widget_delegate()->CanResize() :
|
||||
false;
|
||||
// Don't allow overlapping resize handles when the window is maximized or
|
||||
// fullscreen, as it can't be resized in those states.
|
||||
int resize_border =
|
||||
frame_->IsMaximized() || frame_->IsFullscreen() ? 0 :
|
||||
kResizeInsideBoundsSize;
|
||||
int frame_component = GetHTComponentForFrame(point,
|
||||
resize_border,
|
||||
resize_border,
|
||||
kResizeAreaCornerSize,
|
||||
kResizeAreaCornerSize,
|
||||
can_ever_resize);
|
||||
if (frame_component != HTNOWHERE)
|
||||
return frame_component;
|
||||
|
||||
// Check for possible draggable region in the client area for the frameless
|
||||
// window.
|
||||
if (shell_->draggable_region() &&
|
||||
shell_->draggable_region()->contains(point.x(), point.y()))
|
||||
return HTCAPTION;
|
||||
|
||||
int client_component = frame_->client_view()->NonClientHitTest(point);
|
||||
if (client_component != HTNOWHERE)
|
||||
return client_component;
|
||||
|
||||
// Caption is a safe default.
|
||||
return HTCAPTION;
|
||||
}
|
||||
|
||||
virtual void GetWindowMask(const gfx::Size& size,
|
||||
gfx::Path* window_mask) OVERRIDE {}
|
||||
virtual void ResetWindowControls() OVERRIDE {}
|
||||
virtual void UpdateWindowIcon() OVERRIDE {}
|
||||
virtual void UpdateWindowTitle() OVERRIDE {}
|
||||
|
||||
// views::View implementations:
|
||||
virtual gfx::Size NativeWindowFramelessView::GetPreferredSize() OVERRIDE {
|
||||
gfx::Size pref = frame_->client_view()->GetPreferredSize();
|
||||
gfx::Rect bounds(0, 0, pref.width(), pref.height());
|
||||
return frame_->non_client_view()->GetWindowBoundsForClientBounds(
|
||||
bounds).size();
|
||||
}
|
||||
|
||||
virtual gfx::Size GetMinimumSize() OVERRIDE {
|
||||
return shell_->GetMinimumSize();
|
||||
}
|
||||
|
||||
virtual gfx::Size GetMaximumSize() OVERRIDE {
|
||||
return shell_->GetMaximumSize();
|
||||
}
|
||||
|
||||
private:
|
||||
views::Widget* frame_;
|
||||
NativeWindowWin* shell_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NativeWindowFramelessView);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -71,6 +204,8 @@ NativeWindowWin::NativeWindowWin(content::WebContents* web_contents,
|
||||
resizable_(true) {
|
||||
views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
|
||||
params.delegate = this;
|
||||
params.native_widget = new MenuCommandNativeWidget(this);
|
||||
params.remove_standard_frame = !has_frame_;
|
||||
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
|
||||
window_->set_frame_type(views::Widget::FRAME_TYPE_FORCE_NATIVE);
|
||||
window_->Init(params);
|
||||
@@ -82,7 +217,10 @@ NativeWindowWin::NativeWindowWin(content::WebContents* web_contents,
|
||||
gfx::Size size(width, height);
|
||||
window_->CenterWindow(size);
|
||||
|
||||
window_->UpdateWindowIcon();
|
||||
|
||||
web_view_->SetWebContents(web_contents);
|
||||
OnViewWasResized();
|
||||
}
|
||||
|
||||
NativeWindowWin::~NativeWindowWin() {
|
||||
@@ -127,6 +265,10 @@ void NativeWindowWin::Unmaximize() {
|
||||
window_->Restore();
|
||||
}
|
||||
|
||||
bool NativeWindowWin::IsVisible() {
|
||||
return window_->IsVisible();
|
||||
}
|
||||
|
||||
void NativeWindowWin::Minimize() {
|
||||
window_->Minimize();
|
||||
}
|
||||
@@ -221,15 +363,92 @@ gfx::NativeWindow NativeWindowWin::GetNativeWindow() {
|
||||
return window_->GetNativeView();
|
||||
}
|
||||
|
||||
void NativeWindowWin::OnMenuCommand(int position, HMENU menu) {
|
||||
DCHECK(menu_);
|
||||
menu_->wrapper()->OnMenuCommand(position, menu);
|
||||
}
|
||||
|
||||
void NativeWindowWin::SetMenu(ui::MenuModel* menu_model) {
|
||||
menu_.reset(new atom::Menu2(menu_model, true));
|
||||
::SetMenu(GetNativeWindow(), menu_->GetNativeMenu());
|
||||
RegisterAccelerators();
|
||||
}
|
||||
|
||||
void NativeWindowWin::UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions) {
|
||||
if (has_frame_)
|
||||
return;
|
||||
|
||||
SkRegion* draggable_region = new SkRegion;
|
||||
|
||||
// By default, the whole window is non-draggable. We need to explicitly
|
||||
// include those draggable regions.
|
||||
for (std::vector<DraggableRegion>::const_iterator iter = regions.begin();
|
||||
iter != regions.end(); ++iter) {
|
||||
const DraggableRegion& region = *iter;
|
||||
draggable_region->op(
|
||||
region.bounds.x(),
|
||||
region.bounds.y(),
|
||||
region.bounds.right(),
|
||||
region.bounds.bottom(),
|
||||
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
|
||||
}
|
||||
|
||||
draggable_region_.reset(draggable_region);
|
||||
OnViewWasResized();
|
||||
}
|
||||
|
||||
void NativeWindowWin::HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent& event) {
|
||||
if (event.type == WebKit::WebInputEvent::KeyUp) {
|
||||
ui::Accelerator accelerator(
|
||||
static_cast<ui::KeyboardCode>(event.windowsKeyCode),
|
||||
content::GetModifiersFromNativeWebKeyboardEvent(event));
|
||||
|
||||
if (GetFocusManager()->ProcessAccelerator(accelerator)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Any unhandled keyboard/character messages should be defproced.
|
||||
// This allows stuff like F10, etc to work correctly.
|
||||
DefWindowProc(event.os_event.hwnd, event.os_event.message,
|
||||
event.os_event.wParam, event.os_event.lParam);
|
||||
}
|
||||
|
||||
void NativeWindowWin::Layout() {
|
||||
DCHECK(web_view_);
|
||||
web_view_->SetBounds(0, 0, width(), height());
|
||||
OnViewWasResized();
|
||||
}
|
||||
|
||||
void NativeWindowWin::ViewHierarchyChanged(bool is_add,
|
||||
views::View* parent,
|
||||
views::View* child) {
|
||||
if (is_add && child == this)
|
||||
AddChildView(web_view_);
|
||||
}
|
||||
|
||||
bool NativeWindowWin::AcceleratorPressed(
|
||||
const ui::Accelerator& accelerator) {
|
||||
if (ContainsKey(accelerator_table_, accelerator)) {
|
||||
const MenuItem& item = accelerator_table_[accelerator];
|
||||
item.model->ActivatedAt(item.position);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowWin::DeleteDelegate() {
|
||||
// Do nothing, window is managed by users.
|
||||
}
|
||||
|
||||
views::View* NativeWindowWin::GetInitiallyFocusedView() {
|
||||
return web_view_;
|
||||
}
|
||||
|
||||
bool NativeWindowWin::CanResize() const {
|
||||
return resizable_;
|
||||
}
|
||||
@@ -246,8 +465,15 @@ bool NativeWindowWin::ShouldHandleSystemCommands() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NativeWindowWin::ShouldShowWindowIcon() const {
|
||||
return true;
|
||||
gfx::ImageSkia NativeWindowWin::GetWindowAppIcon() {
|
||||
if (icon_.IsEmpty())
|
||||
return gfx::ImageSkia();
|
||||
else
|
||||
return *icon_.ToImageSkia();
|
||||
}
|
||||
|
||||
gfx::ImageSkia NativeWindowWin::GetWindowIcon() {
|
||||
return GetWindowAppIcon();
|
||||
}
|
||||
|
||||
views::Widget* NativeWindowWin::GetWidget() {
|
||||
@@ -259,12 +485,83 @@ const views::Widget* NativeWindowWin::GetWidget() const {
|
||||
}
|
||||
|
||||
views::ClientView* NativeWindowWin::CreateClientView(views::Widget* widget) {
|
||||
return new NativeWindowClientView(widget, web_view_, this);
|
||||
return new NativeWindowClientView(widget, this);
|
||||
}
|
||||
|
||||
views::NonClientFrameView* NativeWindowWin::CreateNonClientFrameView(
|
||||
views::Widget* widget) {
|
||||
return new NativeWindowFrameView(widget, this);
|
||||
if (has_frame_)
|
||||
return new NativeWindowFrameView(widget, this);
|
||||
|
||||
return new NativeWindowFramelessView(widget, this);
|
||||
}
|
||||
|
||||
void NativeWindowWin::OnViewWasResized() {
|
||||
// Set the window shape of the RWHV.
|
||||
gfx::Size sz = web_view_->size();
|
||||
int height = sz.height(), width = sz.width();
|
||||
gfx::Path path;
|
||||
path.addRect(0, 0, width, height);
|
||||
SetWindowRgn(web_contents()->GetView()->GetNativeView(),
|
||||
path.CreateNativeRegion(),
|
||||
1);
|
||||
|
||||
SkRegion* rgn = new SkRegion;
|
||||
if (!window_->IsFullscreen() && !window_->IsMaximized()) {
|
||||
if (draggable_region())
|
||||
rgn->op(*draggable_region(), SkRegion::kUnion_Op);
|
||||
|
||||
if (!has_frame_ && CanResize()) {
|
||||
rgn->op(0, 0, width, kResizeInsideBoundsSize, SkRegion::kUnion_Op);
|
||||
rgn->op(0, 0, kResizeInsideBoundsSize, height, SkRegion::kUnion_Op);
|
||||
rgn->op(width - kResizeInsideBoundsSize, 0, width, height,
|
||||
SkRegion::kUnion_Op);
|
||||
rgn->op(0, height - kResizeInsideBoundsSize, width, height,
|
||||
SkRegion::kUnion_Op);
|
||||
}
|
||||
}
|
||||
|
||||
content::WebContents* web_contents = GetWebContents();
|
||||
if (web_contents->GetRenderViewHost()->GetView())
|
||||
web_contents->GetRenderViewHost()->GetView()->SetClickthroughRegion(rgn);
|
||||
}
|
||||
|
||||
void NativeWindowWin::RegisterAccelerators() {
|
||||
views::FocusManager* focus_manager = GetFocusManager();
|
||||
accelerator_table_.clear();
|
||||
focus_manager->UnregisterAccelerators(this);
|
||||
|
||||
GenerateAcceleratorTable();
|
||||
for (AcceleratorTable::const_iterator iter = accelerator_table_.begin();
|
||||
iter != accelerator_table_.end(); ++iter) {
|
||||
focus_manager->RegisterAccelerator(
|
||||
iter->first, ui::AcceleratorManager::kNormalPriority, this);
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowWin::GenerateAcceleratorTable() {
|
||||
DCHECK(menu_);
|
||||
ui::SimpleMenuModel* model = static_cast<ui::SimpleMenuModel*>(
|
||||
menu_->model());
|
||||
FillAcceleratorTable(&accelerator_table_, model);
|
||||
}
|
||||
|
||||
void NativeWindowWin::FillAcceleratorTable(AcceleratorTable* table,
|
||||
ui::MenuModel* model) {
|
||||
int count = model->GetItemCount();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
ui::MenuModel::ItemType type = model->GetTypeAt(i);
|
||||
if (type == ui::MenuModel::TYPE_SUBMENU) {
|
||||
ui::MenuModel* submodel = model->GetSubmenuModelAt(i);
|
||||
FillAcceleratorTable(table, submodel);
|
||||
} else {
|
||||
ui::Accelerator accelerator;
|
||||
if (model->GetAcceleratorAt(i, &accelerator)) {
|
||||
MenuItem item = { i, model };
|
||||
(*table)[accelerator] = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
#include "ui/gfx/size.h"
|
||||
#include "ui/views/widget/widget_delegate.h"
|
||||
|
||||
namespace ui {
|
||||
class MenuModel;
|
||||
}
|
||||
|
||||
namespace views {
|
||||
class WebView;
|
||||
class Widget;
|
||||
@@ -19,8 +23,10 @@ class Widget;
|
||||
|
||||
namespace atom {
|
||||
|
||||
class Menu2;
|
||||
|
||||
class NativeWindowWin : public NativeWindow,
|
||||
public views::WidgetDelegate {
|
||||
public views::WidgetDelegateView {
|
||||
public:
|
||||
explicit NativeWindowWin(content::WebContents* web_contents,
|
||||
base::DictionaryValue* options);
|
||||
@@ -34,6 +40,7 @@ class NativeWindowWin : public NativeWindow,
|
||||
virtual bool IsFocused() OVERRIDE;
|
||||
virtual void Show() OVERRIDE;
|
||||
virtual void Hide() OVERRIDE;
|
||||
virtual bool IsVisible() OVERRIDE;
|
||||
virtual void Maximize() OVERRIDE;
|
||||
virtual void Unmaximize() OVERRIDE;
|
||||
virtual void Minimize() OVERRIDE;
|
||||
@@ -60,18 +67,39 @@ class NativeWindowWin : public NativeWindow,
|
||||
virtual bool IsKiosk() OVERRIDE;
|
||||
virtual gfx::NativeWindow GetNativeWindow() OVERRIDE;
|
||||
|
||||
void OnMenuCommand(int position, HMENU menu);
|
||||
|
||||
// Set the native window menu.
|
||||
void SetMenu(ui::MenuModel* menu_model);
|
||||
|
||||
views::Widget* window() const { return window_.get(); }
|
||||
SkRegion* draggable_region() { return draggable_region_.get(); }
|
||||
|
||||
protected:
|
||||
virtual void UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions) OVERRIDE;
|
||||
|
||||
// Overridden from content::WebContentsDelegate:
|
||||
virtual void HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent&) OVERRIDE;
|
||||
|
||||
// Overridden from views::View:
|
||||
virtual void Layout() OVERRIDE;
|
||||
virtual void ViewHierarchyChanged(bool is_add,
|
||||
views::View* parent,
|
||||
views::View* child) OVERRIDE;
|
||||
virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
|
||||
|
||||
// Overridden from views::WidgetDelegate:
|
||||
virtual void DeleteDelegate() OVERRIDE;
|
||||
virtual views::View* GetInitiallyFocusedView() OVERRIDE;
|
||||
virtual bool CanResize() const OVERRIDE;
|
||||
virtual bool CanMaximize() const OVERRIDE;
|
||||
virtual string16 GetWindowTitle() const OVERRIDE;
|
||||
virtual bool ShouldHandleSystemCommands() const OVERRIDE;
|
||||
virtual bool ShouldShowWindowIcon() const OVERRIDE;
|
||||
virtual gfx::ImageSkia GetWindowAppIcon() OVERRIDE;
|
||||
virtual gfx::ImageSkia GetWindowIcon() OVERRIDE;
|
||||
virtual views::Widget* GetWidget() OVERRIDE;
|
||||
virtual const views::Widget* GetWidget() const OVERRIDE;
|
||||
virtual views::ClientView* CreateClientView(views::Widget* widget) OVERRIDE;
|
||||
@@ -79,9 +107,32 @@ class NativeWindowWin : public NativeWindow,
|
||||
views::Widget* widget) OVERRIDE;
|
||||
|
||||
private:
|
||||
typedef struct { int position; ui::MenuModel* model; } MenuItem;
|
||||
typedef std::map<ui::Accelerator, MenuItem> AcceleratorTable;
|
||||
|
||||
void OnViewWasResized();
|
||||
|
||||
// Register accelerators supported by the menu model.
|
||||
void RegisterAccelerators();
|
||||
|
||||
// Generate a table that contains memu model's accelerators and command ids.
|
||||
void GenerateAcceleratorTable();
|
||||
|
||||
// Helper to fill the accelerator table from the model.
|
||||
void FillAcceleratorTable(AcceleratorTable* table,
|
||||
ui::MenuModel* model);
|
||||
|
||||
scoped_ptr<views::Widget> window_;
|
||||
views::WebView* web_view_; // managed by window_.
|
||||
|
||||
// The window menu.
|
||||
scoped_ptr<atom::Menu2> menu_;
|
||||
|
||||
// Map from accelerator to menu item's command id.
|
||||
AcceleratorTable accelerator_table_;
|
||||
|
||||
scoped_ptr<SkRegion> draggable_region_;
|
||||
|
||||
bool resizable_;
|
||||
string16 title_;
|
||||
gfx::Size minimum_size_;
|
||||
|
||||
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() {
|
||||
if (real_job_) // Kill could happen when real_job_ is created.
|
||||
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_
|
||||
169
browser/net/atom_url_request_context_getter.cc
Normal file
169
browser/net/atom_url_request_context_getter.cc
Normal file
@@ -0,0 +1,169 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "browser/net/atom_url_request_context_getter.h"
|
||||
|
||||
#include "base/string_util.h"
|
||||
#include "base/threading/worker_pool.h"
|
||||
#include "browser/net/atom_url_request_job_factory.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/cookie_store_factory.h"
|
||||
#include "content/public/common/url_constants.h"
|
||||
#include "net/cert/cert_verifier.h"
|
||||
#include "net/cookies/cookie_monster.h"
|
||||
#include "net/http/http_auth_handler_factory.h"
|
||||
#include "net/http/http_cache.h"
|
||||
#include "net/http/http_server_properties_impl.h"
|
||||
#include "net/proxy/dhcp_proxy_script_fetcher_factory.h"
|
||||
#include "net/proxy/proxy_config_service.h"
|
||||
#include "net/proxy/proxy_script_fetcher_impl.h"
|
||||
#include "net/proxy/proxy_service.h"
|
||||
#include "net/proxy/proxy_service_v8.h"
|
||||
#include "net/ssl/default_server_bound_cert_store.h"
|
||||
#include "net/ssl/server_bound_cert_service.h"
|
||||
#include "net/ssl/ssl_config_service_defaults.h"
|
||||
#include "net/url_request/data_protocol_handler.h"
|
||||
#include "net/url_request/file_protocol_handler.h"
|
||||
#include "net/url_request/static_http_user_agent_settings.h"
|
||||
#include "net/url_request/url_request_context.h"
|
||||
#include "net/url_request/url_request_context_storage.h"
|
||||
#include "vendor/brightray/browser/network_delegate.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
using content::BrowserThread;
|
||||
|
||||
AtomURLRequestContextGetter::AtomURLRequestContextGetter(
|
||||
const base::FilePath& base_path,
|
||||
MessageLoop* io_loop,
|
||||
MessageLoop* file_loop,
|
||||
scoped_ptr<brightray::NetworkDelegate> network_delegate,
|
||||
content::ProtocolHandlerMap* protocol_handlers)
|
||||
: base_path_(base_path),
|
||||
io_loop_(io_loop),
|
||||
file_loop_(file_loop),
|
||||
job_factory_(NULL),
|
||||
network_delegate_(network_delegate.Pass()) {
|
||||
// Must first be created on the UI thread.
|
||||
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||
|
||||
std::swap(protocol_handlers_, *protocol_handlers);
|
||||
|
||||
// We must create the proxy config service on the UI loop on Linux because it
|
||||
// must synchronously run on the glib message loop. This will be passed to
|
||||
// the URLRequestContextStorage on the IO thread in GetURLRequestContext().
|
||||
proxy_config_service_.reset(
|
||||
net::ProxyService::CreateSystemProxyConfigService(
|
||||
io_loop_->message_loop_proxy(),
|
||||
file_loop_));
|
||||
}
|
||||
|
||||
AtomURLRequestContextGetter::~AtomURLRequestContextGetter() {
|
||||
}
|
||||
|
||||
net::URLRequestContext* AtomURLRequestContextGetter::GetURLRequestContext() {
|
||||
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
||||
|
||||
if (!url_request_context_.get()) {
|
||||
url_request_context_.reset(new net::URLRequestContext());
|
||||
url_request_context_->set_network_delegate(network_delegate_.get());
|
||||
storage_.reset(
|
||||
new net::URLRequestContextStorage(url_request_context_.get()));
|
||||
storage_->set_cookie_store(content::CreatePersistentCookieStore(
|
||||
base_path_.Append(FILE_PATH_LITERAL("Cookies")),
|
||||
false,
|
||||
nullptr,
|
||||
nullptr));
|
||||
storage_->set_server_bound_cert_service(new net::ServerBoundCertService(
|
||||
new net::DefaultServerBoundCertStore(NULL),
|
||||
base::WorkerPool::GetTaskRunner(true)));
|
||||
storage_->set_http_user_agent_settings(
|
||||
new net::StaticHttpUserAgentSettings(
|
||||
"en-us,en", EmptyString()));
|
||||
|
||||
scoped_ptr<net::HostResolver> host_resolver(
|
||||
net::HostResolver::CreateDefaultResolver(NULL));
|
||||
net::DhcpProxyScriptFetcherFactory dhcp_factory;
|
||||
|
||||
storage_->set_cert_verifier(net::CertVerifier::CreateDefault());
|
||||
storage_->set_proxy_service(
|
||||
net::CreateProxyServiceUsingV8ProxyResolver(
|
||||
proxy_config_service_.release(),
|
||||
new net::ProxyScriptFetcherImpl(url_request_context_.get()),
|
||||
dhcp_factory.Create(url_request_context_.get()),
|
||||
host_resolver.get(),
|
||||
NULL,
|
||||
url_request_context_->network_delegate()));
|
||||
storage_->set_ssl_config_service(new net::SSLConfigServiceDefaults);
|
||||
storage_->set_http_auth_handler_factory(
|
||||
net::HttpAuthHandlerFactory::CreateDefault(host_resolver.get()));
|
||||
storage_->set_http_server_properties(new net::HttpServerPropertiesImpl);
|
||||
|
||||
base::FilePath cache_path = base_path_.Append(FILE_PATH_LITERAL("Cache"));
|
||||
net::HttpCache::DefaultBackend* main_backend =
|
||||
new net::HttpCache::DefaultBackend(
|
||||
net::DISK_CACHE,
|
||||
net::CACHE_BACKEND_DEFAULT,
|
||||
cache_path,
|
||||
0,
|
||||
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE));
|
||||
|
||||
net::HttpNetworkSession::Params network_session_params;
|
||||
network_session_params.cert_verifier =
|
||||
url_request_context_->cert_verifier();
|
||||
network_session_params.server_bound_cert_service =
|
||||
url_request_context_->server_bound_cert_service();
|
||||
network_session_params.proxy_service =
|
||||
url_request_context_->proxy_service();
|
||||
network_session_params.ssl_config_service =
|
||||
url_request_context_->ssl_config_service();
|
||||
network_session_params.http_auth_handler_factory =
|
||||
url_request_context_->http_auth_handler_factory();
|
||||
network_session_params.network_delegate =
|
||||
url_request_context_->network_delegate();
|
||||
network_session_params.http_server_properties =
|
||||
url_request_context_->http_server_properties();
|
||||
network_session_params.ignore_certificate_errors = false;
|
||||
|
||||
// Give |storage_| ownership at the end in case it's |mapped_host_resolver|.
|
||||
storage_->set_host_resolver(host_resolver.Pass());
|
||||
network_session_params.host_resolver =
|
||||
url_request_context_->host_resolver();
|
||||
|
||||
net::HttpCache* main_cache = new net::HttpCache(
|
||||
network_session_params, main_backend);
|
||||
storage_->set_http_transaction_factory(main_cache);
|
||||
|
||||
DCHECK(!job_factory_);
|
||||
job_factory_ = new AtomURLRequestJobFactory;
|
||||
for (content::ProtocolHandlerMap::iterator it = protocol_handlers_.begin();
|
||||
it != protocol_handlers_.end();
|
||||
++it) {
|
||||
bool set_protocol = job_factory_->SetProtocolHandler(
|
||||
it->first,
|
||||
it->second.release());
|
||||
DCHECK(set_protocol);
|
||||
}
|
||||
protocol_handlers_.clear();
|
||||
|
||||
job_factory_->SetProtocolHandler(chrome::kDataScheme,
|
||||
new net::DataProtocolHandler);
|
||||
job_factory_->SetProtocolHandler(chrome::kFileScheme,
|
||||
new net::FileProtocolHandler);
|
||||
storage_->set_job_factory(job_factory_);
|
||||
}
|
||||
|
||||
return url_request_context_.get();
|
||||
}
|
||||
|
||||
scoped_refptr<base::SingleThreadTaskRunner>
|
||||
AtomURLRequestContextGetter::GetNetworkTaskRunner() const {
|
||||
return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
|
||||
}
|
||||
|
||||
net::HostResolver* AtomURLRequestContextGetter::host_resolver() {
|
||||
return url_request_context_->host_resolver();
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
69
browser/net/atom_url_request_context_getter.h
Normal file
69
browser/net/atom_url_request_context_getter.h
Normal file
@@ -0,0 +1,69 @@
|
||||
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_NET_ATOM_URL_REQUEST_CONTEXT_GETTER_H_
|
||||
#define ATOM_BROWSER_NET_ATOM_URL_REQUEST_CONTEXT_GETTER_H_
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "content/public/browser/content_browser_client.h"
|
||||
#include "net/url_request/url_request_context_getter.h"
|
||||
|
||||
namespace base {
|
||||
class MessageLoop;
|
||||
}
|
||||
|
||||
namespace brightray {
|
||||
class NetworkDelegate;
|
||||
}
|
||||
|
||||
namespace net {
|
||||
class HostResolver;
|
||||
class ProxyConfigService;
|
||||
class URLRequestContextStorage;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomURLRequestJobFactory;
|
||||
|
||||
class AtomURLRequestContextGetter : public net::URLRequestContextGetter {
|
||||
public:
|
||||
AtomURLRequestContextGetter(
|
||||
const base::FilePath& base_path,
|
||||
base::MessageLoop* io_loop,
|
||||
base::MessageLoop* file_loop,
|
||||
scoped_ptr<brightray::NetworkDelegate> network_delegate,
|
||||
content::ProtocolHandlerMap* protocol_handlers);
|
||||
|
||||
// net::URLRequestContextGetter implementations:
|
||||
virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE;
|
||||
virtual scoped_refptr<base::SingleThreadTaskRunner>
|
||||
GetNetworkTaskRunner() const OVERRIDE;
|
||||
|
||||
net::HostResolver* host_resolver();
|
||||
net::URLRequestContextStorage* storage() const { return storage_.get(); }
|
||||
AtomURLRequestJobFactory* job_factory() const { return job_factory_; }
|
||||
|
||||
protected:
|
||||
virtual ~AtomURLRequestContextGetter();
|
||||
|
||||
private:
|
||||
base::FilePath base_path_;
|
||||
base::MessageLoop* io_loop_;
|
||||
base::MessageLoop* file_loop_;
|
||||
AtomURLRequestJobFactory* job_factory_;
|
||||
|
||||
scoped_ptr<net::ProxyConfigService> proxy_config_service_;
|
||||
scoped_ptr<brightray::NetworkDelegate> network_delegate_;
|
||||
scoped_ptr<net::URLRequestContextStorage> storage_;
|
||||
scoped_ptr<net::URLRequestContext> url_request_context_;
|
||||
content::ProtocolHandlerMap protocol_handlers_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomURLRequestContextGetter);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_NET_ATOM_URL_REQUEST_CONTEXT_GETTER_H_
|
||||
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_
|
||||
@@ -1,27 +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/node_bindings_browser_win.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
NodeBindingsBrowserWin::NodeBindingsBrowserWin()
|
||||
: NodeBindings(true) {
|
||||
}
|
||||
|
||||
NodeBindingsBrowserWin::~NodeBindingsBrowserWin() {
|
||||
}
|
||||
|
||||
void NodeBindingsBrowserWin::PrepareMessageLoop() {
|
||||
}
|
||||
|
||||
void NodeBindingsBrowserWin::RunMessageLoop() {
|
||||
}
|
||||
|
||||
// static
|
||||
NodeBindings* NodeBindings::CreateInBrowser() {
|
||||
return new NodeBindingsBrowserWin();
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
@@ -1,27 +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_NODE_BINDINGS_BROWSER_WIN_H_
|
||||
#define ATOM_BROWSER_NODE_BINDINGS_BROWSER_WIN_H_
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
#include "common/node_bindings.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class NodeBindingsBrowserWin : public NodeBindings {
|
||||
public:
|
||||
NodeBindingsBrowserWin();
|
||||
virtual ~NodeBindingsBrowserWin();
|
||||
|
||||
virtual void PrepareMessageLoop() OVERRIDE;
|
||||
virtual void RunMessageLoop() OVERRIDE;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(NodeBindingsBrowserWin);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_NODE_BINDINGS_BROWSER_WIN_H_
|
||||
183
browser/ui/accelerator_util.cc
Normal file
183
browser/ui/accelerator_util.cc
Normal file
@@ -0,0 +1,183 @@
|
||||
// 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/accelerator_util.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/string_util.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/string_split.h"
|
||||
#include "ui/base/accelerators/accelerator.h"
|
||||
|
||||
namespace accelerator_util {
|
||||
|
||||
namespace {
|
||||
|
||||
// Return key code of the char.
|
||||
ui::KeyboardCode KeyboardCodeFromCharCode(char c, bool* shifted) {
|
||||
*shifted = false;
|
||||
switch (c) {
|
||||
case 8: case 0x7F: return ui::VKEY_BACK;
|
||||
case 9: return ui::VKEY_TAB;
|
||||
case 0xD: case 3: return ui::VKEY_RETURN;
|
||||
case 0x1B: return ui::VKEY_ESCAPE;
|
||||
case ' ': return ui::VKEY_SPACE;
|
||||
|
||||
case 'a': return ui::VKEY_A;
|
||||
case 'b': return ui::VKEY_B;
|
||||
case 'c': return ui::VKEY_C;
|
||||
case 'd': return ui::VKEY_D;
|
||||
case 'e': return ui::VKEY_E;
|
||||
case 'f': return ui::VKEY_F;
|
||||
case 'g': return ui::VKEY_G;
|
||||
case 'h': return ui::VKEY_H;
|
||||
case 'i': return ui::VKEY_I;
|
||||
case 'j': return ui::VKEY_J;
|
||||
case 'k': return ui::VKEY_K;
|
||||
case 'l': return ui::VKEY_L;
|
||||
case 'm': return ui::VKEY_M;
|
||||
case 'n': return ui::VKEY_N;
|
||||
case 'o': return ui::VKEY_O;
|
||||
case 'p': return ui::VKEY_P;
|
||||
case 'q': return ui::VKEY_Q;
|
||||
case 'r': return ui::VKEY_R;
|
||||
case 's': return ui::VKEY_S;
|
||||
case 't': return ui::VKEY_T;
|
||||
case 'u': return ui::VKEY_U;
|
||||
case 'v': return ui::VKEY_V;
|
||||
case 'w': return ui::VKEY_W;
|
||||
case 'x': return ui::VKEY_X;
|
||||
case 'y': return ui::VKEY_Y;
|
||||
case 'z': return ui::VKEY_Z;
|
||||
|
||||
case ')': *shifted = true; case '0': return ui::VKEY_0;
|
||||
case '!': *shifted = true; case '1': return ui::VKEY_1;
|
||||
case '@': *shifted = true; case '2': return ui::VKEY_2;
|
||||
case '#': *shifted = true; case '3': return ui::VKEY_3;
|
||||
case '$': *shifted = true; case '4': return ui::VKEY_4;
|
||||
case '%': *shifted = true; case '5': return ui::VKEY_5;
|
||||
case '^': *shifted = true; case '6': return ui::VKEY_6;
|
||||
case '&': *shifted = true; case '7': return ui::VKEY_7;
|
||||
case '*': *shifted = true; case '8': return ui::VKEY_8;
|
||||
case '(': *shifted = true; case '9': return ui::VKEY_9;
|
||||
|
||||
case ':': *shifted = true; case ';': return ui::VKEY_OEM_1;
|
||||
case '+': *shifted = true; case '=': return ui::VKEY_OEM_PLUS;
|
||||
case '<': *shifted = true; case ',': return ui::VKEY_OEM_COMMA;
|
||||
case '_': *shifted = true; case '-': return ui::VKEY_OEM_MINUS;
|
||||
case '>': *shifted = true; case '.': return ui::VKEY_OEM_PERIOD;
|
||||
case '?': *shifted = true; case '/': return ui::VKEY_OEM_2;
|
||||
case '~': *shifted = true; case '`': return ui::VKEY_OEM_3;
|
||||
case '{': *shifted = true; case '[': return ui::VKEY_OEM_4;
|
||||
case '|': *shifted = true; case '\\': return ui::VKEY_OEM_5;
|
||||
case '}': *shifted = true; case ']': return ui::VKEY_OEM_6;
|
||||
case '"': *shifted = true; case '\'': return ui::VKEY_OEM_7;
|
||||
|
||||
default: return ui::VKEY_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool StringToAccelerator(const std::string& description,
|
||||
ui::Accelerator* accelerator) {
|
||||
if (!IsStringASCII(description)) {
|
||||
LOG(ERROR) << "The accelerator string can only contain ASCII characters";
|
||||
return false;
|
||||
}
|
||||
std::string shortcut(StringToLowerASCII(description));
|
||||
|
||||
std::vector<std::string> tokens;
|
||||
base::SplitString(shortcut, '+', &tokens);
|
||||
|
||||
// Now, parse it into an accelerator.
|
||||
int modifiers = ui::EF_NONE;
|
||||
ui::KeyboardCode key = ui::VKEY_UNKNOWN;
|
||||
for (size_t i = 0; i < tokens.size(); i++) {
|
||||
// We use straight comparing instead of map because the accelerator tends
|
||||
// to be correct and usually only uses few special tokens.
|
||||
if (tokens[i].size() == 1) {
|
||||
bool shifted = false;
|
||||
key = KeyboardCodeFromCharCode(tokens[i][0], &shifted);
|
||||
if (shifted)
|
||||
modifiers |= ui::EF_SHIFT_DOWN;
|
||||
} else if (tokens[i] == "ctrl") {
|
||||
modifiers |= ui::EF_CONTROL_DOWN;
|
||||
} else if (tokens[i] == "command") {
|
||||
modifiers |= ui::EF_COMMAND_DOWN;
|
||||
} else if (tokens[i] == "alt") {
|
||||
modifiers |= ui::EF_ALT_DOWN;
|
||||
} else if (tokens[i] == "shift") {
|
||||
modifiers |= ui::EF_SHIFT_DOWN;
|
||||
} else if (tokens[i] == "tab") {
|
||||
key = ui::VKEY_TAB;
|
||||
} else if (tokens[i] == "space") {
|
||||
key = ui::VKEY_SPACE;
|
||||
} else if (tokens[i] == "backspace") {
|
||||
key = ui::VKEY_BACK;
|
||||
} else if (tokens[i] == "delete") {
|
||||
key = ui::VKEY_DELETE;
|
||||
} else if (tokens[i] == "enter" || tokens[i] == "return") {
|
||||
key = ui::VKEY_RETURN;
|
||||
} else if (tokens[i] == "up") {
|
||||
key = ui::VKEY_UP;
|
||||
} else if (tokens[i] == "down") {
|
||||
key = ui::VKEY_DOWN;
|
||||
} else if (tokens[i] == "left") {
|
||||
key = ui::VKEY_LEFT;
|
||||
} else if (tokens[i] == "right") {
|
||||
key = ui::VKEY_RIGHT;
|
||||
} else if (tokens[i] == "home") {
|
||||
key = ui::VKEY_HOME;
|
||||
} else if (tokens[i] == "end") {
|
||||
key = ui::VKEY_END;
|
||||
} else if (tokens[i] == "pagedown") {
|
||||
key = ui::VKEY_PRIOR;
|
||||
} else if (tokens[i] == "pageup") {
|
||||
key = ui::VKEY_NEXT;
|
||||
} else if (tokens[i] == "esc") {
|
||||
key = ui::VKEY_ESCAPE;
|
||||
} else if (tokens[i] == "volumemute") {
|
||||
key = ui::VKEY_VOLUME_MUTE;
|
||||
} else if (tokens[i] == "volumeup") {
|
||||
key = ui::VKEY_VOLUME_UP;
|
||||
} else if (tokens[i] == "volumedown") {
|
||||
key = ui::VKEY_VOLUME_DOWN;
|
||||
} else if (tokens[i] == "medianexttrack") {
|
||||
key = ui::VKEY_MEDIA_NEXT_TRACK;
|
||||
} else if (tokens[i] == "mediaprevioustrack") {
|
||||
key = ui::VKEY_MEDIA_PREV_TRACK;
|
||||
} else if (tokens[i] == "mediastop") {
|
||||
key = ui::VKEY_MEDIA_STOP;
|
||||
} else if (tokens[i] == "mediaplaypause") {
|
||||
key = ui::VKEY_MEDIA_PLAY_PAUSE;
|
||||
} else if (tokens[i].size() > 1 && tokens[i][0] == 'f') {
|
||||
// F1 - F24.
|
||||
int n;
|
||||
if (base::StringToInt(tokens[i].c_str() + 1, &n)) {
|
||||
key = static_cast<ui::KeyboardCode>(ui::VKEY_F1 + n - 1);
|
||||
} else {
|
||||
LOG(WARNING) << tokens[i] << "is not available on keyboard";
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
LOG(WARNING) << "Invalid accelerator token: " << tokens[i];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (key == ui::VKEY_UNKNOWN) {
|
||||
LOG(WARNING) << "The accelerator doesn't contain a valid key";
|
||||
return false;
|
||||
}
|
||||
|
||||
*accelerator = ui::Accelerator(key, modifiers);
|
||||
SetPlatformAccelerator(accelerator);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace accelerator_util
|
||||
@@ -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_
|
||||
258
browser/ui/atom_menu_controller_mac.mm
Normal file
258
browser/ui/atom_menu_controller_mac.mm
Normal file
@@ -0,0 +1,258 @@
|
||||
// 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 and help menu.
|
||||
if ([[item title] isEqualToString:@"Window"] && [submenu numberOfItems] > 0)
|
||||
[NSApp setWindowsMenu:submenu];
|
||||
else if ([[item title] isEqualToString:@"Help"])
|
||||
[NSApp setHelpMenu:submenu];
|
||||
} else {
|
||||
// The MenuModel works on indexes so we can't just set the command id as the
|
||||
// tag like we do in other menus. Also set the represented object to be
|
||||
// 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
|
||||
294
browser/ui/message_box_win.cc
Normal file
294
browser/ui/message_box_win.cc
Normal file
@@ -0,0 +1,294 @@
|
||||
// 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"
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/message_loop.h"
|
||||
#include "base/run_loop.h"
|
||||
#include "base/string_util.h"
|
||||
#include "base/utf_string_conversions.h"
|
||||
#include "browser/native_window.h"
|
||||
#include "skia/ext/skia_utils_win.h"
|
||||
#include "ui/views/controls/button/label_button.h"
|
||||
#include "ui/views/controls/message_box_view.h"
|
||||
#include "ui/views/layout/grid_layout.h"
|
||||
#include "ui/views/layout/layout_constants.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
#include "ui/views/widget/widget_delegate.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
// The group used by the buttons. This name is chosen voluntarily big not to
|
||||
// conflict with other groups that could be in the dialog content.
|
||||
const int kButtonGroup = 1127;
|
||||
|
||||
class MessageDialog : public base::MessageLoop::Dispatcher,
|
||||
public views::WidgetDelegate,
|
||||
public views::View,
|
||||
public views::ButtonListener {
|
||||
public:
|
||||
MessageDialog(NativeWindow* parent_window,
|
||||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail);
|
||||
virtual ~MessageDialog();
|
||||
|
||||
void Show();
|
||||
|
||||
int GetResult() const;
|
||||
|
||||
void set_callback(const MessageBoxCallback& callback) {
|
||||
delete_on_close_ = true;
|
||||
callback_ = callback;
|
||||
}
|
||||
|
||||
private:
|
||||
// Overridden from MessageLoop::Dispatcher:
|
||||
virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
|
||||
|
||||
// Overridden from views::WidgetDelegate:
|
||||
virtual string16 GetWindowTitle() const;
|
||||
virtual void WindowClosing() OVERRIDE;
|
||||
virtual views::Widget* GetWidget() OVERRIDE;
|
||||
virtual const views::Widget* GetWidget() const OVERRIDE;
|
||||
virtual views::View* GetContentsView() OVERRIDE;
|
||||
virtual views::View* GetInitiallyFocusedView() OVERRIDE;
|
||||
virtual ui::ModalType GetModalType() const OVERRIDE;
|
||||
|
||||
// Overridden from views::View:
|
||||
virtual gfx::Size GetPreferredSize() OVERRIDE;
|
||||
virtual void Layout() OVERRIDE;
|
||||
virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
|
||||
|
||||
// Overridden from views::ButtonListener:
|
||||
virtual void ButtonPressed(views::Button* sender,
|
||||
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);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// MessageDialog, public:
|
||||
|
||||
MessageDialog::MessageDialog(NativeWindow* parent_window,
|
||||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
const std::string& title,
|
||||
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_GT(buttons.size(), 0u);
|
||||
set_owned_by_client();
|
||||
|
||||
views::MessageBoxView::InitParams params(UTF8ToUTF16(title));
|
||||
params.message = UTF8ToUTF16(message + "\n" + detail);
|
||||
message_box_view_ = new views::MessageBoxView(params);
|
||||
AddChildView(message_box_view_);
|
||||
|
||||
for (size_t i = 0; i < buttons.size(); ++i) {
|
||||
views::LabelButton* button = new views::LabelButton(
|
||||
this, UTF8ToUTF16(buttons[i]));
|
||||
button->set_tag(i);
|
||||
button->set_min_size(gfx::Size(60, 20));
|
||||
button->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
|
||||
button->SetGroup(kButtonGroup);
|
||||
|
||||
buttons_.push_back(button);
|
||||
AddChildView(button);
|
||||
}
|
||||
|
||||
// First button is always default button.
|
||||
buttons_[0]->SetIsDefault(true);
|
||||
buttons_[0]->AddAccelerator(ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE));
|
||||
|
||||
views::Widget::InitParams widget_params;
|
||||
widget_params.delegate = this;
|
||||
widget_params.top_level = true;
|
||||
if (parent_window)
|
||||
widget_params.parent = parent_window->GetNativeWindow();
|
||||
widget_ = new views::Widget;
|
||||
widget_->set_frame_type(views::Widget::FRAME_TYPE_FORCE_NATIVE);
|
||||
widget_->Init(widget_params);
|
||||
|
||||
// Bind to ESC.
|
||||
AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
|
||||
|
||||
set_background(views::Background::CreateSolidBackground(
|
||||
skia::COLORREFToSkColor(GetSysColor(COLOR_WINDOW))));
|
||||
}
|
||||
|
||||
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:
|
||||
|
||||
bool MessageDialog::Dispatch(const base::NativeEvent& event) {
|
||||
TranslateMessage(&event);
|
||||
DispatchMessage(&event);
|
||||
return !should_close_;
|
||||
}
|
||||
|
||||
string16 MessageDialog::GetWindowTitle() const {
|
||||
return title_;
|
||||
}
|
||||
|
||||
void MessageDialog::WindowClosing() {
|
||||
should_close_ = true;
|
||||
|
||||
if (delete_on_close_) {
|
||||
callback_.Run(GetResult());
|
||||
base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
|
||||
}
|
||||
}
|
||||
|
||||
views::Widget* MessageDialog::GetWidget() {
|
||||
return widget_;
|
||||
}
|
||||
|
||||
const views::Widget* MessageDialog::GetWidget() const {
|
||||
return widget_;
|
||||
}
|
||||
|
||||
views::View* MessageDialog::GetContentsView() {
|
||||
return this;
|
||||
}
|
||||
|
||||
views::View* MessageDialog::GetInitiallyFocusedView() {
|
||||
if (buttons_.size() > 0)
|
||||
return buttons_[0];
|
||||
else
|
||||
return this;
|
||||
}
|
||||
|
||||
ui::ModalType MessageDialog::GetModalType() const {
|
||||
return ui::MODAL_TYPE_WINDOW;
|
||||
}
|
||||
|
||||
gfx::Size MessageDialog::GetPreferredSize() {
|
||||
gfx::Size size(0, buttons_[0]->GetPreferredSize().height());
|
||||
for (size_t i = 0; i < buttons_.size(); ++i)
|
||||
size.Enlarge(buttons_[i]->GetPreferredSize().width(), 0);
|
||||
|
||||
// Button spaces.
|
||||
size.Enlarge(views::kRelatedButtonHSpacing * (buttons_.size() - 1),
|
||||
views::kRelatedControlVerticalSpacing);
|
||||
|
||||
// The message box view.
|
||||
gfx::Size contents_size = message_box_view_->GetPreferredSize();
|
||||
size.Enlarge(0, contents_size.height());
|
||||
if (contents_size.width() > size.width())
|
||||
size.set_width(contents_size.width());
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void MessageDialog::Layout() {
|
||||
gfx::Rect bounds = GetContentsBounds();
|
||||
|
||||
// Layout the row containing the buttons.
|
||||
int x = bounds.width();
|
||||
int height = buttons_[0]->GetPreferredSize().height() +
|
||||
views::kRelatedControlVerticalSpacing;
|
||||
|
||||
// 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;
|
||||
|
||||
buttons_[i]->SetBounds(x, bounds.height() - height,
|
||||
size.width(), size.height());
|
||||
}
|
||||
|
||||
// Layout the message box view.
|
||||
message_box_view_->SetBounds(bounds.x(), bounds.y(), bounds.width(),
|
||||
bounds.height() - height);
|
||||
}
|
||||
|
||||
bool MessageDialog::AcceleratorPressed(const ui::Accelerator& accelerator) {
|
||||
DCHECK_EQ(accelerator.key_code(), ui::VKEY_ESCAPE);
|
||||
widget_->Close();
|
||||
return true;
|
||||
}
|
||||
|
||||
void MessageDialog::ButtonPressed(views::Button* sender,
|
||||
const ui::Event& event) {
|
||||
result_ = sender->tag();
|
||||
widget_->Close();
|
||||
}
|
||||
|
||||
} // 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) {
|
||||
MessageDialog dialog(parent_window, type, buttons, title, message, detail);
|
||||
dialog.Show();
|
||||
{
|
||||
base::MessageLoop::ScopedNestableTaskAllower allow(
|
||||
base::MessageLoopForUI::current());
|
||||
base::RunLoop run_loop(&dialog);
|
||||
run_loop.Run();
|
||||
}
|
||||
|
||||
return dialog.GetResult();
|
||||
}
|
||||
|
||||
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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user