mirror of
https://github.com/electron/electron.git
synced 2026-02-26 03:01:17 -05:00
Compare commits
953 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e016100860 | ||
|
|
82fc98848a | ||
|
|
ec18c2f354 | ||
|
|
b4da15bba8 | ||
|
|
993a5fda41 | ||
|
|
01921ee6fa | ||
|
|
ad24c11f32 | ||
|
|
351dc4ed6b | ||
|
|
e628c7b37d | ||
|
|
8cc602ff94 | ||
|
|
715fdc8614 | ||
|
|
b1ffd1b02a | ||
|
|
cf6415bf84 | ||
|
|
f386342a7c | ||
|
|
2bc087b5d5 | ||
|
|
172cc22d90 | ||
|
|
12672cf50b | ||
|
|
4e6dc49646 | ||
|
|
129d92b30a | ||
|
|
69e1e3c0bd | ||
|
|
0efdb448b6 | ||
|
|
7842a90c5e | ||
|
|
7c62cfba33 | ||
|
|
acffc713e0 | ||
|
|
d3db178182 | ||
|
|
763dcc545d | ||
|
|
6f25996fa1 | ||
|
|
e296f6daa2 | ||
|
|
092f9d2c46 | ||
|
|
1a5269e51b | ||
|
|
8f32f9f5cb | ||
|
|
b4e836bf2e | ||
|
|
a296b4ef33 | ||
|
|
140ba2858a | ||
|
|
3379641fe2 | ||
|
|
0644129fbe | ||
|
|
c295979270 | ||
|
|
e4a7352b62 | ||
|
|
33eadad139 | ||
|
|
225140bd64 | ||
|
|
58dee04d5c | ||
|
|
4b9ff309ec | ||
|
|
a3f3a35fd1 | ||
|
|
aa03eb5b6c | ||
|
|
ebe70435ef | ||
|
|
0a49dcc623 | ||
|
|
52d07eb30f | ||
|
|
70be04a2d3 | ||
|
|
eaaf52483e | ||
|
|
ebfd03570f | ||
|
|
40c7e6e179 | ||
|
|
de441916d6 | ||
|
|
850edd546c | ||
|
|
b67070f0ae | ||
|
|
c495088390 | ||
|
|
ab1b4c46b2 | ||
|
|
bec7a399cb | ||
|
|
0bf5effe58 | ||
|
|
b65e089028 | ||
|
|
c51f349dfa | ||
|
|
1bb0dde360 | ||
|
|
5c18d89453 | ||
|
|
2ff104d012 | ||
|
|
3402871741 | ||
|
|
74fa2c809d | ||
|
|
ab44edd294 | ||
|
|
5d3445cebb | ||
|
|
24ba712aa5 | ||
|
|
fb60f7946f | ||
|
|
744059b8bd | ||
|
|
8864498065 | ||
|
|
454085eb95 | ||
|
|
6e75af5c0f | ||
|
|
8da7803f3e | ||
|
|
2d6f8350cb | ||
|
|
958658513c | ||
|
|
a28f70e85c | ||
|
|
8f8c3aef87 | ||
|
|
39af10cc8d | ||
|
|
d175a68586 | ||
|
|
f740684f41 | ||
|
|
20a8e7838f | ||
|
|
2f1cb8b52a | ||
|
|
0a7a4c0d0a | ||
|
|
6b8d4a43a3 | ||
|
|
78eac4116c | ||
|
|
5a2f94f415 | ||
|
|
2f04f76e69 | ||
|
|
b8d364f11e | ||
|
|
5871428c83 | ||
|
|
1505dc207b | ||
|
|
dfd076a3e5 | ||
|
|
ad01a1731a | ||
|
|
97ab780305 | ||
|
|
54af048f04 | ||
|
|
488a69d461 | ||
|
|
bbd6c927b1 | ||
|
|
adbb909b39 | ||
|
|
58b1172025 | ||
|
|
438a5acc0f | ||
|
|
58c0486236 | ||
|
|
1c4f50b2df | ||
|
|
dc60bfa885 | ||
|
|
3b05b135a5 | ||
|
|
6b65a66119 | ||
|
|
97c15c463e | ||
|
|
50f226e34e | ||
|
|
2d18f91e57 | ||
|
|
7910fe7785 | ||
|
|
613e5c77ea | ||
|
|
c872b1a770 | ||
|
|
db58048077 | ||
|
|
14803e4cf8 | ||
|
|
1347c61c8e | ||
|
|
69b20d25ee | ||
|
|
9642cd286e | ||
|
|
2a30520799 | ||
|
|
039d4aaecb | ||
|
|
9e922dd0c7 | ||
|
|
4ac59e2674 | ||
|
|
7c5d443284 | ||
|
|
666a2233a7 | ||
|
|
7c75329b18 | ||
|
|
e135bcb5b7 | ||
|
|
d455232eb1 | ||
|
|
c8a794ac34 | ||
|
|
c0ce8723d4 | ||
|
|
9dab6e02ca | ||
|
|
9fb03d584c | ||
|
|
428ad20807 | ||
|
|
92af275f98 | ||
|
|
c7d1f4f6b2 | ||
|
|
ddf2cfd48d | ||
|
|
c69002b0dd | ||
|
|
92ea533aee | ||
|
|
239d535cac | ||
|
|
2eaaad610d | ||
|
|
e0a117414b | ||
|
|
2ab079dc7d | ||
|
|
03e03a5daa | ||
|
|
be24d3e78c | ||
|
|
0e779e20c3 | ||
|
|
2d5c0ac9ee | ||
|
|
8d09f13bad | ||
|
|
b68356b9b9 | ||
|
|
764a6e1d76 | ||
|
|
bbce2c7e2f | ||
|
|
0f648f4468 | ||
|
|
05def654c3 | ||
|
|
2ded7497b6 | ||
|
|
90bd32c680 | ||
|
|
f9d5915542 | ||
|
|
643ed27fd4 | ||
|
|
f154da38e6 | ||
|
|
046a8e8a08 | ||
|
|
80f45f6226 | ||
|
|
898a838ad7 | ||
|
|
b311969f0e | ||
|
|
d719244d1e | ||
|
|
1d0568dd5b | ||
|
|
77a8a3d33c | ||
|
|
d5893d8c9f | ||
|
|
409c6155c2 | ||
|
|
b786772819 | ||
|
|
b2f03fc2d8 | ||
|
|
3e1a5b229c | ||
|
|
8d22eeb3be | ||
|
|
625143426a | ||
|
|
f40155645c | ||
|
|
877830e4a1 | ||
|
|
45f5a10d5d | ||
|
|
d42fd6fc7e | ||
|
|
74248253f5 | ||
|
|
15273c1f7a | ||
|
|
fc92ceb0b6 | ||
|
|
9afa94f4b8 | ||
|
|
edde653d60 | ||
|
|
66553eea1a | ||
|
|
2c97cd64cf | ||
|
|
ff6b9d0907 | ||
|
|
c500c9b289 | ||
|
|
9afb973498 | ||
|
|
1bc49487ad | ||
|
|
f485a9894c | ||
|
|
c140077d53 | ||
|
|
42ce91323c | ||
|
|
0ca9dfbc12 | ||
|
|
b08af89473 | ||
|
|
b9cf0f2126 | ||
|
|
11589a7bde | ||
|
|
b10560a5b0 | ||
|
|
f4d8e32c9f | ||
|
|
617bff8ec8 | ||
|
|
a44f14d76e | ||
|
|
74b4522195 | ||
|
|
99a8f29de9 | ||
|
|
51111430b3 | ||
|
|
9211109088 | ||
|
|
ad7e4a77db | ||
|
|
faf10183d8 | ||
|
|
59c3efd44b | ||
|
|
f2b2c58758 | ||
|
|
b6f6bf9778 | ||
|
|
b0e73532de | ||
|
|
7f0cb0ce1b | ||
|
|
fef53d18c4 | ||
|
|
2aa17debc8 | ||
|
|
0700f08d6d | ||
|
|
1a074bb148 | ||
|
|
74f2e9f102 | ||
|
|
f53995d555 | ||
|
|
9eeebedf5f | ||
|
|
5e61974c24 | ||
|
|
d485cfbca3 | ||
|
|
70feb08f84 | ||
|
|
75b08f510e | ||
|
|
08383a69ce | ||
|
|
7ceca9f426 | ||
|
|
720dc92efe | ||
|
|
73ded9d378 | ||
|
|
48975d04e0 | ||
|
|
417e97eef0 | ||
|
|
b52c07f650 | ||
|
|
1a93b1db52 | ||
|
|
b547772c68 | ||
|
|
4de4ef1ccc | ||
|
|
d822e0d720 | ||
|
|
29c574cf0f | ||
|
|
3840a10da6 | ||
|
|
9bb87af66b | ||
|
|
9ec60cd585 | ||
|
|
959f5d61b7 | ||
|
|
d9ee8519e9 | ||
|
|
8960aa956c | ||
|
|
63258f9f53 | ||
|
|
8b4815fd95 | ||
|
|
32b84bd3f9 | ||
|
|
adab769700 | ||
|
|
d138c2970c | ||
|
|
452619990e | ||
|
|
de17894fce | ||
|
|
6c44553456 | ||
|
|
cc2a9f617d | ||
|
|
1578d2fda9 | ||
|
|
da724d65d7 | ||
|
|
eb92e9cdd8 | ||
|
|
5a980497e8 | ||
|
|
72eb87a631 | ||
|
|
df35700b94 | ||
|
|
ea1b89c699 | ||
|
|
a8658b7dca | ||
|
|
e64fbe3529 | ||
|
|
97c90d31d3 | ||
|
|
a1ec07e07e | ||
|
|
d701e1aa40 | ||
|
|
6d25c81bd1 | ||
|
|
58f1907579 | ||
|
|
3250764e72 | ||
|
|
462e6e0a82 | ||
|
|
59269a70a0 | ||
|
|
8df8b5731e | ||
|
|
dbab889fcc | ||
|
|
891d107a51 | ||
|
|
3ea878941b | ||
|
|
f25cf7481f | ||
|
|
d342c9a6df | ||
|
|
a1f0c24bf4 | ||
|
|
a11d8ea558 | ||
|
|
f6263f8c6b | ||
|
|
d3055a5ca0 | ||
|
|
73790fcef5 | ||
|
|
5010c15ffc | ||
|
|
6656afd57f | ||
|
|
0b7a1a1eef | ||
|
|
72d332dfa0 | ||
|
|
8cf9df2d8d | ||
|
|
3145c78b61 | ||
|
|
de3ccc4b98 | ||
|
|
d0c6176640 | ||
|
|
7cdfa44438 | ||
|
|
10faf314d4 | ||
|
|
378e81ffaa | ||
|
|
423ea00263 | ||
|
|
666aca7803 | ||
|
|
135aca02af | ||
|
|
7ab8134613 | ||
|
|
57244e4718 | ||
|
|
8eb87c5d2b | ||
|
|
02cadde8de | ||
|
|
88ab23def9 | ||
|
|
db6d8de5dc | ||
|
|
652843f447 | ||
|
|
21e5054fac | ||
|
|
a2c26b8c74 | ||
|
|
2cd6ad1a97 | ||
|
|
78e55414d4 | ||
|
|
17628b3e40 | ||
|
|
736fe0c1db | ||
|
|
ed4c69343f | ||
|
|
4421fbf9f3 | ||
|
|
002eb1a326 | ||
|
|
4baaf03ac7 | ||
|
|
c2bfc60a59 | ||
|
|
f78dcfb8e0 | ||
|
|
91bfd1f77c | ||
|
|
9ee0d46734 | ||
|
|
ca2cb9c9ba | ||
|
|
00c484c68b | ||
|
|
38c33d69ae | ||
|
|
5ad3fff6a0 | ||
|
|
cca4f4abd5 | ||
|
|
e54fda6b34 | ||
|
|
b524914008 | ||
|
|
26163e5812 | ||
|
|
0dfcc7a9b3 | ||
|
|
e510384375 | ||
|
|
eb81810a52 | ||
|
|
3b2f3c3152 | ||
|
|
de5bc32d0b | ||
|
|
1e9eccf959 | ||
|
|
4b06c0645c | ||
|
|
c6f870d4e4 | ||
|
|
053594eae8 | ||
|
|
1615c97ce8 | ||
|
|
940db1d1dd | ||
|
|
56dfef8d0d | ||
|
|
3ffd774405 | ||
|
|
076942ca7a | ||
|
|
b6e8420bf2 | ||
|
|
096439dce7 | ||
|
|
346fb745f2 | ||
|
|
020ccd8018 | ||
|
|
ce24226128 | ||
|
|
b3c51e46e7 | ||
|
|
886db7a3f2 | ||
|
|
6c5dde60a3 | ||
|
|
7f06072420 | ||
|
|
5708b7fbec | ||
|
|
5863ed4c33 | ||
|
|
14388feb23 | ||
|
|
e5f852d7d5 | ||
|
|
83e8ceceda | ||
|
|
3ef54147c9 | ||
|
|
f8df377631 | ||
|
|
868dee55de | ||
|
|
7dba4d1d8d | ||
|
|
6840d424cd | ||
|
|
34819140c3 | ||
|
|
9e8a118d10 | ||
|
|
0c7c6ddcc9 | ||
|
|
eadd2f8de6 | ||
|
|
04606a9f97 | ||
|
|
cb4309bbd9 | ||
|
|
1249196118 | ||
|
|
d6ae874038 | ||
|
|
e0e4c1b54c | ||
|
|
628fb5f5e9 | ||
|
|
967c273ddb | ||
|
|
a24d2921af | ||
|
|
5ae57baf11 | ||
|
|
7a390bdd4c | ||
|
|
72f4884127 | ||
|
|
6383eb876e | ||
|
|
c56b3425a9 | ||
|
|
2d3e938a7f | ||
|
|
260ec96edd | ||
|
|
4379d24e9d | ||
|
|
fedf764b7b | ||
|
|
39c6e2d2e5 | ||
|
|
35aaad68d7 | ||
|
|
779583adf5 | ||
|
|
a0784bd038 | ||
|
|
fc9612a5ed | ||
|
|
2cd5fb5694 | ||
|
|
da00329d78 | ||
|
|
fb99bfac52 | ||
|
|
7b19b6b4f2 | ||
|
|
d661099322 | ||
|
|
ea63a04388 | ||
|
|
6f92141587 | ||
|
|
078bd7fb5b | ||
|
|
1703a6f20e | ||
|
|
001b4a3179 | ||
|
|
aab78db8b8 | ||
|
|
9793473b10 | ||
|
|
a89e5592f2 | ||
|
|
989351a41d | ||
|
|
6fb8b2ce4f | ||
|
|
f0be4025a5 | ||
|
|
49da74f976 | ||
|
|
1146441c2a | ||
|
|
d01c200345 | ||
|
|
b7cdb00d09 | ||
|
|
cb92df687d | ||
|
|
2e51afcd9e | ||
|
|
fdc01b8ba8 | ||
|
|
e0528655a8 | ||
|
|
08983e1ba9 | ||
|
|
7d456d3556 | ||
|
|
df4b5f4ede | ||
|
|
fb537d91fc | ||
|
|
b158427271 | ||
|
|
083d0b8b60 | ||
|
|
a2857d2dca | ||
|
|
a90a994a89 | ||
|
|
a2d1ec2c1f | ||
|
|
9b25c16980 | ||
|
|
810f14aecb | ||
|
|
e627592eed | ||
|
|
3e6394a004 | ||
|
|
02e28ea758 | ||
|
|
b98cdf71c4 | ||
|
|
8fca1f52d3 | ||
|
|
1ff00281f3 | ||
|
|
7bcbad925e | ||
|
|
3fa1f3ca6f | ||
|
|
5e7f1ce383 | ||
|
|
79b0fe967b | ||
|
|
d3204e9a9d | ||
|
|
808ceb8811 | ||
|
|
74603624df | ||
|
|
0c0446e254 | ||
|
|
41c1a34b4f | ||
|
|
519b51f055 | ||
|
|
5e2481e631 | ||
|
|
f8786e9d17 | ||
|
|
85a4ff83da | ||
|
|
7231de7c2b | ||
|
|
ae52af3870 | ||
|
|
1569dfa2e8 | ||
|
|
54dac0f37a | ||
|
|
9cf09b8850 | ||
|
|
ae3b47aa75 | ||
|
|
99e8238f90 | ||
|
|
f5a1ffcbd4 | ||
|
|
7042054913 | ||
|
|
16fd56c083 | ||
|
|
9afc016ff9 | ||
|
|
3064afbac4 | ||
|
|
1979b42ee7 | ||
|
|
68155e5fb7 | ||
|
|
9f0571772d | ||
|
|
07cf2eac4e | ||
|
|
822efa2f97 | ||
|
|
0e888ccf22 | ||
|
|
f5b502186b | ||
|
|
4e94e0c82f | ||
|
|
3315e6bda5 | ||
|
|
506d6688e0 | ||
|
|
c7518f84f8 | ||
|
|
cb3e758bc6 | ||
|
|
2bcf8c7bc2 | ||
|
|
bea45867d2 | ||
|
|
70987a9029 | ||
|
|
5c85c2e5d5 | ||
|
|
6f137d62c7 | ||
|
|
3533be2f9f | ||
|
|
a1b28c362d | ||
|
|
26525d6b0f | ||
|
|
16acd669a7 | ||
|
|
a3463119e8 | ||
|
|
9159b06835 | ||
|
|
4c76112698 | ||
|
|
d158dbdb68 | ||
|
|
dadd34249a | ||
|
|
173babc18b | ||
|
|
64c0e0dfdc | ||
|
|
7576de639b | ||
|
|
bdbb994c72 | ||
|
|
ffb1732607 | ||
|
|
02f3d7a25e | ||
|
|
518ec36511 | ||
|
|
12233d704b | ||
|
|
2717556a92 | ||
|
|
7288581393 | ||
|
|
f87a4b9a04 | ||
|
|
b30709f133 | ||
|
|
20e9abe26a | ||
|
|
89b22db618 | ||
|
|
e95ee4775e | ||
|
|
f5ae3111ba | ||
|
|
6b7d3a070a | ||
|
|
e4530e6e32 | ||
|
|
1212e45a6e | ||
|
|
82153eb75f | ||
|
|
960b279419 | ||
|
|
f99cd4d05a | ||
|
|
a720e52568 | ||
|
|
83ee7a464d | ||
|
|
8e5a434560 | ||
|
|
8f06bd6f3e | ||
|
|
fe877da61f | ||
|
|
a1bb0d4d66 | ||
|
|
a6073113a1 | ||
|
|
6902b876a8 | ||
|
|
7d2866f3a7 | ||
|
|
52ba6a25df | ||
|
|
25e15869ec | ||
|
|
b3c76f3904 | ||
|
|
8de9c75caf | ||
|
|
33109a2718 | ||
|
|
cab1b75c41 | ||
|
|
1e9af82bf6 | ||
|
|
ddaf005c2b | ||
|
|
558a612d37 | ||
|
|
5ccc909f2f | ||
|
|
a367934b95 | ||
|
|
2078e5736e | ||
|
|
f0eac9d828 | ||
|
|
8110f2f221 | ||
|
|
c76d87719d | ||
|
|
9bdefa6f1f | ||
|
|
b261c5f87c | ||
|
|
f569617d24 | ||
|
|
88b71b9633 | ||
|
|
f2daeb9d70 | ||
|
|
6088af623e | ||
|
|
57262dd5ef | ||
|
|
2de5ae9991 | ||
|
|
3a094e9802 | ||
|
|
62a5159e72 | ||
|
|
7b955fe829 | ||
|
|
14bc544d89 | ||
|
|
a04bfbbc4b | ||
|
|
69ef175ac5 | ||
|
|
cbac7179fd | ||
|
|
d6e25af59a | ||
|
|
c01a79de6b | ||
|
|
4214b62551 | ||
|
|
88eb5283a0 | ||
|
|
af05f5b329 | ||
|
|
1b3a8435e5 | ||
|
|
432bab3107 | ||
|
|
e15b05603d | ||
|
|
b1db947def | ||
|
|
3d88d56965 | ||
|
|
fdf7452ba9 | ||
|
|
bceac2ab7f | ||
|
|
dcd10d1e4b | ||
|
|
783e4bc591 | ||
|
|
11cfe20395 | ||
|
|
dbb6723dfa | ||
|
|
ee3ac608cf | ||
|
|
565a500320 | ||
|
|
b5c5cce725 | ||
|
|
fcf4da1097 | ||
|
|
ebfbbc0801 | ||
|
|
b508346ed8 | ||
|
|
04de1aa51d | ||
|
|
1c907ffa36 | ||
|
|
1e514620b5 | ||
|
|
4b4654ec71 | ||
|
|
a79fcac047 | ||
|
|
572d4c5687 | ||
|
|
a8d58ea448 | ||
|
|
19daed9479 | ||
|
|
ebb031dafe | ||
|
|
bf5b084945 | ||
|
|
637b642837 | ||
|
|
e6f3c4c22b | ||
|
|
b5ff77ef0d | ||
|
|
bff66caaa6 | ||
|
|
aa20f75335 | ||
|
|
143a5e1178 | ||
|
|
a96ff85005 | ||
|
|
80e02d945c | ||
|
|
edf60b8529 | ||
|
|
7fd60294f9 | ||
|
|
a3ec50437d | ||
|
|
5b5393e82b | ||
|
|
ffd9c743de | ||
|
|
09c2317ae6 | ||
|
|
58efb3c018 | ||
|
|
528e0f3efb | ||
|
|
2a2158e0e3 | ||
|
|
cde7c6a4ef | ||
|
|
210417b428 | ||
|
|
1509aca788 | ||
|
|
b98154431c | ||
|
|
55a8862374 | ||
|
|
c2290ad058 | ||
|
|
cec6895e67 | ||
|
|
794f89abf5 | ||
|
|
37d18d512b | ||
|
|
d98cece115 | ||
|
|
0fbd908fb6 | ||
|
|
c15a9e7d5c | ||
|
|
1418fdbc02 | ||
|
|
9f52b11761 | ||
|
|
01dc0f973c | ||
|
|
b2a8678c47 | ||
|
|
9974a238c2 | ||
|
|
62c44ee47b | ||
|
|
e41b0d4d2c | ||
|
|
eb370ba22a | ||
|
|
afa9f30aac | ||
|
|
2ea2413752 | ||
|
|
fb5fe7a714 | ||
|
|
5236b0c067 | ||
|
|
081a4597e9 | ||
|
|
4b61683cdf | ||
|
|
19ca011735 | ||
|
|
2bfa9da82e | ||
|
|
2532318bee | ||
|
|
87f44c42df | ||
|
|
b822a83bc2 | ||
|
|
7d05a12ee9 | ||
|
|
bd4d6dcda2 | ||
|
|
9b9108f789 | ||
|
|
f198148c79 | ||
|
|
8c83dfe918 | ||
|
|
f93d50c380 | ||
|
|
cc8b22b5ff | ||
|
|
28d1fb8cad | ||
|
|
5e62b5975b | ||
|
|
c2f14e6053 | ||
|
|
0ebd4d04ad | ||
|
|
1023b67d59 | ||
|
|
552a12d2ee | ||
|
|
7f0658efa7 | ||
|
|
15f350edcb | ||
|
|
d02413de00 | ||
|
|
cd93b9412c | ||
|
|
13784e6551 | ||
|
|
b8cf9a2788 | ||
|
|
09a6e37a09 | ||
|
|
ea69e91e49 | ||
|
|
ab6ed823d1 | ||
|
|
33c2768a77 | ||
|
|
1f3a73e802 | ||
|
|
4359eb4472 | ||
|
|
3b762fddfb | ||
|
|
93fb70b62f | ||
|
|
6d9ca4f52b | ||
|
|
77dbec305f | ||
|
|
8f429bc25a | ||
|
|
42e21d15bf | ||
|
|
78459b913b | ||
|
|
197a9b4165 | ||
|
|
1f97cee7c9 | ||
|
|
015ef3e014 | ||
|
|
2d65c3bcd0 | ||
|
|
52789ab96f | ||
|
|
89c7028ed1 | ||
|
|
b3905e867e | ||
|
|
aba517d4fd | ||
|
|
4f6e70a75c | ||
|
|
7b542b88f0 | ||
|
|
3519dd96ee | ||
|
|
1ce86b6dfc | ||
|
|
19963bfcd1 | ||
|
|
2fca10ac98 | ||
|
|
f51103f44a | ||
|
|
339496a361 | ||
|
|
30dfd54575 | ||
|
|
532f75fcab | ||
|
|
7ee2a703d9 | ||
|
|
7c5afdd388 | ||
|
|
f73e1f9188 | ||
|
|
d50db378d7 | ||
|
|
db23d1165c | ||
|
|
bafbee805c | ||
|
|
ef59f4f243 | ||
|
|
83fe340b98 | ||
|
|
b4f90c8c81 | ||
|
|
a1cbd11b5b | ||
|
|
befdfceada | ||
|
|
49e1316f7f | ||
|
|
c164da5a38 | ||
|
|
969916442f | ||
|
|
99bfc9b7f5 | ||
|
|
245dc01e33 | ||
|
|
4818e76ad9 | ||
|
|
98adcac5df | ||
|
|
19e96cc212 | ||
|
|
cfffe39151 | ||
|
|
0dfd00f664 | ||
|
|
dbbc2f19f4 | ||
|
|
cb1d9f60ec | ||
|
|
db2042f561 | ||
|
|
91f3b3955a | ||
|
|
923296b4ee | ||
|
|
e209312459 | ||
|
|
b47fae7393 | ||
|
|
8e05fe3350 | ||
|
|
e6341ceaaa | ||
|
|
0120be5b8c | ||
|
|
19436358fb | ||
|
|
2cb1aa6639 | ||
|
|
2f36f5ca78 | ||
|
|
25a7bcef82 | ||
|
|
c8eaaaea83 | ||
|
|
beb2853bbf | ||
|
|
f76b60f295 | ||
|
|
663a48ee38 | ||
|
|
db8ffe1dc7 | ||
|
|
ad59393641 | ||
|
|
a751f4c689 | ||
|
|
b3e9d35667 | ||
|
|
c2aa7d538f | ||
|
|
1d41903779 | ||
|
|
92f3371118 | ||
|
|
543c4d5597 | ||
|
|
e07f5cd53f | ||
|
|
66c4c7e77b | ||
|
|
274854876c | ||
|
|
81db8e098e | ||
|
|
af05f26a5f | ||
|
|
0b35d97821 | ||
|
|
8a56ab3947 | ||
|
|
82b1607c1e | ||
|
|
16348fc895 | ||
|
|
1eba552a8d | ||
|
|
47eac062f6 | ||
|
|
57580e00f9 | ||
|
|
93bbc6c810 | ||
|
|
894f9c0cb0 | ||
|
|
f22662ffb2 | ||
|
|
559eb20e7f | ||
|
|
ccbe554ec0 | ||
|
|
93243ef223 | ||
|
|
47439cd77c | ||
|
|
ac62871645 | ||
|
|
ab40da3f31 | ||
|
|
6e099af5fe | ||
|
|
c0a6cb69bf | ||
|
|
2597ded985 | ||
|
|
10da361db1 | ||
|
|
36fa4da252 | ||
|
|
68005f9ad4 | ||
|
|
bf5d448e37 | ||
|
|
600077996c | ||
|
|
cef177abc4 | ||
|
|
8572ccb807 | ||
|
|
ce8bbb689c | ||
|
|
9cf9229308 | ||
|
|
7ffa7042b1 | ||
|
|
b360f7d86a | ||
|
|
44f8bfc550 | ||
|
|
bd704dd8aa | ||
|
|
7b3fc14023 | ||
|
|
193f95a888 | ||
|
|
b03f44df10 | ||
|
|
bf9af4d45b | ||
|
|
8181e9a0ef | ||
|
|
d9db657b43 | ||
|
|
e96119fc32 | ||
|
|
8aa559fe51 | ||
|
|
a5e2f8e79e | ||
|
|
2b3a80ecda | ||
|
|
7da3e84369 | ||
|
|
8b8a6aea74 | ||
|
|
16e224bb86 | ||
|
|
459d389e03 | ||
|
|
8e4581a3c0 | ||
|
|
c97c3fb9a1 | ||
|
|
7ce8156691 | ||
|
|
0e6a70c556 | ||
|
|
b68d559329 | ||
|
|
18fcd6990b | ||
|
|
5fe130a684 | ||
|
|
d367af3fa4 | ||
|
|
549ec51bce | ||
|
|
b4674923c9 | ||
|
|
71598e15bf | ||
|
|
cd3c061448 | ||
|
|
163790d107 | ||
|
|
2fdc5780ff | ||
|
|
b76642bd10 | ||
|
|
209e24bf0f | ||
|
|
731773765e | ||
|
|
333fe87490 | ||
|
|
36f0ef703a | ||
|
|
605722c397 | ||
|
|
132c13a11b | ||
|
|
04d24f61fe | ||
|
|
8eb5e651a2 | ||
|
|
5cd0fc4d52 | ||
|
|
d12697c657 | ||
|
|
0819176cb1 | ||
|
|
7d1f6dae6f | ||
|
|
5c2bb42d49 | ||
|
|
db9615f5cd | ||
|
|
09c5da7147 | ||
|
|
4b12a95d37 | ||
|
|
200a19dad9 | ||
|
|
2ee6e43fb3 | ||
|
|
0fef09281b | ||
|
|
f91a81fe77 | ||
|
|
78eff673ec | ||
|
|
51dc8ad70a | ||
|
|
d8cd9b71b0 | ||
|
|
c78a3ff714 | ||
|
|
4642630674 | ||
|
|
a6a5d50c3f | ||
|
|
b4790a7531 | ||
|
|
9199d0df0a | ||
|
|
a84e6227ef | ||
|
|
35dcdfc492 | ||
|
|
2f4333b852 | ||
|
|
bd1fd9680f | ||
|
|
cf79f439ce | ||
|
|
e829a28947 | ||
|
|
6d756d9d13 | ||
|
|
29abfa68e9 | ||
|
|
ab98dcd7cf | ||
|
|
6494ed6b13 | ||
|
|
8893c9502a | ||
|
|
13b6ed6dc5 | ||
|
|
8aa815e6d1 | ||
|
|
719f68a44b | ||
|
|
4c48f0cd36 | ||
|
|
8ef3351846 | ||
|
|
9f0ac13edc | ||
|
|
5459137d3d | ||
|
|
52b2c0d27f | ||
|
|
89087d402d | ||
|
|
64e84b8f6a | ||
|
|
24586c1330 | ||
|
|
f8c6056eec | ||
|
|
03ab9b2686 | ||
|
|
f1a8c5a1ca | ||
|
|
488801e244 | ||
|
|
bf1765f941 | ||
|
|
994be9cdab | ||
|
|
d4e4c6ca15 | ||
|
|
47cb06e201 | ||
|
|
cac97cca0d | ||
|
|
16c08e7e37 | ||
|
|
2de5f9de6c | ||
|
|
06a3875726 | ||
|
|
1ae8bed96a | ||
|
|
2ec74b5958 | ||
|
|
72ebb2c9fe | ||
|
|
52166d2999 | ||
|
|
676cfa03a1 | ||
|
|
64a89fe755 | ||
|
|
2bd03f6eda | ||
|
|
eeaee1a0b7 | ||
|
|
fed9ef0687 | ||
|
|
75448ad7ed | ||
|
|
25db6e0bd8 | ||
|
|
cefe540ec0 | ||
|
|
8363a39a56 | ||
|
|
57ef6adbbd | ||
|
|
5ae9c633ca | ||
|
|
b6a5e927e0 | ||
|
|
625c17fa24 | ||
|
|
f776932718 | ||
|
|
55c07cec68 | ||
|
|
161dc45ec8 | ||
|
|
29827fa66b | ||
|
|
40b6a1a37c | ||
|
|
e4ae579b16 | ||
|
|
582a42f97c | ||
|
|
9a0a10e766 | ||
|
|
cd1c331112 | ||
|
|
8a2b665097 | ||
|
|
690513db7f | ||
|
|
13c1b078f9 | ||
|
|
4da7578dab | ||
|
|
c821a06e2f | ||
|
|
cd7b3dd291 | ||
|
|
bb42c2c7b6 | ||
|
|
af62b7b5c9 | ||
|
|
8f9a109fa6 | ||
|
|
05468cc3fa | ||
|
|
94d69777fa | ||
|
|
67144aaf2a | ||
|
|
d9efc3b4bf | ||
|
|
c32aac0a56 | ||
|
|
92b15c81e9 | ||
|
|
19d742de37 | ||
|
|
e8f33f51fb | ||
|
|
7f7cdbf775 | ||
|
|
7f42c0fa21 | ||
|
|
8306dc427a | ||
|
|
66b3972fbc | ||
|
|
ed244648d0 | ||
|
|
790fba598e | ||
|
|
129159c895 | ||
|
|
f4c696b922 | ||
|
|
f54506acc0 | ||
|
|
4466082592 | ||
|
|
a8256a62e0 | ||
|
|
683917ae67 | ||
|
|
a22b9be681 | ||
|
|
3b20f2aced | ||
|
|
5d23b7468e | ||
|
|
d5b47d1059 | ||
|
|
47e9deeb9a | ||
|
|
6d6e75795f | ||
|
|
cc3066e746 | ||
|
|
0fcc0f3e0a | ||
|
|
da83ba6c06 | ||
|
|
3c186946eb | ||
|
|
31beee9599 | ||
|
|
912ed2ca10 | ||
|
|
c2352d3499 | ||
|
|
3a3b05b2f0 | ||
|
|
95a8f3fc70 | ||
|
|
34cd1435b4 | ||
|
|
d4be2da70e | ||
|
|
e5c4e34ac4 | ||
|
|
6dfa7b5383 | ||
|
|
94382cbaa2 | ||
|
|
981908c336 | ||
|
|
3ee054e316 | ||
|
|
f22d4bf0c0 | ||
|
|
d46e986e80 | ||
|
|
bd6d41bd87 | ||
|
|
4457edb1d3 | ||
|
|
e920ce3e24 | ||
|
|
ce8aa073ee | ||
|
|
2396b51cb6 | ||
|
|
317406f26d | ||
|
|
67a9931b55 | ||
|
|
ad851547e0 | ||
|
|
c4cbb5ecdb | ||
|
|
b97c22d4d7 | ||
|
|
fe631e6eeb | ||
|
|
1314b7c7e5 | ||
|
|
c026863d48 | ||
|
|
51d5ef9d86 | ||
|
|
16fb847009 | ||
|
|
cd8ceec62e | ||
|
|
98a9d8a9e3 | ||
|
|
4e2f242ad0 | ||
|
|
02bdace366 | ||
|
|
6ed538b952 | ||
|
|
dfbe158ca9 | ||
|
|
fb37b5720d | ||
|
|
57ab704300 | ||
|
|
4a310ad630 | ||
|
|
a9ad783bca | ||
|
|
b5c9fe78f1 | ||
|
|
e4bb456964 | ||
|
|
b45ed8d9a2 | ||
|
|
bdf73fcd4c | ||
|
|
3e720bd611 | ||
|
|
ad89a923e9 | ||
|
|
725115e0b5 | ||
|
|
419a14a63f | ||
|
|
d9102efff7 | ||
|
|
895ab49857 | ||
|
|
ebbb974aca | ||
|
|
8a6ba7c49f | ||
|
|
f98da217e1 | ||
|
|
2060acd914 | ||
|
|
014d80c359 | ||
|
|
9b7ad675c6 | ||
|
|
4d56281972 | ||
|
|
5584e3fd49 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -4,8 +4,13 @@
|
||||
/external_binaries/
|
||||
/out/
|
||||
/vendor/brightray/vendor/download/
|
||||
/vendor/debian_wheezy_arm-sysroot/
|
||||
/vendor/debian_wheezy_i386-sysroot/
|
||||
/vendor/python_26/
|
||||
/vendor/npm/
|
||||
/vendor/llvm/
|
||||
/vendor/llvm-build/
|
||||
/vendor/.gclient
|
||||
node_modules/
|
||||
*.xcodeproj
|
||||
*.swp
|
||||
|
||||
9
.gitmodules
vendored
9
.gitmodules
vendored
@@ -13,3 +13,12 @@
|
||||
[submodule "vendor/native_mate"]
|
||||
path = vendor/native_mate
|
||||
url = https://github.com/zcbenz/native-mate.git
|
||||
[submodule "vendor/crashpad"]
|
||||
path = vendor/crashpad
|
||||
url = https://github.com/atom/crashpad.git
|
||||
[submodule "vendor/requests"]
|
||||
path = vendor/requests
|
||||
url = https://github.com/kennethreitz/requests
|
||||
[submodule "vendor/boto"]
|
||||
path = vendor/boto
|
||||
url = https://github.com/boto/boto.git
|
||||
|
||||
25
.travis.yml
25
.travis.yml
@@ -1,15 +1,28 @@
|
||||
git:
|
||||
depth: 10
|
||||
notifications:
|
||||
email: false
|
||||
|
||||
language: cpp
|
||||
compiler: clang
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
env:
|
||||
- TARGET_ARCH=x64
|
||||
|
||||
notifications:
|
||||
email:
|
||||
on_success: never
|
||||
on_failure: change
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
env: TARGET_ARCH=arm
|
||||
- os: linux
|
||||
env: TARGET_ARCH=ia32
|
||||
allow_failures:
|
||||
- env: TARGET_ARCH=arm
|
||||
- env: TARGET_ARCH=ia32
|
||||
|
||||
script: './script/cibuild'
|
||||
|
||||
git:
|
||||
depth: 10
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
:+1::tada: First off, thanks for taking the time to contribute! :tada::+1:
|
||||
|
||||
This project adheres to the [Contributor Covenant 1.2](http://contributor-covenant.org/version/1/2/0).
|
||||
By participating, you are expected to uphold this code. Please report unacceptable behavior to atom@github.com.
|
||||
|
||||
The following is a set of guidelines for contributing to Electron.
|
||||
These are just guidelines, not rules, use your best judgment and feel free to
|
||||
propose changes to this document in a pull request.
|
||||
|
||||
44
README-ko.md
Normal file
44
README-ko.md
Normal file
@@ -0,0 +1,44 @@
|
||||
[](http://electron.atom.io/)
|
||||
|
||||
[](https://travis-ci.org/atom/electron)
|
||||
[](https://david-dm.org/atom/electron#info=devDependencies)
|
||||
[](http://atom-slack.herokuapp.com/)
|
||||
|
||||
### [Electron](https://github.com/atom/electron/) 한국어 참조문서
|
||||
|
||||
:zap: *이전까지 Atom Shell로 알려져 있었습니다* :zap:
|
||||
|
||||
|
||||
Electron은 JavaScript, HTML 그리고 CSS를 이용하여 Cross-Platform 데스크톱 어플리케이션을 개발할 수 있도록 해주는 프레임워크입니다. 이 프레임워크는 [io.js](http://iojs.org) 와
|
||||
[Chromium](http://www.chromium.org) 을 기반으로 만들어 졌으며 [Atom Editor](https://github.com/atom/atom) 에 사용되고 있습니다.
|
||||
|
||||
Electron에 대한 중요한 알림을 받으려면 Twitter에서 [@ElectronJS](https://twitter.com/electronjs)를 Follow하세요.
|
||||
|
||||
## 다운로드
|
||||
|
||||
Linux, Windows, Mac용으로 미리 빌드된 Electron 바이너리와 디버그 심볼이 준비되어 있습니다. [releases](https://github.com/atom/electron/releases) 페이지에서 받아 볼 수 있습니다.
|
||||
|
||||
또한 [`npm`](https://docs.npmjs.com/)을 이용하여 미리 빌드된 Electron 바이너리를 받을 수 있습니다:
|
||||
|
||||
```sh
|
||||
# $PATH에 `electron`을 등록하고 전역에 설치합니다.
|
||||
npm install electron-prebuilt -g
|
||||
|
||||
# 개발용 dependency로 설치합니다.
|
||||
npm install electron-prebuilt --save-dev
|
||||
```
|
||||
|
||||
### 미러
|
||||
|
||||
- [China](https://npm.taobao.org/mirrors/electron)
|
||||
|
||||
## 참조문서
|
||||
|
||||
[docs](https://github.com/atom/electron/tree/master/docs/README-ko.md) 에 프레임워크 사용 가이드와 API 레퍼런스가 있습니다.
|
||||
추가적으로 Electron을 빌드 하는 방법과 프로젝트에 기여하는 방법이 문서에 포함되어 있으니 참고하시기 바랍니다.
|
||||
|
||||
## 커뮤니티
|
||||
|
||||
[Atom 포럼내의 `electron` 카테고리](http://discuss.atom.io/category/electron) 와 Freenode `#atom-shell` 채팅채널이 있습니다.
|
||||
|
||||
[awesome-electron](https://github.com/sindresorhus/awesome-electron) 에 커뮤니티가 운영중인 유용한 예제 앱과 툴, 리소스가 있으니 한번 탐색해 보시기 바랍니다.
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
[](https://travis-ci.org/atom/electron)
|
||||
[](https://david-dm.org/atom/electron#info=devDependencies)
|
||||
[](http://atom-slack.herokuapp.com/)
|
||||
|
||||
:zap: *formerly known as Atom Shell* :zap:
|
||||
|
||||
@@ -13,6 +14,9 @@ editor](https://github.com/atom/atom).
|
||||
Follow [@ElectronJS](https://twitter.com/electronjs) on Twitter for important
|
||||
announcements.
|
||||
|
||||
This project adheres to the [Contributor Covenant 1.2](http://contributor-covenant.org/version/1/2/0).
|
||||
By participating, you are expected to uphold this code. Please report unacceptable behavior to atom@github.com.
|
||||
|
||||
## Downloads
|
||||
|
||||
Prebuilt binaries and debug symbols of Electron for Linux, Windows and Mac can
|
||||
|
||||
37
atom.gyp
37
atom.gyp
@@ -4,9 +4,7 @@
|
||||
'product_name%': 'Electron',
|
||||
'company_name%': 'GitHub, Inc',
|
||||
'company_abbr%': 'github',
|
||||
'version%': '0.27.0',
|
||||
|
||||
'atom_source_root': '<!(["python", "tools/atom_source_root.py"])',
|
||||
'version%': '0.30.5',
|
||||
},
|
||||
'includes': [
|
||||
'filenames.gypi',
|
||||
@@ -17,8 +15,12 @@
|
||||
'ATOM_PRODUCT_NAME="<(product_name)"',
|
||||
'ATOM_PROJECT_NAME="<(project_name)"',
|
||||
],
|
||||
'mac_framework_dirs': [
|
||||
'<(atom_source_root)/external_binaries',
|
||||
'conditions': [
|
||||
['OS=="mac"', {
|
||||
'mac_framework_dirs': [
|
||||
'<(source_root)/external_binaries',
|
||||
],
|
||||
}],
|
||||
],
|
||||
},
|
||||
'targets': [
|
||||
@@ -114,6 +116,15 @@
|
||||
],
|
||||
}], # OS!="mac"
|
||||
['OS=="win"', {
|
||||
'include_dirs': [
|
||||
'<(libchromiumcontent_dir)/gen/ui/resources',
|
||||
],
|
||||
'msvs_settings': {
|
||||
'VCManifestTool': {
|
||||
'EmbedManifest': 'true',
|
||||
'AdditionalManifestFiles': 'atom/browser/resources/win/atom.manifest',
|
||||
}
|
||||
},
|
||||
'copies': [
|
||||
{
|
||||
'variables': {
|
||||
@@ -156,6 +167,10 @@
|
||||
]
|
||||
},
|
||||
],
|
||||
}, {
|
||||
'dependencies': [
|
||||
'vendor/breakpad/breakpad.gyp:dump_syms#host',
|
||||
],
|
||||
}], # OS=="win"
|
||||
['OS=="linux"', {
|
||||
'copies': [
|
||||
@@ -257,8 +272,9 @@
|
||||
'libraries': [
|
||||
'-limm32.lib',
|
||||
'-loleacc.lib',
|
||||
'-lComdlg32.lib',
|
||||
'-lWininet.lib',
|
||||
'-lcomctl32.lib',
|
||||
'-lcomdlg32.lib',
|
||||
'-lwininet.lib',
|
||||
],
|
||||
},
|
||||
'dependencies': [
|
||||
@@ -275,7 +291,8 @@
|
||||
}], # OS=="win"
|
||||
['OS=="mac"', {
|
||||
'dependencies': [
|
||||
'vendor/breakpad/breakpad.gyp:breakpad',
|
||||
'vendor/crashpad/client/client.gyp:crashpad_client',
|
||||
'vendor/crashpad/handler/handler.gyp:crashpad_handler',
|
||||
],
|
||||
}], # OS=="mac"
|
||||
['OS=="linux"', {
|
||||
@@ -430,8 +447,7 @@
|
||||
{
|
||||
'destination': '<(PRODUCT_DIR)/<(product_name) Framework.framework/Versions/A/Resources',
|
||||
'files': [
|
||||
'<(PRODUCT_DIR)/Inspector',
|
||||
'<(PRODUCT_DIR)/crash_report_sender.app',
|
||||
'<(PRODUCT_DIR)/crashpad_handler',
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -452,7 +468,6 @@
|
||||
'tools/mac/create-framework-subdir-symlinks.sh',
|
||||
'<(product_name) Framework',
|
||||
'Libraries',
|
||||
'Frameworks',
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -75,6 +75,16 @@ std::string AtomContentClient::GetProduct() const {
|
||||
void AtomContentClient::AddAdditionalSchemes(
|
||||
std::vector<std::string>* standard_schemes,
|
||||
std::vector<std::string>* savable_schemes) {
|
||||
auto command_line = base::CommandLine::ForCurrentProcess();
|
||||
auto custom_schemes = command_line->GetSwitchValueASCII(
|
||||
switches::kRegisterStandardSchemes);
|
||||
if (!custom_schemes.empty()) {
|
||||
std::vector<std::string> schemes;
|
||||
base::SplitString(custom_schemes, ',', &schemes);
|
||||
standard_schemes->insert(standard_schemes->end(),
|
||||
schemes.begin(),
|
||||
schemes.end());
|
||||
}
|
||||
standard_schemes->push_back("chrome-extension");
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
|
||||
#include "atom/app/atom_library_main.h"
|
||||
|
||||
#include "atom/app/atom_main_args.h"
|
||||
#include "atom/app/atom_main_delegate.h"
|
||||
#include "atom/app/node_main.h"
|
||||
#include "atom/common/atom_command_line.h"
|
||||
#include "base/at_exit.h"
|
||||
#include "base/i18n/icu_util.h"
|
||||
#include "base/mac/bundle_locations.h"
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/app/atom_main.h"
|
||||
#include "atom/app/atom_main_args.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -33,6 +32,7 @@
|
||||
#endif // defined(OS_MACOSX)
|
||||
|
||||
#include "atom/app/node_main.h"
|
||||
#include "atom/common/atom_command_line.h"
|
||||
#include "base/i18n/icu_util.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
|
||||
@@ -12,22 +12,23 @@
|
||||
#endif
|
||||
|
||||
#include "atom/browser/api/atom_api_menu.h"
|
||||
#include "atom/browser/api/atom_api_session.h"
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/atom_browser_main_parts.h"
|
||||
#include "atom/browser/browser.h"
|
||||
#include "atom/browser/api/atom_api_web_contents.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "atom/common/native_mate_converters/gurl_converter.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/environment.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/path_service.h"
|
||||
#include "brightray/browser/brightray_paths.h"
|
||||
#include "native_mate/callback.h"
|
||||
#include "content/public/browser/client_certificate_delegate.h"
|
||||
#include "content/public/browser/gpu_data_manager.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/object_template_builder.h"
|
||||
#include "net/base/load_flags.h"
|
||||
#include "net/proxy/proxy_service.h"
|
||||
#include "net/url_request/url_request_context.h"
|
||||
#include "net/url_request/url_request_context_getter.h"
|
||||
#include "net/ssl/ssl_cert_request_info.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
@@ -60,6 +61,21 @@ struct Converter<Browser::UserTask> {
|
||||
};
|
||||
#endif
|
||||
|
||||
template<>
|
||||
struct Converter<scoped_refptr<net::X509Certificate>> {
|
||||
static v8::Local<v8::Value> ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const scoped_refptr<net::X509Certificate>& val) {
|
||||
mate::Dictionary dict(isolate, v8::Object::New(isolate));
|
||||
std::string encoded_data;
|
||||
net::X509Certificate::GetPEMEncoded(
|
||||
val->os_cert_handle(), &encoded_data);
|
||||
dict.Set("data", encoded_data);
|
||||
dict.Set("issuerName", val->issuer().GetDisplayName());
|
||||
return dict.GetHandle();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
|
||||
@@ -93,50 +109,39 @@ int GetPathConstant(const std::string& name) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
class ResolveProxyHelper {
|
||||
public:
|
||||
ResolveProxyHelper(const GURL& url, App::ResolveProxyCallback callback)
|
||||
: callback_(callback) {
|
||||
net::ProxyService* proxy_service = AtomBrowserContext::Get()->
|
||||
url_request_context_getter()->GetURLRequestContext()->proxy_service();
|
||||
|
||||
// Start the request.
|
||||
int result = proxy_service->ResolveProxy(
|
||||
url, net::LOAD_NORMAL, &proxy_info_,
|
||||
base::Bind(&ResolveProxyHelper::OnResolveProxyCompleted,
|
||||
base::Unretained(this)),
|
||||
&pac_req_, nullptr, net::BoundNetLog());
|
||||
|
||||
// Completed synchronously.
|
||||
if (result != net::ERR_IO_PENDING)
|
||||
OnResolveProxyCompleted(result);
|
||||
void OnClientCertificateSelected(
|
||||
v8::Isolate* isolate,
|
||||
std::shared_ptr<content::ClientCertificateDelegate> delegate,
|
||||
mate::Arguments* args) {
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
mate::Dictionary cert_data;
|
||||
if (!(args->Length() == 1 && args->GetNext(&cert_data))) {
|
||||
args->ThrowError();
|
||||
return;
|
||||
}
|
||||
|
||||
void OnResolveProxyCompleted(int result) {
|
||||
std::string proxy;
|
||||
if (result == net::OK)
|
||||
proxy = proxy_info_.ToPacString();
|
||||
callback_.Run(proxy);
|
||||
std::string encoded_data;
|
||||
cert_data.Get("data", &encoded_data);
|
||||
|
||||
delete this;
|
||||
}
|
||||
auto certs =
|
||||
net::X509Certificate::CreateCertificateListFromBytes(
|
||||
encoded_data.data(), encoded_data.size(),
|
||||
net::X509Certificate::FORMAT_AUTO);
|
||||
|
||||
private:
|
||||
App::ResolveProxyCallback callback_;
|
||||
net::ProxyInfo proxy_info_;
|
||||
net::ProxyService::PacRequest* pac_req_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ResolveProxyHelper);
|
||||
};
|
||||
delegate->ContinueWithCertificate(certs[0].get());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
App::App() {
|
||||
Browser::Get()->AddObserver(this);
|
||||
content::GpuDataManager::GetInstance()->AddObserver(this);
|
||||
}
|
||||
|
||||
App::~App() {
|
||||
Browser::Get()->RemoveObserver(this);
|
||||
content::GpuDataManager::GetInstance()->RemoveObserver(this);
|
||||
}
|
||||
|
||||
void App::OnBeforeQuit(bool* prevent_default) {
|
||||
@@ -172,9 +177,42 @@ void App::OnWillFinishLaunching() {
|
||||
}
|
||||
|
||||
void App::OnFinishLaunching() {
|
||||
// Create the defaultSession.
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
auto browser_context = static_cast<AtomBrowserContext*>(
|
||||
AtomBrowserMainParts::Get()->browser_context());
|
||||
auto handle = Session::CreateFrom(isolate(), browser_context);
|
||||
default_session_.Reset(isolate(), handle.ToV8());
|
||||
|
||||
Emit("ready");
|
||||
}
|
||||
|
||||
void App::OnSelectCertificate(
|
||||
content::WebContents* web_contents,
|
||||
net::SSLCertRequestInfo* cert_request_info,
|
||||
scoped_ptr<content::ClientCertificateDelegate> delegate) {
|
||||
std::shared_ptr<content::ClientCertificateDelegate>
|
||||
shared_delegate(delegate.release());
|
||||
bool prevent_default =
|
||||
Emit("select-certificate",
|
||||
api::WebContents::CreateFrom(isolate(), web_contents),
|
||||
cert_request_info->host_and_port.ToString(),
|
||||
cert_request_info->client_certs,
|
||||
base::Bind(&OnClientCertificateSelected,
|
||||
isolate(),
|
||||
shared_delegate));
|
||||
|
||||
// Default to first certificate from the platform store.
|
||||
if (!prevent_default)
|
||||
shared_delegate->ContinueWithCertificate(
|
||||
cert_request_info->client_certs[0].get());
|
||||
}
|
||||
|
||||
void App::OnGpuProcessCrashed(base::TerminationStatus exit_code) {
|
||||
Emit("gpu-process-crashed");
|
||||
}
|
||||
|
||||
base::FilePath App::GetPath(mate::Arguments* args, const std::string& name) {
|
||||
bool succeed = false;
|
||||
base::FilePath path;
|
||||
@@ -197,10 +235,6 @@ void App::SetPath(mate::Arguments* args,
|
||||
args->ThrowError("Failed to set path");
|
||||
}
|
||||
|
||||
void App::ResolveProxy(const GURL& url, ResolveProxyCallback callback) {
|
||||
new ResolveProxyHelper(url, callback);
|
||||
}
|
||||
|
||||
void App::SetDesktopName(const std::string& desktop_name) {
|
||||
#if defined(OS_LINUX)
|
||||
scoped_ptr<base::Environment> env(base::Environment::Create());
|
||||
@@ -215,6 +249,13 @@ void App::SetAppUserModelId(const std::string& app_id) {
|
||||
#endif
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> App::DefaultSession(v8::Isolate* isolate) {
|
||||
if (default_session_.IsEmpty())
|
||||
return v8::Null(isolate);
|
||||
else
|
||||
return v8::Local<v8::Value>::New(isolate, default_session_);
|
||||
}
|
||||
|
||||
mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) {
|
||||
auto browser = base::Unretained(Browser::Get());
|
||||
@@ -236,9 +277,9 @@ mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder(
|
||||
#endif
|
||||
.SetMethod("setPath", &App::SetPath)
|
||||
.SetMethod("getPath", &App::GetPath)
|
||||
.SetMethod("resolveProxy", &App::ResolveProxy)
|
||||
.SetMethod("setDesktopName", &App::SetDesktopName)
|
||||
.SetMethod("setAppUserModelId", &App::SetAppUserModelId);
|
||||
.SetMethod("setAppUserModelId", &App::SetAppUserModelId)
|
||||
.SetProperty("defaultSession", &App::DefaultSession);
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
@@ -9,11 +9,9 @@
|
||||
|
||||
#include "atom/browser/api/event_emitter.h"
|
||||
#include "atom/browser/browser_observer.h"
|
||||
#include "base/callback.h"
|
||||
#include "content/public/browser/gpu_data_manager_observer.h"
|
||||
#include "native_mate/handle.h"
|
||||
|
||||
class GURL;
|
||||
|
||||
namespace base {
|
||||
class FilePath;
|
||||
}
|
||||
@@ -27,10 +25,9 @@ namespace atom {
|
||||
namespace api {
|
||||
|
||||
class App : public mate::EventEmitter,
|
||||
public BrowserObserver {
|
||||
public BrowserObserver,
|
||||
public content::GpuDataManagerObserver {
|
||||
public:
|
||||
typedef base::Callback<void(std::string)> ResolveProxyCallback;
|
||||
|
||||
static mate::Handle<App> Create(v8::Isolate* isolate);
|
||||
|
||||
protected:
|
||||
@@ -47,6 +44,13 @@ class App : public mate::EventEmitter,
|
||||
void OnActivateWithNoOpenWindows() override;
|
||||
void OnWillFinishLaunching() override;
|
||||
void OnFinishLaunching() override;
|
||||
void OnSelectCertificate(
|
||||
content::WebContents* web_contents,
|
||||
net::SSLCertRequestInfo* cert_request_info,
|
||||
scoped_ptr<content::ClientCertificateDelegate> delegate) override;
|
||||
|
||||
// content::GpuDataManagerObserver:
|
||||
void OnGpuProcessCrashed(base::TerminationStatus exit_code) override;
|
||||
|
||||
// mate::Wrappable:
|
||||
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
||||
@@ -59,9 +63,11 @@ class App : public mate::EventEmitter,
|
||||
const std::string& name,
|
||||
const base::FilePath& path);
|
||||
|
||||
void ResolveProxy(const GURL& url, ResolveProxyCallback callback);
|
||||
void SetDesktopName(const std::string& desktop_name);
|
||||
void SetAppUserModelId(const std::string& app_id);
|
||||
v8::Local<v8::Value> DefaultSession(v8::Isolate* isolate);
|
||||
|
||||
v8::Global<v8::Value> default_session_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(App);
|
||||
};
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "content/public/browser/tracing_controller.h"
|
||||
#include "native_mate/callback.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
@@ -46,6 +47,31 @@ struct Converter<base::trace_event::TraceOptions> {
|
||||
|
||||
namespace {
|
||||
|
||||
using CompletionCallback = base::Callback<void(const base::FilePath&)>;
|
||||
|
||||
scoped_refptr<TracingController::TraceDataSink> GetTraceDataSink(
|
||||
const base::FilePath& path, const CompletionCallback& callback) {
|
||||
base::FilePath result_file_path = path;
|
||||
if (result_file_path.empty() && !base::CreateTemporaryFile(&result_file_path))
|
||||
LOG(ERROR) << "Creating temporary file failed";
|
||||
|
||||
return TracingController::CreateFileSink(result_file_path,
|
||||
base::Bind(callback,
|
||||
result_file_path));
|
||||
}
|
||||
|
||||
void StopRecording(const base::FilePath& path,
|
||||
const CompletionCallback& callback) {
|
||||
TracingController::GetInstance()->DisableRecording(
|
||||
GetTraceDataSink(path, callback));
|
||||
}
|
||||
|
||||
void CaptureMonitoringSnapshot(const base::FilePath& path,
|
||||
const CompletionCallback& callback) {
|
||||
TracingController::GetInstance()->CaptureMonitoringSnapshot(
|
||||
GetTraceDataSink(path, callback));
|
||||
}
|
||||
|
||||
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
|
||||
v8::Local<v8::Context> context, void* priv) {
|
||||
auto controller = base::Unretained(TracingController::GetInstance());
|
||||
@@ -54,14 +80,12 @@ void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
|
||||
&TracingController::GetCategories, controller));
|
||||
dict.SetMethod("startRecording", base::Bind(
|
||||
&TracingController::EnableRecording, controller));
|
||||
dict.SetMethod("stopRecording", base::Bind(
|
||||
&TracingController::DisableRecording, controller, nullptr));
|
||||
dict.SetMethod("stopRecording", &StopRecording);
|
||||
dict.SetMethod("startMonitoring", base::Bind(
|
||||
&TracingController::EnableMonitoring, controller));
|
||||
dict.SetMethod("stopMonitoring", base::Bind(
|
||||
&TracingController::DisableMonitoring, controller));
|
||||
dict.SetMethod("captureMonitoringSnapshot", base::Bind(
|
||||
&TracingController::CaptureMonitoringSnapshot, controller, nullptr));
|
||||
dict.SetMethod("captureMonitoringSnapshot", &CaptureMonitoringSnapshot);
|
||||
dict.SetMethod("getTraceBufferUsage", base::Bind(
|
||||
&TracingController::GetTraceBufferUsage, controller));
|
||||
dict.SetMethod("setWatchEvent", base::Bind(
|
||||
|
||||
348
atom/browser/api/atom_api_cookies.cc
Normal file
348
atom/browser/api/atom_api_cookies.cc
Normal file
@@ -0,0 +1,348 @@
|
||||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/api/atom_api_cookies.h"
|
||||
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/gurl_converter.h"
|
||||
#include "atom/common/native_mate_converters/value_converter.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/values.h"
|
||||
#include "content/public/browser/browser_context.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/object_template_builder.h"
|
||||
#include "net/cookies/cookie_monster.h"
|
||||
#include "net/cookies/cookie_store.h"
|
||||
#include "net/cookies/cookie_util.h"
|
||||
#include "net/url_request/url_request_context.h"
|
||||
#include "net/url_request/url_request_context_getter.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
using atom::api::Cookies;
|
||||
using content::BrowserThread;
|
||||
|
||||
namespace {
|
||||
|
||||
bool GetCookieListFromStore(
|
||||
net::CookieStore* cookie_store,
|
||||
const std::string& url,
|
||||
const net::CookieMonster::GetCookieListCallback& callback) {
|
||||
DCHECK(cookie_store);
|
||||
GURL gurl(url);
|
||||
net::CookieMonster* monster = cookie_store->GetCookieMonster();
|
||||
// Empty url will match all url cookies.
|
||||
if (url.empty()) {
|
||||
monster->GetAllCookiesAsync(callback);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!gurl.is_valid())
|
||||
return false;
|
||||
|
||||
monster->GetAllCookiesForURLAsync(gurl, callback);
|
||||
return true;
|
||||
}
|
||||
|
||||
void RunGetCookiesCallbackOnUIThread(v8::Isolate* isolate,
|
||||
const std::string& error_message,
|
||||
const net::CookieList& cookie_list,
|
||||
const Cookies::CookiesCallback& callback) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
if (!error_message.empty()) {
|
||||
v8::Local<v8::Value> error = mate::ConvertToV8(isolate, error_message);
|
||||
callback.Run(error, v8::Null(isolate));
|
||||
return;
|
||||
}
|
||||
callback.Run(v8::Null(isolate), mate::ConvertToV8(isolate, cookie_list));
|
||||
}
|
||||
|
||||
void RunRemoveCookiesCallbackOnUIThread(
|
||||
v8::Isolate* isolate,
|
||||
const std::string& error_message,
|
||||
const Cookies::CookiesCallback& callback) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
if (!error_message.empty()) {
|
||||
v8::Local<v8::Value> error = mate::ConvertToV8(isolate, error_message);
|
||||
callback.Run(error, v8::Null(isolate));
|
||||
return;
|
||||
}
|
||||
|
||||
callback.Run(v8::Null(isolate), v8::Null(isolate));
|
||||
}
|
||||
|
||||
void RunSetCookiesCallbackOnUIThread(v8::Isolate* isolate,
|
||||
const std::string& error_message,
|
||||
bool set_success,
|
||||
const Cookies::CookiesCallback& callback) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
if (!error_message.empty()) {
|
||||
v8::Local<v8::Value> error = mate::ConvertToV8(isolate, error_message);
|
||||
callback.Run(error, v8::Null(isolate));
|
||||
return;
|
||||
}
|
||||
if (!set_success) {
|
||||
v8::Local<v8::Value> error = mate::ConvertToV8(
|
||||
isolate, "Failed to set cookies");
|
||||
callback.Run(error, v8::Null(isolate));
|
||||
}
|
||||
|
||||
callback.Run(v8::Null(isolate), v8::Null(isolate));
|
||||
}
|
||||
|
||||
bool MatchesDomain(const base::DictionaryValue* filter,
|
||||
const std::string& cookie_domain) {
|
||||
std::string filter_domain;
|
||||
if (!filter->GetString("domain", &filter_domain))
|
||||
return true;
|
||||
|
||||
// Add a leading '.' character to the filter domain if it doesn't exist.
|
||||
if (net::cookie_util::DomainIsHostOnly(filter_domain))
|
||||
filter_domain.insert(0, ".");
|
||||
|
||||
std::string sub_domain(cookie_domain);
|
||||
// Strip any leading '.' character from the input cookie domain.
|
||||
if (!net::cookie_util::DomainIsHostOnly(sub_domain))
|
||||
sub_domain = sub_domain.substr(1);
|
||||
|
||||
// Now check whether the domain argument is a subdomain of the filter domain.
|
||||
for (sub_domain.insert(0, ".");
|
||||
sub_domain.length() >= filter_domain.length();) {
|
||||
if (sub_domain == filter_domain) {
|
||||
return true;
|
||||
}
|
||||
const size_t next_dot = sub_domain.find('.', 1); // Skip over leading dot.
|
||||
sub_domain.erase(0, next_dot);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MatchesCookie(const base::DictionaryValue* filter,
|
||||
const net::CanonicalCookie& cookie) {
|
||||
std::string name, domain, path;
|
||||
bool is_secure, session;
|
||||
if (filter->GetString("name", &name) && name != cookie.Name())
|
||||
return false;
|
||||
if (filter->GetString("path", &path) && path != cookie.Path())
|
||||
return false;
|
||||
if (!MatchesDomain(filter, cookie.Domain()))
|
||||
return false;
|
||||
if (filter->GetBoolean("secure", &is_secure) &&
|
||||
is_secure != cookie.IsSecure())
|
||||
return false;
|
||||
if (filter->GetBoolean("session", &session) &&
|
||||
session != cookie.IsPersistent())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace mate {
|
||||
|
||||
template<>
|
||||
struct Converter<net::CanonicalCookie> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const net::CanonicalCookie& val) {
|
||||
mate::Dictionary dict(isolate, v8::Object::New(isolate));
|
||||
dict.Set("name", val.Name());
|
||||
dict.Set("value", val.Value());
|
||||
dict.Set("domain", val.Domain());
|
||||
dict.Set("host_only", net::cookie_util::DomainIsHostOnly(val.Domain()));
|
||||
dict.Set("path", val.Path());
|
||||
dict.Set("secure", val.IsSecure());
|
||||
dict.Set("http_only", val.IsHttpOnly());
|
||||
dict.Set("session", val.IsPersistent());
|
||||
if (!val.IsPersistent())
|
||||
dict.Set("expirationDate", val.ExpiryDate().ToDoubleT());
|
||||
return dict.GetHandle();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
Cookies::Cookies(content::BrowserContext* browser_context)
|
||||
: request_context_getter_(browser_context->GetRequestContext()) {
|
||||
}
|
||||
|
||||
Cookies::~Cookies() {
|
||||
}
|
||||
|
||||
void Cookies::Get(const base::DictionaryValue& options,
|
||||
const CookiesCallback& callback) {
|
||||
scoped_ptr<base::DictionaryValue> filter(
|
||||
options.DeepCopyWithoutEmptyChildren());
|
||||
|
||||
content::BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&Cookies::GetCookiesOnIOThread, base::Unretained(this),
|
||||
Passed(&filter), callback));
|
||||
}
|
||||
|
||||
void Cookies::GetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> filter,
|
||||
const CookiesCallback& callback) {
|
||||
std::string url;
|
||||
filter->GetString("url", &url);
|
||||
if (!GetCookieListFromStore(GetCookieStore(), url,
|
||||
base::Bind(&Cookies::OnGetCookies, base::Unretained(this),
|
||||
Passed(&filter), callback))) {
|
||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(&RunGetCookiesCallbackOnUIThread, isolate(),
|
||||
"Url is not valid", net::CookieList(), callback));
|
||||
}
|
||||
}
|
||||
|
||||
void Cookies::OnGetCookies(scoped_ptr<base::DictionaryValue> filter,
|
||||
const CookiesCallback& callback,
|
||||
const net::CookieList& cookie_list) {
|
||||
net::CookieList result;
|
||||
for (const auto& cookie : cookie_list) {
|
||||
if (MatchesCookie(filter.get(), cookie))
|
||||
result.push_back(cookie);
|
||||
}
|
||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
|
||||
&RunGetCookiesCallbackOnUIThread, isolate(), "", result, callback));
|
||||
}
|
||||
|
||||
void Cookies::Remove(const mate::Dictionary& details,
|
||||
const CookiesCallback& callback) {
|
||||
GURL url;
|
||||
std::string name;
|
||||
std::string error_message;
|
||||
if (!details.Get("url", &url) || !details.Get("name", &name)) {
|
||||
error_message = "Details(url, name) of removing cookie are required.";
|
||||
}
|
||||
if (error_message.empty() && !url.is_valid()) {
|
||||
error_message = "Url is not valid.";
|
||||
}
|
||||
if (!error_message.empty()) {
|
||||
RunRemoveCookiesCallbackOnUIThread(isolate(), error_message, callback);
|
||||
return;
|
||||
}
|
||||
content::BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&Cookies::RemoveCookiesOnIOThread, base::Unretained(this),
|
||||
url, name, callback));
|
||||
}
|
||||
|
||||
void Cookies::RemoveCookiesOnIOThread(const GURL& url, const std::string& name,
|
||||
const CookiesCallback& callback) {
|
||||
GetCookieStore()->DeleteCookieAsync(url, name,
|
||||
base::Bind(&Cookies::OnRemoveCookies, base::Unretained(this), callback));
|
||||
}
|
||||
|
||||
void Cookies::OnRemoveCookies(const CookiesCallback& callback) {
|
||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(&RunRemoveCookiesCallbackOnUIThread, isolate(), "", callback));
|
||||
}
|
||||
|
||||
void Cookies::Set(const base::DictionaryValue& options,
|
||||
const CookiesCallback& callback) {
|
||||
std::string url;
|
||||
std::string error_message;
|
||||
if (!options.GetString("url", &url)) {
|
||||
error_message = "The url field is required.";
|
||||
}
|
||||
|
||||
GURL gurl(url);
|
||||
if (error_message.empty() && !gurl.is_valid()) {
|
||||
error_message = "Url is not valid.";
|
||||
}
|
||||
|
||||
if (!error_message.empty()) {
|
||||
RunSetCookiesCallbackOnUIThread(isolate(), error_message, false, callback);
|
||||
return;
|
||||
}
|
||||
|
||||
scoped_ptr<base::DictionaryValue> details(
|
||||
options.DeepCopyWithoutEmptyChildren());
|
||||
|
||||
content::BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&Cookies::SetCookiesOnIOThread, base::Unretained(this),
|
||||
Passed(&details), gurl, callback));
|
||||
}
|
||||
|
||||
void Cookies::SetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> details,
|
||||
const GURL& url,
|
||||
const CookiesCallback& callback) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
|
||||
std::string name, value, domain, path;
|
||||
bool secure = false;
|
||||
bool http_only = false;
|
||||
double expiration_date;
|
||||
|
||||
details->GetString("name", &name);
|
||||
details->GetString("value", &value);
|
||||
details->GetString("domain", &domain);
|
||||
details->GetString("path", &path);
|
||||
details->GetBoolean("secure", &secure);
|
||||
details->GetBoolean("http_only", &http_only);
|
||||
|
||||
base::Time expiration_time;
|
||||
if (details->GetDouble("expirationDate", &expiration_date)) {
|
||||
expiration_time = (expiration_date == 0) ?
|
||||
base::Time::UnixEpoch() :
|
||||
base::Time::FromDoubleT(expiration_date);
|
||||
}
|
||||
|
||||
GetCookieStore()->GetCookieMonster()->SetCookieWithDetailsAsync(
|
||||
url,
|
||||
name,
|
||||
value,
|
||||
domain,
|
||||
path,
|
||||
expiration_time,
|
||||
secure,
|
||||
http_only,
|
||||
false,
|
||||
net::COOKIE_PRIORITY_DEFAULT,
|
||||
base::Bind(&Cookies::OnSetCookies, base::Unretained(this), callback));
|
||||
}
|
||||
|
||||
void Cookies::OnSetCookies(const CookiesCallback& callback,
|
||||
bool set_success) {
|
||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(&RunSetCookiesCallbackOnUIThread, isolate(), "", set_success,
|
||||
callback));
|
||||
}
|
||||
|
||||
mate::ObjectTemplateBuilder Cookies::GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) {
|
||||
return mate::ObjectTemplateBuilder(isolate)
|
||||
.SetMethod("get", &Cookies::Get)
|
||||
.SetMethod("remove", &Cookies::Remove)
|
||||
.SetMethod("set", &Cookies::Set);
|
||||
}
|
||||
|
||||
net::CookieStore* Cookies::GetCookieStore() {
|
||||
return request_context_getter_->GetURLRequestContext()->cookie_store();
|
||||
}
|
||||
|
||||
// static
|
||||
mate::Handle<Cookies> Cookies::Create(
|
||||
v8::Isolate* isolate,
|
||||
content::BrowserContext* browser_context) {
|
||||
return mate::CreateHandle(isolate, new Cookies(browser_context));
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
||||
90
atom/browser/api/atom_api_cookies.h
Normal file
90
atom/browser/api/atom_api_cookies.h
Normal file
@@ -0,0 +1,90 @@
|
||||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_API_ATOM_API_COOKIES_H_
|
||||
#define ATOM_BROWSER_API_ATOM_API_COOKIES_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "native_mate/wrappable.h"
|
||||
#include "native_mate/handle.h"
|
||||
#include "net/cookies/canonical_cookie.h"
|
||||
|
||||
namespace base {
|
||||
class DictionaryValue;
|
||||
}
|
||||
|
||||
namespace content {
|
||||
class BrowserContext;
|
||||
}
|
||||
|
||||
namespace mate {
|
||||
class Dictionary;
|
||||
}
|
||||
|
||||
namespace net {
|
||||
class CookieStore;
|
||||
class URLRequestContextGetter;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
class Cookies : public mate::Wrappable {
|
||||
public:
|
||||
// node.js style callback function(error, result)
|
||||
typedef base::Callback<void(v8::Local<v8::Value>, v8::Local<v8::Value>)>
|
||||
CookiesCallback;
|
||||
|
||||
static mate::Handle<Cookies> Create(v8::Isolate* isolate,
|
||||
content::BrowserContext* browser_context);
|
||||
|
||||
protected:
|
||||
explicit Cookies(content::BrowserContext* browser_context);
|
||||
~Cookies();
|
||||
|
||||
void Get(const base::DictionaryValue& options,
|
||||
const CookiesCallback& callback);
|
||||
void Remove(const mate::Dictionary& details,
|
||||
const CookiesCallback& callback);
|
||||
void Set(const base::DictionaryValue& details,
|
||||
const CookiesCallback& callback);
|
||||
|
||||
void GetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> filter,
|
||||
const CookiesCallback& callback);
|
||||
void OnGetCookies(scoped_ptr<base::DictionaryValue> filter,
|
||||
const CookiesCallback& callback,
|
||||
const net::CookieList& cookie_list);
|
||||
|
||||
void RemoveCookiesOnIOThread(const GURL& url,
|
||||
const std::string& name,
|
||||
const CookiesCallback& callback);
|
||||
void OnRemoveCookies(const CookiesCallback& callback);
|
||||
|
||||
void SetCookiesOnIOThread(scoped_ptr<base::DictionaryValue> details,
|
||||
const GURL& url,
|
||||
const CookiesCallback& callback);
|
||||
void OnSetCookies(const CookiesCallback& callback,
|
||||
bool set_success);
|
||||
|
||||
// mate::Wrappable:
|
||||
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) override;
|
||||
|
||||
private:
|
||||
// Must be called on IO thread.
|
||||
net::CookieStore* GetCookieStore();
|
||||
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Cookies);
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_API_ATOM_API_COOKIES_H_
|
||||
@@ -10,9 +10,9 @@
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/ui/file_dialog.h"
|
||||
#include "atom/browser/ui/message_box.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "atom/common/native_mate_converters/image_converter.h"
|
||||
#include "native_mate/callback.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
@@ -41,27 +41,25 @@ namespace {
|
||||
|
||||
void ShowMessageBox(int type,
|
||||
const std::vector<std::string>& buttons,
|
||||
const std::vector<std::string>& texts,
|
||||
int cancel_id,
|
||||
int options,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
const gfx::ImageSkia& icon,
|
||||
atom::NativeWindow* window,
|
||||
mate::Arguments* args) {
|
||||
// FIXME We are exceeding the parameters limit of base::Bind here, so we have
|
||||
// to pass some parameters in an array. We should remove this once we have
|
||||
// variadic template support in base::Bind.
|
||||
const std::string& title = texts[0];
|
||||
const std::string& message = texts[1];
|
||||
const std::string& detail = texts[2];
|
||||
|
||||
v8::Local<v8::Value> peek = args->PeekNext();
|
||||
atom::MessageBoxCallback callback;
|
||||
if (mate::Converter<atom::MessageBoxCallback>::FromV8(args->isolate(),
|
||||
peek,
|
||||
&callback)) {
|
||||
atom::ShowMessageBox(window, (atom::MessageBoxType)type, buttons, title,
|
||||
message, detail, icon, callback);
|
||||
atom::ShowMessageBox(window, (atom::MessageBoxType)type, buttons, cancel_id,
|
||||
options, title, message, detail, icon, callback);
|
||||
} else {
|
||||
int chosen = atom::ShowMessageBox(window, (atom::MessageBoxType)type,
|
||||
buttons, title, message, detail, icon);
|
||||
buttons, cancel_id, options, title,
|
||||
message, detail, icon);
|
||||
args->Return(chosen);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
#include <string>
|
||||
|
||||
#include "atom/common/native_mate_converters/accelerator_converter.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "native_mate/callback.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/common/native_mate_converters/accelerator_converter.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/image_converter.h"
|
||||
#include "atom/common/native_mate_converters/string16_converter.h"
|
||||
#include "native_mate/callback.h"
|
||||
#include "native_mate/constructor.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/object_template_builder.h"
|
||||
@@ -20,7 +20,7 @@ namespace atom {
|
||||
namespace api {
|
||||
|
||||
Menu::Menu()
|
||||
: model_(new ui::SimpleMenuModel(this)),
|
||||
: model_(new AtomMenuModel(this)),
|
||||
parent_(NULL) {
|
||||
}
|
||||
|
||||
@@ -55,11 +55,10 @@ bool Menu::IsCommandIdVisible(int command_id) const {
|
||||
|
||||
bool Menu::GetAcceleratorForCommandId(int command_id,
|
||||
ui::Accelerator* accelerator) {
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
v8::Local<v8::Value> val = get_accelerator_.Run(command_id);
|
||||
return mate::ConvertFromV8(isolate, val, accelerator);
|
||||
return mate::ConvertFromV8(isolate(), val, accelerator);
|
||||
}
|
||||
|
||||
void Menu::ExecuteCommand(int command_id, int event_flags) {
|
||||
@@ -70,10 +69,6 @@ void Menu::MenuWillShow(ui::SimpleMenuModel* source) {
|
||||
menu_will_show_.Run();
|
||||
}
|
||||
|
||||
void Menu::AttachToWindow(Window* window) {
|
||||
window->window()->SetMenu(model_.get());
|
||||
}
|
||||
|
||||
void Menu::InsertItemAt(
|
||||
int index, int command_id, const base::string16& label) {
|
||||
model_->InsertItemAt(index, command_id, label);
|
||||
@@ -168,7 +163,6 @@ void Menu::BuildPrototype(v8::Isolate* isolate,
|
||||
.SetMethod("isItemCheckedAt", &Menu::IsItemCheckedAt)
|
||||
.SetMethod("isEnabledAt", &Menu::IsEnabledAt)
|
||||
.SetMethod("isVisibleAt", &Menu::IsVisibleAt)
|
||||
.SetMethod("attachToWindow", &Menu::AttachToWindow)
|
||||
.SetMethod("_popup", &Menu::Popup)
|
||||
.SetMethod("_popupAt", &Menu::PopupAt);
|
||||
}
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/api/atom_api_window.h"
|
||||
#include "atom/browser/ui/atom_menu_model.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "ui/base/models/simple_menu_model.h"
|
||||
#include "native_mate/wrappable.h"
|
||||
|
||||
namespace atom {
|
||||
@@ -18,7 +18,7 @@ namespace atom {
|
||||
namespace api {
|
||||
|
||||
class Menu : public mate::Wrappable,
|
||||
public ui::SimpleMenuModel::Delegate {
|
||||
public AtomMenuModel::Delegate {
|
||||
public:
|
||||
static mate::Wrappable* Create();
|
||||
|
||||
@@ -33,7 +33,7 @@ class Menu : public mate::Wrappable,
|
||||
static void SendActionToFirstResponder(const std::string& action);
|
||||
#endif
|
||||
|
||||
ui::SimpleMenuModel* model() const { return model_.get(); }
|
||||
AtomMenuModel* model() const { return model_.get(); }
|
||||
|
||||
protected:
|
||||
Menu();
|
||||
@@ -42,7 +42,7 @@ class Menu : public mate::Wrappable,
|
||||
// mate::Wrappable:
|
||||
void AfterInit(v8::Isolate* isolate) override;
|
||||
|
||||
// ui::SimpleMenuModel::Delegate implementations:
|
||||
// ui::SimpleMenuModel::Delegate:
|
||||
bool IsCommandIdChecked(int command_id) const override;
|
||||
bool IsCommandIdEnabled(int command_id) const override;
|
||||
bool IsCommandIdVisible(int command_id) const override;
|
||||
@@ -51,11 +51,10 @@ class Menu : public mate::Wrappable,
|
||||
void ExecuteCommand(int command_id, int event_flags) override;
|
||||
void MenuWillShow(ui::SimpleMenuModel* source) override;
|
||||
|
||||
virtual void AttachToWindow(Window* window);
|
||||
virtual void Popup(Window* window) = 0;
|
||||
virtual void PopupAt(Window* window, int x, int y) = 0;
|
||||
|
||||
scoped_ptr<ui::SimpleMenuModel> model_;
|
||||
scoped_ptr<AtomMenuModel> model_;
|
||||
Menu* parent_;
|
||||
|
||||
private:
|
||||
@@ -99,4 +98,27 @@ class Menu : public mate::Wrappable,
|
||||
|
||||
} // namespace atom
|
||||
|
||||
|
||||
namespace mate {
|
||||
|
||||
template<>
|
||||
struct Converter<atom::AtomMenuModel*> {
|
||||
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
|
||||
atom::AtomMenuModel** out) {
|
||||
// null would be tranfered to NULL.
|
||||
if (val->IsNull()) {
|
||||
*out = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
atom::api::Menu* menu;
|
||||
if (!Converter<atom::api::Menu*>::FromV8(isolate, val, &menu))
|
||||
return false;
|
||||
*out = menu->model();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
#endif // ATOM_BROWSER_API_ATOM_API_MENU_H_
|
||||
|
||||
@@ -22,7 +22,7 @@ void MenuMac::Popup(Window* window) {
|
||||
NativeWindow* native_window = window->window();
|
||||
if (!native_window)
|
||||
return;
|
||||
content::WebContents* web_contents = native_window->GetWebContents();
|
||||
content::WebContents* web_contents = native_window->web_contents();
|
||||
if (!web_contents)
|
||||
return;
|
||||
|
||||
@@ -54,7 +54,7 @@ void MenuMac::PopupAt(Window* window, int x, int y) {
|
||||
NativeWindow* native_window = window->window();
|
||||
if (!native_window)
|
||||
return;
|
||||
content::WebContents* web_contents = native_window->GetWebContents();
|
||||
content::WebContents* web_contents = native_window->web_contents();
|
||||
if (!web_contents)
|
||||
return;
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ void MenuViews::PopupAt(Window* window, int x, int y) {
|
||||
NativeWindow* native_window = static_cast<NativeWindow*>(window->window());
|
||||
if (!native_window)
|
||||
return;
|
||||
content::WebContents* web_contents = native_window->GetWebContents();
|
||||
content::WebContents* web_contents = native_window->web_contents();
|
||||
if (!web_contents)
|
||||
return;
|
||||
content::RenderWidgetHostView* view = web_contents->GetRenderWidgetHostView();
|
||||
|
||||
@@ -41,8 +41,9 @@ void PowerMonitor::OnResume() {
|
||||
// static
|
||||
v8::Local<v8::Value> PowerMonitor::Create(v8::Isolate* isolate) {
|
||||
if (!Browser::Get()->is_ready()) {
|
||||
node::ThrowError("Cannot initialize \"power-monitor\" module"
|
||||
"before app is ready");
|
||||
node::ThrowError(
|
||||
isolate,
|
||||
"Cannot initialize \"power-monitor\" module before app is ready");
|
||||
return v8::Null(isolate);
|
||||
}
|
||||
|
||||
|
||||
128
atom/browser/api/atom_api_power_save_blocker.cc
Normal file
128
atom/browser/api/atom_api_power_save_blocker.cc
Normal file
@@ -0,0 +1,128 @@
|
||||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/api/atom_api_power_save_blocker.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "content/public/browser/power_save_blocker.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
template<>
|
||||
struct Converter<content::PowerSaveBlocker::PowerSaveBlockerType> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
content::PowerSaveBlocker::PowerSaveBlockerType* out) {
|
||||
using content::PowerSaveBlocker;
|
||||
std::string type;
|
||||
if (!ConvertFromV8(isolate, val, &type))
|
||||
return false;
|
||||
if (type == "prevent-app-suspension")
|
||||
*out = PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension;
|
||||
else if (type == "prevent-display-sleep")
|
||||
*out = PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep;
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
PowerSaveBlocker::PowerSaveBlocker()
|
||||
: current_blocker_type_(
|
||||
content::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension) {
|
||||
}
|
||||
|
||||
PowerSaveBlocker::~PowerSaveBlocker() {
|
||||
}
|
||||
|
||||
void PowerSaveBlocker::UpdatePowerSaveBlocker() {
|
||||
if (power_save_blocker_types_.empty()) {
|
||||
power_save_blocker_.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
// |kPowerSaveBlockPreventAppSuspension| keeps system active, but allows
|
||||
// screen to be turned off.
|
||||
// |kPowerSaveBlockPreventDisplaySleep| keeps system and screen active, has a
|
||||
// higher precedence level than |kPowerSaveBlockPreventAppSuspension|.
|
||||
//
|
||||
// Only the highest-precedence blocker type takes effect.
|
||||
content::PowerSaveBlocker::PowerSaveBlockerType new_blocker_type =
|
||||
content::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension;
|
||||
for (const auto& element : power_save_blocker_types_) {
|
||||
if (element.second ==
|
||||
content::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep) {
|
||||
new_blocker_type =
|
||||
content::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!power_save_blocker_ || new_blocker_type != current_blocker_type_) {
|
||||
scoped_ptr<content::PowerSaveBlocker> new_blocker =
|
||||
content::PowerSaveBlocker::Create(
|
||||
new_blocker_type,
|
||||
content::PowerSaveBlocker::kReasonOther,
|
||||
ATOM_PRODUCT_NAME);
|
||||
power_save_blocker_.swap(new_blocker);
|
||||
current_blocker_type_ = new_blocker_type;
|
||||
}
|
||||
}
|
||||
|
||||
int PowerSaveBlocker::Start(
|
||||
content::PowerSaveBlocker::PowerSaveBlockerType type) {
|
||||
static int count = 0;
|
||||
power_save_blocker_types_[count] = type;
|
||||
UpdatePowerSaveBlocker();
|
||||
return count++;
|
||||
}
|
||||
|
||||
bool PowerSaveBlocker::Stop(int id) {
|
||||
bool success = power_save_blocker_types_.erase(id) > 0;
|
||||
UpdatePowerSaveBlocker();
|
||||
return success;
|
||||
}
|
||||
|
||||
bool PowerSaveBlocker::IsStarted(int id) {
|
||||
return power_save_blocker_types_.find(id) != power_save_blocker_types_.end();
|
||||
}
|
||||
|
||||
mate::ObjectTemplateBuilder PowerSaveBlocker::GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) {
|
||||
return mate::ObjectTemplateBuilder(isolate)
|
||||
.SetMethod("start", &PowerSaveBlocker::Start)
|
||||
.SetMethod("stop", &PowerSaveBlocker::Stop)
|
||||
.SetMethod("isStarted", &PowerSaveBlocker::IsStarted);
|
||||
}
|
||||
|
||||
// static
|
||||
mate::Handle<PowerSaveBlocker> PowerSaveBlocker::Create(v8::Isolate* isolate) {
|
||||
return CreateHandle(isolate, new PowerSaveBlocker);
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
||||
|
||||
namespace {
|
||||
|
||||
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
|
||||
v8::Local<v8::Context> context, void* priv) {
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
mate::Dictionary dict(isolate, exports);
|
||||
dict.Set("powerSaveBlocker", atom::api::PowerSaveBlocker::Create(isolate));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_power_save_blocker, Initialize);
|
||||
59
atom/browser/api/atom_api_power_save_blocker.h
Normal file
59
atom/browser/api/atom_api_power_save_blocker.h
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_API_ATOM_API_POWER_SAVE_BLOCKER_H_
|
||||
#define ATOM_BROWSER_API_ATOM_API_POWER_SAVE_BLOCKER_H_
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "content/public/browser/power_save_blocker.h"
|
||||
#include "native_mate/handle.h"
|
||||
#include "native_mate/wrappable.h"
|
||||
|
||||
namespace mate {
|
||||
class Dictionary;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
class PowerSaveBlocker : public mate::Wrappable {
|
||||
public:
|
||||
static mate::Handle<PowerSaveBlocker> Create(v8::Isolate* isolate);
|
||||
|
||||
protected:
|
||||
PowerSaveBlocker();
|
||||
virtual ~PowerSaveBlocker();
|
||||
|
||||
// mate::Wrappable implementations:
|
||||
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) override;
|
||||
|
||||
private:
|
||||
void UpdatePowerSaveBlocker();
|
||||
int Start(content::PowerSaveBlocker::PowerSaveBlockerType type);
|
||||
bool Stop(int id);
|
||||
bool IsStarted(int id);
|
||||
|
||||
scoped_ptr<content::PowerSaveBlocker> power_save_blocker_;
|
||||
|
||||
// Currnet blocker type used by |power_save_blocker_|
|
||||
content::PowerSaveBlocker::PowerSaveBlockerType current_blocker_type_;
|
||||
|
||||
// Map from id to the corresponding blocker type for each request.
|
||||
using PowerSaveBlockerTypeMap =
|
||||
std::map<int, content::PowerSaveBlocker::PowerSaveBlockerType>;
|
||||
PowerSaveBlockerTypeMap power_save_blocker_types_;
|
||||
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(PowerSaveBlocker);
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_API_ATOM_API_POWER_SAVE_BLOCKER_H_
|
||||
@@ -4,12 +4,16 @@
|
||||
|
||||
#include "atom/browser/api/atom_api_protocol.h"
|
||||
|
||||
#include "atom/browser/atom_browser_client.h"
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/atom_browser_main_parts.h"
|
||||
#include "atom/browser/api/atom_api_session.h"
|
||||
#include "atom/browser/net/adapter_request_job.h"
|
||||
#include "atom/browser/net/atom_url_request_job_factory.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "atom/common/native_mate_converters/gurl_converter.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "native_mate/callback.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "net/url_request/url_request_context.h"
|
||||
|
||||
@@ -22,7 +26,7 @@ namespace mate {
|
||||
template<>
|
||||
struct Converter<const net::URLRequest*> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
const net::URLRequest* val) {
|
||||
const net::URLRequest* val) {
|
||||
return mate::ObjectTemplateBuilder(isolate)
|
||||
.SetValue("method", val->method())
|
||||
.SetValue("url", val->url().spec())
|
||||
@@ -33,7 +37,6 @@ struct Converter<const net::URLRequest*> {
|
||||
|
||||
} // namespace mate
|
||||
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
@@ -60,17 +63,13 @@ class CustomProtocolRequestJob : public AdapterRequestJob {
|
||||
registry_(registry) {
|
||||
}
|
||||
|
||||
// AdapterRequestJob:
|
||||
void GetJobTypeInUI() override {
|
||||
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
||||
void GetJobTypeInUI(const Protocol::JsProtocolHandler& callback) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Locker locker(registry_->isolate());
|
||||
v8::HandleScope handle_scope(registry_->isolate());
|
||||
|
||||
// Call the JS handler.
|
||||
Protocol::JsProtocolHandler callback =
|
||||
registry_->GetProtocolHandler(request()->url().scheme());
|
||||
v8::Local<v8::Value> result = callback.Run(request());
|
||||
|
||||
// Determine the type of the job we are going to create.
|
||||
@@ -82,7 +81,7 @@ class CustomProtocolRequestJob : public AdapterRequestJob {
|
||||
return;
|
||||
} else if (result->IsObject()) {
|
||||
v8::Local<v8::Object> obj = result->ToObject();
|
||||
mate::Dictionary dict(isolate, obj);
|
||||
mate::Dictionary dict(registry_->isolate(), obj);
|
||||
std::string name = mate::V8ToString(obj->GetConstructorName());
|
||||
if (name == "RequestStringJob") {
|
||||
std::string mime_type, charset, data;
|
||||
@@ -115,14 +114,38 @@ class CustomProtocolRequestJob : public AdapterRequestJob {
|
||||
GetWeakPtr(), path));
|
||||
return;
|
||||
} else if (name == "RequestErrorJob") {
|
||||
// Default value net::ERR_NOT_IMPLEMENTED
|
||||
int error = -11;
|
||||
int error = net::ERR_NOT_IMPLEMENTED;
|
||||
dict.Get("error", &error);
|
||||
|
||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&AdapterRequestJob::CreateErrorJobAndStart,
|
||||
GetWeakPtr(), error));
|
||||
return;
|
||||
} else if (name == "RequestHttpJob") {
|
||||
GURL url;
|
||||
std::string method, referrer;
|
||||
dict.Get("url", &url);
|
||||
dict.Get("method", &method);
|
||||
dict.Get("referrer", &referrer);
|
||||
|
||||
v8::Local<v8::Value> value;
|
||||
mate::Handle<Session> session;
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter;
|
||||
// "session" null -> pass nullptr;
|
||||
// "session" a Session object -> use passed session.
|
||||
// "session" undefined -> use current session;
|
||||
if (dict.Get("session", &session))
|
||||
request_context_getter =
|
||||
session->browser_context()->GetRequestContext();
|
||||
else if (dict.Get("session", &value) && value->IsNull())
|
||||
request_context_getter = nullptr;
|
||||
else
|
||||
request_context_getter = registry_->request_context_getter();
|
||||
|
||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&AdapterRequestJob::CreateHttpJobAndStart, GetWeakPtr(),
|
||||
request_context_getter, url, method, referrer));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,6 +163,14 @@ class CustomProtocolRequestJob : public AdapterRequestJob {
|
||||
GetWeakPtr(), net::ERR_NOT_IMPLEMENTED));
|
||||
}
|
||||
|
||||
// AdapterRequestJob:
|
||||
void GetJobType() override {
|
||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(&CustomProtocolRequestJob::GetJobTypeInUI,
|
||||
base::Unretained(this),
|
||||
registry_->GetProtocolHandler(request()->url().scheme())));
|
||||
}
|
||||
|
||||
private:
|
||||
Protocol* registry_; // Weak, the Protocol class is expected to live forever.
|
||||
};
|
||||
@@ -177,10 +208,31 @@ class CustomProtocolHandler : public ProtocolHandler {
|
||||
DISALLOW_COPY_AND_ASSIGN(CustomProtocolHandler);
|
||||
};
|
||||
|
||||
std::string ConvertErrorCode(int error_code) {
|
||||
switch (error_code) {
|
||||
case Protocol::ERR_SCHEME_REGISTERED:
|
||||
return "The Scheme is already registered";
|
||||
case Protocol::ERR_SCHEME_UNREGISTERED:
|
||||
return "The Scheme has not been registered";
|
||||
case Protocol::ERR_SCHEME_INTERCEPTED:
|
||||
return "There is no protocol handler to intercept";
|
||||
case Protocol::ERR_SCHEME_UNINTERCEPTED:
|
||||
return "The protocol is not intercepted";
|
||||
case Protocol::ERR_NO_SCHEME:
|
||||
return "The Scheme does not exist.";
|
||||
case Protocol::ERR_SCHEME:
|
||||
return "Cannot intercept custom protocols";
|
||||
default:
|
||||
NOTREACHED();
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Protocol::Protocol()
|
||||
: job_factory_(AtomBrowserContext::Get()->job_factory()) {
|
||||
Protocol::Protocol(AtomBrowserContext* browser_context)
|
||||
: request_context_getter_(browser_context->GetRequestContext()),
|
||||
job_factory_(browser_context->job_factory()) {
|
||||
CHECK(job_factory_);
|
||||
}
|
||||
|
||||
@@ -189,157 +241,168 @@ Protocol::JsProtocolHandler Protocol::GetProtocolHandler(
|
||||
return protocol_handlers_[scheme];
|
||||
}
|
||||
|
||||
void Protocol::OnIOActionCompleted(const JsCompletionCallback& callback,
|
||||
int error) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
|
||||
if (error) {
|
||||
callback.Run(v8::Exception::Error(
|
||||
mate::StringToV8(isolate(), ConvertErrorCode(error))));
|
||||
return;
|
||||
}
|
||||
|
||||
callback.Run(v8::Null(isolate()));
|
||||
}
|
||||
|
||||
mate::ObjectTemplateBuilder Protocol::GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) {
|
||||
return mate::ObjectTemplateBuilder(isolate)
|
||||
.SetMethod("registerProtocol",
|
||||
base::Bind(&Protocol::RegisterProtocol,
|
||||
base::Unretained(this)))
|
||||
.SetMethod("unregisterProtocol",
|
||||
base::Bind(&Protocol::UnregisterProtocol,
|
||||
base::Unretained(this)))
|
||||
.SetMethod("isHandledProtocol",
|
||||
base::Bind(&Protocol::IsHandledProtocol,
|
||||
base::Unretained(this)))
|
||||
.SetMethod("interceptProtocol",
|
||||
base::Bind(&Protocol::InterceptProtocol,
|
||||
base::Unretained(this)))
|
||||
.SetMethod("uninterceptProtocol",
|
||||
base::Bind(&Protocol::UninterceptProtocol,
|
||||
base::Unretained(this)));
|
||||
.SetMethod("registerStandardSchemes", &Protocol::RegisterStandardSchemes)
|
||||
.SetMethod("isHandledProtocol", &Protocol::IsHandledProtocol)
|
||||
.SetMethod("_registerProtocol", &Protocol::RegisterProtocol)
|
||||
.SetMethod("_unregisterProtocol", &Protocol::UnregisterProtocol)
|
||||
.SetMethod("_interceptProtocol", &Protocol::InterceptProtocol)
|
||||
.SetMethod("_uninterceptProtocol", &Protocol::UninterceptProtocol);
|
||||
}
|
||||
|
||||
void Protocol::RegisterProtocol(const std::string& scheme,
|
||||
const JsProtocolHandler& callback) {
|
||||
void Protocol::RegisterStandardSchemes(
|
||||
const std::vector<std::string>& schemes) {
|
||||
atom::AtomBrowserClient::SetCustomSchemes(schemes);
|
||||
}
|
||||
|
||||
void Protocol::IsHandledProtocol(const std::string& scheme,
|
||||
const net::CompletionCallback& callback) {
|
||||
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&AtomURLRequestJobFactory::IsHandledProtocol,
|
||||
base::Unretained(job_factory_), scheme),
|
||||
callback);
|
||||
}
|
||||
|
||||
void Protocol::RegisterProtocol(v8::Isolate* isolate,
|
||||
const std::string& scheme,
|
||||
const JsProtocolHandler& handler,
|
||||
const JsCompletionCallback& callback) {
|
||||
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&Protocol::RegisterProtocolInIO,
|
||||
base::Unretained(this), scheme, handler),
|
||||
base::Bind(&Protocol::OnIOActionCompleted,
|
||||
base::Unretained(this), callback));
|
||||
}
|
||||
|
||||
void Protocol::UnregisterProtocol(v8::Isolate* isolate,
|
||||
const std::string& scheme,
|
||||
const JsCompletionCallback& callback) {
|
||||
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&Protocol::UnregisterProtocolInIO,
|
||||
base::Unretained(this), scheme),
|
||||
base::Bind(&Protocol::OnIOActionCompleted,
|
||||
base::Unretained(this), callback));
|
||||
}
|
||||
|
||||
void Protocol::InterceptProtocol(v8::Isolate* isolate,
|
||||
const std::string& scheme,
|
||||
const JsProtocolHandler& handler,
|
||||
const JsCompletionCallback& callback) {
|
||||
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&Protocol::InterceptProtocolInIO,
|
||||
base::Unretained(this), scheme, handler),
|
||||
base::Bind(&Protocol::OnIOActionCompleted,
|
||||
base::Unretained(this), callback));
|
||||
}
|
||||
|
||||
void Protocol::UninterceptProtocol(v8::Isolate* isolate,
|
||||
const std::string& scheme,
|
||||
const JsCompletionCallback& callback) {
|
||||
BrowserThread::PostTaskAndReplyWithResult(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&Protocol::UninterceptProtocolInIO,
|
||||
base::Unretained(this), scheme),
|
||||
base::Bind(&Protocol::OnIOActionCompleted,
|
||||
base::Unretained(this), callback));
|
||||
}
|
||||
|
||||
int Protocol::RegisterProtocolInIO(const std::string& scheme,
|
||||
const JsProtocolHandler& handler) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
|
||||
if (ContainsKey(protocol_handlers_, scheme) ||
|
||||
job_factory_->IsHandledProtocol(scheme))
|
||||
return node::ThrowError("The scheme is already registered");
|
||||
job_factory_->IsHandledProtocol(scheme)) {
|
||||
return ERR_SCHEME_REGISTERED;
|
||||
}
|
||||
|
||||
protocol_handlers_[scheme] = callback;
|
||||
BrowserThread::PostTask(BrowserThread::IO,
|
||||
FROM_HERE,
|
||||
base::Bind(&Protocol::RegisterProtocolInIO,
|
||||
base::Unretained(this), scheme));
|
||||
protocol_handlers_[scheme] = handler;
|
||||
job_factory_->SetProtocolHandler(scheme, new CustomProtocolHandler(this));
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
void Protocol::UnregisterProtocol(const std::string& scheme) {
|
||||
int Protocol::UnregisterProtocolInIO(const std::string& scheme) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
|
||||
ProtocolHandlersMap::iterator it(protocol_handlers_.find(scheme));
|
||||
if (it == protocol_handlers_.end())
|
||||
return node::ThrowError("The scheme has not been registered");
|
||||
if (it == protocol_handlers_.end()) {
|
||||
return ERR_SCHEME_UNREGISTERED;
|
||||
}
|
||||
|
||||
protocol_handlers_.erase(it);
|
||||
BrowserThread::PostTask(BrowserThread::IO,
|
||||
FROM_HERE,
|
||||
base::Bind(&Protocol::UnregisterProtocolInIO,
|
||||
base::Unretained(this), scheme));
|
||||
job_factory_->SetProtocolHandler(scheme, NULL);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
bool Protocol::IsHandledProtocol(const std::string& scheme) {
|
||||
return job_factory_->IsHandledProtocol(scheme);
|
||||
}
|
||||
int Protocol::InterceptProtocolInIO(const std::string& scheme,
|
||||
const JsProtocolHandler& handler) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
|
||||
// Force the request context to initialize, otherwise we might have nothing
|
||||
// to intercept.
|
||||
request_context_getter_->GetURLRequestContext();
|
||||
|
||||
void Protocol::InterceptProtocol(const std::string& scheme,
|
||||
const JsProtocolHandler& callback) {
|
||||
if (!job_factory_->HasProtocolHandler(scheme))
|
||||
return node::ThrowError("Scheme does not exist.");
|
||||
return ERR_NO_SCHEME;
|
||||
|
||||
if (ContainsKey(protocol_handlers_, scheme))
|
||||
return node::ThrowError("Cannot intercept custom procotols");
|
||||
|
||||
protocol_handlers_[scheme] = callback;
|
||||
BrowserThread::PostTask(BrowserThread::IO,
|
||||
FROM_HERE,
|
||||
base::Bind(&Protocol::InterceptProtocolInIO,
|
||||
base::Unretained(this), scheme));
|
||||
}
|
||||
|
||||
void Protocol::UninterceptProtocol(const std::string& scheme) {
|
||||
ProtocolHandlersMap::iterator it(protocol_handlers_.find(scheme));
|
||||
if (it == protocol_handlers_.end())
|
||||
return node::ThrowError("The scheme has not been registered");
|
||||
|
||||
protocol_handlers_.erase(it);
|
||||
BrowserThread::PostTask(BrowserThread::IO,
|
||||
FROM_HERE,
|
||||
base::Bind(&Protocol::UninterceptProtocolInIO,
|
||||
base::Unretained(this), scheme));
|
||||
}
|
||||
|
||||
void Protocol::RegisterProtocolInIO(const std::string& scheme) {
|
||||
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
||||
|
||||
job_factory_->SetProtocolHandler(scheme, new CustomProtocolHandler(this));
|
||||
BrowserThread::PostTask(BrowserThread::UI,
|
||||
FROM_HERE,
|
||||
base::Bind(&Protocol::EmitEventInUI,
|
||||
base::Unretained(this),
|
||||
"registered", scheme));
|
||||
}
|
||||
|
||||
void Protocol::UnregisterProtocolInIO(const std::string& scheme) {
|
||||
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
||||
|
||||
job_factory_->SetProtocolHandler(scheme, NULL);
|
||||
BrowserThread::PostTask(BrowserThread::UI,
|
||||
FROM_HERE,
|
||||
base::Bind(&Protocol::EmitEventInUI,
|
||||
base::Unretained(this),
|
||||
"unregistered", scheme));
|
||||
}
|
||||
|
||||
void Protocol::InterceptProtocolInIO(const std::string& scheme) {
|
||||
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
||||
return ERR_SCHEME;
|
||||
|
||||
protocol_handlers_[scheme] = handler;
|
||||
ProtocolHandler* original_handler = job_factory_->GetProtocolHandler(scheme);
|
||||
if (original_handler == NULL) {
|
||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
|
||||
&Protocol::EmitEventInUI,
|
||||
base::Unretained(this),
|
||||
"error", "There is no protocol handler to intercpet"));
|
||||
return;
|
||||
if (original_handler == nullptr) {
|
||||
return ERR_SCHEME_INTERCEPTED;
|
||||
}
|
||||
|
||||
job_factory_->ReplaceProtocol(
|
||||
scheme, new CustomProtocolHandler(this, original_handler));
|
||||
BrowserThread::PostTask(BrowserThread::UI,
|
||||
FROM_HERE,
|
||||
base::Bind(&Protocol::EmitEventInUI,
|
||||
base::Unretained(this),
|
||||
"intercepted", scheme));
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
void Protocol::UninterceptProtocolInIO(const std::string& scheme) {
|
||||
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
||||
int Protocol::UninterceptProtocolInIO(const std::string& scheme) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
|
||||
ProtocolHandlersMap::iterator it(protocol_handlers_.find(scheme));
|
||||
if (it == protocol_handlers_.end())
|
||||
return ERR_SCHEME_UNREGISTERED;
|
||||
|
||||
protocol_handlers_.erase(it);
|
||||
CustomProtocolHandler* handler = static_cast<CustomProtocolHandler*>(
|
||||
job_factory_->GetProtocolHandler(scheme));
|
||||
if (handler->original_handler() == NULL) {
|
||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
|
||||
&Protocol::EmitEventInUI,
|
||||
base::Unretained(this),
|
||||
"error", "The protocol is not intercpeted"));
|
||||
return;
|
||||
if (handler->original_handler() == nullptr) {
|
||||
return ERR_SCHEME_UNINTERCEPTED;
|
||||
}
|
||||
|
||||
// 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);
|
||||
BrowserThread::PostTask(BrowserThread::UI,
|
||||
FROM_HERE,
|
||||
base::Bind(&Protocol::EmitEventInUI,
|
||||
base::Unretained(this),
|
||||
"unintercepted", scheme));
|
||||
}
|
||||
|
||||
void Protocol::EmitEventInUI(const std::string& event,
|
||||
const std::string& parameter) {
|
||||
Emit(event, parameter);
|
||||
return OK;
|
||||
}
|
||||
|
||||
// static
|
||||
mate::Handle<Protocol> Protocol::Create(v8::Isolate* isolate) {
|
||||
return CreateHandle(isolate, new Protocol);
|
||||
mate::Handle<Protocol> Protocol::Create(
|
||||
v8::Isolate* isolate, AtomBrowserContext* browser_context) {
|
||||
return mate::CreateHandle(isolate, new Protocol(browser_context));
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
@@ -352,7 +415,9 @@ void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
|
||||
v8::Local<v8::Context> context, void* priv) {
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
mate::Dictionary dict(isolate, exports);
|
||||
dict.Set("protocol", atom::api::Protocol::Create(isolate));
|
||||
auto browser_context = static_cast<atom::AtomBrowserContext*>(
|
||||
atom::AtomBrowserMainParts::Get()->browser_context());
|
||||
dict.Set("protocol", atom::api::Protocol::Create(isolate, browser_context));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -7,32 +7,52 @@
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/browser/api/event_emitter.h"
|
||||
#include "base/callback.h"
|
||||
#include "native_mate/handle.h"
|
||||
#include "net/base/completion_callback.h"
|
||||
|
||||
namespace net {
|
||||
class URLRequest;
|
||||
class URLRequestContextGetter;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomBrowserContext;
|
||||
class AtomURLRequestJobFactory;
|
||||
|
||||
namespace api {
|
||||
|
||||
class Protocol : public mate::EventEmitter {
|
||||
public:
|
||||
typedef base::Callback<v8::Local<v8::Value>(const net::URLRequest*)>
|
||||
JsProtocolHandler;
|
||||
using JsProtocolHandler =
|
||||
base::Callback<v8::Local<v8::Value>(const net::URLRequest*)>;
|
||||
using JsCompletionCallback = base::Callback<void(v8::Local<v8::Value>)>;
|
||||
|
||||
static mate::Handle<Protocol> Create(v8::Isolate* isolate);
|
||||
enum {
|
||||
OK = 0,
|
||||
ERR_SCHEME_REGISTERED,
|
||||
ERR_SCHEME_UNREGISTERED,
|
||||
ERR_SCHEME_INTERCEPTED,
|
||||
ERR_SCHEME_UNINTERCEPTED,
|
||||
ERR_NO_SCHEME,
|
||||
ERR_SCHEME
|
||||
};
|
||||
|
||||
static mate::Handle<Protocol> Create(
|
||||
v8::Isolate* isolate, AtomBrowserContext* browser_context);
|
||||
|
||||
JsProtocolHandler GetProtocolHandler(const std::string& scheme);
|
||||
|
||||
net::URLRequestContextGetter* request_context_getter() {
|
||||
return request_context_getter_.get();
|
||||
}
|
||||
|
||||
protected:
|
||||
Protocol();
|
||||
explicit Protocol(AtomBrowserContext* browser_context);
|
||||
|
||||
// mate::Wrappable implementations:
|
||||
virtual mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
||||
@@ -41,30 +61,43 @@ class Protocol : public mate::EventEmitter {
|
||||
private:
|
||||
typedef std::map<std::string, JsProtocolHandler> ProtocolHandlersMap;
|
||||
|
||||
// Register/unregister an networking |scheme| which would be handled by
|
||||
// |callback|.
|
||||
void RegisterProtocol(const std::string& scheme,
|
||||
const JsProtocolHandler& callback);
|
||||
void UnregisterProtocol(const std::string& scheme);
|
||||
// Callback called after performing action on IO thread.
|
||||
void OnIOActionCompleted(const JsCompletionCallback& callback,
|
||||
int error);
|
||||
|
||||
// Register schemes to standard scheme list.
|
||||
void RegisterStandardSchemes(const std::vector<std::string>& schemes);
|
||||
|
||||
// Returns whether a scheme has been registered.
|
||||
// FIXME Should accept a callback and be asynchronous so we do not have to use
|
||||
// locks.
|
||||
bool IsHandledProtocol(const std::string& scheme);
|
||||
void IsHandledProtocol(const std::string& scheme,
|
||||
const net::CompletionCallback& callback);
|
||||
|
||||
// Register/unregister an networking |scheme| which would be handled by
|
||||
// |callback|.
|
||||
void RegisterProtocol(v8::Isolate* isolate,
|
||||
const std::string& scheme,
|
||||
const JsProtocolHandler& handler,
|
||||
const JsCompletionCallback& callback);
|
||||
void UnregisterProtocol(v8::Isolate* isolate, const std::string& scheme,
|
||||
const JsCompletionCallback& callback);
|
||||
|
||||
// Intercept/unintercept an existing protocol handler.
|
||||
void InterceptProtocol(const std::string& scheme,
|
||||
const JsProtocolHandler& callback);
|
||||
void UninterceptProtocol(const std::string& scheme);
|
||||
void InterceptProtocol(v8::Isolate* isolate,
|
||||
const std::string& scheme,
|
||||
const JsProtocolHandler& handler,
|
||||
const JsCompletionCallback& callback);
|
||||
void UninterceptProtocol(v8::Isolate* isolate, const std::string& scheme,
|
||||
const JsCompletionCallback& callback);
|
||||
|
||||
// The networking related operations have to be done in IO thread.
|
||||
void RegisterProtocolInIO(const std::string& scheme);
|
||||
void UnregisterProtocolInIO(const std::string& scheme);
|
||||
void InterceptProtocolInIO(const std::string& scheme);
|
||||
void UninterceptProtocolInIO(const std::string& scheme);
|
||||
int RegisterProtocolInIO(const std::string& scheme,
|
||||
const JsProtocolHandler& handler);
|
||||
int UnregisterProtocolInIO(const std::string& scheme);
|
||||
int InterceptProtocolInIO(const std::string& scheme,
|
||||
const JsProtocolHandler& handler);
|
||||
int UninterceptProtocolInIO(const std::string& scheme);
|
||||
|
||||
// Do protocol.emit(event, parameter) under UI thread.
|
||||
void EmitEventInUI(const std::string& event, const std::string& parameter);
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
|
||||
|
||||
AtomURLRequestJobFactory* job_factory_;
|
||||
ProtocolHandlersMap protocol_handlers_;
|
||||
|
||||
@@ -113,13 +113,14 @@ mate::ObjectTemplateBuilder Screen::GetObjectTemplateBuilder(
|
||||
// static
|
||||
v8::Local<v8::Value> Screen::Create(v8::Isolate* isolate) {
|
||||
if (!Browser::Get()->is_ready()) {
|
||||
node::ThrowError("Cannot initialize \"screen\" module before app is ready");
|
||||
node::ThrowError(isolate,
|
||||
"Cannot initialize \"screen\" module before app is ready");
|
||||
return v8::Null(isolate);
|
||||
}
|
||||
|
||||
gfx::Screen* screen = gfx::Screen::GetNativeScreen();
|
||||
if (!screen) {
|
||||
node::ThrowError("Failed to get screen information");
|
||||
node::ThrowError(isolate, "Failed to get screen information");
|
||||
return v8::Null(isolate);
|
||||
}
|
||||
|
||||
|
||||
296
atom/browser/api/atom_api_session.cc
Normal file
296
atom/browser/api/atom_api_session.cc
Normal file
@@ -0,0 +1,296 @@
|
||||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/api/atom_api_session.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/browser/api/atom_api_cookies.h"
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/gurl_converter.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/prefs/pref_service.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/thread_task_runner_handle.h"
|
||||
#include "chrome/common/pref_names.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/storage_partition.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/object_template_builder.h"
|
||||
#include "net/base/load_flags.h"
|
||||
#include "net/disk_cache/disk_cache.h"
|
||||
#include "net/proxy/proxy_service.h"
|
||||
#include "net/proxy/proxy_config_service_fixed.h"
|
||||
#include "net/url_request/url_request_context.h"
|
||||
#include "net/url_request/url_request_context_getter.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
using content::BrowserThread;
|
||||
using content::StoragePartition;
|
||||
|
||||
namespace {
|
||||
|
||||
struct ClearStorageDataOptions {
|
||||
GURL origin;
|
||||
uint32 storage_types = StoragePartition::REMOVE_DATA_MASK_ALL;
|
||||
uint32 quota_types = StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL;
|
||||
};
|
||||
|
||||
uint32 GetStorageMask(const std::vector<std::string>& storage_types) {
|
||||
uint32 storage_mask = 0;
|
||||
for (const auto& it : storage_types) {
|
||||
auto type = base::StringToLowerASCII(it);
|
||||
if (type == "appcache")
|
||||
storage_mask |= StoragePartition::REMOVE_DATA_MASK_APPCACHE;
|
||||
else if (type == "cookies")
|
||||
storage_mask |= StoragePartition::REMOVE_DATA_MASK_COOKIES;
|
||||
else if (type == "filesystem")
|
||||
storage_mask |= StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS;
|
||||
else if (type == "indexdb")
|
||||
storage_mask |= StoragePartition::REMOVE_DATA_MASK_INDEXEDDB;
|
||||
else if (type == "localstorage")
|
||||
storage_mask |= StoragePartition::REMOVE_DATA_MASK_LOCAL_STORAGE;
|
||||
else if (type == "shadercache")
|
||||
storage_mask |= StoragePartition::REMOVE_DATA_MASK_SHADER_CACHE;
|
||||
else if (type == "websql")
|
||||
storage_mask |= StoragePartition::REMOVE_DATA_MASK_WEBSQL;
|
||||
else if (type == "serviceworkers")
|
||||
storage_mask |= StoragePartition::REMOVE_DATA_MASK_SERVICE_WORKERS;
|
||||
}
|
||||
return storage_mask;
|
||||
}
|
||||
|
||||
uint32 GetQuotaMask(const std::vector<std::string>& quota_types) {
|
||||
uint32 quota_mask = 0;
|
||||
for (const auto& it : quota_types) {
|
||||
auto type = base::StringToLowerASCII(it);
|
||||
if (type == "temporary")
|
||||
quota_mask |= StoragePartition::QUOTA_MANAGED_STORAGE_MASK_TEMPORARY;
|
||||
else if (type == "persistent")
|
||||
quota_mask |= StoragePartition::QUOTA_MANAGED_STORAGE_MASK_PERSISTENT;
|
||||
else if (type == "syncable")
|
||||
quota_mask |= StoragePartition::QUOTA_MANAGED_STORAGE_MASK_SYNCABLE;
|
||||
}
|
||||
return quota_mask;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace mate {
|
||||
|
||||
template<>
|
||||
struct Converter<ClearStorageDataOptions> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
ClearStorageDataOptions* out) {
|
||||
mate::Dictionary options;
|
||||
if (!ConvertFromV8(isolate, val, &options))
|
||||
return false;
|
||||
options.Get("origin", &out->origin);
|
||||
std::vector<std::string> types;
|
||||
if (options.Get("storages", &types))
|
||||
out->storage_types = GetStorageMask(types);
|
||||
if (options.Get("quotas", &types))
|
||||
out->quota_types = GetQuotaMask(types);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
namespace {
|
||||
|
||||
class ResolveProxyHelper {
|
||||
public:
|
||||
ResolveProxyHelper(AtomBrowserContext* browser_context,
|
||||
const GURL& url,
|
||||
Session::ResolveProxyCallback callback)
|
||||
: callback_(callback),
|
||||
original_thread_(base::ThreadTaskRunnerHandle::Get()) {
|
||||
scoped_refptr<net::URLRequestContextGetter> context_getter =
|
||||
browser_context->GetRequestContext();
|
||||
context_getter->GetNetworkTaskRunner()->PostTask(
|
||||
FROM_HERE,
|
||||
base::Bind(&ResolveProxyHelper::ResolveProxy,
|
||||
base::Unretained(this), context_getter, url));
|
||||
}
|
||||
|
||||
void OnResolveProxyCompleted(int result) {
|
||||
std::string proxy;
|
||||
if (result == net::OK)
|
||||
proxy = proxy_info_.ToPacString();
|
||||
original_thread_->PostTask(FROM_HERE,
|
||||
base::Bind(callback_, proxy));
|
||||
delete this;
|
||||
}
|
||||
|
||||
private:
|
||||
void ResolveProxy(scoped_refptr<net::URLRequestContextGetter> context_getter,
|
||||
const GURL& url) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
|
||||
|
||||
net::ProxyService* proxy_service =
|
||||
context_getter->GetURLRequestContext()->proxy_service();
|
||||
net::CompletionCallback completion_callback =
|
||||
base::Bind(&ResolveProxyHelper::OnResolveProxyCompleted,
|
||||
base::Unretained(this));
|
||||
|
||||
// Start the request.
|
||||
int result = proxy_service->ResolveProxy(
|
||||
url, net::LOAD_NORMAL, &proxy_info_, completion_callback,
|
||||
&pac_req_, nullptr, net::BoundNetLog());
|
||||
|
||||
// Completed synchronously.
|
||||
if (result != net::ERR_IO_PENDING)
|
||||
completion_callback.Run(result);
|
||||
}
|
||||
|
||||
Session::ResolveProxyCallback callback_;
|
||||
net::ProxyInfo proxy_info_;
|
||||
net::ProxyService::PacRequest* pac_req_;
|
||||
scoped_refptr<base::SingleThreadTaskRunner> original_thread_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ResolveProxyHelper);
|
||||
};
|
||||
|
||||
// Runs the callback in UI thread.
|
||||
template <typename ...T>
|
||||
void RunCallbackInUI(const base::Callback<void(T...)>& callback, T... result) {
|
||||
BrowserThread::PostTask(
|
||||
BrowserThread::UI, FROM_HERE, base::Bind(callback, result...));
|
||||
}
|
||||
|
||||
// Callback of HttpCache::GetBackend.
|
||||
void OnGetBackend(disk_cache::Backend** backend_ptr,
|
||||
const net::CompletionCallback& callback,
|
||||
int result) {
|
||||
if (result != net::OK) {
|
||||
RunCallbackInUI(callback, result);
|
||||
} else if (backend_ptr && *backend_ptr) {
|
||||
(*backend_ptr)->DoomAllEntries(base::Bind(&RunCallbackInUI<int>, callback));
|
||||
} else {
|
||||
RunCallbackInUI<int>(callback, net::ERR_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
void ClearHttpCacheInIO(
|
||||
const scoped_refptr<net::URLRequestContextGetter>& context_getter,
|
||||
const net::CompletionCallback& callback) {
|
||||
auto request_context = context_getter->GetURLRequestContext();
|
||||
auto http_cache = request_context->http_transaction_factory()->GetCache();
|
||||
if (!http_cache)
|
||||
RunCallbackInUI<int>(callback, net::ERR_FAILED);
|
||||
|
||||
// Call GetBackend and make the backend's ptr accessable in OnGetBackend.
|
||||
using BackendPtr = disk_cache::Backend*;
|
||||
BackendPtr* backend_ptr = new BackendPtr(nullptr);
|
||||
net::CompletionCallback on_get_backend =
|
||||
base::Bind(&OnGetBackend, base::Owned(backend_ptr), callback);
|
||||
int rv = http_cache->GetBackend(backend_ptr, on_get_backend);
|
||||
if (rv != net::ERR_IO_PENDING)
|
||||
on_get_backend.Run(net::OK);
|
||||
}
|
||||
|
||||
void SetProxyInIO(net::URLRequestContextGetter* getter,
|
||||
const std::string& proxy,
|
||||
const base::Closure& callback) {
|
||||
net::ProxyConfig config;
|
||||
config.proxy_rules().ParseFromString(proxy);
|
||||
auto proxy_service = getter->GetURLRequestContext()->proxy_service();
|
||||
proxy_service->ResetConfigService(new net::ProxyConfigServiceFixed(config));
|
||||
RunCallbackInUI(callback);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Session::Session(AtomBrowserContext* browser_context)
|
||||
: browser_context_(browser_context) {
|
||||
AttachAsUserData(browser_context);
|
||||
}
|
||||
|
||||
Session::~Session() {
|
||||
}
|
||||
|
||||
void Session::ResolveProxy(const GURL& url, ResolveProxyCallback callback) {
|
||||
new ResolveProxyHelper(browser_context_, url, callback);
|
||||
}
|
||||
|
||||
void Session::ClearCache(const net::CompletionCallback& callback) {
|
||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&ClearHttpCacheInIO,
|
||||
make_scoped_refptr(browser_context_->GetRequestContext()),
|
||||
callback));
|
||||
}
|
||||
|
||||
void Session::ClearStorageData(mate::Arguments* args) {
|
||||
// clearStorageData([options, ]callback)
|
||||
ClearStorageDataOptions options;
|
||||
args->GetNext(&options);
|
||||
base::Closure callback;
|
||||
if (!args->GetNext(&callback)) {
|
||||
args->ThrowError();
|
||||
return;
|
||||
}
|
||||
|
||||
auto storage_partition =
|
||||
content::BrowserContext::GetStoragePartition(browser_context_, nullptr);
|
||||
storage_partition->ClearData(
|
||||
options.storage_types, options.quota_types, options.origin,
|
||||
content::StoragePartition::OriginMatcherFunction(),
|
||||
base::Time(), base::Time::Max(), callback);
|
||||
}
|
||||
|
||||
void Session::SetProxy(const std::string& proxy,
|
||||
const base::Closure& callback) {
|
||||
auto getter = browser_context_->GetRequestContext();
|
||||
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&SetProxyInIO, base::Unretained(getter), proxy, callback));
|
||||
}
|
||||
|
||||
void Session::SetDownloadPath(const base::FilePath& path) {
|
||||
browser_context_->prefs()->SetFilePath(
|
||||
prefs::kDownloadDefaultDirectory, path);
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) {
|
||||
if (cookies_.IsEmpty()) {
|
||||
auto handle = atom::api::Cookies::Create(isolate, browser_context_);
|
||||
cookies_.Reset(isolate, handle.ToV8());
|
||||
}
|
||||
return v8::Local<v8::Value>::New(isolate, cookies_);
|
||||
}
|
||||
|
||||
mate::ObjectTemplateBuilder Session::GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) {
|
||||
return mate::ObjectTemplateBuilder(isolate)
|
||||
.SetMethod("resolveProxy", &Session::ResolveProxy)
|
||||
.SetMethod("clearCache", &Session::ClearCache)
|
||||
.SetMethod("clearStorageData", &Session::ClearStorageData)
|
||||
.SetMethod("setProxy", &Session::SetProxy)
|
||||
.SetMethod("setDownloadPath", &Session::SetDownloadPath)
|
||||
.SetProperty("cookies", &Session::Cookies);
|
||||
}
|
||||
|
||||
// static
|
||||
mate::Handle<Session> Session::CreateFrom(
|
||||
v8::Isolate* isolate,
|
||||
AtomBrowserContext* browser_context) {
|
||||
auto existing = TrackableObject::FromWrappedClass(isolate, browser_context);
|
||||
if (existing)
|
||||
return mate::CreateHandle(isolate, static_cast<Session*>(existing));
|
||||
|
||||
return mate::CreateHandle(isolate, new Session(browser_context));
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
||||
67
atom/browser/api/atom_api_session.h
Normal file
67
atom/browser/api/atom_api_session.h
Normal file
@@ -0,0 +1,67 @@
|
||||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_API_ATOM_API_SESSION_H_
|
||||
#define ATOM_BROWSER_API_ATOM_API_SESSION_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/api/trackable_object.h"
|
||||
#include "native_mate/handle.h"
|
||||
#include "net/base/completion_callback.h"
|
||||
|
||||
class GURL;
|
||||
|
||||
namespace base {
|
||||
class FilePath;
|
||||
}
|
||||
|
||||
namespace mate {
|
||||
class Arguments;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomBrowserContext;
|
||||
|
||||
namespace api {
|
||||
|
||||
class Session: public mate::TrackableObject<Session> {
|
||||
public:
|
||||
using ResolveProxyCallback = base::Callback<void(std::string)>;
|
||||
|
||||
// Gets or creates Session from the |browser_context|.
|
||||
static mate::Handle<Session> CreateFrom(
|
||||
v8::Isolate* isolate, AtomBrowserContext* browser_context);
|
||||
|
||||
AtomBrowserContext* browser_context() const { return browser_context_; }
|
||||
|
||||
protected:
|
||||
explicit Session(AtomBrowserContext* browser_context);
|
||||
~Session();
|
||||
|
||||
// mate::Wrappable implementations:
|
||||
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) override;
|
||||
|
||||
private:
|
||||
void ResolveProxy(const GURL& url, ResolveProxyCallback callback);
|
||||
void ClearCache(const net::CompletionCallback& callback);
|
||||
void ClearStorageData(mate::Arguments* args);
|
||||
void SetProxy(const std::string& proxy, const base::Closure& callback);
|
||||
void SetDownloadPath(const base::FilePath& path);
|
||||
v8::Local<v8::Value> Cookies(v8::Isolate* isolate);
|
||||
|
||||
v8::Global<v8::Value> cookies_;
|
||||
|
||||
AtomBrowserContext* browser_context_; // weak ref
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Session);
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_API_ATOM_API_SESSION_H_
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "atom/common/native_mate_converters/string16_converter.h"
|
||||
#include "native_mate/constructor.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "ui/events/event_constants.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
@@ -32,20 +33,33 @@ Tray::~Tray() {
|
||||
}
|
||||
|
||||
// static
|
||||
mate::Wrappable* Tray::New(const gfx::Image& image) {
|
||||
mate::Wrappable* Tray::New(v8::Isolate* isolate, const gfx::Image& image) {
|
||||
if (!Browser::Get()->is_ready()) {
|
||||
node::ThrowError("Cannot create Tray before app is ready");
|
||||
node::ThrowError(isolate, "Cannot create Tray before app is ready");
|
||||
return nullptr;
|
||||
}
|
||||
return new Tray(image);
|
||||
}
|
||||
|
||||
void Tray::OnClicked(const gfx::Rect& bounds) {
|
||||
Emit("clicked", bounds);
|
||||
void Tray::OnClicked(const gfx::Rect& bounds, int modifiers) {
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
EmitCustomEvent("clicked",
|
||||
ModifiersToObject(isolate(), modifiers), bounds);
|
||||
}
|
||||
|
||||
void Tray::OnDoubleClicked() {
|
||||
Emit("double-clicked");
|
||||
void Tray::OnDoubleClicked(const gfx::Rect& bounds, int modifiers) {
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
EmitCustomEvent("double-clicked",
|
||||
ModifiersToObject(isolate(), modifiers), bounds);
|
||||
}
|
||||
|
||||
void Tray::OnRightClicked(const gfx::Rect& bounds, int modifiers) {
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
EmitCustomEvent("right-clicked",
|
||||
ModifiersToObject(isolate(), modifiers), bounds);
|
||||
}
|
||||
|
||||
void Tray::OnBalloonShow() {
|
||||
@@ -60,45 +74,40 @@ void Tray::OnBalloonClosed() {
|
||||
Emit("balloon-closed");
|
||||
}
|
||||
|
||||
void Tray::OnDropFiles(const std::vector<std::string>& files) {
|
||||
Emit("drop-files", files);
|
||||
}
|
||||
|
||||
bool Tray::IsDestroyed() const {
|
||||
return !tray_icon_;
|
||||
}
|
||||
|
||||
void Tray::Destroy() {
|
||||
tray_icon_.reset();
|
||||
}
|
||||
|
||||
void Tray::SetImage(mate::Arguments* args, const gfx::Image& image) {
|
||||
if (!CheckTrayLife(args))
|
||||
return;
|
||||
tray_icon_->SetImage(image);
|
||||
}
|
||||
|
||||
void Tray::SetPressedImage(mate::Arguments* args, const gfx::Image& image) {
|
||||
if (!CheckTrayLife(args))
|
||||
return;
|
||||
tray_icon_->SetPressedImage(image);
|
||||
}
|
||||
|
||||
void Tray::SetToolTip(mate::Arguments* args, const std::string& tool_tip) {
|
||||
if (!CheckTrayLife(args))
|
||||
return;
|
||||
tray_icon_->SetToolTip(tool_tip);
|
||||
}
|
||||
|
||||
void Tray::SetTitle(mate::Arguments* args, const std::string& title) {
|
||||
if (!CheckTrayLife(args))
|
||||
return;
|
||||
tray_icon_->SetTitle(title);
|
||||
}
|
||||
|
||||
void Tray::SetHighlightMode(mate::Arguments* args, bool highlight) {
|
||||
if (!CheckTrayLife(args))
|
||||
return;
|
||||
tray_icon_->SetHighlightMode(highlight);
|
||||
}
|
||||
|
||||
void Tray::DisplayBalloon(mate::Arguments* args,
|
||||
const mate::Dictionary& options) {
|
||||
if (!CheckTrayLife(args))
|
||||
return;
|
||||
|
||||
gfx::Image icon;
|
||||
options.Get("icon", &icon);
|
||||
base::string16 title, content;
|
||||
@@ -111,32 +120,38 @@ void Tray::DisplayBalloon(mate::Arguments* args,
|
||||
tray_icon_->DisplayBalloon(icon, title, content);
|
||||
}
|
||||
|
||||
void Tray::PopUpContextMenu(mate::Arguments* args) {
|
||||
gfx::Point pos;
|
||||
args->GetNext(&pos);
|
||||
tray_icon_->PopUpContextMenu(pos);
|
||||
}
|
||||
|
||||
void Tray::SetContextMenu(mate::Arguments* args, Menu* menu) {
|
||||
if (!CheckTrayLife(args))
|
||||
return;
|
||||
tray_icon_->SetContextMenu(menu->model());
|
||||
}
|
||||
|
||||
bool Tray::CheckTrayLife(mate::Arguments* args) {
|
||||
if (!tray_icon_) {
|
||||
args->ThrowError("Tray is already destroyed");
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
v8::Local<v8::Object> Tray::ModifiersToObject(v8::Isolate* isolate,
|
||||
int modifiers) {
|
||||
mate::Dictionary obj(isolate, v8::Object::New(isolate));
|
||||
obj.Set("shiftKey", static_cast<bool>(modifiers & ui::EF_SHIFT_DOWN));
|
||||
obj.Set("ctrlKey", static_cast<bool>(modifiers & ui::EF_CONTROL_DOWN));
|
||||
obj.Set("altKey", static_cast<bool>(modifiers & ui::EF_ALT_DOWN));
|
||||
obj.Set("metaKey", static_cast<bool>(modifiers & ui::EF_COMMAND_DOWN));
|
||||
return obj.GetHandle();
|
||||
}
|
||||
|
||||
// static
|
||||
void Tray::BuildPrototype(v8::Isolate* isolate,
|
||||
v8::Local<v8::ObjectTemplate> prototype) {
|
||||
mate::ObjectTemplateBuilder(isolate, prototype)
|
||||
.SetMethod("destroy", &Tray::Destroy)
|
||||
.SetMethod("destroy", &Tray::Destroy, true)
|
||||
.SetMethod("setImage", &Tray::SetImage)
|
||||
.SetMethod("setPressedImage", &Tray::SetPressedImage)
|
||||
.SetMethod("setToolTip", &Tray::SetToolTip)
|
||||
.SetMethod("setTitle", &Tray::SetTitle)
|
||||
.SetMethod("setHighlightMode", &Tray::SetHighlightMode)
|
||||
.SetMethod("displayBalloon", &Tray::DisplayBalloon)
|
||||
.SetMethod("popUpContextMenu", &Tray::PopUpContextMenu)
|
||||
.SetMethod("_setContextMenu", &Tray::SetContextMenu);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#define ATOM_BROWSER_API_ATOM_API_TRAY_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/browser/api/event_emitter.h"
|
||||
#include "atom/browser/ui/tray_icon_observer.h"
|
||||
@@ -31,7 +32,7 @@ class Menu;
|
||||
class Tray : public mate::EventEmitter,
|
||||
public TrayIconObserver {
|
||||
public:
|
||||
static mate::Wrappable* New(const gfx::Image& image);
|
||||
static mate::Wrappable* New(v8::Isolate* isolate, const gfx::Image& image);
|
||||
|
||||
static void BuildPrototype(v8::Isolate* isolate,
|
||||
v8::Local<v8::ObjectTemplate> prototype);
|
||||
@@ -41,11 +42,16 @@ class Tray : public mate::EventEmitter,
|
||||
virtual ~Tray();
|
||||
|
||||
// TrayIconObserver:
|
||||
void OnClicked(const gfx::Rect&) override;
|
||||
void OnDoubleClicked() override;
|
||||
void OnClicked(const gfx::Rect& bounds, int modifiers) override;
|
||||
void OnDoubleClicked(const gfx::Rect& bounds, int modifiers) override;
|
||||
void OnRightClicked(const gfx::Rect& bounds, int modifiers) override;
|
||||
void OnBalloonShow() override;
|
||||
void OnBalloonClicked() override;
|
||||
void OnBalloonClosed() override;
|
||||
void OnDropFiles(const std::vector<std::string>& files) override;
|
||||
|
||||
// mate::Wrappable:
|
||||
bool IsDestroyed() const override;
|
||||
|
||||
void Destroy();
|
||||
void SetImage(mate::Arguments* args, const gfx::Image& image);
|
||||
@@ -54,10 +60,11 @@ class Tray : public mate::EventEmitter,
|
||||
void SetTitle(mate::Arguments* args, const std::string& title);
|
||||
void SetHighlightMode(mate::Arguments* args, bool highlight);
|
||||
void DisplayBalloon(mate::Arguments* args, const mate::Dictionary& options);
|
||||
void PopUpContextMenu(mate::Arguments* args);
|
||||
void SetContextMenu(mate::Arguments* args, Menu* menu);
|
||||
|
||||
private:
|
||||
bool CheckTrayLife(mate::Arguments* args);
|
||||
v8::Local<v8::Object> ModifiersToObject(v8::Isolate* isolate, int modifiers);
|
||||
|
||||
scoped_ptr<TrayIcon> tray_icon_;
|
||||
|
||||
|
||||
@@ -6,13 +6,16 @@
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "atom/browser/api/atom_api_session.h"
|
||||
#include "atom/browser/atom_browser_client.h"
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/atom_javascript_dialog_manager.h"
|
||||
#include "atom/browser/atom_browser_main_parts.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/web_dialog_helper.h"
|
||||
#include "atom/browser/web_view_manager.h"
|
||||
#include "atom/browser/web_view_guest_delegate.h"
|
||||
#include "atom/common/api/api_messages.h"
|
||||
#include "atom/common/api/event_emitter_caller.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "atom/common/native_mate_converters/gfx_converter.h"
|
||||
#include "atom/common/native_mate_converters/gurl_converter.h"
|
||||
#include "atom/common/native_mate_converters/image_converter.h"
|
||||
@@ -21,29 +24,99 @@
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "brightray/browser/inspectable_web_contents.h"
|
||||
#include "brightray/browser/media/media_stream_devices_controller.h"
|
||||
#include "chrome/browser/printing/print_view_manager_basic.h"
|
||||
#include "chrome/browser/printing/print_preview_message_handler.h"
|
||||
#include "content/public/browser/favicon_status.h"
|
||||
#include "content/public/browser/guest_host.h"
|
||||
#include "content/public/browser/navigation_details.h"
|
||||
#include "content/public/browser/navigation_entry.h"
|
||||
#include "content/public/browser/plugin_service.h"
|
||||
#include "content/public/browser/render_frame_host.h"
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#include "content/public/browser/render_widget_host_view.h"
|
||||
#include "content/public/browser/resource_request_details.h"
|
||||
#include "content/public/browser/service_worker_context.h"
|
||||
#include "content/public/browser/storage_partition.h"
|
||||
#include "content/public/browser/site_instance.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "native_mate/callback.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/object_template_builder.h"
|
||||
#include "net/http/http_response_headers.h"
|
||||
#include "net/url_request/static_http_user_agent_settings.h"
|
||||
#include "net/url_request/url_request_context.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
namespace {
|
||||
|
||||
struct PrintSettings {
|
||||
bool silent;
|
||||
bool print_background;
|
||||
};
|
||||
|
||||
void SetUserAgentInIO(scoped_refptr<net::URLRequestContextGetter> getter,
|
||||
std::string user_agent) {
|
||||
getter->GetURLRequestContext()->set_http_user_agent_settings(
|
||||
new net::StaticHttpUserAgentSettings("en-us,en", user_agent));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace mate {
|
||||
|
||||
template<>
|
||||
struct Converter<atom::SetSizeParams> {
|
||||
static bool FromV8(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> val,
|
||||
atom::SetSizeParams* out) {
|
||||
mate::Dictionary params;
|
||||
if (!ConvertFromV8(isolate, val, ¶ms))
|
||||
return false;
|
||||
bool autosize;
|
||||
if (params.Get("enableAutoSize", &autosize))
|
||||
out->enable_auto_size.reset(new bool(true));
|
||||
gfx::Size size;
|
||||
if (params.Get("min", &size))
|
||||
out->min_size.reset(new gfx::Size(size));
|
||||
if (params.Get("max", &size))
|
||||
out->max_size.reset(new gfx::Size(size));
|
||||
if (params.Get("normal", &size))
|
||||
out->normal_size.reset(new gfx::Size(size));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Converter<PrintSettings> {
|
||||
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
|
||||
PrintSettings* out) {
|
||||
mate::Dictionary dict;
|
||||
if (!ConvertFromV8(isolate, val, &dict))
|
||||
return false;
|
||||
dict.Get("silent", &(out->silent));
|
||||
dict.Get("printBackground", &(out->print_background));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Converter<WindowOpenDisposition> {
|
||||
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||
WindowOpenDisposition val) {
|
||||
std::string disposition = "other";
|
||||
switch (val) {
|
||||
case CURRENT_TAB: disposition = "default"; break;
|
||||
case NEW_FOREGROUND_TAB: disposition = "foreground-tab"; break;
|
||||
case NEW_BACKGROUND_TAB: disposition = "background-tab"; break;
|
||||
case NEW_POPUP: case NEW_WINDOW: disposition = "new-window"; break;
|
||||
default: break;
|
||||
}
|
||||
return mate::ConvertToV8(isolate, disposition);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
@@ -52,14 +125,9 @@ namespace {
|
||||
|
||||
v8::Persistent<v8::ObjectTemplate> template_;
|
||||
|
||||
// Get the window that has the |guest| embedded.
|
||||
NativeWindow* GetWindowFromGuest(const content::WebContents* guest) {
|
||||
WebViewManager::WebViewInfo info;
|
||||
if (WebViewManager::GetInfoForProcess(guest->GetRenderProcessHost(), &info))
|
||||
return NativeWindow::FromWebContents(info.embedder);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
// The wrapWebContents funtion which is implemented in JavaScript
|
||||
using WrapWebContentsCallback = base::Callback<void(v8::Local<v8::Value>)>;
|
||||
WrapWebContentsCallback g_wrap_web_contents;
|
||||
|
||||
content::ServiceWorkerContext* GetServiceWorkerContext(
|
||||
const content::WebContents* web_contents) {
|
||||
@@ -68,11 +136,10 @@ content::ServiceWorkerContext* GetServiceWorkerContext(
|
||||
if (!context || !site_instance)
|
||||
return nullptr;
|
||||
|
||||
content::StoragePartition* storage_partition =
|
||||
content::BrowserContext::GetStoragePartition(
|
||||
context, site_instance);
|
||||
|
||||
DCHECK(storage_partition);
|
||||
auto storage_partition =
|
||||
content::BrowserContext::GetStoragePartition(context, site_instance);
|
||||
if (!storage_partition)
|
||||
return nullptr;
|
||||
|
||||
return storage_partition->GetServiceWorkerContext();
|
||||
}
|
||||
@@ -81,33 +148,51 @@ content::ServiceWorkerContext* GetServiceWorkerContext(
|
||||
|
||||
WebContents::WebContents(content::WebContents* web_contents)
|
||||
: content::WebContentsObserver(web_contents),
|
||||
guest_instance_id_(-1),
|
||||
element_instance_id_(-1),
|
||||
guest_opaque_(true),
|
||||
guest_host_(nullptr),
|
||||
auto_size_enabled_(false) {
|
||||
type_(REMOTE) {
|
||||
AttachAsUserData(web_contents);
|
||||
web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
|
||||
}
|
||||
|
||||
WebContents::WebContents(const mate::Dictionary& options)
|
||||
: guest_instance_id_(-1),
|
||||
element_instance_id_(-1),
|
||||
guest_opaque_(true),
|
||||
guest_host_(nullptr),
|
||||
auto_size_enabled_(false) {
|
||||
options.Get("guestInstanceId", &guest_instance_id_);
|
||||
WebContents::WebContents(const mate::Dictionary& options) {
|
||||
bool is_guest = false;
|
||||
options.Get("isGuest", &is_guest);
|
||||
|
||||
auto browser_context = AtomBrowserContext::Get();
|
||||
content::SiteInstance* site_instance = content::SiteInstance::CreateForURL(
|
||||
browser_context, GURL("chrome-guest://fake-host"));
|
||||
type_ = is_guest ? WEB_VIEW : BROWSER_WINDOW;
|
||||
|
||||
content::WebContents::CreateParams params(browser_context, site_instance);
|
||||
bool is_guest;
|
||||
if (options.Get("isGuest", &is_guest) && is_guest)
|
||||
params.guest_delegate = this;
|
||||
auto browser_context = AtomBrowserMainParts::Get()->browser_context();
|
||||
content::WebContents* web_contents;
|
||||
if (is_guest) {
|
||||
content::SiteInstance* site_instance = content::SiteInstance::CreateForURL(
|
||||
browser_context, GURL("chrome-guest://fake-host"));
|
||||
content::WebContents::CreateParams params(browser_context, site_instance);
|
||||
guest_delegate_.reset(new WebViewGuestDelegate);
|
||||
params.guest_delegate = guest_delegate_.get();
|
||||
web_contents = content::WebContents::Create(params);
|
||||
} else {
|
||||
content::WebContents::CreateParams params(browser_context);
|
||||
web_contents = content::WebContents::Create(params);
|
||||
}
|
||||
|
||||
storage_.reset(brightray::InspectableWebContents::Create(params));
|
||||
Observe(storage_->GetWebContents());
|
||||
web_contents()->SetDelegate(this);
|
||||
Observe(web_contents);
|
||||
AttachAsUserData(web_contents);
|
||||
InitWithWebContents(web_contents);
|
||||
|
||||
web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
|
||||
|
||||
if (is_guest) {
|
||||
guest_delegate_->Initialize(this);
|
||||
|
||||
NativeWindow* owner_window = nullptr;
|
||||
WebContents* embedder = nullptr;
|
||||
if (options.Get("embedder", &embedder) && embedder) {
|
||||
// New WebContents's owner_window is the embedder's owner_window.
|
||||
auto relay = NativeWindowRelay::FromWebContents(embedder->web_contents());
|
||||
if (relay)
|
||||
owner_window = relay->window.get();
|
||||
}
|
||||
if (owner_window)
|
||||
SetOwnerWindow(owner_window);
|
||||
}
|
||||
}
|
||||
|
||||
WebContents::~WebContents() {
|
||||
@@ -119,8 +204,12 @@ bool WebContents::AddMessageToConsole(content::WebContents* source,
|
||||
const base::string16& message,
|
||||
int32 line_no,
|
||||
const base::string16& source_id) {
|
||||
Emit("console-message", level, message, line_no, source_id);
|
||||
return true;
|
||||
if (type_ == BROWSER_WINDOW) {
|
||||
return false;
|
||||
} else {
|
||||
Emit("console-message", level, message, line_no, source_id);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool WebContents::ShouldCreateWebContents(
|
||||
@@ -132,22 +221,21 @@ bool WebContents::ShouldCreateWebContents(
|
||||
const GURL& target_url,
|
||||
const std::string& partition_id,
|
||||
content::SessionStorageNamespace* session_storage_namespace) {
|
||||
Emit("-new-window",
|
||||
target_url,
|
||||
frame_name,
|
||||
static_cast<int>(NEW_FOREGROUND_TAB));
|
||||
if (type_ == BROWSER_WINDOW)
|
||||
Emit("-new-window", target_url, frame_name, NEW_FOREGROUND_TAB);
|
||||
else
|
||||
Emit("new-window", target_url, frame_name, NEW_FOREGROUND_TAB);
|
||||
return false;
|
||||
}
|
||||
|
||||
void WebContents::CloseContents(content::WebContents* source) {
|
||||
Emit("close");
|
||||
}
|
||||
|
||||
content::WebContents* WebContents::OpenURLFromTab(
|
||||
content::WebContents* source,
|
||||
const content::OpenURLParams& params) {
|
||||
if (params.disposition != CURRENT_TAB) {
|
||||
Emit("-new-window", params.url, "", static_cast<int>(params.disposition));
|
||||
if (type_ == BROWSER_WINDOW)
|
||||
Emit("-new-window", params.url, "", params.disposition);
|
||||
else
|
||||
Emit("new-window", params.url, "", params.disposition);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -155,103 +243,88 @@ content::WebContents* WebContents::OpenURLFromTab(
|
||||
if (Emit("will-navigate", params.url))
|
||||
return nullptr;
|
||||
|
||||
content::NavigationController::LoadURLParams load_url_params(params.url);
|
||||
load_url_params.referrer = params.referrer;
|
||||
load_url_params.transition_type = params.transition;
|
||||
load_url_params.extra_headers = params.extra_headers;
|
||||
load_url_params.should_replace_current_entry =
|
||||
params.should_replace_current_entry;
|
||||
load_url_params.is_renderer_initiated = params.is_renderer_initiated;
|
||||
load_url_params.transferred_global_request_id =
|
||||
params.transferred_global_request_id;
|
||||
load_url_params.should_clear_history_list = true;
|
||||
|
||||
web_contents()->GetController().LoadURLWithParams(load_url_params);
|
||||
return web_contents();
|
||||
return CommonWebContentsDelegate::OpenURLFromTab(source, params);
|
||||
}
|
||||
|
||||
content::JavaScriptDialogManager* WebContents::GetJavaScriptDialogManager(
|
||||
content::WebContents* source) {
|
||||
if (!dialog_manager_)
|
||||
dialog_manager_.reset(new AtomJavaScriptDialogManager);
|
||||
|
||||
return dialog_manager_.get();
|
||||
void WebContents::BeforeUnloadFired(content::WebContents* tab,
|
||||
bool proceed,
|
||||
bool* proceed_to_fire_unload) {
|
||||
if (type_ == BROWSER_WINDOW)
|
||||
*proceed_to_fire_unload = proceed;
|
||||
else
|
||||
*proceed_to_fire_unload = true;
|
||||
}
|
||||
|
||||
void WebContents::RunFileChooser(content::WebContents* guest,
|
||||
const content::FileChooserParams& params) {
|
||||
if (!web_dialog_helper_)
|
||||
web_dialog_helper_.reset(new WebDialogHelper(GetWindowFromGuest(guest)));
|
||||
web_dialog_helper_->RunFileChooser(guest, params);
|
||||
void WebContents::MoveContents(content::WebContents* source,
|
||||
const gfx::Rect& pos) {
|
||||
Emit("move", pos);
|
||||
}
|
||||
|
||||
void WebContents::EnumerateDirectory(content::WebContents* guest,
|
||||
int request_id,
|
||||
const base::FilePath& path) {
|
||||
if (!web_dialog_helper_)
|
||||
web_dialog_helper_.reset(new WebDialogHelper(GetWindowFromGuest(guest)));
|
||||
web_dialog_helper_->EnumerateDirectory(guest, request_id, path);
|
||||
void WebContents::CloseContents(content::WebContents* source) {
|
||||
Emit("close");
|
||||
if (type_ == BROWSER_WINDOW)
|
||||
owner_window()->CloseContents(source);
|
||||
}
|
||||
|
||||
bool WebContents::CheckMediaAccessPermission(content::WebContents* web_contents,
|
||||
const GURL& security_origin,
|
||||
content::MediaStreamType type) {
|
||||
return true;
|
||||
void WebContents::ActivateContents(content::WebContents* source) {
|
||||
Emit("activate");
|
||||
}
|
||||
|
||||
void WebContents::RequestMediaAccessPermission(
|
||||
content::WebContents*,
|
||||
const content::MediaStreamRequest& request,
|
||||
const content::MediaResponseCallback& callback) {
|
||||
brightray::MediaStreamDevicesController controller(request, callback);
|
||||
controller.TakeAction();
|
||||
bool WebContents::IsPopupOrPanel(const content::WebContents* source) const {
|
||||
return type_ == BROWSER_WINDOW;
|
||||
}
|
||||
|
||||
void WebContents::HandleKeyboardEvent(
|
||||
content::WebContents* source,
|
||||
const content::NativeWebKeyboardEvent& event) {
|
||||
if (!attached())
|
||||
return;
|
||||
|
||||
// Send the unhandled keyboard events back to the embedder to reprocess them.
|
||||
embedder_web_contents_->GetDelegate()->HandleKeyboardEvent(
|
||||
web_contents(), event);
|
||||
if (type_ == BROWSER_WINDOW) {
|
||||
owner_window()->HandleKeyboardEvent(source, event);
|
||||
} else if (type_ == WEB_VIEW && guest_delegate_) {
|
||||
// Send the unhandled keyboard events back to the embedder.
|
||||
guest_delegate_->HandleKeyboardEvent(source, event);
|
||||
}
|
||||
}
|
||||
|
||||
void WebContents::EnterFullscreenModeForTab(content::WebContents* source,
|
||||
const GURL& origin) {
|
||||
auto window = GetWindowFromGuest(source);
|
||||
if (window) {
|
||||
window->SetHtmlApiFullscreen(true);
|
||||
window->NotifyWindowEnterHtmlFullScreen();
|
||||
source->GetRenderViewHost()->WasResized();
|
||||
Emit("enter-html-full-screen");
|
||||
}
|
||||
CommonWebContentsDelegate::EnterFullscreenModeForTab(source, origin);
|
||||
Emit("enter-html-full-screen");
|
||||
}
|
||||
|
||||
void WebContents::ExitFullscreenModeForTab(content::WebContents* source) {
|
||||
auto window = GetWindowFromGuest(source);
|
||||
if (window) {
|
||||
window->SetHtmlApiFullscreen(false);
|
||||
window->NotifyWindowLeaveHtmlFullScreen();
|
||||
source->GetRenderViewHost()->WasResized();
|
||||
Emit("leave-html-full-screen");
|
||||
}
|
||||
CommonWebContentsDelegate::ExitFullscreenModeForTab(source);
|
||||
Emit("leave-html-full-screen");
|
||||
}
|
||||
|
||||
bool WebContents::IsFullscreenForTabOrPending(
|
||||
const content::WebContents* source) const {
|
||||
auto window = GetWindowFromGuest(source);
|
||||
if (window)
|
||||
return window->is_html_api_fullscreen();
|
||||
else
|
||||
return false;
|
||||
void WebContents::RendererUnresponsive(content::WebContents* source) {
|
||||
Emit("unresponsive");
|
||||
if (type_ == BROWSER_WINDOW)
|
||||
owner_window()->RendererUnresponsive(source);
|
||||
}
|
||||
|
||||
void WebContents::RendererResponsive(content::WebContents* source) {
|
||||
Emit("responsive");
|
||||
if (type_ == BROWSER_WINDOW)
|
||||
owner_window()->RendererResponsive(source);
|
||||
}
|
||||
|
||||
void WebContents::BeforeUnloadFired(const base::TimeTicks& proceed_time) {
|
||||
// Do nothing, we override this method just to avoid compilation error since
|
||||
// there are two virtual functions named BeforeUnloadFired.
|
||||
}
|
||||
|
||||
void WebContents::RenderViewDeleted(content::RenderViewHost* render_view_host) {
|
||||
Emit("render-view-deleted",
|
||||
render_view_host->GetProcess()->GetID(),
|
||||
render_view_host->GetRoutingID());
|
||||
int process_id = render_view_host->GetProcess()->GetID();
|
||||
Emit("render-view-deleted", process_id);
|
||||
|
||||
// process.emit('ATOM_BROWSER_RELEASE_RENDER_VIEW', processId);
|
||||
// Tell the rpc server that a render view has been deleted and we need to
|
||||
// release all objects owned by it.
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
node::Environment* env = node::Environment::GetCurrent(isolate());
|
||||
mate::EmitEvent(isolate(), env->process_object(),
|
||||
"ATOM_BROWSER_RELEASE_RENDER_VIEW", process_id);
|
||||
}
|
||||
|
||||
void WebContents::RenderProcessGone(base::TerminationStatus status) {
|
||||
@@ -266,11 +339,6 @@ void WebContents::PluginCrashed(const base::FilePath& plugin_path,
|
||||
Emit("plugin-crashed", info.name, info.version);
|
||||
}
|
||||
|
||||
void WebContents::OnGpuProcessCrashed(base::TerminationStatus exit_code) {
|
||||
if (exit_code == base::TERMINATION_STATUS_PROCESS_CRASHED)
|
||||
Emit("gpu-crashed");
|
||||
}
|
||||
|
||||
void WebContents::DocumentLoadedInFrame(
|
||||
content::RenderFrameHost* render_frame_host) {
|
||||
if (!render_frame_host->GetParent())
|
||||
@@ -312,18 +380,29 @@ void WebContents::DidStopLoading() {
|
||||
|
||||
void WebContents::DidGetResourceResponseStart(
|
||||
const content::ResourceRequestDetails& details) {
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
mate::Dictionary response_headers(isolate, v8::Object::New(isolate));
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
base::DictionaryValue response_headers;
|
||||
|
||||
net::HttpResponseHeaders* headers = details.response_info.headers.get();
|
||||
net::HttpResponseHeaders* headers = details.headers.get();
|
||||
if (!headers)
|
||||
return;
|
||||
void* iter = nullptr;
|
||||
std::string key;
|
||||
std::string value;
|
||||
while (headers && headers->EnumerateHeaderLines(&iter, &key, &value))
|
||||
response_headers.Set(base::StringToLowerASCII(key),
|
||||
base::StringToLowerASCII(value));
|
||||
while (headers->EnumerateHeaderLines(&iter, &key, &value)) {
|
||||
key = base::StringToLowerASCII(key);
|
||||
value = base::StringToLowerASCII(value);
|
||||
if (response_headers.HasKey(key)) {
|
||||
base::ListValue* values = nullptr;
|
||||
if (response_headers.GetList(key, &values))
|
||||
values->AppendString(value);
|
||||
} else {
|
||||
scoped_ptr<base::ListValue> values(new base::ListValue());
|
||||
values->AppendString(value);
|
||||
response_headers.Set(key, values.Pass());
|
||||
}
|
||||
}
|
||||
|
||||
Emit("did-get-response-details",
|
||||
details.socket_address.IsEmpty(),
|
||||
@@ -383,29 +462,11 @@ bool WebContents::OnMessageReceived(const IPC::Message& message) {
|
||||
return handled;
|
||||
}
|
||||
|
||||
void WebContents::RenderViewReady() {
|
||||
if (!is_guest())
|
||||
return;
|
||||
|
||||
// We don't want to accidentally set the opacity of an interstitial page.
|
||||
// WebContents::GetRenderWidgetHostView will return the RWHV of an
|
||||
// interstitial page if one is showing at this time. We only want opacity
|
||||
// to apply to web pages.
|
||||
if (guest_opaque_) {
|
||||
web_contents()
|
||||
->GetRenderViewHost()
|
||||
->GetView()
|
||||
->SetBackgroundColorToDefault();
|
||||
} else {
|
||||
web_contents()->GetRenderViewHost()->GetView()->SetBackgroundColor(
|
||||
SK_ColorTRANSPARENT);
|
||||
}
|
||||
}
|
||||
|
||||
void WebContents::WebContentsDestroyed() {
|
||||
// The RenderViewDeleted was not called when the WebContents is destroyed.
|
||||
RenderViewDeleted(web_contents()->GetRenderViewHost());
|
||||
Emit("destroyed");
|
||||
RemoveFromWeakMap();
|
||||
}
|
||||
|
||||
void WebContents::NavigationEntryCommitted(
|
||||
@@ -414,51 +475,15 @@ void WebContents::NavigationEntryCommitted(
|
||||
details.is_in_page, details.did_replace_entry);
|
||||
}
|
||||
|
||||
void WebContents::DidAttach(int guest_proxy_routing_id) {
|
||||
Emit("did-attach");
|
||||
}
|
||||
|
||||
void WebContents::ElementSizeChanged(const gfx::Size& size) {
|
||||
element_size_ = size;
|
||||
|
||||
// Only resize if needed.
|
||||
if (!size.IsEmpty())
|
||||
guest_host_->SizeContents(size);
|
||||
}
|
||||
|
||||
content::WebContents* WebContents::GetOwnerWebContents() const {
|
||||
return embedder_web_contents_;
|
||||
}
|
||||
|
||||
void WebContents::GuestSizeChanged(const gfx::Size& new_size) {
|
||||
if (!auto_size_enabled_)
|
||||
return;
|
||||
GuestSizeChangedDueToAutoSize(guest_size_, new_size);
|
||||
guest_size_ = new_size;
|
||||
}
|
||||
|
||||
void WebContents::SetGuestHost(content::GuestHost* guest_host) {
|
||||
guest_host_ = guest_host;
|
||||
}
|
||||
|
||||
void WebContents::WillAttach(content::WebContents* embedder_web_contents,
|
||||
int element_instance_id,
|
||||
bool is_full_page_plugin) {
|
||||
embedder_web_contents_ = embedder_web_contents;
|
||||
element_instance_id_ = element_instance_id;
|
||||
}
|
||||
|
||||
void WebContents::Destroy() {
|
||||
if (storage_) {
|
||||
if (type_ == WEB_VIEW && managed_web_contents()) {
|
||||
// When force destroying the "destroyed" event is not emitted.
|
||||
WebContentsDestroyed();
|
||||
|
||||
// Give the content module an opportunity to perform some cleanup.
|
||||
guest_host_->WillDestroy();
|
||||
guest_host_ = nullptr;
|
||||
guest_delegate_->Destroy();
|
||||
|
||||
Observe(nullptr);
|
||||
storage_.reset();
|
||||
DestroyWebContents();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -466,16 +491,24 @@ bool WebContents::IsAlive() const {
|
||||
return web_contents() != NULL;
|
||||
}
|
||||
|
||||
int WebContents::GetID() const {
|
||||
return web_contents()->GetRenderProcessHost()->GetID();
|
||||
}
|
||||
|
||||
bool WebContents::Equal(const WebContents* web_contents) const {
|
||||
return GetID() == web_contents->GetID();
|
||||
}
|
||||
|
||||
void WebContents::LoadURL(const GURL& url, const mate::Dictionary& options) {
|
||||
content::NavigationController::LoadURLParams params(url);
|
||||
|
||||
GURL http_referrer;
|
||||
if (options.Get("httpreferrer", &http_referrer))
|
||||
if (options.Get("httpReferrer", &http_referrer))
|
||||
params.referrer = content::Referrer(http_referrer.GetAsReferrer(),
|
||||
blink::WebReferrerPolicyDefault);
|
||||
|
||||
std::string user_agent;
|
||||
if (options.Get("useragent", &user_agent))
|
||||
if (options.Get("userAgent", &user_agent))
|
||||
SetUserAgent(user_agent);
|
||||
|
||||
params.transition_type = ui::PAGE_TRANSITION_TYPED;
|
||||
@@ -519,50 +552,161 @@ void WebContents::GoToOffset(int offset) {
|
||||
web_contents()->GetController().GoToOffset(offset);
|
||||
}
|
||||
|
||||
int WebContents::GetRoutingID() const {
|
||||
return web_contents()->GetRoutingID();
|
||||
}
|
||||
|
||||
int WebContents::GetProcessID() const {
|
||||
return web_contents()->GetRenderProcessHost()->GetID();
|
||||
}
|
||||
|
||||
bool WebContents::IsCrashed() const {
|
||||
return web_contents()->IsCrashed();
|
||||
}
|
||||
|
||||
void WebContents::SetUserAgent(const std::string& user_agent) {
|
||||
web_contents()->SetUserAgentOverride(user_agent);
|
||||
scoped_refptr<net::URLRequestContextGetter> getter =
|
||||
web_contents()->GetBrowserContext()->GetRequestContext();
|
||||
getter->GetNetworkTaskRunner()->PostTask(FROM_HERE,
|
||||
base::Bind(&SetUserAgentInIO, getter, user_agent));
|
||||
}
|
||||
|
||||
std::string WebContents::GetUserAgent() {
|
||||
return web_contents()->GetUserAgentOverride();
|
||||
}
|
||||
|
||||
void WebContents::InsertCSS(const std::string& css) {
|
||||
web_contents()->InsertCSS(css);
|
||||
}
|
||||
|
||||
void WebContents::ExecuteJavaScript(const base::string16& code) {
|
||||
web_contents()->GetMainFrame()->ExecuteJavaScript(code);
|
||||
void WebContents::ExecuteJavaScript(const base::string16& code,
|
||||
bool has_user_gesture) {
|
||||
Send(new AtomViewMsg_ExecuteJavaScript(routing_id(), code, has_user_gesture));
|
||||
}
|
||||
|
||||
void WebContents::OpenDevTools() {
|
||||
storage_->SetCanDock(false);
|
||||
storage_->ShowDevTools();
|
||||
void WebContents::OpenDevTools(mate::Arguments* args) {
|
||||
if (type_ == REMOTE)
|
||||
return;
|
||||
|
||||
bool detach = false;
|
||||
if (type_ == WEB_VIEW) {
|
||||
detach = true;
|
||||
} else if (args && args->Length() == 1) {
|
||||
mate::Dictionary options;
|
||||
args->GetNext(&options) && options.Get("detach", &detach);
|
||||
}
|
||||
managed_web_contents()->SetCanDock(!detach);
|
||||
managed_web_contents()->ShowDevTools();
|
||||
}
|
||||
|
||||
void WebContents::CloseDevTools() {
|
||||
storage_->CloseDevTools();
|
||||
if (type_ == REMOTE)
|
||||
return;
|
||||
|
||||
managed_web_contents()->CloseDevTools();
|
||||
}
|
||||
|
||||
bool WebContents::IsDevToolsOpened() {
|
||||
return storage_->IsDevToolsViewShowing();
|
||||
if (type_ == REMOTE)
|
||||
return false;
|
||||
|
||||
return managed_web_contents()->IsDevToolsViewShowing();
|
||||
}
|
||||
|
||||
void WebContents::ToggleDevTools() {
|
||||
if (IsDevToolsOpened())
|
||||
CloseDevTools();
|
||||
else
|
||||
OpenDevTools(nullptr);
|
||||
}
|
||||
|
||||
void WebContents::InspectElement(int x, int y) {
|
||||
OpenDevTools();
|
||||
if (type_ == REMOTE)
|
||||
return;
|
||||
|
||||
OpenDevTools(nullptr);
|
||||
scoped_refptr<content::DevToolsAgentHost> agent(
|
||||
content::DevToolsAgentHost::GetOrCreateFor(storage_->GetWebContents()));
|
||||
content::DevToolsAgentHost::GetOrCreateFor(web_contents()));
|
||||
agent->InspectElement(x, y);
|
||||
}
|
||||
|
||||
void WebContents::InspectServiceWorker() {
|
||||
if (type_ == REMOTE)
|
||||
return;
|
||||
|
||||
for (const auto& agent_host : content::DevToolsAgentHost::GetOrCreateAll()) {
|
||||
if (agent_host->GetType() ==
|
||||
content::DevToolsAgentHost::TYPE_SERVICE_WORKER) {
|
||||
OpenDevTools(nullptr);
|
||||
managed_web_contents()->AttachTo(agent_host);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> WebContents::Session(v8::Isolate* isolate) {
|
||||
if (session_.IsEmpty()) {
|
||||
auto handle = Session::CreateFrom(isolate, GetBrowserContext());
|
||||
session_.Reset(isolate, handle.ToV8());
|
||||
}
|
||||
return v8::Local<v8::Value>::New(isolate, session_);
|
||||
}
|
||||
|
||||
void WebContents::HasServiceWorker(
|
||||
const base::Callback<void(bool)>& callback) {
|
||||
auto context = GetServiceWorkerContext(web_contents());
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
context->CheckHasServiceWorker(web_contents()->GetLastCommittedURL(),
|
||||
GURL::EmptyGURL(),
|
||||
callback);
|
||||
}
|
||||
|
||||
void WebContents::UnregisterServiceWorker(
|
||||
const base::Callback<void(bool)>& callback) {
|
||||
auto context = GetServiceWorkerContext(web_contents());
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
context->UnregisterServiceWorker(web_contents()->GetLastCommittedURL(),
|
||||
callback);
|
||||
}
|
||||
|
||||
void WebContents::SetAudioMuted(bool muted) {
|
||||
web_contents()->SetAudioMuted(muted);
|
||||
}
|
||||
|
||||
bool WebContents::IsAudioMuted() {
|
||||
return web_contents()->IsAudioMuted();
|
||||
}
|
||||
|
||||
void WebContents::Print(mate::Arguments* args) {
|
||||
PrintSettings settings = { false, false };
|
||||
if (args->Length() == 1 && !args->GetNext(&settings)) {
|
||||
args->ThrowError();
|
||||
return;
|
||||
}
|
||||
|
||||
printing::PrintViewManagerBasic::FromWebContents(web_contents())->
|
||||
PrintNow(settings.silent, settings.print_background);
|
||||
}
|
||||
|
||||
void WebContents::PrintToPDF(const base::DictionaryValue& setting,
|
||||
const PrintToPDFCallback& callback) {
|
||||
printing::PrintPreviewMessageHandler::FromWebContents(web_contents())->
|
||||
PrintToPDF(setting, callback);
|
||||
}
|
||||
|
||||
void WebContents::AddWorkSpace(const base::FilePath& path) {
|
||||
if (path.empty()) {
|
||||
node::ThrowError(isolate(), "path cannot be empty");
|
||||
return;
|
||||
}
|
||||
DevToolsAddFileSystem(path);
|
||||
}
|
||||
|
||||
void WebContents::RemoveWorkSpace(const base::FilePath& path) {
|
||||
if (path.empty()) {
|
||||
node::ThrowError(isolate(), "path cannot be empty");
|
||||
return;
|
||||
}
|
||||
DevToolsRemoveFileSystem(path);
|
||||
}
|
||||
|
||||
void WebContents::Undo() {
|
||||
web_contents()->Undo();
|
||||
}
|
||||
@@ -607,95 +751,41 @@ void WebContents::ReplaceMisspelling(const base::string16& word) {
|
||||
web_contents()->ReplaceMisspelling(word);
|
||||
}
|
||||
|
||||
void WebContents::Focus() {
|
||||
web_contents()->Focus();
|
||||
}
|
||||
|
||||
void WebContents::TabTraverse(bool reverse) {
|
||||
web_contents()->FocusThroughTabTraversal(reverse);
|
||||
}
|
||||
|
||||
bool WebContents::SendIPCMessage(const base::string16& channel,
|
||||
const base::ListValue& args) {
|
||||
return Send(new AtomViewMsg_Message(routing_id(), channel, args));
|
||||
}
|
||||
|
||||
void WebContents::SetAutoSize(bool enabled,
|
||||
const gfx::Size& min_size,
|
||||
const gfx::Size& max_size) {
|
||||
min_auto_size_ = min_size;
|
||||
min_auto_size_.SetToMin(max_size);
|
||||
max_auto_size_ = max_size;
|
||||
max_auto_size_.SetToMax(min_size);
|
||||
|
||||
enabled &= !min_auto_size_.IsEmpty() && !max_auto_size_.IsEmpty();
|
||||
if (!enabled && !auto_size_enabled_)
|
||||
return;
|
||||
|
||||
auto_size_enabled_ = enabled;
|
||||
|
||||
if (!attached())
|
||||
return;
|
||||
|
||||
content::RenderViewHost* rvh = web_contents()->GetRenderViewHost();
|
||||
if (auto_size_enabled_) {
|
||||
rvh->EnableAutoResize(min_auto_size_, max_auto_size_);
|
||||
} else {
|
||||
rvh->DisableAutoResize(element_size_);
|
||||
guest_size_ = element_size_;
|
||||
GuestSizeChangedDueToAutoSize(guest_size_, element_size_);
|
||||
}
|
||||
void WebContents::SetSize(const SetSizeParams& params) {
|
||||
if (guest_delegate_)
|
||||
guest_delegate_->SetSize(params);
|
||||
}
|
||||
|
||||
void WebContents::SetAllowTransparency(bool allow) {
|
||||
if (guest_opaque_ != allow)
|
||||
return;
|
||||
|
||||
guest_opaque_ = !allow;
|
||||
if (!web_contents()->GetRenderViewHost()->GetView())
|
||||
return;
|
||||
|
||||
if (guest_opaque_) {
|
||||
web_contents()
|
||||
->GetRenderViewHost()
|
||||
->GetView()
|
||||
->SetBackgroundColorToDefault();
|
||||
} else {
|
||||
web_contents()->GetRenderViewHost()->GetView()->SetBackgroundColor(
|
||||
SK_ColorTRANSPARENT);
|
||||
}
|
||||
if (guest_delegate_)
|
||||
guest_delegate_->SetAllowTransparency(allow);
|
||||
}
|
||||
|
||||
void WebContents::HasServiceWorker(
|
||||
const base::Callback<void(bool)>& callback) {
|
||||
auto context = GetServiceWorkerContext(web_contents());
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
context->CheckHasServiceWorker(web_contents()->GetLastCommittedURL(),
|
||||
GURL::EmptyGURL(),
|
||||
callback);
|
||||
}
|
||||
|
||||
void WebContents::UnregisterServiceWorker(
|
||||
const base::Callback<void(bool)>& callback) {
|
||||
auto context = GetServiceWorkerContext(web_contents());
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
context->UnregisterServiceWorker(web_contents()->GetLastCommittedURL(),
|
||||
callback);
|
||||
}
|
||||
|
||||
void WebContents::InspectServiceWorker() {
|
||||
for (const auto& agent_host : content::DevToolsAgentHost::GetOrCreateAll()) {
|
||||
if (agent_host->GetType() ==
|
||||
content::DevToolsAgentHost::TYPE_SERVICE_WORKER) {
|
||||
OpenDevTools();
|
||||
storage_->AttachTo(agent_host);
|
||||
break;
|
||||
}
|
||||
}
|
||||
bool WebContents::IsGuest() const {
|
||||
return type_ == WEB_VIEW;
|
||||
}
|
||||
|
||||
mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) {
|
||||
if (template_.IsEmpty())
|
||||
template_.Reset(isolate, mate::ObjectTemplateBuilder(isolate)
|
||||
.SetMethod("destroy", &WebContents::Destroy)
|
||||
.SetMethod("isAlive", &WebContents::IsAlive)
|
||||
.SetMethod("destroy", &WebContents::Destroy, true)
|
||||
.SetMethod("isAlive", &WebContents::IsAlive, true)
|
||||
.SetMethod("getId", &WebContents::GetID)
|
||||
.SetMethod("equal", &WebContents::Equal)
|
||||
.SetMethod("_loadUrl", &WebContents::LoadURL)
|
||||
.SetMethod("getTitle", &WebContents::GetTitle)
|
||||
.SetMethod("isLoading", &WebContents::IsLoading)
|
||||
@@ -705,16 +795,18 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
|
||||
.SetMethod("_goBack", &WebContents::GoBack)
|
||||
.SetMethod("_goForward", &WebContents::GoForward)
|
||||
.SetMethod("_goToOffset", &WebContents::GoToOffset)
|
||||
.SetMethod("getRoutingId", &WebContents::GetRoutingID)
|
||||
.SetMethod("getProcessId", &WebContents::GetProcessID)
|
||||
.SetMethod("isCrashed", &WebContents::IsCrashed)
|
||||
.SetMethod("setUserAgent", &WebContents::SetUserAgent)
|
||||
.SetMethod("getUserAgent", &WebContents::GetUserAgent)
|
||||
.SetMethod("insertCSS", &WebContents::InsertCSS)
|
||||
.SetMethod("_executeJavaScript", &WebContents::ExecuteJavaScript)
|
||||
.SetMethod("openDevTools", &WebContents::OpenDevTools)
|
||||
.SetMethod("closeDevTools", &WebContents::CloseDevTools)
|
||||
.SetMethod("isDevToolsOpened", &WebContents::IsDevToolsOpened)
|
||||
.SetMethod("toggleDevTools", &WebContents::ToggleDevTools)
|
||||
.SetMethod("inspectElement", &WebContents::InspectElement)
|
||||
.SetMethod("setAudioMuted", &WebContents::SetAudioMuted)
|
||||
.SetMethod("isAudioMuted", &WebContents::IsAudioMuted)
|
||||
.SetMethod("undo", &WebContents::Undo)
|
||||
.SetMethod("redo", &WebContents::Redo)
|
||||
.SetMethod("cut", &WebContents::Cut)
|
||||
@@ -726,20 +818,35 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
|
||||
.SetMethod("unselect", &WebContents::Unselect)
|
||||
.SetMethod("replace", &WebContents::Replace)
|
||||
.SetMethod("replaceMisspelling", &WebContents::ReplaceMisspelling)
|
||||
.SetMethod("_send", &WebContents::SendIPCMessage)
|
||||
.SetMethod("setAutoSize", &WebContents::SetAutoSize)
|
||||
.SetMethod("focus", &WebContents::Focus)
|
||||
.SetMethod("tabTraverse", &WebContents::TabTraverse)
|
||||
.SetMethod("_send", &WebContents::SendIPCMessage, true)
|
||||
.SetMethod("setSize", &WebContents::SetSize)
|
||||
.SetMethod("setAllowTransparency", &WebContents::SetAllowTransparency)
|
||||
.SetMethod("isGuest", &WebContents::is_guest)
|
||||
.SetMethod("isGuest", &WebContents::IsGuest)
|
||||
.SetMethod("hasServiceWorker", &WebContents::HasServiceWorker)
|
||||
.SetMethod("unregisterServiceWorker",
|
||||
&WebContents::UnregisterServiceWorker)
|
||||
.SetMethod("inspectServiceWorker", &WebContents::InspectServiceWorker)
|
||||
.SetMethod("print", &WebContents::Print)
|
||||
.SetMethod("_printToPDF", &WebContents::PrintToPDF)
|
||||
.SetMethod("addWorkSpace", &WebContents::AddWorkSpace)
|
||||
.SetMethod("removeWorkSpace", &WebContents::RemoveWorkSpace)
|
||||
.SetProperty("session", &WebContents::Session)
|
||||
.Build());
|
||||
|
||||
return mate::ObjectTemplateBuilder(
|
||||
isolate, v8::Local<v8::ObjectTemplate>::New(isolate, template_));
|
||||
}
|
||||
|
||||
bool WebContents::IsDestroyed() const {
|
||||
return !IsAlive();
|
||||
}
|
||||
|
||||
AtomBrowserContext* WebContents::GetBrowserContext() const {
|
||||
return static_cast<AtomBrowserContext*>(web_contents()->GetBrowserContext());
|
||||
}
|
||||
|
||||
void WebContents::OnRendererMessage(const base::string16& channel,
|
||||
const base::ListValue& args) {
|
||||
// webContents.emit(channel, new Event(), args...);
|
||||
@@ -753,23 +860,34 @@ void WebContents::OnRendererMessageSync(const base::string16& channel,
|
||||
EmitWithSender(base::UTF16ToUTF8(channel), web_contents(), message, args);
|
||||
}
|
||||
|
||||
void WebContents::GuestSizeChangedDueToAutoSize(const gfx::Size& old_size,
|
||||
const gfx::Size& new_size) {
|
||||
Emit("size-changed",
|
||||
old_size.width(), old_size.height(),
|
||||
new_size.width(), new_size.height());
|
||||
}
|
||||
|
||||
// static
|
||||
mate::Handle<WebContents> WebContents::CreateFrom(
|
||||
v8::Isolate* isolate, content::WebContents* web_contents) {
|
||||
return mate::CreateHandle(isolate, new WebContents(web_contents));
|
||||
// We have an existing WebContents object in JS.
|
||||
auto existing = TrackableObject::FromWrappedClass(isolate, web_contents);
|
||||
if (existing)
|
||||
return mate::CreateHandle(isolate, static_cast<WebContents*>(existing));
|
||||
|
||||
// Otherwise create a new WebContents wrapper object.
|
||||
auto handle = mate::CreateHandle(isolate, new WebContents(web_contents));
|
||||
g_wrap_web_contents.Run(handle.ToV8());
|
||||
return handle;
|
||||
}
|
||||
|
||||
// static
|
||||
mate::Handle<WebContents> WebContents::Create(
|
||||
v8::Isolate* isolate, const mate::Dictionary& options) {
|
||||
return mate::CreateHandle(isolate, new WebContents(options));
|
||||
auto handle = mate::CreateHandle(isolate, new WebContents(options));
|
||||
g_wrap_web_contents.Run(handle.ToV8());
|
||||
return handle;
|
||||
}
|
||||
|
||||
void SetWrapWebContents(const WrapWebContentsCallback& callback) {
|
||||
g_wrap_web_contents = callback;
|
||||
}
|
||||
|
||||
void ClearWrapWebContents() {
|
||||
g_wrap_web_contents.Reset();
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
@@ -784,6 +902,8 @@ void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
mate::Dictionary dict(isolate, exports);
|
||||
dict.SetMethod("create", &atom::api::WebContents::Create);
|
||||
dict.SetMethod("_setWrapWebContents", &atom::api::SetWrapWebContents);
|
||||
dict.SetMethod("_clearWrapWebContents", &atom::api::ClearWrapWebContents);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -8,13 +8,10 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/browser/api/event_emitter.h"
|
||||
#include "brightray/browser/default_web_contents_delegate.h"
|
||||
#include "content/public/browser/browser_plugin_guest_delegate.h"
|
||||
#include "atom/browser/api/trackable_object.h"
|
||||
#include "atom/browser/common_web_contents_delegate.h"
|
||||
#include "content/public/common/favicon_url.h"
|
||||
#include "content/public/browser/web_contents_delegate.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
#include "content/public/browser/gpu_data_manager_observer.h"
|
||||
#include "native_mate/handle.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
|
||||
@@ -23,22 +20,26 @@ class InspectableWebContents;
|
||||
}
|
||||
|
||||
namespace mate {
|
||||
class Arguments;
|
||||
class Dictionary;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomJavaScriptDialogManager;
|
||||
class WebDialogHelper;
|
||||
struct SetSizeParams;
|
||||
class AtomBrowserContext;
|
||||
class WebViewGuestDelegate;
|
||||
|
||||
namespace api {
|
||||
|
||||
class WebContents : public mate::EventEmitter,
|
||||
public content::BrowserPluginGuestDelegate,
|
||||
public content::WebContentsDelegate,
|
||||
public content::WebContentsObserver,
|
||||
public content::GpuDataManagerObserver {
|
||||
class WebContents : public mate::TrackableObject<WebContents>,
|
||||
public CommonWebContentsDelegate,
|
||||
public content::WebContentsObserver {
|
||||
public:
|
||||
// For node.js callback function type: function(error, buffer)
|
||||
using PrintToPDFCallback =
|
||||
base::Callback<void(v8::Local<v8::Value>, v8::Local<v8::Value>)>;
|
||||
|
||||
// Create from an existing WebContents.
|
||||
static mate::Handle<WebContents> CreateFrom(
|
||||
v8::Isolate* isolate, content::WebContents* web_contents);
|
||||
@@ -49,6 +50,8 @@ class WebContents : public mate::EventEmitter,
|
||||
|
||||
void Destroy();
|
||||
bool IsAlive() const;
|
||||
int GetID() const;
|
||||
bool Equal(const WebContents* web_contents) const;
|
||||
void LoadURL(const GURL& url, const mate::Dictionary& options);
|
||||
base::string16 GetTitle() const;
|
||||
bool IsLoading() const;
|
||||
@@ -58,19 +61,32 @@ class WebContents : public mate::EventEmitter,
|
||||
void GoBack();
|
||||
void GoForward();
|
||||
void GoToOffset(int offset);
|
||||
int GetRoutingID() const;
|
||||
int GetProcessID() const;
|
||||
bool IsCrashed() const;
|
||||
void SetUserAgent(const std::string& user_agent);
|
||||
std::string GetUserAgent();
|
||||
void InsertCSS(const std::string& css);
|
||||
void ExecuteJavaScript(const base::string16& code);
|
||||
void OpenDevTools();
|
||||
void ExecuteJavaScript(const base::string16& code,
|
||||
bool has_user_gesture);
|
||||
void OpenDevTools(mate::Arguments* args);
|
||||
void CloseDevTools();
|
||||
bool IsDevToolsOpened();
|
||||
void ToggleDevTools();
|
||||
void InspectElement(int x, int y);
|
||||
void InspectServiceWorker();
|
||||
v8::Local<v8::Value> Session(v8::Isolate* isolate);
|
||||
void HasServiceWorker(const base::Callback<void(bool)>&);
|
||||
void UnregisterServiceWorker(const base::Callback<void(bool)>&);
|
||||
void InspectServiceWorker();
|
||||
void SetAudioMuted(bool muted);
|
||||
bool IsAudioMuted();
|
||||
void Print(mate::Arguments* args);
|
||||
|
||||
// Print current page as PDF.
|
||||
void PrintToPDF(const base::DictionaryValue& setting,
|
||||
const PrintToPDFCallback& callback);
|
||||
|
||||
// DevTools workspace api.
|
||||
void AddWorkSpace(const base::FilePath& path);
|
||||
void RemoveWorkSpace(const base::FilePath& path);
|
||||
|
||||
// Editing commands.
|
||||
void Undo();
|
||||
@@ -85,27 +101,18 @@ class WebContents : public mate::EventEmitter,
|
||||
void Replace(const base::string16& word);
|
||||
void ReplaceMisspelling(const base::string16& word);
|
||||
|
||||
// Focus.
|
||||
void Focus();
|
||||
void TabTraverse(bool reverse);
|
||||
|
||||
// Sending messages to browser.
|
||||
bool SendIPCMessage(const base::string16& channel,
|
||||
const base::ListValue& args);
|
||||
|
||||
// Toggles autosize mode for corresponding <webview>.
|
||||
void SetAutoSize(bool enabled,
|
||||
const gfx::Size& min_size,
|
||||
const gfx::Size& max_size);
|
||||
|
||||
// Sets the transparency of the guest.
|
||||
// Methods for creating <webview>.
|
||||
void SetSize(const SetSizeParams& params);
|
||||
void SetAllowTransparency(bool allow);
|
||||
|
||||
// Returns whether this is a guest view.
|
||||
bool is_guest() const { return guest_instance_id_ != -1; }
|
||||
|
||||
// Returns whether this guest has an associated embedder.
|
||||
bool attached() const { return !!embedder_web_contents_; }
|
||||
|
||||
content::WebContents* web_contents() const {
|
||||
return content::WebContentsObserver::web_contents();
|
||||
}
|
||||
bool IsGuest() const;
|
||||
|
||||
protected:
|
||||
explicit WebContents(content::WebContents* web_contents);
|
||||
@@ -115,6 +122,7 @@ class WebContents : public mate::EventEmitter,
|
||||
// mate::Wrappable:
|
||||
mate::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) override;
|
||||
bool IsDestroyed() const override;
|
||||
|
||||
// content::WebContentsDelegate:
|
||||
bool AddMessageToConsole(content::WebContents* source,
|
||||
@@ -131,34 +139,28 @@ class WebContents : public mate::EventEmitter,
|
||||
const GURL& target_url,
|
||||
const std::string& partition_id,
|
||||
content::SessionStorageNamespace* session_storage_namespace) override;
|
||||
void CloseContents(content::WebContents* source) override;
|
||||
content::WebContents* OpenURLFromTab(
|
||||
content::WebContents* source,
|
||||
const content::OpenURLParams& params) override;
|
||||
content::JavaScriptDialogManager* GetJavaScriptDialogManager(
|
||||
content::WebContents* source) override;
|
||||
void RunFileChooser(content::WebContents* web_contents,
|
||||
const content::FileChooserParams& params) override;
|
||||
void EnumerateDirectory(content::WebContents* web_contents,
|
||||
int request_id,
|
||||
const base::FilePath& path) override;
|
||||
bool CheckMediaAccessPermission(content::WebContents* web_contents,
|
||||
const GURL& security_origin,
|
||||
content::MediaStreamType type) override;
|
||||
void RequestMediaAccessPermission(
|
||||
content::WebContents*,
|
||||
const content::MediaStreamRequest&,
|
||||
const content::MediaResponseCallback&) override;
|
||||
void BeforeUnloadFired(content::WebContents* tab,
|
||||
bool proceed,
|
||||
bool* proceed_to_fire_unload) override;
|
||||
void MoveContents(content::WebContents* source,
|
||||
const gfx::Rect& pos) override;
|
||||
void CloseContents(content::WebContents* source) override;
|
||||
void ActivateContents(content::WebContents* contents) override;
|
||||
bool IsPopupOrPanel(const content::WebContents* source) const override;
|
||||
void HandleKeyboardEvent(
|
||||
content::WebContents* source,
|
||||
const content::NativeWebKeyboardEvent& event) override;
|
||||
void EnterFullscreenModeForTab(content::WebContents* source,
|
||||
const GURL& origin) override;
|
||||
void ExitFullscreenModeForTab(content::WebContents* source) override;
|
||||
bool IsFullscreenForTabOrPending(
|
||||
const content::WebContents* source) const override;
|
||||
void RendererUnresponsive(content::WebContents* source) override;
|
||||
void RendererResponsive(content::WebContents* source) override;
|
||||
|
||||
// content::WebContentsObserver:
|
||||
void BeforeUnloadFired(const base::TimeTicks& proceed_time) override;
|
||||
void RenderViewDeleted(content::RenderViewHost*) override;
|
||||
void RenderProcessGone(base::TerminationStatus status) override;
|
||||
void DocumentLoadedInFrame(
|
||||
@@ -184,7 +186,6 @@ class WebContents : public mate::EventEmitter,
|
||||
const content::LoadCommittedDetails& details,
|
||||
const content::FrameNavigateParams& params) override;
|
||||
bool OnMessageReceived(const IPC::Message& message) override;
|
||||
void RenderViewReady() override;
|
||||
void WebContentsDestroyed() override;
|
||||
void NavigationEntryCommitted(
|
||||
const content::LoadCommittedDetails& load_details) override;
|
||||
@@ -194,20 +195,15 @@ class WebContents : public mate::EventEmitter,
|
||||
void PluginCrashed(const base::FilePath& plugin_path,
|
||||
base::ProcessId plugin_pid) override;
|
||||
|
||||
// content::BrowserPluginGuestDelegate:
|
||||
void DidAttach(int guest_proxy_routing_id) final;
|
||||
void ElementSizeChanged(const gfx::Size& size) final;
|
||||
content::WebContents* GetOwnerWebContents() const final;
|
||||
void GuestSizeChanged(const gfx::Size& new_size) final;
|
||||
void SetGuestHost(content::GuestHost* guest_host) final;
|
||||
void WillAttach(content::WebContents* embedder_web_contents,
|
||||
int element_instance_id,
|
||||
bool is_full_page_plugin) final;
|
||||
|
||||
// content::GpuDataManagerObserver:
|
||||
void OnGpuProcessCrashed(base::TerminationStatus exit_code) override;
|
||||
|
||||
private:
|
||||
enum Type {
|
||||
BROWSER_WINDOW, // Used by BrowserWindow.
|
||||
WEB_VIEW, // Used by <webview>.
|
||||
REMOTE, // Thin wrap around an existing WebContents.
|
||||
};
|
||||
|
||||
AtomBrowserContext* GetBrowserContext() const;
|
||||
|
||||
// Called when received a message from renderer.
|
||||
void OnRendererMessage(const base::string16& channel,
|
||||
const base::ListValue& args);
|
||||
@@ -217,46 +213,12 @@ class WebContents : public mate::EventEmitter,
|
||||
const base::ListValue& args,
|
||||
IPC::Message* message);
|
||||
|
||||
void GuestSizeChangedDueToAutoSize(const gfx::Size& old_size,
|
||||
const gfx::Size& new_size);
|
||||
v8::Global<v8::Value> session_;
|
||||
|
||||
scoped_ptr<WebDialogHelper> web_dialog_helper_;
|
||||
scoped_ptr<AtomJavaScriptDialogManager> dialog_manager_;
|
||||
scoped_ptr<WebViewGuestDelegate> guest_delegate_;
|
||||
|
||||
// Unique ID for a guest WebContents.
|
||||
int guest_instance_id_;
|
||||
|
||||
// |element_instance_id_| is an identifer that's unique to a particular
|
||||
// element.
|
||||
int element_instance_id_;
|
||||
|
||||
// Stores whether the contents of the guest can be transparent.
|
||||
bool guest_opaque_;
|
||||
|
||||
// Stores the WebContents that managed by this class.
|
||||
scoped_ptr<brightray::InspectableWebContents> storage_;
|
||||
|
||||
// The WebContents that attaches this guest view.
|
||||
content::WebContents* embedder_web_contents_;
|
||||
|
||||
// The size of the container element.
|
||||
gfx::Size element_size_;
|
||||
|
||||
// The size of the guest content. Note: In autosize mode, the container
|
||||
// element may not match the size of the guest.
|
||||
gfx::Size guest_size_;
|
||||
|
||||
// A pointer to the guest_host.
|
||||
content::GuestHost* guest_host_;
|
||||
|
||||
// Indicates whether autosize mode is enabled or not.
|
||||
bool auto_size_enabled_;
|
||||
|
||||
// The maximum size constraints of the container element in autosize mode.
|
||||
gfx::Size max_auto_size_;
|
||||
|
||||
// The minimum size constraints of the container element in autosize mode.
|
||||
gfx::Size min_auto_size_;
|
||||
// The type of current WebContents.
|
||||
Type type_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WebContents);
|
||||
};
|
||||
|
||||
@@ -4,46 +4,46 @@
|
||||
|
||||
#include "atom/browser/api/atom_api_window.h"
|
||||
|
||||
#include "atom/browser/api/atom_api_menu.h"
|
||||
#include "atom/browser/api/atom_api_web_contents.h"
|
||||
#include "atom/browser/browser.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/gfx_converter.h"
|
||||
#include "atom/common/native_mate_converters/gurl_converter.h"
|
||||
#include "atom/common/native_mate_converters/image_converter.h"
|
||||
#include "atom/common/native_mate_converters/string16_converter.h"
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
#include "native_mate/callback.h"
|
||||
#include "native_mate/constructor.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "ui/gfx/geometry/rect.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "atom/browser/native_window_views.h"
|
||||
#include "atom/browser/ui/win/taskbar_host.h"
|
||||
#endif
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
namespace {
|
||||
|
||||
struct PrintSettings {
|
||||
bool silent;
|
||||
bool print_background;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#if defined(OS_WIN)
|
||||
namespace mate {
|
||||
|
||||
template<>
|
||||
struct Converter<PrintSettings> {
|
||||
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
|
||||
PrintSettings* out) {
|
||||
struct Converter<atom::TaskbarHost::ThumbarButton> {
|
||||
static bool FromV8(v8::Isolate* isolate, v8::Handle<v8::Value> val,
|
||||
atom::TaskbarHost::ThumbarButton* out) {
|
||||
mate::Dictionary dict;
|
||||
if (!ConvertFromV8(isolate, val, &dict))
|
||||
return false;
|
||||
dict.Get("silent", &(out->silent));
|
||||
dict.Get("printBackground", &(out->print_background));
|
||||
return true;
|
||||
dict.Get("click", &(out->clicked_callback));
|
||||
dict.Get("tooltip", &(out->tooltip));
|
||||
dict.Get("flags", &out->flags);
|
||||
return dict.Get("icon", &(out->icon));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
#endif
|
||||
|
||||
namespace atom {
|
||||
|
||||
@@ -63,8 +63,17 @@ void OnCapturePageDone(
|
||||
} // namespace
|
||||
|
||||
|
||||
Window::Window(const mate::Dictionary& options)
|
||||
: window_(NativeWindow::Create(options)) {
|
||||
Window::Window(v8::Isolate* isolate, const mate::Dictionary& options) {
|
||||
// Creates the WebContents used by BrowserWindow.
|
||||
mate::Dictionary web_contents_options(isolate, v8::Object::New(isolate));
|
||||
auto web_contents = WebContents::Create(isolate, web_contents_options);
|
||||
web_contents_.Reset(isolate, web_contents.ToV8());
|
||||
api_web_contents_ = web_contents.get();
|
||||
|
||||
// Creates BrowserWindow.
|
||||
window_.reset(NativeWindow::Create(web_contents->managed_web_contents(),
|
||||
options));
|
||||
web_contents->SetOwnerWindow(window_.get());
|
||||
window_->InitFromOptions(options);
|
||||
window_->AddObserver(this);
|
||||
}
|
||||
@@ -79,25 +88,21 @@ void Window::OnPageTitleUpdated(bool* prevent_default,
|
||||
*prevent_default = Emit("page-title-updated", title);
|
||||
}
|
||||
|
||||
void Window::WillCreatePopupWindow(const base::string16& frame_name,
|
||||
const GURL& target_url,
|
||||
const std::string& partition_id,
|
||||
WindowOpenDisposition disposition) {
|
||||
Emit("-new-window", target_url, frame_name, static_cast<int>(disposition));
|
||||
}
|
||||
|
||||
void Window::WillNavigate(bool* prevent_default, const GURL& url) {
|
||||
*prevent_default = Emit("-will-navigate", url);
|
||||
}
|
||||
|
||||
void Window::WillCloseWindow(bool* prevent_default) {
|
||||
*prevent_default = Emit("close");
|
||||
}
|
||||
|
||||
void Window::OnWindowClosed() {
|
||||
Emit("closed");
|
||||
if (api_web_contents_) {
|
||||
api_web_contents_->DestroyWebContents();
|
||||
api_web_contents_ = nullptr;
|
||||
web_contents_.Reset();
|
||||
}
|
||||
|
||||
RemoveFromWeakMap();
|
||||
window_->RemoveObserver(this);
|
||||
|
||||
Emit("closed");
|
||||
}
|
||||
|
||||
void Window::OnWindowBlur() {
|
||||
@@ -164,19 +169,45 @@ void Window::OnDevToolsFocus() {
|
||||
Emit("devtools-focused");
|
||||
}
|
||||
|
||||
void Window::OnDevToolsOpened() {
|
||||
Emit("devtools-opened");
|
||||
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
auto handle = WebContents::CreateFrom(
|
||||
isolate(), api_web_contents_->GetDevToolsWebContents());
|
||||
devtools_web_contents_.Reset(isolate(), handle.ToV8());
|
||||
}
|
||||
|
||||
void Window::OnDevToolsClosed() {
|
||||
Emit("devtools-closed");
|
||||
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
devtools_web_contents_.Reset();
|
||||
}
|
||||
|
||||
void Window::OnExecuteWindowsCommand(const std::string& command_name) {
|
||||
Emit("app-command", command_name);
|
||||
}
|
||||
|
||||
// static
|
||||
mate::Wrappable* Window::New(v8::Isolate* isolate,
|
||||
const mate::Dictionary& options) {
|
||||
if (!Browser::Get()->is_ready()) {
|
||||
node::ThrowError("Cannot create BrowserWindow before app is ready");
|
||||
node::ThrowError(isolate,
|
||||
"Cannot create BrowserWindow before app is ready");
|
||||
return nullptr;
|
||||
}
|
||||
return new Window(options);
|
||||
return new Window(isolate, options);
|
||||
}
|
||||
|
||||
bool Window::IsDestroyed() const {
|
||||
return !window_ || window_->IsClosed();
|
||||
}
|
||||
|
||||
void Window::Destroy() {
|
||||
window_->DestroyWebContents();
|
||||
window_->CloseImmediately();
|
||||
window_->CloseContents(nullptr);
|
||||
}
|
||||
|
||||
void Window::Close() {
|
||||
@@ -355,26 +386,6 @@ bool Window::IsKiosk() {
|
||||
return window_->IsKiosk();
|
||||
}
|
||||
|
||||
void Window::OpenDevTools(bool can_dock) {
|
||||
window_->OpenDevTools(can_dock);
|
||||
}
|
||||
|
||||
void Window::CloseDevTools() {
|
||||
window_->CloseDevTools();
|
||||
}
|
||||
|
||||
bool Window::IsDevToolsOpened() {
|
||||
return window_->IsDevToolsOpened();
|
||||
}
|
||||
|
||||
void Window::InspectElement(int x, int y) {
|
||||
window_->InspectElement(x, y);
|
||||
}
|
||||
|
||||
void Window::InspectServiceWorker() {
|
||||
window_->InspectServiceWorker();
|
||||
}
|
||||
|
||||
void Window::FocusOnWebView() {
|
||||
window_->FocusOnWebView();
|
||||
}
|
||||
@@ -418,16 +429,6 @@ void Window::CapturePage(mate::Arguments* args) {
|
||||
rect, base::Bind(&OnCapturePageDone, args->isolate(), callback));
|
||||
}
|
||||
|
||||
void Window::Print(mate::Arguments* args) {
|
||||
PrintSettings settings = { false, false };;
|
||||
if (args->Length() == 1 && !args->GetNext(&settings)) {
|
||||
args->ThrowError();
|
||||
return;
|
||||
}
|
||||
|
||||
window_->Print(settings.silent, settings.print_background);
|
||||
}
|
||||
|
||||
void Window::SetProgressBar(double progress) {
|
||||
window_->SetProgressBar(progress);
|
||||
}
|
||||
@@ -437,6 +438,37 @@ void Window::SetOverlayIcon(const gfx::Image& overlay,
|
||||
window_->SetOverlayIcon(overlay, description);
|
||||
}
|
||||
|
||||
bool Window::SetThumbarButtons(mate::Arguments* args) {
|
||||
#if defined(OS_WIN)
|
||||
std::vector<TaskbarHost::ThumbarButton> buttons;
|
||||
if (!args->GetNext(&buttons)) {
|
||||
args->ThrowError();
|
||||
return false;
|
||||
}
|
||||
auto window = static_cast<NativeWindowViews*>(window_.get());
|
||||
return window->taskbar_host().SetThumbarButtons(
|
||||
window->GetAcceleratedWidget(), buttons);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Window::SetMenu(v8::Isolate* isolate, v8::Local<v8::Value> value) {
|
||||
mate::Handle<Menu> menu;
|
||||
if (value->IsObject() &&
|
||||
mate::V8ToString(value->ToObject()->GetConstructorName()) == "Menu" &&
|
||||
mate::ConvertFromV8(isolate, value, &menu)) {
|
||||
menu_.Reset(isolate, menu.ToV8());
|
||||
window_->SetMenu(menu->model());
|
||||
} else if (value->IsNull()) {
|
||||
menu_.Reset();
|
||||
window_->SetMenu(nullptr);
|
||||
} else {
|
||||
isolate->ThrowException(v8::Exception::TypeError(
|
||||
mate::StringToV8(isolate, "Invalid Menu")));
|
||||
}
|
||||
}
|
||||
|
||||
void Window::SetAutoHideMenuBar(bool auto_hide) {
|
||||
window_->SetAutoHideMenuBar(auto_hide);
|
||||
}
|
||||
@@ -459,6 +491,12 @@ void Window::ShowDefinitionForSelection() {
|
||||
}
|
||||
#endif
|
||||
|
||||
void Window::SetAspectRatio(double aspect_ratio, mate::Arguments* args) {
|
||||
gfx::Size extra_size;
|
||||
args->GetNext(&extra_size);
|
||||
window_->SetAspectRatio(aspect_ratio, extra_size);
|
||||
}
|
||||
|
||||
void Window::SetVisibleOnAllWorkspaces(bool visible) {
|
||||
return window_->SetVisibleOnAllWorkspaces(visible);
|
||||
}
|
||||
@@ -467,20 +505,29 @@ bool Window::IsVisibleOnAllWorkspaces() {
|
||||
return window_->IsVisibleOnAllWorkspaces();
|
||||
}
|
||||
|
||||
mate::Handle<WebContents> Window::GetWebContents(v8::Isolate* isolate) const {
|
||||
return WebContents::CreateFrom(isolate, window_->GetWebContents());
|
||||
int32_t Window::ID() const {
|
||||
return weak_map_id();
|
||||
}
|
||||
|
||||
mate::Handle<WebContents> Window::GetDevToolsWebContents(
|
||||
v8::Isolate* isolate) const {
|
||||
return WebContents::CreateFrom(isolate, window_->GetDevToolsWebContents());
|
||||
v8::Local<v8::Value> Window::WebContents(v8::Isolate* isolate) {
|
||||
if (web_contents_.IsEmpty())
|
||||
return v8::Null(isolate);
|
||||
else
|
||||
return v8::Local<v8::Value>::New(isolate, web_contents_);
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> Window::DevToolsWebContents(v8::Isolate* isolate) {
|
||||
if (devtools_web_contents_.IsEmpty())
|
||||
return v8::Null(isolate);
|
||||
else
|
||||
return v8::Local<v8::Value>::New(isolate, devtools_web_contents_);
|
||||
}
|
||||
|
||||
// static
|
||||
void Window::BuildPrototype(v8::Isolate* isolate,
|
||||
v8::Local<v8::ObjectTemplate> prototype) {
|
||||
mate::ObjectTemplateBuilder(isolate, prototype)
|
||||
.SetMethod("destroy", &Window::Destroy)
|
||||
.SetMethod("destroy", &Window::Destroy, true)
|
||||
.SetMethod("close", &Window::Close)
|
||||
.SetMethod("isClosed", &Window::IsClosed)
|
||||
.SetMethod("focus", &Window::Focus)
|
||||
@@ -497,6 +544,7 @@ void Window::BuildPrototype(v8::Isolate* isolate,
|
||||
.SetMethod("isMinimized", &Window::IsMinimized)
|
||||
.SetMethod("setFullScreen", &Window::SetFullScreen)
|
||||
.SetMethod("isFullScreen", &Window::IsFullscreen)
|
||||
.SetMethod("setAspectRatio", &Window::SetAspectRatio)
|
||||
.SetMethod("getBounds", &Window::GetBounds)
|
||||
.SetMethod("setBounds", &Window::SetBounds)
|
||||
.SetMethod("getSize", &Window::GetSize)
|
||||
@@ -524,17 +572,14 @@ void Window::BuildPrototype(v8::Isolate* isolate,
|
||||
.SetMethod("getRepresentedFilename", &Window::GetRepresentedFilename)
|
||||
.SetMethod("setDocumentEdited", &Window::SetDocumentEdited)
|
||||
.SetMethod("isDocumentEdited", &Window::IsDocumentEdited)
|
||||
.SetMethod("_openDevTools", &Window::OpenDevTools)
|
||||
.SetMethod("closeDevTools", &Window::CloseDevTools)
|
||||
.SetMethod("isDevToolsOpened", &Window::IsDevToolsOpened)
|
||||
.SetMethod("inspectElement", &Window::InspectElement)
|
||||
.SetMethod("focusOnWebView", &Window::FocusOnWebView)
|
||||
.SetMethod("blurWebView", &Window::BlurWebView)
|
||||
.SetMethod("isWebViewFocused", &Window::IsWebViewFocused)
|
||||
.SetMethod("capturePage", &Window::CapturePage)
|
||||
.SetMethod("print", &Window::Print)
|
||||
.SetMethod("setProgressBar", &Window::SetProgressBar)
|
||||
.SetMethod("setOverlayIcon", &Window::SetOverlayIcon)
|
||||
.SetMethod("setThumbarButtons", &Window::SetThumbarButtons)
|
||||
.SetMethod("setMenu", &Window::SetMenu)
|
||||
.SetMethod("setAutoHideMenuBar", &Window::SetAutoHideMenuBar)
|
||||
.SetMethod("isMenuBarAutoHide", &Window::IsMenuBarAutoHide)
|
||||
.SetMethod("setMenuBarVisibility", &Window::SetMenuBarVisibility)
|
||||
@@ -547,9 +592,9 @@ void Window::BuildPrototype(v8::Isolate* isolate,
|
||||
.SetMethod("showDefinitionForSelection",
|
||||
&Window::ShowDefinitionForSelection)
|
||||
#endif
|
||||
.SetMethod("_getWebContents", &Window::GetWebContents)
|
||||
.SetMethod("_getDevToolsWebContents", &Window::GetDevToolsWebContents)
|
||||
.SetMethod("inspectServiceWorker", &Window::InspectServiceWorker);
|
||||
.SetProperty("id", &Window::ID, true)
|
||||
.SetProperty("webContents", &Window::WebContents, true)
|
||||
.SetProperty("devToolsWebContents", &Window::DevToolsWebContents, true);
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
@@ -559,14 +604,21 @@ void Window::BuildPrototype(v8::Isolate* isolate,
|
||||
|
||||
namespace {
|
||||
|
||||
using atom::api::Window;
|
||||
|
||||
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
|
||||
v8::Local<v8::Context> context, void* priv) {
|
||||
using atom::api::Window;
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
v8::Local<v8::Function> constructor = mate::CreateConstructor<Window>(
|
||||
isolate, "BrowserWindow", base::Bind(&Window::New));
|
||||
mate::Dictionary browser_window(isolate, constructor);
|
||||
browser_window.SetMethod("fromId",
|
||||
&mate::TrackableObject<Window>::FromWeakMapID);
|
||||
browser_window.SetMethod("getAllWindows",
|
||||
&mate::TrackableObject<Window>::GetAll);
|
||||
|
||||
mate::Dictionary dict(isolate, exports);
|
||||
dict.Set("BrowserWindow", static_cast<v8::Local<v8::Value>>(constructor));
|
||||
dict.Set("BrowserWindow", browser_window);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -10,8 +10,9 @@
|
||||
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
#include "atom/browser/api/trackable_object.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/native_window_observer.h"
|
||||
#include "atom/browser/api/event_emitter.h"
|
||||
#include "native_mate/handle.h"
|
||||
|
||||
class GURL;
|
||||
@@ -33,7 +34,7 @@ namespace api {
|
||||
|
||||
class WebContents;
|
||||
|
||||
class Window : public mate::EventEmitter,
|
||||
class Window : public mate::TrackableObject<Window>,
|
||||
public NativeWindowObserver {
|
||||
public:
|
||||
static mate::Wrappable* New(v8::Isolate* isolate,
|
||||
@@ -45,17 +46,12 @@ class Window : public mate::EventEmitter,
|
||||
NativeWindow* window() const { return window_.get(); }
|
||||
|
||||
protected:
|
||||
explicit Window(const mate::Dictionary& options);
|
||||
Window(v8::Isolate* isolate, const mate::Dictionary& options);
|
||||
virtual ~Window();
|
||||
|
||||
// NativeWindowObserver:
|
||||
void OnPageTitleUpdated(bool* prevent_default,
|
||||
const std::string& title) override;
|
||||
void WillCreatePopupWindow(const base::string16& frame_name,
|
||||
const GURL& target_url,
|
||||
const std::string& partition_id,
|
||||
WindowOpenDisposition disposition) override;
|
||||
void WillNavigate(bool* prevent_default, const GURL& url) override;
|
||||
void WillCloseWindow(bool* prevent_default) override;
|
||||
void OnWindowClosed() override;
|
||||
void OnWindowBlur() override;
|
||||
@@ -74,6 +70,12 @@ class Window : public mate::EventEmitter,
|
||||
void OnRendererUnresponsive() override;
|
||||
void OnRendererResponsive() override;
|
||||
void OnDevToolsFocus() override;
|
||||
void OnDevToolsOpened() override;
|
||||
void OnDevToolsClosed() override;
|
||||
void OnExecuteWindowsCommand(const std::string& command_name) override;
|
||||
|
||||
// mate::Wrappable:
|
||||
bool IsDestroyed() const override;
|
||||
|
||||
private:
|
||||
// APIs for NativeWindow.
|
||||
@@ -117,11 +119,6 @@ class Window : public mate::EventEmitter,
|
||||
void SetSkipTaskbar(bool skip);
|
||||
void SetKiosk(bool kiosk);
|
||||
bool IsKiosk();
|
||||
void OpenDevTools(bool can_dock);
|
||||
void CloseDevTools();
|
||||
bool IsDevToolsOpened();
|
||||
void InspectElement(int x, int y);
|
||||
void InspectServiceWorker();
|
||||
void FocusOnWebView();
|
||||
void BlurWebView();
|
||||
bool IsWebViewFocused();
|
||||
@@ -130,14 +127,16 @@ class Window : public mate::EventEmitter,
|
||||
void SetDocumentEdited(bool edited);
|
||||
bool IsDocumentEdited();
|
||||
void CapturePage(mate::Arguments* args);
|
||||
void Print(mate::Arguments* args);
|
||||
void SetProgressBar(double progress);
|
||||
void SetOverlayIcon(const gfx::Image& overlay,
|
||||
const std::string& description);
|
||||
bool SetThumbarButtons(mate::Arguments* args);
|
||||
void SetMenu(v8::Isolate* isolate, v8::Local<v8::Value> menu);
|
||||
void SetAutoHideMenuBar(bool auto_hide);
|
||||
bool IsMenuBarAutoHide();
|
||||
void SetMenuBarVisibility(bool visible);
|
||||
bool IsMenuBarVisible();
|
||||
void SetAspectRatio(double aspect_ratio, mate::Arguments* args);
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
void ShowDefinitionForSelection();
|
||||
@@ -146,9 +145,15 @@ class Window : public mate::EventEmitter,
|
||||
void SetVisibleOnAllWorkspaces(bool visible);
|
||||
bool IsVisibleOnAllWorkspaces();
|
||||
|
||||
// APIs for WebContents.
|
||||
mate::Handle<WebContents> GetWebContents(v8::Isolate* isolate) const;
|
||||
mate::Handle<WebContents> GetDevToolsWebContents(v8::Isolate* isolate) const;
|
||||
int32_t ID() const;
|
||||
v8::Local<v8::Value> WebContents(v8::Isolate* isolate);
|
||||
v8::Local<v8::Value> DevToolsWebContents(v8::Isolate* isolate);
|
||||
|
||||
v8::Global<v8::Value> web_contents_;
|
||||
v8::Global<v8::Value> devtools_web_contents_;
|
||||
v8::Global<v8::Value> menu_;
|
||||
|
||||
api::WebContents* api_web_contents_;
|
||||
|
||||
scoped_ptr<NativeWindow> window_;
|
||||
|
||||
|
||||
@@ -6,10 +6,9 @@
|
||||
|
||||
#include "atom/browser/api/event.h"
|
||||
#include "native_mate/arguments.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "native_mate/object_template_builder.h"
|
||||
|
||||
#include "atom/common/node_includes.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
namespace {
|
||||
@@ -17,8 +16,8 @@ namespace {
|
||||
v8::Persistent<v8::ObjectTemplate> event_template;
|
||||
|
||||
void PreventDefault(mate::Arguments* args) {
|
||||
args->GetThis()->Set(StringToV8(args->isolate(), "defaultPrevented"),
|
||||
v8::True(args->isolate()));
|
||||
mate::Dictionary self(args->isolate(), args->GetThis());
|
||||
self.Set("defaultPrevented", true);
|
||||
}
|
||||
|
||||
// Create a pure JavaScript Event object.
|
||||
@@ -38,11 +37,8 @@ v8::Local<v8::Object> CreateEventObject(v8::Isolate* isolate) {
|
||||
EventEmitter::EventEmitter() {
|
||||
}
|
||||
|
||||
bool EventEmitter::CallEmit(v8::Isolate* isolate,
|
||||
const base::StringPiece& name,
|
||||
content::WebContents* sender,
|
||||
IPC::Message* message,
|
||||
ValueArray args) {
|
||||
v8::Local<v8::Object> EventEmitter::CreateJSEvent(
|
||||
v8::Isolate* isolate, content::WebContents* sender, IPC::Message* message) {
|
||||
v8::Local<v8::Object> event;
|
||||
bool use_native_event = sender && message;
|
||||
|
||||
@@ -53,16 +49,16 @@ bool EventEmitter::CallEmit(v8::Isolate* isolate,
|
||||
} else {
|
||||
event = CreateEventObject(isolate);
|
||||
}
|
||||
mate::Dictionary(isolate, event).Set("sender", GetWrapper(isolate));
|
||||
return event;
|
||||
}
|
||||
|
||||
// args = [name, event, args...];
|
||||
args.insert(args.begin(), event);
|
||||
args.insert(args.begin(), mate::StringToV8(isolate, name));
|
||||
|
||||
// this.emit.apply(this, args);
|
||||
node::MakeCallback(isolate, GetWrapper(isolate), "emit", args.size(),
|
||||
&args[0]);
|
||||
|
||||
return event->Get(StringToV8(isolate, "defaultPrevented"))->BooleanValue();
|
||||
v8::Local<v8::Object> EventEmitter::CreateCustomEvent(
|
||||
v8::Isolate* isolate, v8::Local<v8::Object> custom_event) {
|
||||
v8::Local<v8::Object> event = CreateEventObject(isolate);
|
||||
event->SetPrototype(custom_event->CreationContext(), custom_event);
|
||||
mate::Dictionary(isolate, event).Set("sender", GetWrapper(isolate));
|
||||
return event;
|
||||
}
|
||||
|
||||
} // namespace mate
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "atom/common/api/event_emitter_caller.h"
|
||||
#include "native_mate/wrappable.h"
|
||||
|
||||
namespace content {
|
||||
@@ -24,8 +25,13 @@ class EventEmitter : public Wrappable {
|
||||
public:
|
||||
typedef std::vector<v8::Local<v8::Value>> ValueArray;
|
||||
|
||||
protected:
|
||||
EventEmitter();
|
||||
// this.emit(name, event, args...);
|
||||
template<typename... Args>
|
||||
bool EmitCustomEvent(const base::StringPiece& name,
|
||||
v8::Local<v8::Object> event,
|
||||
const Args&... args) {
|
||||
return EmitWithEvent(name, CreateCustomEvent(isolate(), event), args...);
|
||||
}
|
||||
|
||||
// this.emit(name, new Event(), args...);
|
||||
template<typename... Args>
|
||||
@@ -39,21 +45,31 @@ class EventEmitter : public Wrappable {
|
||||
content::WebContents* sender,
|
||||
IPC::Message* message,
|
||||
const Args&... args) {
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
ValueArray converted = { ConvertToV8(isolate, args)... };
|
||||
return CallEmit(isolate, name, sender, message, converted);
|
||||
v8::Local<v8::Object> event = CreateJSEvent(isolate(), sender, message);
|
||||
return EmitWithEvent(name, event, args...);
|
||||
}
|
||||
|
||||
protected:
|
||||
EventEmitter();
|
||||
|
||||
private:
|
||||
// Lower level implementations.
|
||||
bool CallEmit(v8::Isolate* isolate,
|
||||
const base::StringPiece& name,
|
||||
content::WebContents* sender,
|
||||
IPC::Message* message,
|
||||
ValueArray args);
|
||||
// this.emit(name, event, args...);
|
||||
template<typename... Args>
|
||||
bool EmitWithEvent(const base::StringPiece& name,
|
||||
v8::Local<v8::Object> event,
|
||||
const Args&... args) {
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
EmitEvent(isolate(), GetWrapper(isolate()), name, event, args...);
|
||||
return event->Get(
|
||||
StringToV8(isolate(), "defaultPrevented"))->BooleanValue();
|
||||
}
|
||||
|
||||
v8::Local<v8::Object> CreateJSEvent(v8::Isolate* isolate,
|
||||
content::WebContents* sender,
|
||||
IPC::Message* message);
|
||||
v8::Local<v8::Object> CreateCustomEvent(
|
||||
v8::Isolate* isolate, v8::Local<v8::Object> event);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(EventEmitter);
|
||||
};
|
||||
|
||||
@@ -25,13 +25,21 @@ if process.platform is 'darwin'
|
||||
show: bindings.dockShow
|
||||
setMenu: bindings.dockSetMenu
|
||||
|
||||
appPath = null
|
||||
app.setAppPath = (path) ->
|
||||
appPath = path
|
||||
|
||||
app.getAppPath = ->
|
||||
appPath
|
||||
|
||||
# Be compatible with old API.
|
||||
app.once 'ready', -> app.emit 'finish-launching'
|
||||
app.once 'ready', -> @emit 'finish-launching'
|
||||
app.terminate = app.quit
|
||||
app.exit = process.exit
|
||||
app.getHomeDir = -> app.getPath 'home'
|
||||
app.getDataPath = -> app.getPath 'userData'
|
||||
app.setDataPath = (path) -> app.setPath 'userData', path
|
||||
app.getHomeDir = -> @getPath 'home'
|
||||
app.getDataPath = -> @getPath 'userData'
|
||||
app.setDataPath = (path) -> @setPath 'userData', path
|
||||
app.resolveProxy = -> @defaultSession.resolveProxy.apply @defaultSession, arguments
|
||||
|
||||
# Only one App object pemitted.
|
||||
module.exports = app
|
||||
|
||||
@@ -1,78 +1,49 @@
|
||||
EventEmitter = require('events').EventEmitter
|
||||
IDWeakMap = require 'id-weak-map'
|
||||
app = require 'app'
|
||||
ipc = require 'ipc'
|
||||
wrapWebContents = require('web-contents').wrap
|
||||
|
||||
BrowserWindow = process.atomBinding('window').BrowserWindow
|
||||
BrowserWindow::__proto__ = EventEmitter.prototype
|
||||
|
||||
# Store all created windows in the weak map.
|
||||
BrowserWindow.windows = new IDWeakMap
|
||||
|
||||
BrowserWindow::_init = ->
|
||||
# Simulate the application menu on platforms other than OS X.
|
||||
if process.platform isnt 'darwin'
|
||||
menu = app.getApplicationMenu()
|
||||
@setMenu menu if menu?
|
||||
|
||||
@webContents = @getWebContents()
|
||||
@devToolsWebContents = null
|
||||
@webContents.once 'destroyed', => @webContents = null
|
||||
|
||||
# Remember the window ID.
|
||||
Object.defineProperty this, 'id',
|
||||
value: BrowserWindow.windows.add(this)
|
||||
enumerable: true
|
||||
|
||||
# Make new windows requested by links behave like "window.open"
|
||||
@on '-new-window', (event, url, frameName) =>
|
||||
event.sender = @webContents
|
||||
@webContents.on '-new-window', (event, url, frameName) ->
|
||||
options = show: true, width: 800, height: 600
|
||||
ipc.emit 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', event, url, frameName, options
|
||||
|
||||
# Redirect "will-navigate" to webContents.
|
||||
@on '-will-navigate', (event, url) =>
|
||||
@webContents.emit 'will-navigate', event, url
|
||||
# window.resizeTo(...)
|
||||
# window.moveTo(...)
|
||||
@webContents.on 'move', (event, size) =>
|
||||
@setBounds size
|
||||
|
||||
# Remove the window from weak map immediately when it's destroyed, since we
|
||||
# could be iterating windows before GC happened.
|
||||
@once 'closed', =>
|
||||
BrowserWindow.windows.remove @id if BrowserWindow.windows.has @id
|
||||
# Hide the auto-hide menu when webContents is focused.
|
||||
@webContents.on 'activate', =>
|
||||
if process.platform isnt 'darwin' and @isMenuBarAutoHide() and @isMenuBarVisible()
|
||||
@setMenuBarVisibility false
|
||||
|
||||
BrowserWindow::openDevTools = (options={}) ->
|
||||
options.detach ?= false
|
||||
@_openDevTools !options.detach
|
||||
# Forward the crashed event.
|
||||
@webContents.on 'crashed', =>
|
||||
@emit 'crashed'
|
||||
|
||||
# Force devToolsWebContents to be created.
|
||||
@devToolsWebContents = @getDevToolsWebContents()
|
||||
@devToolsWebContents.once 'destroyed', => @devToolsWebContents = null
|
||||
# Sometimes the webContents doesn't get focus when window is shown, so we have
|
||||
# to force focusing on webContents in this case. The safest way is to focus it
|
||||
# when we first start to load URL, if we do it earlier it won't have effect,
|
||||
# if we do it later we might move focus in the page.
|
||||
# Though this hack is only needed on OS X when the app is launched from
|
||||
# Finder, we still do it on all platforms in case of other bugs we don't know.
|
||||
@webContents.once 'load-url', ->
|
||||
@focus()
|
||||
|
||||
# Emit devtools events.
|
||||
@devToolsWebContents.once 'did-finish-load', => @emit 'devtools-opened'
|
||||
@devToolsWebContents.once 'destroyed', => @emit 'devtools-closed'
|
||||
|
||||
BrowserWindow::toggleDevTools = ->
|
||||
if @isDevToolsOpened() then @closeDevTools() else @openDevTools()
|
||||
|
||||
BrowserWindow::getWebContents = ->
|
||||
wrapWebContents @_getWebContents()
|
||||
|
||||
BrowserWindow::getDevToolsWebContents = ->
|
||||
wrapWebContents @_getDevToolsWebContents()
|
||||
|
||||
BrowserWindow::setMenu = (menu) ->
|
||||
if process.platform is 'darwin'
|
||||
throw new Error('BrowserWindow.setMenu is not available on OS X')
|
||||
|
||||
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.getAllWindows = ->
|
||||
windows = BrowserWindow.windows
|
||||
windows.get key for key in windows.keys()
|
||||
# Redirect focus/blur event to app instance too.
|
||||
@on 'blur', (event) =>
|
||||
app.emit 'browser-window-blur', event, this
|
||||
@on 'focus', (event) =>
|
||||
app.emit 'browser-window-focus', event, this
|
||||
|
||||
BrowserWindow.getFocusedWindow = ->
|
||||
windows = BrowserWindow.getAllWindows()
|
||||
@@ -80,14 +51,11 @@ BrowserWindow.getFocusedWindow = ->
|
||||
|
||||
BrowserWindow.fromWebContents = (webContents) ->
|
||||
windows = BrowserWindow.getAllWindows()
|
||||
return window for window in windows when webContents.equal window.webContents
|
||||
return window for window in windows when window.webContents?.equal webContents
|
||||
|
||||
BrowserWindow.fromDevToolsWebContents = (webContents) ->
|
||||
windows = BrowserWindow.getAllWindows()
|
||||
return window for window in windows when webContents.equal window.devToolsWebContents
|
||||
|
||||
BrowserWindow.fromId = (id) ->
|
||||
BrowserWindow.windows.get id
|
||||
return window for window in windows when window.devToolsWebContents?.equal webContents
|
||||
|
||||
# Helpers.
|
||||
BrowserWindow::loadUrl = -> @webContents.loadUrl.apply @webContents, arguments
|
||||
@@ -102,10 +70,15 @@ BrowserWindow::getPageTitle = -> @webContents.getTitle()
|
||||
BrowserWindow::isLoading = -> @webContents.isLoading()
|
||||
BrowserWindow::isWaitingForResponse = -> @webContents.isWaitingForResponse()
|
||||
BrowserWindow::stop = -> @webContents.stop()
|
||||
BrowserWindow::getRoutingId = -> @webContents.getRoutingId()
|
||||
BrowserWindow::getProcessId = -> @webContents.getProcessId()
|
||||
BrowserWindow::isCrashed = -> @webContents.isCrashed()
|
||||
BrowserWindow::executeJavaScriptInDevTools = (code) ->
|
||||
@devToolsWebContents.executeJavaScript code
|
||||
BrowserWindow::executeJavaScriptInDevTools = (code) -> @devToolsWebContents?.executeJavaScript code
|
||||
BrowserWindow::openDevTools = -> @webContents.openDevTools.apply @webContents, arguments
|
||||
BrowserWindow::closeDevTools = -> @webContents.closeDevTools()
|
||||
BrowserWindow::isDevToolsOpened = -> @webContents.isDevToolsOpened()
|
||||
BrowserWindow::toggleDevTools = -> @webContents.toggleDevTools()
|
||||
BrowserWindow::inspectElement = -> @webContents.inspectElement.apply @webContents, arguments
|
||||
BrowserWindow::inspectServiceWorker = -> @webContents.inspectServiceWorker()
|
||||
BrowserWindow::print = -> @webContents.print.apply @webContents, arguments
|
||||
BrowserWindow::printToPDF = -> @webContents.printToPDF.apply @webContents, arguments
|
||||
|
||||
module.exports = BrowserWindow
|
||||
|
||||
@@ -1,7 +1 @@
|
||||
module.exports = process.atomBinding 'content_tracing'
|
||||
|
||||
# Mirrored from content::TracingController::Options
|
||||
module.exports.DEFAULT_OPTIONS = 0
|
||||
module.exports.ENABLE_SYSTRACE = 1 << 0
|
||||
module.exports.ENABLE_SAMPLING = 1 << 1
|
||||
module.exports.RECORD_CONTINUOUSLY = 1 << 2
|
||||
|
||||
@@ -9,7 +9,10 @@ fileDialogProperties =
|
||||
multiSelections: 1 << 2
|
||||
createDirectory: 1 << 3
|
||||
|
||||
messageBoxTypes = ['none', 'info', 'warning']
|
||||
messageBoxTypes = ['none', 'info', 'warning', 'error', 'question']
|
||||
|
||||
messageBoxOptions =
|
||||
noLink: 1 << 0
|
||||
|
||||
parseArgs = (window, options, callback) ->
|
||||
unless window is null or window?.constructor is BrowserWindow
|
||||
@@ -93,9 +96,23 @@ module.exports =
|
||||
options.detail ?= ''
|
||||
options.icon ?= null
|
||||
|
||||
# Choose a default button to get selected when dialog is cancelled.
|
||||
unless options.cancelId?
|
||||
options.cancelId = 0
|
||||
for text, i in options.buttons
|
||||
if text.toLowerCase() in ['cancel', 'no']
|
||||
options.cancelId = i
|
||||
break
|
||||
|
||||
flags = if options.noLink then messageBoxOptions.noLink else 0
|
||||
|
||||
binding.showMessageBox messageBoxType,
|
||||
options.buttons,
|
||||
[options.title, options.message, options.detail],
|
||||
options.cancelId,
|
||||
flags,
|
||||
options.title,
|
||||
options.message,
|
||||
options.detail,
|
||||
options.icon,
|
||||
window,
|
||||
callback
|
||||
@@ -104,4 +121,5 @@ module.exports =
|
||||
binding.showErrorBox args...
|
||||
|
||||
# Mark standard asynchronous functions.
|
||||
v8Util.setHiddenValue f, 'asynchronous', true for k, f of module.exports
|
||||
for api in ['showMessageBox', 'showOpenDialog', 'showSaveDialog']
|
||||
v8Util.setHiddenValue module.exports[api], 'asynchronous', true
|
||||
|
||||
@@ -130,10 +130,11 @@ Menu::_callMenuWillShow = ->
|
||||
|
||||
applicationMenu = null
|
||||
Menu.setApplicationMenu = (menu) ->
|
||||
throw new TypeError('Invalid menu') unless menu?.constructor is Menu
|
||||
throw new TypeError('Invalid menu') unless menu is null or menu.constructor is Menu
|
||||
applicationMenu = menu # Keep a reference.
|
||||
|
||||
if process.platform is 'darwin'
|
||||
return if menu is null
|
||||
menu._callMenuWillShow()
|
||||
bindings.setApplicationMenu menu
|
||||
else
|
||||
|
||||
@@ -40,6 +40,7 @@ class NavigationController
|
||||
loadUrl: (url, options={}) ->
|
||||
@pendingIndex = -1
|
||||
@webContents._loadUrl url, options
|
||||
@webContents.emit 'load-url', url, options
|
||||
|
||||
getUrl: ->
|
||||
if @currentIndex is -1
|
||||
|
||||
3
atom/browser/api/lib/power-save-blocker.coffee
Normal file
3
atom/browser/api/lib/power-save-blocker.coffee
Normal file
@@ -0,0 +1,3 @@
|
||||
bindings = process.atomBinding 'power_save_blocker'
|
||||
|
||||
module.exports = bindings.powerSaveBlocker
|
||||
@@ -6,6 +6,29 @@ EventEmitter = require('events').EventEmitter
|
||||
|
||||
protocol.__proto__ = EventEmitter.prototype
|
||||
|
||||
GetWrappedCallback = (scheme, callback, notification) ->
|
||||
wrappedCallback = (error) ->
|
||||
if not callback?
|
||||
if error
|
||||
throw error
|
||||
else
|
||||
protocol.emit notification, scheme
|
||||
else
|
||||
callback error, scheme
|
||||
|
||||
# Compatibility with old api.
|
||||
protocol.registerProtocol = (scheme, handler, callback) ->
|
||||
protocol._registerProtocol scheme, handler, GetWrappedCallback(scheme, callback, 'registered')
|
||||
|
||||
protocol.unregisterProtocol = (scheme, callback) ->
|
||||
protocol._unregisterProtocol scheme, GetWrappedCallback(scheme, callback, 'unregistered')
|
||||
|
||||
protocol.interceptProtocol = (scheme, handler, callback) ->
|
||||
protocol._interceptProtocol scheme, handler, GetWrappedCallback(scheme, callback, 'intercepted')
|
||||
|
||||
protocol.uninterceptProtocol = (scheme, callback) ->
|
||||
protocol._uninterceptProtocol scheme, GetWrappedCallback(scheme, callback, 'unintercepted')
|
||||
|
||||
protocol.RequestStringJob =
|
||||
class RequestStringJob
|
||||
constructor: ({mimeType, charset, data}) ->
|
||||
@@ -34,4 +57,8 @@ protocol.RequestErrorJob =
|
||||
class RequestErrorJob
|
||||
constructor: (@error) ->
|
||||
|
||||
protocol.RequestHttpJob =
|
||||
class RequestHttpJob
|
||||
constructor: ({@session, @url, @method, @referrer}) ->
|
||||
|
||||
module.exports = protocol
|
||||
|
||||
@@ -3,8 +3,12 @@ bindings = process.atomBinding 'tray'
|
||||
|
||||
Tray = bindings.Tray
|
||||
Tray::__proto__ = EventEmitter.prototype
|
||||
|
||||
Tray::setContextMenu = (menu) ->
|
||||
@_setContextMenu menu
|
||||
@menu = menu # Keep a strong reference of menu.
|
||||
|
||||
# Keep compatibility with old APIs.
|
||||
Tray::popContextMenu = Tray::popUpContextMenu
|
||||
|
||||
module.exports = Tray
|
||||
|
||||
@@ -3,9 +3,38 @@ NavigationController = require './navigation-controller'
|
||||
binding = process.atomBinding 'web_contents'
|
||||
ipc = require 'ipc'
|
||||
|
||||
module.exports.wrap = (webContents) ->
|
||||
return null unless webContents.isAlive()
|
||||
nextId = 0
|
||||
getNextId = -> ++nextId
|
||||
|
||||
PDFPageSize =
|
||||
A4:
|
||||
custom_display_name: "A4"
|
||||
height_microns: 297000
|
||||
name: "ISO_A4"
|
||||
is_default: "true"
|
||||
width_microns: 210000
|
||||
A3:
|
||||
custom_display_name: "A3"
|
||||
height_microns: 420000
|
||||
name: "ISO_A3"
|
||||
width_microns: 297000
|
||||
Legal:
|
||||
custom_display_name: "Legal"
|
||||
height_microns: 355600
|
||||
name: "NA_LEGAL"
|
||||
width_microns: 215900
|
||||
Letter:
|
||||
custom_display_name: "Letter"
|
||||
height_microns: 279400
|
||||
name: "NA_LETTER"
|
||||
width_microns: 215900
|
||||
Tabloid:
|
||||
height_microns: 431800
|
||||
name: "NA_LEDGER"
|
||||
width_microns: 279400
|
||||
custom_display_name: "Tabloid"
|
||||
|
||||
wrapWebContents = (webContents) ->
|
||||
# webContents is an EventEmitter.
|
||||
webContents.__proto__ = EventEmitter.prototype
|
||||
|
||||
@@ -17,15 +46,11 @@ module.exports.wrap = (webContents) ->
|
||||
# web contents has been loaded.
|
||||
webContents.loaded = false
|
||||
webContents.once 'did-finish-load', -> @loaded = true
|
||||
webContents.executeJavaScript = (code) ->
|
||||
webContents.executeJavaScript = (code, hasUserGesture=false) ->
|
||||
if @loaded
|
||||
@_executeJavaScript code
|
||||
@_executeJavaScript code, hasUserGesture
|
||||
else
|
||||
webContents.once 'did-finish-load', @_executeJavaScript.bind(this, code)
|
||||
|
||||
# The processId and routingId and identify a webContents.
|
||||
webContents.getId = -> "#{@getProcessId()}-#{@getRoutingId()}"
|
||||
webContents.equal = (other) -> @getId() is other.getId()
|
||||
webContents.once 'did-finish-load', @_executeJavaScript.bind(this, code, hasUserGesture)
|
||||
|
||||
# The navigation controller.
|
||||
controller = new NavigationController(webContents)
|
||||
@@ -33,34 +58,57 @@ module.exports.wrap = (webContents) ->
|
||||
do (name, method) ->
|
||||
webContents[name] = -> method.apply controller, arguments
|
||||
|
||||
# Translate |disposition| to string for 'new-window' event.
|
||||
webContents.on '-new-window', (args..., disposition) ->
|
||||
disposition =
|
||||
switch disposition
|
||||
when 2 then 'default'
|
||||
when 4 then 'foreground-tab'
|
||||
when 5 then 'background-tab'
|
||||
when 6, 7 then 'new-window'
|
||||
else 'other'
|
||||
@emit 'new-window', args..., disposition
|
||||
|
||||
# Tell the rpc server that a render view has been deleted and we need to
|
||||
# release all objects owned by it.
|
||||
webContents.on 'render-view-deleted', (event, processId, routingId) ->
|
||||
process.emit 'ATOM_BROWSER_RELEASE_RENDER_VIEW', "#{processId}-#{routingId}"
|
||||
|
||||
# Dispatch IPC messages to the ipc module.
|
||||
webContents.on 'ipc-message', (event, packed) ->
|
||||
[channel, args...] = packed
|
||||
Object.defineProperty event, 'sender', value: webContents
|
||||
ipc.emit channel, event, args...
|
||||
webContents.on 'ipc-message-sync', (event, packed) ->
|
||||
[channel, args...] = packed
|
||||
Object.defineProperty event, 'returnValue', set: (value) -> event.sendReply JSON.stringify(value)
|
||||
Object.defineProperty event, 'sender', value: webContents
|
||||
ipc.emit channel, event, args...
|
||||
|
||||
webContents
|
||||
webContents.printToPDF = (options, callback) ->
|
||||
printingSetting =
|
||||
pageRage: []
|
||||
mediaSize: {}
|
||||
landscape: false
|
||||
color: 2
|
||||
headerFooterEnabled: false
|
||||
marginsType: 0
|
||||
isFirstRequest: false
|
||||
requestID: getNextId()
|
||||
previewModifiable: true
|
||||
printToPDF: true
|
||||
printWithCloudPrint: false
|
||||
printWithPrivet: false
|
||||
printWithExtension: false
|
||||
deviceName: "Save as PDF"
|
||||
generateDraftData: true
|
||||
fitToPageEnabled: false
|
||||
duplex: 0
|
||||
copies: 1
|
||||
collate: true
|
||||
shouldPrintBackgrounds: false
|
||||
shouldPrintSelectionOnly: false
|
||||
|
||||
if options.landscape
|
||||
printingSetting.landscape = options.landscape
|
||||
if options.marginsType
|
||||
printingSetting.marginsType = options.marginsType
|
||||
if options.printSelectionOnly
|
||||
printingSetting.shouldPrintSelectionOnly = options.printSelectionOnly
|
||||
if options.printBackground
|
||||
printingSetting.shouldPrintBackgrounds = options.printBackground
|
||||
|
||||
if options.pageSize and PDFPageSize[options.pageSize]
|
||||
printingSetting.mediaSize = PDFPageSize[options.pageSize]
|
||||
else
|
||||
printingSetting.mediaSize = PDFPageSize['A4']
|
||||
|
||||
@_printToPDF printingSetting, callback
|
||||
|
||||
binding._setWrapWebContents wrapWebContents
|
||||
process.once 'exit', binding._clearWrapWebContents
|
||||
|
||||
module.exports.create = (options={}) ->
|
||||
@wrap binding.create(options)
|
||||
binding.create(options)
|
||||
|
||||
68
atom/browser/api/trackable_object.cc
Normal file
68
atom/browser/api/trackable_object.cc
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/api/trackable_object.h"
|
||||
|
||||
#include "atom/browser/atom_browser_main_parts.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/supports_user_data.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
namespace {
|
||||
|
||||
const char* kTrackedObjectKey = "TrackedObjectKey";
|
||||
|
||||
class IDUserData : public base::SupportsUserData::Data {
|
||||
public:
|
||||
explicit IDUserData(int32_t id) : id_(id) {}
|
||||
|
||||
operator int32_t() const { return id_; }
|
||||
|
||||
private:
|
||||
int32_t id_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(IDUserData);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TrackableObjectBase::TrackableObjectBase()
|
||||
: weak_map_id_(0), wrapped_(nullptr) {
|
||||
}
|
||||
|
||||
TrackableObjectBase::~TrackableObjectBase() {
|
||||
}
|
||||
|
||||
void TrackableObjectBase::AfterInit(v8::Isolate* isolate) {
|
||||
if (wrapped_)
|
||||
AttachAsUserData(wrapped_);
|
||||
}
|
||||
|
||||
void TrackableObjectBase::AttachAsUserData(base::SupportsUserData* wrapped) {
|
||||
if (weak_map_id_ != 0) {
|
||||
wrapped->SetUserData(kTrackedObjectKey, new IDUserData(weak_map_id_));
|
||||
wrapped_ = nullptr;
|
||||
} else {
|
||||
// If the TrackableObjectBase is not ready yet then delay SetUserData until
|
||||
// AfterInit is called.
|
||||
wrapped_ = wrapped;
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
int32_t TrackableObjectBase::GetIDFromWrappedClass(base::SupportsUserData* w) {
|
||||
auto id = static_cast<IDUserData*>(w->GetUserData(kTrackedObjectKey));
|
||||
if (id)
|
||||
return *id;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// static
|
||||
void TrackableObjectBase::RegisterDestructionCallback(void (*c)()) {
|
||||
atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback(base::Bind(c));
|
||||
}
|
||||
|
||||
} // namespace mate
|
||||
125
atom/browser/api/trackable_object.h
Normal file
125
atom/browser/api/trackable_object.h
Normal file
@@ -0,0 +1,125 @@
|
||||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_API_TRACKABLE_OBJECT_H_
|
||||
#define ATOM_BROWSER_API_TRACKABLE_OBJECT_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "atom/browser/api/event_emitter.h"
|
||||
#include "atom/common/id_weak_map.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
|
||||
namespace base {
|
||||
class SupportsUserData;
|
||||
}
|
||||
|
||||
namespace mate {
|
||||
|
||||
// Users should use TrackableObject instead.
|
||||
class TrackableObjectBase : public mate::EventEmitter {
|
||||
public:
|
||||
TrackableObjectBase();
|
||||
|
||||
// The ID in weak map.
|
||||
int32_t weak_map_id() const { return weak_map_id_; }
|
||||
|
||||
// Wrap TrackableObject into a class that SupportsUserData.
|
||||
void AttachAsUserData(base::SupportsUserData* wrapped);
|
||||
|
||||
protected:
|
||||
~TrackableObjectBase() override;
|
||||
|
||||
// mate::Wrappable:
|
||||
void AfterInit(v8::Isolate* isolate) override;
|
||||
|
||||
// Get the weak_map_id from SupportsUserData.
|
||||
static int32_t GetIDFromWrappedClass(base::SupportsUserData* wrapped);
|
||||
|
||||
// Register a callback that should be destroyed before JavaScript environment
|
||||
// gets destroyed.
|
||||
static void RegisterDestructionCallback(void (*callback)());
|
||||
|
||||
int32_t weak_map_id_;
|
||||
base::SupportsUserData* wrapped_;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(TrackableObjectBase);
|
||||
};
|
||||
|
||||
// All instances of TrackableObject will be kept in a weak map and can be got
|
||||
// from its ID.
|
||||
template<typename T>
|
||||
class TrackableObject : public TrackableObjectBase {
|
||||
public:
|
||||
// Finds out the TrackableObject from its ID in weak map.
|
||||
static T* FromWeakMapID(v8::Isolate* isolate, int32_t id) {
|
||||
if (!weak_map_)
|
||||
return nullptr;
|
||||
|
||||
v8::MaybeLocal<v8::Object> object = weak_map_->Get(isolate, id);
|
||||
if (object.IsEmpty())
|
||||
return nullptr;
|
||||
|
||||
T* self = nullptr;
|
||||
mate::ConvertFromV8(isolate, object.ToLocalChecked(), &self);
|
||||
return self;
|
||||
}
|
||||
|
||||
// Finds out the TrackableObject from the class it wraps.
|
||||
static T* FromWrappedClass(v8::Isolate* isolate,
|
||||
base::SupportsUserData* wrapped) {
|
||||
int32_t id = GetIDFromWrappedClass(wrapped);
|
||||
if (!id)
|
||||
return nullptr;
|
||||
return FromWeakMapID(isolate, id);
|
||||
}
|
||||
|
||||
// Returns all objects in this class's weak map.
|
||||
static std::vector<v8::Local<v8::Object>> GetAll(v8::Isolate* isolate) {
|
||||
if (weak_map_)
|
||||
return weak_map_->Values(isolate);
|
||||
else
|
||||
return std::vector<v8::Local<v8::Object>>();
|
||||
}
|
||||
|
||||
TrackableObject() {
|
||||
RegisterDestructionCallback(&TrackableObject<T>::ReleaseAllWeakReferences);
|
||||
}
|
||||
|
||||
// Removes this instance from the weak map.
|
||||
void RemoveFromWeakMap() {
|
||||
if (weak_map_ && weak_map_->Has(weak_map_id()))
|
||||
weak_map_->Remove(weak_map_id());
|
||||
}
|
||||
|
||||
protected:
|
||||
~TrackableObject() override {
|
||||
RemoveFromWeakMap();
|
||||
}
|
||||
|
||||
void AfterInit(v8::Isolate* isolate) override {
|
||||
if (!weak_map_)
|
||||
weak_map_.reset(new atom::IDWeakMap);
|
||||
weak_map_id_ = weak_map_->Add(isolate, GetWrapper(isolate));
|
||||
TrackableObjectBase::AfterInit(isolate);
|
||||
}
|
||||
|
||||
private:
|
||||
// Releases all weak references in weak map, called when app is terminating.
|
||||
static void ReleaseAllWeakReferences() {
|
||||
weak_map_.reset();
|
||||
}
|
||||
|
||||
static scoped_ptr<atom::IDWeakMap> weak_map_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(TrackableObject);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
scoped_ptr<atom::IDWeakMap> TrackableObject<T>::weak_map_;
|
||||
|
||||
} // namespace mate
|
||||
|
||||
#endif // ATOM_BROWSER_API_TRACKABLE_OBJECT_H_
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <utility>
|
||||
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/atom_browser_main_parts.h"
|
||||
#include "atom/common/google_api_key.h"
|
||||
|
||||
namespace atom {
|
||||
@@ -39,8 +40,8 @@ void AtomAccessTokenStore::LoadAccessTokens(
|
||||
token_pair.first = GURL(kGeolocationProviderUrl);
|
||||
access_token_set.insert(token_pair);
|
||||
|
||||
callback.Run(access_token_set,
|
||||
AtomBrowserContext::Get()->url_request_context_getter());
|
||||
auto browser_context = AtomBrowserMainParts::Get()->browser_context();
|
||||
callback.Run(access_token_set, browser_context->url_request_context_getter());
|
||||
}
|
||||
|
||||
void AtomAccessTokenStore::SaveAccessToken(const GURL& server_url,
|
||||
|
||||
@@ -4,28 +4,36 @@
|
||||
|
||||
#include "atom/browser/atom_browser_client.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <shlobj.h>
|
||||
#endif
|
||||
|
||||
#include "atom/browser/atom_access_token_store.h"
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/atom_browser_main_parts.h"
|
||||
#include "atom/browser/atom_quota_permission_context.h"
|
||||
#include "atom/browser/atom_resource_dispatcher_host_delegate.h"
|
||||
#include "atom/browser/atom_speech_recognition_manager_delegate.h"
|
||||
#include "atom/browser/browser.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/web_view_manager.h"
|
||||
#include "atom/browser/window_list.h"
|
||||
#include "atom/common/options_switches.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "chrome/browser/printing/printing_message_filter.h"
|
||||
#include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h"
|
||||
#include "chrome/browser/speech/tts_message_filter.h"
|
||||
#include "content/public/browser/browser_ppapi_host.h"
|
||||
#include "content/public/browser/client_certificate_delegate.h"
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#include "content/public/browser/resource_dispatcher_host.h"
|
||||
#include "content/public/browser/site_instance.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "content/public/common/web_preferences.h"
|
||||
#include "net/cert/x509_certificate.h"
|
||||
#include "net/ssl/ssl_cert_request_info.h"
|
||||
#include "ppapi/host/ppapi_host.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
|
||||
@@ -33,25 +41,64 @@ namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
// The default routing id of WebContents.
|
||||
// In Electron each RenderProcessHost only has one WebContents, so this ID is
|
||||
// same for every WebContents.
|
||||
int kDefaultRoutingID = 2;
|
||||
|
||||
// Next navigation should not restart renderer process.
|
||||
bool g_suppress_renderer_process_restart = false;
|
||||
|
||||
struct FindByProcessId {
|
||||
explicit FindByProcessId(int child_process_id)
|
||||
: child_process_id_(child_process_id) {
|
||||
}
|
||||
// Custom schemes to be registered to standard.
|
||||
std::string g_custom_schemes = "";
|
||||
|
||||
bool operator() (NativeWindow* const window) {
|
||||
content::WebContents* web_contents = window->GetWebContents();
|
||||
if (!web_contents)
|
||||
return false;
|
||||
|
||||
int id = window->GetWebContents()->GetRenderProcessHost()->GetID();
|
||||
return id == child_process_id_;
|
||||
}
|
||||
|
||||
int child_process_id_;
|
||||
// Find out the owner of the child process according to |process_id|.
|
||||
enum ProcessOwner {
|
||||
OWNER_NATIVE_WINDOW,
|
||||
OWNER_GUEST_WEB_CONTENTS,
|
||||
OWNER_NONE, // it might be devtools though.
|
||||
};
|
||||
ProcessOwner GetProcessOwner(int process_id,
|
||||
NativeWindow** window,
|
||||
WebViewManager::WebViewInfo* info) {
|
||||
auto web_contents = content::WebContents::FromRenderViewHost(
|
||||
content::RenderViewHost::FromID(process_id, kDefaultRoutingID));
|
||||
if (!web_contents)
|
||||
return OWNER_NONE;
|
||||
|
||||
// First search for NativeWindow.
|
||||
for (auto native_window : *WindowList::GetInstance())
|
||||
if (web_contents == native_window->web_contents()) {
|
||||
*window = native_window;
|
||||
return OWNER_NATIVE_WINDOW;
|
||||
}
|
||||
|
||||
// Then search for guest WebContents.
|
||||
if (WebViewManager::GetInfoForWebContents(web_contents, info))
|
||||
return OWNER_GUEST_WEB_CONTENTS;
|
||||
|
||||
return OWNER_NONE;
|
||||
}
|
||||
|
||||
scoped_refptr<net::X509Certificate> ImportCertFromFile(
|
||||
const base::FilePath& path) {
|
||||
if (path.empty())
|
||||
return nullptr;
|
||||
|
||||
std::string cert_data;
|
||||
if (!base::ReadFileToString(path, &cert_data))
|
||||
return nullptr;
|
||||
|
||||
net::CertificateList certs =
|
||||
net::X509Certificate::CreateCertificateListFromBytes(
|
||||
cert_data.data(), cert_data.size(),
|
||||
net::X509Certificate::FORMAT_AUTO);
|
||||
|
||||
if (certs.empty())
|
||||
return nullptr;
|
||||
|
||||
return certs[0];
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -60,8 +107,12 @@ void AtomBrowserClient::SuppressRendererProcessRestartForOnce() {
|
||||
g_suppress_renderer_process_restart = true;
|
||||
}
|
||||
|
||||
AtomBrowserClient::AtomBrowserClient()
|
||||
: dying_render_process_(nullptr) {
|
||||
void AtomBrowserClient::SetCustomSchemes(
|
||||
const std::vector<std::string>& schemes) {
|
||||
g_custom_schemes = JoinString(schemes, ',');
|
||||
}
|
||||
|
||||
AtomBrowserClient::AtomBrowserClient() {
|
||||
}
|
||||
|
||||
AtomBrowserClient::~AtomBrowserClient() {
|
||||
@@ -69,9 +120,9 @@ AtomBrowserClient::~AtomBrowserClient() {
|
||||
|
||||
void AtomBrowserClient::RenderProcessWillLaunch(
|
||||
content::RenderProcessHost* host) {
|
||||
int id = host->GetID();
|
||||
host->AddFilter(new printing::PrintingMessageFilter(host->GetID()));
|
||||
host->AddFilter(new TtsMessageFilter(id, host->GetBrowserContext()));
|
||||
int process_id = host->GetID();
|
||||
host->AddFilter(new printing::PrintingMessageFilter(process_id));
|
||||
host->AddFilter(new TtsMessageFilter(process_id, host->GetBrowserContext()));
|
||||
}
|
||||
|
||||
content::SpeechRecognitionManagerDelegate*
|
||||
@@ -83,15 +134,8 @@ content::AccessTokenStore* AtomBrowserClient::CreateAccessTokenStore() {
|
||||
return new AtomAccessTokenStore;
|
||||
}
|
||||
|
||||
void AtomBrowserClient::ResourceDispatcherHostCreated() {
|
||||
resource_dispatcher_delegate_.reset(new AtomResourceDispatcherHostDelegate);
|
||||
content::ResourceDispatcherHost::Get()->SetDelegate(
|
||||
resource_dispatcher_delegate_.get());
|
||||
}
|
||||
|
||||
void AtomBrowserClient::OverrideWebkitPrefs(
|
||||
content::RenderViewHost* render_view_host,
|
||||
content::WebPreferences* prefs) {
|
||||
content::RenderViewHost* host, content::WebPreferences* prefs) {
|
||||
prefs->javascript_enabled = true;
|
||||
prefs->web_security_enabled = true;
|
||||
prefs->javascript_can_open_windows_automatically = true;
|
||||
@@ -109,18 +153,10 @@ void AtomBrowserClient::OverrideWebkitPrefs(
|
||||
prefs->allow_displaying_insecure_content = false;
|
||||
prefs->allow_running_insecure_content = false;
|
||||
|
||||
// Turn off web security for devtools.
|
||||
auto web_contents = content::WebContents::FromRenderViewHost(
|
||||
render_view_host);
|
||||
if (web_contents && web_contents->GetURL().SchemeIs("chrome-devtools")) {
|
||||
prefs->web_security_enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Custom preferences of guest page.
|
||||
auto process = render_view_host->GetProcess();
|
||||
auto web_contents = content::WebContents::FromRenderViewHost(host);
|
||||
WebViewManager::WebViewInfo info;
|
||||
if (WebViewManager::GetInfoForProcess(process, &info)) {
|
||||
if (WebViewManager::GetInfoForWebContents(web_contents, &info)) {
|
||||
prefs->web_security_enabled = !info.disable_web_security;
|
||||
return;
|
||||
}
|
||||
@@ -144,82 +180,57 @@ void AtomBrowserClient::OverrideSiteInstanceForNavigation(
|
||||
return;
|
||||
}
|
||||
|
||||
if (current_instance->HasProcess())
|
||||
dying_render_process_ = current_instance->GetProcess();
|
||||
// Restart renderer process for all navigations except "javacript:" scheme.
|
||||
if (url.SchemeIs(url::kJavaScriptScheme))
|
||||
return;
|
||||
|
||||
// Restart renderer process for all navigations.
|
||||
*new_instance = content::SiteInstance::CreateForURL(browser_context, url);
|
||||
}
|
||||
|
||||
void AtomBrowserClient::AppendExtraCommandLineSwitches(
|
||||
base::CommandLine* command_line,
|
||||
int child_process_id) {
|
||||
int process_id) {
|
||||
std::string process_type = command_line->GetSwitchValueASCII("type");
|
||||
if (process_type != "renderer")
|
||||
return;
|
||||
|
||||
WindowList* list = WindowList::GetInstance();
|
||||
NativeWindow* window = nullptr;
|
||||
// The registered standard schemes.
|
||||
if (!g_custom_schemes.empty())
|
||||
command_line->AppendSwitchASCII(switches::kRegisterStandardSchemes,
|
||||
g_custom_schemes);
|
||||
|
||||
// Find the owner of this child process.
|
||||
WindowList::const_iterator iter = std::find_if(
|
||||
list->begin(), list->end(), FindByProcessId(child_process_id));
|
||||
if (iter != list->end())
|
||||
window = *iter;
|
||||
|
||||
// If the render process is a newly started one, which means the window still
|
||||
// uses the old going-to-be-swapped render process, then we try to find the
|
||||
// window from the swapped render process.
|
||||
if (!window && dying_render_process_) {
|
||||
int dying_process_id = dying_render_process_->GetID();
|
||||
WindowList::const_iterator iter = std::find_if(
|
||||
list->begin(), list->end(), FindByProcessId(dying_process_id));
|
||||
if (iter != list->end()) {
|
||||
window = *iter;
|
||||
child_process_id = dying_process_id;
|
||||
} else {
|
||||
// It appears that the dying process doesn't belong to a BrowserWindow,
|
||||
// then it might be a guest process, if it is we should update its
|
||||
// process ID in the WebViewManager.
|
||||
auto child_process = content::RenderProcessHost::FromID(child_process_id);
|
||||
// Update the process ID in webview guests.
|
||||
WebViewManager::UpdateGuestProcessID(dying_render_process_,
|
||||
child_process);
|
||||
}
|
||||
#if defined(OS_WIN)
|
||||
// Append --app-user-model-id.
|
||||
PWSTR current_app_id;
|
||||
if (SUCCEEDED(GetCurrentProcessExplicitAppUserModelID(¤t_app_id))) {
|
||||
command_line->AppendSwitchNative(switches::kAppUserModelId, current_app_id);
|
||||
CoTaskMemFree(current_app_id);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (window) {
|
||||
window->AppendExtraCommandLineSwitches(command_line, child_process_id);
|
||||
} else {
|
||||
// Append commnad line arguments for guest web view.
|
||||
auto child_process = content::RenderProcessHost::FromID(child_process_id);
|
||||
WebViewManager::WebViewInfo info;
|
||||
if (WebViewManager::GetInfoForProcess(child_process, &info)) {
|
||||
command_line->AppendSwitchASCII(
|
||||
switches::kGuestInstanceID,
|
||||
base::IntToString(info.guest_instance_id));
|
||||
command_line->AppendSwitchASCII(
|
||||
switches::kNodeIntegration,
|
||||
info.node_integration ? "true" : "false");
|
||||
if (info.plugins)
|
||||
command_line->AppendSwitch(switches::kEnablePlugins);
|
||||
if (!info.preload_script.empty())
|
||||
command_line->AppendSwitchPath(
|
||||
switches::kPreloadScript,
|
||||
info.preload_script);
|
||||
}
|
||||
NativeWindow* window;
|
||||
WebViewManager::WebViewInfo info;
|
||||
ProcessOwner owner = GetProcessOwner(process_id, &window, &info);
|
||||
|
||||
if (owner == OWNER_NATIVE_WINDOW) {
|
||||
window->AppendExtraCommandLineSwitches(command_line);
|
||||
} else if (owner == OWNER_GUEST_WEB_CONTENTS) {
|
||||
command_line->AppendSwitchASCII(
|
||||
switches::kGuestInstanceID, base::IntToString(info.guest_instance_id));
|
||||
command_line->AppendSwitchASCII(
|
||||
switches::kNodeIntegration, info.node_integration ? "true" : "false");
|
||||
if (info.plugins)
|
||||
command_line->AppendSwitch(switches::kEnablePlugins);
|
||||
if (!info.preload_script.empty())
|
||||
command_line->AppendSwitchPath(
|
||||
switches::kPreloadScript, info.preload_script);
|
||||
}
|
||||
|
||||
dying_render_process_ = nullptr;
|
||||
}
|
||||
|
||||
void AtomBrowserClient::DidCreatePpapiPlugin(
|
||||
content::BrowserPpapiHost* browser_host) {
|
||||
auto command_line = base::CommandLine::ForCurrentProcess();
|
||||
if (command_line->HasSwitch(switches::kEnablePlugins))
|
||||
browser_host->GetPpapiHost()->AddHostFactoryFilter(
|
||||
scoped_ptr<ppapi::host::HostFactory>(
|
||||
new chrome::ChromeBrowserPepperHostFactory(browser_host)));
|
||||
content::BrowserPpapiHost* host) {
|
||||
host->GetPpapiHost()->AddHostFactoryFilter(
|
||||
make_scoped_ptr(new chrome::ChromeBrowserPepperHostFactory(host)));
|
||||
}
|
||||
|
||||
content::QuotaPermissionContext*
|
||||
@@ -227,6 +238,26 @@ content::QuotaPermissionContext*
|
||||
return new AtomQuotaPermissionContext;
|
||||
}
|
||||
|
||||
void AtomBrowserClient::SelectClientCertificate(
|
||||
content::WebContents* web_contents,
|
||||
net::SSLCertRequestInfo* cert_request_info,
|
||||
scoped_ptr<content::ClientCertificateDelegate> delegate) {
|
||||
// --client-certificate=`path`
|
||||
auto cmd = base::CommandLine::ForCurrentProcess();
|
||||
if (cmd->HasSwitch(switches::kClientCertificate)) {
|
||||
auto cert_path = cmd->GetSwitchValuePath(switches::kClientCertificate);
|
||||
auto certificate = ImportCertFromFile(cert_path);
|
||||
if (certificate.get())
|
||||
delegate->ContinueWithCertificate(certificate.get());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cert_request_info->client_certs.empty())
|
||||
Browser::Get()->ClientCertificateSelector(web_contents,
|
||||
cert_request_info,
|
||||
delegate.Pass());
|
||||
}
|
||||
|
||||
brightray::BrowserMainParts* AtomBrowserClient::OverrideCreateBrowserMainParts(
|
||||
const content::MainFunctionParams&) {
|
||||
v8::V8::Initialize(); // Init V8 before creating main parts.
|
||||
|
||||
@@ -6,17 +6,21 @@
|
||||
#define ATOM_BROWSER_ATOM_BROWSER_CLIENT_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "brightray/browser/browser_client.h"
|
||||
|
||||
namespace content {
|
||||
class QuotaPermissionContext;
|
||||
class ClientCertificateDelegate;
|
||||
}
|
||||
|
||||
namespace net {
|
||||
class SSLCertRequestInfo;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomResourceDispatcherHostDelegate;
|
||||
|
||||
class AtomBrowserClient : public brightray::BrowserClient {
|
||||
public:
|
||||
AtomBrowserClient();
|
||||
@@ -24,6 +28,8 @@ class AtomBrowserClient : public brightray::BrowserClient {
|
||||
|
||||
// Don't force renderer process to restart for once.
|
||||
static void SuppressRendererProcessRestartForOnce();
|
||||
// Custom schemes to be registered to standard.
|
||||
static void SetCustomSchemes(const std::vector<std::string>& schemes);
|
||||
|
||||
protected:
|
||||
// content::ContentBrowserClient:
|
||||
@@ -31,7 +37,6 @@ class AtomBrowserClient : public brightray::BrowserClient {
|
||||
content::SpeechRecognitionManagerDelegate*
|
||||
CreateSpeechRecognitionManagerDelegate() override;
|
||||
content::AccessTokenStore* CreateAccessTokenStore() override;
|
||||
void ResourceDispatcherHostCreated() override;
|
||||
void OverrideWebkitPrefs(content::RenderViewHost* render_view_host,
|
||||
content::WebPreferences* prefs) override;
|
||||
std::string GetApplicationLocale() override;
|
||||
@@ -39,21 +44,20 @@ class AtomBrowserClient : public brightray::BrowserClient {
|
||||
content::BrowserContext* browser_context,
|
||||
content::SiteInstance* current_instance,
|
||||
const GURL& dest_url,
|
||||
content::SiteInstance** new_instance);
|
||||
content::SiteInstance** new_instance) override;
|
||||
void AppendExtraCommandLineSwitches(base::CommandLine* command_line,
|
||||
int child_process_id) override;
|
||||
void DidCreatePpapiPlugin(content::BrowserPpapiHost* browser_host) override;
|
||||
content::QuotaPermissionContext* CreateQuotaPermissionContext() override;
|
||||
void SelectClientCertificate(
|
||||
content::WebContents* web_contents,
|
||||
net::SSLCertRequestInfo* cert_request_info,
|
||||
scoped_ptr<content::ClientCertificateDelegate> delegate) override;
|
||||
|
||||
private:
|
||||
brightray::BrowserMainParts* OverrideCreateBrowserMainParts(
|
||||
const content::MainFunctionParams&) override;
|
||||
|
||||
scoped_ptr<AtomResourceDispatcherHostDelegate> resource_dispatcher_delegate_;
|
||||
|
||||
// The render process which would be swapped out soon.
|
||||
content::RenderProcessHost* dying_render_process_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomBrowserClient);
|
||||
};
|
||||
|
||||
|
||||
@@ -5,17 +5,26 @@
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
|
||||
#include "atom/browser/atom_browser_main_parts.h"
|
||||
#include "atom/browser/atom_download_manager_delegate.h"
|
||||
#include "atom/browser/browser.h"
|
||||
#include "atom/browser/net/atom_url_request_job_factory.h"
|
||||
#include "atom/browser/net/asar/asar_protocol_handler.h"
|
||||
#include "atom/browser/net/http_protocol_handler.h"
|
||||
#include "atom/browser/web_view_manager.h"
|
||||
#include "atom/common/atom_version.h"
|
||||
#include "atom/common/chrome_version.h"
|
||||
#include "atom/common/options_switches.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/prefs/pref_registry_simple.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/threading/sequenced_worker_pool.h"
|
||||
#include "base/threading/worker_pool.h"
|
||||
#include "chrome/browser/browser_process.h"
|
||||
#include "chrome/common/pref_names.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/common/url_constants.h"
|
||||
#include "content/public/common/user_agent.h"
|
||||
#include "net/ftp/ftp_network_layer.h"
|
||||
#include "net/url_request/data_protocol_handler.h"
|
||||
#include "net/url_request/ftp_protocol_handler.h"
|
||||
@@ -37,16 +46,40 @@ class NoCacheBackend : public net::HttpCache::BackendFactory {
|
||||
}
|
||||
};
|
||||
|
||||
std::string RemoveWhitespace(const std::string& str) {
|
||||
std::string trimmed;
|
||||
if (base::RemoveChars(str, " ", &trimmed))
|
||||
return trimmed;
|
||||
else
|
||||
return str;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
AtomBrowserContext::AtomBrowserContext()
|
||||
: fake_browser_process_(new BrowserProcess),
|
||||
job_factory_(new AtomURLRequestJobFactory) {
|
||||
: job_factory_(new AtomURLRequestJobFactory) {
|
||||
}
|
||||
|
||||
AtomBrowserContext::~AtomBrowserContext() {
|
||||
}
|
||||
|
||||
std::string AtomBrowserContext::GetUserAgent() {
|
||||
Browser* browser = Browser::Get();
|
||||
std::string name = RemoveWhitespace(browser->GetName());
|
||||
std::string user_agent;
|
||||
if (name == ATOM_PRODUCT_NAME) {
|
||||
user_agent = "Chrome/" CHROME_VERSION_STRING " "
|
||||
ATOM_PRODUCT_NAME "/" ATOM_VERSION_STRING;
|
||||
} else {
|
||||
user_agent = base::StringPrintf(
|
||||
"%s/%s Chrome/%s " ATOM_PRODUCT_NAME "/" ATOM_VERSION_STRING,
|
||||
name.c_str(),
|
||||
browser->GetVersion().c_str(),
|
||||
CHROME_VERSION_STRING);
|
||||
}
|
||||
return content::BuildUserAgentFromProduct(user_agent);
|
||||
}
|
||||
|
||||
net::URLRequestJobFactory* AtomBrowserContext::CreateURLRequestJobFactory(
|
||||
content::ProtocolHandlerMap* handlers,
|
||||
content::URLRequestInterceptorScopedVector* interceptors) {
|
||||
@@ -100,16 +133,27 @@ AtomBrowserContext::CreateHttpCacheBackendFactory(
|
||||
return brightray::BrowserContext::CreateHttpCacheBackendFactory(base_path);
|
||||
}
|
||||
|
||||
content::DownloadManagerDelegate*
|
||||
AtomBrowserContext::GetDownloadManagerDelegate() {
|
||||
if (!download_manager_delegate_.get()) {
|
||||
auto download_manager = content::BrowserContext::GetDownloadManager(this);
|
||||
download_manager_delegate_.reset(
|
||||
new AtomDownloadManagerDelegate(download_manager));
|
||||
}
|
||||
return download_manager_delegate_.get();
|
||||
}
|
||||
|
||||
content::BrowserPluginGuestManager* AtomBrowserContext::GetGuestManager() {
|
||||
if (!guest_manager_)
|
||||
guest_manager_.reset(new WebViewManager(this));
|
||||
return guest_manager_.get();
|
||||
}
|
||||
|
||||
// static
|
||||
AtomBrowserContext* AtomBrowserContext::Get() {
|
||||
return static_cast<AtomBrowserContext*>(
|
||||
AtomBrowserMainParts::Get()->browser_context());
|
||||
void AtomBrowserContext::RegisterPrefs(PrefRegistrySimple* pref_registry) {
|
||||
pref_registry->RegisterFilePathPref(prefs::kSelectFileLastDirectory,
|
||||
base::FilePath());
|
||||
pref_registry->RegisterFilePathPref(prefs::kDownloadDefaultDirectory,
|
||||
base::FilePath());
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -5,12 +5,13 @@
|
||||
#ifndef ATOM_BROWSER_ATOM_BROWSER_CONTEXT_H_
|
||||
#define ATOM_BROWSER_ATOM_BROWSER_CONTEXT_H_
|
||||
|
||||
#include "brightray/browser/browser_context.h"
|
||||
#include <string>
|
||||
|
||||
class BrowserProcess;
|
||||
#include "brightray/browser/browser_context.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomDownloadManagerDelegate;
|
||||
class AtomURLRequestJobFactory;
|
||||
class WebViewManager;
|
||||
|
||||
@@ -19,10 +20,8 @@ class AtomBrowserContext : public brightray::BrowserContext {
|
||||
AtomBrowserContext();
|
||||
virtual ~AtomBrowserContext();
|
||||
|
||||
// Returns the browser context singleton.
|
||||
static AtomBrowserContext* Get();
|
||||
|
||||
// brightray::URLRequestContextGetter::Delegate:
|
||||
std::string GetUserAgent() override;
|
||||
net::URLRequestJobFactory* CreateURLRequestJobFactory(
|
||||
content::ProtocolHandlerMap* handlers,
|
||||
content::URLRequestInterceptorScopedVector* interceptors) override;
|
||||
@@ -30,13 +29,16 @@ class AtomBrowserContext : public brightray::BrowserContext {
|
||||
const base::FilePath& base_path) override;
|
||||
|
||||
// content::BrowserContext:
|
||||
content::DownloadManagerDelegate* GetDownloadManagerDelegate() override;
|
||||
content::BrowserPluginGuestManager* GetGuestManager() override;
|
||||
|
||||
// brightray::BrowserContext:
|
||||
void RegisterPrefs(PrefRegistrySimple* pref_registry) override;
|
||||
|
||||
AtomURLRequestJobFactory* job_factory() const { return job_factory_; }
|
||||
|
||||
private:
|
||||
// A fake BrowserProcess object that used to feed the source code from chrome.
|
||||
scoped_ptr<BrowserProcess> fake_browser_process_;
|
||||
scoped_ptr<AtomDownloadManagerDelegate> download_manager_delegate_;
|
||||
scoped_ptr<WebViewManager> guest_manager_;
|
||||
|
||||
AtomURLRequestJobFactory* job_factory_; // Weak reference.
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "atom/browser/atom_browser_main_parts.h"
|
||||
|
||||
#include "atom/browser/api/trackable_object.h"
|
||||
#include "atom/browser/atom_browser_client.h"
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/browser.h"
|
||||
@@ -11,6 +12,7 @@
|
||||
#include "atom/common/api/atom_bindings.h"
|
||||
#include "atom/common/node_bindings.h"
|
||||
#include "base/command_line.h"
|
||||
#include "chrome/browser/browser_process.h"
|
||||
#include "v8/include/v8-debug.h"
|
||||
|
||||
#if defined(USE_X11)
|
||||
@@ -25,7 +27,8 @@ namespace atom {
|
||||
AtomBrowserMainParts* AtomBrowserMainParts::self_ = NULL;
|
||||
|
||||
AtomBrowserMainParts::AtomBrowserMainParts()
|
||||
: browser_(new Browser),
|
||||
: fake_browser_process_(new BrowserProcess),
|
||||
browser_(new Browser),
|
||||
node_bindings_(NodeBindings::Create(true)),
|
||||
atom_bindings_(new AtomBindings),
|
||||
gc_timer_(true, true) {
|
||||
@@ -34,6 +37,8 @@ AtomBrowserMainParts::AtomBrowserMainParts()
|
||||
}
|
||||
|
||||
AtomBrowserMainParts::~AtomBrowserMainParts() {
|
||||
for (const auto& callback : destruction_callbacks_)
|
||||
callback.Run();
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -42,6 +47,11 @@ AtomBrowserMainParts* AtomBrowserMainParts::Get() {
|
||||
return self_;
|
||||
}
|
||||
|
||||
void AtomBrowserMainParts::RegisterDestructionCallback(
|
||||
const base::Closure& callback) {
|
||||
destruction_callbacks_.push_back(callback);
|
||||
}
|
||||
|
||||
brightray::BrowserContext* AtomBrowserMainParts::CreateBrowserContext() {
|
||||
return new AtomBrowserContext();
|
||||
}
|
||||
|
||||
@@ -5,9 +5,14 @@
|
||||
#ifndef ATOM_BROWSER_ATOM_BROWSER_MAIN_PARTS_H_
|
||||
#define ATOM_BROWSER_ATOM_BROWSER_MAIN_PARTS_H_
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/timer/timer.h"
|
||||
#include "brightray/browser/browser_main_parts.h"
|
||||
|
||||
class BrowserProcess;
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomBindings;
|
||||
@@ -22,6 +27,10 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
|
||||
|
||||
static AtomBrowserMainParts* Get();
|
||||
|
||||
// Register a callback that should be destroyed before JavaScript environment
|
||||
// gets destroyed.
|
||||
void RegisterDestructionCallback(const base::Closure& callback);
|
||||
|
||||
Browser* browser() { return browser_.get(); }
|
||||
|
||||
protected:
|
||||
@@ -41,6 +50,9 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
|
||||
void SetDPIFromGSettings();
|
||||
#endif
|
||||
|
||||
// A fake BrowserProcess object that used to feed the source code from chrome.
|
||||
scoped_ptr<BrowserProcess> fake_browser_process_;
|
||||
|
||||
scoped_ptr<Browser> browser_;
|
||||
scoped_ptr<JavascriptEnvironment> js_env_;
|
||||
scoped_ptr<NodeBindings> node_bindings_;
|
||||
@@ -48,6 +60,9 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
|
||||
|
||||
base::Timer gc_timer_;
|
||||
|
||||
// List of callbacks should be executed before destroying JS env.
|
||||
std::list<base::Closure> destruction_callbacks_;
|
||||
|
||||
static AtomBrowserMainParts* self_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomBrowserMainParts);
|
||||
|
||||
151
atom/browser/atom_download_manager_delegate.cc
Normal file
151
atom/browser/atom_download_manager_delegate.cc
Normal file
@@ -0,0 +1,151 @@
|
||||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/atom_download_manager_delegate.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/ui/file_dialog.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/prefs/pref_service.h"
|
||||
#include "chrome/common/pref_names.h"
|
||||
#include "content/public/browser/browser_context.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/download_manager.h"
|
||||
#include "net/base/filename_util.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
AtomDownloadManagerDelegate::AtomDownloadManagerDelegate(
|
||||
content::DownloadManager* manager)
|
||||
: download_manager_(manager),
|
||||
weak_ptr_factory_(this) {}
|
||||
|
||||
AtomDownloadManagerDelegate::~AtomDownloadManagerDelegate() {
|
||||
if (download_manager_) {
|
||||
DCHECK_EQ(static_cast<content::DownloadManagerDelegate*>(this),
|
||||
download_manager_->GetDelegate());
|
||||
download_manager_->SetDelegate(nullptr);
|
||||
download_manager_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void AtomDownloadManagerDelegate::CreateDownloadPath(
|
||||
const GURL& url,
|
||||
const std::string& content_disposition,
|
||||
const std::string& suggested_filename,
|
||||
const std::string& mime_type,
|
||||
const base::FilePath& default_download_path,
|
||||
const CreateDownloadPathCallback& callback) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
|
||||
|
||||
auto generated_name = net::GenerateFileName(url,
|
||||
content_disposition,
|
||||
std::string(),
|
||||
suggested_filename,
|
||||
mime_type,
|
||||
std::string());
|
||||
|
||||
if (!base::PathExists(default_download_path))
|
||||
base::CreateDirectory(default_download_path);
|
||||
|
||||
base::FilePath path(default_download_path.Append(generated_name));
|
||||
content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(callback, path));
|
||||
}
|
||||
|
||||
void AtomDownloadManagerDelegate::OnDownloadPathGenerated(
|
||||
uint32 download_id,
|
||||
const content::DownloadTargetCallback& callback,
|
||||
const base::FilePath& default_path) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
|
||||
auto item = download_manager_->GetDownload(download_id);
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
NativeWindow* window = nullptr;
|
||||
auto relay = NativeWindowRelay::FromWebContents(item->GetWebContents());
|
||||
if (relay)
|
||||
window = relay->window.get();
|
||||
|
||||
file_dialog::Filters filters;
|
||||
base::FilePath path;
|
||||
if (!file_dialog::ShowSaveDialog(window, item->GetURL().spec(), default_path,
|
||||
filters, &path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remeber the last selected download directory.
|
||||
AtomBrowserContext* browser_context = static_cast<AtomBrowserContext*>(
|
||||
download_manager_->GetBrowserContext());
|
||||
browser_context->prefs()->SetFilePath(prefs::kDownloadDefaultDirectory,
|
||||
path.DirName());
|
||||
callback.Run(path,
|
||||
content::DownloadItem::TARGET_DISPOSITION_PROMPT,
|
||||
content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, path);
|
||||
}
|
||||
|
||||
void AtomDownloadManagerDelegate::Shutdown() {
|
||||
weak_ptr_factory_.InvalidateWeakPtrs();
|
||||
download_manager_ = nullptr;
|
||||
}
|
||||
|
||||
bool AtomDownloadManagerDelegate::DetermineDownloadTarget(
|
||||
content::DownloadItem* download,
|
||||
const content::DownloadTargetCallback& callback) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
|
||||
AtomBrowserContext* browser_context = static_cast<AtomBrowserContext*>(
|
||||
download_manager_->GetBrowserContext());
|
||||
base::FilePath default_download_path = browser_context->prefs()->GetFilePath(
|
||||
prefs::kDownloadDefaultDirectory);
|
||||
// If users didn't set download path, use 'Downloads' directory by default.
|
||||
if (default_download_path.empty()) {
|
||||
auto path = download_manager_->GetBrowserContext()->GetPath();
|
||||
default_download_path = path.Append(FILE_PATH_LITERAL("Downloads"));
|
||||
}
|
||||
|
||||
if (!download->GetForcedFilePath().empty()) {
|
||||
callback.Run(download->GetForcedFilePath(),
|
||||
content::DownloadItem::TARGET_DISPOSITION_OVERWRITE,
|
||||
content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
|
||||
download->GetForcedFilePath());
|
||||
return true;
|
||||
}
|
||||
|
||||
CreateDownloadPathCallback download_path_callback =
|
||||
base::Bind(&AtomDownloadManagerDelegate::OnDownloadPathGenerated,
|
||||
weak_ptr_factory_.GetWeakPtr(),
|
||||
download->GetId(), callback);
|
||||
|
||||
content::BrowserThread::PostTask(
|
||||
content::BrowserThread::FILE, FROM_HERE,
|
||||
base::Bind(&AtomDownloadManagerDelegate::CreateDownloadPath,
|
||||
weak_ptr_factory_.GetWeakPtr(),
|
||||
download->GetURL(),
|
||||
download->GetContentDisposition(),
|
||||
download->GetSuggestedFilename(),
|
||||
download->GetMimeType(),
|
||||
default_download_path,
|
||||
download_path_callback));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AtomDownloadManagerDelegate::ShouldOpenDownload(
|
||||
content::DownloadItem* download,
|
||||
const content::DownloadOpenDelayedCallback& callback) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void AtomDownloadManagerDelegate::GetNextId(
|
||||
const content::DownloadIdCallback& callback) {
|
||||
static uint32 next_id = content::DownloadItem::kInvalidId + 1;
|
||||
callback.Run(next_id++);
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
57
atom/browser/atom_download_manager_delegate.h
Normal file
57
atom/browser/atom_download_manager_delegate.h
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_ATOM_DOWNLOAD_MANAGER_DELEGATE_H_
|
||||
#define ATOM_BROWSER_ATOM_DOWNLOAD_MANAGER_DELEGATE_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "content/public/browser/download_manager_delegate.h"
|
||||
|
||||
namespace content {
|
||||
class DownloadManager;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomDownloadManagerDelegate : public content::DownloadManagerDelegate {
|
||||
public:
|
||||
using CreateDownloadPathCallback =
|
||||
base::Callback<void(const base::FilePath&)>;
|
||||
|
||||
explicit AtomDownloadManagerDelegate(content::DownloadManager* manager);
|
||||
virtual ~AtomDownloadManagerDelegate();
|
||||
|
||||
// Generate default file path to save the download.
|
||||
void CreateDownloadPath(const GURL& url,
|
||||
const std::string& suggested_filename,
|
||||
const std::string& content_disposition,
|
||||
const std::string& mime_type,
|
||||
const base::FilePath& path,
|
||||
const CreateDownloadPathCallback& callback);
|
||||
void OnDownloadPathGenerated(uint32 download_id,
|
||||
const content::DownloadTargetCallback& callback,
|
||||
const base::FilePath& default_path);
|
||||
|
||||
// content::DownloadManagerDelegate:
|
||||
void Shutdown() override;
|
||||
bool DetermineDownloadTarget(
|
||||
content::DownloadItem* download,
|
||||
const content::DownloadTargetCallback& callback) override;
|
||||
bool ShouldOpenDownload(
|
||||
content::DownloadItem* download,
|
||||
const content::DownloadOpenDelayedCallback& callback) override;
|
||||
void GetNextId(const content::DownloadIdCallback& callback) override;
|
||||
|
||||
private:
|
||||
content::DownloadManager* download_manager_;
|
||||
base::WeakPtrFactory<AtomDownloadManagerDelegate> weak_ptr_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomDownloadManagerDelegate);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_ATOM_DOWNLOAD_MANAGER_DELEGATE_H_
|
||||
@@ -1,33 +0,0 @@
|
||||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/atom_resource_dispatcher_host_delegate.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "content/public/browser/render_frame_host.h"
|
||||
#include "content/public/browser/resource_request_info.h"
|
||||
#include "net/http/http_response_headers.h"
|
||||
#include "net/url_request/url_request.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
AtomResourceDispatcherHostDelegate::AtomResourceDispatcherHostDelegate() {
|
||||
}
|
||||
|
||||
void AtomResourceDispatcherHostDelegate::OnResponseStarted(
|
||||
net::URLRequest* request,
|
||||
content::ResourceContext* resource_context,
|
||||
content::ResourceResponse* response,
|
||||
IPC::Sender* sender) {
|
||||
// Remove the "X-Frame-Options" from response headers for devtools.
|
||||
if (request->url().SchemeIs("chrome-devtools")) {
|
||||
net::HttpResponseHeaders* response_headers = request->response_headers();
|
||||
if (response_headers && response_headers->HasHeader("x-frame-options"))
|
||||
response_headers->RemoveHeader("x-frame-options");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
@@ -1,30 +0,0 @@
|
||||
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_ATOM_RESOURCE_DISPATCHER_HOST_DELEGATE_H_
|
||||
#define ATOM_BROWSER_ATOM_RESOURCE_DISPATCHER_HOST_DELEGATE_H_
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
#include "content/public/browser/resource_dispatcher_host_delegate.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomResourceDispatcherHostDelegate
|
||||
: public content::ResourceDispatcherHostDelegate {
|
||||
public:
|
||||
AtomResourceDispatcherHostDelegate();
|
||||
|
||||
// content::ResourceDispatcherHostDelegate:
|
||||
void OnResponseStarted(net::URLRequest* request,
|
||||
content::ResourceContext* resource_context,
|
||||
content::ResourceResponse* response,
|
||||
IPC::Sender* sender) override;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomResourceDispatcherHostDelegate);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_ATOM_RESOURCE_DISPATCHER_HOST_DELEGATE_H_
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "atom/browser/atom_browser_main_parts.h"
|
||||
#include "atom/browser/window_list.h"
|
||||
#include "base/message_loop/message_loop.h"
|
||||
#include "content/public/browser/client_certificate_delegate.h"
|
||||
#include "net/ssl/ssl_cert_request_info.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
@@ -104,6 +106,17 @@ void Browser::DidFinishLaunching() {
|
||||
FOR_EACH_OBSERVER(BrowserObserver, observers_, OnFinishLaunching());
|
||||
}
|
||||
|
||||
void Browser::ClientCertificateSelector(
|
||||
content::WebContents* web_contents,
|
||||
net::SSLCertRequestInfo* cert_request_info,
|
||||
scoped_ptr<content::ClientCertificateDelegate> delegate) {
|
||||
FOR_EACH_OBSERVER(BrowserObserver,
|
||||
observers_,
|
||||
OnSelectCertificate(web_contents,
|
||||
cert_request_info,
|
||||
delegate.Pass()));
|
||||
}
|
||||
|
||||
void Browser::NotifyAndShutdown() {
|
||||
bool prevent_default = false;
|
||||
FOR_EACH_OBSERVER(BrowserObserver, observers_, OnWillQuit(&prevent_default));
|
||||
|
||||
@@ -115,6 +115,12 @@ class Browser : public WindowListObserver {
|
||||
void WillFinishLaunching();
|
||||
void DidFinishLaunching();
|
||||
|
||||
// Called when client certificate is required.
|
||||
void ClientCertificateSelector(
|
||||
content::WebContents* web_contents,
|
||||
net::SSLCertRequestInfo* cert_request_info,
|
||||
scoped_ptr<content::ClientCertificateDelegate> delegate);
|
||||
|
||||
void AddObserver(BrowserObserver* obs) {
|
||||
observers_.AddObserver(obs);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,17 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "content/public/browser/client_certificate_delegate.h"
|
||||
|
||||
namespace content {
|
||||
class WebContents;
|
||||
}
|
||||
|
||||
namespace net {
|
||||
class SSLCertRequestInfo;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
class BrowserObserver {
|
||||
@@ -40,6 +51,12 @@ class BrowserObserver {
|
||||
virtual void OnWillFinishLaunching() {}
|
||||
virtual void OnFinishLaunching() {}
|
||||
|
||||
// The browser requires client certificate.
|
||||
virtual void OnSelectCertificate(
|
||||
content::WebContents* web_contents,
|
||||
net::SSLCertRequestInfo* cert_request_info,
|
||||
scoped_ptr<content::ClientCertificateDelegate> delegate) {}
|
||||
|
||||
protected:
|
||||
virtual ~BrowserObserver() {}
|
||||
};
|
||||
|
||||
377
atom/browser/common_web_contents_delegate.cc
Normal file
377
atom/browser/common_web_contents_delegate.cc
Normal file
@@ -0,0 +1,377 @@
|
||||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/common_web_contents_delegate.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/browser/atom_javascript_dialog_manager.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/ui/file_dialog.h"
|
||||
#include "atom/browser/web_dialog_helper.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "chrome/browser/printing/print_preview_message_handler.h"
|
||||
#include "chrome/browser/printing/print_view_manager_basic.h"
|
||||
#include "chrome/browser/ui/browser_dialogs.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/child_process_security_policy.h"
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#include "storage/browser/fileapi/isolated_context.h"
|
||||
|
||||
using content::BrowserThread;
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
struct FileSystem {
|
||||
FileSystem() {
|
||||
}
|
||||
FileSystem(const std::string& file_system_name,
|
||||
const std::string& root_url,
|
||||
const std::string& file_system_path)
|
||||
: file_system_name(file_system_name),
|
||||
root_url(root_url),
|
||||
file_system_path(file_system_path) {
|
||||
}
|
||||
|
||||
std::string file_system_name;
|
||||
std::string root_url;
|
||||
std::string file_system_path;
|
||||
};
|
||||
|
||||
std::string RegisterFileSystem(content::WebContents* web_contents,
|
||||
const base::FilePath& path,
|
||||
std::string* registered_name) {
|
||||
auto isolated_context = storage::IsolatedContext::GetInstance();
|
||||
std::string file_system_id = isolated_context->RegisterFileSystemForPath(
|
||||
storage::kFileSystemTypeNativeLocal,
|
||||
std::string(),
|
||||
path,
|
||||
registered_name);
|
||||
|
||||
content::ChildProcessSecurityPolicy* policy =
|
||||
content::ChildProcessSecurityPolicy::GetInstance();
|
||||
content::RenderViewHost* render_view_host = web_contents->GetRenderViewHost();
|
||||
int renderer_id = render_view_host->GetProcess()->GetID();
|
||||
policy->GrantReadFileSystem(renderer_id, file_system_id);
|
||||
policy->GrantWriteFileSystem(renderer_id, file_system_id);
|
||||
policy->GrantCreateFileForFileSystem(renderer_id, file_system_id);
|
||||
policy->GrantDeleteFromFileSystem(renderer_id, file_system_id);
|
||||
|
||||
if (!policy->CanReadFile(renderer_id, path))
|
||||
policy->GrantReadFile(renderer_id, path);
|
||||
|
||||
return file_system_id;
|
||||
}
|
||||
|
||||
FileSystem CreateFileSystemStruct(
|
||||
content::WebContents* web_contents,
|
||||
const std::string& file_system_id,
|
||||
const std::string& registered_name,
|
||||
const std::string& file_system_path) {
|
||||
const GURL origin = web_contents->GetURL().GetOrigin();
|
||||
std::string file_system_name =
|
||||
storage::GetIsolatedFileSystemName(origin, file_system_id);
|
||||
std::string root_url = storage::GetIsolatedFileSystemRootURIString(
|
||||
origin, file_system_id, registered_name);
|
||||
return FileSystem(file_system_name, root_url, file_system_path);
|
||||
}
|
||||
|
||||
base::DictionaryValue* CreateFileSystemValue(const FileSystem& file_system) {
|
||||
base::DictionaryValue* file_system_value = new base::DictionaryValue();
|
||||
file_system_value->SetString("fileSystemName", file_system.file_system_name);
|
||||
file_system_value->SetString("rootURL", file_system.root_url);
|
||||
file_system_value->SetString("fileSystemPath", file_system.file_system_path);
|
||||
return file_system_value;
|
||||
}
|
||||
|
||||
void WriteToFile(const base::FilePath& path,
|
||||
const std::string& content) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
|
||||
DCHECK(!path.empty());
|
||||
|
||||
base::WriteFile(path, content.data(), content.size());
|
||||
}
|
||||
|
||||
void AppendToFile(const base::FilePath& path,
|
||||
const std::string& content) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
|
||||
DCHECK(!path.empty());
|
||||
|
||||
base::AppendToFile(path, content.data(), content.size());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
CommonWebContentsDelegate::CommonWebContentsDelegate()
|
||||
: html_fullscreen_(false),
|
||||
native_fullscreen_(false) {
|
||||
}
|
||||
|
||||
CommonWebContentsDelegate::~CommonWebContentsDelegate() {
|
||||
}
|
||||
|
||||
void CommonWebContentsDelegate::InitWithWebContents(
|
||||
content::WebContents* web_contents) {
|
||||
web_contents->SetDelegate(this);
|
||||
|
||||
printing::PrintViewManagerBasic::CreateForWebContents(web_contents);
|
||||
printing::PrintPreviewMessageHandler::CreateForWebContents(web_contents);
|
||||
|
||||
// Create InspectableWebContents.
|
||||
web_contents_.reset(brightray::InspectableWebContents::Create(web_contents));
|
||||
web_contents_->SetDelegate(this);
|
||||
}
|
||||
|
||||
void CommonWebContentsDelegate::SetOwnerWindow(NativeWindow* owner_window) {
|
||||
content::WebContents* web_contents = GetWebContents();
|
||||
owner_window_ = owner_window->GetWeakPtr();
|
||||
NativeWindowRelay* relay = new NativeWindowRelay(owner_window_);
|
||||
web_contents->SetUserData(relay->key, relay);
|
||||
}
|
||||
|
||||
void CommonWebContentsDelegate::DestroyWebContents() {
|
||||
web_contents_.reset();
|
||||
}
|
||||
|
||||
content::WebContents* CommonWebContentsDelegate::GetWebContents() const {
|
||||
if (!web_contents_)
|
||||
return nullptr;
|
||||
return web_contents_->GetWebContents();
|
||||
}
|
||||
|
||||
content::WebContents*
|
||||
CommonWebContentsDelegate::GetDevToolsWebContents() const {
|
||||
if (!web_contents_)
|
||||
return nullptr;
|
||||
return web_contents_->GetDevToolsWebContents();
|
||||
}
|
||||
|
||||
content::WebContents* CommonWebContentsDelegate::OpenURLFromTab(
|
||||
content::WebContents* source,
|
||||
const content::OpenURLParams& params) {
|
||||
content::NavigationController::LoadURLParams load_url_params(params.url);
|
||||
load_url_params.referrer = params.referrer;
|
||||
load_url_params.transition_type = params.transition;
|
||||
load_url_params.extra_headers = params.extra_headers;
|
||||
load_url_params.should_replace_current_entry =
|
||||
params.should_replace_current_entry;
|
||||
load_url_params.is_renderer_initiated = params.is_renderer_initiated;
|
||||
load_url_params.transferred_global_request_id =
|
||||
params.transferred_global_request_id;
|
||||
load_url_params.should_clear_history_list = true;
|
||||
|
||||
source->GetController().LoadURLWithParams(load_url_params);
|
||||
return source;
|
||||
}
|
||||
|
||||
void CommonWebContentsDelegate::RequestToLockMouse(
|
||||
content::WebContents* web_contents,
|
||||
bool user_gesture,
|
||||
bool last_unlocked_by_target) {
|
||||
GetWebContents()->GotResponseToLockMouseRequest(true);
|
||||
}
|
||||
|
||||
bool CommonWebContentsDelegate::CanOverscrollContent() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
content::JavaScriptDialogManager*
|
||||
CommonWebContentsDelegate::GetJavaScriptDialogManager(
|
||||
content::WebContents* source) {
|
||||
if (!dialog_manager_)
|
||||
dialog_manager_.reset(new AtomJavaScriptDialogManager);
|
||||
|
||||
return dialog_manager_.get();
|
||||
}
|
||||
|
||||
content::ColorChooser* CommonWebContentsDelegate::OpenColorChooser(
|
||||
content::WebContents* web_contents,
|
||||
SkColor color,
|
||||
const std::vector<content::ColorSuggestion>& suggestions) {
|
||||
return chrome::ShowColorChooser(web_contents, color);
|
||||
}
|
||||
|
||||
void CommonWebContentsDelegate::RunFileChooser(
|
||||
content::WebContents* guest,
|
||||
const content::FileChooserParams& params) {
|
||||
if (!web_dialog_helper_)
|
||||
web_dialog_helper_.reset(new WebDialogHelper(owner_window()));
|
||||
web_dialog_helper_->RunFileChooser(guest, params);
|
||||
}
|
||||
|
||||
void CommonWebContentsDelegate::EnumerateDirectory(content::WebContents* guest,
|
||||
int request_id,
|
||||
const base::FilePath& path) {
|
||||
if (!web_dialog_helper_)
|
||||
web_dialog_helper_.reset(new WebDialogHelper(owner_window()));
|
||||
web_dialog_helper_->EnumerateDirectory(guest, request_id, path);
|
||||
}
|
||||
|
||||
void CommonWebContentsDelegate::EnterFullscreenModeForTab(
|
||||
content::WebContents* source, const GURL& origin) {
|
||||
if (!owner_window_)
|
||||
return;
|
||||
SetHtmlApiFullscreen(true);
|
||||
owner_window_->NotifyWindowEnterHtmlFullScreen();
|
||||
source->GetRenderViewHost()->WasResized();
|
||||
}
|
||||
|
||||
void CommonWebContentsDelegate::ExitFullscreenModeForTab(
|
||||
content::WebContents* source) {
|
||||
if (!owner_window_)
|
||||
return;
|
||||
SetHtmlApiFullscreen(false);
|
||||
owner_window_->NotifyWindowLeaveHtmlFullScreen();
|
||||
source->GetRenderViewHost()->WasResized();
|
||||
}
|
||||
|
||||
bool CommonWebContentsDelegate::IsFullscreenForTabOrPending(
|
||||
const content::WebContents* source) const {
|
||||
return html_fullscreen_;
|
||||
}
|
||||
|
||||
void CommonWebContentsDelegate::DevToolsSaveToFile(
|
||||
const std::string& url, const std::string& content, bool save_as) {
|
||||
base::FilePath path;
|
||||
PathsMap::iterator it = saved_files_.find(url);
|
||||
if (it != saved_files_.end() && !save_as) {
|
||||
path = it->second;
|
||||
} else {
|
||||
file_dialog::Filters filters;
|
||||
base::FilePath default_path(base::FilePath::FromUTF8Unsafe(url));
|
||||
if (!file_dialog::ShowSaveDialog(owner_window(), url, default_path,
|
||||
filters, &path)) {
|
||||
base::StringValue url_value(url);
|
||||
web_contents_->CallClientFunction(
|
||||
"DevToolsAPI.canceledSaveURL", &url_value, nullptr, nullptr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
saved_files_[url] = path;
|
||||
BrowserThread::PostTaskAndReply(
|
||||
BrowserThread::FILE, FROM_HERE,
|
||||
base::Bind(&WriteToFile, path, content),
|
||||
base::Bind(&CommonWebContentsDelegate::OnDevToolsSaveToFile,
|
||||
base::Unretained(this), url));
|
||||
}
|
||||
|
||||
void CommonWebContentsDelegate::DevToolsAppendToFile(
|
||||
const std::string& url, const std::string& content) {
|
||||
PathsMap::iterator it = saved_files_.find(url);
|
||||
if (it == saved_files_.end())
|
||||
return;
|
||||
|
||||
BrowserThread::PostTaskAndReply(
|
||||
BrowserThread::FILE, FROM_HERE,
|
||||
base::Bind(&AppendToFile, it->second, content),
|
||||
base::Bind(&CommonWebContentsDelegate::OnDevToolsAppendToFile,
|
||||
base::Unretained(this), url));
|
||||
}
|
||||
|
||||
void CommonWebContentsDelegate::DevToolsAddFileSystem(
|
||||
const base::FilePath& file_system_path) {
|
||||
base::FilePath path = file_system_path;
|
||||
if (path.empty()) {
|
||||
file_dialog::Filters filters;
|
||||
base::FilePath default_path;
|
||||
std::vector<base::FilePath> paths;
|
||||
int flag = file_dialog::FILE_DIALOG_OPEN_DIRECTORY;
|
||||
if (!file_dialog::ShowOpenDialog(owner_window(), "", default_path,
|
||||
filters, flag, &paths))
|
||||
return;
|
||||
|
||||
path = paths[0];
|
||||
}
|
||||
|
||||
std::string registered_name;
|
||||
std::string file_system_id = RegisterFileSystem(GetDevToolsWebContents(),
|
||||
path,
|
||||
®istered_name);
|
||||
|
||||
WorkspaceMap::iterator it = saved_paths_.find(file_system_id);
|
||||
if (it != saved_paths_.end())
|
||||
return;
|
||||
|
||||
saved_paths_[file_system_id] = path;
|
||||
|
||||
FileSystem file_system = CreateFileSystemStruct(GetDevToolsWebContents(),
|
||||
file_system_id,
|
||||
registered_name,
|
||||
path.AsUTF8Unsafe());
|
||||
|
||||
scoped_ptr<base::StringValue> error_string_value(
|
||||
new base::StringValue(std::string()));
|
||||
scoped_ptr<base::DictionaryValue> file_system_value;
|
||||
if (!file_system.file_system_path.empty())
|
||||
file_system_value.reset(CreateFileSystemValue(file_system));
|
||||
web_contents_->CallClientFunction(
|
||||
"DevToolsAPI.fileSystemAdded",
|
||||
error_string_value.get(),
|
||||
file_system_value.get(),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
void CommonWebContentsDelegate::DevToolsRemoveFileSystem(
|
||||
const base::FilePath& file_system_path) {
|
||||
if (!web_contents_)
|
||||
return;
|
||||
|
||||
storage::IsolatedContext::GetInstance()->
|
||||
RevokeFileSystemByPath(file_system_path);
|
||||
|
||||
for (auto it = saved_paths_.begin(); it != saved_paths_.end(); ++it)
|
||||
if (it->second == file_system_path) {
|
||||
saved_paths_.erase(it);
|
||||
break;
|
||||
}
|
||||
|
||||
base::StringValue file_system_path_value(file_system_path.AsUTF8Unsafe());
|
||||
web_contents_->CallClientFunction(
|
||||
"DevToolsAPI.fileSystemRemoved",
|
||||
&file_system_path_value,
|
||||
nullptr,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
void CommonWebContentsDelegate::OnDevToolsSaveToFile(
|
||||
const std::string& url) {
|
||||
// Notify DevTools.
|
||||
base::StringValue url_value(url);
|
||||
web_contents_->CallClientFunction(
|
||||
"DevToolsAPI.savedURL", &url_value, nullptr, nullptr);
|
||||
}
|
||||
|
||||
void CommonWebContentsDelegate::OnDevToolsAppendToFile(
|
||||
const std::string& url) {
|
||||
// Notify DevTools.
|
||||
base::StringValue url_value(url);
|
||||
web_contents_->CallClientFunction(
|
||||
"DevToolsAPI.appendedToURL", &url_value, nullptr, nullptr);
|
||||
}
|
||||
|
||||
void CommonWebContentsDelegate::SetHtmlApiFullscreen(bool enter_fullscreen) {
|
||||
// Window is already in fullscreen mode, save the state.
|
||||
if (enter_fullscreen && owner_window_->IsFullscreen()) {
|
||||
native_fullscreen_ = true;
|
||||
html_fullscreen_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Exit html fullscreen state but not window's fullscreen mode.
|
||||
if (!enter_fullscreen && native_fullscreen_) {
|
||||
html_fullscreen_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
owner_window_->SetFullScreen(enter_fullscreen);
|
||||
html_fullscreen_ = enter_fullscreen;
|
||||
native_fullscreen_ = false;
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
129
atom/browser/common_web_contents_delegate.h
Normal file
129
atom/browser/common_web_contents_delegate.h
Normal file
@@ -0,0 +1,129 @@
|
||||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_COMMON_WEB_CONTENTS_DELEGATE_H_
|
||||
#define ATOM_BROWSER_COMMON_WEB_CONTENTS_DELEGATE_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "brightray/browser/default_web_contents_delegate.h"
|
||||
#include "brightray/browser/inspectable_web_contents_impl.h"
|
||||
#include "brightray/browser/inspectable_web_contents_delegate.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomJavaScriptDialogManager;
|
||||
class NativeWindow;
|
||||
class WebDialogHelper;
|
||||
|
||||
class CommonWebContentsDelegate
|
||||
: public brightray::DefaultWebContentsDelegate,
|
||||
public brightray::InspectableWebContentsDelegate {
|
||||
public:
|
||||
CommonWebContentsDelegate();
|
||||
virtual ~CommonWebContentsDelegate();
|
||||
|
||||
// Creates a InspectableWebContents object and takes onwership of
|
||||
// |web_contents|.
|
||||
void InitWithWebContents(content::WebContents* web_contents);
|
||||
|
||||
// Set the window as owner window.
|
||||
void SetOwnerWindow(NativeWindow* owner_window);
|
||||
|
||||
// Destroy the managed InspectableWebContents object.
|
||||
void DestroyWebContents();
|
||||
|
||||
// Returns the WebContents managed by this delegate.
|
||||
content::WebContents* GetWebContents() const;
|
||||
|
||||
// Returns the WebContents of devtools.
|
||||
content::WebContents* GetDevToolsWebContents() const;
|
||||
|
||||
brightray::InspectableWebContents* managed_web_contents() const {
|
||||
return web_contents_.get();
|
||||
}
|
||||
|
||||
NativeWindow* owner_window() const { return owner_window_.get(); }
|
||||
|
||||
protected:
|
||||
// content::WebContentsDelegate:
|
||||
content::WebContents* OpenURLFromTab(
|
||||
content::WebContents* source,
|
||||
const content::OpenURLParams& params) override;
|
||||
void RequestToLockMouse(content::WebContents* web_contents,
|
||||
bool user_gesture,
|
||||
bool last_unlocked_by_target) override;
|
||||
bool CanOverscrollContent() const override;
|
||||
content::JavaScriptDialogManager* GetJavaScriptDialogManager(
|
||||
content::WebContents* source) override;
|
||||
content::ColorChooser* OpenColorChooser(
|
||||
content::WebContents* web_contents,
|
||||
SkColor color,
|
||||
const std::vector<content::ColorSuggestion>& suggestions) override;
|
||||
void RunFileChooser(content::WebContents* web_contents,
|
||||
const content::FileChooserParams& params) override;
|
||||
void EnumerateDirectory(content::WebContents* web_contents,
|
||||
int request_id,
|
||||
const base::FilePath& path) override;
|
||||
void EnterFullscreenModeForTab(content::WebContents* source,
|
||||
const GURL& origin) override;
|
||||
void ExitFullscreenModeForTab(content::WebContents* source) override;
|
||||
bool IsFullscreenForTabOrPending(
|
||||
const content::WebContents* source) const override;
|
||||
|
||||
// brightray::InspectableWebContentsDelegate:
|
||||
void DevToolsSaveToFile(const std::string& url,
|
||||
const std::string& content,
|
||||
bool save_as) override;
|
||||
void DevToolsAppendToFile(const std::string& url,
|
||||
const std::string& content) override;
|
||||
void DevToolsAddFileSystem(const base::FilePath& path) override;
|
||||
void DevToolsRemoveFileSystem(
|
||||
const base::FilePath& file_system_path) override;
|
||||
|
||||
private:
|
||||
// Callback for when DevToolsSaveToFile has completed.
|
||||
void OnDevToolsSaveToFile(const std::string& url);
|
||||
|
||||
// Callback for when DevToolsAppendToFile has completed.
|
||||
void OnDevToolsAppendToFile(const std::string& url);
|
||||
|
||||
// Set fullscreen mode triggered by html api.
|
||||
void SetHtmlApiFullscreen(bool enter_fullscreen);
|
||||
|
||||
// The window that this WebContents belongs to.
|
||||
base::WeakPtr<NativeWindow> owner_window_;
|
||||
|
||||
// Whether window is fullscreened by HTML5 api.
|
||||
bool html_fullscreen_;
|
||||
|
||||
// Whether window is fullscreened by window api.
|
||||
bool native_fullscreen_;
|
||||
|
||||
scoped_ptr<WebDialogHelper> web_dialog_helper_;
|
||||
scoped_ptr<AtomJavaScriptDialogManager> dialog_manager_;
|
||||
|
||||
// The stored InspectableWebContents object.
|
||||
// Notice that web_contents_ must be placed after dialog_manager_, so we can
|
||||
// make sure web_contents_ is destroyed before dialog_manager_, otherwise a
|
||||
// crash would happen.
|
||||
scoped_ptr<brightray::InspectableWebContents> web_contents_;
|
||||
|
||||
// Maps url to file path, used by the file requests sent from devtools.
|
||||
typedef std::map<std::string, base::FilePath> PathsMap;
|
||||
PathsMap saved_files_;
|
||||
|
||||
// Maps file system id to file path, used by the file system requests
|
||||
// sent from devtools.
|
||||
typedef std::map<std::string, base::FilePath> WorkspaceMap;
|
||||
WorkspaceMap saved_paths_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CommonWebContentsDelegate);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_COMMON_WEB_CONTENTS_DELEGATE_H_
|
||||
@@ -1,10 +1,7 @@
|
||||
var app = require('app');
|
||||
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() {
|
||||
@@ -15,221 +12,9 @@ app.on('ready', function() {
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
resizable: false,
|
||||
'auto-hide-menu-bar': true,
|
||||
'use-content-size': true,
|
||||
});
|
||||
mainWindow.loadUrl('file://' + __dirname + '/index.html');
|
||||
mainWindow.focus();
|
||||
|
||||
if (process.platform == 'darwin') {
|
||||
var template = [
|
||||
{
|
||||
label: 'Electron',
|
||||
submenu: [
|
||||
{
|
||||
label: 'About Electron',
|
||||
selector: 'orderFrontStandardAboutPanel:'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Services',
|
||||
submenu: []
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Hide Electron',
|
||||
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() { mainWindow.restart(); }
|
||||
},
|
||||
{
|
||||
label: 'Toggle Full Screen',
|
||||
accelerator: 'Ctrl+Command+F',
|
||||
click: function() { mainWindow.setFullScreen(!mainWindow.isFullScreen()); }
|
||||
},
|
||||
{
|
||||
label: 'Toggle Developer Tools',
|
||||
accelerator: 'Alt+Command+I',
|
||||
click: function() { mainWindow.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:'
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Help',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Learn More',
|
||||
click: function() { require('shell').openExternal('http://electron.atom.io') }
|
||||
},
|
||||
{
|
||||
label: 'Documentation',
|
||||
click: function() { require('shell').openExternal('https://github.com/atom/electron/tree/master/docs#readme') }
|
||||
},
|
||||
{
|
||||
label: 'Community Discussions',
|
||||
click: function() { require('shell').openExternal('https://discuss.atom.io/c/electron') }
|
||||
},
|
||||
{
|
||||
label: 'Search Issues',
|
||||
click: function() { require('shell').openExternal('https://github.com/atom/electron/issues') }
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
menu = Menu.buildFromTemplate(template);
|
||||
Menu.setApplicationMenu(menu);
|
||||
} else {
|
||||
var template = [
|
||||
{
|
||||
label: '&File',
|
||||
submenu: [
|
||||
{
|
||||
label: '&Open',
|
||||
accelerator: 'Ctrl+O',
|
||||
},
|
||||
{
|
||||
label: '&Close',
|
||||
accelerator: 'Ctrl+W',
|
||||
click: function() { mainWindow.close(); }
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '&View',
|
||||
submenu: [
|
||||
{
|
||||
label: '&Reload',
|
||||
accelerator: 'Ctrl+R',
|
||||
click: function() { mainWindow.restart(); }
|
||||
},
|
||||
{
|
||||
label: 'Toggle &Full Screen',
|
||||
accelerator: 'F11',
|
||||
click: function() { mainWindow.setFullScreen(!mainWindow.isFullScreen()); }
|
||||
},
|
||||
{
|
||||
label: 'Toggle &Developer Tools',
|
||||
accelerator: 'Alt+Ctrl+I',
|
||||
click: function() { mainWindow.toggleDevTools(); }
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Help',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Learn More',
|
||||
click: function() { require('shell').openExternal('http://electron.atom.io') }
|
||||
},
|
||||
{
|
||||
label: 'Documentation',
|
||||
click: function() { require('shell').openExternal('https://github.com/atom/electron/tree/master/docs#readme') }
|
||||
},
|
||||
{
|
||||
label: 'Community Discussions',
|
||||
click: function() { require('shell').openExternal('https://discuss.atom.io/c/electron') }
|
||||
},
|
||||
{
|
||||
label: 'Search Issues',
|
||||
click: function() { require('shell').openExternal('https://github.com/atom/electron/issues') }
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
menu = Menu.buildFromTemplate(template);
|
||||
mainWindow.setMenu(menu);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2,6 +2,8 @@ var app = require('app');
|
||||
var dialog = require('dialog');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var Menu = require('menu');
|
||||
var BrowserWindow = require('browser-window');
|
||||
|
||||
// Quit when all windows are closed and no other one is listening to this.
|
||||
app.on('window-all-closed', function() {
|
||||
@@ -29,6 +31,249 @@ for (var i in argv) {
|
||||
}
|
||||
}
|
||||
|
||||
// Create default menu.
|
||||
app.once('ready', function() {
|
||||
if (Menu.getApplicationMenu())
|
||||
return;
|
||||
|
||||
var template;
|
||||
if (process.platform == 'darwin') {
|
||||
template = [
|
||||
{
|
||||
label: 'Electron',
|
||||
submenu: [
|
||||
{
|
||||
label: 'About Electron',
|
||||
selector: 'orderFrontStandardAboutPanel:'
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Services',
|
||||
submenu: []
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Hide Electron',
|
||||
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() {
|
||||
var focusedWindow = BrowserWindow.getFocusedWindow();
|
||||
if (focusedWindow)
|
||||
focusedWindow.reload();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Toggle Full Screen',
|
||||
accelerator: 'Ctrl+Command+F',
|
||||
click: function() {
|
||||
var focusedWindow = BrowserWindow.getFocusedWindow();
|
||||
if (focusedWindow)
|
||||
focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Toggle Developer Tools',
|
||||
accelerator: 'Alt+Command+I',
|
||||
click: function() {
|
||||
var focusedWindow = BrowserWindow.getFocusedWindow();
|
||||
if (focusedWindow)
|
||||
focusedWindow.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:'
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Help',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Learn More',
|
||||
click: function() { require('shell').openExternal('http://electron.atom.io') }
|
||||
},
|
||||
{
|
||||
label: 'Documentation',
|
||||
click: function() { require('shell').openExternal('https://github.com/atom/electron/tree/master/docs#readme') }
|
||||
},
|
||||
{
|
||||
label: 'Community Discussions',
|
||||
click: function() { require('shell').openExternal('https://discuss.atom.io/c/electron') }
|
||||
},
|
||||
{
|
||||
label: 'Search Issues',
|
||||
click: function() { require('shell').openExternal('https://github.com/atom/electron/issues') }
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
} else {
|
||||
template = [
|
||||
{
|
||||
label: '&File',
|
||||
submenu: [
|
||||
{
|
||||
label: '&Open',
|
||||
accelerator: 'Ctrl+O',
|
||||
},
|
||||
{
|
||||
label: '&Close',
|
||||
accelerator: 'Ctrl+W',
|
||||
click: function() {
|
||||
var focusedWindow = BrowserWindow.getFocusedWindow();
|
||||
if (focusedWindow)
|
||||
focusedWindow.close();
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '&View',
|
||||
submenu: [
|
||||
{
|
||||
label: '&Reload',
|
||||
accelerator: 'Ctrl+R',
|
||||
click: function() {
|
||||
var focusedWindow = BrowserWindow.getFocusedWindow();
|
||||
if (focusedWindow)
|
||||
focusedWindow.reload();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Toggle &Full Screen',
|
||||
accelerator: 'F11',
|
||||
click: function() {
|
||||
var focusedWindow = BrowserWindow.getFocusedWindow();
|
||||
if (focusedWindow)
|
||||
focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Toggle &Developer Tools',
|
||||
accelerator: 'Shift+Ctrl+I',
|
||||
click: function() {
|
||||
var focusedWindow = BrowserWindow.getFocusedWindow();
|
||||
if (focusedWindow)
|
||||
focusedWindow.toggleDevTools();
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Help',
|
||||
submenu: [
|
||||
{
|
||||
label: 'Learn More',
|
||||
click: function() { require('shell').openExternal('http://electron.atom.io') }
|
||||
},
|
||||
{
|
||||
label: 'Documentation',
|
||||
click: function() { require('shell').openExternal('https://github.com/atom/electron/tree/master/docs#readme') }
|
||||
},
|
||||
{
|
||||
label: 'Community Discussions',
|
||||
click: function() { require('shell').openExternal('https://discuss.atom.io/c/electron') }
|
||||
},
|
||||
{
|
||||
label: 'Search Issues',
|
||||
click: function() { require('shell').openExternal('https://github.com/atom/electron/issues') }
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
var menu = Menu.buildFromTemplate(template);
|
||||
Menu.setApplicationMenu(menu);
|
||||
});
|
||||
|
||||
// Start the specified app if there is one specified in command line, otherwise
|
||||
// start the default app.
|
||||
if (option.file && !option.webdriver) {
|
||||
@@ -46,6 +291,7 @@ if (option.file && !option.webdriver) {
|
||||
app.setName(packageJson.name);
|
||||
app.setPath('userData', path.join(app.getPath('appData'), app.getName()));
|
||||
app.setPath('userCache', path.join(app.getPath('cache'), app.getName()));
|
||||
app.setAppPath(packagePath);
|
||||
}
|
||||
|
||||
// Run the app.
|
||||
@@ -53,7 +299,7 @@ if (option.file && !option.webdriver) {
|
||||
} catch(e) {
|
||||
if (e.code == 'MODULE_NOT_FOUND') {
|
||||
app.focus();
|
||||
dialog.showErrorBox('Error opening app', 'The app provided is not a valid electron app, please read the docs on how to write one:\nhttps://github.com/atom/electron/tree/master/docs');
|
||||
dialog.showErrorBox('Error opening app', 'The app provided is not a valid electron app, please read the docs on how to write one:\nhttps://github.com/atom/electron/tree/master/docs\n\n' + e.toString());
|
||||
process.exit(1);
|
||||
} else {
|
||||
console.error('App threw an error when running', e);
|
||||
|
||||
@@ -3,6 +3,7 @@ webContents = require 'web-contents'
|
||||
webViewManager = null # Doesn't exist in early initialization.
|
||||
|
||||
supportedWebViewEvents = [
|
||||
'load-commit'
|
||||
'did-finish-load'
|
||||
'did-fail-load'
|
||||
'did-frame-finish-load'
|
||||
@@ -38,10 +39,7 @@ createGuest = (embedder, params) ->
|
||||
webViewManager ?= process.atomBinding 'web_view_manager'
|
||||
|
||||
id = getNextInstanceId embedder
|
||||
guest = webContents.create
|
||||
isGuest: true
|
||||
guestInstanceId: id
|
||||
storagePartitionId: params.storagePartitionId
|
||||
guest = webContents.create {isGuest: true, embedder}
|
||||
guestInstances[id] = {guest, embedder}
|
||||
|
||||
# Destroy guest when the embedder is gone or navigated.
|
||||
@@ -58,14 +56,19 @@ createGuest = (embedder, params) ->
|
||||
delete @attachParams
|
||||
|
||||
@viewInstanceId = params.instanceId
|
||||
min = width: params.minwidth, height: params.minheight
|
||||
max = width: params.maxwidth, height: params.maxheight
|
||||
@setAutoSize params.autosize, min, max
|
||||
@setSize
|
||||
normal:
|
||||
width: params.elementWidth, height: params.elementHeight
|
||||
enableAutoSize: params.autosize
|
||||
min:
|
||||
width: params.minwidth, height: params.minheight
|
||||
max:
|
||||
width: params.maxwidth, height: params.maxheight
|
||||
|
||||
if params.src
|
||||
opts = {}
|
||||
opts.httpreferrer = params.httpreferrer if params.httpreferrer
|
||||
opts.useragent = params.useragent if params.useragent
|
||||
opts.httpReferrer = params.httpreferrer if params.httpreferrer
|
||||
opts.userAgent = params.useragent if params.useragent
|
||||
@loadUrl params.src, opts
|
||||
|
||||
if params.allowtransparency?
|
||||
@@ -123,7 +126,7 @@ destroyGuest = (embedder, id) ->
|
||||
delete reverseEmbedderElementsMap[id]
|
||||
delete embedderElementsMap[key]
|
||||
|
||||
ipc.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_CREATE_GUEST', (event, type, params, requestId) ->
|
||||
ipc.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_CREATE_GUEST', (event, params, requestId) ->
|
||||
event.sender.send "ATOM_SHELL_RESPONSE_#{requestId}", createGuest(event.sender, params)
|
||||
|
||||
ipc.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_ATTACH_GUEST', (event, elementInstanceId, guestInstanceId, params) ->
|
||||
@@ -132,8 +135,8 @@ ipc.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_ATTACH_GUEST', (event, elementInstanceId,
|
||||
ipc.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_DESTROY_GUEST', (event, id) ->
|
||||
destroyGuest event.sender, id
|
||||
|
||||
ipc.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_SET_AUTO_SIZE', (event, id, params) ->
|
||||
guestInstances[id]?.guest.setAutoSize params.enableAutoSize, params.min, params.max
|
||||
ipc.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_SET_SIZE', (event, id, params) ->
|
||||
guestInstances[id]?.guest.setSize params
|
||||
|
||||
ipc.on 'ATOM_SHELL_GUEST_VIEW_MANAGER_SET_ALLOW_TRANSPARENCY', (event, id, allowtransparency) ->
|
||||
guestInstances[id]?.guest.setAllowTransparency allowtransparency
|
||||
|
||||
@@ -21,9 +21,8 @@ createGuest = (embedder, url, frameName, options) ->
|
||||
# guest is closed by user then we should prevent |embedder| from double
|
||||
# closing guest.
|
||||
closedByEmbedder = ->
|
||||
embedder.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSED', guest.id
|
||||
guest.removeListener 'closed', closedByUser
|
||||
guest.destroy() unless guest.isClosed()
|
||||
guest.destroy()
|
||||
closedByUser = ->
|
||||
embedder.send 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSED', guest.id
|
||||
embedder.removeListener 'render-view-deleted', closedByEmbedder
|
||||
@@ -41,24 +40,21 @@ createGuest = (embedder, url, frameName, options) ->
|
||||
# Routed window.open messages.
|
||||
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPEN', (event, args...) ->
|
||||
[url, frameName, options] = args
|
||||
event.sender.emit '-new-window', event, url, frameName, 7
|
||||
event.sender.emit 'new-window', event, url, frameName, 'new-window'
|
||||
if event.sender.isGuest() or event.defaultPrevented
|
||||
event.returnValue = null
|
||||
else
|
||||
event.returnValue = createGuest event.sender, args...
|
||||
|
||||
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_CLOSE', (event, guestId) ->
|
||||
return unless BrowserWindow.windows.has guestId
|
||||
BrowserWindow.windows.get(guestId).destroy()
|
||||
BrowserWindow.fromId(guestId)?.destroy()
|
||||
|
||||
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_METHOD', (event, guestId, method, args...) ->
|
||||
return unless BrowserWindow.windows.has guestId
|
||||
BrowserWindow.windows.get(guestId)[method] args...
|
||||
BrowserWindow.fromId(guestId)?[method] args...
|
||||
|
||||
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', (event, guestId, message, targetOrigin) ->
|
||||
return unless BrowserWindow.windows.has guestId
|
||||
guestContents = BrowserWindow.windows.get(guestId).webContents
|
||||
if guestContents.getUrl().indexOf(targetOrigin) is 0 or targetOrigin is '*'
|
||||
guestContents = BrowserWindow.fromId(guestId)?.webContents
|
||||
if guestContents?.getUrl().indexOf(targetOrigin) is 0 or targetOrigin is '*'
|
||||
guestContents.send 'ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', message, targetOrigin
|
||||
|
||||
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPENER_POSTMESSAGE', (event, message, targetOrigin) ->
|
||||
@@ -67,5 +63,7 @@ ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WINDOW_OPENER_POSTMESSAGE', (event, mess
|
||||
embedder.send 'ATOM_SHELL_GUEST_WINDOW_POSTMESSAGE', message, targetOrigin
|
||||
|
||||
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', (event, guestId, method, args...) ->
|
||||
return unless BrowserWindow.windows.has guestId
|
||||
BrowserWindow.windows.get(guestId).webContents?[method] args...
|
||||
BrowserWindow.fromId(guestId)?.webContents?[method] args...
|
||||
|
||||
ipc.on 'ATOM_SHELL_GUEST_WINDOW_MANAGER_IS_GUEST_WINDOW', (event) ->
|
||||
event.returnValue = v8Util.getHiddenValue(event.sender, 'embedder') isnt undefined
|
||||
|
||||
@@ -38,7 +38,7 @@ process.on 'uncaughtException', (error) ->
|
||||
# Show error in GUI.
|
||||
stack = error.stack ? "#{error.name}: #{error.message}"
|
||||
message = "Uncaught Exception:\n#{stack}"
|
||||
require('dialog').showErrorBox 'A JavaScript error occured in the browser process', message
|
||||
require('dialog').showErrorBox 'A JavaScript error occurred in the main process', message
|
||||
|
||||
# Emit 'exit' event on quit.
|
||||
app = require 'app'
|
||||
@@ -87,6 +87,7 @@ app.commandLine.appendSwitch 'enable-npapi'
|
||||
# Set the user path according to application's name.
|
||||
app.setPath 'userData', path.join(app.getPath('appData'), app.getName())
|
||||
app.setPath 'userCache', path.join(app.getPath('cache'), app.getName())
|
||||
app.setAppPath packagePath
|
||||
|
||||
# Load the chrome extension support.
|
||||
require './chrome-extension'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
EventEmitter = require('events').EventEmitter
|
||||
IDWeakMap = require 'id-weak-map'
|
||||
IDWeakMap = process.atomBinding('id_weak_map').IDWeakMap
|
||||
v8Util = process.atomBinding 'v8_util'
|
||||
|
||||
# Class to reference all objects.
|
||||
|
||||
@@ -7,8 +7,10 @@ v8Util = process.atomBinding 'v8_util'
|
||||
valueToMeta = (sender, value) ->
|
||||
meta = type: typeof value
|
||||
|
||||
meta.type = 'buffer' if Buffer.isBuffer value
|
||||
meta.type = 'value' if value is null
|
||||
meta.type = 'array' if Array.isArray value
|
||||
meta.type = 'promise' if value? and value.constructor.name is 'Promise'
|
||||
|
||||
# Treat the arguments object as array.
|
||||
meta.type = 'array' if meta.type is 'object' and value.callee? and value.length?
|
||||
@@ -26,6 +28,10 @@ valueToMeta = (sender, value) ->
|
||||
|
||||
meta.members = []
|
||||
meta.members.push {name: prop, type: typeof field} for prop, field of value
|
||||
else if meta.type is 'buffer'
|
||||
meta.value = Array::slice.call value, 0
|
||||
else if meta.type is 'promise'
|
||||
meta.then = valueToMeta(sender, value.then.bind(value))
|
||||
else
|
||||
meta.type = 'value'
|
||||
meta.value = value
|
||||
@@ -43,6 +49,8 @@ unwrapArgs = (sender, args) ->
|
||||
when 'value' then meta.value
|
||||
when 'remote-object' then objectsRegistry.get meta.id
|
||||
when 'array' then unwrapArgs sender, meta.value
|
||||
when 'buffer' then new Buffer(meta.value)
|
||||
when 'promise' then Promise.resolve(then: metaToValue(meta.then))
|
||||
when 'object'
|
||||
ret = v8Util.createObjectWithName meta.name
|
||||
for member in meta.members
|
||||
|
||||
@@ -9,14 +9,9 @@
|
||||
#include <vector>
|
||||
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/atom_javascript_dialog_manager.h"
|
||||
#include "atom/browser/browser.h"
|
||||
#include "atom/browser/ui/file_dialog.h"
|
||||
#include "atom/browser/web_dialog_helper.h"
|
||||
#include "atom/browser/atom_browser_main_parts.h"
|
||||
#include "atom/browser/window_list.h"
|
||||
#include "atom/common/api/api_messages.h"
|
||||
#include "atom/common/atom_version.h"
|
||||
#include "atom/common/chrome_version.h"
|
||||
#include "atom/common/native_mate_converters/image_converter.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
#include "atom/common/options_switches.h"
|
||||
@@ -26,27 +21,17 @@
|
||||
#include "base/prefs/pref_service.h"
|
||||
#include "base/message_loop/message_loop.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "brightray/browser/inspectable_web_contents.h"
|
||||
#include "brightray/browser/inspectable_web_contents_view.h"
|
||||
#include "chrome/browser/printing/print_view_manager_basic.h"
|
||||
#include "chrome/browser/ui/browser_dialogs.h"
|
||||
#include "content/browser/renderer_host/render_widget_host_impl.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"
|
||||
#include "content/public/browser/notification_source.h"
|
||||
#include "content/public/browser/notification_types.h"
|
||||
#include "content/public/browser/plugin_service.h"
|
||||
#include "content/public/browser/render_frame_host.h"
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#include "content/public/browser/render_widget_host_view.h"
|
||||
#include "content/public/common/content_switches.h"
|
||||
#include "content/public/common/renderer_preferences.h"
|
||||
#include "content/public/common/user_agent.h"
|
||||
#include "content/public/common/web_preferences.h"
|
||||
#include "ipc/ipc_message_macros.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
@@ -66,6 +51,8 @@ using content::NavigationEntry;
|
||||
using content::RenderWidgetHostView;
|
||||
using content::RenderWidgetHost;
|
||||
|
||||
DEFINE_WEB_CONTENTS_USER_DATA_KEY(atom::NativeWindowRelay);
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
@@ -78,34 +65,42 @@ const char* kWebRuntimeFeatures[] = {
|
||||
switches::kOverlayScrollbars,
|
||||
switches::kOverlayFullscreenVideo,
|
||||
switches::kSharedWorker,
|
||||
switches::kPageVisibility,
|
||||
};
|
||||
|
||||
std::string RemoveWhitespace(const std::string& str) {
|
||||
std::string trimmed;
|
||||
if (base::RemoveChars(str, " ", &trimmed))
|
||||
return trimmed;
|
||||
else
|
||||
return str;
|
||||
// Convert draggable regions in raw format to SkRegion format. Caller is
|
||||
// responsible for deleting the returned SkRegion instance.
|
||||
scoped_ptr<SkRegion> DraggableRegionsToSkRegion(
|
||||
const std::vector<DraggableRegion>& regions) {
|
||||
scoped_ptr<SkRegion> sk_region(new SkRegion);
|
||||
for (const DraggableRegion& region : regions) {
|
||||
sk_region->op(
|
||||
region.bounds.x(),
|
||||
region.bounds.y(),
|
||||
region.bounds.right(),
|
||||
region.bounds.bottom(),
|
||||
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
|
||||
}
|
||||
return sk_region.Pass();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
NativeWindow::NativeWindow(content::WebContents* web_contents,
|
||||
const mate::Dictionary& options)
|
||||
: content::WebContentsObserver(web_contents),
|
||||
NativeWindow::NativeWindow(
|
||||
brightray::InspectableWebContents* inspectable_web_contents,
|
||||
const mate::Dictionary& options)
|
||||
: content::WebContentsObserver(inspectable_web_contents->GetWebContents()),
|
||||
has_frame_(true),
|
||||
transparent_(false),
|
||||
enable_larger_than_screen_(false),
|
||||
is_closed_(false),
|
||||
node_integration_(true),
|
||||
has_dialog_attached_(false),
|
||||
html_fullscreen_(false),
|
||||
native_fullscreen_(false),
|
||||
zoom_factor_(1.0),
|
||||
weak_factory_(this),
|
||||
inspectable_web_contents_(
|
||||
brightray::InspectableWebContents::Create(web_contents)) {
|
||||
printing::PrintViewManagerBasic::CreateForWebContents(web_contents);
|
||||
aspect_ratio_(0.0),
|
||||
inspectable_web_contents_(inspectable_web_contents),
|
||||
weak_factory_(this) {
|
||||
inspectable_web_contents->GetView()->SetDelegate(this);
|
||||
|
||||
options.Get(switches::kFrame, &has_frame_);
|
||||
options.Get(switches::kTransparent, &transparent_);
|
||||
@@ -138,24 +133,7 @@ NativeWindow::NativeWindow(content::WebContents* web_contents,
|
||||
// Read the zoom factor before any navigation.
|
||||
options.Get(switches::kZoomFactor, &zoom_factor_);
|
||||
|
||||
web_contents->SetDelegate(this);
|
||||
inspectable_web_contents()->SetDelegate(this);
|
||||
|
||||
WindowList::AddWindow(this);
|
||||
|
||||
// Override the user agent to contain application and atom-shell's version.
|
||||
Browser* browser = Browser::Get();
|
||||
std::string product_name = base::StringPrintf(
|
||||
"%s/%s Chrome/%s " ATOM_PRODUCT_NAME "/" ATOM_VERSION_STRING,
|
||||
RemoveWhitespace(browser->GetName()).c_str(),
|
||||
browser->GetVersion().c_str(),
|
||||
CHROME_VERSION_STRING);
|
||||
web_contents->GetMutableRendererPrefs()->user_agent_override =
|
||||
content::BuildUserAgentFromProduct(product_name);
|
||||
|
||||
// Get notified of title updated message.
|
||||
registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED,
|
||||
content::Source<content::WebContents>(web_contents));
|
||||
}
|
||||
|
||||
NativeWindow::~NativeWindow() {
|
||||
@@ -164,18 +142,12 @@ NativeWindow::~NativeWindow() {
|
||||
NotifyWindowClosed();
|
||||
}
|
||||
|
||||
// static
|
||||
NativeWindow* NativeWindow::Create(const mate::Dictionary& options) {
|
||||
content::WebContents::CreateParams create_params(AtomBrowserContext::Get());
|
||||
return Create(content::WebContents::Create(create_params), options);
|
||||
}
|
||||
|
||||
// static
|
||||
NativeWindow* NativeWindow::FromWebContents(
|
||||
content::WebContents* web_contents) {
|
||||
WindowList& window_list = *WindowList::GetInstance();
|
||||
for (NativeWindow* window : window_list) {
|
||||
if (window->GetWebContents() == web_contents)
|
||||
if (window->web_contents() == web_contents)
|
||||
return window;
|
||||
}
|
||||
return nullptr;
|
||||
@@ -211,10 +183,12 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) {
|
||||
if (options.Get(switches::kAlwaysOnTop, &top) && top) {
|
||||
SetAlwaysOnTop(true);
|
||||
}
|
||||
#if defined(OS_MACOSX) || defined(OS_WIN)
|
||||
bool fullscreen;
|
||||
if (options.Get(switches::kFullscreen, &fullscreen) && fullscreen) {
|
||||
SetFullScreen(true);
|
||||
}
|
||||
#endif
|
||||
bool skip;
|
||||
if (options.Get(switches::kSkipTaskbar, &skip) && skip) {
|
||||
SetSkipTaskbar(skip);
|
||||
@@ -267,11 +241,6 @@ bool NativeWindow::IsDocumentEdited() {
|
||||
void NativeWindow::SetMenu(ui::MenuModel* menu) {
|
||||
}
|
||||
|
||||
void NativeWindow::Print(bool silent, bool print_background) {
|
||||
printing::PrintViewManagerBasic::FromWebContents(GetWebContents())->
|
||||
PrintNow(silent, print_background);
|
||||
}
|
||||
|
||||
void NativeWindow::ShowDefinitionForSelection() {
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
@@ -290,60 +259,41 @@ bool NativeWindow::IsMenuBarVisible() {
|
||||
return true;
|
||||
}
|
||||
|
||||
double NativeWindow::GetAspectRatio() {
|
||||
return aspect_ratio_;
|
||||
}
|
||||
|
||||
gfx::Size NativeWindow::GetAspectRatioExtraSize() {
|
||||
return aspect_ratio_extraSize_;
|
||||
}
|
||||
|
||||
void NativeWindow::SetAspectRatio(double aspect_ratio,
|
||||
const gfx::Size& extra_size) {
|
||||
aspect_ratio_ = aspect_ratio;
|
||||
aspect_ratio_extraSize_ = extra_size;
|
||||
}
|
||||
|
||||
bool NativeWindow::HasModalDialog() {
|
||||
return has_dialog_attached_;
|
||||
}
|
||||
|
||||
void NativeWindow::OpenDevTools(bool can_dock) {
|
||||
inspectable_web_contents()->SetCanDock(can_dock);
|
||||
inspectable_web_contents()->ShowDevTools();
|
||||
}
|
||||
|
||||
void NativeWindow::CloseDevTools() {
|
||||
inspectable_web_contents()->CloseDevTools();
|
||||
}
|
||||
|
||||
bool NativeWindow::IsDevToolsOpened() {
|
||||
return inspectable_web_contents()->IsDevToolsViewShowing();
|
||||
}
|
||||
|
||||
void NativeWindow::InspectElement(int x, int y) {
|
||||
OpenDevTools(true);
|
||||
scoped_refptr<content::DevToolsAgentHost> agent(
|
||||
content::DevToolsAgentHost::GetOrCreateFor(GetWebContents()));
|
||||
agent->InspectElement(x, y);
|
||||
}
|
||||
|
||||
void NativeWindow::InspectServiceWorker() {
|
||||
for (const auto& agent_host : content::DevToolsAgentHost::GetOrCreateAll()) {
|
||||
if (agent_host->GetType() ==
|
||||
content::DevToolsAgentHost::TYPE_SERVICE_WORKER) {
|
||||
OpenDevTools(true);
|
||||
inspectable_web_contents()->AttachTo(agent_host);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindow::FocusOnWebView() {
|
||||
GetWebContents()->GetRenderViewHost()->Focus();
|
||||
web_contents()->GetRenderViewHost()->Focus();
|
||||
}
|
||||
|
||||
void NativeWindow::BlurWebView() {
|
||||
GetWebContents()->GetRenderViewHost()->Blur();
|
||||
web_contents()->GetRenderViewHost()->Blur();
|
||||
}
|
||||
|
||||
bool NativeWindow::IsWebViewFocused() {
|
||||
RenderWidgetHostView* host_view =
|
||||
GetWebContents()->GetRenderViewHost()->GetView();
|
||||
auto host_view = web_contents()->GetRenderViewHost()->GetView();
|
||||
return host_view && host_view->HasFocus();
|
||||
}
|
||||
|
||||
void NativeWindow::CapturePage(const gfx::Rect& rect,
|
||||
const CapturePageCallback& callback) {
|
||||
content::WebContents* contents = GetWebContents();
|
||||
RenderWidgetHostView* const view = contents->GetRenderWidgetHostView();
|
||||
RenderWidgetHost* const host = view ? view->GetRenderWidgetHost() : nullptr;
|
||||
const auto view = web_contents()->GetRenderWidgetHostView();
|
||||
const auto host = view ? view->GetRenderWidgetHost() : nullptr;
|
||||
if (!view || !host) {
|
||||
callback.Run(SkBitmap());
|
||||
return;
|
||||
@@ -373,14 +323,7 @@ void NativeWindow::CapturePage(const gfx::Rect& rect,
|
||||
kBGRA_8888_SkColorType);
|
||||
}
|
||||
|
||||
void NativeWindow::DestroyWebContents() {
|
||||
if (!inspectable_web_contents_)
|
||||
return;
|
||||
|
||||
inspectable_web_contents_.reset();
|
||||
}
|
||||
|
||||
void NativeWindow::CloseWebContents() {
|
||||
void NativeWindow::RequestToClosePage() {
|
||||
bool prevent_default = false;
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver,
|
||||
observers_,
|
||||
@@ -390,12 +333,6 @@ void NativeWindow::CloseWebContents() {
|
||||
return;
|
||||
}
|
||||
|
||||
content::WebContents* web_contents(GetWebContents());
|
||||
if (!web_contents) {
|
||||
CloseImmediately();
|
||||
return;
|
||||
}
|
||||
|
||||
// Assume the window is not responding if it doesn't cancel the close and is
|
||||
// not closed in 5s, in this way we can quickly show the unresponsive
|
||||
// dialog when the window is busy executing some script withouth waiting for
|
||||
@@ -403,26 +340,49 @@ void NativeWindow::CloseWebContents() {
|
||||
if (window_unresposive_closure_.IsCancelled())
|
||||
ScheduleUnresponsiveEvent(5000);
|
||||
|
||||
if (web_contents->NeedToFireBeforeUnload())
|
||||
web_contents->DispatchBeforeUnload(false);
|
||||
if (web_contents()->NeedToFireBeforeUnload())
|
||||
web_contents()->DispatchBeforeUnload(false);
|
||||
else
|
||||
web_contents->Close();
|
||||
web_contents()->Close();
|
||||
}
|
||||
|
||||
content::WebContents* NativeWindow::GetWebContents() const {
|
||||
void NativeWindow::CloseContents(content::WebContents* source) {
|
||||
if (!inspectable_web_contents_)
|
||||
return nullptr;
|
||||
return inspectable_web_contents()->GetWebContents();
|
||||
return;
|
||||
|
||||
inspectable_web_contents_->GetView()->SetDelegate(nullptr);
|
||||
inspectable_web_contents_ = nullptr;
|
||||
Observe(nullptr);
|
||||
|
||||
// When the web contents is gone, close the window immediately, but the
|
||||
// memory will not be freed until you call delete.
|
||||
// In this way, it would be safe to manage windows via smart pointers. If you
|
||||
// want to free memory when the window is closed, you can do deleting by
|
||||
// overriding the OnWindowClosed method in the observer.
|
||||
CloseImmediately();
|
||||
|
||||
// Do not sent "unresponsive" event after window is closed.
|
||||
window_unresposive_closure_.Cancel();
|
||||
}
|
||||
|
||||
content::WebContents* NativeWindow::GetDevToolsWebContents() const {
|
||||
if (!inspectable_web_contents_)
|
||||
return nullptr;
|
||||
return inspectable_web_contents()->devtools_web_contents();
|
||||
void NativeWindow::RendererUnresponsive(content::WebContents* source) {
|
||||
// Schedule the unresponsive shortly later, since we may receive the
|
||||
// responsive event soon. This could happen after the whole application had
|
||||
// blocked for a while.
|
||||
// Also notice that when closing this event would be ignored because we have
|
||||
// explicity started a close timeout counter. This is on purpose because we
|
||||
// don't want the unresponsive event to be sent too early when user is closing
|
||||
// the window.
|
||||
ScheduleUnresponsiveEvent(50);
|
||||
}
|
||||
|
||||
void NativeWindow::RendererResponsive(content::WebContents* source) {
|
||||
window_unresposive_closure_.Cancel();
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnRendererResponsive());
|
||||
}
|
||||
|
||||
void NativeWindow::AppendExtraCommandLineSwitches(
|
||||
base::CommandLine* command_line, int child_process_id) {
|
||||
base::CommandLine* command_line) {
|
||||
// Append --node-integration to renderer process.
|
||||
command_line->AppendSwitchASCII(switches::kNodeIntegration,
|
||||
node_integration_ ? "true" : "false");
|
||||
@@ -467,8 +427,6 @@ void NativeWindow::OverrideWebkitPrefs(content::WebPreferences* prefs) {
|
||||
std::vector<base::FilePath> list;
|
||||
if (web_preferences_.Get("javascript", &b))
|
||||
prefs->javascript_enabled = b;
|
||||
if (web_preferences_.Get("web-security", &b))
|
||||
prefs->web_security_enabled = b;
|
||||
if (web_preferences_.Get("images", &b))
|
||||
prefs->images_enabled = b;
|
||||
if (web_preferences_.Get("java", &b))
|
||||
@@ -479,6 +437,15 @@ void NativeWindow::OverrideWebkitPrefs(content::WebPreferences* prefs) {
|
||||
prefs->experimental_webgl_enabled = b;
|
||||
if (web_preferences_.Get("webaudio", &b))
|
||||
prefs->webaudio_enabled = b;
|
||||
if (web_preferences_.Get("web-security", &b)) {
|
||||
prefs->web_security_enabled = b;
|
||||
prefs->allow_displaying_insecure_content = !b;
|
||||
prefs->allow_running_insecure_content = !b;
|
||||
}
|
||||
if (web_preferences_.Get("allow-displaying-insecure-content", &b))
|
||||
prefs->allow_displaying_insecure_content = b;
|
||||
if (web_preferences_.Get("allow-running-insecure-content", &b))
|
||||
prefs->allow_running_insecure_content = b;
|
||||
if (web_preferences_.Get("extra-plugin-dirs", &list)) {
|
||||
if (content::PluginService::GetInstance()->NPAPIPluginsSupported()) {
|
||||
for (size_t i = 0; i < list.size(); ++i)
|
||||
@@ -489,37 +456,14 @@ void NativeWindow::OverrideWebkitPrefs(content::WebPreferences* prefs) {
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindow::SetHtmlApiFullscreen(bool enter_fullscreen) {
|
||||
// Window is already in fullscreen mode, save the state.
|
||||
if (enter_fullscreen && IsFullscreen()) {
|
||||
native_fullscreen_ = true;
|
||||
html_fullscreen_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Exit html fullscreen state but not window's fullscreen mode.
|
||||
if (!enter_fullscreen && native_fullscreen_) {
|
||||
html_fullscreen_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
SetFullScreen(enter_fullscreen);
|
||||
html_fullscreen_ = enter_fullscreen;
|
||||
native_fullscreen_ = false;
|
||||
}
|
||||
|
||||
void NativeWindow::NotifyWindowClosed() {
|
||||
if (is_closed_)
|
||||
return;
|
||||
|
||||
WindowList::RemoveWindow(this);
|
||||
|
||||
is_closed_ = true;
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnWindowClosed());
|
||||
|
||||
// Do not receive any notification after window has been closed, there is a
|
||||
// crash that seems to be caused by this: http://git.io/YqMG5g.
|
||||
registrar_.RemoveAll();
|
||||
|
||||
WindowList::RemoveWindow(this);
|
||||
}
|
||||
|
||||
void NativeWindow::NotifyWindowBlur() {
|
||||
@@ -578,70 +522,22 @@ void NativeWindow::NotifyWindowLeaveHtmlFullScreen() {
|
||||
OnWindowLeaveHtmlFullScreen());
|
||||
}
|
||||
|
||||
bool NativeWindow::ShouldCreateWebContents(
|
||||
content::WebContents* web_contents,
|
||||
int route_id,
|
||||
int main_frame_route_id,
|
||||
WindowContainerType window_container_type,
|
||||
const base::string16& frame_name,
|
||||
const GURL& target_url,
|
||||
const std::string& partition_id,
|
||||
content::SessionStorageNamespace* session_storage_namespace) {
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver,
|
||||
observers_,
|
||||
WillCreatePopupWindow(frame_name,
|
||||
target_url,
|
||||
partition_id,
|
||||
NEW_FOREGROUND_TAB));
|
||||
return false;
|
||||
void NativeWindow::NotifyWindowExecuteWindowsCommand(
|
||||
const std::string& command) {
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver, observers_,
|
||||
OnExecuteWindowsCommand(command));
|
||||
}
|
||||
|
||||
// In atom-shell all reloads and navigations started by renderer process would
|
||||
// be redirected to this method, so we can have precise control of how we
|
||||
// would open the url (in our case, is to restart the renderer process). See
|
||||
// AtomRendererClient::ShouldFork for how this is done.
|
||||
content::WebContents* NativeWindow::OpenURLFromTab(
|
||||
content::WebContents* source,
|
||||
const content::OpenURLParams& params) {
|
||||
if (params.disposition != CURRENT_TAB) {
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver,
|
||||
observers_,
|
||||
WillCreatePopupWindow(base::string16(),
|
||||
params.url,
|
||||
"",
|
||||
params.disposition));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Give user a chance to prevent navigation.
|
||||
bool prevent_default = false;
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver,
|
||||
observers_,
|
||||
WillNavigate(&prevent_default, params.url));
|
||||
if (prevent_default)
|
||||
return nullptr;
|
||||
|
||||
content::NavigationController::LoadURLParams load_url_params(params.url);
|
||||
load_url_params.referrer = params.referrer;
|
||||
load_url_params.transition_type = params.transition;
|
||||
load_url_params.extra_headers = params.extra_headers;
|
||||
load_url_params.should_replace_current_entry =
|
||||
params.should_replace_current_entry;
|
||||
load_url_params.is_renderer_initiated = params.is_renderer_initiated;
|
||||
load_url_params.transferred_global_request_id =
|
||||
params.transferred_global_request_id;
|
||||
load_url_params.should_clear_history_list = true;
|
||||
|
||||
source->GetController().LoadURLWithParams(load_url_params);
|
||||
return source;
|
||||
void NativeWindow::DevToolsFocused() {
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnDevToolsFocus());
|
||||
}
|
||||
|
||||
content::JavaScriptDialogManager* NativeWindow::GetJavaScriptDialogManager(
|
||||
content::WebContents* source) {
|
||||
if (!dialog_manager_)
|
||||
dialog_manager_.reset(new AtomJavaScriptDialogManager);
|
||||
void NativeWindow::DevToolsOpened() {
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnDevToolsOpened());
|
||||
}
|
||||
|
||||
return dialog_manager_.get();
|
||||
void NativeWindow::DevToolsClosed() {
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnDevToolsClosed());
|
||||
}
|
||||
|
||||
void NativeWindow::RenderViewCreated(
|
||||
@@ -656,117 +552,22 @@ void NativeWindow::RenderViewCreated(
|
||||
impl->SetBackgroundOpaque(false);
|
||||
}
|
||||
|
||||
void NativeWindow::BeforeUnloadFired(content::WebContents* tab,
|
||||
bool proceed,
|
||||
bool* proceed_to_fire_unload) {
|
||||
*proceed_to_fire_unload = proceed;
|
||||
void NativeWindow::BeforeUnloadDialogCancelled() {
|
||||
WindowList::WindowCloseCancelled(this);
|
||||
|
||||
if (!proceed) {
|
||||
WindowList::WindowCloseCancelled(this);
|
||||
|
||||
// Cancel unresponsive event when window close is cancelled.
|
||||
window_unresposive_closure_.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
content::ColorChooser* NativeWindow::OpenColorChooser(
|
||||
content::WebContents* web_contents,
|
||||
SkColor color,
|
||||
const std::vector<content::ColorSuggestion>& suggestions) {
|
||||
return chrome::ShowColorChooser(web_contents, color);
|
||||
}
|
||||
|
||||
void NativeWindow::RunFileChooser(content::WebContents* web_contents,
|
||||
const content::FileChooserParams& params) {
|
||||
if (!web_dialog_helper_)
|
||||
web_dialog_helper_.reset(new WebDialogHelper(this));
|
||||
web_dialog_helper_->RunFileChooser(web_contents, params);
|
||||
}
|
||||
|
||||
void NativeWindow::EnumerateDirectory(content::WebContents* web_contents,
|
||||
int request_id,
|
||||
const base::FilePath& path) {
|
||||
if (!web_dialog_helper_)
|
||||
web_dialog_helper_.reset(new WebDialogHelper(this));
|
||||
web_dialog_helper_->EnumerateDirectory(web_contents, request_id, path);
|
||||
}
|
||||
|
||||
void NativeWindow::RequestToLockMouse(content::WebContents* web_contents,
|
||||
bool user_gesture,
|
||||
bool last_unlocked_by_target) {
|
||||
GetWebContents()->GotResponseToLockMouseRequest(true);
|
||||
}
|
||||
|
||||
bool NativeWindow::CanOverscrollContent() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void NativeWindow::ActivateContents(content::WebContents* contents) {
|
||||
FocusOnWebView();
|
||||
}
|
||||
|
||||
void NativeWindow::DeactivateContents(content::WebContents* contents) {
|
||||
BlurWebView();
|
||||
}
|
||||
|
||||
void NativeWindow::MoveContents(content::WebContents* source,
|
||||
const gfx::Rect& pos) {
|
||||
SetBounds(pos);
|
||||
}
|
||||
|
||||
void NativeWindow::CloseContents(content::WebContents* source) {
|
||||
// Destroy the WebContents before we close the window.
|
||||
DestroyWebContents();
|
||||
|
||||
// When the web contents is gone, close the window immediately, but the
|
||||
// memory will not be freed until you call delete.
|
||||
// In this way, it would be safe to manage windows via smart pointers. If you
|
||||
// want to free memory when the window is closed, you can do deleting by
|
||||
// overriding the OnWindowClosed method in the observer.
|
||||
CloseImmediately();
|
||||
|
||||
// Do not sent "unresponsive" event after window is closed.
|
||||
// Cancel unresponsive event when window close is cancelled.
|
||||
window_unresposive_closure_.Cancel();
|
||||
}
|
||||
|
||||
bool NativeWindow::IsPopupOrPanel(const content::WebContents* source) const {
|
||||
// Only popup window can use things like window.moveTo.
|
||||
return true;
|
||||
}
|
||||
|
||||
void NativeWindow::RendererUnresponsive(content::WebContents* source) {
|
||||
// Schedule the unresponsive shortly later, since we may receive the
|
||||
// responsive event soon. This could happen after the whole application had
|
||||
// blocked for a while.
|
||||
// Also notice that when closing this event would be ignored because we have
|
||||
// explicity started a close timeout counter. This is on purpose because we
|
||||
// don't want the unresponsive event to be sent too early when user is closing
|
||||
// the window.
|
||||
ScheduleUnresponsiveEvent(50);
|
||||
}
|
||||
|
||||
void NativeWindow::RendererResponsive(content::WebContents* source) {
|
||||
window_unresposive_closure_.Cancel();
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnRendererResponsive());
|
||||
}
|
||||
|
||||
void NativeWindow::EnterFullscreenModeForTab(content::WebContents* source,
|
||||
const GURL& origin) {
|
||||
SetHtmlApiFullscreen(true);
|
||||
}
|
||||
|
||||
void NativeWindow::ExitFullscreenModeForTab(content::WebContents* source) {
|
||||
SetHtmlApiFullscreen(false);
|
||||
}
|
||||
|
||||
bool NativeWindow::IsFullscreenForTabOrPending(
|
||||
const content::WebContents* source) const {
|
||||
return is_html_api_fullscreen();
|
||||
}
|
||||
|
||||
void NativeWindow::BeforeUnloadFired(const base::TimeTicks& proceed_time) {
|
||||
// Do nothing, we override this method just to avoid compilation error since
|
||||
// there are two virtual functions named BeforeUnloadFired.
|
||||
void NativeWindow::TitleWasSet(content::NavigationEntry* entry,
|
||||
bool explicit_set) {
|
||||
bool prevent_default = false;
|
||||
std::string text = entry ? base::UTF16ToUTF8(entry->GetTitle()) : "";
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver,
|
||||
observers_,
|
||||
OnPageTitleUpdated(&prevent_default, text));
|
||||
if (!prevent_default)
|
||||
SetTitle(text);
|
||||
}
|
||||
|
||||
bool NativeWindow::OnMessageReceived(const IPC::Message& message) {
|
||||
@@ -780,65 +581,12 @@ bool NativeWindow::OnMessageReceived(const IPC::Message& message) {
|
||||
return handled;
|
||||
}
|
||||
|
||||
void NativeWindow::Observe(int type,
|
||||
const content::NotificationSource& source,
|
||||
const content::NotificationDetails& details) {
|
||||
if (type == content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED) {
|
||||
std::pair<NavigationEntry*, bool>* title =
|
||||
content::Details<std::pair<NavigationEntry*, bool>>(details).ptr();
|
||||
|
||||
if (title->first) {
|
||||
bool prevent_default = false;
|
||||
std::string text = base::UTF16ToUTF8(title->first->GetTitle());
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver,
|
||||
observers_,
|
||||
OnPageTitleUpdated(&prevent_default, text));
|
||||
|
||||
if (!prevent_default)
|
||||
SetTitle(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindow::DevToolsSaveToFile(const std::string& url,
|
||||
const std::string& content,
|
||||
bool save_as) {
|
||||
base::FilePath path;
|
||||
PathsMap::iterator it = saved_files_.find(url);
|
||||
if (it != saved_files_.end() && !save_as) {
|
||||
path = it->second;
|
||||
} else {
|
||||
file_dialog::Filters filters;
|
||||
base::FilePath default_path(base::FilePath::FromUTF8Unsafe(url));
|
||||
if (!file_dialog::ShowSaveDialog(this, url, default_path, filters, &path)) {
|
||||
base::StringValue url_value(url);
|
||||
CallDevToolsFunction("DevToolsAPI.canceledSaveURL", &url_value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
saved_files_[url] = path;
|
||||
base::WriteFile(path, content.data(), content.size());
|
||||
|
||||
// Notify devtools.
|
||||
base::StringValue url_value(url);
|
||||
CallDevToolsFunction("DevToolsAPI.savedURL", &url_value);
|
||||
}
|
||||
|
||||
void NativeWindow::DevToolsAppendToFile(const std::string& url,
|
||||
const std::string& content) {
|
||||
PathsMap::iterator it = saved_files_.find(url);
|
||||
if (it == saved_files_.end())
|
||||
void NativeWindow::UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions) {
|
||||
// Draggable region is not supported for non-frameless window.
|
||||
if (has_frame_)
|
||||
return;
|
||||
base::AppendToFile(it->second, content.data(), content.size());
|
||||
|
||||
// Notify devtools.
|
||||
base::StringValue url_value(url);
|
||||
CallDevToolsFunction("DevToolsAPI.appendedToURL", &url_value);
|
||||
}
|
||||
|
||||
void NativeWindow::DevToolsFocused() {
|
||||
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnDevToolsFocus());
|
||||
draggable_region_ = DraggableRegionsToSkRegion(regions);
|
||||
}
|
||||
|
||||
void NativeWindow::ScheduleUnresponsiveEvent(int ms) {
|
||||
@@ -869,27 +617,4 @@ void NativeWindow::OnCapturePageDone(const CapturePageCallback& callback,
|
||||
callback.Run(bitmap);
|
||||
}
|
||||
|
||||
void NativeWindow::CallDevToolsFunction(const std::string& function_name,
|
||||
const base::Value* arg1,
|
||||
const base::Value* arg2,
|
||||
const base::Value* arg3) {
|
||||
std::string params;
|
||||
if (arg1) {
|
||||
std::string json;
|
||||
base::JSONWriter::Write(arg1, &json);
|
||||
params.append(json);
|
||||
if (arg2) {
|
||||
base::JSONWriter::Write(arg2, &json);
|
||||
params.append(", " + json);
|
||||
if (arg3) {
|
||||
base::JSONWriter::Write(arg3, &json);
|
||||
params.append(", " + json);
|
||||
}
|
||||
}
|
||||
}
|
||||
base::string16 javascript =
|
||||
base::UTF8ToUTF16(function_name + "(" + params + ");");
|
||||
GetDevToolsWebContents()->GetMainFrame()->ExecuteJavaScript(javascript);
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -15,22 +15,26 @@
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/observer_list.h"
|
||||
#include "brightray/browser/default_web_contents_delegate.h"
|
||||
#include "brightray/browser/inspectable_web_contents_delegate.h"
|
||||
#include "brightray/browser/inspectable_web_contents_impl.h"
|
||||
#include "content/public/browser/notification_registrar.h"
|
||||
#include "content/public/browser/notification_observer.h"
|
||||
#include "brightray/browser/inspectable_web_contents_view_delegate.h"
|
||||
#include "content/public/browser/readback_types.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
#include "content/public/browser/web_contents_user_data.h"
|
||||
#include "native_mate/persistent_dictionary.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
#include "ui/gfx/image/image_skia.h"
|
||||
|
||||
class SkRegion;
|
||||
|
||||
namespace base {
|
||||
class CommandLine;
|
||||
}
|
||||
|
||||
namespace brightray {
|
||||
class InspectableWebContents;
|
||||
}
|
||||
|
||||
namespace content {
|
||||
class BrowserContext;
|
||||
class WebContents;
|
||||
struct NativeWebKeyboardEvent;
|
||||
struct WebPreferences;
|
||||
}
|
||||
|
||||
@@ -50,16 +54,12 @@ class MenuModel;
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomJavaScriptDialogManager;
|
||||
struct DraggableRegion;
|
||||
class WebDialogHelper;
|
||||
|
||||
class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
public brightray::InspectableWebContentsDelegate,
|
||||
public content::WebContentsObserver,
|
||||
public content::NotificationObserver {
|
||||
class NativeWindow : public content::WebContentsObserver,
|
||||
public brightray::InspectableWebContentsViewDelegate {
|
||||
public:
|
||||
typedef base::Callback<void(const SkBitmap& bitmap)> CapturePageCallback;
|
||||
using CapturePageCallback = base::Callback<void(const SkBitmap& bitmap)>;
|
||||
|
||||
class DialogScope {
|
||||
public:
|
||||
@@ -84,12 +84,9 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
|
||||
// Create window with existing WebContents, the caller is responsible for
|
||||
// managing the window's live.
|
||||
static NativeWindow* Create(content::WebContents* web_contents,
|
||||
const mate::Dictionary& options);
|
||||
|
||||
// Create window with new WebContents, the caller is responsible for
|
||||
// managing the window's live.
|
||||
static NativeWindow* Create(const mate::Dictionary& options);
|
||||
static NativeWindow* Create(
|
||||
brightray::InspectableWebContents* inspectable_web_contents,
|
||||
const mate::Dictionary& options);
|
||||
|
||||
// Find a window from its WebContents
|
||||
static NativeWindow* FromWebContents(content::WebContents* web_contents);
|
||||
@@ -98,6 +95,7 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
|
||||
virtual void Close() = 0;
|
||||
virtual void CloseImmediately() = 0;
|
||||
virtual bool IsClosed() const { return is_closed_; }
|
||||
virtual void Focus(bool focus) = 0;
|
||||
virtual bool IsFocused() = 0;
|
||||
virtual void Show() = 0;
|
||||
@@ -142,19 +140,17 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
virtual void SetMenu(ui::MenuModel* menu);
|
||||
virtual bool HasModalDialog();
|
||||
virtual gfx::NativeWindow GetNativeWindow() = 0;
|
||||
|
||||
// Taskbar/Dock APIs.
|
||||
virtual void SetProgressBar(double progress) = 0;
|
||||
virtual void SetOverlayIcon(const gfx::Image& overlay,
|
||||
const std::string& description) = 0;
|
||||
|
||||
// Workspace APIs.
|
||||
virtual void SetVisibleOnAllWorkspaces(bool visible) = 0;
|
||||
virtual bool IsVisibleOnAllWorkspaces() = 0;
|
||||
|
||||
virtual bool IsClosed() const { return is_closed_; }
|
||||
virtual void OpenDevTools(bool can_dock);
|
||||
virtual void CloseDevTools();
|
||||
virtual bool IsDevToolsOpened();
|
||||
virtual void InspectElement(int x, int y);
|
||||
virtual void InspectServiceWorker();
|
||||
|
||||
// Webview APIs.
|
||||
virtual void FocusOnWebView();
|
||||
virtual void BlurWebView();
|
||||
virtual bool IsWebViewFocused();
|
||||
@@ -164,9 +160,6 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
virtual void CapturePage(const gfx::Rect& rect,
|
||||
const CapturePageCallback& callback);
|
||||
|
||||
// Print current page.
|
||||
virtual void Print(bool silent, bool print_background);
|
||||
|
||||
// Show popup dictionary.
|
||||
virtual void ShowDefinitionForSelection();
|
||||
|
||||
@@ -176,29 +169,30 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
virtual void SetMenuBarVisibility(bool visible);
|
||||
virtual bool IsMenuBarVisible();
|
||||
|
||||
// The same with closing a tab in a real browser.
|
||||
//
|
||||
// Should be called by platform code when user want to close the window.
|
||||
virtual void CloseWebContents();
|
||||
|
||||
// Destroy the WebContents immediately.
|
||||
virtual void DestroyWebContents();
|
||||
// Set the aspect ratio when resizing window.
|
||||
double GetAspectRatio();
|
||||
gfx::Size GetAspectRatioExtraSize();
|
||||
void SetAspectRatio(double aspect_ratio, const gfx::Size& extra_size);
|
||||
|
||||
base::WeakPtr<NativeWindow> GetWeakPtr() {
|
||||
return weak_factory_.GetWeakPtr();
|
||||
}
|
||||
|
||||
content::WebContents* GetWebContents() const;
|
||||
content::WebContents* GetDevToolsWebContents() const;
|
||||
// Requests the WebContents to close, can be cancelled by the page.
|
||||
virtual void RequestToClosePage();
|
||||
|
||||
// Methods called by the WebContents.
|
||||
virtual void CloseContents(content::WebContents* source);
|
||||
virtual void RendererUnresponsive(content::WebContents* source);
|
||||
virtual void RendererResponsive(content::WebContents* source);
|
||||
virtual void HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent& event) {}
|
||||
|
||||
// Called when renderer process is going to be started.
|
||||
void AppendExtraCommandLineSwitches(base::CommandLine* command_line,
|
||||
int child_process_id);
|
||||
void AppendExtraCommandLineSwitches(base::CommandLine* command_line);
|
||||
void OverrideWebkitPrefs(content::WebPreferences* prefs);
|
||||
|
||||
// Set fullscreen mode triggered by html api.
|
||||
void SetHtmlApiFullscreen(bool enter_fullscreen);
|
||||
|
||||
// Public API used by platform-dependent delegates and observers to send UI
|
||||
// related notifications.
|
||||
void NotifyWindowClosed();
|
||||
@@ -215,99 +209,59 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
void NotifyWindowLeaveFullScreen();
|
||||
void NotifyWindowEnterHtmlFullScreen();
|
||||
void NotifyWindowLeaveHtmlFullScreen();
|
||||
void NotifyWindowExecuteWindowsCommand(const std::string& command);
|
||||
|
||||
void AddObserver(NativeWindowObserver* obs) {
|
||||
observers_.AddObserver(obs);
|
||||
}
|
||||
|
||||
void RemoveObserver(NativeWindowObserver* obs) {
|
||||
observers_.RemoveObserver(obs);
|
||||
}
|
||||
|
||||
bool has_frame() const { return has_frame_; }
|
||||
brightray::InspectableWebContents* inspectable_web_contents() const {
|
||||
return inspectable_web_contents_;
|
||||
}
|
||||
|
||||
bool is_html_api_fullscreen() const { return html_fullscreen_; }
|
||||
bool has_frame() const { return has_frame_; }
|
||||
bool transparent() const { return transparent_; }
|
||||
SkRegion* draggable_region() const { return draggable_region_.get(); }
|
||||
bool enable_larger_than_screen() const { return enable_larger_than_screen_; }
|
||||
gfx::ImageSkia icon() const { return icon_; }
|
||||
|
||||
void set_has_dialog_attached(bool has_dialog_attached) {
|
||||
has_dialog_attached_ = has_dialog_attached;
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit NativeWindow(content::WebContents* web_contents,
|
||||
const mate::Dictionary& options);
|
||||
NativeWindow(brightray::InspectableWebContents* inspectable_web_contents,
|
||||
const mate::Dictionary& options);
|
||||
|
||||
brightray::InspectableWebContentsImpl* inspectable_web_contents() const {
|
||||
return static_cast<brightray::InspectableWebContentsImpl*>(
|
||||
inspectable_web_contents_.get());
|
||||
}
|
||||
// brightray::InspectableWebContentsViewDelegate:
|
||||
void DevToolsFocused() override;
|
||||
void DevToolsOpened() override;
|
||||
void DevToolsClosed() override;
|
||||
|
||||
// Called when the window needs to update its draggable region.
|
||||
virtual void UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions) = 0;
|
||||
|
||||
// Implementations of content::WebContentsDelegate.
|
||||
bool ShouldCreateWebContents(
|
||||
content::WebContents* web_contents,
|
||||
int route_id,
|
||||
int main_frame_route_id,
|
||||
WindowContainerType window_container_type,
|
||||
const base::string16& frame_name,
|
||||
const GURL& target_url,
|
||||
const std::string& partition_id,
|
||||
content::SessionStorageNamespace* session_storage_namespace) override;
|
||||
content::WebContents* OpenURLFromTab(
|
||||
content::WebContents* source,
|
||||
const content::OpenURLParams& params) override;
|
||||
content::JavaScriptDialogManager* GetJavaScriptDialogManager(
|
||||
content::WebContents* source) override;
|
||||
void BeforeUnloadFired(content::WebContents* tab,
|
||||
bool proceed,
|
||||
bool* proceed_to_fire_unload) override;
|
||||
content::ColorChooser* OpenColorChooser(
|
||||
content::WebContents* web_contents,
|
||||
SkColor color,
|
||||
const std::vector<content::ColorSuggestion>& suggestions) override;
|
||||
void RunFileChooser(content::WebContents* web_contents,
|
||||
const content::FileChooserParams& params) override;
|
||||
void EnumerateDirectory(content::WebContents* web_contents,
|
||||
int request_id,
|
||||
const base::FilePath& path) override;
|
||||
void RequestToLockMouse(content::WebContents* web_contents,
|
||||
bool user_gesture,
|
||||
bool last_unlocked_by_target) override;
|
||||
bool CanOverscrollContent() const override;
|
||||
void ActivateContents(content::WebContents* contents) override;
|
||||
void DeactivateContents(content::WebContents* contents) override;
|
||||
void MoveContents(content::WebContents* source,
|
||||
const gfx::Rect& pos) override;
|
||||
void CloseContents(content::WebContents* source) override;
|
||||
bool IsPopupOrPanel(
|
||||
const content::WebContents* source) const override;
|
||||
void RendererUnresponsive(content::WebContents* source) override;
|
||||
void RendererResponsive(content::WebContents* source) override;
|
||||
void EnterFullscreenModeForTab(content::WebContents* source,
|
||||
const GURL& origin) override;
|
||||
void ExitFullscreenModeForTab(content::WebContents* source) override;
|
||||
bool IsFullscreenForTabOrPending(
|
||||
const content::WebContents* source) const override;
|
||||
|
||||
// Implementations of content::WebContentsObserver.
|
||||
// content::WebContentsObserver:
|
||||
void RenderViewCreated(content::RenderViewHost* render_view_host) override;
|
||||
void BeforeUnloadFired(const base::TimeTicks& proceed_time) override;
|
||||
void BeforeUnloadDialogCancelled() override;
|
||||
void TitleWasSet(content::NavigationEntry* entry, bool explicit_set) override;
|
||||
bool OnMessageReceived(const IPC::Message& message) override;
|
||||
|
||||
// Implementations of content::NotificationObserver.
|
||||
void Observe(int type,
|
||||
const content::NotificationSource& source,
|
||||
const content::NotificationDetails& details) override;
|
||||
private:
|
||||
// Called when the window needs to update its draggable region.
|
||||
void UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions);
|
||||
|
||||
// Implementations of brightray::InspectableWebContentsDelegate.
|
||||
void DevToolsSaveToFile(const std::string& url,
|
||||
const std::string& content,
|
||||
bool save_as) override;
|
||||
void DevToolsAppendToFile(const std::string& url,
|
||||
const std::string& content) override;
|
||||
void DevToolsFocused() override;
|
||||
// Schedule a notification unresponsive event.
|
||||
void ScheduleUnresponsiveEvent(int ms);
|
||||
|
||||
// Dispatch unresponsive event to observers.
|
||||
void NotifyWindowUnresponsive();
|
||||
|
||||
// Called when CapturePage has done.
|
||||
void OnCapturePageDone(const CapturePageCallback& callback,
|
||||
const SkBitmap& bitmap,
|
||||
content::ReadbackResponse response);
|
||||
|
||||
// Whether window has standard frame.
|
||||
bool has_frame_;
|
||||
@@ -315,36 +269,16 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
// Whether window is transparent.
|
||||
bool transparent_;
|
||||
|
||||
// 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.
|
||||
|
||||
// Whether window can be resized larger than screen.
|
||||
bool enable_larger_than_screen_;
|
||||
|
||||
// Window icon.
|
||||
gfx::ImageSkia icon_;
|
||||
|
||||
private:
|
||||
// Schedule a notification unresponsive event.
|
||||
void ScheduleUnresponsiveEvent(int ms);
|
||||
|
||||
// Dispatch unresponsive event to observers.
|
||||
void NotifyWindowUnresponsive();
|
||||
|
||||
// Call a function in devtools.
|
||||
void CallDevToolsFunction(const std::string& function_name,
|
||||
const base::Value* arg1 = NULL,
|
||||
const base::Value* arg2 = NULL,
|
||||
const base::Value* arg3 = NULL);
|
||||
|
||||
// Called when CapturePage has done.
|
||||
void OnCapturePageDone(const CapturePageCallback& callback,
|
||||
const SkBitmap& bitmap,
|
||||
content::ReadbackResponse response);
|
||||
|
||||
// Notification manager.
|
||||
content::NotificationRegistrar registrar_;
|
||||
|
||||
// Observers of this window.
|
||||
ObserverList<NativeWindowObserver> observers_;
|
||||
|
||||
// The windows has been closed.
|
||||
bool is_closed_;
|
||||
|
||||
@@ -354,12 +288,6 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
// There is a dialog that has been attached to window.
|
||||
bool has_dialog_attached_;
|
||||
|
||||
// Whether window is fullscreened by HTML5 api.
|
||||
bool html_fullscreen_;
|
||||
|
||||
// Whether window is fullscreened by window api.
|
||||
bool native_fullscreen_;
|
||||
|
||||
// Closure that would be called when window is unresponsive when closing,
|
||||
// it should be cancelled when we can prove that the window is responsive.
|
||||
base::CancelableClosure window_unresposive_closure_;
|
||||
@@ -373,23 +301,37 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
|
||||
// Page's default zoom factor.
|
||||
double zoom_factor_;
|
||||
|
||||
// Used to maintain the aspect ratio of a view which is inside of the
|
||||
// content view.
|
||||
double aspect_ratio_;
|
||||
gfx::Size aspect_ratio_extraSize_;
|
||||
|
||||
// The page this window is viewing.
|
||||
brightray::InspectableWebContents* inspectable_web_contents_;
|
||||
|
||||
// Observers of this window.
|
||||
ObserverList<NativeWindowObserver> observers_;
|
||||
|
||||
base::WeakPtrFactory<NativeWindow> weak_factory_;
|
||||
|
||||
scoped_ptr<WebDialogHelper> web_dialog_helper_;
|
||||
scoped_ptr<AtomJavaScriptDialogManager> dialog_manager_;
|
||||
|
||||
// Notice that inspectable_web_contents_ must be placed after dialog_manager_,
|
||||
// so we can make sure inspectable_web_contents_ is destroyed before
|
||||
// dialog_manager_, otherwise a crash would happen.
|
||||
scoped_ptr<brightray::InspectableWebContents> inspectable_web_contents_;
|
||||
|
||||
// Maps url to file path, used by the file requests sent from devtools.
|
||||
typedef std::map<std::string, base::FilePath> PathsMap;
|
||||
PathsMap saved_files_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NativeWindow);
|
||||
};
|
||||
|
||||
|
||||
// This class provides a hook to get a NativeWindow from a WebContents.
|
||||
class NativeWindowRelay :
|
||||
public content::WebContentsUserData<NativeWindowRelay> {
|
||||
public:
|
||||
explicit NativeWindowRelay(base::WeakPtr<NativeWindow> window)
|
||||
: key(UserDataKey()), window(window) {}
|
||||
|
||||
void* key;
|
||||
base::WeakPtr<NativeWindow> window;
|
||||
|
||||
private:
|
||||
friend class content::WebContentsUserData<NativeWindow>;
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_NATIVE_WINDOW_H_
|
||||
|
||||
@@ -11,23 +11,21 @@
|
||||
#include <vector>
|
||||
|
||||
#include "base/mac/scoped_nsobject.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
|
||||
@class AtomNSWindow;
|
||||
@class AtomNSWindowDelegate;
|
||||
@class FullSizeContentView;
|
||||
class SkRegion;
|
||||
|
||||
namespace atom {
|
||||
|
||||
class NativeWindowMac : public NativeWindow {
|
||||
public:
|
||||
explicit NativeWindowMac(content::WebContents* web_contents,
|
||||
const mate::Dictionary& options);
|
||||
virtual ~NativeWindowMac();
|
||||
NativeWindowMac(brightray::InspectableWebContents* inspectable_web_contents,
|
||||
const mate::Dictionary& options);
|
||||
~NativeWindowMac() override;
|
||||
|
||||
// NativeWindow implementation.
|
||||
// NativeWindow:
|
||||
void Close() override;
|
||||
void CloseImmediately() override;
|
||||
void Focus(bool focus) override;
|
||||
@@ -88,10 +86,7 @@ class NativeWindowMac : public NativeWindow {
|
||||
void ClipWebView();
|
||||
|
||||
protected:
|
||||
void UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions) override;
|
||||
|
||||
// Implementations of content::WebContentsDelegate.
|
||||
// NativeWindow:
|
||||
void HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent&) override;
|
||||
@@ -117,10 +112,6 @@ class NativeWindowMac : public NativeWindow {
|
||||
// The presentation options before entering kiosk mode.
|
||||
NSApplicationPresentationOptions kiosk_options_;
|
||||
|
||||
// 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_;
|
||||
|
||||
@@ -20,7 +20,26 @@
|
||||
#include "content/public/browser/render_widget_host_view.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
|
||||
static const CGFloat kAtomWindowCornerRadius = 4.0;
|
||||
namespace {
|
||||
|
||||
// The radius of rounded corner.
|
||||
const CGFloat kAtomWindowCornerRadius = 4.0;
|
||||
|
||||
// Prevents window from resizing during the scope.
|
||||
class ScopedDisableResize {
|
||||
public:
|
||||
ScopedDisableResize() { disable_resize_ = true; }
|
||||
~ScopedDisableResize() { disable_resize_ = false; }
|
||||
|
||||
static bool IsResizeDisabled() { return disable_resize_; }
|
||||
|
||||
private:
|
||||
static bool disable_resize_;
|
||||
};
|
||||
|
||||
bool ScopedDisableResize::disable_resize_ = false;
|
||||
|
||||
} // namespace
|
||||
|
||||
@interface NSView (PrivateMethods)
|
||||
- (CGFloat)roundedCornerRadius;
|
||||
@@ -68,7 +87,7 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
|
||||
}
|
||||
|
||||
- (void)windowDidBecomeMain:(NSNotification*)notification {
|
||||
content::WebContents* web_contents = shell_->GetWebContents();
|
||||
content::WebContents* web_contents = shell_->web_contents();
|
||||
if (!web_contents)
|
||||
return;
|
||||
|
||||
@@ -82,7 +101,7 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
|
||||
}
|
||||
|
||||
- (void)windowDidResignMain:(NSNotification*)notification {
|
||||
content::WebContents* web_contents = shell_->GetWebContents();
|
||||
content::WebContents* web_contents = shell_->web_contents();
|
||||
if (!web_contents)
|
||||
return;
|
||||
|
||||
@@ -95,6 +114,44 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
|
||||
shell_->NotifyWindowBlur();
|
||||
}
|
||||
|
||||
- (NSSize)windowWillResize:(NSWindow*)sender toSize:(NSSize)frameSize {
|
||||
NSSize newSize = frameSize;
|
||||
double aspectRatio = shell_->GetAspectRatio();
|
||||
|
||||
if (aspectRatio > 0.0) {
|
||||
gfx::Size windowSize = shell_->GetSize();
|
||||
gfx::Size contentSize = shell_->GetContentSize();
|
||||
gfx::Size extraSize = shell_->GetAspectRatioExtraSize();
|
||||
|
||||
double extraWidthPlusFrame =
|
||||
windowSize.width() - contentSize.width() + extraSize.width();
|
||||
double extraHeightPlusFrame =
|
||||
windowSize.height() - contentSize.height() + extraSize.height();
|
||||
|
||||
newSize.width =
|
||||
roundf((frameSize.height - extraHeightPlusFrame) * aspectRatio +
|
||||
extraWidthPlusFrame);
|
||||
|
||||
// If the new width is less than the frame size use it as the primary
|
||||
// constraint. This ensures that the value returned by this method will
|
||||
// never be larger than the users requested window size.
|
||||
if (newSize.width <= frameSize.width) {
|
||||
newSize.height =
|
||||
roundf((newSize.width - extraWidthPlusFrame) / aspectRatio +
|
||||
extraHeightPlusFrame);
|
||||
} else {
|
||||
newSize.height =
|
||||
roundf((frameSize.width - extraWidthPlusFrame) / aspectRatio +
|
||||
extraHeightPlusFrame);
|
||||
newSize.width =
|
||||
roundf((newSize.height - extraHeightPlusFrame) * aspectRatio +
|
||||
extraWidthPlusFrame);
|
||||
}
|
||||
}
|
||||
|
||||
return newSize;
|
||||
}
|
||||
|
||||
- (void)windowDidResize:(NSNotification*)notification {
|
||||
if (!shell_->has_frame())
|
||||
shell_->ClipWebView();
|
||||
@@ -104,7 +161,7 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
|
||||
|
||||
- (void)windowDidMove:(NSNotification*)notification {
|
||||
// TODO(zcbenz): Remove the alias after figuring out a proper
|
||||
// way to disptach move.
|
||||
// way to disptach move.
|
||||
shell_->NotifyWindowMove();
|
||||
shell_->NotifyWindowMoved();
|
||||
}
|
||||
@@ -149,7 +206,7 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
|
||||
// When user tries to close the window by clicking the close button, we do
|
||||
// not close the window immediately, instead we try to close the web page
|
||||
// fisrt, and when the web page is closed the window will also be closed.
|
||||
shell_->CloseWebContents();
|
||||
shell_->RequestToClosePage();
|
||||
return NO;
|
||||
}
|
||||
|
||||
@@ -176,8 +233,12 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
|
||||
enable_larger_than_screen_ = enable;
|
||||
}
|
||||
|
||||
// Enable the window to be larger than screen.
|
||||
- (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen*)screen {
|
||||
// Resizing is disabled.
|
||||
if (ScopedDisableResize::IsResizeDisabled())
|
||||
return [self frame];
|
||||
|
||||
// Enable the window to be larger than screen.
|
||||
if (enable_larger_than_screen_)
|
||||
return frameRect;
|
||||
else
|
||||
@@ -280,31 +341,9 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
// Convert draggable regions in raw format to SkRegion format. Caller is
|
||||
// responsible for deleting the returned SkRegion instance.
|
||||
SkRegion* DraggableRegionsToSkRegion(
|
||||
const std::vector<DraggableRegion>& regions) {
|
||||
SkRegion* sk_region = new SkRegion;
|
||||
for (std::vector<DraggableRegion>::const_iterator iter = regions.begin();
|
||||
iter != regions.end();
|
||||
++iter) {
|
||||
const DraggableRegion& region = *iter;
|
||||
sk_region->op(
|
||||
region.bounds.x(),
|
||||
region.bounds.y(),
|
||||
region.bounds.right(),
|
||||
region.bounds.bottom(),
|
||||
region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
|
||||
}
|
||||
return sk_region;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
NativeWindowMac::NativeWindowMac(content::WebContents* web_contents,
|
||||
const mate::Dictionary& options)
|
||||
NativeWindowMac::NativeWindowMac(
|
||||
brightray::InspectableWebContents* web_contents,
|
||||
const mate::Dictionary& options)
|
||||
: NativeWindow(web_contents, options),
|
||||
is_kiosk_(false),
|
||||
attention_request_id_(0) {
|
||||
@@ -324,7 +363,7 @@ NativeWindowMac::NativeWindowMac(content::WebContents* web_contents,
|
||||
|
||||
NSUInteger styleMask = NSTitledWindowMask | NSClosableWindowMask |
|
||||
NSMiniaturizableWindowMask | NSResizableWindowMask;
|
||||
if (!useStandardWindow || transparent_ || !has_frame_) {
|
||||
if (!useStandardWindow || transparent() || !has_frame()) {
|
||||
styleMask |= NSTexturedBackgroundWindowMask;
|
||||
}
|
||||
|
||||
@@ -334,12 +373,12 @@ NativeWindowMac::NativeWindowMac(content::WebContents* web_contents,
|
||||
backing:NSBackingStoreBuffered
|
||||
defer:YES]);
|
||||
[window_ setShell:this];
|
||||
[window_ setEnableLargerThanScreen:enable_larger_than_screen_];
|
||||
[window_ setEnableLargerThanScreen:enable_larger_than_screen()];
|
||||
|
||||
window_delegate_.reset([[AtomNSWindowDelegate alloc] initWithShell:this]);
|
||||
[window_ setDelegate:window_delegate_];
|
||||
|
||||
if (transparent_) {
|
||||
if (transparent()) {
|
||||
// Make window has transparent background.
|
||||
[window_ setOpaque:NO];
|
||||
[window_ setHasShadow:NO];
|
||||
@@ -347,7 +386,7 @@ NativeWindowMac::NativeWindowMac(content::WebContents* web_contents,
|
||||
}
|
||||
|
||||
// Remove non-transparent corners, see http://git.io/vfonD.
|
||||
if (!has_frame_)
|
||||
if (!has_frame())
|
||||
[window_ setOpaque:NO];
|
||||
|
||||
// We will manage window's lifetime ourselves.
|
||||
@@ -356,7 +395,7 @@ NativeWindowMac::NativeWindowMac(content::WebContents* web_contents,
|
||||
// On OS X the initial window size doesn't include window frame.
|
||||
bool use_content_size = false;
|
||||
options.Get(switches::kUseContentSize, &use_content_size);
|
||||
if (has_frame_ && !use_content_size)
|
||||
if (!has_frame() || !use_content_size)
|
||||
SetSize(gfx::Size(width, height));
|
||||
|
||||
// Enable the NSView to accept first mouse event.
|
||||
@@ -385,9 +424,7 @@ NativeWindowMac::NativeWindowMac(content::WebContents* web_contents,
|
||||
}
|
||||
|
||||
NativeWindowMac::~NativeWindowMac() {
|
||||
// Force InspectableWebContents to be destroyed before we destroy window,
|
||||
// because it may still be observing the window at this time.
|
||||
DestroyWebContents();
|
||||
Observe(nullptr);
|
||||
}
|
||||
|
||||
void NativeWindowMac::Close() {
|
||||
@@ -495,6 +532,11 @@ gfx::Rect NativeWindowMac::GetBounds() {
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetContentSize(const gfx::Size& size) {
|
||||
if (!has_frame()) {
|
||||
SetSize(size);
|
||||
return;
|
||||
}
|
||||
|
||||
NSRect frame_nsrect = [window_ frame];
|
||||
NSSize frame = frame_nsrect.size;
|
||||
NSSize content = [window_ contentRectForFrameRect:frame_nsrect].size;
|
||||
@@ -508,6 +550,9 @@ void NativeWindowMac::SetContentSize(const gfx::Size& size) {
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowMac::GetContentSize() {
|
||||
if (!has_frame())
|
||||
return GetSize();
|
||||
|
||||
NSRect bounds = [[window_ contentView] bounds];
|
||||
return gfx::Size(bounds.size.width, bounds.size.height);
|
||||
}
|
||||
@@ -539,12 +584,15 @@ gfx::Size NativeWindowMac::GetMaximumSize() {
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetResizable(bool resizable) {
|
||||
// Change styleMask for frameless causes the window to change size, so we have
|
||||
// to explicitly disables that.
|
||||
ScopedDisableResize disable_resize;
|
||||
if (resizable) {
|
||||
[[window_ standardWindowButton:NSWindowZoomButton] setEnabled:YES];
|
||||
[window_ setStyleMask:[window_ styleMask] | NSResizableWindowMask];
|
||||
} else {
|
||||
[[window_ standardWindowButton:NSWindowZoomButton] setEnabled:NO];
|
||||
[window_ setStyleMask:[window_ styleMask] ^ NSResizableWindowMask];
|
||||
[window_ setStyleMask:[window_ styleMask] & (~NSResizableWindowMask)];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -566,7 +614,7 @@ void NativeWindowMac::Center() {
|
||||
|
||||
void NativeWindowMac::SetTitle(const std::string& title) {
|
||||
// We don't want the title to show in transparent window.
|
||||
if (transparent_)
|
||||
if (transparent())
|
||||
return;
|
||||
|
||||
[window_ setTitle:base::SysUTF8ToNSString(title)];
|
||||
@@ -678,10 +726,9 @@ void NativeWindowMac::SetOverlayIcon(const gfx::Image& overlay,
|
||||
}
|
||||
|
||||
void NativeWindowMac::ShowDefinitionForSelection() {
|
||||
content::WebContents* web_contents = GetWebContents();
|
||||
if (!web_contents)
|
||||
if (!web_contents())
|
||||
return;
|
||||
content::RenderWidgetHostView* rwhv = web_contents->GetRenderWidgetHostView();
|
||||
auto rwhv = web_contents()->GetRenderWidgetHostView();
|
||||
if (!rwhv)
|
||||
return;
|
||||
rwhv->ShowDefinitionForSelection();
|
||||
@@ -703,17 +750,16 @@ bool NativeWindowMac::IsVisibleOnAllWorkspaces() {
|
||||
}
|
||||
|
||||
bool NativeWindowMac::IsWithinDraggableRegion(NSPoint point) const {
|
||||
if (!draggable_region_)
|
||||
if (!draggable_region())
|
||||
return false;
|
||||
content::WebContents* web_contents = GetWebContents();
|
||||
if (!web_contents)
|
||||
if (!web_contents())
|
||||
return false;
|
||||
NSView* webView = web_contents->GetNativeView();
|
||||
NSView* webView = web_contents()->GetNativeView();
|
||||
NSInteger webViewHeight = NSHeight([webView bounds]);
|
||||
// |draggable_region_| is stored in local platform-indepdent coordiate system
|
||||
// while |point| is in local Cocoa coordinate system. Do the conversion
|
||||
// to match these two.
|
||||
return draggable_region_->contains(point.x, webViewHeight - point.y);
|
||||
return draggable_region()->contains(point.x, webViewHeight - point.y);
|
||||
}
|
||||
|
||||
void NativeWindowMac::HandleMouseEvent(NSEvent* event) {
|
||||
@@ -733,15 +779,6 @@ void NativeWindowMac::HandleMouseEvent(NSEvent* event) {
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowMac::UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions) {
|
||||
// Draggable region is not supported for non-frameless window.
|
||||
if (has_frame_)
|
||||
return;
|
||||
|
||||
draggable_region_.reset(DraggableRegionsToSkRegion(regions));
|
||||
}
|
||||
|
||||
void NativeWindowMac::HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent& event) {
|
||||
@@ -768,7 +805,7 @@ void NativeWindowMac::HandleKeyboardEvent(
|
||||
|
||||
void NativeWindowMac::InstallView() {
|
||||
NSView* view = inspectable_web_contents()->GetView()->GetNativeView();
|
||||
if (has_frame_) {
|
||||
if (has_frame()) {
|
||||
// Add layer with white background for the contents view.
|
||||
base::scoped_nsobject<CALayer> layer([[CALayer alloc] init]);
|
||||
[layer setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)];
|
||||
@@ -815,16 +852,15 @@ void NativeWindowMac::UninstallView() {
|
||||
}
|
||||
|
||||
void NativeWindowMac::ClipWebView() {
|
||||
content::WebContents* web_contents = GetWebContents();
|
||||
if (!web_contents)
|
||||
if (!web_contents())
|
||||
return;
|
||||
NSView* webView = web_contents->GetNativeView();
|
||||
NSView* webView = web_contents()->GetNativeView();
|
||||
webView.layer.masksToBounds = YES;
|
||||
webView.layer.cornerRadius = kAtomWindowCornerRadius;
|
||||
}
|
||||
|
||||
void NativeWindowMac::InstallDraggableRegionView() {
|
||||
NSView* webView = GetWebContents()->GetNativeView();
|
||||
NSView* webView = web_contents()->GetNativeView();
|
||||
base::scoped_nsobject<NSView> controlRegion(
|
||||
[[ControlRegionView alloc] initWithShellWindow:this]);
|
||||
[controlRegion setFrame:NSMakeRect(0, 0,
|
||||
@@ -834,9 +870,10 @@ void NativeWindowMac::InstallDraggableRegionView() {
|
||||
}
|
||||
|
||||
// static
|
||||
NativeWindow* NativeWindow::Create(content::WebContents* web_contents,
|
||||
const mate::Dictionary& options) {
|
||||
return new NativeWindowMac(web_contents, options);
|
||||
NativeWindow* NativeWindow::Create(
|
||||
brightray::InspectableWebContents* inspectable_web_contents,
|
||||
const mate::Dictionary& options) {
|
||||
return new NativeWindowMac(inspectable_web_contents, options);
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -55,14 +55,19 @@ class NativeWindowObserver {
|
||||
virtual void OnWindowEnterHtmlFullScreen() {}
|
||||
virtual void OnWindowLeaveHtmlFullScreen() {}
|
||||
|
||||
// Called when devtools window gets focused.
|
||||
// Redirect devtools events.
|
||||
virtual void OnDevToolsFocus() {}
|
||||
virtual void OnDevToolsOpened() {}
|
||||
virtual void OnDevToolsClosed() {}
|
||||
|
||||
// Called when renderer is hung.
|
||||
virtual void OnRendererUnresponsive() {}
|
||||
|
||||
// Called when renderer recovers.
|
||||
virtual void OnRendererResponsive() {}
|
||||
|
||||
// Called on Windows when App Commands arrive (WM_APPCOMMAND)
|
||||
virtual void OnExecuteWindowsCommand(const std::string& command_name) {}
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -4,10 +4,6 @@
|
||||
|
||||
#include "atom/browser/native_window_views.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <shobjidl.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -16,10 +12,10 @@
|
||||
#include "atom/common/draggable_region.h"
|
||||
#include "atom/common/options_switches.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "browser/inspectable_web_contents_view.h"
|
||||
#include "brightray/browser/inspectable_web_contents.h"
|
||||
#include "brightray/browser/inspectable_web_contents_view.h"
|
||||
#include "content/public/browser/native_web_keyboard_event.h"
|
||||
#include "native_mate/dictionary.h"
|
||||
#include "ui/aura/window.h"
|
||||
#include "ui/aura/window_tree_host.h"
|
||||
#include "ui/base/hit_test.h"
|
||||
#include "ui/gfx/image/image.h"
|
||||
@@ -35,26 +31,20 @@
|
||||
#include "atom/browser/browser.h"
|
||||
#include "atom/browser/ui/views/global_menu_bar_x11.h"
|
||||
#include "atom/browser/ui/views/frameless_view.h"
|
||||
#include "atom/browser/ui/views/native_frame_view.h"
|
||||
#include "atom/browser/ui/x/window_state_watcher.h"
|
||||
#include "atom/browser/ui/x/x_window_utils.h"
|
||||
#include "base/environment.h"
|
||||
#include "base/nix/xdg_util.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "chrome/browser/ui/libgtk2ui/unity_service.h"
|
||||
#include "dbus/bus.h"
|
||||
#include "dbus/object_proxy.h"
|
||||
#include "dbus/message.h"
|
||||
#include "ui/base/x/x11_util.h"
|
||||
#include "ui/gfx/x/x11_types.h"
|
||||
#include "ui/views/window/native_frame_view.h"
|
||||
#elif defined(OS_WIN)
|
||||
#include "atom/browser/ui/views/win_frame_view.h"
|
||||
#include "base/win/scoped_comptr.h"
|
||||
#include "base/win/windows_version.h"
|
||||
#include "atom/browser/ui/win/atom_desktop_window_tree_host_win.h"
|
||||
#include "ui/base/win/shell.h"
|
||||
#include "ui/gfx/icon_util.h"
|
||||
#include "ui/gfx/win/dpi.h"
|
||||
#include "ui/views/win/hwnd_util.h"
|
||||
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
|
||||
#endif
|
||||
|
||||
namespace atom {
|
||||
@@ -68,42 +58,6 @@ const int kMenuBarHeight = 20;
|
||||
const int kMenuBarHeight = 25;
|
||||
#endif
|
||||
|
||||
#if defined(USE_X11)
|
||||
// Returns true if the bus name "com.canonical.AppMenu.Registrar" is available.
|
||||
bool ShouldUseGlobalMenuBar() {
|
||||
dbus::Bus::Options options;
|
||||
scoped_refptr<dbus::Bus> bus(new dbus::Bus(options));
|
||||
|
||||
dbus::ObjectProxy* object_proxy =
|
||||
bus->GetObjectProxy(DBUS_SERVICE_DBUS, dbus::ObjectPath(DBUS_PATH_DBUS));
|
||||
dbus::MethodCall method_call(DBUS_INTERFACE_DBUS, "ListNames");
|
||||
scoped_ptr<dbus::Response> response(object_proxy->CallMethodAndBlock(
|
||||
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
|
||||
if (!response) {
|
||||
bus->ShutdownAndBlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
dbus::MessageReader reader(response.get());
|
||||
dbus::MessageReader array_reader(NULL);
|
||||
if (!reader.PopArray(&array_reader)) {
|
||||
bus->ShutdownAndBlock();
|
||||
return false;
|
||||
}
|
||||
while (array_reader.HasMoreData()) {
|
||||
std::string name;
|
||||
if (array_reader.PopString(&name) &&
|
||||
name == "com.canonical.AppMenu.Registrar") {
|
||||
bus->ShutdownAndBlock();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bus->ShutdownAndBlock();
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool IsAltKey(const content::NativeWebKeyboardEvent& event) {
|
||||
#if defined(USE_X11)
|
||||
// 164 and 165 represent VK_LALT and VK_RALT.
|
||||
@@ -123,6 +77,70 @@ bool IsAltModifier(const content::NativeWebKeyboardEvent& event) {
|
||||
(modifiers == (Modifiers::AltKey | Modifiers::IsRight));
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Convert Win32 WM_APPCOMMANDS to strings.
|
||||
const char* AppCommandToString(int command_id) {
|
||||
switch (command_id) {
|
||||
case APPCOMMAND_BROWSER_BACKWARD : return "browser-backward";
|
||||
case APPCOMMAND_BROWSER_FORWARD : return "browser-forward";
|
||||
case APPCOMMAND_BROWSER_REFRESH : return "browser-refresh";
|
||||
case APPCOMMAND_BROWSER_STOP : return "browser-stop";
|
||||
case APPCOMMAND_BROWSER_SEARCH : return "browser-search";
|
||||
case APPCOMMAND_BROWSER_FAVORITES : return "browser-favorites";
|
||||
case APPCOMMAND_BROWSER_HOME : return "browser-home";
|
||||
case APPCOMMAND_VOLUME_MUTE : return "volume-mute";
|
||||
case APPCOMMAND_VOLUME_DOWN : return "volume-down";
|
||||
case APPCOMMAND_VOLUME_UP : return "volume-up";
|
||||
case APPCOMMAND_MEDIA_NEXTTRACK : return "media-nexttrack";
|
||||
case APPCOMMAND_MEDIA_PREVIOUSTRACK : return "media-previoustrack";
|
||||
case APPCOMMAND_MEDIA_STOP : return "media-stop";
|
||||
case APPCOMMAND_MEDIA_PLAY_PAUSE : return "media-play_pause";
|
||||
case APPCOMMAND_LAUNCH_MAIL : return "launch-mail";
|
||||
case APPCOMMAND_LAUNCH_MEDIA_SELECT : return "launch-media-select";
|
||||
case APPCOMMAND_LAUNCH_APP1 : return "launch-app1";
|
||||
case APPCOMMAND_LAUNCH_APP2 : return "launch-app2";
|
||||
case APPCOMMAND_BASS_DOWN : return "bass-down";
|
||||
case APPCOMMAND_BASS_BOOST : return "bass-boost";
|
||||
case APPCOMMAND_BASS_UP : return "bass-up";
|
||||
case APPCOMMAND_TREBLE_DOWN : return "treble-down";
|
||||
case APPCOMMAND_TREBLE_UP : return "treble-up";
|
||||
case APPCOMMAND_MICROPHONE_VOLUME_MUTE : return "microphone-volume-mute";
|
||||
case APPCOMMAND_MICROPHONE_VOLUME_DOWN : return "microphone-volume-down";
|
||||
case APPCOMMAND_MICROPHONE_VOLUME_UP : return "microphone-volume-up";
|
||||
case APPCOMMAND_HELP : return "help";
|
||||
case APPCOMMAND_FIND : return "find";
|
||||
case APPCOMMAND_NEW : return "new";
|
||||
case APPCOMMAND_OPEN : return "open";
|
||||
case APPCOMMAND_CLOSE : return "close";
|
||||
case APPCOMMAND_SAVE : return "save";
|
||||
case APPCOMMAND_PRINT : return "print";
|
||||
case APPCOMMAND_UNDO : return "undo";
|
||||
case APPCOMMAND_REDO : return "redo";
|
||||
case APPCOMMAND_COPY : return "copy";
|
||||
case APPCOMMAND_CUT : return "cut";
|
||||
case APPCOMMAND_PASTE : return "paste";
|
||||
case APPCOMMAND_REPLY_TO_MAIL : return "reply-to-mail";
|
||||
case APPCOMMAND_FORWARD_MAIL : return "forward-mail";
|
||||
case APPCOMMAND_SEND_MAIL : return "send-mail";
|
||||
case APPCOMMAND_SPELL_CHECK : return "spell-check";
|
||||
case APPCOMMAND_MIC_ON_OFF_TOGGLE : return "mic-on-off-toggle";
|
||||
case APPCOMMAND_CORRECTION_LIST : return "correction-list";
|
||||
case APPCOMMAND_MEDIA_PLAY : return "media-play";
|
||||
case APPCOMMAND_MEDIA_PAUSE : return "media-pause";
|
||||
case APPCOMMAND_MEDIA_RECORD : return "media-record";
|
||||
case APPCOMMAND_MEDIA_FAST_FORWARD : return "media-fast-forward";
|
||||
case APPCOMMAND_MEDIA_REWIND : return "media-rewind";
|
||||
case APPCOMMAND_MEDIA_CHANNEL_UP : return "media-channel-up";
|
||||
case APPCOMMAND_MEDIA_CHANNEL_DOWN : return "media-channel-down";
|
||||
case APPCOMMAND_DELETE : return "delete";
|
||||
case APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE:
|
||||
return "dictate-or-command-control-toggle";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
class NativeWindowClientView : public views::ClientView {
|
||||
public:
|
||||
NativeWindowClientView(views::Widget* widget,
|
||||
@@ -132,7 +150,7 @@ class NativeWindowClientView : public views::ClientView {
|
||||
virtual ~NativeWindowClientView() {}
|
||||
|
||||
bool CanClose() override {
|
||||
static_cast<NativeWindowViews*>(contents_view())->CloseWebContents();
|
||||
static_cast<NativeWindowViews*>(contents_view())->RequestToClosePage();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -142,8 +160,9 @@ class NativeWindowClientView : public views::ClientView {
|
||||
|
||||
} // namespace
|
||||
|
||||
NativeWindowViews::NativeWindowViews(content::WebContents* web_contents,
|
||||
const mate::Dictionary& options)
|
||||
NativeWindowViews::NativeWindowViews(
|
||||
brightray::InspectableWebContents* web_contents,
|
||||
const mate::Dictionary& options)
|
||||
: NativeWindow(web_contents, options),
|
||||
window_(new views::Widget),
|
||||
web_view_(inspectable_web_contents()->GetView()->GetView()),
|
||||
@@ -165,7 +184,7 @@ NativeWindowViews::NativeWindowViews(content::WebContents* web_contents,
|
||||
options.Get(switches::kResizable, &resizable_);
|
||||
#endif
|
||||
|
||||
if (enable_larger_than_screen_)
|
||||
if (enable_larger_than_screen())
|
||||
// We need to set a default maximum window size here otherwise Windows
|
||||
// will not allow us to resize the window larger than scree.
|
||||
// Setting directly to INT_MAX somehow doesn't work, so we just devide
|
||||
@@ -185,12 +204,20 @@ NativeWindowViews::NativeWindowViews(content::WebContents* web_contents,
|
||||
params.bounds = bounds;
|
||||
params.delegate = this;
|
||||
params.type = views::Widget::InitParams::TYPE_WINDOW;
|
||||
params.remove_standard_frame = !has_frame_;
|
||||
params.remove_standard_frame = !has_frame();
|
||||
|
||||
if (transparent_)
|
||||
if (transparent())
|
||||
params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
|
||||
|
||||
#if defined(USE_X11)
|
||||
#if defined(OS_WIN)
|
||||
params.native_widget =
|
||||
new views::DesktopNativeWidgetAura(window_.get());
|
||||
atom_desktop_window_tree_host_win_ = new AtomDesktopWindowTreeHostWin(
|
||||
this,
|
||||
window_.get(),
|
||||
static_cast<views::DesktopNativeWidgetAura*>(params.native_widget));
|
||||
params.desktop_window_tree_host = atom_desktop_window_tree_host_win_;
|
||||
#elif defined(USE_X11)
|
||||
std::string name = Browser::Get()->GetName();
|
||||
// Set WM_WINDOW_ROLE.
|
||||
params.wm_role_name = "browser-window";
|
||||
@@ -219,14 +246,21 @@ NativeWindowViews::NativeWindowViews(content::WebContents* web_contents,
|
||||
|
||||
// Before the window is mapped the SetWMSpecState can not work, so we have
|
||||
// to manually set the _NET_WM_STATE.
|
||||
std::vector<::Atom> state_atom_list;
|
||||
bool skip_taskbar = false;
|
||||
if (options.Get(switches::kSkipTaskbar, &skip_taskbar) && skip_taskbar) {
|
||||
std::vector<::Atom> state_atom_list;
|
||||
state_atom_list.push_back(GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
|
||||
ui::SetAtomArrayProperty(GetAcceleratedWidget(), "_NET_WM_STATE", "ATOM",
|
||||
state_atom_list);
|
||||
}
|
||||
|
||||
// Before the window is mapped, there is no SHOW_FULLSCREEN_STATE.
|
||||
bool fullscreen = false;
|
||||
if (options.Get(switches::kFullscreen, & fullscreen) && fullscreen) {
|
||||
state_atom_list.push_back(GetAtom("_NET_WM_STATE_FULLSCREEN"));
|
||||
}
|
||||
|
||||
ui::SetAtomArrayProperty(GetAcceleratedWidget(), "_NET_WM_STATE", "ATOM",
|
||||
state_atom_list);
|
||||
|
||||
// Set the _NET_WM_WINDOW_TYPE.
|
||||
std::string window_type;
|
||||
if (options.Get(switches::kType, &window_type))
|
||||
@@ -238,24 +272,24 @@ NativeWindowViews::NativeWindowViews(content::WebContents* web_contents,
|
||||
set_background(views::Background::CreateStandardPanelBackground());
|
||||
AddChildView(web_view_);
|
||||
|
||||
if (has_frame_ &&
|
||||
if (has_frame() &&
|
||||
options.Get(switches::kUseContentSize, &use_content_size_) &&
|
||||
use_content_size_)
|
||||
bounds = ContentBoundsToWindowBounds(bounds);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
if (!has_frame_) {
|
||||
if (!has_frame()) {
|
||||
// Set Window style so that we get a minimize and maximize animation when
|
||||
// frameless.
|
||||
DWORD frame_style = WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX |
|
||||
WS_CAPTION;
|
||||
// We should not show a frame for transparent window.
|
||||
if (transparent_)
|
||||
if (transparent())
|
||||
frame_style &= ~(WS_THICKFRAME | WS_CAPTION);
|
||||
::SetWindowLong(GetAcceleratedWidget(), GWL_STYLE, frame_style);
|
||||
}
|
||||
|
||||
if (transparent_) {
|
||||
if (transparent()) {
|
||||
// Transparent window on Windows has to have WS_EX_COMPOSITED style.
|
||||
LONG ex_style = ::GetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE);
|
||||
ex_style |= WS_EX_COMPOSITED;
|
||||
@@ -265,14 +299,14 @@ NativeWindowViews::NativeWindowViews(content::WebContents* web_contents,
|
||||
|
||||
// TODO(zcbenz): This was used to force using native frame on Windows 2003, we
|
||||
// should check whether setting it in InitParams can work.
|
||||
if (has_frame_) {
|
||||
if (has_frame()) {
|
||||
window_->set_frame_type(views::Widget::FrameType::FRAME_TYPE_FORCE_NATIVE);
|
||||
window_->FrameTypeChanged();
|
||||
}
|
||||
|
||||
// The given window is most likely not rectangular since it uses
|
||||
// transparency and has no standard frame, don't show a shadow for it.
|
||||
if (transparent_ && !has_frame_)
|
||||
if (transparent() && !has_frame())
|
||||
wm::SetShadowType(GetNativeWindow(), wm::SHADOW_TYPE_NONE);
|
||||
|
||||
window_->UpdateWindowIcon();
|
||||
@@ -352,17 +386,19 @@ bool NativeWindowViews::IsMinimized() {
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetFullScreen(bool fullscreen) {
|
||||
#if defined(OS_WIN)
|
||||
// There is no native fullscreen state on Windows.
|
||||
window_->SetFullscreen(fullscreen);
|
||||
if (fullscreen)
|
||||
NotifyWindowEnterFullScreen();
|
||||
else
|
||||
NotifyWindowLeaveFullScreen();
|
||||
#else
|
||||
if (IsVisible())
|
||||
window_->SetFullscreen(fullscreen);
|
||||
else
|
||||
window_->native_widget_private()->ShowWithWindowState(
|
||||
ui::SHOW_STATE_FULLSCREEN);
|
||||
#if defined(OS_WIN)
|
||||
// There is no native fullscreen state on Windows.
|
||||
if (fullscreen)
|
||||
NotifyWindowEnterFullScreen();
|
||||
else
|
||||
NotifyWindowLeaveFullScreen();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -393,7 +429,7 @@ gfx::Rect NativeWindowViews::GetBounds() {
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetContentSize(const gfx::Size& size) {
|
||||
if (!has_frame_) {
|
||||
if (!has_frame()) {
|
||||
NativeWindow::SetSize(size);
|
||||
return;
|
||||
}
|
||||
@@ -404,7 +440,7 @@ void NativeWindowViews::SetContentSize(const gfx::Size& size) {
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowViews::GetContentSize() {
|
||||
if (!has_frame_)
|
||||
if (!has_frame())
|
||||
return GetSize();
|
||||
|
||||
gfx::Size content_size =
|
||||
@@ -416,14 +452,6 @@ gfx::Size NativeWindowViews::GetContentSize() {
|
||||
|
||||
void NativeWindowViews::SetMinimumSize(const gfx::Size& size) {
|
||||
minimum_size_ = size;
|
||||
|
||||
#if defined(USE_X11)
|
||||
XSizeHints size_hints;
|
||||
size_hints.flags = PMinSize;
|
||||
size_hints.min_width = size.width();
|
||||
size_hints.min_height = size.height();
|
||||
XSetWMNormalHints(gfx::GetXDisplay(), GetAcceleratedWidget(), &size_hints);
|
||||
#endif
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowViews::GetMinimumSize() {
|
||||
@@ -432,14 +460,6 @@ gfx::Size NativeWindowViews::GetMinimumSize() {
|
||||
|
||||
void NativeWindowViews::SetMaximumSize(const gfx::Size& size) {
|
||||
maximum_size_ = size;
|
||||
|
||||
#if defined(USE_X11)
|
||||
XSizeHints size_hints;
|
||||
size_hints.flags = PMaxSize;
|
||||
size_hints.max_width = size.width();
|
||||
size_hints.max_height = size.height();
|
||||
XSetWMNormalHints(gfx::GetXDisplay(), GetAcceleratedWidget(), &size_hints);
|
||||
#endif
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowViews::GetMaximumSize() {
|
||||
@@ -541,6 +561,19 @@ bool NativeWindowViews::IsKiosk() {
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetMenu(ui::MenuModel* menu_model) {
|
||||
if (menu_model == nullptr) {
|
||||
// Remove accelerators
|
||||
accelerator_table_.clear();
|
||||
GetFocusManager()->UnregisterAccelerators(this);
|
||||
// and menu bar.
|
||||
#if defined(USE_X11)
|
||||
global_menu_bar_.reset();
|
||||
#endif
|
||||
SetMenuBarVisibility(false);
|
||||
menu_bar_.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
RegisterAccelerators(menu_model);
|
||||
|
||||
#if defined(USE_X11)
|
||||
@@ -555,7 +588,7 @@ void NativeWindowViews::SetMenu(ui::MenuModel* menu_model) {
|
||||
#endif
|
||||
|
||||
// Do not show menu bar in frameless window.
|
||||
if (!has_frame_)
|
||||
if (!has_frame())
|
||||
return;
|
||||
|
||||
if (!menu_bar_) {
|
||||
@@ -580,24 +613,7 @@ gfx::NativeWindow NativeWindowViews::GetNativeWindow() {
|
||||
|
||||
void NativeWindowViews::SetProgressBar(double progress) {
|
||||
#if defined(OS_WIN)
|
||||
if (base::win::GetVersion() < base::win::VERSION_WIN7)
|
||||
return;
|
||||
base::win::ScopedComPtr<ITaskbarList3> taskbar;
|
||||
if (FAILED(taskbar.CreateInstance(CLSID_TaskbarList, NULL,
|
||||
CLSCTX_INPROC_SERVER) ||
|
||||
FAILED(taskbar->HrInit()))) {
|
||||
return;
|
||||
}
|
||||
HWND frame = views::HWNDForNativeWindow(GetNativeWindow());
|
||||
if (progress > 1.0) {
|
||||
taskbar->SetProgressState(frame, TBPF_INDETERMINATE);
|
||||
} else if (progress < 0) {
|
||||
taskbar->SetProgressState(frame, TBPF_NOPROGRESS);
|
||||
} else if (progress >= 0) {
|
||||
taskbar->SetProgressValue(frame,
|
||||
static_cast<int>(progress * 100),
|
||||
100);
|
||||
}
|
||||
taskbar_host_.SetProgressBar(GetAcceleratedWidget(), progress);
|
||||
#elif defined(USE_X11)
|
||||
if (unity::IsRunning()) {
|
||||
unity::SetProgressFraction(progress);
|
||||
@@ -608,22 +624,7 @@ void NativeWindowViews::SetProgressBar(double progress) {
|
||||
void NativeWindowViews::SetOverlayIcon(const gfx::Image& overlay,
|
||||
const std::string& description) {
|
||||
#if defined(OS_WIN)
|
||||
if (base::win::GetVersion() < base::win::VERSION_WIN7)
|
||||
return;
|
||||
|
||||
base::win::ScopedComPtr<ITaskbarList3> taskbar;
|
||||
if (FAILED(taskbar.CreateInstance(CLSID_TaskbarList, NULL,
|
||||
CLSCTX_INPROC_SERVER) ||
|
||||
FAILED(taskbar->HrInit()))) {
|
||||
return;
|
||||
}
|
||||
|
||||
HWND frame = views::HWNDForNativeWindow(GetNativeWindow());
|
||||
|
||||
std::wstring wstr = std::wstring(description.begin(), description.end());
|
||||
taskbar->SetOverlayIcon(frame,
|
||||
IconUtil::CreateHICONFromSkBitmap(overlay.AsBitmap()),
|
||||
wstr.c_str());
|
||||
taskbar_host_.SetOverlayIcon(GetAcceleratedWidget(), overlay, description);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -680,29 +681,6 @@ gfx::AcceleratedWidget NativeWindowViews::GetAcceleratedWidget() {
|
||||
return GetNativeWindow()->GetHost()->GetAcceleratedWidget();
|
||||
}
|
||||
|
||||
void NativeWindowViews::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);
|
||||
}
|
||||
|
||||
void NativeWindowViews::OnWidgetActivationChanged(
|
||||
views::Widget* widget, bool active) {
|
||||
if (widget != window_.get())
|
||||
@@ -713,8 +691,9 @@ void NativeWindowViews::OnWidgetActivationChanged(
|
||||
else
|
||||
NotifyWindowBlur();
|
||||
|
||||
if (active && GetWebContents() && !IsDevToolsOpened())
|
||||
GetWebContents()->Focus();
|
||||
if (active && inspectable_web_contents() &&
|
||||
!inspectable_web_contents()->IsDevToolsViewShowing())
|
||||
web_contents()->Focus();
|
||||
|
||||
// Hide menu bar when window is blured.
|
||||
if (!active && menu_bar_autohide_ && menu_bar_visible_)
|
||||
@@ -761,7 +740,7 @@ bool NativeWindowViews::ShouldHandleSystemCommands() const {
|
||||
}
|
||||
|
||||
gfx::ImageSkia NativeWindowViews::GetWindowAppIcon() {
|
||||
return icon_;
|
||||
return icon();
|
||||
}
|
||||
|
||||
gfx::ImageSkia NativeWindowViews::GetWindowIcon() {
|
||||
@@ -784,12 +763,12 @@ bool NativeWindowViews::ShouldDescendIntoChildForEventHandling(
|
||||
gfx::NativeView child,
|
||||
const gfx::Point& location) {
|
||||
// App window should claim mouse events that fall within the draggable region.
|
||||
if (draggable_region_ &&
|
||||
draggable_region_->contains(location.x(), location.y()))
|
||||
if (draggable_region() &&
|
||||
draggable_region()->contains(location.x(), location.y()))
|
||||
return false;
|
||||
|
||||
// And the events on border for dragging resizable frameless window.
|
||||
if (!has_frame_ && CanResize()) {
|
||||
if (!has_frame() && CanResize()) {
|
||||
FramelessView* frame = static_cast<FramelessView*>(
|
||||
window_->non_client_view()->frame_view());
|
||||
return frame->ResizingBorderHitTest(location) == HTNOWHERE;
|
||||
@@ -809,8 +788,8 @@ views::NonClientFrameView* NativeWindowViews::CreateNonClientFrameView(
|
||||
frame_view->Init(this, widget);
|
||||
return frame_view;
|
||||
#else
|
||||
if (has_frame_) {
|
||||
return new views::NativeFrameView(widget);
|
||||
if (has_frame()) {
|
||||
return new NativeFrameView(this, widget);
|
||||
} else {
|
||||
FramelessView* frame_view = new FramelessView;
|
||||
frame_view->Init(this, widget);
|
||||
@@ -839,6 +818,9 @@ bool NativeWindowViews::ExecuteWindowsCommand(int command_id) {
|
||||
is_minimized_ = false;
|
||||
} else if ((command_id & sc_mask) == SC_MAXIMIZE) {
|
||||
NotifyWindowMaximize();
|
||||
} else {
|
||||
std::string command = AppCommandToString(command_id);
|
||||
NotifyWindowExecuteWindowsCommand(command);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -856,12 +838,16 @@ void NativeWindowViews::GetDevToolsWindowWMClass(
|
||||
}
|
||||
#endif
|
||||
|
||||
void NativeWindowViews::ActivateContents(content::WebContents* contents) {
|
||||
NativeWindow::ActivateContents(contents);
|
||||
// Hide menu bar when web view is clicked.
|
||||
if (menu_bar_autohide_ && menu_bar_visible_)
|
||||
SetMenuBarVisibility(false);
|
||||
#if defined(OS_WIN)
|
||||
bool NativeWindowViews::PreHandleMSG(
|
||||
UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) {
|
||||
// Handle thumbar button click message.
|
||||
if (message == WM_COMMAND && HIWORD(w_param) == THBN_CLICKED)
|
||||
return taskbar_host_.HandleThumbarButtonEvent(LOWORD(w_param));
|
||||
else
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
void NativeWindowViews::HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
@@ -931,6 +917,7 @@ void NativeWindowViews::RegisterAccelerators(ui::MenuModel* menu_model) {
|
||||
|
||||
gfx::Rect NativeWindowViews::ContentBoundsToWindowBounds(
|
||||
const gfx::Rect& bounds) {
|
||||
gfx::Point origin = bounds.origin();
|
||||
#if defined(OS_WIN)
|
||||
gfx::Rect dpi_bounds = gfx::win::DIPToScreenRect(bounds);
|
||||
gfx::Rect window_bounds = gfx::win::ScreenToDIPRect(
|
||||
@@ -939,6 +926,9 @@ gfx::Rect NativeWindowViews::ContentBoundsToWindowBounds(
|
||||
gfx::Rect window_bounds =
|
||||
window_->non_client_view()->GetWindowBoundsForClientBounds(bounds);
|
||||
#endif
|
||||
// The window's position would also be changed, but we only want to change
|
||||
// the size.
|
||||
window_bounds.set_origin(origin);
|
||||
|
||||
if (menu_bar_ && menu_bar_visible_)
|
||||
window_bounds.set_height(window_bounds.height() + kMenuBarHeight);
|
||||
@@ -955,9 +945,10 @@ ui::WindowShowState NativeWindowViews::GetRestoredState() {
|
||||
}
|
||||
|
||||
// static
|
||||
NativeWindow* NativeWindow::Create(content::WebContents* web_contents,
|
||||
const mate::Dictionary& options) {
|
||||
return new NativeWindowViews(web_contents, options);
|
||||
NativeWindow* NativeWindow::Create(
|
||||
brightray::InspectableWebContents* inspectable_web_contents,
|
||||
const mate::Dictionary& options) {
|
||||
return new NativeWindowViews(inspectable_web_contents, options);
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -14,6 +14,11 @@
|
||||
#include "ui/views/widget/widget_delegate.h"
|
||||
#include "ui/views/widget/widget_observer.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "atom/browser/ui/win/message_handler_delegate.h"
|
||||
#include "atom/browser/ui/win/taskbar_host.h"
|
||||
#endif
|
||||
|
||||
namespace views {
|
||||
class UnhandledKeyboardEventHandler;
|
||||
}
|
||||
@@ -24,13 +29,20 @@ class GlobalMenuBarX11;
|
||||
class MenuBar;
|
||||
class WindowStateWatcher;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
class AtomDesktopWindowTreeHostWin;
|
||||
#endif
|
||||
|
||||
class NativeWindowViews : public NativeWindow,
|
||||
#if defined(OS_WIN)
|
||||
public MessageHandlerDelegate,
|
||||
#endif
|
||||
public views::WidgetDelegateView,
|
||||
public views::WidgetObserver {
|
||||
public:
|
||||
explicit NativeWindowViews(content::WebContents* web_contents,
|
||||
const mate::Dictionary& options);
|
||||
virtual ~NativeWindowViews();
|
||||
NativeWindowViews(brightray::InspectableWebContents* inspectable_web_contents,
|
||||
const mate::Dictionary& options);
|
||||
~NativeWindowViews() override;
|
||||
|
||||
// NativeWindow:
|
||||
void Close() override;
|
||||
@@ -82,14 +94,13 @@ class NativeWindowViews : public NativeWindow,
|
||||
|
||||
gfx::AcceleratedWidget GetAcceleratedWidget();
|
||||
|
||||
SkRegion* draggable_region() const { return draggable_region_.get(); }
|
||||
views::Widget* widget() const { return window_.get(); }
|
||||
|
||||
private:
|
||||
// NativeWindow:
|
||||
void UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions) override;
|
||||
#if defined(OS_WIN)
|
||||
TaskbarHost& taskbar_host() { return taskbar_host_; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
// views::WidgetObserver:
|
||||
void OnWidgetActivationChanged(
|
||||
views::Widget* widget, bool active) override;
|
||||
@@ -120,15 +131,20 @@ class NativeWindowViews : public NativeWindow,
|
||||
bool ExecuteWindowsCommand(int command_id) override;
|
||||
#endif
|
||||
|
||||
// brightray::InspectableWebContentsDelegate:
|
||||
// brightray::InspectableWebContentsViewDelegate:
|
||||
gfx::ImageSkia GetDevToolsWindowIcon() override;
|
||||
#if defined(USE_X11)
|
||||
void GetDevToolsWindowWMClass(
|
||||
std::string* name, std::string* class_name) override;
|
||||
#endif
|
||||
|
||||
// content::WebContentsDelegate:
|
||||
void ActivateContents(content::WebContents* contents) override;
|
||||
#if defined(OS_WIN)
|
||||
// MessageHandlerDelegate:
|
||||
bool PreHandleMSG(
|
||||
UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) override;
|
||||
#endif
|
||||
|
||||
// NativeWindow:
|
||||
void HandleKeyboardEvent(
|
||||
content::WebContents*,
|
||||
const content::NativeWebKeyboardEvent& event) override;
|
||||
@@ -160,9 +176,13 @@ class NativeWindowViews : public NativeWindow,
|
||||
// Handles window state events.
|
||||
scoped_ptr<WindowStateWatcher> window_state_watcher_;
|
||||
#elif defined(OS_WIN)
|
||||
// Weak ref.
|
||||
AtomDesktopWindowTreeHostWin* atom_desktop_window_tree_host_win_;
|
||||
// Records window was whether restored from minimized state or maximized
|
||||
// state.
|
||||
bool is_minimized_;
|
||||
// In charge of running taskbar related APIs.
|
||||
TaskbarHost taskbar_host_;
|
||||
#endif
|
||||
|
||||
// Handles unhandled keyboard messages coming back from the renderer process.
|
||||
@@ -178,8 +198,6 @@ class NativeWindowViews : public NativeWindow,
|
||||
gfx::Size maximum_size_;
|
||||
gfx::Size widget_size_;
|
||||
|
||||
scoped_ptr<SkRegion> draggable_region_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NativeWindowViews);
|
||||
};
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "base/threading/sequenced_worker_pool.h"
|
||||
#include "atom/browser/net/url_request_buffer_job.h"
|
||||
#include "atom/browser/net/url_request_fetch_job.h"
|
||||
#include "atom/browser/net/url_request_string_job.h"
|
||||
#include "atom/browser/net/asar/url_request_asar_job.h"
|
||||
#include "atom/common/asar/asar_util.h"
|
||||
@@ -26,11 +27,7 @@ AdapterRequestJob::AdapterRequestJob(ProtocolHandler* protocol_handler,
|
||||
|
||||
void AdapterRequestJob::Start() {
|
||||
DCHECK(!real_job_.get());
|
||||
content::BrowserThread::PostTask(
|
||||
content::BrowserThread::UI,
|
||||
FROM_HERE,
|
||||
base::Bind(&AdapterRequestJob::GetJobTypeInUI,
|
||||
weak_factory_.GetWeakPtr()));
|
||||
GetJobType();
|
||||
}
|
||||
|
||||
void AdapterRequestJob::Kill() {
|
||||
@@ -42,7 +39,11 @@ bool AdapterRequestJob::ReadRawData(net::IOBuffer* buf,
|
||||
int buf_size,
|
||||
int *bytes_read) {
|
||||
DCHECK(!real_job_.get());
|
||||
return real_job_->ReadRawData(buf, buf_size, bytes_read);
|
||||
// Read post-filtered data if available.
|
||||
if (real_job_->HasFilter())
|
||||
return real_job_->Read(buf, buf_size, bytes_read);
|
||||
else
|
||||
return real_job_->ReadRawData(buf, buf_size, bytes_read);
|
||||
}
|
||||
|
||||
bool AdapterRequestJob::IsRedirectResponse(GURL* location,
|
||||
@@ -66,6 +67,19 @@ bool AdapterRequestJob::GetCharset(std::string* charset) {
|
||||
return real_job_->GetCharset(charset);
|
||||
}
|
||||
|
||||
void AdapterRequestJob::GetResponseInfo(net::HttpResponseInfo* info) {
|
||||
real_job_->GetResponseInfo(info);
|
||||
}
|
||||
|
||||
int AdapterRequestJob::GetResponseCode() const {
|
||||
return real_job_->GetResponseCode();
|
||||
}
|
||||
|
||||
void AdapterRequestJob::GetLoadTimingInfo(
|
||||
net::LoadTimingInfo* load_timing_info) const {
|
||||
real_job_->GetLoadTimingInfo(load_timing_info);
|
||||
}
|
||||
|
||||
base::WeakPtr<AdapterRequestJob> AdapterRequestJob::GetWeakPtr() {
|
||||
return weak_factory_.GetWeakPtr();
|
||||
}
|
||||
@@ -104,13 +118,31 @@ void AdapterRequestJob::CreateFileJobAndStart(const base::FilePath& path) {
|
||||
real_job_->Start();
|
||||
}
|
||||
|
||||
void AdapterRequestJob::CreateHttpJobAndStart(
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter,
|
||||
const GURL& url,
|
||||
const std::string& method,
|
||||
const std::string& referrer) {
|
||||
if (!url.is_valid()) {
|
||||
CreateErrorJobAndStart(net::ERR_INVALID_URL);
|
||||
return;
|
||||
}
|
||||
|
||||
real_job_ = new URLRequestFetchJob(request_context_getter, request(),
|
||||
network_delegate(), url, method, referrer);
|
||||
real_job_->Start();
|
||||
}
|
||||
|
||||
void AdapterRequestJob::CreateJobFromProtocolHandlerAndStart() {
|
||||
real_job_ = protocol_handler_->MaybeCreateJob(request(),
|
||||
network_delegate());
|
||||
if (!real_job_.get())
|
||||
if (!real_job_.get()) {
|
||||
CreateErrorJobAndStart(net::ERR_NOT_IMPLEMENTED);
|
||||
else
|
||||
} else {
|
||||
// Copy headers from original request.
|
||||
real_job_->SetExtraRequestHeaders(request()->extra_request_headers());
|
||||
real_job_->Start();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
#include "base/memory/ref_counted_memory.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "net/url_request/url_request_context.h"
|
||||
#include "net/url_request/url_request_context_getter.h"
|
||||
#include "net/url_request/url_request_job.h"
|
||||
#include "net/url_request/url_request_job_factory.h"
|
||||
#include "v8/include/v8.h"
|
||||
@@ -19,6 +21,8 @@ class FilePath;
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomBrowserContext;
|
||||
|
||||
// Ask JS which type of job it wants, and then delegate corresponding methods.
|
||||
class AdapterRequestJob : public net::URLRequestJob {
|
||||
public:
|
||||
@@ -40,13 +44,17 @@ class AdapterRequestJob : public net::URLRequestJob {
|
||||
net::Filter* SetupFilter() const override;
|
||||
bool GetMimeType(std::string* mime_type) const override;
|
||||
bool GetCharset(std::string* charset) override;
|
||||
void GetResponseInfo(net::HttpResponseInfo* info) override;
|
||||
int GetResponseCode() const override;
|
||||
void GetLoadTimingInfo(
|
||||
net::LoadTimingInfo* load_timing_info) const 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;
|
||||
virtual void GetJobType() = 0;
|
||||
|
||||
void CreateErrorJobAndStart(int error_code);
|
||||
void CreateStringJobAndStart(const std::string& mime_type,
|
||||
@@ -56,6 +64,11 @@ class AdapterRequestJob : public net::URLRequestJob {
|
||||
const std::string& charset,
|
||||
scoped_refptr<base::RefCountedBytes> data);
|
||||
void CreateFileJobAndStart(const base::FilePath& path);
|
||||
void CreateHttpJobAndStart(
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter,
|
||||
const GURL& url,
|
||||
const std::string& method,
|
||||
const std::string& referrer);
|
||||
void CreateJobFromProtocolHandlerAndStart();
|
||||
|
||||
private:
|
||||
|
||||
@@ -6,9 +6,12 @@
|
||||
#include "atom/browser/net/atom_url_request_job_factory.h"
|
||||
|
||||
#include "base/stl_util.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "net/base/load_flags.h"
|
||||
#include "net/url_request/url_request.h"
|
||||
|
||||
using content::BrowserThread;
|
||||
|
||||
namespace atom {
|
||||
|
||||
typedef net::URLRequestJobFactory::ProtocolHandler ProtocolHandler;
|
||||
@@ -22,9 +25,7 @@ AtomURLRequestJobFactory::~AtomURLRequestJobFactory() {
|
||||
bool AtomURLRequestJobFactory::SetProtocolHandler(
|
||||
const std::string& scheme,
|
||||
ProtocolHandler* protocol_handler) {
|
||||
DCHECK(CalledOnValidThread());
|
||||
|
||||
base::AutoLock locked(lock_);
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
|
||||
if (!protocol_handler) {
|
||||
ProtocolHandlerMap::iterator it = protocol_handler_map_.find(scheme);
|
||||
@@ -45,10 +46,9 @@ bool AtomURLRequestJobFactory::SetProtocolHandler(
|
||||
ProtocolHandler* AtomURLRequestJobFactory::ReplaceProtocol(
|
||||
const std::string& scheme,
|
||||
ProtocolHandler* protocol_handler) {
|
||||
DCHECK(CalledOnValidThread());
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
DCHECK(protocol_handler);
|
||||
|
||||
base::AutoLock locked(lock_);
|
||||
if (!ContainsKey(protocol_handler_map_, scheme))
|
||||
return nullptr;
|
||||
ProtocolHandler* original_protocol_handler = protocol_handler_map_[scheme];
|
||||
@@ -58,9 +58,8 @@ ProtocolHandler* AtomURLRequestJobFactory::ReplaceProtocol(
|
||||
|
||||
ProtocolHandler* AtomURLRequestJobFactory::GetProtocolHandler(
|
||||
const std::string& scheme) const {
|
||||
DCHECK(CalledOnValidThread());
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
|
||||
base::AutoLock locked(lock_);
|
||||
ProtocolHandlerMap::const_iterator it = protocol_handler_map_.find(scheme);
|
||||
if (it == protocol_handler_map_.end())
|
||||
return nullptr;
|
||||
@@ -69,7 +68,6 @@ ProtocolHandler* AtomURLRequestJobFactory::GetProtocolHandler(
|
||||
|
||||
bool AtomURLRequestJobFactory::HasProtocolHandler(
|
||||
const std::string& scheme) const {
|
||||
base::AutoLock locked(lock_);
|
||||
return ContainsKey(protocol_handler_map_, scheme);
|
||||
}
|
||||
|
||||
@@ -77,9 +75,8 @@ net::URLRequestJob* AtomURLRequestJobFactory::MaybeCreateJobWithProtocolHandler(
|
||||
const std::string& scheme,
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate) const {
|
||||
DCHECK(CalledOnValidThread());
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
|
||||
base::AutoLock locked(lock_);
|
||||
ProtocolHandlerMap::const_iterator it = protocol_handler_map_.find(scheme);
|
||||
if (it == protocol_handler_map_.end())
|
||||
return nullptr;
|
||||
@@ -101,7 +98,8 @@ net::URLRequestJob* AtomURLRequestJobFactory::MaybeInterceptResponse(
|
||||
|
||||
bool AtomURLRequestJobFactory::IsHandledProtocol(
|
||||
const std::string& scheme) const {
|
||||
DCHECK(CalledOnValidThread());
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
|
||||
return HasProtocolHandler(scheme) ||
|
||||
net::URLRequest::IsHandledProtocol(scheme);
|
||||
}
|
||||
|
||||
@@ -56,12 +56,10 @@ class AtomURLRequestJobFactory : public net::URLRequestJobFactory {
|
||||
bool IsSafeRedirectTarget(const GURL& location) const override;
|
||||
|
||||
private:
|
||||
typedef std::map<std::string, ProtocolHandler*> ProtocolHandlerMap;
|
||||
using ProtocolHandlerMap = std::map<std::string, ProtocolHandler*>;
|
||||
|
||||
ProtocolHandlerMap protocol_handler_map_;
|
||||
|
||||
mutable base::Lock lock_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomURLRequestJobFactory);
|
||||
};
|
||||
|
||||
|
||||
198
atom/browser/net/url_request_fetch_job.cc
Normal file
198
atom/browser/net/url_request_fetch_job.cc
Normal file
@@ -0,0 +1,198 @@
|
||||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/net/url_request_fetch_job.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/thread_task_runner_handle.h"
|
||||
#include "net/base/io_buffer.h"
|
||||
#include "net/base/net_errors.h"
|
||||
#include "net/http/http_response_headers.h"
|
||||
#include "net/url_request/url_fetcher.h"
|
||||
#include "net/url_request/url_fetcher_response_writer.h"
|
||||
#include "net/url_request/url_request_context_builder.h"
|
||||
#include "net/url_request/url_request_status.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
// Convert string to RequestType.
|
||||
net::URLFetcher::RequestType GetRequestType(const std::string& raw) {
|
||||
std::string method = StringToUpperASCII(raw);
|
||||
if (method.empty() || method == "GET")
|
||||
return net::URLFetcher::GET;
|
||||
else if (method == "POST")
|
||||
return net::URLFetcher::POST;
|
||||
else if (method == "HEAD")
|
||||
return net::URLFetcher::HEAD;
|
||||
else if (method == "DELETE")
|
||||
return net::URLFetcher::DELETE_REQUEST;
|
||||
else if (method == "PUT")
|
||||
return net::URLFetcher::PUT;
|
||||
else if (method == "PATCH")
|
||||
return net::URLFetcher::PATCH;
|
||||
else // Use "GET" as fallback.
|
||||
return net::URLFetcher::GET;
|
||||
}
|
||||
|
||||
// Pipe the response writer back to URLRequestFetchJob.
|
||||
class ResponsePiper : public net::URLFetcherResponseWriter {
|
||||
public:
|
||||
explicit ResponsePiper(URLRequestFetchJob* job)
|
||||
: first_write_(true), job_(job) {}
|
||||
|
||||
// net::URLFetcherResponseWriter:
|
||||
int Initialize(const net::CompletionCallback& callback) override {
|
||||
return net::OK;
|
||||
}
|
||||
int Write(net::IOBuffer* buffer,
|
||||
int num_bytes,
|
||||
const net::CompletionCallback& callback) override {
|
||||
if (first_write_) {
|
||||
// The URLFetcherResponseWriter doesn't have an event when headers have
|
||||
// been read, so we have to emulate by hooking to first write event.
|
||||
job_->HeadersCompleted();
|
||||
first_write_ = false;
|
||||
}
|
||||
return job_->DataAvailable(buffer, num_bytes);
|
||||
}
|
||||
int Finish(const net::CompletionCallback& callback) override {
|
||||
return net::OK;
|
||||
}
|
||||
|
||||
private:
|
||||
bool first_write_;
|
||||
URLRequestFetchJob* job_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ResponsePiper);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
URLRequestFetchJob::URLRequestFetchJob(
|
||||
scoped_refptr<net::URLRequestContextGetter> request_context_getter,
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate,
|
||||
const GURL& url,
|
||||
const std::string& method,
|
||||
const std::string& referrer)
|
||||
: net::URLRequestJob(request, network_delegate),
|
||||
pending_buffer_size_(0) {
|
||||
// Use |request|'s method if |method| is not specified.
|
||||
net::URLFetcher::RequestType request_type;
|
||||
if (method.empty())
|
||||
request_type = GetRequestType(request->method());
|
||||
else
|
||||
request_type = GetRequestType(method);
|
||||
|
||||
fetcher_.reset(net::URLFetcher::Create(url, request_type, this));
|
||||
// Use request context if provided else create one.
|
||||
if (request_context_getter)
|
||||
fetcher_->SetRequestContext(request_context_getter.get());
|
||||
else
|
||||
fetcher_->SetRequestContext(GetRequestContext());
|
||||
|
||||
fetcher_->SaveResponseWithWriter(make_scoped_ptr(new ResponsePiper(this)));
|
||||
|
||||
// Use |request|'s referrer if |referrer| is not specified.
|
||||
if (referrer.empty()) {
|
||||
fetcher_->SetReferrer(request->referrer());
|
||||
} else {
|
||||
fetcher_->SetReferrer(referrer);
|
||||
}
|
||||
|
||||
// Use |request|'s headers.
|
||||
fetcher_->SetExtraRequestHeaders(request->extra_request_headers().ToString());
|
||||
}
|
||||
|
||||
net::URLRequestContextGetter* URLRequestFetchJob::GetRequestContext() {
|
||||
if (!url_request_context_getter_.get()) {
|
||||
auto task_runner = base::ThreadTaskRunnerHandle::Get();
|
||||
net::URLRequestContextBuilder builder;
|
||||
builder.set_proxy_service(net::ProxyService::CreateDirect());
|
||||
url_request_context_getter_ =
|
||||
new net::TrivialURLRequestContextGetter(builder.Build(), task_runner);
|
||||
}
|
||||
return url_request_context_getter_.get();
|
||||
}
|
||||
|
||||
void URLRequestFetchJob::HeadersCompleted() {
|
||||
response_info_.reset(new net::HttpResponseInfo);
|
||||
response_info_->headers = fetcher_->GetResponseHeaders();
|
||||
NotifyHeadersComplete();
|
||||
}
|
||||
|
||||
int URLRequestFetchJob::DataAvailable(net::IOBuffer* buffer, int num_bytes) {
|
||||
// Clear the IO_PENDING status.
|
||||
SetStatus(net::URLRequestStatus());
|
||||
// Do nothing if pending_buffer_ is empty, i.e. there's no ReadRawData()
|
||||
// operation waiting for IO completion.
|
||||
if (!pending_buffer_.get())
|
||||
return net::ERR_IO_PENDING;
|
||||
|
||||
// pending_buffer_ is set to the IOBuffer instance provided to ReadRawData()
|
||||
// by URLRequestJob.
|
||||
|
||||
int bytes_read = std::min(num_bytes, pending_buffer_size_);
|
||||
memcpy(pending_buffer_->data(), buffer->data(), bytes_read);
|
||||
|
||||
// Clear the buffers before notifying the read is complete, so that it is
|
||||
// safe for the observer to read.
|
||||
pending_buffer_ = nullptr;
|
||||
pending_buffer_size_ = 0;
|
||||
|
||||
NotifyReadComplete(bytes_read);
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
void URLRequestFetchJob::Start() {
|
||||
fetcher_->Start();
|
||||
}
|
||||
|
||||
void URLRequestFetchJob::Kill() {
|
||||
URLRequestJob::Kill();
|
||||
fetcher_.reset();
|
||||
}
|
||||
|
||||
bool URLRequestFetchJob::ReadRawData(net::IOBuffer* dest,
|
||||
int dest_size,
|
||||
int* bytes_read) {
|
||||
pending_buffer_ = dest;
|
||||
pending_buffer_size_ = dest_size;
|
||||
SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool URLRequestFetchJob::GetMimeType(std::string* mime_type) const {
|
||||
if (!response_info_)
|
||||
return false;
|
||||
|
||||
return response_info_->headers->GetMimeType(mime_type);
|
||||
}
|
||||
|
||||
void URLRequestFetchJob::GetResponseInfo(net::HttpResponseInfo* info) {
|
||||
if (response_info_)
|
||||
*info = *response_info_;
|
||||
}
|
||||
|
||||
int URLRequestFetchJob::GetResponseCode() const {
|
||||
if (!response_info_)
|
||||
return -1;
|
||||
|
||||
return response_info_->headers->response_code();
|
||||
}
|
||||
|
||||
void URLRequestFetchJob::OnURLFetchComplete(const net::URLFetcher* source) {
|
||||
pending_buffer_ = nullptr;
|
||||
pending_buffer_size_ = 0;
|
||||
NotifyDone(fetcher_->GetStatus());
|
||||
if (fetcher_->GetStatus().is_success())
|
||||
NotifyReadComplete(0);
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
57
atom/browser/net/url_request_fetch_job.h
Normal file
57
atom/browser/net/url_request_fetch_job.h
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_NET_URL_REQUEST_FETCH_JOB_H_
|
||||
#define ATOM_BROWSER_NET_URL_REQUEST_FETCH_JOB_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "net/url_request/url_request_context_getter.h"
|
||||
#include "net/url_request/url_fetcher_delegate.h"
|
||||
#include "net/url_request/url_request_job.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomBrowserContext;
|
||||
|
||||
class URLRequestFetchJob : public net::URLRequestJob,
|
||||
public net::URLFetcherDelegate {
|
||||
public:
|
||||
URLRequestFetchJob(scoped_refptr<net::URLRequestContextGetter> context_getter,
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate,
|
||||
const GURL& url,
|
||||
const std::string& method,
|
||||
const std::string& referrer);
|
||||
|
||||
net::URLRequestContextGetter* GetRequestContext();
|
||||
void HeadersCompleted();
|
||||
int DataAvailable(net::IOBuffer* buffer, int num_bytes);
|
||||
|
||||
// net::URLRequestJob:
|
||||
void Start() override;
|
||||
void Kill() override;
|
||||
bool ReadRawData(net::IOBuffer* buf,
|
||||
int buf_size,
|
||||
int* bytes_read) override;
|
||||
bool GetMimeType(std::string* mime_type) const override;
|
||||
void GetResponseInfo(net::HttpResponseInfo* info) override;
|
||||
int GetResponseCode() const override;
|
||||
|
||||
// net::URLFetcherDelegate:
|
||||
void OnURLFetchComplete(const net::URLFetcher* source) override;
|
||||
|
||||
private:
|
||||
scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
|
||||
scoped_ptr<net::URLFetcher> fetcher_;
|
||||
scoped_refptr<net::IOBuffer> pending_buffer_;
|
||||
int pending_buffer_size_;
|
||||
scoped_ptr<net::HttpResponseInfo> response_info_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(URLRequestFetchJob);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_NET_URL_REQUEST_FETCH_JOB_H_
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>atom.icns</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.27.0</string>
|
||||
<string>0.30.5</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.8.0</string>
|
||||
<key>NSMainNibFile</key>
|
||||
@@ -26,5 +26,7 @@
|
||||
<string>AtomApplication</string>
|
||||
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
||||
<true/>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
18
atom/browser/resources/win/atom.manifest
Normal file
18
atom/browser/resources/win/atom.manifest
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity type="Win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"></assemblyIdentity>
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<security>
|
||||
<requestedPrivileges>
|
||||
<requestedExecutionLevel level="asInvoker" />
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
|
||||
</assembly>
|
||||
@@ -1,6 +1,12 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "grit\\ui_unscaled_resources.h"
|
||||
#include "resource.h"
|
||||
#include <winresrc.h>
|
||||
#ifdef IDC_STATIC
|
||||
#undef IDC_STATIC
|
||||
#endif
|
||||
#define IDC_STATIC (-1)
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
@@ -50,8 +56,8 @@ END
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 0,27,0,0
|
||||
PRODUCTVERSION 0,27,0,0
|
||||
FILEVERSION 0,30,5,0
|
||||
PRODUCTVERSION 0,30,5,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -68,12 +74,12 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "GitHub, Inc."
|
||||
VALUE "FileDescription", "Electron"
|
||||
VALUE "FileVersion", "0.27.0"
|
||||
VALUE "FileVersion", "0.30.5"
|
||||
VALUE "InternalName", "electron.exe"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
|
||||
VALUE "OriginalFilename", "electron.exe"
|
||||
VALUE "ProductName", "Electron"
|
||||
VALUE "ProductVersion", "0.27.0"
|
||||
VALUE "ProductVersion", "0.30.5"
|
||||
VALUE "SquirrelAwareVersion", "1"
|
||||
END
|
||||
END
|
||||
@@ -106,3 +112,28 @@ END
|
||||
IDR_MAINFRAME ICON "atom.ico"
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Cursors
|
||||
//
|
||||
IDC_ALIAS CURSOR "ui\\resources\\cursors\\aliasb.cur"
|
||||
IDC_CELL CURSOR "ui\\resources\\cursors\\cell.cur"
|
||||
IDC_COLRESIZE CURSOR "ui\\resources\\cursors\\col_resize.cur"
|
||||
IDC_COPYCUR CURSOR "ui\\resources\\cursors\\copy.cur"
|
||||
IDC_CURSOR_NONE CURSOR "ui\\resources\\cursors\\none.cur"
|
||||
IDC_HAND_GRAB CURSOR "ui\\resources\\cursors\\hand_grab.cur"
|
||||
IDC_HAND_GRABBING CURSOR "ui\\resources\\cursors\\hand_grabbing.cur"
|
||||
IDC_PAN_EAST CURSOR "ui\\resources\\cursors\\pan_east.cur"
|
||||
IDC_PAN_MIDDLE CURSOR "ui\\resources\\cursors\\pan_middle.cur"
|
||||
IDC_PAN_NORTH CURSOR "ui\\resources\\cursors\\pan_north.cur"
|
||||
IDC_PAN_NORTH_EAST CURSOR "ui\\resources\\cursors\\pan_north_east.cur"
|
||||
IDC_PAN_NORTH_WEST CURSOR "ui\\resources\\cursors\\pan_north_west.cur"
|
||||
IDC_PAN_SOUTH CURSOR "ui\\resources\\cursors\\pan_south.cur"
|
||||
IDC_PAN_SOUTH_EAST CURSOR "ui\\resources\\cursors\\pan_south_east.cur"
|
||||
IDC_PAN_SOUTH_WEST CURSOR "ui\\resources\\cursors\\pan_south_west.cur"
|
||||
IDC_PAN_WEST CURSOR "ui\\resources\\cursors\\pan_west.cur"
|
||||
IDC_ROWRESIZE CURSOR "ui\\resources\\cursors\\row_resize.cur"
|
||||
IDC_VERTICALTEXT CURSOR "ui\\resources\\cursors\\vertical_text.cur"
|
||||
IDC_ZOOMIN CURSOR "ui\\resources\\cursors\\zoom_in.cur"
|
||||
IDC_ZOOMOUT CURSOR "ui\\resources\\cursors\\zoom_out.cur"
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -152,9 +152,9 @@ bool StringToAccelerator(const std::string& description,
|
||||
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_PRIOR;
|
||||
} else if (tokens[i] == "pagedown") {
|
||||
key = ui::VKEY_NEXT;
|
||||
} else if (tokens[i] == "esc" || tokens[i] == "escape") {
|
||||
key = ui::VKEY_ESCAPE;
|
||||
|
||||
22
atom/browser/ui/atom_menu_model.cc
Normal file
22
atom/browser/ui/atom_menu_model.cc
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/ui/atom_menu_model.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
AtomMenuModel::AtomMenuModel(Delegate* delegate)
|
||||
: ui::SimpleMenuModel(delegate),
|
||||
delegate_(delegate) {
|
||||
}
|
||||
|
||||
AtomMenuModel::~AtomMenuModel() {
|
||||
}
|
||||
|
||||
void AtomMenuModel::MenuClosed() {
|
||||
ui::SimpleMenuModel::MenuClosed();
|
||||
FOR_EACH_OBSERVER(Observer, observers_, MenuClosed());
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
47
atom/browser/ui/atom_menu_model.h
Normal file
47
atom/browser/ui/atom_menu_model.h
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_UI_ATOM_MENU_MODEL_H_
|
||||
#define ATOM_BROWSER_UI_ATOM_MENU_MODEL_H_
|
||||
|
||||
#include "base/observer_list.h"
|
||||
#include "ui/base/models/simple_menu_model.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomMenuModel : public ui::SimpleMenuModel {
|
||||
public:
|
||||
class Delegate : public ui::SimpleMenuModel::Delegate {
|
||||
public:
|
||||
virtual ~Delegate() {}
|
||||
};
|
||||
|
||||
class Observer {
|
||||
public:
|
||||
virtual ~Observer() {}
|
||||
|
||||
// Notifies the menu has been closed.
|
||||
virtual void MenuClosed() {}
|
||||
};
|
||||
|
||||
explicit AtomMenuModel(Delegate* delegate);
|
||||
virtual ~AtomMenuModel();
|
||||
|
||||
void AddObserver(Observer* obs) { observers_.AddObserver(obs); }
|
||||
void RemoveObserver(Observer* obs) { observers_.RemoveObserver(obs); }
|
||||
|
||||
// ui::SimpleMenuModel:
|
||||
void MenuClosed() override;
|
||||
|
||||
private:
|
||||
Delegate* delegate_; // weak ref.
|
||||
|
||||
ObserverList<Observer> observers_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomMenuModel);
|
||||
};
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_UI_ATOM_MENU_MODEL_H_
|
||||
@@ -5,61 +5,15 @@
|
||||
|
||||
#import "atom/browser/ui/cocoa/atom_menu_controller.h"
|
||||
|
||||
#include "atom/browser/ui/atom_menu_model.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/events/cocoa/cocoa_event_utils.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;
|
||||
@@ -166,8 +120,7 @@ int EventFlagsFromNSEvent(NSEvent* event) {
|
||||
[item setTarget:nil];
|
||||
[item setAction:nil];
|
||||
ui::MenuModel* submenuModel = model->GetSubmenuModelAt(index);
|
||||
NSMenu* submenu =
|
||||
[self menuFromModel:(ui::SimpleMenuModel*)submenuModel];
|
||||
NSMenu* submenu = [self menuFromModel:submenuModel];
|
||||
[submenu setTitle:[item title]];
|
||||
[item setSubmenu:submenu];
|
||||
|
||||
@@ -246,8 +199,9 @@ int EventFlagsFromNSEvent(NSEvent* event) {
|
||||
[[sender representedObject] pointerValue]);
|
||||
DCHECK(model);
|
||||
if (model) {
|
||||
int event_flags = EventFlagsFromNSEvent([NSApp currentEvent]);
|
||||
model->ActivatedAt(modelIndex, event_flags);
|
||||
NSEvent* event = [NSApp currentEvent];
|
||||
model->ActivatedAt(modelIndex,
|
||||
ui::EventFlagsFromModifiers([event modifierFlags]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,49 +4,18 @@
|
||||
|
||||
#include "atom/browser/ui/file_dialog.h"
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <gdk/gdkx.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
// This conflicts with mate::Converter,
|
||||
#undef True
|
||||
#undef False
|
||||
// and V8.
|
||||
#undef None
|
||||
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "chrome/browser/ui/libgtk2ui/gtk2_signal.h"
|
||||
#include "ui/aura/window.h"
|
||||
#include "ui/aura/window_tree_host.h"
|
||||
#include "chrome/browser/ui/libgtk2ui/gtk2_util.h"
|
||||
#include "ui/views/widget/desktop_aura/x11_desktop_handler.h"
|
||||
|
||||
namespace file_dialog {
|
||||
|
||||
namespace {
|
||||
|
||||
const char kAuraTransientParent[] = "aura-transient-parent";
|
||||
|
||||
void SetGtkTransientForAura(GtkWidget* dialog, aura::Window* parent) {
|
||||
if (!parent || !parent->GetHost())
|
||||
return;
|
||||
|
||||
gtk_widget_realize(dialog);
|
||||
GdkWindow* gdk_window = gtk_widget_get_window(dialog);
|
||||
|
||||
// TODO(erg): Check to make sure we're using X11 if wayland or some other
|
||||
// display server ever happens. Otherwise, this will crash.
|
||||
XSetTransientForHint(GDK_WINDOW_XDISPLAY(gdk_window),
|
||||
GDK_WINDOW_XID(gdk_window),
|
||||
parent->GetHost()->GetAcceleratedWidget());
|
||||
|
||||
// We also set the |parent| as a property of |dialog|, so that we can unlink
|
||||
// the two later.
|
||||
g_object_set_data(G_OBJECT(dialog), kAuraTransientParent, parent);
|
||||
}
|
||||
|
||||
// Makes sure that .jpg also shows .JPG.
|
||||
gboolean FileFilterCaseInsensitive(const GtkFileFilterInfo* file_info,
|
||||
std::string* file_extension) {
|
||||
@@ -65,7 +34,7 @@ class FileChooserDialog {
|
||||
const std::string& title,
|
||||
const base::FilePath& default_path,
|
||||
const Filters& filters)
|
||||
: dialog_scope_(new atom::NativeWindow::DialogScope(parent_window)) {
|
||||
: dialog_scope_(parent_window) {
|
||||
const char* confirm_text = GTK_STOCK_OK;
|
||||
if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
|
||||
confirm_text = GTK_STOCK_SAVE;
|
||||
@@ -81,7 +50,7 @@ class FileChooserDialog {
|
||||
NULL);
|
||||
if (parent_window) {
|
||||
gfx::NativeWindow window = parent_window->GetNativeWindow();
|
||||
SetGtkTransientForAura(dialog_, window);
|
||||
libgtk2ui::SetGtkTransientForAura(dialog_, window);
|
||||
}
|
||||
|
||||
if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
|
||||
@@ -93,12 +62,15 @@ class FileChooserDialog {
|
||||
gtk_window_set_modal(GTK_WINDOW(dialog_), TRUE);
|
||||
|
||||
if (!default_path.empty()) {
|
||||
if (base::DirectoryExists(default_path))
|
||||
if (base::DirectoryExists(default_path)) {
|
||||
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog_),
|
||||
default_path.value().c_str());
|
||||
else
|
||||
gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog_),
|
||||
default_path.value().c_str());
|
||||
} else {
|
||||
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog_),
|
||||
default_path.DirName().value().c_str());
|
||||
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog_),
|
||||
default_path.BaseName().value().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (!filters.empty())
|
||||
@@ -159,13 +131,13 @@ class FileChooserDialog {
|
||||
private:
|
||||
void AddFilters(const Filters& filters);
|
||||
|
||||
atom::NativeWindow::DialogScope dialog_scope_;
|
||||
|
||||
GtkWidget* dialog_;
|
||||
|
||||
SaveDialogCallback save_callback_;
|
||||
OpenDialogCallback open_callback_;
|
||||
|
||||
scoped_ptr<atom::NativeWindow::DialogScope> dialog_scope_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(FileChooserDialog);
|
||||
};
|
||||
|
||||
|
||||
@@ -18,25 +18,11 @@ namespace file_dialog {
|
||||
|
||||
namespace {
|
||||
|
||||
CFStringRef CreateUTIFromExtension(const std::string& ext) {
|
||||
base::ScopedCFTypeRef<CFStringRef> ext_cf(base::SysUTF8ToCFStringRef(ext));
|
||||
return UTTypeCreatePreferredIdentifierForTag(
|
||||
kUTTagClassFilenameExtension, ext_cf.get(), NULL);
|
||||
}
|
||||
|
||||
void SetAllowedFileTypes(NSSavePanel* dialog, const Filters& filters) {
|
||||
NSMutableSet* file_type_set = [NSMutableSet set];
|
||||
for (size_t i = 0; i < filters.size(); ++i) {
|
||||
const Filter& filter = filters[i];
|
||||
for (size_t j = 0; j < filter.second.size(); ++j) {
|
||||
base::ScopedCFTypeRef<CFStringRef> uti(
|
||||
CreateUTIFromExtension(filter.second[j]));
|
||||
[file_type_set addObject:base::mac::CFToNSCast(uti.get())];
|
||||
|
||||
// Always allow the extension itself, in case the UTI doesn't map
|
||||
// back to the original extension correctly. This occurs with dynamic
|
||||
// UTIs on 10.7 and 10.8.
|
||||
// See http://crbug.com/148840, http://openradar.me/12316273
|
||||
base::ScopedCFTypeRef<CFStringRef> ext_cf(
|
||||
base::SysUTF8ToCFStringRef(filter.second[j]));
|
||||
[file_type_set addObject:base::mac::CFToNSCast(ext_cf.get())];
|
||||
|
||||
@@ -120,12 +120,13 @@ struct RunState {
|
||||
};
|
||||
|
||||
bool CreateDialogThread(RunState* run_state) {
|
||||
base::Thread* thread = new base::Thread(ATOM_PRODUCT_NAME "FileDialogThread");
|
||||
scoped_ptr<base::Thread> thread(
|
||||
new base::Thread(ATOM_PRODUCT_NAME "FileDialogThread"));
|
||||
thread->init_com_with_mta(false);
|
||||
if (!thread->Start())
|
||||
return false;
|
||||
|
||||
run_state->dialog_thread = thread;
|
||||
run_state->dialog_thread = thread.release();
|
||||
run_state->ui_message_loop = base::MessageLoop::current();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,14 @@ class NativeWindow;
|
||||
enum MessageBoxType {
|
||||
MESSAGE_BOX_TYPE_NONE = 0,
|
||||
MESSAGE_BOX_TYPE_INFORMATION,
|
||||
MESSAGE_BOX_TYPE_WARNING
|
||||
MESSAGE_BOX_TYPE_WARNING,
|
||||
MESSAGE_BOX_TYPE_ERROR,
|
||||
MESSAGE_BOX_TYPE_QUESTION,
|
||||
};
|
||||
|
||||
enum MessageBoxOptions {
|
||||
MESSAGE_BOX_NONE = 0,
|
||||
MESSAGE_BOX_NO_LINK = 1 << 0,
|
||||
};
|
||||
|
||||
typedef base::Callback<void(int code)> MessageBoxCallback;
|
||||
@@ -30,6 +37,8 @@ typedef base::Callback<void(int code)> MessageBoxCallback;
|
||||
int ShowMessageBox(NativeWindow* parent_window,
|
||||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
int cancel_id,
|
||||
int options,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
@@ -38,6 +47,8 @@ int ShowMessageBox(NativeWindow* parent_window,
|
||||
void ShowMessageBox(NativeWindow* parent_window,
|
||||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
int cancel_id,
|
||||
int options,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
|
||||
205
atom/browser/ui/message_box_gtk.cc
Normal file
205
atom/browser/ui/message_box_gtk.cc
Normal file
@@ -0,0 +1,205 @@
|
||||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/ui/message_box.h"
|
||||
|
||||
#include "atom/browser/browser.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "chrome/browser/ui/libgtk2ui/gtk2_signal.h"
|
||||
#include "chrome/browser/ui/libgtk2ui/gtk2_util.h"
|
||||
#include "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h"
|
||||
#include "ui/views/widget/desktop_aura/x11_desktop_handler.h"
|
||||
|
||||
#define ANSI_FOREGROUND_RED "\x1b[31m"
|
||||
#define ANSI_FOREGROUND_BLACK "\x1b[30m"
|
||||
#define ANSI_TEXT_BOLD "\x1b[1m"
|
||||
#define ANSI_BACKGROUND_GRAY "\x1b[47m"
|
||||
#define ANSI_RESET "\x1b[0m"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
class GtkMessageBox {
|
||||
public:
|
||||
GtkMessageBox(NativeWindow* parent_window,
|
||||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
int cancel_id,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
const gfx::ImageSkia& icon)
|
||||
: dialog_scope_(parent_window),
|
||||
cancel_id_(cancel_id) {
|
||||
// Create dialog.
|
||||
dialog_ = gtk_message_dialog_new(
|
||||
nullptr, // parent
|
||||
static_cast<GtkDialogFlags>(0), // no flags
|
||||
GetMessageType(type), // type
|
||||
GTK_BUTTONS_NONE, // no buttons
|
||||
"%s", message.c_str());
|
||||
if (!detail.empty())
|
||||
gtk_message_dialog_format_secondary_text(
|
||||
GTK_MESSAGE_DIALOG(dialog_), "%s", detail.c_str());
|
||||
if (!title.empty())
|
||||
gtk_window_set_title(GTK_WINDOW(dialog_), title.c_str());
|
||||
|
||||
// Set dialog's icon.
|
||||
if (!icon.isNull()) {
|
||||
GdkPixbuf* pixbuf = libgtk2ui::GdkPixbufFromSkBitmap(*icon.bitmap());
|
||||
GtkWidget* image = gtk_image_new_from_pixbuf(pixbuf);
|
||||
gtk_message_dialog_set_image(GTK_MESSAGE_DIALOG(dialog_), image);
|
||||
gtk_widget_show(image);
|
||||
g_object_unref(pixbuf);
|
||||
}
|
||||
|
||||
// Add buttons.
|
||||
for (size_t i = 0; i < buttons.size(); ++i) {
|
||||
gtk_dialog_add_button(GTK_DIALOG(dialog_),
|
||||
TranslateToStock(i, buttons[i]),
|
||||
i);
|
||||
}
|
||||
|
||||
// Parent window.
|
||||
if (parent_window) {
|
||||
gfx::NativeWindow window = parent_window->GetNativeWindow();
|
||||
libgtk2ui::SetGtkTransientForAura(dialog_, window);
|
||||
}
|
||||
}
|
||||
|
||||
~GtkMessageBox() {
|
||||
gtk_widget_destroy(dialog_);
|
||||
}
|
||||
|
||||
GtkMessageType GetMessageType(MessageBoxType type) {
|
||||
switch (type) {
|
||||
case MESSAGE_BOX_TYPE_INFORMATION:
|
||||
return GTK_MESSAGE_INFO;
|
||||
case MESSAGE_BOX_TYPE_WARNING:
|
||||
return GTK_MESSAGE_WARNING;
|
||||
case MESSAGE_BOX_TYPE_QUESTION:
|
||||
return GTK_MESSAGE_QUESTION;
|
||||
case MESSAGE_BOX_TYPE_ERROR:
|
||||
return GTK_MESSAGE_ERROR;
|
||||
default:
|
||||
return GTK_MESSAGE_OTHER;
|
||||
}
|
||||
}
|
||||
|
||||
const char* TranslateToStock(int id, const std::string& text) {
|
||||
std::string lower = base::StringToLowerASCII(text);
|
||||
if (lower == "cancel")
|
||||
return GTK_STOCK_CANCEL;
|
||||
else if (lower == "no")
|
||||
return GTK_STOCK_NO;
|
||||
else if (lower == "ok")
|
||||
return GTK_STOCK_OK;
|
||||
else if (lower == "yes")
|
||||
return GTK_STOCK_YES;
|
||||
else
|
||||
return text.c_str();
|
||||
}
|
||||
|
||||
void Show() {
|
||||
gtk_widget_show_all(dialog_);
|
||||
// We need to call gtk_window_present after making the widgets visible to
|
||||
// make sure window gets correctly raised and gets focus.
|
||||
int time = views::X11DesktopHandler::get()->wm_user_time_ms();
|
||||
gtk_window_present_with_time(GTK_WINDOW(dialog_), time);
|
||||
}
|
||||
|
||||
int RunSynchronous() {
|
||||
gtk_window_set_modal(GTK_WINDOW(dialog_), TRUE);
|
||||
Show();
|
||||
int response = gtk_dialog_run(GTK_DIALOG(dialog_));
|
||||
if (response < 0)
|
||||
return cancel_id_;
|
||||
else
|
||||
return response;
|
||||
}
|
||||
|
||||
void RunAsynchronous(const MessageBoxCallback& callback) {
|
||||
callback_ = callback;
|
||||
g_signal_connect(dialog_, "delete-event",
|
||||
G_CALLBACK(gtk_widget_hide_on_delete), nullptr);
|
||||
g_signal_connect(dialog_, "response",
|
||||
G_CALLBACK(OnResponseDialogThunk), this);
|
||||
Show();
|
||||
}
|
||||
|
||||
CHROMEGTK_CALLBACK_1(GtkMessageBox, void, OnResponseDialog, int);
|
||||
|
||||
private:
|
||||
atom::NativeWindow::DialogScope dialog_scope_;
|
||||
|
||||
// The id to return when the dialog is closed without pressing buttons.
|
||||
int cancel_id_;
|
||||
|
||||
GtkWidget* dialog_;
|
||||
MessageBoxCallback callback_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(GtkMessageBox);
|
||||
};
|
||||
|
||||
void GtkMessageBox::OnResponseDialog(GtkWidget* widget, int response) {
|
||||
gtk_widget_hide_all(dialog_);
|
||||
|
||||
if (response < 0)
|
||||
callback_.Run(cancel_id_);
|
||||
else
|
||||
callback_.Run(response);
|
||||
delete this;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int ShowMessageBox(NativeWindow* parent,
|
||||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
int cancel_id,
|
||||
int options,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
const gfx::ImageSkia& icon) {
|
||||
return GtkMessageBox(parent, type, buttons, cancel_id, title, message, detail,
|
||||
icon).RunSynchronous();
|
||||
}
|
||||
|
||||
void ShowMessageBox(NativeWindow* parent,
|
||||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
int cancel_id,
|
||||
int options,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
const gfx::ImageSkia& icon,
|
||||
const MessageBoxCallback& callback) {
|
||||
(new GtkMessageBox(parent, type, buttons, cancel_id, title, message, detail,
|
||||
icon))->RunAsynchronous(callback);
|
||||
}
|
||||
|
||||
void ShowErrorBox(const base::string16& title, const base::string16& content) {
|
||||
if (Browser::Get()->is_ready()) {
|
||||
GtkMessageBox(nullptr, MESSAGE_BOX_TYPE_ERROR, { "OK" }, 0, "Error",
|
||||
base::UTF16ToUTF8(title).c_str(),
|
||||
base::UTF16ToUTF8(content).c_str(),
|
||||
gfx::ImageSkia()).RunSynchronous();
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
ANSI_TEXT_BOLD ANSI_BACKGROUND_GRAY
|
||||
ANSI_FOREGROUND_RED "%s\n"
|
||||
ANSI_FOREGROUND_BLACK "%s"
|
||||
ANSI_RESET "\n",
|
||||
base::UTF16ToUTF8(title).c_str(),
|
||||
base::UTF16ToUTF8(content).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
@@ -94,6 +94,8 @@ void SetReturnCode(int* ret_code, int result) {
|
||||
int ShowMessageBox(NativeWindow* parent_window,
|
||||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
int cancel_id,
|
||||
int options,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
@@ -125,6 +127,8 @@ int ShowMessageBox(NativeWindow* parent_window,
|
||||
void ShowMessageBox(NativeWindow* parent_window,
|
||||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
int cancel_id,
|
||||
int options,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
|
||||
@@ -1,417 +0,0 @@
|
||||
// Copyright (c) 2013 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/ui/message_box.h"
|
||||
|
||||
#if defined(USE_X11)
|
||||
#include <gtk/gtk.h>
|
||||
#endif
|
||||
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/message_loop/message_loop.h"
|
||||
#include "base/run_loop.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/string16.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "ui/views/background.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/bubble/bubble_border.h"
|
||||
#include "ui/views/bubble/bubble_frame_view.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
#include "ui/views/widget/widget_delegate.h"
|
||||
#include "ui/wm/core/shadow_types.h"
|
||||
|
||||
#if defined(USE_X11)
|
||||
#include "atom/browser/browser.h"
|
||||
#include "ui/views/window/native_frame_view.h"
|
||||
#endif
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "ui/base/win/message_box_win.h"
|
||||
#endif
|
||||
|
||||
#define ANSI_FOREGROUND_RED "\x1b[31m"
|
||||
#define ANSI_FOREGROUND_BLACK "\x1b[30m"
|
||||
#define ANSI_TEXT_BOLD "\x1b[1m"
|
||||
#define ANSI_BACKGROUND_GRAY "\x1b[47m"
|
||||
#define ANSI_RESET "\x1b[0m"
|
||||
|
||||
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 MessageDialogClientView;
|
||||
|
||||
class MessageDialog : 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,
|
||||
const gfx::ImageSkia& icon);
|
||||
virtual ~MessageDialog();
|
||||
|
||||
void Show(base::RunLoop* run_loop = NULL);
|
||||
void Close();
|
||||
|
||||
int GetResult() const;
|
||||
|
||||
void set_callback(const MessageBoxCallback& callback) {
|
||||
delete_on_close_ = true;
|
||||
callback_ = callback;
|
||||
}
|
||||
|
||||
private:
|
||||
// Overridden from views::WidgetDelegate:
|
||||
base::string16 GetWindowTitle() const override;
|
||||
gfx::ImageSkia GetWindowAppIcon() override;
|
||||
gfx::ImageSkia GetWindowIcon() override;
|
||||
bool ShouldShowWindowIcon() const override;
|
||||
views::Widget* GetWidget() override;
|
||||
const views::Widget* GetWidget() const override;
|
||||
views::View* GetContentsView() override;
|
||||
views::View* GetInitiallyFocusedView() override;
|
||||
ui::ModalType GetModalType() const override;
|
||||
views::NonClientFrameView* CreateNonClientFrameView(
|
||||
views::Widget* widget) override;
|
||||
views::ClientView* CreateClientView(views::Widget* widget) override;
|
||||
|
||||
// Overridden from views::View:
|
||||
gfx::Size GetPreferredSize() const override;
|
||||
void Layout() override;
|
||||
bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
|
||||
|
||||
// Overridden from views::ButtonListener:
|
||||
void ButtonPressed(views::Button* sender, const ui::Event& event) override;
|
||||
|
||||
gfx::ImageSkia icon_;
|
||||
|
||||
bool delete_on_close_;
|
||||
int result_;
|
||||
base::string16 title_;
|
||||
|
||||
NativeWindow* parent_;
|
||||
scoped_ptr<views::Widget> widget_;
|
||||
views::MessageBoxView* message_box_view_;
|
||||
std::vector<views::LabelButton*> buttons_;
|
||||
|
||||
base::RunLoop* run_loop_;
|
||||
scoped_ptr<NativeWindow::DialogScope> dialog_scope_;
|
||||
MessageBoxCallback callback_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MessageDialog);
|
||||
};
|
||||
|
||||
class MessageDialogClientView : public views::ClientView {
|
||||
public:
|
||||
MessageDialogClientView(MessageDialog* dialog, views::Widget* widget)
|
||||
: views::ClientView(widget, dialog),
|
||||
dialog_(dialog) {
|
||||
}
|
||||
|
||||
// views::ClientView:
|
||||
bool CanClose() override {
|
||||
dialog_->Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
MessageDialog* dialog_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MessageDialogClientView);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 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,
|
||||
const gfx::ImageSkia& icon)
|
||||
: icon_(icon),
|
||||
delete_on_close_(false),
|
||||
result_(-1),
|
||||
title_(base::UTF8ToUTF16(title)),
|
||||
parent_(parent_window),
|
||||
message_box_view_(NULL),
|
||||
run_loop_(NULL),
|
||||
dialog_scope_(new NativeWindow::DialogScope(parent_window)) {
|
||||
DCHECK_GT(buttons.size(), 0u);
|
||||
set_owned_by_client();
|
||||
|
||||
if (!parent_)
|
||||
set_background(views::Background::CreateStandardPanelBackground());
|
||||
|
||||
std::string content = message + "\n" + detail;
|
||||
views::MessageBoxView::InitParams box_params(base::UTF8ToUTF16(content));
|
||||
message_box_view_ = new views::MessageBoxView(box_params);
|
||||
AddChildView(message_box_view_);
|
||||
|
||||
for (size_t i = 0; i < buttons.size(); ++i) {
|
||||
views::LabelButton* button = new views::LabelButton(
|
||||
this, base::UTF8ToUTF16(buttons[i]));
|
||||
button->set_tag(i);
|
||||
button->SetMinSize(gfx::Size(60, 30));
|
||||
button->SetStyle(views::Button::STYLE_BUTTON);
|
||||
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 params;
|
||||
params.delegate = this;
|
||||
params.type = views::Widget::InitParams::TYPE_WINDOW;
|
||||
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
|
||||
if (parent_) {
|
||||
params.parent = parent_->GetNativeWindow();
|
||||
params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
|
||||
// Use bubble style for dialog has a parent.
|
||||
params.remove_standard_frame = true;
|
||||
}
|
||||
|
||||
widget_.reset(new views::Widget);
|
||||
widget_->Init(params);
|
||||
widget_->UpdateWindowIcon();
|
||||
|
||||
// Bind to ESC.
|
||||
AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
|
||||
}
|
||||
|
||||
MessageDialog::~MessageDialog() {
|
||||
}
|
||||
|
||||
void MessageDialog::Show(base::RunLoop* run_loop) {
|
||||
run_loop_ = run_loop;
|
||||
widget_->Show();
|
||||
}
|
||||
|
||||
void MessageDialog::Close() {
|
||||
dialog_scope_.reset();
|
||||
|
||||
if (delete_on_close_) {
|
||||
callback_.Run(GetResult());
|
||||
base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
|
||||
} else if (run_loop_) {
|
||||
run_loop_->Quit();
|
||||
}
|
||||
}
|
||||
|
||||
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:
|
||||
|
||||
base::string16 MessageDialog::GetWindowTitle() const {
|
||||
return title_;
|
||||
}
|
||||
|
||||
gfx::ImageSkia MessageDialog::GetWindowAppIcon() {
|
||||
return icon_;
|
||||
}
|
||||
|
||||
gfx::ImageSkia MessageDialog::GetWindowIcon() {
|
||||
return icon_;
|
||||
}
|
||||
|
||||
bool MessageDialog::ShouldShowWindowIcon() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
views::Widget* MessageDialog::GetWidget() {
|
||||
return widget_.get();
|
||||
}
|
||||
|
||||
const views::Widget* MessageDialog::GetWidget() const {
|
||||
return widget_.get();
|
||||
}
|
||||
|
||||
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_SYSTEM;
|
||||
}
|
||||
|
||||
views::NonClientFrameView* MessageDialog::CreateNonClientFrameView(
|
||||
views::Widget* widget) {
|
||||
if (!parent_) {
|
||||
#if defined(USE_X11)
|
||||
return new views::NativeFrameView(widget);
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Create a bubble style frame like Chrome.
|
||||
views::BubbleFrameView* frame = new views::BubbleFrameView(gfx::Insets());
|
||||
const SkColor color = widget->GetNativeTheme()->GetSystemColor(
|
||||
ui::NativeTheme::kColorId_DialogBackground);
|
||||
scoped_ptr<views::BubbleBorder> border(new views::BubbleBorder(
|
||||
views::BubbleBorder::FLOAT, views::BubbleBorder::SMALL_SHADOW, color));
|
||||
frame->SetBubbleBorder(border.Pass());
|
||||
wm::SetShadowType(widget->GetNativeWindow(), wm::SHADOW_TYPE_NONE);
|
||||
return frame;
|
||||
}
|
||||
|
||||
views::ClientView* MessageDialog::CreateClientView(views::Widget* widget) {
|
||||
return new MessageDialogClientView(this, widget);
|
||||
}
|
||||
|
||||
gfx::Size MessageDialog::GetPreferredSize() const {
|
||||
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,
|
||||
const gfx::ImageSkia& icon) {
|
||||
MessageDialog dialog(
|
||||
parent_window, type, buttons, title, message, detail, icon);
|
||||
{
|
||||
base::MessageLoop::ScopedNestableTaskAllower allow(
|
||||
base::MessageLoopForUI::current());
|
||||
base::RunLoop run_loop;
|
||||
dialog.Show(&run_loop);
|
||||
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 gfx::ImageSkia& icon,
|
||||
const MessageBoxCallback& callback) {
|
||||
// The dialog would be deleted when the dialog is closed.
|
||||
MessageDialog* dialog = new MessageDialog(
|
||||
parent_window, type, buttons, title, message, detail, icon);
|
||||
dialog->set_callback(callback);
|
||||
dialog->Show();
|
||||
}
|
||||
|
||||
void ShowErrorBox(const base::string16& title, const base::string16& content) {
|
||||
#if defined(OS_WIN)
|
||||
ui::MessageBox(NULL, content, title, MB_OK | MB_ICONERROR | MB_TASKMODAL);
|
||||
#elif defined(USE_X11)
|
||||
if (Browser::Get()->is_ready()) {
|
||||
GtkWidget* dialog = gtk_message_dialog_new(
|
||||
NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
|
||||
"%s", base::UTF16ToUTF8(title).c_str());
|
||||
gtk_message_dialog_format_secondary_text(
|
||||
GTK_MESSAGE_DIALOG(dialog),
|
||||
"%s", base::UTF16ToUTF8(content).c_str());
|
||||
gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
gtk_widget_destroy(dialog);
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
ANSI_TEXT_BOLD ANSI_BACKGROUND_GRAY
|
||||
ANSI_FOREGROUND_RED "%s\n"
|
||||
ANSI_FOREGROUND_BLACK "%s"
|
||||
ANSI_RESET "\n",
|
||||
base::UTF16ToUTF8(title).c_str(),
|
||||
base::UTF16ToUTF8(content).c_str());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
236
atom/browser/ui/message_box_win.cc
Normal file
236
atom/browser/ui/message_box_win.cc
Normal file
@@ -0,0 +1,236 @@
|
||||
// Copyright (c) 2013 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/ui/message_box.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <commctrl.h>
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "atom/browser/browser.h"
|
||||
#include "atom/browser/native_window_views.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/threading/thread.h"
|
||||
#include "base/win/scoped_gdi_object.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "ui/gfx/icon_util.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
// Small command ID values are already taken by Windows, we have to start from
|
||||
// a large number to avoid conflicts with Windows.
|
||||
const int kIDStart = 100;
|
||||
|
||||
// Get the common ID from button's name.
|
||||
struct CommonButtonID {
|
||||
int button;
|
||||
int id;
|
||||
};
|
||||
CommonButtonID GetCommonID(const base::string16& button) {
|
||||
base::string16 lower = base::StringToLowerASCII(button);
|
||||
if (lower == L"ok")
|
||||
return { TDCBF_OK_BUTTON, IDOK };
|
||||
else if (lower == L"yes")
|
||||
return { TDCBF_YES_BUTTON, IDYES };
|
||||
else if (lower == L"no")
|
||||
return { TDCBF_NO_BUTTON, IDNO };
|
||||
else if (lower == L"cancel")
|
||||
return { TDCBF_CANCEL_BUTTON, IDCANCEL };
|
||||
else if (lower == L"retry")
|
||||
return { TDCBF_RETRY_BUTTON, IDRETRY };
|
||||
else if (lower == L"close")
|
||||
return { TDCBF_CLOSE_BUTTON, IDCLOSE };
|
||||
return { -1, -1 };
|
||||
}
|
||||
|
||||
// Determine whether the buttons are common buttons, if so map common ID
|
||||
// to button ID.
|
||||
void MapToCommonID(const std::vector<base::string16>& buttons,
|
||||
std::map<int, int>* id_map,
|
||||
TASKDIALOG_COMMON_BUTTON_FLAGS* button_flags,
|
||||
std::vector<TASKDIALOG_BUTTON>* dialog_buttons) {
|
||||
for (size_t i = 0; i < buttons.size(); ++i) {
|
||||
auto common = GetCommonID(buttons[i]);
|
||||
if (common.button != -1) {
|
||||
// It is a common button.
|
||||
(*id_map)[common.id] = i;
|
||||
(*button_flags) |= common.button;
|
||||
} else {
|
||||
// It is a custom button.
|
||||
dialog_buttons->push_back({i + kIDStart, buttons[i].c_str()});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ShowMessageBoxUTF16(HWND parent,
|
||||
MessageBoxType type,
|
||||
const std::vector<base::string16>& buttons,
|
||||
int cancel_id,
|
||||
int options,
|
||||
const base::string16& title,
|
||||
const base::string16& message,
|
||||
const base::string16& detail,
|
||||
const gfx::ImageSkia& icon) {
|
||||
TASKDIALOG_FLAGS flags = TDF_SIZE_TO_CONTENT; // show all content.
|
||||
if (cancel_id != 0)
|
||||
flags |= TDF_ALLOW_DIALOG_CANCELLATION; // allow dialog to be cancelled.
|
||||
|
||||
TASKDIALOGCONFIG config = { 0 };
|
||||
config.cbSize = sizeof(config);
|
||||
config.hwndParent = parent;
|
||||
config.hInstance = GetModuleHandle(NULL);
|
||||
config.dwFlags = flags;
|
||||
|
||||
// TaskDialogIndirect doesn't allow empty name, if we set empty title it
|
||||
// will show "electron.exe" in title.
|
||||
base::string16 app_name = base::UTF8ToUTF16(Browser::Get()->GetName());
|
||||
if (title.empty())
|
||||
config.pszWindowTitle = app_name.c_str();
|
||||
else
|
||||
config.pszWindowTitle = title.c_str();
|
||||
|
||||
base::win::ScopedHICON hicon;
|
||||
if (!icon.isNull()) {
|
||||
hicon.Set(IconUtil::CreateHICONFromSkBitmap(*icon.bitmap()));
|
||||
config.dwFlags |= TDF_USE_HICON_MAIN;
|
||||
config.hMainIcon = hicon.Get();
|
||||
} else {
|
||||
// Show icon according to dialog's type.
|
||||
switch (type) {
|
||||
case MESSAGE_BOX_TYPE_INFORMATION:
|
||||
case MESSAGE_BOX_TYPE_QUESTION:
|
||||
config.pszMainIcon = TD_INFORMATION_ICON;
|
||||
break;
|
||||
case MESSAGE_BOX_TYPE_WARNING:
|
||||
config.pszMainIcon = TD_WARNING_ICON;
|
||||
break;
|
||||
case MESSAGE_BOX_TYPE_ERROR:
|
||||
config.pszMainIcon = TD_ERROR_ICON;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If "detail" is empty then don't make message hilighted.
|
||||
if (detail.empty()) {
|
||||
config.pszContent = message.c_str();
|
||||
} else {
|
||||
config.pszMainInstruction = message.c_str();
|
||||
config.pszContent = detail.c_str();
|
||||
}
|
||||
|
||||
// Iterate through the buttons, put common buttons in dwCommonButtons
|
||||
// and custom buttons in pButtons.
|
||||
std::map<int, int> id_map;
|
||||
std::vector<TASKDIALOG_BUTTON> dialog_buttons;
|
||||
if (options & MESSAGE_BOX_NO_LINK) {
|
||||
for (size_t i = 0; i < buttons.size(); ++i)
|
||||
dialog_buttons.push_back({i + kIDStart, buttons[i].c_str()});
|
||||
} else {
|
||||
MapToCommonID(buttons, &id_map, &config.dwCommonButtons, &dialog_buttons);
|
||||
}
|
||||
if (dialog_buttons.size() > 0) {
|
||||
config.pButtons = &dialog_buttons.front();
|
||||
config.cButtons = dialog_buttons.size();
|
||||
if (!(options & MESSAGE_BOX_NO_LINK))
|
||||
config.dwFlags |= TDF_USE_COMMAND_LINKS; // custom buttons as links.
|
||||
}
|
||||
|
||||
int id = 0;
|
||||
TaskDialogIndirect(&config, &id, NULL, NULL);
|
||||
if (id_map.find(id) != id_map.end()) // common button.
|
||||
return id_map[id];
|
||||
else if (id >= kIDStart) // custom button.
|
||||
return id - kIDStart;
|
||||
else
|
||||
return cancel_id;
|
||||
}
|
||||
|
||||
void RunMessageBoxInNewThread(base::Thread* thread,
|
||||
NativeWindow* parent,
|
||||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
int cancel_id,
|
||||
int options,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
const gfx::ImageSkia& icon,
|
||||
const MessageBoxCallback& callback) {
|
||||
int result = ShowMessageBox(parent, type, buttons, cancel_id, options, title,
|
||||
message, detail, icon);
|
||||
content::BrowserThread::PostTask(
|
||||
content::BrowserThread::UI, FROM_HERE, base::Bind(callback, result));
|
||||
content::BrowserThread::DeleteSoon(
|
||||
content::BrowserThread::UI, FROM_HERE, thread);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int ShowMessageBox(NativeWindow* parent,
|
||||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
int cancel_id,
|
||||
int options,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
const gfx::ImageSkia& icon) {
|
||||
std::vector<base::string16> utf16_buttons;
|
||||
for (const auto& button : buttons)
|
||||
utf16_buttons.push_back(base::UTF8ToUTF16(button));
|
||||
|
||||
HWND hwnd_parent = parent ?
|
||||
static_cast<atom::NativeWindowViews*>(parent)->GetAcceleratedWidget() :
|
||||
NULL;
|
||||
|
||||
NativeWindow::DialogScope dialog_scope(parent);
|
||||
return ShowMessageBoxUTF16(hwnd_parent,
|
||||
type,
|
||||
utf16_buttons,
|
||||
cancel_id,
|
||||
options,
|
||||
base::UTF8ToUTF16(title),
|
||||
base::UTF8ToUTF16(message),
|
||||
base::UTF8ToUTF16(detail),
|
||||
icon);
|
||||
}
|
||||
|
||||
void ShowMessageBox(NativeWindow* parent,
|
||||
MessageBoxType type,
|
||||
const std::vector<std::string>& buttons,
|
||||
int cancel_id,
|
||||
int options,
|
||||
const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& detail,
|
||||
const gfx::ImageSkia& icon,
|
||||
const MessageBoxCallback& callback) {
|
||||
scoped_ptr<base::Thread> thread(
|
||||
new base::Thread(ATOM_PRODUCT_NAME "MessageBoxThread"));
|
||||
thread->init_com_with_mta(false);
|
||||
if (!thread->Start()) {
|
||||
callback.Run(cancel_id);
|
||||
return;
|
||||
}
|
||||
|
||||
base::Thread* unretained = thread.release();
|
||||
unretained->message_loop()->PostTask(
|
||||
FROM_HERE,
|
||||
base::Bind(&RunMessageBoxInNewThread, base::Unretained(unretained),
|
||||
parent, type, buttons, cancel_id, options, title, message,
|
||||
detail, icon, callback));
|
||||
}
|
||||
|
||||
void ShowErrorBox(const base::string16& title, const base::string16& content) {
|
||||
ShowMessageBoxUTF16(NULL, MESSAGE_BOX_TYPE_ERROR, {}, 0, 0, L"Error", title,
|
||||
content, gfx::ImageSkia());
|
||||
}
|
||||
|
||||
} // 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