mirror of
https://github.com/electron/electron.git
synced 2026-02-26 03:01:17 -05:00
Compare commits
1010 Commits
v1.7.10
...
v1.8.2-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f8adaed763 | ||
|
|
2db845e202 | ||
|
|
9c217fc6c7 | ||
|
|
3f21e1240f | ||
|
|
dd139706ea | ||
|
|
d92e229b3b | ||
|
|
96aa0aa2f1 | ||
|
|
3c607394d7 | ||
|
|
6930f5c3ba | ||
|
|
037f76c47b | ||
|
|
690e8cf75b | ||
|
|
6298748d0b | ||
|
|
69e461083a | ||
|
|
4d18cbe728 | ||
|
|
3cb062b3d6 | ||
|
|
e4064d8dc2 | ||
|
|
7630ac6e90 | ||
|
|
8f20ce6dcf | ||
|
|
b7bc4eb586 | ||
|
|
14db204315 | ||
|
|
8c5aad8b17 | ||
|
|
061447d34e | ||
|
|
fded32dc4f | ||
|
|
7003a2a19c | ||
|
|
40bad250aa | ||
|
|
7cc73140f8 | ||
|
|
a2f95c5f90 | ||
|
|
e25a46378b | ||
|
|
2cee035b4e | ||
|
|
5d03f3ca64 | ||
|
|
6fd6315cb2 | ||
|
|
32edf6a2b8 | ||
|
|
db6de6a2b2 | ||
|
|
34d108e896 | ||
|
|
b2564242e0 | ||
|
|
7bc58c6a5f | ||
|
|
16ffff4aec | ||
|
|
78ccf14e53 | ||
|
|
1445ba5116 | ||
|
|
be9e6700d9 | ||
|
|
0c47207a0e | ||
|
|
4b41822a62 | ||
|
|
3b29adc000 | ||
|
|
b51396f1cd | ||
|
|
0d8cfe8dbe | ||
|
|
4f9c5310a9 | ||
|
|
70643a865b | ||
|
|
b2fdfa2710 | ||
|
|
a83b8e751b | ||
|
|
447e0e6c8b | ||
|
|
d8fe846d50 | ||
|
|
c7e40a2a64 | ||
|
|
4a42738db9 | ||
|
|
51a023e7bb | ||
|
|
c122852f09 | ||
|
|
92872154d4 | ||
|
|
dba9181611 | ||
|
|
596a61f1ad | ||
|
|
be67fcf62b | ||
|
|
0711e1e5e1 | ||
|
|
70fae85451 | ||
|
|
432d050481 | ||
|
|
3c38438303 | ||
|
|
05bae0b4c4 | ||
|
|
b029c088db | ||
|
|
b8b3b441a7 | ||
|
|
71b8eaf085 | ||
|
|
fa37d49fb6 | ||
|
|
dafd3d69bc | ||
|
|
4f6bdc5824 | ||
|
|
c9f2080e4b | ||
|
|
6cacb9838e | ||
|
|
5eb00e45aa | ||
|
|
4c04f1c7ed | ||
|
|
7904be8763 | ||
|
|
cf749a8e18 | ||
|
|
42d7d51b75 | ||
|
|
cb98ed8674 | ||
|
|
435e027dc3 | ||
|
|
2441d51093 | ||
|
|
cd5785c410 | ||
|
|
dc7eaf8d78 | ||
|
|
79414d4822 | ||
|
|
3cc8330998 | ||
|
|
efaf7a6b85 | ||
|
|
5376df1519 | ||
|
|
f2d6d6b6a1 | ||
|
|
14c6e78147 | ||
|
|
2a826c7ca9 | ||
|
|
c465257d69 | ||
|
|
daad465fcd | ||
|
|
e3b6271806 | ||
|
|
5b18bea7e3 | ||
|
|
cf7e9df3a0 | ||
|
|
3311e0bd67 | ||
|
|
9a2d103e7f | ||
|
|
1dea186a6e | ||
|
|
f469059e90 | ||
|
|
e2a91ff689 | ||
|
|
b525f2f031 | ||
|
|
6f11aa169a | ||
|
|
6fab8cc3a5 | ||
|
|
ccb6651752 | ||
|
|
a9a9e58b68 | ||
|
|
780c1b8f56 | ||
|
|
aaae1bb176 | ||
|
|
9f922e9932 | ||
|
|
e10feb6be2 | ||
|
|
2138c5bff0 | ||
|
|
6243d45946 | ||
|
|
be0e3d9555 | ||
|
|
7f4c501f81 | ||
|
|
fc265b7600 | ||
|
|
bdbc6bb165 | ||
|
|
933c7330a5 | ||
|
|
75a117e4e2 | ||
|
|
f5c04c7037 | ||
|
|
c8b544a47d | ||
|
|
e5983eacd6 | ||
|
|
0bfbd9b3c4 | ||
|
|
8657169017 | ||
|
|
668b736ef2 | ||
|
|
97c64de28e | ||
|
|
b51a9cf4f6 | ||
|
|
367b4b05a1 | ||
|
|
33bd2aa1a0 | ||
|
|
f8dd04e5f7 | ||
|
|
b695f1221c | ||
|
|
57f934a806 | ||
|
|
8a8f169628 | ||
|
|
3a1106d026 | ||
|
|
ee2a28b35b | ||
|
|
dc410efa36 | ||
|
|
99d35f7786 | ||
|
|
58bd0986c8 | ||
|
|
31172ecaa0 | ||
|
|
f6ce1afad3 | ||
|
|
4b8ab8fc97 | ||
|
|
d05a1f8053 | ||
|
|
bbde795a1f | ||
|
|
4a92e5fc24 | ||
|
|
b6109030a1 | ||
|
|
1f2c949316 | ||
|
|
ff707a0f3d | ||
|
|
7c446cc61c | ||
|
|
5e8618ec3b | ||
|
|
639dc2377f | ||
|
|
5ea3a5886b | ||
|
|
68f514b92f | ||
|
|
64bfabdeba | ||
|
|
6b666b69c0 | ||
|
|
6b2ddc4814 | ||
|
|
32113bf7f9 | ||
|
|
9c04d18387 | ||
|
|
163a33a9db | ||
|
|
b382dec4a2 | ||
|
|
4d364fa27a | ||
|
|
72440d4ae7 | ||
|
|
cee1c459c7 | ||
|
|
7e0593950c | ||
|
|
8de9d5265a | ||
|
|
276e12ce71 | ||
|
|
573f664899 | ||
|
|
26daffea9c | ||
|
|
4b10445c2e | ||
|
|
193beb57c9 | ||
|
|
f8b3009ebf | ||
|
|
cafb9477b0 | ||
|
|
71b36ef54d | ||
|
|
5373afa472 | ||
|
|
13b86598e8 | ||
|
|
35dc6d03b9 | ||
|
|
45d16d5add | ||
|
|
e39aacb30e | ||
|
|
5daaff91ea | ||
|
|
12653d36ea | ||
|
|
7b0b87bfef | ||
|
|
3c0b233d04 | ||
|
|
aa6b9a5025 | ||
|
|
29438940f6 | ||
|
|
f0facdc01f | ||
|
|
40b94e97e5 | ||
|
|
a06a8a6f79 | ||
|
|
ba754cf5c3 | ||
|
|
9a2a98d522 | ||
|
|
ae960027f2 | ||
|
|
13749797ec | ||
|
|
9291ab95dd | ||
|
|
5adbbef6cd | ||
|
|
0c88b073d1 | ||
|
|
f5b9e1f732 | ||
|
|
912c023c6d | ||
|
|
2ad1d8ba28 | ||
|
|
387ed21f94 | ||
|
|
7c5bd62158 | ||
|
|
00665b9501 | ||
|
|
26fedcf8da | ||
|
|
9b3960fe90 | ||
|
|
9bf950aa33 | ||
|
|
26baea58c9 | ||
|
|
51f6311f32 | ||
|
|
e51042f5a1 | ||
|
|
1986236b19 | ||
|
|
ef78805a1c | ||
|
|
bb997c2ea4 | ||
|
|
d475eaf011 | ||
|
|
3dcde82485 | ||
|
|
c260a0ab78 | ||
|
|
98eee28cbc | ||
|
|
a34255ceef | ||
|
|
07dea13c77 | ||
|
|
1454783450 | ||
|
|
546ede19c7 | ||
|
|
8eb38be153 | ||
|
|
5e50a9ab8f | ||
|
|
bf42426acc | ||
|
|
6b9e67c972 | ||
|
|
247af376fe | ||
|
|
43aa555d64 | ||
|
|
5e0fe575c9 | ||
|
|
11957b62bb | ||
|
|
edd113548a | ||
|
|
5383b4809f | ||
|
|
083b6e2bbe | ||
|
|
859bb81b29 | ||
|
|
ca480948aa | ||
|
|
f01e5bee92 | ||
|
|
d1cdcc5760 | ||
|
|
fa795ff4cd | ||
|
|
bd766067ac | ||
|
|
b3a1fc65e5 | ||
|
|
2063af8ac6 | ||
|
|
0aaf961f17 | ||
|
|
067662b304 | ||
|
|
8b85a3be23 | ||
|
|
43bb74cb13 | ||
|
|
6f3fdb6ae6 | ||
|
|
8736a41cfb | ||
|
|
803fa35484 | ||
|
|
ecb11b3a4c | ||
|
|
85a811db55 | ||
|
|
63632f1137 | ||
|
|
42d6fe209c | ||
|
|
9c8fcfb723 | ||
|
|
3bd38bd1fd | ||
|
|
2b2c7d7f9f | ||
|
|
41fa61b446 | ||
|
|
5c318932c2 | ||
|
|
7cb408838f | ||
|
|
c3930f235a | ||
|
|
18a69b8c48 | ||
|
|
4b10c39ca0 | ||
|
|
4ceeddc09f | ||
|
|
498742d6b3 | ||
|
|
4cc8008cfc | ||
|
|
bf5b9e70bb | ||
|
|
b23fa34470 | ||
|
|
f937f971c1 | ||
|
|
9727717839 | ||
|
|
a7f059d951 | ||
|
|
1d6803b234 | ||
|
|
1c09dede1a | ||
|
|
65f125a245 | ||
|
|
14df9a58c7 | ||
|
|
dc9c2673d7 | ||
|
|
24acd74d15 | ||
|
|
577012370e | ||
|
|
3af83f1c97 | ||
|
|
33092e6324 | ||
|
|
2bd44612fd | ||
|
|
a106956cfe | ||
|
|
2f7718265a | ||
|
|
f3125358c0 | ||
|
|
0df058dc1e | ||
|
|
7b9ad5001b | ||
|
|
e8f8100e19 | ||
|
|
6961162636 | ||
|
|
28c009fcc0 | ||
|
|
d2e1705c80 | ||
|
|
0adf775d9a | ||
|
|
7f89cd0774 | ||
|
|
93df164485 | ||
|
|
7b08a93549 | ||
|
|
a538e47994 | ||
|
|
3136f833a5 | ||
|
|
58708d6242 | ||
|
|
a9c13359dc | ||
|
|
08b8f2df55 | ||
|
|
cd19d7c705 | ||
|
|
b2a735ef4f | ||
|
|
cb78e4875b | ||
|
|
06075c4499 | ||
|
|
603060f051 | ||
|
|
91414dde62 | ||
|
|
c9926bed9f | ||
|
|
5c6d418b59 | ||
|
|
dc8b583363 | ||
|
|
da21d6cdda | ||
|
|
e4214a6cbe | ||
|
|
04cce89fdc | ||
|
|
60f539789d | ||
|
|
2e487adf8a | ||
|
|
7bad679a69 | ||
|
|
29a85bc928 | ||
|
|
541b369175 | ||
|
|
ce20f45a45 | ||
|
|
b429dafa38 | ||
|
|
9292c7ec53 | ||
|
|
42da83f8ca | ||
|
|
b6fb016a9a | ||
|
|
77a26882a3 | ||
|
|
c5914516c8 | ||
|
|
ca8f45a501 | ||
|
|
8719e9f098 | ||
|
|
fe9069c028 | ||
|
|
85ef4c6d91 | ||
|
|
e2d5aaf0f3 | ||
|
|
eed54a18c4 | ||
|
|
7a3efd1543 | ||
|
|
abecde0572 | ||
|
|
ada9dfdc5e | ||
|
|
0317189213 | ||
|
|
1130ccf69b | ||
|
|
d8f2183b3d | ||
|
|
e64e9995b6 | ||
|
|
13fc080213 | ||
|
|
6feff1d6e8 | ||
|
|
6cd308f9ad | ||
|
|
83a290a411 | ||
|
|
d4350079c9 | ||
|
|
56979804ec | ||
|
|
68314dbc05 | ||
|
|
b53e41af42 | ||
|
|
17f4e53d6b | ||
|
|
08845c9903 | ||
|
|
beb06c0787 | ||
|
|
c72e0c1508 | ||
|
|
b635962d2b | ||
|
|
166fb476a3 | ||
|
|
0c9e106502 | ||
|
|
3230048f81 | ||
|
|
52cbec2438 | ||
|
|
bb04b22ec8 | ||
|
|
fc920ffd06 | ||
|
|
c9dca6b8ad | ||
|
|
246c808222 | ||
|
|
a431aa8c4a | ||
|
|
46b775bf46 | ||
|
|
5f6f117bad | ||
|
|
c2d9e082cb | ||
|
|
4db34ff092 | ||
|
|
d4880b135a | ||
|
|
bccaf56200 | ||
|
|
06811cc557 | ||
|
|
3c1c5a4099 | ||
|
|
1e8bdc15e2 | ||
|
|
ffd43c1886 | ||
|
|
c0f2a7b44a | ||
|
|
f129622446 | ||
|
|
042f84140d | ||
|
|
135454342d | ||
|
|
f7bc5481f3 | ||
|
|
424f9aeae6 | ||
|
|
d54148de4e | ||
|
|
0e6100ae17 | ||
|
|
8d1ff1c59a | ||
|
|
c38f66cc1b | ||
|
|
7593bec687 | ||
|
|
e8935232b1 | ||
|
|
7e1adfcab7 | ||
|
|
98df153750 | ||
|
|
491a00fd84 | ||
|
|
aaa8aec946 | ||
|
|
b58ceae69c | ||
|
|
43e118fe45 | ||
|
|
36a51bbf4d | ||
|
|
c1cad655c8 | ||
|
|
e7649a800a | ||
|
|
75f32afcd5 | ||
|
|
f93121b226 | ||
|
|
b1e707d535 | ||
|
|
7c0f7329d9 | ||
|
|
508b614769 | ||
|
|
9b364d5be3 | ||
|
|
9038987e1d | ||
|
|
1672fd22e1 | ||
|
|
3fc5d51a96 | ||
|
|
577c0042b0 | ||
|
|
db5a429948 | ||
|
|
87802b2c17 | ||
|
|
66846bff97 | ||
|
|
67f0eb7b3b | ||
|
|
61a93c711c | ||
|
|
f9c3123f5f | ||
|
|
1cd53768ab | ||
|
|
b7ebee985b | ||
|
|
42f51850cc | ||
|
|
463260b249 | ||
|
|
f8048977ac | ||
|
|
1e9942c1bf | ||
|
|
4119da607f | ||
|
|
9f3cfa2dbd | ||
|
|
44f91e12e1 | ||
|
|
306b627090 | ||
|
|
90e7d7e112 | ||
|
|
7be79613b8 | ||
|
|
05035eb1e3 | ||
|
|
cf12d31875 | ||
|
|
32f92f7a90 | ||
|
|
392f4b44f0 | ||
|
|
a65ab1d5a7 | ||
|
|
57537ea10e | ||
|
|
51cbd977f0 | ||
|
|
392e88db34 | ||
|
|
0a0897ef28 | ||
|
|
5b193bad4b | ||
|
|
c647b0c65e | ||
|
|
9193720789 | ||
|
|
3208a77bf3 | ||
|
|
cbda307ebf | ||
|
|
0358862066 | ||
|
|
d901504ea9 | ||
|
|
4dc74776c1 | ||
|
|
71f13620d3 | ||
|
|
a914d3c534 | ||
|
|
242a55aa60 | ||
|
|
9045171ad7 | ||
|
|
e5797a57a7 | ||
|
|
3a571bbdb4 | ||
|
|
f40cc5ab54 | ||
|
|
60e614b10c | ||
|
|
f57b619097 | ||
|
|
8763e8ee35 | ||
|
|
5030db000a | ||
|
|
4c9d432bd9 | ||
|
|
1ad95eca4a | ||
|
|
7b8dc38e88 | ||
|
|
bce7d37086 | ||
|
|
13b9b5c0c0 | ||
|
|
cf6e3ca087 | ||
|
|
b79e61db1d | ||
|
|
bdf3552be6 | ||
|
|
26220f2b31 | ||
|
|
f2a1f0124d | ||
|
|
2b510d7a06 | ||
|
|
d07529feca | ||
|
|
6381f28847 | ||
|
|
af99e65876 | ||
|
|
6fa9249062 | ||
|
|
06d782279c | ||
|
|
88616df2e5 | ||
|
|
c51ac6048d | ||
|
|
30abdbccf8 | ||
|
|
66df065e31 | ||
|
|
ed25941c65 | ||
|
|
2c7787900f | ||
|
|
9308c96f95 | ||
|
|
4ffb6c5f75 | ||
|
|
b5ba8699f3 | ||
|
|
19ac2179fb | ||
|
|
1e6d51642c | ||
|
|
878813f968 | ||
|
|
d7e5855ebf | ||
|
|
a48219ecf2 | ||
|
|
995dccc726 | ||
|
|
0572b395ba | ||
|
|
6e08682a7f | ||
|
|
000ea8febd | ||
|
|
b02691cebd | ||
|
|
909fc98e1b | ||
|
|
53d138505a | ||
|
|
e655222d2f | ||
|
|
d096fc8acf | ||
|
|
48be4e765a | ||
|
|
841763326a | ||
|
|
2ed2aedb00 | ||
|
|
767a178bd1 | ||
|
|
ec610cd97b | ||
|
|
e027ba9c47 | ||
|
|
d350134c4f | ||
|
|
b8a58d0fce | ||
|
|
1d25d58c26 | ||
|
|
c85b159d46 | ||
|
|
77d4927e8b | ||
|
|
2bd8877be3 | ||
|
|
242e097e9b | ||
|
|
443c30890b | ||
|
|
6326c6727e | ||
|
|
61e606bedc | ||
|
|
bedb8ca191 | ||
|
|
35eea8bea5 | ||
|
|
66827755e7 | ||
|
|
85ef1ee21f | ||
|
|
e5d4574d3a | ||
|
|
a1347f67a1 | ||
|
|
c9da806c84 | ||
|
|
a45b1625fc | ||
|
|
1761d5da06 | ||
|
|
63749e281d | ||
|
|
11ac780caf | ||
|
|
31eb83223b | ||
|
|
7062a6e55d | ||
|
|
5e6b683cfb | ||
|
|
8e1945f768 | ||
|
|
0ae12c2b3d | ||
|
|
54563dc94c | ||
|
|
f81e4ec972 | ||
|
|
d7aa0b0ddb | ||
|
|
e098f414e4 | ||
|
|
f8f21815eb | ||
|
|
80e6a64e47 | ||
|
|
bb71b09452 | ||
|
|
4342480473 | ||
|
|
0b205019b6 | ||
|
|
ee519b7552 | ||
|
|
fae918be59 | ||
|
|
b77fe4ca12 | ||
|
|
3a0de7e24a | ||
|
|
44572dce7d | ||
|
|
ba6f01a109 | ||
|
|
9f55e162a3 | ||
|
|
d51a8accee | ||
|
|
cd411a5c36 | ||
|
|
fe7c827e30 | ||
|
|
cc80930e2b | ||
|
|
d20ce404ef | ||
|
|
2d269fb7f1 | ||
|
|
15bfb86eec | ||
|
|
8c5bb5969c | ||
|
|
a337b12877 | ||
|
|
4e05d24d1b | ||
|
|
5c94e23004 | ||
|
|
587c49f6b1 | ||
|
|
211688453c | ||
|
|
5e7a45d6da | ||
|
|
f72c72f4d4 | ||
|
|
028bab0320 | ||
|
|
ee2168b94d | ||
|
|
c4de658964 | ||
|
|
9fcf7eb27c | ||
|
|
6131a523dc | ||
|
|
93e40ee79c | ||
|
|
150a4797a4 | ||
|
|
745fa707dd | ||
|
|
09b93aa164 | ||
|
|
1bb042a661 | ||
|
|
32ad59de26 | ||
|
|
d594092675 | ||
|
|
7570ec9d39 | ||
|
|
3f73e000ee | ||
|
|
7df5182901 | ||
|
|
7c1c8f323c | ||
|
|
68d35dbeb1 | ||
|
|
7a163ef0cc | ||
|
|
b77467ca8f | ||
|
|
e8ec1a6ed4 | ||
|
|
bf2b6b3ac4 | ||
|
|
56581b416d | ||
|
|
a2f178b664 | ||
|
|
01ca3ae07f | ||
|
|
cc6803b358 | ||
|
|
33394f76d4 | ||
|
|
f0048d54b0 | ||
|
|
0cc1ebc021 | ||
|
|
3ad1cccb1d | ||
|
|
9f895879bf | ||
|
|
9db9ffd3e4 | ||
|
|
0ca53420d5 | ||
|
|
6932a42b0a | ||
|
|
b1e6845409 | ||
|
|
96f1a25bbd | ||
|
|
e7bb553d3b | ||
|
|
7f2c4a9e06 | ||
|
|
c620d0de05 | ||
|
|
04430c6dda | ||
|
|
0dfadf7c09 | ||
|
|
911e266e9a | ||
|
|
223942bf99 | ||
|
|
94f46c9059 | ||
|
|
fc443a8c2c | ||
|
|
e05f6102c2 | ||
|
|
d2d4b4cc23 | ||
|
|
c1c8f7b0f1 | ||
|
|
2353fdb400 | ||
|
|
e81cf74b39 | ||
|
|
e096b5ce83 | ||
|
|
3de008035a | ||
|
|
f026bbb454 | ||
|
|
5ef4caf8ab | ||
|
|
7788b33dc9 | ||
|
|
d9d557dcc5 | ||
|
|
2915617c5c | ||
|
|
0f34967648 | ||
|
|
0c9ada08a4 | ||
|
|
89246f3714 | ||
|
|
24913a5ef9 | ||
|
|
2289d085fa | ||
|
|
945fef8a5a | ||
|
|
928d2f78c3 | ||
|
|
04373b8658 | ||
|
|
044a3a29a6 | ||
|
|
2e747e72cf | ||
|
|
494000114c | ||
|
|
415f1ca3a4 | ||
|
|
750f59cb55 | ||
|
|
18589a498c | ||
|
|
15b0878a17 | ||
|
|
05c50b0a2e | ||
|
|
8062962d01 | ||
|
|
31bf873c20 | ||
|
|
6e85f82d7a | ||
|
|
c932871bb1 | ||
|
|
3c6a7c332a | ||
|
|
d45788a7b8 | ||
|
|
f49f7d65a5 | ||
|
|
9b6f9a0b18 | ||
|
|
afe033a6e1 | ||
|
|
4753ada7a9 | ||
|
|
5217718d7b | ||
|
|
ea42851c9b | ||
|
|
91e11f8e6f | ||
|
|
3545280e1d | ||
|
|
c70508edb1 | ||
|
|
de4cb9022b | ||
|
|
dfd90c3526 | ||
|
|
ff97817668 | ||
|
|
741dc1eb0b | ||
|
|
c33c21e174 | ||
|
|
75feb495ad | ||
|
|
2abde14a7c | ||
|
|
aeb568b41f | ||
|
|
e1ddd3bdbc | ||
|
|
f3f6bedf8e | ||
|
|
42a2126273 | ||
|
|
d87ea5713d | ||
|
|
5940231b76 | ||
|
|
d54cb307d5 | ||
|
|
2bb26b30dc | ||
|
|
696c7d59fd | ||
|
|
d27f7c25b3 | ||
|
|
5843c98153 | ||
|
|
d552c97599 | ||
|
|
a99280398b | ||
|
|
cb7f8e256e | ||
|
|
d621471eb2 | ||
|
|
ec587032b2 | ||
|
|
df098c2b2b | ||
|
|
5b5c4787e9 | ||
|
|
c4cfb3e711 | ||
|
|
b4075bed87 | ||
|
|
b7119b5756 | ||
|
|
4147fa4629 | ||
|
|
0ab83b301d | ||
|
|
ecbeb0d117 | ||
|
|
f928a399ae | ||
|
|
28900a9b63 | ||
|
|
fb6a4febb0 | ||
|
|
27fd2dad59 | ||
|
|
639f445f5e | ||
|
|
fa8649e671 | ||
|
|
fa444dd029 | ||
|
|
ba5fe1d161 | ||
|
|
9cfadbe6af | ||
|
|
16499358b3 | ||
|
|
d86724f17a | ||
|
|
26e6f2c46c | ||
|
|
0bcc5d37ab | ||
|
|
564ca27679 | ||
|
|
9fecf4b2f7 | ||
|
|
800ba9a325 | ||
|
|
b277353238 | ||
|
|
5eb4b9ad6f | ||
|
|
8ebab10cb0 | ||
|
|
fc99785314 | ||
|
|
af92a639be | ||
|
|
e1a232e7c8 | ||
|
|
6bf2ec4188 | ||
|
|
af329a9429 | ||
|
|
07840906dd | ||
|
|
ff023115f5 | ||
|
|
33dd5e26fb | ||
|
|
77a1c5d7fc | ||
|
|
9483f0fc14 | ||
|
|
c23b4a48ec | ||
|
|
76efee675f | ||
|
|
f6ac00532f | ||
|
|
a870799c32 | ||
|
|
787675ab08 | ||
|
|
ac55c358e9 | ||
|
|
53b0698ee2 | ||
|
|
073583ff3d | ||
|
|
19a7c7ac39 | ||
|
|
0d69738bd6 | ||
|
|
0301961c25 | ||
|
|
e18cdc185a | ||
|
|
d0c91daaed | ||
|
|
dc7cc6921e | ||
|
|
dae63d323c | ||
|
|
a19a229a59 | ||
|
|
589585a269 | ||
|
|
432b912c6a | ||
|
|
5819acfd3d | ||
|
|
0d312f3674 | ||
|
|
64c8ff62af | ||
|
|
2048a1a638 | ||
|
|
c34fb146f6 | ||
|
|
c39f5f1fad | ||
|
|
9a7d8a0511 | ||
|
|
6bded6bf7b | ||
|
|
fa4d52f042 | ||
|
|
618f8a9d06 | ||
|
|
ddb1d92c77 | ||
|
|
1cb13be65f | ||
|
|
d6bab3043c | ||
|
|
e66341ec59 | ||
|
|
a01abd0fee | ||
|
|
2d771674bb | ||
|
|
74cb673ce1 | ||
|
|
b9f0131165 | ||
|
|
13d363d1f1 | ||
|
|
9f60673e4b | ||
|
|
549c30f9b2 | ||
|
|
59cadf9e4b | ||
|
|
bca71fcfc1 | ||
|
|
1430faa2fd | ||
|
|
8493d5707e | ||
|
|
92d0772eba | ||
|
|
6ebd00267e | ||
|
|
894bcdf749 | ||
|
|
f256967414 | ||
|
|
64c447bf04 | ||
|
|
2c56b67ea5 | ||
|
|
10ab870237 | ||
|
|
cc9771a3d0 | ||
|
|
e6733b4b23 | ||
|
|
0694334487 | ||
|
|
c51e3c2882 | ||
|
|
6442e6b5e8 | ||
|
|
38342fbe48 | ||
|
|
f293e1422b | ||
|
|
20325b9952 | ||
|
|
c265ea21c2 | ||
|
|
fbfd781426 | ||
|
|
195cb91721 | ||
|
|
511e82de67 | ||
|
|
8e9b98360a | ||
|
|
6ba3ee3950 | ||
|
|
54bd60d657 | ||
|
|
4fb800a899 | ||
|
|
a81ea1ffde | ||
|
|
c56d8b4fe9 | ||
|
|
5bb7b4bb42 | ||
|
|
4b1e2b42a4 | ||
|
|
c784968e85 | ||
|
|
6b010614e2 | ||
|
|
14eea98566 | ||
|
|
c2ab4f711f | ||
|
|
1630f14b99 | ||
|
|
64d9e5b861 | ||
|
|
346a4bee0b | ||
|
|
db0aeaa26e | ||
|
|
7cd64f1bd1 | ||
|
|
5978775ce1 | ||
|
|
a936430fd5 | ||
|
|
b54804d449 | ||
|
|
74c970c25f | ||
|
|
8fe675e56c | ||
|
|
cc666c727f | ||
|
|
178b39b5a8 | ||
|
|
6c201fcae4 | ||
|
|
39a366cf76 | ||
|
|
0550a4a9b8 | ||
|
|
7f4b74f8c6 | ||
|
|
e58ba1dc8e | ||
|
|
f0f17fffd8 | ||
|
|
4febbec102 | ||
|
|
b2f3625eaa | ||
|
|
593ae7bf0e | ||
|
|
5510d8cfb1 | ||
|
|
68e0fbfd60 | ||
|
|
9337e29482 | ||
|
|
56233054ae | ||
|
|
6e6b097968 | ||
|
|
a7bae32527 | ||
|
|
c6918966c2 | ||
|
|
93a8e75238 | ||
|
|
66a5ac4d67 | ||
|
|
e1c4962312 | ||
|
|
55f2b524e7 | ||
|
|
75b2915fee | ||
|
|
6a285e2e76 | ||
|
|
c4634f7e98 | ||
|
|
87d4666648 | ||
|
|
deb7ccbef3 | ||
|
|
bb153ee79e | ||
|
|
dc43dc2a13 | ||
|
|
65eb4e1994 | ||
|
|
6717f0d2bb | ||
|
|
6a93052f7d | ||
|
|
7ecac42214 | ||
|
|
fdfbf3abfa | ||
|
|
a44c2d5dcc | ||
|
|
f984bd2ff5 | ||
|
|
eca7ff986c | ||
|
|
bf07c5aebd | ||
|
|
e64d4e5bd7 | ||
|
|
15d2cfe458 | ||
|
|
88b3109137 | ||
|
|
5cb58cd42f | ||
|
|
485b9099f1 | ||
|
|
cd5cd25f74 | ||
|
|
18e7354b4a | ||
|
|
9605e6cb40 | ||
|
|
d3f30e7a9c | ||
|
|
1f604c0826 | ||
|
|
2bfc2be8c9 | ||
|
|
d233fc044a | ||
|
|
b4428e7e41 | ||
|
|
8b55e6e2f5 | ||
|
|
94ab1c790f | ||
|
|
de67e42fc9 | ||
|
|
136857952e | ||
|
|
cd42133651 | ||
|
|
0c93e4b8d7 | ||
|
|
f954b60119 | ||
|
|
565ece6986 | ||
|
|
f0680587fa | ||
|
|
f17bd040ad | ||
|
|
b1011768e5 | ||
|
|
b6787dbbb3 | ||
|
|
1731359a17 | ||
|
|
f2c0d1f0c5 | ||
|
|
db081d95d5 | ||
|
|
a50e36d256 | ||
|
|
6c60c6ca76 | ||
|
|
2c1984b6ed | ||
|
|
dede3d6213 | ||
|
|
70fd42808e | ||
|
|
19323c88f9 | ||
|
|
c0331673da | ||
|
|
eeb2e58ad8 | ||
|
|
39c2a4721b | ||
|
|
94dd068e15 | ||
|
|
8695672082 | ||
|
|
15db4ee450 | ||
|
|
81f7b422e4 | ||
|
|
766b604de5 | ||
|
|
ac6a44f0ac | ||
|
|
2b9b186fd1 | ||
|
|
0cfae1cc2b | ||
|
|
340431750b | ||
|
|
4bc4a0c45b | ||
|
|
01f549628f | ||
|
|
9c552644d8 | ||
|
|
f6792c0232 | ||
|
|
ecff620528 | ||
|
|
f908678e8e | ||
|
|
32121b9c38 | ||
|
|
c4d1fb929c | ||
|
|
65908bbb87 | ||
|
|
44481db1ee | ||
|
|
5543bfc278 | ||
|
|
d4bbd7c7ab | ||
|
|
814702f5b8 | ||
|
|
6191e6e787 | ||
|
|
9120774c00 | ||
|
|
78c87d4bd3 | ||
|
|
5f82168213 | ||
|
|
a84d49fe5c | ||
|
|
2ec223ba11 | ||
|
|
35b2bc6b51 | ||
|
|
68250d80cd | ||
|
|
2edf4da859 | ||
|
|
7741a0e6ad | ||
|
|
25c0cf0612 | ||
|
|
9487222726 | ||
|
|
60b363fa3b | ||
|
|
90fbe5c06c | ||
|
|
7226adee29 | ||
|
|
27c1612f44 | ||
|
|
fb6759b5e0 | ||
|
|
eabbac4ca1 | ||
|
|
d943519fb4 | ||
|
|
9d2aa6f1c7 | ||
|
|
9f8f95f4c9 | ||
|
|
924a345fac | ||
|
|
59238a915e | ||
|
|
03d15809be | ||
|
|
778772710a | ||
|
|
fb02343ec0 | ||
|
|
dc6e451010 | ||
|
|
1f71a2e94c | ||
|
|
b407834ed7 | ||
|
|
f1036f7305 | ||
|
|
c3e0e4682d | ||
|
|
a0fd37c8a3 | ||
|
|
23b35af7f2 | ||
|
|
ddefc08ec5 | ||
|
|
f79a90161c | ||
|
|
29dc06c89d | ||
|
|
5737f8b74e | ||
|
|
bbd1b325fb | ||
|
|
152d573fbd | ||
|
|
adaec2d32b | ||
|
|
b6f0d04813 | ||
|
|
fe0a96200d | ||
|
|
c6ba812d79 | ||
|
|
6ab0a8a287 | ||
|
|
90ec61fbe9 | ||
|
|
ba0c43e1fc | ||
|
|
1d10654a22 | ||
|
|
76d46ce509 | ||
|
|
5ef668de64 | ||
|
|
ca4a6e4692 | ||
|
|
1d132565c9 | ||
|
|
7d1a49db48 | ||
|
|
9945fc5148 | ||
|
|
ad33e569d6 | ||
|
|
34fff57646 | ||
|
|
4fc2b3e642 | ||
|
|
4bb95acc2b | ||
|
|
c7cf844bcd | ||
|
|
ba9b8719ac | ||
|
|
f4411889a9 | ||
|
|
627eb30409 | ||
|
|
b8b7d0ab1a | ||
|
|
45db999593 | ||
|
|
4d9f309888 | ||
|
|
e2fe95894f | ||
|
|
e16e1e2854 | ||
|
|
90574160db | ||
|
|
b997c2ffc1 | ||
|
|
f824b1e9d4 | ||
|
|
48821a6d2a | ||
|
|
d09cab2e21 | ||
|
|
ffbb16e854 | ||
|
|
30fafc2772 | ||
|
|
9b8a77f0d8 | ||
|
|
d322769de8 | ||
|
|
faaeab7e4a | ||
|
|
567646e624 | ||
|
|
adddff3ee2 | ||
|
|
99e57f9072 | ||
|
|
6415f181ca | ||
|
|
bd971b6371 | ||
|
|
0adc887b32 | ||
|
|
7c7300ff82 | ||
|
|
bda5e4efcb | ||
|
|
cc350efbd8 | ||
|
|
49fbb52b01 | ||
|
|
3d700ee49f | ||
|
|
c7f2e2731c | ||
|
|
1126719e7f | ||
|
|
a20f633272 | ||
|
|
fb7bd8f11e | ||
|
|
7a4ca08a8d | ||
|
|
3939359354 | ||
|
|
1709b8e39d | ||
|
|
a419fe75ca | ||
|
|
4ba4fe4f62 | ||
|
|
3062027bab | ||
|
|
78f11df6e4 | ||
|
|
3405596983 | ||
|
|
d6fbf5f1bb | ||
|
|
6d16eb81d2 | ||
|
|
6a872dd938 | ||
|
|
796664ef1c | ||
|
|
10f2c80162 | ||
|
|
3d33da7696 | ||
|
|
60c0bf1636 | ||
|
|
646a8eb753 | ||
|
|
8a2c35023f | ||
|
|
ba5fa2c8b1 | ||
|
|
235ae0989f | ||
|
|
837a34cf71 | ||
|
|
01f31edb95 | ||
|
|
cfe914ff83 | ||
|
|
06f4c1b337 | ||
|
|
3815ed8af4 | ||
|
|
c1a40fbd98 | ||
|
|
bb1627a69b | ||
|
|
ad90de0c82 | ||
|
|
0cd99d9815 | ||
|
|
6956f2fc69 | ||
|
|
fd6aeda6f6 | ||
|
|
b4bb00843b | ||
|
|
4c48908a31 | ||
|
|
404589d9b5 | ||
|
|
d913b53fea | ||
|
|
c6289ef219 | ||
|
|
47d652b5a2 | ||
|
|
7bfece1144 | ||
|
|
a55015d63d | ||
|
|
a5dfb09037 | ||
|
|
ae5c8e63d9 | ||
|
|
ebe058e7cb | ||
|
|
96dd9b9ab8 | ||
|
|
fdd0d67fd3 | ||
|
|
a16c4167eb | ||
|
|
1a6f0ae437 | ||
|
|
df66223f4c | ||
|
|
39c46a9b75 | ||
|
|
e6abfa959a | ||
|
|
a8759a3176 | ||
|
|
0736de1e8d | ||
|
|
12dbcfa2ea | ||
|
|
a84fa0eecb | ||
|
|
517184b89b | ||
|
|
5f2dd2ef6c | ||
|
|
1b8963ff6e |
@@ -3,10 +3,67 @@ version: 2
|
||||
jobs:
|
||||
electron-linux-arm:
|
||||
docker:
|
||||
- image: electronbuilds/electron:0.0.4
|
||||
- image: electronbuilds/electron:0.0.3
|
||||
environment:
|
||||
TARGET_ARCH: arm
|
||||
resource_class: 2xlarge
|
||||
resource_class: xlarge
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Check for release
|
||||
command: |
|
||||
if [ -n "${RUN_RELEASE_BUILD}" ]; then
|
||||
echo 'release build triggered from api'
|
||||
echo 'export ELECTRON_RELEASE=1 TRIGGERED_BY_API=1' >> $BASH_ENV
|
||||
fi
|
||||
- run:
|
||||
name: Bootstrap
|
||||
command: |
|
||||
if [ "$ELECTRON_RELEASE" == "1" ]; then
|
||||
echo 'Bootstrapping Electron for release build'
|
||||
script/bootstrap.py --target_arch=$TARGET_ARCH
|
||||
else
|
||||
echo 'Bootstrapping Electron for debug build'
|
||||
script/bootstrap.py --target_arch=$TARGET_ARCH --dev
|
||||
fi
|
||||
- run: npm run lint
|
||||
- run:
|
||||
name: Build
|
||||
command: |
|
||||
if [ "$ELECTRON_RELEASE" == "1" ]; then
|
||||
echo 'Building Electron for release'
|
||||
script/build.py -c R
|
||||
else
|
||||
echo 'Building Electron for debug'
|
||||
script/build.py -c D
|
||||
fi
|
||||
- run:
|
||||
name: Create distribution
|
||||
command: |
|
||||
if [ "$ELECTRON_RELEASE" == "1" ]; then
|
||||
echo 'Creating Electron release distribution'
|
||||
script/create-dist.py
|
||||
else
|
||||
echo 'Skipping create distribution because build is not for release'
|
||||
fi
|
||||
- run:
|
||||
name: Upload distribution
|
||||
command: |
|
||||
if [ "$ELECTRON_RELEASE" == "1" ] && [ "$TRIGGERED_BY_API" != "1" ]; then
|
||||
echo 'Uploading Electron release distribution to github releases'
|
||||
script/upload.py
|
||||
elif [ "$ELECTRON_RELEASE" == "1" ] && [ "$TRIGGERED_BY_API" == "1" ]; then
|
||||
echo 'Uploading Electron release distribution to s3'
|
||||
script/upload.py --upload_to_s3
|
||||
else
|
||||
echo 'Skipping upload distribution because build is not for release'
|
||||
fi
|
||||
electron-linux-arm64:
|
||||
docker:
|
||||
- image: electronbuilds/electron:0.0.3
|
||||
environment:
|
||||
TARGET_ARCH: arm64
|
||||
resource_class: xlarge
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
@@ -60,7 +117,7 @@ jobs:
|
||||
fi
|
||||
electron-linux-ia32:
|
||||
docker:
|
||||
- image: electronbuilds/electron:0.0.4
|
||||
- image: electronbuilds/electron:0.0.3
|
||||
environment:
|
||||
TARGET_ARCH: ia32
|
||||
resource_class: xlarge
|
||||
@@ -115,9 +172,67 @@ jobs:
|
||||
else
|
||||
echo 'Skipping upload distribution because build is not for release'
|
||||
fi
|
||||
electron-linux-mips64el:
|
||||
docker:
|
||||
- image: electronbuilds/electron:0.0.3
|
||||
environment:
|
||||
TARGET_ARCH: mips64el
|
||||
resource_class: xlarge
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Check for release
|
||||
command: |
|
||||
if [ -n "${RUN_RELEASE_BUILD}" ]; then
|
||||
echo 'release build triggered from api'
|
||||
echo 'export ELECTRON_RELEASE=1 TRIGGERED_BY_API=1' >> $BASH_ENV
|
||||
fi
|
||||
- run:
|
||||
name: Bootstrap
|
||||
command: |
|
||||
if [ "$ELECTRON_RELEASE" == "1" ]; then
|
||||
echo 'Bootstrapping Electron for release build'
|
||||
script/bootstrap.py --target_arch=$TARGET_ARCH
|
||||
else
|
||||
echo 'Bootstrapping Electron for debug build'
|
||||
script/bootstrap.py --target_arch=$TARGET_ARCH --dev
|
||||
fi
|
||||
- run: npm run lint
|
||||
- run:
|
||||
name: Build
|
||||
command: |
|
||||
if [ "$ELECTRON_RELEASE" == "1" ]; then
|
||||
echo 'Building Electron for release'
|
||||
script/build.py -c R
|
||||
else
|
||||
echo 'Building Electron for debug'
|
||||
script/build.py -c D
|
||||
fi
|
||||
- run:
|
||||
name: Create distribution
|
||||
command: |
|
||||
if [ "$ELECTRON_RELEASE" == "1" ]; then
|
||||
echo 'Creating Electron release distribution'
|
||||
script/create-dist.py
|
||||
else
|
||||
echo 'Skipping create distribution because build is not for release'
|
||||
fi
|
||||
- run:
|
||||
name: Upload distribution
|
||||
command: |
|
||||
if [ "$ELECTRON_RELEASE" == "1" ] && [ "$TRIGGERED_BY_API" != "1" ]; then
|
||||
echo 'Uploading Electron release distribution to github releases'
|
||||
script/upload.py
|
||||
elif [ "$ELECTRON_RELEASE" == "1" ] && [ "$TRIGGERED_BY_API" == "1" ]; then
|
||||
echo 'Uploading Electron release distribution to s3'
|
||||
script/upload.py --upload_to_s3
|
||||
else
|
||||
echo 'Skipping upload distribution because build is not for release'
|
||||
fi
|
||||
|
||||
electron-linux-x64:
|
||||
docker:
|
||||
- image: electronbuilds/electron:0.0.4
|
||||
- image: electronbuilds/electron:0.0.3
|
||||
environment:
|
||||
TARGET_ARCH: x64
|
||||
DISPLAY: ':99.0'
|
||||
@@ -215,6 +330,9 @@ workflows:
|
||||
build-arm:
|
||||
jobs:
|
||||
- electron-linux-arm
|
||||
build-arm64:
|
||||
jobs:
|
||||
- electron-linux-arm64
|
||||
build-ia32:
|
||||
jobs:
|
||||
- electron-linux-ia32
|
||||
|
||||
2
.dockerignore
Normal file
2
.dockerignore
Normal file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!tools/xvfb-init.sh
|
||||
21
.github/CODEOWNERS
vendored
Normal file
21
.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Order is important. The LAST matching pattern has the MOST precedence.
|
||||
# gitignore style patterns are used, not globs.
|
||||
# https://help.github.com/articles/about-codeowners
|
||||
# https://git-scm.com/docs/gitignore
|
||||
|
||||
# Everything that falls through the cracks:
|
||||
* @electron/reviewers
|
||||
|
||||
# filename patterns
|
||||
*browser_view* @electron/browserview
|
||||
*notification* @electron/notifications
|
||||
*pdf* @electron/printing
|
||||
*printing* @electron/printing
|
||||
*updater* @electron/updater
|
||||
|
||||
# directories
|
||||
/.github/ @electron/hubbers
|
||||
/default_app/ @electron/docs
|
||||
/docs/ @electron/docs
|
||||
/docs-translations/ @electron/i18n
|
||||
/npm/ @electron/hubbers
|
||||
29
.github/config.yml
vendored
Normal file
29
.github/config.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
# Configuration for new-issue-welcome - https://github.com/behaviorbot/new-issue-welcome
|
||||
|
||||
# Comment to be posted to on first time issues
|
||||
newIssueWelcomeComment: |
|
||||
👋 Thanks for opening your first issue here! If you're reporting a 🐞 bug, please make sure you include steps to reproduce it. We get a lot of issues on this repo, so please be patient and we will get back to you as soon as we can.
|
||||
|
||||
To help make it easier for us to investigate your issue, please follow the [contributing guidelines](https://github.com/electron/electron/blob/master/CONTRIBUTING.md#submitting-issues).
|
||||
|
||||
# Configuration for new-pr-welcome - https://github.com/behaviorbot/new-pr-welcome
|
||||
|
||||
# Comment to be posted to on PRs from first time contributors in your repository
|
||||
newPRWelcomeComment: |
|
||||
💖 Thanks for opening this pull request! 💖
|
||||
|
||||
Here is a list of things that will help get it across the finish line:
|
||||
- Follow the JavaScript, C++, and Python [coding style](https://github.com/electron/electron/blob/master/docs/development/coding-style.md).
|
||||
- Run `npm run lint` locally to catch formatting errors earlier.
|
||||
- Document any user-facing changes you've made following the [documentation styleguide](https://github.com/electron/electron/blob/master/docs/styleguide.md).
|
||||
- Include tests when adding/changing behavior.
|
||||
- Include screenshots and animated GIFs whenever possible.
|
||||
We get a lot of pull requests on this repo, so please be patient and we will get back to you as soon as we can.
|
||||
|
||||
# Configuration for first-pr-merge - https://github.com/behaviorbot/first-pr-merge
|
||||
|
||||
# Comment to be posted to on pull requests merged by a first time user
|
||||
firstPRMergeComment: >
|
||||
Congrats on merging your first pull request! 🎉🎉🎉
|
||||
|
||||
# It is recommend to include as many gifs and emojis as possiblec
|
||||
25
.github/stale.yml
vendored
Normal file
25
.github/stale.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 45
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 7
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- fixme/bug
|
||||
- fixme/crash
|
||||
- fixme/regression
|
||||
- fixme/security
|
||||
- blocked
|
||||
- blocking-stable
|
||||
- needs-review
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: stale
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity and is not currently prioritized. It will be closed
|
||||
in a week if no further activity occurs :)
|
||||
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: >
|
||||
If you still think this issue is relevant, please ping a maintainer or
|
||||
leave a comment!
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,5 +1,6 @@
|
||||
.DS_Store
|
||||
.env
|
||||
.gclient_done
|
||||
.npmrc
|
||||
.tags*
|
||||
.vs/
|
||||
@@ -14,7 +15,6 @@
|
||||
*.vcxproj.filters
|
||||
*.vcxproj.user
|
||||
*.xcodeproj
|
||||
node_modules/
|
||||
/.idea/
|
||||
/brightray/brightray.opensdf
|
||||
/brightray/brightray.sdf
|
||||
@@ -32,12 +32,17 @@ node_modules/
|
||||
/vendor/debian_jessie_arm-sysroot/
|
||||
/vendor/debian_jessie_arm64-sysroot/
|
||||
/vendor/debian_jessie_i386-sysroot/
|
||||
/vendor/debian_jessie_mips64-sysroot/
|
||||
/vendor/debian_wheezy_amd64-sysroot/
|
||||
/vendor/debian_wheezy_arm-sysroot/
|
||||
/vendor/debian_wheezy_i386-sysroot/
|
||||
/vendor/gcc-4.8.3-d197-n64-loongson/
|
||||
/vendor/readme-gcc483-loongson.txt
|
||||
/vendor/download/
|
||||
/vendor/llvm-build/
|
||||
/vendor/llvm/
|
||||
/vendor/node/deps/node-inspect/.npmrc
|
||||
/vendor/npm/
|
||||
/vendor/python_26/
|
||||
node_modules/
|
||||
SHASUMS256.txt
|
||||
|
||||
@@ -1 +1 @@
|
||||
v7.9.0
|
||||
v8.2.1
|
||||
|
||||
6
.remarkrc
Normal file
6
.remarkrc
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"plugins": [
|
||||
["remark-lint-code-block-style", "fenced"],
|
||||
["remark-lint-fenced-code-flag"]
|
||||
]
|
||||
}
|
||||
@@ -5,7 +5,7 @@ notifications:
|
||||
|
||||
before_install:
|
||||
- export BOTO_CONFIG=/dev/null
|
||||
|
||||
|
||||
language: node_js
|
||||
node_js:
|
||||
- "4"
|
||||
@@ -22,6 +22,8 @@ matrix:
|
||||
env: TARGET_ARCH=arm
|
||||
- os: linux
|
||||
env: TARGET_ARCH=ia32
|
||||
- os: linux
|
||||
env: TARGET_ARCH=arm64
|
||||
allow_failures:
|
||||
- os: osx
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
# Contributor Covenant Code of Conduct:
|
||||
|
||||
## Our Pledge
|
||||
|
||||
@@ -40,7 +40,7 @@ Project maintainers who do not follow or enforce the Code of Conduct in good fai
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||
This Code of Conduct is adapted from the [Contributor-Covenant][homepage], version 1.4, available at [https://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
[homepage]: https://contributor-covenant.org
|
||||
[version]: https://contributor-covenant.org/version/1/4/
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
# Contributing to Electron
|
||||
|
||||
:memo: Available Translations: [Korean](https://github.com/electron/electron/tree/master/docs-translations/ko-KR/project/CONTRIBUTING.md) | [Simplified Chinese](https://github.com/electron/electron/tree/master/docs-translations/zh-CN/project/CONTRIBUTING.md) | [Brazilian Portuguese](https://github.com/electron/electron/tree/master/docs-translations/pt-BR/project/CONTRIBUTING.md) | [Dutch](https://github.com/electron/electron/tree/master/docs-translations/nl/project/CONTRIBUTING.md)
|
||||
|
||||
:+1::tada: First off, thanks for taking the time to contribute! :tada::+1:
|
||||
|
||||
This project adheres to the Contributor Covenant [code of conduct](CODE_OF_CONDUCT.md).
|
||||
@@ -14,6 +12,7 @@ propose changes to this document in a pull request.
|
||||
|
||||
## Submitting Issues
|
||||
|
||||
### Creating Issues
|
||||
* You can create an issue [here](https://github.com/electron/electron/issues/new),
|
||||
but before doing that please read the notes below and include as many details as
|
||||
possible with your report. If you can, please include:
|
||||
@@ -27,6 +26,15 @@ possible with your report. If you can, please include:
|
||||
* Perform a [cursory search](https://github.com/electron/electron/issues?utf8=✓&q=is%3Aissue+)
|
||||
to see if a similar issue has already been submitted
|
||||
|
||||
### Issue Maintenance and Closure
|
||||
* If an issue is inactive for 45 days (no activity of any kind), it will be
|
||||
marked for closure with `stale`.
|
||||
* If after this label is applied, no further activity occurs in the next 7 days,
|
||||
the issue will be closed.
|
||||
* If an issue has been closed and you still feel it's relevant, feel free to
|
||||
ping a maintainer or add a comment!
|
||||
|
||||
|
||||
## Submitting Pull Requests
|
||||
|
||||
* Include screenshots and animated GIFs in your pull request whenever possible.
|
||||
|
||||
18
Dockerfile
Normal file
18
Dockerfile
Normal file
@@ -0,0 +1,18 @@
|
||||
FROM electronbuilds/libchromiumcontent:0.0.4
|
||||
|
||||
USER root
|
||||
|
||||
# Set up HOME directory
|
||||
ENV HOME=/home
|
||||
RUN chmod a+rwx /home
|
||||
|
||||
# Install node.js
|
||||
RUN curl -sL https://deb.nodesource.com/setup_6.x | bash -
|
||||
RUN apt-get update && apt-get install -y --force-yes nodejs
|
||||
|
||||
# Install wget used by crash reporter
|
||||
RUN apt-get install -y --force-yes wget
|
||||
|
||||
# Add xvfb init script
|
||||
ADD tools/xvfb-init.sh /etc/init.d/xvfb
|
||||
RUN chmod a+x /etc/init.d/xvfb
|
||||
17
Dockerfile.circleci
Normal file
17
Dockerfile.circleci
Normal file
@@ -0,0 +1,17 @@
|
||||
FROM electronbuilds/libchromiumcontent:0.0.4
|
||||
|
||||
USER root
|
||||
|
||||
# Install node.js
|
||||
RUN curl -sL https://deb.nodesource.com/setup_6.x | bash -
|
||||
RUN apt-get update && apt-get install -y --force-yes nodejs
|
||||
|
||||
# Install wget used by crash reporter
|
||||
RUN apt-get install -y --force-yes wget
|
||||
|
||||
# Add xvfb init script
|
||||
ADD tools/xvfb-init.sh /etc/init.d/xvfb
|
||||
RUN chmod a+x /etc/init.d/xvfb
|
||||
|
||||
USER builduser
|
||||
WORKDIR /home/builduser
|
||||
50
README.md
50
README.md
@@ -1,21 +1,22 @@
|
||||
[](https://electron.atom.io/)
|
||||
[](https://electronjs.org)
|
||||
|
||||
[](https://travis-ci.org/electron/electron)
|
||||
[](https://ci.appveyor.com/project/electron-bot/electron/branch/master)
|
||||
[](https://david-dm.org/electron/electron?type=dev)
|
||||
[](http://atom-slack.herokuapp.com/)
|
||||
[](https://atom-slack.herokuapp.com/)
|
||||
|
||||
:memo: Available Translations: [Korean](https://github.com/electron/electron/tree/master/docs-translations/ko-KR/project/README.md) | [Simplified Chinese](https://github.com/electron/electron/tree/master/docs-translations/zh-CN/project/README.md) | [Brazilian Portuguese](https://github.com/electron/electron/tree/master/docs-translations/pt-BR/project/README.md) | [Traditional Chinese](https://github.com/electron/electron/tree/master/docs-translations/zh-TW/project/README.md) | [Spanish](https://github.com/electron/electron/tree/master/docs-translations/es/project/README.md) | [Turkish](https://github.com/electron/electron/tree/master/docs-translations/tr-TR/project/README.md) | [German](https://github.com/electron/electron/tree/master/docs-translations/de-DE/project/README.md)
|
||||
:memo: Available Translations: 🇨🇳 🇹🇼 🇧🇷 🇪🇸 🇰🇷 🇯🇵 🇷🇺 🇫🇷 🇹🇭 🇳🇱 🇹🇷 🇮🇩 🇺🇦 🇨🇿 🇮🇹.
|
||||
View these docs in other languages at [electron/electron-i18n](https://github.com/electron/electron-i18n/tree/master/content/).
|
||||
|
||||
The Electron framework lets you write cross-platform desktop applications
|
||||
using JavaScript, HTML and CSS. It is based on [Node.js](https://nodejs.org/) and
|
||||
[Chromium](http://www.chromium.org) and is used by the [Atom
|
||||
editor](https://github.com/atom/atom) and many other [apps](https://electron.atom.io/apps).
|
||||
[Chromium](https://www.chromium.org) and is used by the [Atom
|
||||
editor](https://github.com/atom/atom) and many other [apps](https://electronjs.org/apps).
|
||||
|
||||
Follow [@ElectronJS](https://twitter.com/electronjs) on Twitter for important
|
||||
announcements.
|
||||
|
||||
This project adheres to the Contributor Covenant
|
||||
This project adheres to the Contributor Covenant
|
||||
[code of conduct](https://github.com/electron/electron/tree/master/CODE_OF_CONDUCT.md).
|
||||
By participating, you are expected to uphold this code. Please report unacceptable
|
||||
behavior to [electron@github.com](mailto:electron@github.com).
|
||||
@@ -32,29 +33,29 @@ npm install electron --save-dev --save-exact
|
||||
|
||||
The `--save-exact` flag is recommended as Electron does not follow semantic
|
||||
versioning. For info on how to manage Electron versions in your apps, see
|
||||
[Electron versioning](https://electron.atom.io/docs/tutorial/electron-versioning/).
|
||||
[Electron versioning](https://electronjs.org/docs/tutorial/electron-versioning).
|
||||
|
||||
For more installation options and troubleshooting tips, see
|
||||
[installation](https://electron.atom.io/docs/tutorial/installation/).
|
||||
[installation](https://electronjs.org/docs/tutorial/installation).
|
||||
|
||||
## Quick Start
|
||||
## Quick start
|
||||
|
||||
Clone and run the
|
||||
Clone and run the
|
||||
[electron/electron-quick-start](https://github.com/electron/electron-quick-start)
|
||||
repository to see a minimal Electron app in action:
|
||||
|
||||
```
|
||||
```sh
|
||||
git clone https://github.com/electron/electron-quick-start
|
||||
cd electron-quick-start
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
|
||||
## Resources for Learning Electron
|
||||
## Resources for learning Electron
|
||||
|
||||
- [electron.atom.io/docs](http://electron.atom.io/docs) - all of Electron's documentation
|
||||
- [electronjs.org/docs](https://electronjs.org/docs) - all of Electron's documentation
|
||||
- [electron/electron-quick-start](https://github.com/electron/electron-quick-start) - a very basic starter Electron app
|
||||
- [electron.atom.io/community/#boilerplates](http://electron.atom.io/community/#boilerplates) - sample starter apps created by the community
|
||||
- [electronjs.org/community#boilerplates](https://electronjs.org/community#boilerplates) - sample starter apps created by the community
|
||||
- [electron/simple-samples](https://github.com/electron/simple-samples) - small applications with ideas for taking them further
|
||||
- [electron/electron-api-demos](https://github.com/electron/electron-api-demos) - an Electron app that teaches you how to use Electron
|
||||
- [hokein/electron-sample-apps](https://github.com/hokein/electron-sample-apps) - small demo apps for the various Electron APIs
|
||||
@@ -82,32 +83,21 @@ const child = proc.spawn(electron)
|
||||
|
||||
## Documentation Translations
|
||||
|
||||
- [Brazilian Portuguese](https://github.com/electron/electron/tree/master/docs-translations/pt-BR)
|
||||
- [Korean](https://github.com/electron/electron/tree/master/docs-translations/ko-KR)
|
||||
- [Japanese](https://github.com/electron/electron/tree/master/docs-translations/jp)
|
||||
- [Spanish](https://github.com/electron/electron/tree/master/docs-translations/es)
|
||||
- [Simplified Chinese](https://github.com/electron/electron/tree/master/docs-translations/zh-CN)
|
||||
- [Traditional Chinese](https://github.com/electron/electron/tree/master/docs-translations/zh-TW)
|
||||
- [Turkish](https://github.com/electron/electron/tree/master/docs-translations/tr-TR)
|
||||
- [Thai](https://github.com/electron/electron/tree/master/docs-translations/th-TH)
|
||||
- [Ukrainian](https://github.com/electron/electron/tree/master/docs-translations/uk-UA)
|
||||
- [Russian](https://github.com/electron/electron/tree/master/docs-translations/ru-RU)
|
||||
- [French](https://github.com/electron/electron/tree/master/docs-translations/fr-FR)
|
||||
- [Indonesian](https://github.com/electron/electron/tree/master/docs-translations/id)
|
||||
Find documentation translations in [electron/electron-i18n](https://github.com/electron/electron-i18n).
|
||||
|
||||
## Community
|
||||
|
||||
You can ask questions and interact with the community in the following
|
||||
locations:
|
||||
- [`electron`](http://discuss.atom.io/c/electron) category on the Atom
|
||||
- [`electron`](https://discuss.atom.io/c/electron) category on the Atom
|
||||
forums
|
||||
- `#atom-shell` channel on Freenode
|
||||
- [`Atom`](http://atom-slack.herokuapp.com/) channel on Slack
|
||||
- [`Atom`](https://atom-slack.herokuapp.com) channel on Slack
|
||||
- [`electron-ru`](https://telegram.me/electron_ru) *(Russian)*
|
||||
- [`electron-br`](https://electron-br.slack.com) *(Brazilian Portuguese)*
|
||||
- [`electron-kr`](http://www.meetup.com/electron-kr/) *(Korean)*
|
||||
- [`electron-kr`](https://electron-kr.github.io/electron-kr) *(Korean)*
|
||||
- [`electron-jp`](https://electron-jp.slack.com) *(Japanese)*
|
||||
- [`electron-tr`](http://electron-tr.herokuapp.com) *(Turkish)*
|
||||
- [`electron-tr`](https://electron-tr.herokuapp.com) *(Turkish)*
|
||||
- [`electron-id`](https://electron-id.slack.com) *(Indonesia)*
|
||||
|
||||
Check out [awesome-electron](https://github.com/sindresorhus/awesome-electron)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#if defined(OS_WIN)
|
||||
#include <windows.h> // windows.h must be included first
|
||||
|
||||
#include <atlbase.h> // ensures that ATL statics like `_AtlWinModule` are initialized (it's an issue in static debug build)
|
||||
#include <shellapi.h>
|
||||
#include <shellscalingapi.h>
|
||||
#include <tchar.h>
|
||||
@@ -34,7 +35,7 @@
|
||||
|
||||
namespace {
|
||||
|
||||
const char* kRunAsNode = "ELECTRON_RUN_AS_NODE";
|
||||
const auto kRunAsNode = "ELECTRON_RUN_AS_NODE";
|
||||
|
||||
bool IsEnvSet(const char* name) {
|
||||
#if defined(OS_WIN)
|
||||
@@ -56,6 +57,29 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
|
||||
|
||||
bool run_as_node = IsEnvSet(kRunAsNode);
|
||||
|
||||
#ifdef _DEBUG
|
||||
// Don't display assert dialog boxes in CI test runs
|
||||
static const auto kCI = "ELECTRON_CI";
|
||||
bool is_ci = IsEnvSet(kCI);
|
||||
if (!is_ci) {
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
if (!_wcsicmp(wargv[i], L"--ci")) {
|
||||
is_ci = true;
|
||||
_putenv_s(kCI, "1"); // set flag for child processes
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_ci) {
|
||||
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
|
||||
_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
|
||||
|
||||
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
|
||||
_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
|
||||
|
||||
_set_error_mode(_OUT_TO_STDERR);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Make sure the output is printed to console.
|
||||
if (run_as_node || !IsEnvSet("ELECTRON_NO_ATTACH_CONSOLE"))
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "atom/app/uv_task_runner.h"
|
||||
|
||||
#include "base/stl_util.h"
|
||||
@@ -19,13 +21,13 @@ UvTaskRunner::~UvTaskRunner() {
|
||||
}
|
||||
|
||||
bool UvTaskRunner::PostDelayedTask(const tracked_objects::Location& from_here,
|
||||
const base::Closure& task,
|
||||
base::OnceClosure task,
|
||||
base::TimeDelta delay) {
|
||||
auto* timer = new uv_timer_t;
|
||||
timer->data = this;
|
||||
uv_timer_init(loop_, timer);
|
||||
uv_timer_start(timer, UvTaskRunner::OnTimeout, delay.InMilliseconds(), 0);
|
||||
tasks_[timer] = task;
|
||||
tasks_[timer] = std::move(task);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -35,9 +37,9 @@ bool UvTaskRunner::RunsTasksOnCurrentThread() const {
|
||||
|
||||
bool UvTaskRunner::PostNonNestableDelayedTask(
|
||||
const tracked_objects::Location& from_here,
|
||||
const base::Closure& task,
|
||||
base::OnceClosure task,
|
||||
base::TimeDelta delay) {
|
||||
return PostDelayedTask(from_here, task, delay);
|
||||
return PostDelayedTask(from_here, std::move(task), delay);
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -46,7 +48,7 @@ void UvTaskRunner::OnTimeout(uv_timer_t* timer) {
|
||||
if (!ContainsKey(self->tasks_, timer))
|
||||
return;
|
||||
|
||||
self->tasks_[timer].Run();
|
||||
std::move(self->tasks_[timer]).Run();
|
||||
self->tasks_.erase(timer);
|
||||
uv_timer_stop(timer);
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(timer), UvTaskRunner::OnClose);
|
||||
|
||||
@@ -21,12 +21,12 @@ class UvTaskRunner : public base::SingleThreadTaskRunner {
|
||||
|
||||
// base::SingleThreadTaskRunner:
|
||||
bool PostDelayedTask(const tracked_objects::Location& from_here,
|
||||
const base::Closure& task,
|
||||
base::OnceClosure task,
|
||||
base::TimeDelta delay) override;
|
||||
bool RunsTasksOnCurrentThread() const override;
|
||||
bool PostNonNestableDelayedTask(
|
||||
const tracked_objects::Location& from_here,
|
||||
const base::Closure& task,
|
||||
base::OnceClosure task,
|
||||
base::TimeDelta delay) override;
|
||||
|
||||
private:
|
||||
@@ -35,7 +35,7 @@ class UvTaskRunner : public base::SingleThreadTaskRunner {
|
||||
|
||||
uv_loop_t* loop_;
|
||||
|
||||
std::map<uv_timer_t*, base::Closure> tasks_;
|
||||
std::map<uv_timer_t*, base::OnceClosure> tasks_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(UvTaskRunner);
|
||||
};
|
||||
|
||||
@@ -54,6 +54,10 @@
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#endif
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
#include "atom/browser/ui/cocoa/atom_bundle_mover.h"
|
||||
#endif
|
||||
|
||||
using atom::Browser;
|
||||
|
||||
namespace mate {
|
||||
@@ -371,6 +375,8 @@ int GetPathConstant(const std::string& name) {
|
||||
return brightray::DIR_CACHE;
|
||||
else if (name == "userCache")
|
||||
return brightray::DIR_USER_CACHE;
|
||||
else if (name == "logs")
|
||||
return brightray::DIR_APP_LOGS;
|
||||
else if (name == "home")
|
||||
return base::DIR_HOME;
|
||||
else if (name == "temp")
|
||||
@@ -586,6 +592,18 @@ void App::OnAccessibilitySupportChanged() {
|
||||
}
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
void App::OnWillContinueUserActivity(
|
||||
bool* prevent_default,
|
||||
const std::string& type) {
|
||||
*prevent_default = Emit("will-continue-activity", type);
|
||||
}
|
||||
|
||||
void App::OnDidFailToContinueUserActivity(
|
||||
const std::string& type,
|
||||
const std::string& error) {
|
||||
Emit("continue-activity-error", type, error);
|
||||
}
|
||||
|
||||
void App::OnContinueUserActivity(
|
||||
bool* prevent_default,
|
||||
const std::string& type,
|
||||
@@ -593,22 +611,39 @@ void App::OnContinueUserActivity(
|
||||
*prevent_default = Emit("continue-activity", type, user_info);
|
||||
}
|
||||
|
||||
void App::OnUserActivityWasContinued(
|
||||
const std::string& type,
|
||||
const base::DictionaryValue& user_info) {
|
||||
Emit("activity-was-continued", type, user_info);
|
||||
}
|
||||
|
||||
void App::OnUpdateUserActivityState(
|
||||
bool* prevent_default,
|
||||
const std::string& type,
|
||||
const base::DictionaryValue& user_info) {
|
||||
*prevent_default = Emit("update-activity-state", type, user_info);
|
||||
}
|
||||
|
||||
void App::OnNewWindowForTab() {
|
||||
Emit("new-window-for-tab");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void App::OnLogin(LoginHandler* login_handler,
|
||||
const base::DictionaryValue& request_details) {
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
bool prevent_default = Emit(
|
||||
"login",
|
||||
WebContents::CreateFrom(isolate(), login_handler->GetWebContents()),
|
||||
request_details,
|
||||
login_handler->auth_info(),
|
||||
base::Bind(&PassLoginInformation, make_scoped_refptr(login_handler)));
|
||||
bool prevent_default = false;
|
||||
content::WebContents* web_contents = login_handler->GetWebContents();
|
||||
if (web_contents) {
|
||||
prevent_default =
|
||||
Emit("login",
|
||||
WebContents::CreateFrom(isolate(), web_contents),
|
||||
request_details,
|
||||
login_handler->auth_info(),
|
||||
base::Bind(&PassLoginInformation,
|
||||
make_scoped_refptr(login_handler)));
|
||||
}
|
||||
|
||||
// Default behavior is to always cancel the auth.
|
||||
if (!prevent_default)
|
||||
@@ -875,6 +910,16 @@ bool App::IsAccessibilitySupportEnabled() {
|
||||
return ax_state->IsAccessibleBrowser();
|
||||
}
|
||||
|
||||
void App::SetAccessibilitySupportEnabled(bool enabled) {
|
||||
auto ax_state = content::BrowserAccessibilityState::GetInstance();
|
||||
if (enabled) {
|
||||
ax_state->OnScreenReaderDetected();
|
||||
} else {
|
||||
ax_state->DisableAccessibility();
|
||||
}
|
||||
Browser::Get()->OnAccessibilitySupportChanged();
|
||||
}
|
||||
|
||||
Browser::LoginItemSettings App::GetLoginItemSettings(mate::Arguments* args) {
|
||||
Browser::LoginItemSettings options;
|
||||
args->GetNext(&options);
|
||||
@@ -1033,8 +1078,17 @@ std::vector<mate::Dictionary> App::GetAppMetrics(v8::Isolate* isolate) {
|
||||
cpu_dict.Set("percentCPUUsage",
|
||||
process_metric.second->metrics->GetPlatformIndependentCPUUsage()
|
||||
/ processor_count);
|
||||
|
||||
#if !defined(OS_WIN)
|
||||
cpu_dict.Set("idleWakeupsPerSecond",
|
||||
process_metric.second->metrics->GetIdleWakeupsPerSecond());
|
||||
#else
|
||||
// Chrome's underlying process_metrics.cc will throw a non-fatal warning
|
||||
// that this method isn't implemented on Windows, so set it to 0 instead
|
||||
// of calling it
|
||||
cpu_dict.Set("idleWakeupsPerSecond", 0);
|
||||
#endif
|
||||
|
||||
pid_dict.Set("cpu", cpu_dict);
|
||||
pid_dict.Set("pid", process_metric.second->pid);
|
||||
pid_dict.Set("type",
|
||||
@@ -1078,6 +1132,16 @@ void App::EnableMixedSandbox(mate::Arguments* args) {
|
||||
command_line->AppendSwitch(switches::kEnableMixedSandbox);
|
||||
}
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
bool App::MoveToApplicationsFolder(mate::Arguments* args) {
|
||||
return ui::cocoa::AtomBundleMover::Move(args);
|
||||
}
|
||||
|
||||
bool App::IsInApplicationsFolder() {
|
||||
return ui::cocoa::AtomBundleMover::IsCurrentAppInApplicationsFolder();
|
||||
}
|
||||
#endif
|
||||
|
||||
// static
|
||||
mate::Handle<App> App::Create(v8::Isolate* isolate) {
|
||||
return mate::CreateHandle(isolate, new App(isolate));
|
||||
@@ -1121,6 +1185,10 @@ void App::BuildPrototype(
|
||||
base::Bind(&Browser::SetUserActivity, browser))
|
||||
.SetMethod("getCurrentActivityType",
|
||||
base::Bind(&Browser::GetCurrentActivityType, browser))
|
||||
.SetMethod("invalidateCurrentActivity",
|
||||
base::Bind(&Browser::InvalidateCurrentActivity, browser))
|
||||
.SetMethod("updateCurrentActivity",
|
||||
base::Bind(&Browser::UpdateCurrentActivity, browser))
|
||||
.SetMethod("setAboutPanelOptions",
|
||||
base::Bind(&Browser::SetAboutPanelOptions, browser))
|
||||
#endif
|
||||
@@ -1147,6 +1215,8 @@ void App::BuildPrototype(
|
||||
.SetMethod("relaunch", &App::Relaunch)
|
||||
.SetMethod("isAccessibilitySupportEnabled",
|
||||
&App::IsAccessibilitySupportEnabled)
|
||||
.SetMethod("setAccessibilitySupportEnabled",
|
||||
&App::SetAccessibilitySupportEnabled)
|
||||
.SetMethod("disableHardwareAcceleration",
|
||||
&App::DisableHardwareAcceleration)
|
||||
.SetMethod("disableDomainBlockingFor3DAPIs",
|
||||
@@ -1156,6 +1226,10 @@ void App::BuildPrototype(
|
||||
.SetMethod("getGPUFeatureStatus", &App::GetGPUFeatureStatus)
|
||||
.SetMethod("enableMixedSandbox", &App::EnableMixedSandbox)
|
||||
// TODO(juturu): Remove in 2.0, deprecate before then with warnings
|
||||
#if defined(OS_MACOSX)
|
||||
.SetMethod("moveToApplicationsFolder", &App::MoveToApplicationsFolder)
|
||||
.SetMethod("isInApplicationsFolder", &App::IsInApplicationsFolder)
|
||||
#endif
|
||||
.SetMethod("getAppMemoryInfo", &App::GetAppMetrics);
|
||||
}
|
||||
|
||||
|
||||
@@ -115,11 +115,23 @@ class App : public AtomBrowserClient::Delegate,
|
||||
void OnAccessibilitySupportChanged() override;
|
||||
void OnPreMainMessageLoopRun() override;
|
||||
#if defined(OS_MACOSX)
|
||||
void OnWillContinueUserActivity(
|
||||
bool* prevent_default,
|
||||
const std::string& type) override;
|
||||
void OnDidFailToContinueUserActivity(
|
||||
const std::string& type,
|
||||
const std::string& error) override;
|
||||
void OnContinueUserActivity(
|
||||
bool* prevent_default,
|
||||
const std::string& type,
|
||||
const base::DictionaryValue& user_info) override;
|
||||
|
||||
void OnUserActivityWasContinued(
|
||||
const std::string& type,
|
||||
const base::DictionaryValue& user_info) override;
|
||||
void OnUpdateUserActivityState(
|
||||
bool* prevent_default,
|
||||
const std::string& type,
|
||||
const base::DictionaryValue& user_info) override;
|
||||
void OnNewWindowForTab() override;
|
||||
#endif
|
||||
|
||||
@@ -173,6 +185,7 @@ class App : public AtomBrowserClient::Delegate,
|
||||
void DisableHardwareAcceleration(mate::Arguments* args);
|
||||
void DisableDomainBlockingFor3DAPIs(mate::Arguments* args);
|
||||
bool IsAccessibilitySupportEnabled();
|
||||
void SetAccessibilitySupportEnabled(bool enabled);
|
||||
Browser::LoginItemSettings GetLoginItemSettings(mate::Arguments* args);
|
||||
#if defined(USE_NSS_CERTS)
|
||||
void ImportCertificate(const base::DictionaryValue& options,
|
||||
@@ -185,6 +198,11 @@ class App : public AtomBrowserClient::Delegate,
|
||||
v8::Local<v8::Value> GetGPUFeatureStatus(v8::Isolate* isolate);
|
||||
void EnableMixedSandbox(mate::Arguments* args);
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
bool MoveToApplicationsFolder(mate::Arguments* args);
|
||||
bool IsInApplicationsFolder();
|
||||
#endif
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Get the current Jump List settings.
|
||||
v8::Local<v8::Value> GetJumpListSettings();
|
||||
|
||||
@@ -114,7 +114,7 @@ void BrowserView::SetBackgroundColor(const std::string& color_name) {
|
||||
view_->SetBackgroundColor(ParseHexColor(color_name));
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> BrowserView::WebContents() {
|
||||
v8::Local<v8::Value> BrowserView::GetWebContents() {
|
||||
if (web_contents_.IsEmpty()) {
|
||||
return v8::Null(isolate());
|
||||
}
|
||||
@@ -131,7 +131,7 @@ void BrowserView::BuildPrototype(v8::Isolate* isolate,
|
||||
.SetMethod("setAutoResize", &BrowserView::SetAutoResize)
|
||||
.SetMethod("setBounds", &BrowserView::SetBounds)
|
||||
.SetMethod("setBackgroundColor", &BrowserView::SetBackgroundColor)
|
||||
.SetProperty("webContents", &BrowserView::WebContents)
|
||||
.SetProperty("webContents", &BrowserView::GetWebContents)
|
||||
.SetProperty("id", &BrowserView::ID);
|
||||
}
|
||||
|
||||
@@ -154,6 +154,8 @@ void Initialize(v8::Local<v8::Object> exports,
|
||||
isolate, BrowserView::GetConstructor(isolate)->GetFunction());
|
||||
browser_view.SetMethod("fromId",
|
||||
&mate::TrackableObject<BrowserView>::FromWeakMapID);
|
||||
browser_view.SetMethod("getAllViews",
|
||||
&mate::TrackableObject<BrowserView>::GetAll);
|
||||
mate::Dictionary dict(isolate, exports);
|
||||
dict.Set("BrowserView", browser_view);
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ class BrowserView : public mate::TrackableObject<BrowserView> {
|
||||
void SetBounds(const gfx::Rect& bounds);
|
||||
void SetBackgroundColor(const std::string& color_name);
|
||||
|
||||
v8::Local<v8::Value> WebContents();
|
||||
v8::Local<v8::Value> GetWebContents();
|
||||
|
||||
v8::Global<v8::Value> web_contents_;
|
||||
class WebContents* api_web_contents_;
|
||||
|
||||
@@ -169,14 +169,22 @@ void Notification::NotificationDisplayed() {
|
||||
}
|
||||
|
||||
void Notification::NotificationDestroyed() {
|
||||
Emit("close");
|
||||
}
|
||||
|
||||
void Notification::NotificationClosed() {
|
||||
Emit("close");
|
||||
}
|
||||
|
||||
void Notification::Close() {
|
||||
if (notification_) {
|
||||
notification_->Dismiss();
|
||||
notification_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
// Showing notifications
|
||||
void Notification::Show() {
|
||||
Close();
|
||||
if (presenter_) {
|
||||
notification_ = presenter_->CreateNotification(this);
|
||||
if (notification_) {
|
||||
@@ -207,6 +215,7 @@ void Notification::BuildPrototype(v8::Isolate* isolate,
|
||||
mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
|
||||
.MakeDestroyable()
|
||||
.SetMethod("show", &Notification::Show)
|
||||
.SetMethod("close", &Notification::Close)
|
||||
.SetProperty("title", &Notification::GetTitle, &Notification::SetTitle)
|
||||
.SetProperty("subtitle", &Notification::GetSubtitle,
|
||||
&Notification::SetSubtitle)
|
||||
|
||||
@@ -45,6 +45,7 @@ class Notification : public mate::TrackableObject<Notification>,
|
||||
~Notification() override;
|
||||
|
||||
void Show();
|
||||
void Close();
|
||||
|
||||
// Prop Getters
|
||||
base::string16 GetTitle() const;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "atom/browser/net/url_request_async_asar_job.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_stream_job.h"
|
||||
#include "atom/browser/net/url_request_string_job.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/value_converter.h"
|
||||
@@ -208,6 +209,8 @@ void Protocol::BuildPrototype(
|
||||
&Protocol::RegisterProtocol<URLRequestAsyncAsarJob>)
|
||||
.SetMethod("registerHttpProtocol",
|
||||
&Protocol::RegisterProtocol<URLRequestFetchJob>)
|
||||
.SetMethod("registerStreamProtocol",
|
||||
&Protocol::RegisterProtocol<URLRequestStreamJob>)
|
||||
.SetMethod("unregisterProtocol", &Protocol::UnregisterProtocol)
|
||||
.SetMethod("isProtocolHandled", &Protocol::IsProtocolHandled)
|
||||
.SetMethod("interceptStringProtocol",
|
||||
@@ -218,6 +221,8 @@ void Protocol::BuildPrototype(
|
||||
&Protocol::InterceptProtocol<URLRequestAsyncAsarJob>)
|
||||
.SetMethod("interceptHttpProtocol",
|
||||
&Protocol::InterceptProtocol<URLRequestFetchJob>)
|
||||
.SetMethod("interceptStreamProtocol",
|
||||
&Protocol::InterceptProtocol<URLRequestStreamJob>)
|
||||
.SetMethod("uninterceptProtocol", &Protocol::UninterceptProtocol);
|
||||
}
|
||||
|
||||
|
||||
@@ -78,6 +78,10 @@ class Protocol : public mate::TrackableObject<Protocol> {
|
||||
net::URLRequestJob* MaybeCreateJob(
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate) const override {
|
||||
if (!request->initiator().has_value()) {
|
||||
// Don't intercept this request as it was created by `net.request`.
|
||||
return nullptr;
|
||||
}
|
||||
RequestJob* request_job = new RequestJob(request, network_delegate);
|
||||
request_job->SetHandlerInfo(isolate_, request_context_.get(), handler_);
|
||||
return request_job;
|
||||
|
||||
@@ -212,6 +212,7 @@ struct Converter<atom::VerifyRequestParams> {
|
||||
dict.Set("hostname", val.hostname);
|
||||
dict.Set("certificate", val.certificate);
|
||||
dict.Set("verificationResult", val.default_result);
|
||||
dict.Set("errorCode", val.error_code);
|
||||
return dict.GetHandle();
|
||||
}
|
||||
};
|
||||
@@ -433,6 +434,7 @@ void DownloadIdCallback(content::DownloadManager* download_manager,
|
||||
content::DownloadItem::INTERRUPTED,
|
||||
content::DownloadDangerType::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
|
||||
content::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT, false,
|
||||
base::Time(), false,
|
||||
std::vector<content::DownloadItem::ReceivedSlice>());
|
||||
}
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ void SystemPreferences::BuildPrototype(
|
||||
&SystemPreferences::UnsubscribeLocalNotification)
|
||||
.SetMethod("getUserDefault", &SystemPreferences::GetUserDefault)
|
||||
.SetMethod("setUserDefault", &SystemPreferences::SetUserDefault)
|
||||
.SetMethod("removeUserDefault", &SystemPreferences::RemoveUserDefault)
|
||||
.SetMethod("isSwipeTrackingFromScrollEventsEnabled",
|
||||
&SystemPreferences::IsSwipeTrackingFromScrollEventsEnabled)
|
||||
#endif
|
||||
|
||||
@@ -76,6 +76,7 @@ class SystemPreferences : public mate::EventEmitter<SystemPreferences>
|
||||
void SetUserDefault(const std::string& name,
|
||||
const std::string& type,
|
||||
mate::Arguments* args);
|
||||
void RemoveUserDefault(const std::string& name);
|
||||
bool IsSwipeTrackingFromScrollEventsEnabled();
|
||||
#endif
|
||||
bool IsDarkMode();
|
||||
|
||||
@@ -229,6 +229,11 @@ void SystemPreferences::SetUserDefault(const std::string& name,
|
||||
}
|
||||
}
|
||||
|
||||
void SystemPreferences::RemoveUserDefault(const std::string& name) {
|
||||
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
|
||||
[defaults removeObjectForKey:base::SysUTF8ToNSString(name)];
|
||||
}
|
||||
|
||||
bool SystemPreferences::IsDarkMode() {
|
||||
NSString* mode = [[NSUserDefaults standardUserDefaults]
|
||||
stringForKey:@"AppleInterfaceStyle"];
|
||||
|
||||
@@ -86,8 +86,10 @@ mate::WrappableBase* Tray::New(mate::Handle<NativeImage> image,
|
||||
return new Tray(args->isolate(), args->GetThis(), image);
|
||||
}
|
||||
|
||||
void Tray::OnClicked(const gfx::Rect& bounds, int modifiers) {
|
||||
EmitWithFlags("click", modifiers, bounds);
|
||||
void Tray::OnClicked(const gfx::Rect& bounds,
|
||||
const gfx::Point& location,
|
||||
int modifiers) {
|
||||
EmitWithFlags("click", modifiers, bounds, location);
|
||||
}
|
||||
|
||||
void Tray::OnDoubleClicked(const gfx::Rect& bounds, int modifiers) {
|
||||
@@ -130,6 +132,10 @@ void Tray::OnMouseExited(const gfx::Point& location, int modifiers) {
|
||||
EmitWithFlags("mouse-leave", modifiers, location);
|
||||
}
|
||||
|
||||
void Tray::OnMouseMoved(const gfx::Point& location, int modifiers) {
|
||||
EmitWithFlags("mouse-move", modifiers, location);
|
||||
}
|
||||
|
||||
void Tray::OnDragEntered() {
|
||||
Emit("drag-enter");
|
||||
}
|
||||
|
||||
@@ -47,7 +47,9 @@ class Tray : public mate::TrackableObject<Tray>,
|
||||
~Tray() override;
|
||||
|
||||
// TrayIconObserver:
|
||||
void OnClicked(const gfx::Rect& bounds, int modifiers) override;
|
||||
void OnClicked(const gfx::Rect& bounds,
|
||||
const gfx::Point& location,
|
||||
int modifiers) override;
|
||||
void OnDoubleClicked(const gfx::Rect& bounds, int modifiers) override;
|
||||
void OnRightClicked(const gfx::Rect& bounds, int modifiers) override;
|
||||
void OnBalloonShow() override;
|
||||
@@ -61,6 +63,7 @@ class Tray : public mate::TrackableObject<Tray>,
|
||||
void OnDragEnded() override;
|
||||
void OnMouseEntered(const gfx::Point& location, int modifiers) override;
|
||||
void OnMouseExited(const gfx::Point& location, int modifiers) override;
|
||||
void OnMouseMoved(const gfx::Point& location, int modifiers) override;
|
||||
|
||||
void SetImage(v8::Isolate* isolate, mate::Handle<NativeImage> image);
|
||||
void SetPressedImage(v8::Isolate* isolate, mate::Handle<NativeImage> image);
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
#include "content/browser/renderer_host/render_widget_host_view_base.h"
|
||||
#include "content/browser/web_contents/web_contents_impl.h"
|
||||
#include "content/common/view_messages.h"
|
||||
#include "content/public/browser/child_process_security_policy.h"
|
||||
#include "content/public/browser/favicon_status.h"
|
||||
#include "content/public/browser/native_web_keyboard_event.h"
|
||||
#include "content/public/browser/navigation_details.h"
|
||||
@@ -81,6 +82,7 @@
|
||||
#include "third_party/WebKit/public/web/WebFindOptions.h"
|
||||
#include "ui/display/screen.h"
|
||||
#include "ui/events/base_event_utils.h"
|
||||
#include "ui/latency/latency_info.h"
|
||||
|
||||
#if !defined(OS_MACOSX)
|
||||
#include "ui/aura/window.h"
|
||||
@@ -284,12 +286,13 @@ WebContents::WebContents(v8::Isolate* isolate,
|
||||
request_id_(0),
|
||||
background_throttling_(true),
|
||||
enable_devtools_(true) {
|
||||
const mate::Dictionary options = mate::Dictionary::CreateEmpty(isolate);
|
||||
if (type == REMOTE) {
|
||||
web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
|
||||
Init(isolate);
|
||||
AttachAsUserData(web_contents);
|
||||
InitZoomController(web_contents, options);
|
||||
} else {
|
||||
const mate::Dictionary options = mate::Dictionary::CreateEmpty(isolate);
|
||||
auto session = Session::CreateFrom(isolate, GetBrowserContext());
|
||||
session_.Reset(isolate, session.ToV8());
|
||||
InitWithSessionAndOptions(isolate, web_contents, session, options);
|
||||
@@ -303,6 +306,10 @@ WebContents::WebContents(v8::Isolate* isolate, const mate::Dictionary& options)
|
||||
request_id_(0),
|
||||
background_throttling_(true),
|
||||
enable_devtools_(true) {
|
||||
// WebContents may need to emit events when it is garbage collected, so it
|
||||
// has to be deleted in the first gc callback.
|
||||
MarkHighMemoryUsage();
|
||||
|
||||
// Read options.
|
||||
options.Get("backgroundThrottling", &background_throttling_);
|
||||
|
||||
@@ -386,6 +393,15 @@ WebContents::WebContents(v8::Isolate* isolate, const mate::Dictionary& options)
|
||||
InitWithSessionAndOptions(isolate, web_contents, session, options);
|
||||
}
|
||||
|
||||
void WebContents::InitZoomController(content::WebContents* web_contents,
|
||||
const mate::Dictionary& options) {
|
||||
WebContentsZoomController::CreateForWebContents(web_contents);
|
||||
zoom_controller_ = WebContentsZoomController::FromWebContents(web_contents);
|
||||
double zoom_factor;
|
||||
if (options.Get(options::kZoomFactor, &zoom_factor))
|
||||
zoom_controller_->SetDefaultZoomFactor(zoom_factor);
|
||||
}
|
||||
|
||||
void WebContents::InitWithSessionAndOptions(v8::Isolate* isolate,
|
||||
content::WebContents *web_contents,
|
||||
mate::Handle<api::Session> session,
|
||||
@@ -403,11 +419,7 @@ void WebContents::InitWithSessionAndOptions(v8::Isolate* isolate,
|
||||
// Initialize security state client.
|
||||
SecurityStateTabHelper::CreateForWebContents(web_contents);
|
||||
// Initialize zoom controller.
|
||||
WebContentsZoomController::CreateForWebContents(web_contents);
|
||||
zoom_controller_ = WebContentsZoomController::FromWebContents(web_contents);
|
||||
double zoom_factor;
|
||||
if (options.Get(options::kZoomFactor, &zoom_factor))
|
||||
zoom_controller_->SetDefaultZoomFactor(zoom_factor);
|
||||
InitZoomController(web_contents, options);
|
||||
|
||||
web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
|
||||
|
||||
@@ -468,7 +480,7 @@ bool WebContents::DidAddMessageToConsole(content::WebContents* source,
|
||||
const base::string16& message,
|
||||
int32_t line_no,
|
||||
const base::string16& source_id) {
|
||||
if (type_ == BROWSER_WINDOW || type_ == OFF_SCREEN) {
|
||||
if (type_ == OFF_SCREEN) {
|
||||
return false;
|
||||
} else {
|
||||
Emit("console-message", level, message, line_no, source_id);
|
||||
@@ -586,16 +598,18 @@ void WebContents::HandleKeyboardEvent(
|
||||
}
|
||||
}
|
||||
|
||||
bool WebContents::PreHandleKeyboardEvent(
|
||||
content::KeyboardEventProcessingResult WebContents::PreHandleKeyboardEvent(
|
||||
content::WebContents* source,
|
||||
const content::NativeWebKeyboardEvent& event,
|
||||
bool* is_keyboard_shortcut) {
|
||||
if (event.type() == blink::WebInputEvent::Type::RawKeyDown ||
|
||||
event.type() == blink::WebInputEvent::Type::KeyUp) {
|
||||
return Emit("before-input-event", event);
|
||||
} else {
|
||||
return false;
|
||||
const content::NativeWebKeyboardEvent& event) {
|
||||
if (event.GetType() == blink::WebInputEvent::Type::kRawKeyDown ||
|
||||
event.GetType() == blink::WebInputEvent::Type::kKeyUp) {
|
||||
bool prevent_default = Emit("before-input-event", event);
|
||||
if (prevent_default) {
|
||||
return content::KeyboardEventProcessingResult::HANDLED;
|
||||
}
|
||||
}
|
||||
|
||||
return content::KeyboardEventProcessingResult::NOT_HANDLED;
|
||||
}
|
||||
|
||||
void WebContents::EnterFullscreenModeForTab(content::WebContents* source,
|
||||
@@ -753,7 +767,11 @@ void WebContents::MediaStoppedPlaying(const MediaPlayerInfo& video_type,
|
||||
}
|
||||
|
||||
void WebContents::DidChangeThemeColor(SkColor theme_color) {
|
||||
Emit("did-change-theme-color", atom::ToRGBHex(theme_color));
|
||||
if (theme_color != SK_ColorTRANSPARENT) {
|
||||
Emit("did-change-theme-color", atom::ToRGBHex(theme_color));
|
||||
} else {
|
||||
Emit("did-change-theme-color", nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void WebContents::DocumentLoadedInFrame(
|
||||
@@ -818,7 +836,7 @@ void WebContents::DidFinishNavigation(
|
||||
bool is_main_frame = navigation_handle->IsInMainFrame();
|
||||
if (navigation_handle->HasCommitted() && !navigation_handle->IsErrorPage()) {
|
||||
auto url = navigation_handle->GetURL();
|
||||
bool is_in_page = navigation_handle->IsSamePage();
|
||||
bool is_in_page = navigation_handle->IsSameDocument();
|
||||
if (is_main_frame && !is_in_page) {
|
||||
Emit("did-navigate", url);
|
||||
} else if (is_in_page) {
|
||||
@@ -891,6 +909,17 @@ void WebContents::DevToolsClosed() {
|
||||
Emit("devtools-closed");
|
||||
}
|
||||
|
||||
void WebContents::ShowAutofillPopup(content::RenderFrameHost* frame_host,
|
||||
const gfx::RectF& bounds,
|
||||
const std::vector<base::string16>& values,
|
||||
const std::vector<base::string16>& labels) {
|
||||
auto relay = NativeWindowRelay::FromWebContents(web_contents());
|
||||
if (relay) {
|
||||
relay->window->ShowAutofillPopup(
|
||||
frame_host, web_contents(), bounds, values, labels);
|
||||
}
|
||||
}
|
||||
|
||||
bool WebContents::OnMessageReceived(const IPC::Message& message) {
|
||||
bool handled = true;
|
||||
IPC_BEGIN_MESSAGE_MAP(WebContents, message)
|
||||
@@ -915,9 +944,10 @@ bool WebContents::OnMessageReceived(const IPC::Message& message,
|
||||
auto relay = NativeWindowRelay::FromWebContents(web_contents());
|
||||
if (!relay)
|
||||
return false;
|
||||
IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(WebContents, message, frame_host)
|
||||
IPC_MESSAGE_HANDLER(AtomAutofillFrameHostMsg_ShowPopup, ShowAutofillPopup)
|
||||
IPC_END_MESSAGE_MAP()
|
||||
IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(NativeWindow, message, frame_host)
|
||||
IPC_MESSAGE_FORWARD(AtomAutofillFrameHostMsg_ShowPopup,
|
||||
relay->window.get(), NativeWindow::ShowAutofillPopup)
|
||||
IPC_MESSAGE_FORWARD(AtomAutofillFrameHostMsg_HidePopup,
|
||||
relay->window.get(), NativeWindow::HideAutofillPopup)
|
||||
IPC_MESSAGE_UNHANDLED(handled = false)
|
||||
@@ -1002,7 +1032,7 @@ void WebContents::LoadURL(const GURL& url, const mate::Dictionary& options) {
|
||||
GURL http_referrer;
|
||||
if (options.Get("httpReferrer", &http_referrer))
|
||||
params.referrer = content::Referrer(http_referrer.GetAsReferrer(),
|
||||
blink::WebReferrerPolicyDefault);
|
||||
blink::kWebReferrerPolicyDefault);
|
||||
|
||||
std::string user_agent;
|
||||
if (options.Get("userAgent", &user_agent))
|
||||
@@ -1240,9 +1270,22 @@ void WebContents::HasServiceWorker(
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
context->CheckHasServiceWorker(web_contents()->GetLastCommittedURL(),
|
||||
GURL::EmptyGURL(),
|
||||
callback);
|
||||
struct WrappedCallback {
|
||||
base::Callback<void(bool)> callback_;
|
||||
explicit WrappedCallback(const base::Callback<void(bool)>& callback)
|
||||
: callback_(callback) {}
|
||||
void Run(content::ServiceWorkerCapability capability) {
|
||||
callback_.Run(capability !=
|
||||
content::ServiceWorkerCapability::NO_SERVICE_WORKER);
|
||||
delete this;
|
||||
}
|
||||
};
|
||||
|
||||
auto wrapped_callback = new WrappedCallback(callback);
|
||||
|
||||
context->CheckHasServiceWorker(
|
||||
web_contents()->GetLastCommittedURL(), GURL::EmptyGURL(),
|
||||
base::Bind(&WrappedCallback::Run, base::Unretained(wrapped_callback)));
|
||||
}
|
||||
|
||||
void WebContents::UnregisterServiceWorker(
|
||||
@@ -1269,13 +1312,21 @@ bool WebContents::IsAudioMuted() {
|
||||
|
||||
void WebContents::Print(mate::Arguments* args) {
|
||||
PrintSettings settings = { false, false, base::string16() };
|
||||
if (args->Length() == 1 && !args->GetNext(&settings)) {
|
||||
if (args->Length() >= 1 && !args->GetNext(&settings)) {
|
||||
args->ThrowError();
|
||||
return;
|
||||
}
|
||||
|
||||
printing::PrintViewManagerBasic::FromWebContents(web_contents())->
|
||||
PrintNow(web_contents()->GetMainFrame(),
|
||||
auto print_view_manager_basic_ptr =
|
||||
printing::PrintViewManagerBasic::FromWebContents(web_contents());
|
||||
if (args->Length() == 2) {
|
||||
base::Callback<void(bool)> callback;
|
||||
if (!args->GetNext(&callback)) {
|
||||
args->ThrowError();
|
||||
return;
|
||||
}
|
||||
print_view_manager_basic_ptr->SetCallback(callback);
|
||||
}
|
||||
print_view_manager_basic_ptr->PrintNow(web_contents()->GetMainFrame(),
|
||||
settings.silent,
|
||||
settings.print_background,
|
||||
settings.device_name);
|
||||
@@ -1426,22 +1477,22 @@ void WebContents::SendInputEvent(v8::Isolate* isolate,
|
||||
return;
|
||||
|
||||
int type = mate::GetWebInputEventType(isolate, input_event);
|
||||
if (blink::WebInputEvent::isMouseEventType(type)) {
|
||||
if (blink::WebInputEvent::IsMouseEventType(type)) {
|
||||
blink::WebMouseEvent mouse_event;
|
||||
if (mate::ConvertFromV8(isolate, input_event, &mouse_event)) {
|
||||
view->ProcessMouseEvent(mouse_event, ui::LatencyInfo());
|
||||
return;
|
||||
}
|
||||
} else if (blink::WebInputEvent::isKeyboardEventType(type)) {
|
||||
} else if (blink::WebInputEvent::IsKeyboardEventType(type)) {
|
||||
content::NativeWebKeyboardEvent keyboard_event(
|
||||
blink::WebKeyboardEvent::RawKeyDown,
|
||||
blink::WebInputEvent::NoModifiers,
|
||||
blink::WebKeyboardEvent::kRawKeyDown,
|
||||
blink::WebInputEvent::kNoModifiers,
|
||||
ui::EventTimeForNow());
|
||||
if (mate::ConvertFromV8(isolate, input_event, &keyboard_event)) {
|
||||
view->ProcessKeyboardEvent(keyboard_event);
|
||||
return;
|
||||
}
|
||||
} else if (type == blink::WebInputEvent::MouseWheel) {
|
||||
} else if (type == blink::WebInputEvent::kMouseWheel) {
|
||||
blink::WebMouseWheelEvent mouse_wheel_event;
|
||||
if (mate::ConvertFromV8(isolate, input_event, &mouse_wheel_event)) {
|
||||
view->ProcessMouseWheelEvent(mouse_wheel_event, ui::LatencyInfo());
|
||||
@@ -1541,7 +1592,7 @@ void WebContents::CapturePage(mate::Arguments* args) {
|
||||
gfx::Size bitmap_size = view_size;
|
||||
const gfx::NativeView native_view = view->GetNativeView();
|
||||
const float scale =
|
||||
display::Screen::GetScreen()->GetDisplayNearestWindow(native_view)
|
||||
display::Screen::GetScreen()->GetDisplayNearestView(native_view)
|
||||
.device_scale_factor();
|
||||
if (scale > 1.0f)
|
||||
bitmap_size = gfx::ScaleToCeiledSize(view_size, scale);
|
||||
@@ -1553,7 +1604,7 @@ void WebContents::CapturePage(mate::Arguments* args) {
|
||||
}
|
||||
|
||||
void WebContents::OnCursorChange(const content::WebCursor& cursor) {
|
||||
content::WebCursor::CursorInfo info;
|
||||
content::CursorInfo info;
|
||||
cursor.GetCursorInfo(&info);
|
||||
|
||||
if (cursor.IsCustom()) {
|
||||
@@ -1584,10 +1635,6 @@ bool WebContents::IsOffScreen() const {
|
||||
#endif
|
||||
}
|
||||
|
||||
bool WebContents::IsOffScreenOrEmbedderOffscreen() const {
|
||||
return IsOffScreen() || (embedder_ && embedder_->IsOffScreen());
|
||||
}
|
||||
|
||||
void WebContents::OnPaint(const gfx::Rect& dirty_rect, const SkBitmap& bitmap) {
|
||||
Emit("paint", dirty_rect, gfx::Image::CreateFrom1xBitmap(bitmap));
|
||||
}
|
||||
@@ -1758,6 +1805,16 @@ void WebContents::SetEmbedder(const WebContents* embedder) {
|
||||
}
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> WebContents::GetNativeView() const {
|
||||
gfx::NativeView ptr = web_contents()->GetNativeView();
|
||||
auto buffer = node::Buffer::Copy(
|
||||
isolate(), reinterpret_cast<char*>(&ptr), sizeof(gfx::NativeView));
|
||||
if (buffer.IsEmpty())
|
||||
return v8::Null(isolate());
|
||||
else
|
||||
return buffer.ToLocalChecked();
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> WebContents::DevToolsWebContents(v8::Isolate* isolate) {
|
||||
if (devtools_web_contents_.IsEmpty())
|
||||
return v8::Null(isolate);
|
||||
@@ -1773,6 +1830,12 @@ v8::Local<v8::Value> WebContents::Debugger(v8::Isolate* isolate) {
|
||||
return v8::Local<v8::Value>::New(isolate, debugger_);
|
||||
}
|
||||
|
||||
void WebContents::GrantOriginAccess(const GURL& url) {
|
||||
content::ChildProcessSecurityPolicy::GetInstance()->GrantOrigin(
|
||||
web_contents()->GetMainFrame()->GetProcess()->GetID(),
|
||||
url::Origin(url));
|
||||
}
|
||||
|
||||
// static
|
||||
void WebContents::BuildPrototype(v8::Isolate* isolate,
|
||||
v8::Local<v8::FunctionTemplate> prototype) {
|
||||
@@ -1863,10 +1926,12 @@ void WebContents::BuildPrototype(v8::Isolate* isolate,
|
||||
.SetMethod("copyImageAt", &WebContents::CopyImageAt)
|
||||
.SetMethod("capturePage", &WebContents::CapturePage)
|
||||
.SetMethod("setEmbedder", &WebContents::SetEmbedder)
|
||||
.SetMethod("getNativeView", &WebContents::GetNativeView)
|
||||
.SetMethod("setWebRTCIPHandlingPolicy",
|
||||
&WebContents::SetWebRTCIPHandlingPolicy)
|
||||
.SetMethod("getWebRTCIPHandlingPolicy",
|
||||
&WebContents::GetWebRTCIPHandlingPolicy)
|
||||
.SetMethod("_grantOriginAccess", &WebContents::GrantOriginAccess)
|
||||
.SetProperty("id", &WebContents::ID)
|
||||
.SetProperty("session", &WebContents::Session)
|
||||
.SetProperty("hostWebContents", &WebContents::HostWebContents)
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "atom/browser/common_web_contents_delegate.h"
|
||||
#include "atom/browser/ui/autofill_popup.h"
|
||||
#include "content/common/cursors/webcursor.h"
|
||||
#include "content/public/browser/keyboard_event_processing_result.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
#include "content/public/common/favicon_url.h"
|
||||
#include "native_mate/handle.h"
|
||||
@@ -115,7 +116,8 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||
void DisableDeviceEmulation();
|
||||
void InspectElement(int x, int y);
|
||||
void InspectServiceWorker();
|
||||
void HasServiceWorker(const base::Callback<void(bool)>&);
|
||||
void HasServiceWorker(
|
||||
const base::Callback<void(bool)>&);
|
||||
void UnregisterServiceWorker(const base::Callback<void(bool)>&);
|
||||
void SetIgnoreMenuShortcuts(bool ignore);
|
||||
void SetAudioMuted(bool muted);
|
||||
@@ -123,6 +125,7 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||
void Print(mate::Arguments* args);
|
||||
std::vector<printing::PrinterBasicInfo> GetPrinterList();
|
||||
void SetEmbedder(const WebContents* embedder);
|
||||
v8::Local<v8::Value> GetNativeView() const;
|
||||
|
||||
// Print current page as PDF.
|
||||
void PrintToPDF(const base::DictionaryValue& setting,
|
||||
@@ -179,7 +182,6 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||
|
||||
// Methods for offscreen rendering
|
||||
bool IsOffScreen() const;
|
||||
bool IsOffScreenOrEmbedderOffscreen() const;
|
||||
void OnPaint(const gfx::Rect& dirty_rect, const SkBitmap& bitmap);
|
||||
void StartPainting();
|
||||
void StopPainting();
|
||||
@@ -214,6 +216,10 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||
// Returns the owner window.
|
||||
v8::Local<v8::Value> GetOwnerBrowserWindow();
|
||||
|
||||
// Grants the child process the capability to access URLs with the origin of
|
||||
// the specified URL.
|
||||
void GrantOriginAccess(const GURL& url);
|
||||
|
||||
// Properties.
|
||||
int32_t ID() const;
|
||||
v8::Local<v8::Value> Session(v8::Isolate* isolate);
|
||||
@@ -268,9 +274,9 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||
void HandleKeyboardEvent(
|
||||
content::WebContents* source,
|
||||
const content::NativeWebKeyboardEvent& event) override;
|
||||
bool PreHandleKeyboardEvent(content::WebContents* source,
|
||||
const content::NativeWebKeyboardEvent& event,
|
||||
bool* is_keyboard_shortcut) override;
|
||||
content::KeyboardEventProcessingResult PreHandleKeyboardEvent(
|
||||
content::WebContents* source,
|
||||
const content::NativeWebKeyboardEvent& event) override;
|
||||
void EnterFullscreenModeForTab(content::WebContents* source,
|
||||
const GURL& origin) override;
|
||||
void ExitFullscreenModeForTab(content::WebContents* source) override;
|
||||
@@ -351,6 +357,11 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||
void DevToolsOpened() override;
|
||||
void DevToolsClosed() override;
|
||||
|
||||
void ShowAutofillPopup(content::RenderFrameHost* frame_host,
|
||||
const gfx::RectF& bounds,
|
||||
const std::vector<base::string16>& values,
|
||||
const std::vector<base::string16>& labels);
|
||||
|
||||
private:
|
||||
AtomBrowserContext* GetBrowserContext() const;
|
||||
|
||||
@@ -378,6 +389,9 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||
// get the zoom level.
|
||||
void OnGetZoomLevel(IPC::Message* reply_msg);
|
||||
|
||||
void InitZoomController(content::WebContents* web_contents,
|
||||
const mate::Dictionary& options);
|
||||
|
||||
v8::Global<v8::Value> session_;
|
||||
v8::Global<v8::Value> devtools_web_contents_;
|
||||
v8::Global<v8::Value> debugger_;
|
||||
|
||||
@@ -144,6 +144,7 @@ void Window::Init(v8::Isolate* isolate,
|
||||
options,
|
||||
parent.IsEmpty() ? nullptr : parent->window_.get()));
|
||||
web_contents->SetOwnerWindow(window_.get());
|
||||
window_->set_is_offscreen_dummy(api_web_contents_->IsOffScreen());
|
||||
|
||||
#if defined(TOOLKIT_VIEWS)
|
||||
// Sets the window icon.
|
||||
@@ -603,6 +604,14 @@ void Window::SetSkipTaskbar(bool skip) {
|
||||
window_->SetSkipTaskbar(skip);
|
||||
}
|
||||
|
||||
void Window::SetSimpleFullScreen(bool simple_fullscreen) {
|
||||
window_->SetSimpleFullScreen(simple_fullscreen);
|
||||
}
|
||||
|
||||
bool Window::IsSimpleFullScreen() {
|
||||
return window_->IsSimpleFullScreen();
|
||||
}
|
||||
|
||||
void Window::SetKiosk(bool kiosk) {
|
||||
window_->SetKiosk(kiosk);
|
||||
}
|
||||
@@ -623,6 +632,14 @@ bool Window::HasShadow() {
|
||||
return window_->HasShadow();
|
||||
}
|
||||
|
||||
void Window::SetOpacity(const double opacity) {
|
||||
window_->SetOpacity(opacity);
|
||||
}
|
||||
|
||||
double Window::GetOpacity() {
|
||||
return window_->GetOpacity();
|
||||
}
|
||||
|
||||
void Window::FocusOnWebView() {
|
||||
window_->FocusOnWebView();
|
||||
}
|
||||
@@ -651,8 +668,11 @@ bool Window::IsDocumentEdited() {
|
||||
return window_->IsDocumentEdited();
|
||||
}
|
||||
|
||||
void Window::SetIgnoreMouseEvents(bool ignore) {
|
||||
return window_->SetIgnoreMouseEvents(ignore);
|
||||
void Window::SetIgnoreMouseEvents(bool ignore, mate::Arguments* args) {
|
||||
mate::Dictionary options;
|
||||
bool forward = false;
|
||||
args->GetNext(&options) && options.Get("forward", &forward);
|
||||
return window_->SetIgnoreMouseEvents(ignore, forward);
|
||||
}
|
||||
|
||||
void Window::SetContentProtection(bool enable) {
|
||||
@@ -907,6 +927,30 @@ void Window::SetAutoHideCursor(bool auto_hide) {
|
||||
window_->SetAutoHideCursor(auto_hide);
|
||||
}
|
||||
|
||||
void Window::SelectPreviousTab() {
|
||||
window_->SelectPreviousTab();
|
||||
}
|
||||
|
||||
void Window::SelectNextTab() {
|
||||
window_->SelectNextTab();
|
||||
}
|
||||
|
||||
void Window::MergeAllWindows() {
|
||||
window_->MergeAllWindows();
|
||||
}
|
||||
|
||||
void Window::MoveTabToNewWindow() {
|
||||
window_->MoveTabToNewWindow();
|
||||
}
|
||||
|
||||
void Window::ToggleTabBar() {
|
||||
window_->ToggleTabBar();
|
||||
}
|
||||
|
||||
void Window::AddTabbedWindow(NativeWindow* window) {
|
||||
window_->AddTabbedWindow(window);
|
||||
}
|
||||
|
||||
void Window::SetVibrancy(mate::Arguments* args) {
|
||||
std::string type;
|
||||
|
||||
@@ -1018,11 +1062,15 @@ void Window::BuildPrototype(v8::Isolate* isolate,
|
||||
.SetMethod("getTitle", &Window::GetTitle)
|
||||
.SetMethod("flashFrame", &Window::FlashFrame)
|
||||
.SetMethod("setSkipTaskbar", &Window::SetSkipTaskbar)
|
||||
.SetMethod("setSimpleFullScreen", &Window::SetSimpleFullScreen)
|
||||
.SetMethod("isSimpleFullScreen", &Window::IsSimpleFullScreen)
|
||||
.SetMethod("setKiosk", &Window::SetKiosk)
|
||||
.SetMethod("isKiosk", &Window::IsKiosk)
|
||||
.SetMethod("setBackgroundColor", &Window::SetBackgroundColor)
|
||||
.SetMethod("setHasShadow", &Window::SetHasShadow)
|
||||
.SetMethod("hasShadow", &Window::HasShadow)
|
||||
.SetMethod("setOpacity", &Window::SetOpacity)
|
||||
.SetMethod("getOpacity", &Window::GetOpacity)
|
||||
.SetMethod("setRepresentedFilename", &Window::SetRepresentedFilename)
|
||||
.SetMethod("getRepresentedFilename", &Window::GetRepresentedFilename)
|
||||
.SetMethod("setDocumentEdited", &Window::SetDocumentEdited)
|
||||
@@ -1047,6 +1095,12 @@ void Window::BuildPrototype(v8::Isolate* isolate,
|
||||
&Window::IsVisibleOnAllWorkspaces)
|
||||
#if defined(OS_MACOSX)
|
||||
.SetMethod("setAutoHideCursor", &Window::SetAutoHideCursor)
|
||||
.SetMethod("mergeAllWindows", &Window::MergeAllWindows)
|
||||
.SetMethod("selectPreviousTab", &Window::SelectPreviousTab)
|
||||
.SetMethod("selectNextTab", &Window::SelectNextTab)
|
||||
.SetMethod("moveTabToNewWindow", &Window::MoveTabToNewWindow)
|
||||
.SetMethod("toggleTabBar", &Window::ToggleTabBar)
|
||||
.SetMethod("addTabbedWindow", &Window::AddTabbedWindow)
|
||||
#endif
|
||||
.SetMethod("setVibrancy", &Window::SetVibrancy)
|
||||
.SetMethod("_setTouchBarItems", &Window::SetTouchBar)
|
||||
|
||||
@@ -154,11 +154,15 @@ class Window : public mate::TrackableObject<Window>,
|
||||
std::string GetTitle();
|
||||
void FlashFrame(bool flash);
|
||||
void SetSkipTaskbar(bool skip);
|
||||
void SetSimpleFullScreen(bool simple_fullscreen);
|
||||
bool IsSimpleFullScreen();
|
||||
void SetKiosk(bool kiosk);
|
||||
bool IsKiosk();
|
||||
void SetBackgroundColor(const std::string& color_name);
|
||||
void SetHasShadow(bool has_shadow);
|
||||
bool HasShadow();
|
||||
void SetOpacity(const double opacity);
|
||||
double GetOpacity();
|
||||
void FocusOnWebView();
|
||||
void BlurWebView();
|
||||
bool IsWebViewFocused();
|
||||
@@ -166,7 +170,7 @@ class Window : public mate::TrackableObject<Window>,
|
||||
std::string GetRepresentedFilename();
|
||||
void SetDocumentEdited(bool edited);
|
||||
bool IsDocumentEdited();
|
||||
void SetIgnoreMouseEvents(bool ignore);
|
||||
void SetIgnoreMouseEvents(bool ignore, mate::Arguments* args);
|
||||
void SetContentProtection(bool enable);
|
||||
void SetFocusable(bool focusable);
|
||||
void SetProgressBar(double progress, mate::Arguments* args);
|
||||
@@ -212,6 +216,13 @@ class Window : public mate::TrackableObject<Window>,
|
||||
|
||||
void SetAutoHideCursor(bool auto_hide);
|
||||
|
||||
void SelectPreviousTab();
|
||||
void SelectNextTab();
|
||||
void MergeAllWindows();
|
||||
void MoveTabToNewWindow();
|
||||
void ToggleTabBar();
|
||||
void AddTabbedWindow(NativeWindow* window);
|
||||
|
||||
void SetVibrancy(mate::Arguments* args);
|
||||
void SetTouchBar(const std::vector<mate::PersistentDictionary>& items);
|
||||
void RefreshTouchBarItem(const std::string& item_id);
|
||||
|
||||
@@ -79,8 +79,12 @@ class EventEmitter : public Wrappable<T> {
|
||||
const Args&... args) {
|
||||
v8::Locker locker(isolate());
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
v8::Local<v8::Object> wrapper = GetWrapper();
|
||||
if (wrapper.IsEmpty()) {
|
||||
return false;
|
||||
}
|
||||
v8::Local<v8::Object> event = internal::CreateJSEvent(
|
||||
isolate(), GetWrapper(), sender, message);
|
||||
isolate(), wrapper, sender, message);
|
||||
return EmitWithEvent(name, event, args...);
|
||||
}
|
||||
|
||||
|
||||
121
atom/browser/api/event_subscriber.cc
Normal file
121
atom/browser/api/event_subscriber.cc
Normal file
@@ -0,0 +1,121 @@
|
||||
// Copyright (c) 2017 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/api/event_subscriber.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// A FunctionTemplate lifetime is bound to the v8 context, so it can be safely
|
||||
// stored as a global here since there's only one for the main process.
|
||||
v8::Global<v8::FunctionTemplate> g_cached_template;
|
||||
|
||||
struct JSHandlerData {
|
||||
JSHandlerData(v8::Isolate* isolate,
|
||||
mate::internal::EventSubscriberBase* subscriber)
|
||||
: handle_(isolate, v8::External::New(isolate, this)),
|
||||
subscriber_(subscriber) {
|
||||
handle_.SetWeak(this, GC, v8::WeakCallbackType::kFinalizer);
|
||||
}
|
||||
|
||||
static void GC(const v8::WeakCallbackInfo<JSHandlerData>& data) {
|
||||
delete data.GetParameter();
|
||||
}
|
||||
|
||||
v8::Global<v8::External> handle_;
|
||||
mate::internal::EventSubscriberBase* subscriber_;
|
||||
};
|
||||
|
||||
void InvokeCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
v8::Locker locker(info.GetIsolate());
|
||||
v8::HandleScope handle_scope(info.GetIsolate());
|
||||
v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
|
||||
v8::Context::Scope context_scope(context);
|
||||
mate::Arguments args(info);
|
||||
v8::Local<v8::Value> handler, event;
|
||||
args.GetNext(&handler);
|
||||
args.GetNext(&event);
|
||||
DCHECK(handler->IsExternal());
|
||||
DCHECK(event->IsString());
|
||||
JSHandlerData* handler_data = static_cast<JSHandlerData*>(
|
||||
v8::Local<v8::External>::Cast(handler)->Value());
|
||||
handler_data->subscriber_->EventEmitted(mate::V8ToString(event), &args);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace mate {
|
||||
|
||||
namespace internal {
|
||||
|
||||
EventSubscriberBase::EventSubscriberBase(v8::Isolate* isolate,
|
||||
v8::Local<v8::Object> emitter)
|
||||
: isolate_(isolate), emitter_(isolate, emitter) {
|
||||
if (g_cached_template.IsEmpty()) {
|
||||
g_cached_template = v8::Global<v8::FunctionTemplate>(
|
||||
isolate_, v8::FunctionTemplate::New(isolate_, InvokeCallback));
|
||||
}
|
||||
}
|
||||
|
||||
EventSubscriberBase::~EventSubscriberBase() {
|
||||
if (!isolate_) {
|
||||
return;
|
||||
}
|
||||
RemoveAllListeners();
|
||||
emitter_.Reset();
|
||||
DCHECK_EQ(js_handlers_.size(), 0);
|
||||
}
|
||||
|
||||
void EventSubscriberBase::On(const std::string& event_name) {
|
||||
DCHECK(js_handlers_.find(event_name) == js_handlers_.end());
|
||||
v8::Locker locker(isolate_);
|
||||
v8::Isolate::Scope isolate_scope(isolate_);
|
||||
v8::HandleScope handle_scope(isolate_);
|
||||
auto fn_template = g_cached_template.Get(isolate_);
|
||||
auto event = mate::StringToV8(isolate_, event_name);
|
||||
auto js_handler_data = new JSHandlerData(isolate_, this);
|
||||
v8::Local<v8::Value> fn = internal::BindFunctionWith(
|
||||
isolate_, isolate_->GetCurrentContext(), fn_template->GetFunction(),
|
||||
js_handler_data->handle_.Get(isolate_), event);
|
||||
js_handlers_.insert(
|
||||
std::make_pair(event_name, v8::Global<v8::Value>(isolate_, fn)));
|
||||
internal::ValueVector converted_args = {event, fn};
|
||||
internal::CallMethodWithArgs(isolate_, emitter_.Get(isolate_), "on",
|
||||
&converted_args);
|
||||
}
|
||||
|
||||
void EventSubscriberBase::Off(const std::string& event_name) {
|
||||
v8::Locker locker(isolate_);
|
||||
v8::Isolate::Scope isolate_scope(isolate_);
|
||||
v8::HandleScope handle_scope(isolate_);
|
||||
auto js_handler = js_handlers_.find(event_name);
|
||||
DCHECK(js_handler != js_handlers_.end());
|
||||
RemoveListener(js_handler);
|
||||
}
|
||||
|
||||
void EventSubscriberBase::RemoveAllListeners() {
|
||||
v8::Locker locker(isolate_);
|
||||
v8::Isolate::Scope isolate_scope(isolate_);
|
||||
v8::HandleScope handle_scope(isolate_);
|
||||
while (!js_handlers_.empty()) {
|
||||
RemoveListener(js_handlers_.begin());
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::string, v8::Global<v8::Value>>::iterator
|
||||
EventSubscriberBase::RemoveListener(
|
||||
std::map<std::string, v8::Global<v8::Value>>::iterator it) {
|
||||
internal::ValueVector args = {StringToV8(isolate_, it->first),
|
||||
it->second.Get(isolate_)};
|
||||
internal::CallMethodWithArgs(
|
||||
isolate_, v8::Local<v8::Object>::Cast(emitter_.Get(isolate_)),
|
||||
"removeListener", &args);
|
||||
it->second.Reset();
|
||||
return js_handlers_.erase(it);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace mate
|
||||
132
atom/browser/api/event_subscriber.h
Normal file
132
atom/browser/api/event_subscriber.h
Normal file
@@ -0,0 +1,132 @@
|
||||
// Copyright (c) 2017 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_EVENT_SUBSCRIBER_H_
|
||||
#define ATOM_BROWSER_API_EVENT_SUBSCRIBER_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "atom/common/api/event_emitter_caller.h"
|
||||
#include "base/synchronization/lock.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "native_mate/native_mate/arguments.h"
|
||||
|
||||
namespace mate {
|
||||
|
||||
namespace internal {
|
||||
|
||||
class EventSubscriberBase {
|
||||
public:
|
||||
EventSubscriberBase(v8::Isolate* isolate, v8::Local<v8::Object> emitter);
|
||||
virtual ~EventSubscriberBase();
|
||||
virtual void EventEmitted(const std::string& event_name,
|
||||
mate::Arguments* args) = 0;
|
||||
|
||||
protected:
|
||||
void On(const std::string& event_name);
|
||||
void Off(const std::string& event_name);
|
||||
void RemoveAllListeners();
|
||||
|
||||
private:
|
||||
std::map<std::string, v8::Global<v8::Value>>::iterator RemoveListener(
|
||||
std::map<std::string, v8::Global<v8::Value>>::iterator it);
|
||||
|
||||
v8::Isolate* isolate_;
|
||||
v8::Global<v8::Object> emitter_;
|
||||
std::map<std::string, v8::Global<v8::Value>> js_handlers_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(EventSubscriberBase);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename HandlerType>
|
||||
class EventSubscriber : internal::EventSubscriberBase {
|
||||
public:
|
||||
using EventCallback = void (HandlerType::*)(mate::Arguments* args);
|
||||
// Alias to unique_ptr with deleter.
|
||||
using unique_ptr = std::unique_ptr<EventSubscriber<HandlerType>,
|
||||
void (*)(EventSubscriber<HandlerType>*)>;
|
||||
// EventSubscriber should only be created/deleted in the main thread since it
|
||||
// communicates with the V8 engine. This smart pointer makes it simpler to
|
||||
// bind the lifetime of EventSubscriber with a class whose lifetime is managed
|
||||
// by a non-UI thread.
|
||||
class SafePtr : public unique_ptr {
|
||||
public:
|
||||
SafePtr() : SafePtr(nullptr) {}
|
||||
explicit SafePtr(EventSubscriber<HandlerType>* ptr)
|
||||
: unique_ptr(ptr, Deleter) {}
|
||||
|
||||
private:
|
||||
// Custom deleter that schedules destructor invocation to the main thread.
|
||||
static void Deleter(EventSubscriber<HandlerType>* ptr) {
|
||||
DCHECK(
|
||||
!::content::BrowserThread::CurrentlyOn(::content::BrowserThread::UI));
|
||||
DCHECK(ptr);
|
||||
// Acquire handler lock and reset handler_ to ensure that any new events
|
||||
// emitted will be ignored after this function returns
|
||||
base::AutoLock auto_lock(ptr->handler_lock_);
|
||||
ptr->handler_ = nullptr;
|
||||
content::BrowserThread::PostTask(
|
||||
content::BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(
|
||||
[](EventSubscriber<HandlerType>* subscriber) {
|
||||
delete subscriber;
|
||||
},
|
||||
ptr));
|
||||
}
|
||||
};
|
||||
|
||||
EventSubscriber(HandlerType* handler,
|
||||
v8::Isolate* isolate,
|
||||
v8::Local<v8::Object> emitter)
|
||||
: EventSubscriberBase(isolate, emitter), handler_(handler) {
|
||||
DCHECK_CURRENTLY_ON(::content::BrowserThread::UI);
|
||||
}
|
||||
|
||||
void On(const std::string& event, EventCallback callback) {
|
||||
DCHECK_CURRENTLY_ON(::content::BrowserThread::UI);
|
||||
EventSubscriberBase::On(event);
|
||||
callbacks_.insert(std::make_pair(event, callback));
|
||||
}
|
||||
|
||||
void Off(const std::string& event) {
|
||||
DCHECK_CURRENTLY_ON(::content::BrowserThread::UI);
|
||||
EventSubscriberBase::Off(event);
|
||||
DCHECK(callbacks_.find(event) != callbacks_.end());
|
||||
callbacks_.erase(callbacks_.find(event));
|
||||
}
|
||||
|
||||
void RemoveAllListeners() {
|
||||
DCHECK_CURRENTLY_ON(::content::BrowserThread::UI);
|
||||
EventSubscriberBase::RemoveAllListeners();
|
||||
callbacks_.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
void EventEmitted(const std::string& event_name,
|
||||
mate::Arguments* args) override {
|
||||
DCHECK_CURRENTLY_ON(::content::BrowserThread::UI);
|
||||
base::AutoLock auto_lock(handler_lock_);
|
||||
if (!handler_) {
|
||||
// handler_ was probably destroyed by another thread and we should not
|
||||
// access it.
|
||||
return;
|
||||
}
|
||||
auto it = callbacks_.find(event_name);
|
||||
if (it != callbacks_.end()) {
|
||||
auto method = it->second;
|
||||
(handler_->*method)(args);
|
||||
}
|
||||
}
|
||||
|
||||
HandlerType* handler_;
|
||||
base::Lock handler_lock_;
|
||||
std::map<std::string, EventCallback> callbacks_;
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
#endif // ATOM_BROWSER_API_EVENT_SUBSCRIBER_H_
|
||||
@@ -45,9 +45,9 @@ bool FrameSubscriber::ShouldCaptureFrame(
|
||||
|
||||
gfx::Size view_size = rect.size();
|
||||
gfx::Size bitmap_size = view_size;
|
||||
const gfx::NativeView native_view = view_->GetNativeView();
|
||||
gfx::NativeView native_view = view_->GetNativeView();
|
||||
const float scale =
|
||||
display::Screen::GetScreen()->GetDisplayNearestWindow(native_view)
|
||||
display::Screen::GetScreen()->GetDisplayNearestView(native_view)
|
||||
.device_scale_factor();
|
||||
if (scale > 1.0f)
|
||||
bitmap_size = gfx::ScaleToCeiledSize(view_size, scale);
|
||||
@@ -78,20 +78,32 @@ void FrameSubscriber::OnFrameDelivered(const FrameCaptureCallback& callback,
|
||||
v8::Locker locker(isolate_);
|
||||
v8::HandleScope handle_scope(isolate_);
|
||||
|
||||
size_t rgb_arr_size = bitmap.width() * bitmap.height() *
|
||||
bitmap.bytesPerPixel();
|
||||
v8::MaybeLocal<v8::Object> buffer = node::Buffer::New(isolate_, rgb_arr_size);
|
||||
size_t rgb_row_size = bitmap.width() * bitmap.bytesPerPixel();
|
||||
|
||||
v8::MaybeLocal<v8::Object> buffer =
|
||||
node::Buffer::New(isolate_, rgb_row_size * bitmap.height());
|
||||
|
||||
if (buffer.IsEmpty())
|
||||
return;
|
||||
|
||||
bitmap.copyPixelsTo(
|
||||
reinterpret_cast<uint8_t*>(node::Buffer::Data(buffer.ToLocalChecked())),
|
||||
rgb_arr_size);
|
||||
auto local_buffer = buffer.ToLocalChecked();
|
||||
|
||||
{
|
||||
SkAutoLockPixels lock(bitmap);
|
||||
auto source = static_cast<const unsigned char*>(bitmap.getPixels());
|
||||
auto target = node::Buffer::Data(local_buffer);
|
||||
|
||||
for (int y = 0; y < bitmap.height(); ++y) {
|
||||
memcpy(target, source, rgb_row_size);
|
||||
source += bitmap.rowBytes();
|
||||
target += rgb_row_size;
|
||||
}
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> damage =
|
||||
mate::Converter<gfx::Rect>::ToV8(isolate_, damage_rect);
|
||||
|
||||
callback_.Run(buffer.ToLocalChecked(), damage);
|
||||
callback_.Run(local_buffer, damage);
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "atom/browser/atom_browser_main_parts.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/memory/ptr_util.h"
|
||||
#include "base/supports_user_data.h"
|
||||
|
||||
namespace mate {
|
||||
@@ -46,16 +47,19 @@ void TrackableObjectBase::Destroy() {
|
||||
}
|
||||
|
||||
void TrackableObjectBase::AttachAsUserData(base::SupportsUserData* wrapped) {
|
||||
wrapped->SetUserData(kTrackedObjectKey, new IDUserData(weak_map_id_));
|
||||
wrapped->SetUserData(kTrackedObjectKey,
|
||||
base::MakeUnique<IDUserData>(weak_map_id_));
|
||||
}
|
||||
|
||||
// static
|
||||
int32_t TrackableObjectBase::GetIDFromWrappedClass(base::SupportsUserData* w) {
|
||||
auto id = static_cast<IDUserData*>(w->GetUserData(kTrackedObjectKey));
|
||||
if (id)
|
||||
return *id;
|
||||
else
|
||||
return 0;
|
||||
int32_t TrackableObjectBase::GetIDFromWrappedClass(
|
||||
base::SupportsUserData* wrapped) {
|
||||
if (wrapped) {
|
||||
auto id = static_cast<IDUserData*>(wrapped->GetUserData(kTrackedObjectKey));
|
||||
if (id)
|
||||
return *id;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
@@ -30,15 +30,15 @@ class TrackableObjectBase {
|
||||
// Wrap TrackableObject into a class that SupportsUserData.
|
||||
void AttachAsUserData(base::SupportsUserData* wrapped);
|
||||
|
||||
// Get the weak_map_id from SupportsUserData.
|
||||
static int32_t GetIDFromWrappedClass(base::SupportsUserData* wrapped);
|
||||
|
||||
protected:
|
||||
virtual ~TrackableObjectBase();
|
||||
|
||||
// Returns a closure that can destroy the native class.
|
||||
base::Closure GetDestroyClosure();
|
||||
|
||||
// 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 base::Closure RegisterDestructionCallback(const base::Closure& c);
|
||||
@@ -62,7 +62,10 @@ class TrackableObject : public TrackableObjectBase,
|
||||
public:
|
||||
// Mark the JS object as destroyed.
|
||||
void MarkDestroyed() {
|
||||
Wrappable<T>::GetWrapper()->SetAlignedPointerInInternalField(0, nullptr);
|
||||
v8::Local<v8::Object> wrapper = Wrappable<T>::GetWrapper();
|
||||
if (!wrapper.IsEmpty()) {
|
||||
wrapper->SetAlignedPointerInInternalField(0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
bool IsDestroyed() {
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include "atom/browser/net/about_protocol_handler.h"
|
||||
#include "atom/browser/net/asar/asar_protocol_handler.h"
|
||||
#include "atom/browser/net/atom_cert_verifier.h"
|
||||
#include "atom/browser/net/atom_ct_delegate.h"
|
||||
#include "atom/browser/net/atom_network_delegate.h"
|
||||
#include "atom/browser/net/atom_url_request_job_factory.h"
|
||||
#include "atom/browser/net/http_protocol_handler.h"
|
||||
@@ -72,7 +71,6 @@ AtomBrowserContext::AtomBrowserContext(const std::string& partition,
|
||||
bool in_memory,
|
||||
const base::DictionaryValue& options)
|
||||
: brightray::BrowserContext(partition, in_memory),
|
||||
ct_delegate_(new AtomCTDelegate),
|
||||
network_delegate_(new AtomNetworkDelegate),
|
||||
cookie_delegate_(new AtomCookieDelegate) {
|
||||
// Construct user agent string.
|
||||
@@ -192,8 +190,9 @@ content::PermissionManager* AtomBrowserContext::GetPermissionManager() {
|
||||
return permission_manager_.get();
|
||||
}
|
||||
|
||||
std::unique_ptr<net::CertVerifier> AtomBrowserContext::CreateCertVerifier() {
|
||||
return base::WrapUnique(new AtomCertVerifier(ct_delegate_.get()));
|
||||
std::unique_ptr<net::CertVerifier> AtomBrowserContext::CreateCertVerifier(
|
||||
brightray::RequireCTDelegate* ct_delegate) {
|
||||
return base::WrapUnique(new AtomCertVerifier(ct_delegate));
|
||||
}
|
||||
|
||||
std::vector<std::string> AtomBrowserContext::GetCookieableSchemes() {
|
||||
@@ -204,11 +203,6 @@ std::vector<std::string> AtomBrowserContext::GetCookieableSchemes() {
|
||||
return default_schemes;
|
||||
}
|
||||
|
||||
net::TransportSecurityState::RequireCTDelegate*
|
||||
AtomBrowserContext::GetRequireCTDelegate() {
|
||||
return ct_delegate_.get();
|
||||
}
|
||||
|
||||
void AtomBrowserContext::RegisterPrefs(PrefRegistrySimple* pref_registry) {
|
||||
pref_registry->RegisterFilePathPref(prefs::kSelectFileLastDirectory,
|
||||
base::FilePath());
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
namespace atom {
|
||||
|
||||
class AtomBlobReader;
|
||||
class AtomCTDelegate;
|
||||
class AtomDownloadManagerDelegate;
|
||||
class AtomNetworkDelegate;
|
||||
class AtomPermissionManager;
|
||||
@@ -40,10 +39,9 @@ class AtomBrowserContext : public brightray::BrowserContext {
|
||||
content::ProtocolHandlerMap* protocol_handlers) override;
|
||||
net::HttpCache::BackendFactory* CreateHttpCacheBackendFactory(
|
||||
const base::FilePath& base_path) override;
|
||||
std::unique_ptr<net::CertVerifier> CreateCertVerifier() override;
|
||||
std::unique_ptr<net::CertVerifier> CreateCertVerifier(
|
||||
brightray::RequireCTDelegate* ct_delegate) override;
|
||||
std::vector<std::string> GetCookieableSchemes() override;
|
||||
net::TransportSecurityState::RequireCTDelegate* GetRequireCTDelegate()
|
||||
override;
|
||||
|
||||
// content::BrowserContext:
|
||||
content::DownloadManagerDelegate* GetDownloadManagerDelegate() override;
|
||||
@@ -69,7 +67,6 @@ class AtomBrowserContext : public brightray::BrowserContext {
|
||||
std::unique_ptr<WebViewManager> guest_manager_;
|
||||
std::unique_ptr<AtomPermissionManager> permission_manager_;
|
||||
std::unique_ptr<AtomBlobReader> blob_reader_;
|
||||
std::unique_ptr<AtomCTDelegate> ct_delegate_;
|
||||
std::string user_agent_;
|
||||
bool use_cache_;
|
||||
|
||||
|
||||
@@ -92,6 +92,7 @@ void AtomDownloadManagerDelegate::OnDownloadPathGenerated(
|
||||
// Show save dialog if save path was not set already on item
|
||||
file_dialog::DialogSettings settings;
|
||||
settings.parent_window = window;
|
||||
settings.force_detached = window->is_offscreen_dummy();
|
||||
settings.title = item->GetURL().spec();
|
||||
settings.default_path = default_path;
|
||||
if (path.empty() && file_dialog::ShowSaveDialog(settings, &path)) {
|
||||
@@ -115,7 +116,10 @@ void AtomDownloadManagerDelegate::OnDownloadPathGenerated(
|
||||
// If user cancels the file save dialog, run the callback with empty FilePath.
|
||||
callback.Run(path,
|
||||
content::DownloadItem::TARGET_DISPOSITION_PROMPT,
|
||||
content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, path);
|
||||
content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, path,
|
||||
path.empty() ?
|
||||
content::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED :
|
||||
content::DOWNLOAD_INTERRUPT_REASON_NONE);
|
||||
}
|
||||
|
||||
void AtomDownloadManagerDelegate::Shutdown() {
|
||||
@@ -132,7 +136,8 @@ bool AtomDownloadManagerDelegate::DetermineDownloadTarget(
|
||||
callback.Run(download->GetForcedFilePath(),
|
||||
content::DownloadItem::TARGET_DISPOSITION_OVERWRITE,
|
||||
content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
|
||||
download->GetForcedFilePath());
|
||||
download->GetForcedFilePath(),
|
||||
content::DOWNLOAD_INTERRUPT_REASON_NONE);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -143,7 +148,7 @@ bool AtomDownloadManagerDelegate::DetermineDownloadTarget(
|
||||
callback.Run(save_path,
|
||||
content::DownloadItem::TARGET_DISPOSITION_OVERWRITE,
|
||||
content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
|
||||
save_path);
|
||||
save_path, content::DOWNLOAD_INTERRUPT_REASON_NONE);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/download_manager.h"
|
||||
#include "content/public/browser/render_frame_host.h"
|
||||
#include "content/public/browser/stream_info.h"
|
||||
#include "net/base/escape.h"
|
||||
#include "net/ssl/client_cert_store.h"
|
||||
@@ -34,8 +35,7 @@ namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
void OnOpenExternal(const GURL& escaped_url,
|
||||
bool allowed) {
|
||||
void OnOpenExternal(const GURL& escaped_url, bool allowed) {
|
||||
if (allowed)
|
||||
platform_util::OpenExternal(
|
||||
#if defined(OS_WIN)
|
||||
@@ -66,6 +66,8 @@ void HandleExternalProtocolInUI(
|
||||
|
||||
void OnPdfResourceIntercepted(
|
||||
const GURL& original_url,
|
||||
int render_process_host_id,
|
||||
int render_frame_id,
|
||||
const content::ResourceRequestInfo::WebContentsGetter&
|
||||
web_contents_getter) {
|
||||
content::WebContents* web_contents = web_contents_getter.Run();
|
||||
@@ -75,7 +77,7 @@ void OnPdfResourceIntercepted(
|
||||
if (!WebContentsPreferences::IsPluginsEnabled(web_contents)) {
|
||||
auto browser_context = web_contents->GetBrowserContext();
|
||||
auto download_manager =
|
||||
content::BrowserContext::GetDownloadManager(browser_context);
|
||||
content::BrowserContext::GetDownloadManager(browser_context);
|
||||
|
||||
download_manager->DownloadUrl(
|
||||
content::DownloadUrlParameters::CreateForWebContentsMainFrame(
|
||||
@@ -86,26 +88,29 @@ void OnPdfResourceIntercepted(
|
||||
// The URL passes the original pdf resource url, that will be requested
|
||||
// by the webui page.
|
||||
// chrome://pdf-viewer/index.html?src=https://somepage/123.pdf
|
||||
content::NavigationController::LoadURLParams params(
|
||||
GURL(base::StringPrintf(
|
||||
"%sindex.html?%s=%s",
|
||||
kPdfViewerUIOrigin,
|
||||
kPdfPluginSrc,
|
||||
net::EscapeUrlEncodedData(original_url.spec(), false).c_str())));
|
||||
content::NavigationController::LoadURLParams params(GURL(base::StringPrintf(
|
||||
"%sindex.html?%s=%s", kPdfViewerUIOrigin, kPdfPluginSrc,
|
||||
net::EscapeUrlEncodedData(original_url.spec(), false).c_str())));
|
||||
|
||||
content::RenderFrameHost* frame_host =
|
||||
content::RenderFrameHost::FromID(render_process_host_id, render_frame_id);
|
||||
if (!frame_host) {
|
||||
return;
|
||||
}
|
||||
|
||||
params.frame_tree_node_id = frame_host->GetFrameTreeNodeId();
|
||||
web_contents->GetController().LoadURLWithParams(params);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
AtomResourceDispatcherHostDelegate::AtomResourceDispatcherHostDelegate() {
|
||||
}
|
||||
AtomResourceDispatcherHostDelegate::AtomResourceDispatcherHostDelegate() {}
|
||||
|
||||
bool AtomResourceDispatcherHostDelegate::HandleExternalProtocol(
|
||||
const GURL& url,
|
||||
content::ResourceRequestInfo* info) {
|
||||
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(&HandleExternalProtocolInUI,
|
||||
url,
|
||||
base::Bind(&HandleExternalProtocolInUI, url,
|
||||
info->GetWebContentsGetterForRequest(),
|
||||
info->HasUserGesture()));
|
||||
return true;
|
||||
@@ -121,16 +126,16 @@ AtomResourceDispatcherHostDelegate::CreateLoginDelegate(
|
||||
std::unique_ptr<net::ClientCertStore>
|
||||
AtomResourceDispatcherHostDelegate::CreateClientCertStore(
|
||||
content::ResourceContext* resource_context) {
|
||||
#if defined(USE_NSS_CERTS)
|
||||
return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreNSS(
|
||||
net::ClientCertStoreNSS::PasswordDelegateFactory()));
|
||||
#elif defined(OS_WIN)
|
||||
return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreWin());
|
||||
#elif defined(OS_MACOSX)
|
||||
return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreMac());
|
||||
#elif defined(USE_OPENSSL)
|
||||
return std::unique_ptr<net::ClientCertStore>();
|
||||
#endif
|
||||
#if defined(USE_NSS_CERTS)
|
||||
return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreNSS(
|
||||
net::ClientCertStoreNSS::PasswordDelegateFactory()));
|
||||
#elif defined(OS_WIN)
|
||||
return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreWin());
|
||||
#elif defined(OS_MACOSX)
|
||||
return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreMac());
|
||||
#elif defined(USE_OPENSSL)
|
||||
return std::unique_ptr<net::ClientCertStore>();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool AtomResourceDispatcherHostDelegate::ShouldInterceptResourceAsStream(
|
||||
@@ -141,11 +146,20 @@ bool AtomResourceDispatcherHostDelegate::ShouldInterceptResourceAsStream(
|
||||
std::string* payload) {
|
||||
const content::ResourceRequestInfo* info =
|
||||
content::ResourceRequestInfo::ForRequest(request);
|
||||
if (mime_type == "application/pdf" && info->IsMainFrame()) {
|
||||
|
||||
int render_process_host_id;
|
||||
int render_frame_id;
|
||||
if (!info->GetAssociatedRenderFrame(&render_process_host_id,
|
||||
&render_frame_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mime_type == "application/pdf") {
|
||||
*origin = GURL(kPdfViewerUIOrigin);
|
||||
content::BrowserThread::PostTask(
|
||||
BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(&OnPdfResourceIntercepted, request->url(),
|
||||
render_process_host_id, render_frame_id,
|
||||
info->GetWebContentsGetterForRequest()));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -11,27 +11,28 @@ namespace atom {
|
||||
void BridgeTaskRunner::MessageLoopIsReady() {
|
||||
auto message_loop = base::MessageLoop::current();
|
||||
CHECK(message_loop);
|
||||
for (const TaskPair& task : tasks_) {
|
||||
for (TaskPair& task : tasks_) {
|
||||
message_loop->task_runner()->PostDelayedTask(
|
||||
base::get<0>(task), base::get<1>(task), base::get<2>(task));
|
||||
std::get<0>(task), std::move(std::get<1>(task)), std::get<2>(task));
|
||||
}
|
||||
for (const TaskPair& task : non_nestable_tasks_) {
|
||||
for (TaskPair& task : non_nestable_tasks_) {
|
||||
message_loop->task_runner()->PostNonNestableDelayedTask(
|
||||
base::get<0>(task), base::get<1>(task), base::get<2>(task));
|
||||
std::get<0>(task), std::move(std::get<1>(task)), std::get<2>(task));
|
||||
}
|
||||
}
|
||||
|
||||
bool BridgeTaskRunner::PostDelayedTask(
|
||||
const tracked_objects::Location& from_here,
|
||||
const base::Closure& task,
|
||||
base::OnceClosure task,
|
||||
base::TimeDelta delay) {
|
||||
auto message_loop = base::MessageLoop::current();
|
||||
if (!message_loop) {
|
||||
tasks_.push_back(std::make_tuple(from_here, task, delay));
|
||||
tasks_.push_back(std::make_tuple(from_here, std::move(task), delay));
|
||||
return true;
|
||||
}
|
||||
|
||||
return message_loop->task_runner()->PostDelayedTask(from_here, task, delay);
|
||||
return message_loop->task_runner()->PostDelayedTask(
|
||||
from_here, std::move(task), delay);
|
||||
}
|
||||
|
||||
bool BridgeTaskRunner::RunsTasksOnCurrentThread() const {
|
||||
@@ -44,16 +45,17 @@ bool BridgeTaskRunner::RunsTasksOnCurrentThread() const {
|
||||
|
||||
bool BridgeTaskRunner::PostNonNestableDelayedTask(
|
||||
const tracked_objects::Location& from_here,
|
||||
const base::Closure& task,
|
||||
base::OnceClosure task,
|
||||
base::TimeDelta delay) {
|
||||
auto message_loop = base::MessageLoop::current();
|
||||
if (!message_loop) {
|
||||
non_nestable_tasks_.push_back(std::make_tuple(from_here, task, delay));
|
||||
non_nestable_tasks_.push_back(std::make_tuple(
|
||||
from_here, std::move(task), delay));
|
||||
return true;
|
||||
}
|
||||
|
||||
return message_loop->task_runner()->PostNonNestableDelayedTask(
|
||||
from_here, task, delay);
|
||||
from_here, std::move(task), delay);
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -25,17 +25,17 @@ class BridgeTaskRunner : public base::SingleThreadTaskRunner {
|
||||
|
||||
// base::SingleThreadTaskRunner:
|
||||
bool PostDelayedTask(const tracked_objects::Location& from_here,
|
||||
const base::Closure& task,
|
||||
base::OnceClosure task,
|
||||
base::TimeDelta delay) override;
|
||||
bool RunsTasksOnCurrentThread() const override;
|
||||
bool PostNonNestableDelayedTask(
|
||||
const tracked_objects::Location& from_here,
|
||||
const base::Closure& task,
|
||||
base::OnceClosure task,
|
||||
base::TimeDelta delay) override;
|
||||
|
||||
private:
|
||||
using TaskPair = std::tuple<
|
||||
tracked_objects::Location, base::Closure, base::TimeDelta>;
|
||||
tracked_objects::Location, base::OnceClosure, base::TimeDelta>;
|
||||
std::vector<TaskPair> tasks_;
|
||||
std::vector<TaskPair> non_nestable_tasks_;
|
||||
|
||||
|
||||
@@ -119,10 +119,32 @@ class Browser : public WindowListObserver {
|
||||
// Returns the type name of the current user activity.
|
||||
std::string GetCurrentActivityType();
|
||||
|
||||
// Invalidates the current user activity.
|
||||
void InvalidateCurrentActivity();
|
||||
|
||||
// Updates the current user activity
|
||||
void UpdateCurrentActivity(const std::string& type,
|
||||
const base::DictionaryValue& user_info);
|
||||
|
||||
// Indicates that an user activity is about to be resumed.
|
||||
bool WillContinueUserActivity(const std::string& type);
|
||||
|
||||
// Indicates a failure to resume a Handoff activity.
|
||||
void DidFailToContinueUserActivity(const std::string& type,
|
||||
const std::string& error);
|
||||
|
||||
// Resumes an activity via hand-off.
|
||||
bool ContinueUserActivity(const std::string& type,
|
||||
const base::DictionaryValue& user_info);
|
||||
|
||||
// Indicates that an activity was continued on another device.
|
||||
void UserActivityWasContinued(const std::string& type,
|
||||
const base::DictionaryValue& user_info);
|
||||
|
||||
// Gives an oportunity to update the Handoff payload.
|
||||
bool UpdateUserActivityState(const std::string& type,
|
||||
const base::DictionaryValue& user_info);
|
||||
|
||||
// Bounce the dock icon.
|
||||
enum BounceType {
|
||||
BOUNCE_CRITICAL = 0,
|
||||
|
||||
@@ -4,16 +4,62 @@
|
||||
|
||||
#include "atom/browser/browser.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/window_list.h"
|
||||
#include "atom/common/atom_version.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/environment.h"
|
||||
#include "base/process/launch.h"
|
||||
#include "brightray/common/application_info.h"
|
||||
|
||||
#if defined(USE_X11)
|
||||
#include "chrome/browser/ui/libgtkui/gtk_util.h"
|
||||
#include "chrome/browser/ui/libgtkui/unity_service.h"
|
||||
#endif
|
||||
|
||||
namespace atom {
|
||||
|
||||
const char kXdgSettings[] = "xdg-settings";
|
||||
const char kXdgSettingsDefaultSchemeHandler[] = "default-url-scheme-handler";
|
||||
|
||||
bool LaunchXdgUtility(const std::vector<std::string>& argv, int* exit_code) {
|
||||
*exit_code = EXIT_FAILURE;
|
||||
int devnull = open("/dev/null", O_RDONLY);
|
||||
if (devnull < 0) return false;
|
||||
|
||||
base::LaunchOptions options;
|
||||
|
||||
base::FileHandleMappingVector remap;
|
||||
remap.push_back(std::make_pair(devnull, STDIN_FILENO));
|
||||
options.fds_to_remap = &remap;
|
||||
|
||||
base::Process process = base::LaunchProcess(argv, options);
|
||||
close(devnull);
|
||||
|
||||
if (!process.IsValid()) return false;
|
||||
return process.WaitForExit(exit_code);
|
||||
}
|
||||
|
||||
bool SetDefaultWebClient(const std::string& protocol) {
|
||||
std::unique_ptr<base::Environment> env(base::Environment::Create());
|
||||
|
||||
std::vector<std::string> argv;
|
||||
argv.push_back(kXdgSettings);
|
||||
argv.push_back("set");
|
||||
if (!protocol.empty()) {
|
||||
argv.push_back(kXdgSettingsDefaultSchemeHandler);
|
||||
argv.push_back(protocol);
|
||||
}
|
||||
argv.push_back(libgtkui::GetDesktopName(env.get()));
|
||||
|
||||
int exit_code;
|
||||
bool ran_ok = LaunchXdgUtility(argv, &exit_code);
|
||||
return ran_ok && exit_code == EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void Browser::Focus() {
|
||||
// Focus on the first visible window.
|
||||
for (const auto& window : WindowList::GetWindows()) {
|
||||
@@ -33,18 +79,40 @@ void Browser::ClearRecentDocuments() {
|
||||
void Browser::SetAppUserModelID(const base::string16& name) {
|
||||
}
|
||||
|
||||
bool Browser::RemoveAsDefaultProtocolClient(const std::string& protocol,
|
||||
mate::Arguments* args) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Browser::SetAsDefaultProtocolClient(const std::string& protocol,
|
||||
mate::Arguments* args) {
|
||||
return false;
|
||||
return SetDefaultWebClient(protocol);
|
||||
}
|
||||
|
||||
bool Browser::IsDefaultProtocolClient(const std::string& protocol,
|
||||
mate::Arguments* args) {
|
||||
std::unique_ptr<base::Environment> env(base::Environment::Create());
|
||||
|
||||
if (protocol.empty()) return false;
|
||||
|
||||
std::vector<std::string> argv;
|
||||
argv.push_back(kXdgSettings);
|
||||
argv.push_back("check");
|
||||
argv.push_back(kXdgSettingsDefaultSchemeHandler);
|
||||
argv.push_back(protocol);
|
||||
argv.push_back(libgtkui::GetDesktopName(env.get()));
|
||||
|
||||
std::string reply;
|
||||
int success_code;
|
||||
bool ran_ok = base::GetAppOutputWithExitCode(base::CommandLine(argv),
|
||||
&reply, &success_code);
|
||||
|
||||
if (!ran_ok || success_code != EXIT_SUCCESS) return false;
|
||||
|
||||
// Allow any reply that starts with "yes".
|
||||
return base::StartsWith(reply, "yes", base::CompareCase::SENSITIVE)
|
||||
? true
|
||||
: false;
|
||||
}
|
||||
|
||||
// Todo implement
|
||||
bool Browser::RemoveAsDefaultProtocolClient(const std::string& protocol,
|
||||
mate::Arguments* args) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -144,6 +144,30 @@ std::string Browser::GetCurrentActivityType() {
|
||||
return base::SysNSStringToUTF8(userActivity.activityType);
|
||||
}
|
||||
|
||||
void Browser::InvalidateCurrentActivity() {
|
||||
[[AtomApplication sharedApplication] invalidateCurrentActivity];
|
||||
}
|
||||
|
||||
void Browser::UpdateCurrentActivity(const std::string& type,
|
||||
const base::DictionaryValue& user_info) {
|
||||
[[AtomApplication sharedApplication]
|
||||
updateCurrentActivity:base::SysUTF8ToNSString(type)
|
||||
withUserInfo:DictionaryValueToNSDictionary(user_info)];
|
||||
}
|
||||
|
||||
bool Browser::WillContinueUserActivity(const std::string& type) {
|
||||
bool prevent_default = false;
|
||||
for (BrowserObserver& observer : observers_)
|
||||
observer.OnWillContinueUserActivity(&prevent_default, type);
|
||||
return prevent_default;
|
||||
}
|
||||
|
||||
void Browser::DidFailToContinueUserActivity(const std::string& type,
|
||||
const std::string& error) {
|
||||
for (BrowserObserver& observer : observers_)
|
||||
observer.OnDidFailToContinueUserActivity(type, error);
|
||||
}
|
||||
|
||||
bool Browser::ContinueUserActivity(const std::string& type,
|
||||
const base::DictionaryValue& user_info) {
|
||||
bool prevent_default = false;
|
||||
@@ -152,6 +176,20 @@ bool Browser::ContinueUserActivity(const std::string& type,
|
||||
return prevent_default;
|
||||
}
|
||||
|
||||
void Browser::UserActivityWasContinued(const std::string& type,
|
||||
const base::DictionaryValue& user_info) {
|
||||
for (BrowserObserver& observer : observers_)
|
||||
observer.OnUserActivityWasContinued(type, user_info);
|
||||
}
|
||||
|
||||
bool Browser::UpdateUserActivityState(const std::string& type,
|
||||
const base::DictionaryValue& user_info) {
|
||||
bool prevent_default = false;
|
||||
for (BrowserObserver& observer : observers_)
|
||||
observer.OnUpdateUserActivityState(&prevent_default, type, user_info);
|
||||
return prevent_default;
|
||||
}
|
||||
|
||||
Browser::LoginItemSettings Browser::GetLoginItemSettings(
|
||||
const LoginItemSettings& options) {
|
||||
LoginItemSettings settings;
|
||||
|
||||
@@ -59,12 +59,28 @@ class BrowserObserver {
|
||||
virtual void OnPreMainMessageLoopRun() {}
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
// The browser wants to report that an user activity will resume. (macOS only)
|
||||
virtual void OnWillContinueUserActivity(
|
||||
bool* prevent_default,
|
||||
const std::string& type) {}
|
||||
// The browser wants to report an user activity resuming error. (macOS only)
|
||||
virtual void OnDidFailToContinueUserActivity(
|
||||
const std::string& type,
|
||||
const std::string& error) {}
|
||||
// The browser wants to resume a user activity via handoff. (macOS only)
|
||||
virtual void OnContinueUserActivity(
|
||||
bool* prevent_default,
|
||||
const std::string& type,
|
||||
const base::DictionaryValue& user_info) {}
|
||||
|
||||
// The browser wants to notify that an user activity was resumed. (macOS only)
|
||||
virtual void OnUserActivityWasContinued(
|
||||
const std::string& type,
|
||||
const base::DictionaryValue& user_info) {}
|
||||
// The browser wants to update an user activity payload. (macOS only)
|
||||
virtual void OnUpdateUserActivityState(
|
||||
bool* prevent_default,
|
||||
const std::string& type,
|
||||
const base::DictionaryValue& user_info) {}
|
||||
// User clicked the native macOS new tab button. (macOS only)
|
||||
virtual void OnNewWindowForTab() {}
|
||||
#endif
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "atom/browser/web_dialog_helper.h"
|
||||
#include "atom/common/atom_constants.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/memory/ptr_util.h"
|
||||
#include "chrome/browser/printing/print_preview_message_handler.h"
|
||||
#include "chrome/browser/printing/print_view_manager_basic.h"
|
||||
#include "chrome/browser/ssl/security_state_tab_helper.h"
|
||||
@@ -241,7 +242,8 @@ void CommonWebContentsDelegate::RunFileChooser(
|
||||
content::RenderFrameHost* render_frame_host,
|
||||
const content::FileChooserParams& params) {
|
||||
if (!web_dialog_helper_)
|
||||
web_dialog_helper_.reset(new WebDialogHelper(owner_window()));
|
||||
web_dialog_helper_.reset(new WebDialogHelper(
|
||||
owner_window(), owner_window()->is_offscreen_dummy()));
|
||||
web_dialog_helper_->RunFileChooser(render_frame_host, params);
|
||||
}
|
||||
|
||||
@@ -249,7 +251,8 @@ 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_.reset(new WebDialogHelper(
|
||||
owner_window(), owner_window()->is_offscreen_dummy()));
|
||||
web_dialog_helper_->EnumerateDirectory(guest, request_id, path);
|
||||
}
|
||||
|
||||
@@ -297,10 +300,11 @@ void CommonWebContentsDelegate::DevToolsSaveToFile(
|
||||
} else {
|
||||
file_dialog::DialogSettings settings;
|
||||
settings.parent_window = owner_window();
|
||||
settings.force_detached = owner_window()->is_offscreen_dummy();
|
||||
settings.title = url;
|
||||
settings.default_path = base::FilePath::FromUTF8Unsafe(url);
|
||||
if (!file_dialog::ShowSaveDialog(settings, &path)) {
|
||||
base::StringValue url_value(url);
|
||||
base::Value url_value(url);
|
||||
web_contents_->CallClientFunction(
|
||||
"DevToolsAPI.canceledSaveURL", &url_value, nullptr, nullptr);
|
||||
return;
|
||||
@@ -363,6 +367,7 @@ void CommonWebContentsDelegate::DevToolsAddFileSystem(
|
||||
std::vector<base::FilePath> paths;
|
||||
file_dialog::DialogSettings settings;
|
||||
settings.parent_window = owner_window();
|
||||
settings.force_detached = owner_window()->is_offscreen_dummy();
|
||||
settings.properties = file_dialog::FILE_DIALOG_OPEN_DIRECTORY;
|
||||
if (!file_dialog::ShowOpenDialog(settings, &paths))
|
||||
return;
|
||||
@@ -384,7 +389,7 @@ void CommonWebContentsDelegate::DevToolsAddFileSystem(
|
||||
auto pref_service = GetPrefService(GetDevToolsWebContents());
|
||||
DictionaryPrefUpdate update(pref_service, prefs::kDevToolsFileSystemPaths);
|
||||
update.Get()->SetWithoutPathExpansion(
|
||||
path.AsUTF8Unsafe(), base::Value::CreateNullValue());
|
||||
path.AsUTF8Unsafe(), base::MakeUnique<base::Value>());
|
||||
|
||||
web_contents_->CallClientFunction("DevToolsAPI.fileSystemAdded",
|
||||
file_system_value.get(),
|
||||
@@ -404,7 +409,7 @@ void CommonWebContentsDelegate::DevToolsRemoveFileSystem(
|
||||
DictionaryPrefUpdate update(pref_service, prefs::kDevToolsFileSystemPaths);
|
||||
update.Get()->RemoveWithoutPathExpansion(path, nullptr);
|
||||
|
||||
base::StringValue file_system_path_value(path);
|
||||
base::Value file_system_path_value(path);
|
||||
web_contents_->CallClientFunction("DevToolsAPI.fileSystemRemoved",
|
||||
&file_system_path_value,
|
||||
nullptr, nullptr);
|
||||
@@ -468,7 +473,7 @@ void CommonWebContentsDelegate::DevToolsSearchInPath(
|
||||
void CommonWebContentsDelegate::OnDevToolsSaveToFile(
|
||||
const std::string& url) {
|
||||
// Notify DevTools.
|
||||
base::StringValue url_value(url);
|
||||
base::Value url_value(url);
|
||||
web_contents_->CallClientFunction(
|
||||
"DevToolsAPI.savedURL", &url_value, nullptr, nullptr);
|
||||
}
|
||||
@@ -476,7 +481,7 @@ void CommonWebContentsDelegate::OnDevToolsSaveToFile(
|
||||
void CommonWebContentsDelegate::OnDevToolsAppendToFile(
|
||||
const std::string& url) {
|
||||
// Notify DevTools.
|
||||
base::StringValue url_value(url);
|
||||
base::Value url_value(url);
|
||||
web_contents_->CallClientFunction(
|
||||
"DevToolsAPI.appendedToURL", &url_value, nullptr, nullptr);
|
||||
}
|
||||
@@ -486,7 +491,7 @@ void CommonWebContentsDelegate::OnDevToolsIndexingWorkCalculated(
|
||||
const std::string& file_system_path,
|
||||
int total_work) {
|
||||
base::Value request_id_value(request_id);
|
||||
base::StringValue file_system_path_value(file_system_path);
|
||||
base::Value file_system_path_value(file_system_path);
|
||||
base::Value total_work_value(total_work);
|
||||
web_contents_->CallClientFunction("DevToolsAPI.indexingTotalWorkCalculated",
|
||||
&request_id_value,
|
||||
@@ -499,7 +504,7 @@ void CommonWebContentsDelegate::OnDevToolsIndexingWorked(
|
||||
const std::string& file_system_path,
|
||||
int worked) {
|
||||
base::Value request_id_value(request_id);
|
||||
base::StringValue file_system_path_value(file_system_path);
|
||||
base::Value file_system_path_value(file_system_path);
|
||||
base::Value worked_value(worked);
|
||||
web_contents_->CallClientFunction("DevToolsAPI.indexingWorked",
|
||||
&request_id_value,
|
||||
@@ -512,7 +517,7 @@ void CommonWebContentsDelegate::OnDevToolsIndexingDone(
|
||||
const std::string& file_system_path) {
|
||||
devtools_indexing_jobs_.erase(request_id);
|
||||
base::Value request_id_value(request_id);
|
||||
base::StringValue file_system_path_value(file_system_path);
|
||||
base::Value file_system_path_value(file_system_path);
|
||||
web_contents_->CallClientFunction("DevToolsAPI.indexingDone",
|
||||
&request_id_value,
|
||||
&file_system_path_value,
|
||||
@@ -528,7 +533,7 @@ void CommonWebContentsDelegate::OnDevToolsSearchCompleted(
|
||||
file_paths_value.AppendString(file_path);
|
||||
}
|
||||
base::Value request_id_value(request_id);
|
||||
base::StringValue file_system_path_value(file_system_path);
|
||||
base::Value file_system_path_value(file_system_path);
|
||||
web_contents_->CallClientFunction("DevToolsAPI.searchCompleted",
|
||||
&request_id_value,
|
||||
&file_system_path_value,
|
||||
|
||||
@@ -20,11 +20,11 @@ void CommonWebContentsDelegate::HandleKeyboardEvent(
|
||||
content::WebContents* source,
|
||||
const content::NativeWebKeyboardEvent& event) {
|
||||
if (event.skip_in_browser ||
|
||||
event.type() == content::NativeWebKeyboardEvent::Char)
|
||||
event.GetType() == content::NativeWebKeyboardEvent::kChar)
|
||||
return;
|
||||
|
||||
// Escape exits tabbed fullscreen mode.
|
||||
if (event.windowsKeyCode == ui::VKEY_ESCAPE && is_html_fullscreen())
|
||||
if (event.windows_key_code == ui::VKEY_ESCAPE && is_html_fullscreen())
|
||||
ExitFullscreenModeForTab(source);
|
||||
|
||||
if (!ignore_menu_shortcuts_) {
|
||||
|
||||
@@ -19,7 +19,7 @@ void CommonWebContentsDelegate::HandleKeyboardEvent(
|
||||
content::WebContents* source,
|
||||
const content::NativeWebKeyboardEvent& event) {
|
||||
// Escape exits tabbed fullscreen mode.
|
||||
if (event.windowsKeyCode == ui::VKEY_ESCAPE && is_html_fullscreen())
|
||||
if (event.windows_key_code == ui::VKEY_ESCAPE && is_html_fullscreen())
|
||||
ExitFullscreenModeForTab(source);
|
||||
|
||||
// Let the NativeWindow handle other parts.
|
||||
|
||||
@@ -33,7 +33,7 @@ class BluetoothChooser : public content::BluetoothChooser {
|
||||
bool is_gatt_connected,
|
||||
bool is_paired,
|
||||
int signal_strength_level) override;
|
||||
void RemoveDevice(const std::string& device_id) override;
|
||||
void RemoveDevice(const std::string& device_id);
|
||||
|
||||
private:
|
||||
std::vector<DeviceInfo> device_list_;
|
||||
|
||||
@@ -6,10 +6,13 @@
|
||||
#import "base/mac/scoped_nsobject.h"
|
||||
|
||||
@interface AtomApplication : NSApplication<CrAppProtocol,
|
||||
CrAppControlProtocol> {
|
||||
CrAppControlProtocol,
|
||||
NSUserActivityDelegate> {
|
||||
@private
|
||||
BOOL handlingSendEvent_;
|
||||
base::scoped_nsobject<NSUserActivity> currentActivity_;
|
||||
NSCondition* handoffLock_;
|
||||
BOOL updateReceived_;
|
||||
}
|
||||
|
||||
+ (AtomApplication*)sharedApplication;
|
||||
@@ -24,5 +27,8 @@
|
||||
- (void)setCurrentActivity:(NSString*)type
|
||||
withUserInfo:(NSDictionary*)userInfo
|
||||
withWebpageURL:(NSURL*)webpageURL;
|
||||
- (void)invalidateCurrentActivity;
|
||||
- (void)updateCurrentActivity:(NSString*)type
|
||||
withUserInfo:(NSDictionary*)userInfo;
|
||||
|
||||
@end
|
||||
|
||||
@@ -4,11 +4,23 @@
|
||||
|
||||
#import "atom/browser/mac/atom_application.h"
|
||||
|
||||
#include "atom/browser/mac/dict_util.h"
|
||||
#include "atom/browser/browser.h"
|
||||
#include "base/auto_reset.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "content/public/browser/browser_accessibility_state.h"
|
||||
|
||||
namespace {
|
||||
|
||||
inline void dispatch_sync_main(dispatch_block_t block) {
|
||||
if ([NSThread isMainThread])
|
||||
block();
|
||||
else
|
||||
dispatch_sync(dispatch_get_main_queue(), block);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@implementation AtomApplication
|
||||
|
||||
+ (AtomApplication*)sharedApplication {
|
||||
@@ -35,19 +47,78 @@
|
||||
[[NSUserActivity alloc] initWithActivityType:type]);
|
||||
[currentActivity_ setUserInfo:userInfo];
|
||||
[currentActivity_ setWebpageURL:webpageURL];
|
||||
[currentActivity_ setDelegate:self];
|
||||
[currentActivity_ becomeCurrent];
|
||||
[currentActivity_ setNeedsSave:YES];
|
||||
}
|
||||
|
||||
- (NSUserActivity*)getCurrentActivity {
|
||||
return currentActivity_.get();
|
||||
}
|
||||
|
||||
- (void)invalidateCurrentActivity {
|
||||
if (currentActivity_) {
|
||||
[currentActivity_ invalidate];
|
||||
currentActivity_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateCurrentActivity:(NSString*)type
|
||||
withUserInfo:(NSDictionary*)userInfo {
|
||||
if (currentActivity_) {
|
||||
[currentActivity_ addUserInfoEntriesFromDictionary:userInfo];
|
||||
}
|
||||
|
||||
[handoffLock_ lock];
|
||||
updateReceived_ = YES;
|
||||
[handoffLock_ signal];
|
||||
[handoffLock_ unlock];
|
||||
}
|
||||
|
||||
- (void)userActivityWillSave:(NSUserActivity *)userActivity {
|
||||
__block BOOL shouldWait = NO;
|
||||
dispatch_sync_main(^{
|
||||
std::string activity_type(base::SysNSStringToUTF8(userActivity.activityType));
|
||||
std::unique_ptr<base::DictionaryValue> user_info =
|
||||
atom::NSDictionaryToDictionaryValue(userActivity.userInfo);
|
||||
|
||||
atom::Browser* browser = atom::Browser::Get();
|
||||
shouldWait = browser->UpdateUserActivityState(activity_type, *user_info) ? YES : NO;
|
||||
});
|
||||
|
||||
if (shouldWait) {
|
||||
[handoffLock_ lock];
|
||||
updateReceived_ = NO;
|
||||
while (!updateReceived_) {
|
||||
BOOL isSignaled = [handoffLock_ waitUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
|
||||
if (!isSignaled) break;
|
||||
}
|
||||
[handoffLock_ unlock];
|
||||
}
|
||||
|
||||
[userActivity setNeedsSave:YES];
|
||||
}
|
||||
|
||||
- (void)userActivityWasContinued:(NSUserActivity *)userActivity {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
std::string activity_type(base::SysNSStringToUTF8(userActivity.activityType));
|
||||
std::unique_ptr<base::DictionaryValue> user_info =
|
||||
atom::NSDictionaryToDictionaryValue(userActivity.userInfo);
|
||||
|
||||
atom::Browser* browser = atom::Browser::Get();
|
||||
browser->UserActivityWasContinued(activity_type, *user_info);
|
||||
});
|
||||
[userActivity setNeedsSave:YES];
|
||||
}
|
||||
|
||||
- (void)awakeFromNib {
|
||||
[[NSAppleEventManager sharedAppleEventManager]
|
||||
setEventHandler:self
|
||||
andSelector:@selector(handleURLEvent:withReplyEvent:)
|
||||
forEventClass:kInternetEventClass
|
||||
andEventID:kAEGetURL];
|
||||
|
||||
handoffLock_ = [NSCondition new];
|
||||
}
|
||||
|
||||
- (void)handleURLEvent:(NSAppleEventDescriptor*)event
|
||||
@@ -72,6 +143,9 @@
|
||||
bool enableAccessibility = ([self voiceOverEnabled] && [value boolValue]);
|
||||
[self updateAccessibilityEnabled:enableAccessibility];
|
||||
}
|
||||
else if ([attribute isEqualToString:@"AXManualAccessibility"]) {
|
||||
[self updateAccessibilityEnabled:[value boolValue]];
|
||||
}
|
||||
return [super accessibilitySetValue:value forAttribute:attribute];
|
||||
}
|
||||
|
||||
|
||||
@@ -7,9 +7,36 @@
|
||||
#import "atom/browser/mac/atom_application.h"
|
||||
#include "atom/browser/browser.h"
|
||||
#include "atom/browser/mac/dict_util.h"
|
||||
#include "base/allocator/allocator_shim.h"
|
||||
#include "base/allocator/features.h"
|
||||
#include "base/mac/mac_util.h"
|
||||
#include "base/mac/scoped_objc_class_swizzler.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "base/values.h"
|
||||
|
||||
#if BUILDFLAG(USE_EXPERIMENTAL_ALLOCATOR_SHIM)
|
||||
// On macOS 10.12, the IME system attempts to allocate a 2^64 size buffer,
|
||||
// which would typically cause an OOM crash. To avoid this, the problematic
|
||||
// method is swizzled out and the make-OOM-fatal bit is disabled for the
|
||||
// duration of the original call. https://crbug.com/654695
|
||||
static base::mac::ScopedObjCClassSwizzler* g_swizzle_imk_input_session;
|
||||
@interface OOMDisabledIMKInputSession : NSObject
|
||||
@end
|
||||
@implementation OOMDisabledIMKInputSession
|
||||
- (void)_coreAttributesFromRange:(NSRange)range
|
||||
whichAttributes:(long long)attributes
|
||||
completionHandler:(void (^)(void))block {
|
||||
// The allocator flag is per-process, so other threads may temporarily
|
||||
// not have fatal OOM occur while this method executes, but it is better
|
||||
// than crashing when using IME.
|
||||
base::allocator::SetCallNewHandlerOnMallocFailure(false);
|
||||
g_swizzle_imk_input_session->GetOriginalImplementation()(self, _cmd, range,
|
||||
attributes, block);
|
||||
base::allocator::SetCallNewHandlerOnMallocFailure(true);
|
||||
}
|
||||
@end
|
||||
#endif // BUILDFLAG(USE_EXPERIMENTAL_ALLOCATOR_SHIM)
|
||||
|
||||
@implementation AtomApplicationDelegate
|
||||
|
||||
- (void)setApplicationDockMenu:(atom::AtomMenuModel*)model {
|
||||
@@ -35,6 +62,16 @@
|
||||
std::unique_ptr<base::DictionaryValue> empty_info(new base::DictionaryValue);
|
||||
atom::Browser::Get()->DidFinishLaunching(*empty_info);
|
||||
}
|
||||
|
||||
#if BUILDFLAG(USE_EXPERIMENTAL_ALLOCATOR_SHIM)
|
||||
// Disable fatal OOM to hack around an OS bug https://crbug.com/654695.
|
||||
if (base::mac::IsOS10_12()) {
|
||||
g_swizzle_imk_input_session = new base::mac::ScopedObjCClassSwizzler(
|
||||
NSClassFromString(@"IMKInputSession"),
|
||||
[OOMDisabledIMKInputSession class],
|
||||
@selector(_coreAttributesFromRange:whichAttributes:completionHandler:));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
- (NSMenu*)applicationDockMenu:(NSApplication*)sender {
|
||||
@@ -81,6 +118,21 @@ continueUserActivity:(NSUserActivity*)userActivity
|
||||
return browser->ContinueUserActivity(activity_type, *user_info) ? YES : NO;
|
||||
}
|
||||
|
||||
- (BOOL)application:(NSApplication*)application willContinueUserActivityWithType:(NSString*)userActivityType {
|
||||
std::string activity_type(base::SysNSStringToUTF8(userActivityType));
|
||||
|
||||
atom::Browser* browser = atom::Browser::Get();
|
||||
return browser->WillContinueUserActivity(activity_type) ? YES : NO;
|
||||
}
|
||||
|
||||
- (void)application:(NSApplication*)application didFailToContinueUserActivityWithType:(NSString*)userActivityType error:(NSError*)error {
|
||||
std::string activity_type(base::SysNSStringToUTF8(userActivityType));
|
||||
std::string error_message(base::SysNSStringToUTF8([error localizedDescription]));
|
||||
|
||||
atom::Browser* browser = atom::Browser::Get();
|
||||
browser->DidFailToContinueUserActivity(activity_type, error_message);
|
||||
}
|
||||
|
||||
- (IBAction)newWindowForTab:(id)sender {
|
||||
atom::Browser::Get()->NewWindowForTab();
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "atom/browser/mac/dict_util.h"
|
||||
|
||||
#include "base/json/json_writer.h"
|
||||
#include "base/memory/ptr_util.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "base/values.h"
|
||||
|
||||
@@ -45,14 +46,14 @@ std::unique_ptr<base::ListValue> NSArrayToListValue(NSArray* arr) {
|
||||
if (sub_arr)
|
||||
result->Append(std::move(sub_arr));
|
||||
else
|
||||
result->Append(base::Value::CreateNullValue());
|
||||
result->Append(base::MakeUnique<base::Value>());
|
||||
} else if ([value isKindOfClass:[NSDictionary class]]) {
|
||||
std::unique_ptr<base::DictionaryValue> sub_dict =
|
||||
NSDictionaryToDictionaryValue(value);
|
||||
if (sub_dict)
|
||||
result->Append(std::move(sub_dict));
|
||||
else
|
||||
result->Append(base::Value::CreateNullValue());
|
||||
result->Append(base::MakeUnique<base::Value>());
|
||||
} else {
|
||||
result->AppendString(base::SysNSStringToUTF8([value description]));
|
||||
}
|
||||
@@ -104,7 +105,7 @@ std::unique_ptr<base::DictionaryValue> NSDictionaryToDictionaryValue(
|
||||
result->SetWithoutPathExpansion(str_key, std::move(sub_arr));
|
||||
else
|
||||
result->SetWithoutPathExpansion(str_key,
|
||||
base::Value::CreateNullValue());
|
||||
base::MakeUnique<base::Value>());
|
||||
} else if ([value isKindOfClass:[NSDictionary class]]) {
|
||||
std::unique_ptr<base::DictionaryValue> sub_dict =
|
||||
NSDictionaryToDictionaryValue(value);
|
||||
@@ -112,7 +113,7 @@ std::unique_ptr<base::DictionaryValue> NSDictionaryToDictionaryValue(
|
||||
result->SetWithoutPathExpansion(str_key, std::move(sub_dict));
|
||||
else
|
||||
result->SetWithoutPathExpansion(str_key,
|
||||
base::Value::CreateNullValue());
|
||||
base::MakeUnique<base::Value>());
|
||||
} else {
|
||||
result->SetStringWithoutPathExpansion(
|
||||
str_key,
|
||||
|
||||
@@ -43,10 +43,20 @@ const NSAutoresizingMaskOptions kDefaultAutoResizingMask =
|
||||
- (void)mouseDown:(NSEvent *)event
|
||||
{
|
||||
if ([self.window respondsToSelector:@selector(performWindowDragWithEvent)]) {
|
||||
// According to Google, using performWindowDragWithEvent:
|
||||
// does not generate a NSWindowWillMoveNotification. Hence post one.
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:NSWindowWillMoveNotification
|
||||
object:self];
|
||||
|
||||
[self.window performWindowDragWithEvent:event];
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.window.styleMask & NSFullScreenWindowMask) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.initialLocation = [event locationInWindow];
|
||||
}
|
||||
|
||||
@@ -56,17 +66,53 @@ const NSAutoresizingMaskOptions kDefaultAutoResizingMask =
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.window.styleMask & NSFullScreenWindowMask) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSPoint currentLocation = [NSEvent mouseLocation];
|
||||
NSPoint newOrigin;
|
||||
|
||||
NSRect screenFrame = [[NSScreen mainScreen] frame];
|
||||
NSSize screenSize = screenFrame.size;
|
||||
NSRect windowFrame = [self.window frame];
|
||||
NSSize windowSize = windowFrame.size;
|
||||
|
||||
newOrigin.x = currentLocation.x - self.initialLocation.x;
|
||||
newOrigin.y = currentLocation.y - self.initialLocation.y;
|
||||
|
||||
BOOL inMenuBar = (newOrigin.y + windowSize.height) > (screenFrame.origin.y + screenSize.height);
|
||||
BOOL screenAboveMainScreen = false;
|
||||
|
||||
if (inMenuBar) {
|
||||
for (NSScreen *screen in [NSScreen screens]) {
|
||||
NSRect currentScreenFrame = [screen frame];
|
||||
BOOL isHigher = currentScreenFrame.origin.y > screenFrame.origin.y;
|
||||
|
||||
// If there's another screen that is generally above the current screen,
|
||||
// we'll draw a new rectangle that is just above the current screen. If the
|
||||
// "higher" screen intersects with this rectangle, we'll allow drawing above
|
||||
// the menubar.
|
||||
if (isHigher) {
|
||||
NSRect aboveScreenRect = NSMakeRect(
|
||||
screenFrame.origin.x,
|
||||
screenFrame.origin.y + screenFrame.size.height - 10,
|
||||
screenFrame.size.width,
|
||||
200
|
||||
);
|
||||
|
||||
BOOL screenAboveIntersects = NSIntersectsRect(currentScreenFrame, aboveScreenRect);
|
||||
|
||||
if (screenAboveIntersects) {
|
||||
screenAboveMainScreen = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Don't let window get dragged up under the menu bar
|
||||
if ((newOrigin.y + windowFrame.size.height) > (screenFrame.origin.y + screenFrame.size.height)) {
|
||||
if (inMenuBar && !screenAboveMainScreen) {
|
||||
newOrigin.y = screenFrame.origin.y + (screenFrame.size.height - windowFrame.size.height);
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ NativeWindow::NativeWindow(
|
||||
aspect_ratio_(0.0),
|
||||
parent_(parent),
|
||||
is_modal_(false),
|
||||
is_osr_dummy_(false),
|
||||
inspectable_web_contents_(inspectable_web_contents),
|
||||
weak_factory_(this) {
|
||||
options.Get(options::kFrame, &has_frame_);
|
||||
@@ -117,6 +118,14 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) {
|
||||
bool center;
|
||||
if (options.Get(options::kX, &x) && options.Get(options::kY, &y)) {
|
||||
SetPosition(gfx::Point(x, y));
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// FIXME(felixrieseberg): Dirty, dirty workaround for
|
||||
// https://github.com/electron/electron/issues/10862
|
||||
// Somehow, we need to call `SetBounds` twice to get
|
||||
// usable results. The root cause is still unknown.
|
||||
SetPosition(gfx::Point(x, y));
|
||||
#endif
|
||||
} else if (options.Get(options::kCenter, ¢er) && center) {
|
||||
Center();
|
||||
}
|
||||
@@ -159,6 +168,10 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) {
|
||||
if (options.Get(options::kHasShadow, &has_shadow)) {
|
||||
SetHasShadow(has_shadow);
|
||||
}
|
||||
double opacity;
|
||||
if (options.Get(options::kOpacity, &opacity)) {
|
||||
SetOpacity(opacity);
|
||||
}
|
||||
bool top;
|
||||
if (options.Get(options::kAlwaysOnTop, &top) && top) {
|
||||
SetAlwaysOnTop(true);
|
||||
@@ -336,6 +349,24 @@ void NativeWindow::SetParentWindow(NativeWindow* parent) {
|
||||
void NativeWindow::SetAutoHideCursor(bool auto_hide) {
|
||||
}
|
||||
|
||||
void NativeWindow::SelectPreviousTab() {
|
||||
}
|
||||
|
||||
void NativeWindow::SelectNextTab() {
|
||||
}
|
||||
|
||||
void NativeWindow::MergeAllWindows() {
|
||||
}
|
||||
|
||||
void NativeWindow::MoveTabToNewWindow() {
|
||||
}
|
||||
|
||||
void NativeWindow::ToggleTabBar() {
|
||||
}
|
||||
|
||||
void NativeWindow::AddTabbedWindow(NativeWindow* window) {
|
||||
}
|
||||
|
||||
void NativeWindow::SetVibrancy(const std::string& filename) {
|
||||
}
|
||||
|
||||
|
||||
@@ -134,16 +134,20 @@ class NativeWindow : public base::SupportsUserData,
|
||||
virtual std::string GetTitle() = 0;
|
||||
virtual void FlashFrame(bool flash) = 0;
|
||||
virtual void SetSkipTaskbar(bool skip) = 0;
|
||||
virtual void SetSimpleFullScreen(bool simple_fullscreen) = 0;
|
||||
virtual bool IsSimpleFullScreen() = 0;
|
||||
virtual void SetKiosk(bool kiosk) = 0;
|
||||
virtual bool IsKiosk() = 0;
|
||||
virtual void SetBackgroundColor(const std::string& color_name) = 0;
|
||||
virtual void SetHasShadow(bool has_shadow) = 0;
|
||||
virtual bool HasShadow() = 0;
|
||||
virtual void SetOpacity(const double opacity) = 0;
|
||||
virtual double GetOpacity() = 0;
|
||||
virtual void SetRepresentedFilename(const std::string& filename);
|
||||
virtual std::string GetRepresentedFilename();
|
||||
virtual void SetDocumentEdited(bool edited);
|
||||
virtual bool IsDocumentEdited();
|
||||
virtual void SetIgnoreMouseEvents(bool ignore) = 0;
|
||||
virtual void SetIgnoreMouseEvents(bool ignore, bool forward) = 0;
|
||||
virtual void SetContentProtection(bool enable) = 0;
|
||||
virtual void SetFocusable(bool focusable);
|
||||
virtual void SetMenu(AtomMenuModel* menu);
|
||||
@@ -182,6 +186,14 @@ class NativeWindow : public base::SupportsUserData,
|
||||
virtual void RefreshTouchBarItem(const std::string& item_id);
|
||||
virtual void SetEscapeTouchBarItem(const mate::PersistentDictionary& item);
|
||||
|
||||
// Native Tab API
|
||||
virtual void SelectPreviousTab();
|
||||
virtual void SelectNextTab();
|
||||
virtual void MergeAllWindows();
|
||||
virtual void MoveTabToNewWindow();
|
||||
virtual void ToggleTabBar();
|
||||
virtual void AddTabbedWindow(NativeWindow* window);
|
||||
|
||||
// Webview APIs.
|
||||
virtual void FocusOnWebView();
|
||||
virtual void BlurWebView();
|
||||
@@ -219,6 +231,7 @@ class NativeWindow : public base::SupportsUserData,
|
||||
const content::NativeWebKeyboardEvent& event) {}
|
||||
virtual void ShowAutofillPopup(
|
||||
content::RenderFrameHost* frame_host,
|
||||
content::WebContents* web_contents,
|
||||
const gfx::RectF& bounds,
|
||||
const std::vector<base::string16>& values,
|
||||
const std::vector<base::string16>& labels) {}
|
||||
@@ -276,6 +289,9 @@ class NativeWindow : public base::SupportsUserData,
|
||||
SkRegion* draggable_region() const { return draggable_region_.get(); }
|
||||
bool enable_larger_than_screen() const { return enable_larger_than_screen_; }
|
||||
|
||||
void set_is_offscreen_dummy(bool is_dummy) { is_osr_dummy_ = is_dummy; }
|
||||
bool is_offscreen_dummy() const { return is_osr_dummy_; }
|
||||
|
||||
NativeWindow* parent() const { return parent_; }
|
||||
bool is_modal() const { return is_modal_; }
|
||||
|
||||
@@ -354,6 +370,9 @@ class NativeWindow : public base::SupportsUserData,
|
||||
// Is this a modal window.
|
||||
bool is_modal_;
|
||||
|
||||
// Is this a dummy window for an offscreen WebContents.
|
||||
bool is_osr_dummy_;
|
||||
|
||||
// The page this window is viewing.
|
||||
brightray::InspectableWebContents* inspectable_web_contents_;
|
||||
|
||||
|
||||
@@ -76,16 +76,20 @@ class NativeWindowMac : public NativeWindow,
|
||||
std::string GetTitle() override;
|
||||
void FlashFrame(bool flash) override;
|
||||
void SetSkipTaskbar(bool skip) override;
|
||||
void SetSimpleFullScreen(bool simple_fullscreen) override;
|
||||
bool IsSimpleFullScreen() override;
|
||||
void SetKiosk(bool kiosk) override;
|
||||
bool IsKiosk() override;
|
||||
void SetBackgroundColor(const std::string& color_name) override;
|
||||
void SetHasShadow(bool has_shadow) override;
|
||||
bool HasShadow() override;
|
||||
void SetOpacity(const double opacity) override;
|
||||
double GetOpacity() override;
|
||||
void SetRepresentedFilename(const std::string& filename) override;
|
||||
std::string GetRepresentedFilename() override;
|
||||
void SetDocumentEdited(bool edited) override;
|
||||
bool IsDocumentEdited() override;
|
||||
void SetIgnoreMouseEvents(bool ignore) override;
|
||||
void SetIgnoreMouseEvents(bool ignore, bool) override;
|
||||
void SetContentProtection(bool enable) override;
|
||||
void SetBrowserView(NativeBrowserView* browser_view) override;
|
||||
void SetParentWindow(NativeWindow* parent) override;
|
||||
@@ -101,6 +105,13 @@ class NativeWindowMac : public NativeWindow,
|
||||
|
||||
void SetAutoHideCursor(bool auto_hide) override;
|
||||
|
||||
void SelectPreviousTab() override;
|
||||
void SelectNextTab() override;
|
||||
void MergeAllWindows() override;
|
||||
void MoveTabToNewWindow() override;
|
||||
void ToggleTabBar() override;
|
||||
void AddTabbedWindow(NativeWindow* window) override;
|
||||
|
||||
void SetVibrancy(const std::string& type) override;
|
||||
void SetTouchBar(
|
||||
const std::vector<mate::PersistentDictionary>& items) override;
|
||||
@@ -135,6 +146,8 @@ class NativeWindowMac : public NativeWindow,
|
||||
|
||||
bool fullscreen_window_title() const { return fullscreen_window_title_; }
|
||||
|
||||
bool simple_fullscreen() const { return always_simple_fullscreen_; }
|
||||
|
||||
protected:
|
||||
// Return a vector of non-draggable regions that fill a window of size
|
||||
// |width| by |height|, but leave gaps where the window should be draggable.
|
||||
@@ -148,6 +161,7 @@ class NativeWindowMac : public NativeWindow,
|
||||
void UpdateDraggableRegions(
|
||||
const std::vector<DraggableRegion>& regions) override;
|
||||
|
||||
void InternalSetParentWindow(NativeWindow* parent, bool attach);
|
||||
void ShowWindowButton(NSWindowButton button);
|
||||
|
||||
void InstallView();
|
||||
@@ -189,6 +203,17 @@ class NativeWindowMac : public NativeWindow,
|
||||
// The "titleBarStyle" option.
|
||||
TitleBarStyle title_bar_style_;
|
||||
|
||||
// Simple (pre-Lion) Fullscreen Settings
|
||||
bool always_simple_fullscreen_;
|
||||
bool is_simple_fullscreen_;
|
||||
bool was_maximizable_;
|
||||
bool was_movable_;
|
||||
NSRect original_frame_;
|
||||
NSUInteger simple_fullscreen_mask_;
|
||||
|
||||
// The presentation options before entering simple fullscreen mode.
|
||||
NSApplicationPresentationOptions simple_fullscreen_options_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NativeWindowMac);
|
||||
};
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "atom/browser/native_window_mac.h"
|
||||
|
||||
#include <AvailabilityMacros.h>
|
||||
#include <Quartz/Quartz.h>
|
||||
#include <string>
|
||||
|
||||
@@ -173,6 +174,7 @@ bool ScopedDisableResize::disable_resize_ = false;
|
||||
atom::NativeWindowMac* shell_;
|
||||
bool is_zooming_;
|
||||
int level_;
|
||||
bool is_resizable_;
|
||||
}
|
||||
- (id)initWithShell:(atom::NativeWindowMac*)shell;
|
||||
@end
|
||||
@@ -335,6 +337,9 @@ bool ScopedDisableResize::disable_resize_ = false;
|
||||
}
|
||||
|
||||
- (void)windowWillEnterFullScreen:(NSNotification*)notification {
|
||||
// Setting resizable to true before entering fullscreen
|
||||
is_resizable_ = shell_->IsResizable();
|
||||
shell_->SetResizable(true);
|
||||
// Hide the native toolbar before entering fullscreen, so there is no visual
|
||||
// artifacts.
|
||||
if (base::mac::IsAtLeastOS10_10() &&
|
||||
@@ -394,6 +399,7 @@ bool ScopedDisableResize::disable_resize_ = false;
|
||||
}
|
||||
|
||||
- (void)windowDidExitFullScreen:(NSNotification*)notification {
|
||||
shell_->SetResizable(is_resizable_);
|
||||
shell_->NotifyWindowLeaveFullScreen();
|
||||
}
|
||||
|
||||
@@ -460,7 +466,7 @@ bool ScopedDisableResize::disable_resize_ = false;
|
||||
|
||||
@end
|
||||
|
||||
#if !defined(MAC_OS_X_VERSION_10_12)
|
||||
#if !defined(AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER)
|
||||
|
||||
enum {
|
||||
NSWindowTabbingModeDisallowed = 2
|
||||
@@ -469,9 +475,15 @@ enum {
|
||||
@interface NSWindow (SierraSDK)
|
||||
- (void)setTabbingMode:(NSInteger)mode;
|
||||
- (void)setTabbingIdentifier:(NSString*)identifier;
|
||||
- (void)addTabbedWindow:(NSWindow*)window ordered:(NSWindowOrderingMode)ordered;
|
||||
- (IBAction)selectPreviousTab:(id)sender;
|
||||
- (IBAction)selectNextTab:(id)sender;
|
||||
- (IBAction)mergeAllWindows:(id)sender;
|
||||
- (IBAction)moveTabToNewWindow:(id)sender;
|
||||
- (IBAction)toggleTabBar:(id)sender;
|
||||
@end
|
||||
|
||||
#endif // MAC_OS_X_VERSION_10_12
|
||||
#endif
|
||||
|
||||
@interface AtomNSWindow : EventDispatchingWindow<QLPreviewPanelDataSource, QLPreviewPanelDelegate, NSTouchBarDelegate> {
|
||||
@private
|
||||
@@ -720,6 +732,13 @@ enum {
|
||||
[super performClose:sender];
|
||||
}
|
||||
|
||||
- (void)toggleFullScreen:(id)sender {
|
||||
if (shell_->simple_fullscreen())
|
||||
shell_->SetSimpleFullScreen(!shell_->IsSimpleFullScreen());
|
||||
else
|
||||
[super toggleFullScreen:sender];
|
||||
}
|
||||
|
||||
- (void)performMiniaturize:(id)sender {
|
||||
if (shell_->title_bar_style() == atom::NativeWindowMac::CUSTOM_BUTTONS_ON_HOVER)
|
||||
[self miniaturize:self];
|
||||
@@ -819,7 +838,9 @@ NativeWindowMac::NativeWindowMac(
|
||||
zoom_to_page_width_(false),
|
||||
fullscreen_window_title_(false),
|
||||
attention_request_id_(0),
|
||||
title_bar_style_(NORMAL) {
|
||||
title_bar_style_(NORMAL),
|
||||
always_simple_fullscreen_(false),
|
||||
is_simple_fullscreen_(false) {
|
||||
int width = 800, height = 600;
|
||||
options.Get(options::kWidth, &width);
|
||||
options.Get(options::kHeight, &height);
|
||||
@@ -941,10 +962,16 @@ NativeWindowMac::NativeWindowMac(
|
||||
// We will manage window's lifetime ourselves.
|
||||
[window_ setReleasedWhenClosed:NO];
|
||||
|
||||
// Hide the title bar background
|
||||
if (title_bar_style_ != NORMAL) {
|
||||
if (base::mac::IsAtLeastOS10_10()) {
|
||||
[window_ setTitlebarAppearsTransparent:YES];
|
||||
}
|
||||
}
|
||||
|
||||
// Hide the title bar.
|
||||
if (title_bar_style_ == HIDDEN_INSET) {
|
||||
if (base::mac::IsAtLeastOS10_10()) {
|
||||
[window_ setTitlebarAppearsTransparent:YES];
|
||||
base::scoped_nsobject<NSToolbar> toolbar(
|
||||
[[NSToolbar alloc] initWithIdentifier:@"titlebarStylingToolbar"]);
|
||||
[toolbar setShowsBaselineSeparator:NO];
|
||||
@@ -965,6 +992,8 @@ NativeWindowMac::NativeWindowMac(
|
||||
|
||||
options.Get(options::kFullscreenWindowTitle, &fullscreen_window_title_);
|
||||
|
||||
options.Get(options::kSimpleFullScreen, &always_simple_fullscreen_);
|
||||
|
||||
// Enable the NSView to accept first mouse event.
|
||||
bool acceptsFirstMouse = false;
|
||||
options.Get(options::kAcceptFirstMouse, &acceptsFirstMouse);
|
||||
@@ -1065,6 +1094,10 @@ void NativeWindowMac::Show() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Reattach the window to the parent to actually show it.
|
||||
if (parent())
|
||||
InternalSetParentWindow(parent(), true);
|
||||
|
||||
// This method is supposed to put focus on window, however if the app does not
|
||||
// have focus then "makeKeyAndOrderFront" will only show the window.
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
@@ -1073,6 +1106,10 @@ void NativeWindowMac::Show() {
|
||||
}
|
||||
|
||||
void NativeWindowMac::ShowInactive() {
|
||||
// Reattach the window to the parent to actually show it.
|
||||
if (parent())
|
||||
InternalSetParentWindow(parent(), true);
|
||||
|
||||
[window_ orderFrontRegardless];
|
||||
}
|
||||
|
||||
@@ -1083,6 +1120,10 @@ void NativeWindowMac::Hide() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Deattach the window from the parent before.
|
||||
if (parent())
|
||||
InternalSetParentWindow(parent(), false);
|
||||
|
||||
[window_ orderOut:nil];
|
||||
}
|
||||
|
||||
@@ -1351,6 +1392,80 @@ void NativeWindowMac::FlashFrame(bool flash) {
|
||||
void NativeWindowMac::SetSkipTaskbar(bool skip) {
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetSimpleFullScreen(bool simple_fullscreen) {
|
||||
NSWindow* window = GetNativeWindow();
|
||||
|
||||
if (simple_fullscreen && !is_simple_fullscreen_) {
|
||||
is_simple_fullscreen_ = true;
|
||||
|
||||
// Take note of the current window size
|
||||
original_frame_ = [window frame];
|
||||
|
||||
simple_fullscreen_options_ = [NSApp currentSystemPresentationOptions];
|
||||
simple_fullscreen_mask_ = [window styleMask];
|
||||
|
||||
// We can simulate the pre-Lion fullscreen by auto-hiding the dock and menu bar
|
||||
NSApplicationPresentationOptions options =
|
||||
NSApplicationPresentationAutoHideDock +
|
||||
NSApplicationPresentationAutoHideMenuBar;
|
||||
[NSApp setPresentationOptions:options];
|
||||
|
||||
was_maximizable_ = IsMaximizable();
|
||||
was_movable_ = IsMovable();
|
||||
|
||||
NSRect fullscreenFrame = [window.screen frame];
|
||||
|
||||
if ( !fullscreen_window_title() ) {
|
||||
// Hide the titlebar
|
||||
SetStyleMask(false, NSTitledWindowMask);
|
||||
|
||||
// Resize the window to accomodate the _entire_ screen size
|
||||
fullscreenFrame.size.height -= [[[NSApplication sharedApplication] mainMenu] menuBarHeight];
|
||||
} else {
|
||||
// No need to hide the title, but we should still hide the window buttons
|
||||
[[window standardWindowButton:NSWindowZoomButton] setHidden:YES];
|
||||
[[window standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
|
||||
[[window standardWindowButton:NSWindowCloseButton] setHidden:YES];
|
||||
}
|
||||
|
||||
[window setFrame:fullscreenFrame display: YES animate: YES];
|
||||
|
||||
// Fullscreen windows can't be resized, minimized, maximized, or moved
|
||||
SetMinimizable(false);
|
||||
SetResizable(false);
|
||||
SetMaximizable(false);
|
||||
SetMovable(false);
|
||||
} else if (!simple_fullscreen && is_simple_fullscreen_) {
|
||||
is_simple_fullscreen_ = false;
|
||||
|
||||
if ( !fullscreen_window_title() ) {
|
||||
// Restore the titlebar
|
||||
SetStyleMask(true, NSTitledWindowMask);
|
||||
} else {
|
||||
// Show the window buttons
|
||||
[[window standardWindowButton:NSWindowZoomButton] setHidden:NO];
|
||||
[[window standardWindowButton:NSWindowMiniaturizeButton] setHidden:NO];
|
||||
[[window standardWindowButton:NSWindowCloseButton] setHidden:NO];
|
||||
}
|
||||
|
||||
[window setFrame:original_frame_ display: YES animate: YES];
|
||||
|
||||
[NSApp setPresentationOptions:simple_fullscreen_options_];
|
||||
|
||||
// Restore original style mask
|
||||
ScopedDisableResize disable_resize;
|
||||
[window_ setStyleMask:simple_fullscreen_mask_];
|
||||
|
||||
// Restore window manipulation abilities
|
||||
SetMaximizable(was_maximizable_);
|
||||
SetMovable(was_movable_);
|
||||
}
|
||||
}
|
||||
|
||||
bool NativeWindowMac::IsSimpleFullScreen() {
|
||||
return is_simple_fullscreen_;
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetKiosk(bool kiosk) {
|
||||
if (kiosk && !is_kiosk_) {
|
||||
kiosk_options_ = [NSApp currentSystemPresentationOptions];
|
||||
@@ -1396,6 +1511,14 @@ bool NativeWindowMac::HasShadow() {
|
||||
return [window_ hasShadow];
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetOpacity(const double opacity) {
|
||||
[window_ setAlphaValue:opacity];
|
||||
}
|
||||
|
||||
double NativeWindowMac::GetOpacity() {
|
||||
return [window_ alphaValue];
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetRepresentedFilename(const std::string& filename) {
|
||||
[window_ setRepresentedFilename:base::SysUTF8ToNSString(filename)];
|
||||
}
|
||||
@@ -1412,7 +1535,7 @@ bool NativeWindowMac::IsDocumentEdited() {
|
||||
return [window_ isDocumentEdited];
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetIgnoreMouseEvents(bool ignore) {
|
||||
void NativeWindowMac::SetIgnoreMouseEvents(bool ignore, bool) {
|
||||
[window_ setIgnoresMouseEvents:ignore];
|
||||
}
|
||||
|
||||
@@ -1442,18 +1565,7 @@ void NativeWindowMac::SetBrowserView(NativeBrowserView* browser_view) {
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetParentWindow(NativeWindow* parent) {
|
||||
if (is_modal())
|
||||
return;
|
||||
|
||||
NativeWindow::SetParentWindow(parent);
|
||||
|
||||
// Remove current parent window.
|
||||
if ([window_ parentWindow])
|
||||
[[window_ parentWindow] removeChildWindow:window_];
|
||||
|
||||
// Set new current window.
|
||||
if (parent)
|
||||
[parent->GetNativeWindow() addChildWindow:window_ ordered:NSWindowAbove];
|
||||
InternalSetParentWindow(parent, IsVisible());
|
||||
}
|
||||
|
||||
gfx::NativeView NativeWindowMac::GetNativeView() const {
|
||||
@@ -1523,6 +1635,42 @@ void NativeWindowMac::SetAutoHideCursor(bool auto_hide) {
|
||||
[window_ setDisableAutoHideCursor:!auto_hide];
|
||||
}
|
||||
|
||||
void NativeWindowMac::SelectPreviousTab() {
|
||||
if ([window_ respondsToSelector:@selector(selectPreviousTab:)]) {
|
||||
[window_ selectPreviousTab:nil];
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowMac::SelectNextTab() {
|
||||
if ([window_ respondsToSelector:@selector(selectNextTab:)]) {
|
||||
[window_ selectNextTab:nil];
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowMac::MergeAllWindows() {
|
||||
if ([window_ respondsToSelector:@selector(mergeAllWindows:)]) {
|
||||
[window_ mergeAllWindows:nil];
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowMac::MoveTabToNewWindow() {
|
||||
if ([window_ respondsToSelector:@selector(moveTabToNewWindow:)]) {
|
||||
[window_ moveTabToNewWindow:nil];
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowMac::ToggleTabBar() {
|
||||
if ([window_ respondsToSelector:@selector(toggleTabBar:)]) {
|
||||
[window_ toggleTabBar:nil];
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowMac::AddTabbedWindow(NativeWindow* window) {
|
||||
if ([window_ respondsToSelector:@selector(addTabbedWindow:ordered:)]) {
|
||||
[window_ addTabbedWindow:window->GetNativeWindow() ordered:NSWindowAbove];
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetVibrancy(const std::string& type) {
|
||||
if (!base::mac::IsAtLeastOS10_10()) return;
|
||||
|
||||
@@ -1604,10 +1752,10 @@ void NativeWindowMac::SetEscapeTouchBarItem(const mate::PersistentDictionary& it
|
||||
}
|
||||
|
||||
void NativeWindowMac::OnInputEvent(const blink::WebInputEvent& event) {
|
||||
switch (event.type()) {
|
||||
case blink::WebInputEvent::GestureScrollBegin:
|
||||
case blink::WebInputEvent::GestureScrollUpdate:
|
||||
case blink::WebInputEvent::GestureScrollEnd:
|
||||
switch (event.GetType()) {
|
||||
case blink::WebInputEvent::kGestureScrollBegin:
|
||||
case blink::WebInputEvent::kGestureScrollUpdate:
|
||||
case blink::WebInputEvent::kGestureScrollEnd:
|
||||
this->NotifyWindowScrollTouchEdge();
|
||||
break;
|
||||
default:
|
||||
@@ -1672,6 +1820,26 @@ void NativeWindowMac::UpdateDraggableRegions(
|
||||
UpdateDraggableRegionViews(regions);
|
||||
}
|
||||
|
||||
void NativeWindowMac::InternalSetParentWindow(NativeWindow* parent, bool attach) {
|
||||
if (is_modal())
|
||||
return;
|
||||
|
||||
NativeWindow::SetParentWindow(parent);
|
||||
|
||||
// Do not remove/add if we are already properly attached.
|
||||
if (attach && parent && [window_ parentWindow] == parent->GetNativeWindow())
|
||||
return;
|
||||
|
||||
// Remove current parent window.
|
||||
if ([window_ parentWindow])
|
||||
[[window_ parentWindow] removeChildWindow:window_];
|
||||
|
||||
// Set new parent window.
|
||||
// Note that this method will force the window to become visible.
|
||||
if (parent && attach)
|
||||
[parent->GetNativeWindow() addChildWindow:window_ ordered:NSWindowAbove];
|
||||
}
|
||||
|
||||
void NativeWindowMac::ShowWindowButton(NSWindowButton button) {
|
||||
auto view = [window_ standardWindowButton:button];
|
||||
[view.superview addSubview:view positioned:NSWindowAbove relativeTo:nil];
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include "atom/browser/api/atom_api_web_contents.h"
|
||||
#include "atom/browser/native_browser_view_views.h"
|
||||
#include "atom/browser/ui/views/menu_bar.h"
|
||||
#include "atom/browser/web_contents_preferences.h"
|
||||
#include "atom/browser/web_view_manager.h"
|
||||
#include "atom/browser/window_list.h"
|
||||
#include "atom/common/color_util.h"
|
||||
#include "atom/common/draggable_region.h"
|
||||
@@ -82,17 +84,17 @@ void FlipWindowStyle(HWND handle, bool on, DWORD flag) {
|
||||
#endif
|
||||
|
||||
bool IsAltKey(const content::NativeWebKeyboardEvent& event) {
|
||||
return event.windowsKeyCode == ui::VKEY_MENU;
|
||||
return event.windows_key_code == ui::VKEY_MENU;
|
||||
}
|
||||
|
||||
bool IsAltModifier(const content::NativeWebKeyboardEvent& event) {
|
||||
typedef content::NativeWebKeyboardEvent::Modifiers Modifiers;
|
||||
int modifiers = event.modifiers();
|
||||
modifiers &= ~Modifiers::NumLockOn;
|
||||
modifiers &= ~Modifiers::CapsLockOn;
|
||||
return (modifiers == Modifiers::AltKey) ||
|
||||
(modifiers == (Modifiers::AltKey | Modifiers::IsLeft)) ||
|
||||
(modifiers == (Modifiers::AltKey | Modifiers::IsRight));
|
||||
int modifiers = event.GetModifiers();
|
||||
modifiers &= ~Modifiers::kNumLockOn;
|
||||
modifiers &= ~Modifiers::kCapsLockOn;
|
||||
return (modifiers == Modifiers::kAltKey) ||
|
||||
(modifiers == (Modifiers::kAltKey | Modifiers::kIsLeft)) ||
|
||||
(modifiers == (Modifiers::kAltKey | Modifiers::kIsRight));
|
||||
}
|
||||
|
||||
#if defined(USE_X11)
|
||||
@@ -304,11 +306,16 @@ NativeWindowViews::NativeWindowViews(
|
||||
::SetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE, ex_style);
|
||||
#endif
|
||||
|
||||
// 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()) {
|
||||
// TODO(zcbenz): This was used to force using native frame on Windows 2003,
|
||||
// we should check whether setting it in InitParams can work.
|
||||
window_->set_frame_type(views::Widget::FrameType::FRAME_TYPE_FORCE_NATIVE);
|
||||
window_->FrameTypeChanged();
|
||||
#if defined(OS_WIN)
|
||||
// thickFrame also works for normal window.
|
||||
if (!thick_frame_)
|
||||
FlipWindowStyle(GetAcceleratedWidget(), false, WS_THICKFRAME);
|
||||
#endif
|
||||
}
|
||||
|
||||
gfx::Size size = bounds.size();
|
||||
@@ -334,6 +341,11 @@ NativeWindowViews::NativeWindowViews(
|
||||
|
||||
NativeWindowViews::~NativeWindowViews() {
|
||||
window_->RemoveObserver(this);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Disable mouse forwarding to relinquish resources, should any be held.
|
||||
SetForwardMouseMessages(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
void NativeWindowViews::Close() {
|
||||
@@ -572,6 +584,12 @@ gfx::Size NativeWindowViews::GetContentSize() {
|
||||
void NativeWindowViews::SetContentSizeConstraints(
|
||||
const extensions::SizeConstraints& size_constraints) {
|
||||
NativeWindow::SetContentSizeConstraints(size_constraints);
|
||||
#if defined(OS_WIN)
|
||||
// Changing size constraints would force adding the WS_THICKFRAME style, so
|
||||
// do nothing if thickFrame is false.
|
||||
if (!thick_frame_)
|
||||
return;
|
||||
#endif
|
||||
// widget_delegate() is only available after Init() is called, we make use of
|
||||
// this to determine whether native widget has initialized.
|
||||
if (window_ && window_->widget_delegate())
|
||||
@@ -584,7 +602,7 @@ void NativeWindowViews::SetContentSizeConstraints(
|
||||
|
||||
void NativeWindowViews::SetResizable(bool resizable) {
|
||||
#if defined(OS_WIN)
|
||||
if (has_frame())
|
||||
if (has_frame() && thick_frame_)
|
||||
FlipWindowStyle(GetAcceleratedWidget(), resizable, WS_THICKFRAME);
|
||||
#elif defined(USE_X11)
|
||||
if (resizable != resizable_) {
|
||||
@@ -754,6 +772,14 @@ void NativeWindowViews::SetSkipTaskbar(bool skip) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetSimpleFullScreen(bool simple_fullscreen) {
|
||||
SetFullScreen(simple_fullscreen);
|
||||
}
|
||||
|
||||
bool NativeWindowViews::IsSimpleFullScreen() {
|
||||
return IsFullscreen();
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetKiosk(bool kiosk) {
|
||||
SetFullScreen(kiosk);
|
||||
}
|
||||
@@ -790,14 +816,41 @@ bool NativeWindowViews::HasShadow() {
|
||||
!= wm::ShadowElevation::NONE;
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetIgnoreMouseEvents(bool ignore) {
|
||||
void NativeWindowViews::SetOpacity(const double opacity) {
|
||||
#if defined(OS_WIN)
|
||||
HWND hwnd = GetAcceleratedWidget();
|
||||
if (!layered_) {
|
||||
LONG ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
|
||||
ex_style |= WS_EX_LAYERED;
|
||||
::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style);
|
||||
layered_ = true;
|
||||
}
|
||||
::SetLayeredWindowAttributes(hwnd, 0, opacity * 255, LWA_ALPHA);
|
||||
#endif
|
||||
opacity_ = opacity;
|
||||
}
|
||||
|
||||
double NativeWindowViews::GetOpacity() {
|
||||
return opacity_;
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetIgnoreMouseEvents(bool ignore, bool forward) {
|
||||
#if defined(OS_WIN)
|
||||
LONG ex_style = ::GetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE);
|
||||
if (ignore)
|
||||
ex_style |= (WS_EX_TRANSPARENT | WS_EX_LAYERED);
|
||||
else
|
||||
ex_style &= ~(WS_EX_TRANSPARENT | WS_EX_LAYERED);
|
||||
if (layered_)
|
||||
ex_style |= WS_EX_LAYERED;
|
||||
::SetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE, ex_style);
|
||||
|
||||
// Forwarding is always disabled when not ignoring mouse messages.
|
||||
if (!ignore) {
|
||||
SetForwardMouseMessages(false);
|
||||
} else {
|
||||
SetForwardMouseMessages(forward);
|
||||
}
|
||||
#elif defined(USE_X11)
|
||||
if (ignore) {
|
||||
XRectangle r = {0, 0, 1, 1};
|
||||
@@ -1090,9 +1143,31 @@ void NativeWindowViews::OnWidgetBoundsChanged(
|
||||
if (widget != window_.get())
|
||||
return;
|
||||
|
||||
if (widget_size_ != bounds.size()) {
|
||||
// Note: We intentionally use `GetBounds()` instead of `bounds` to properly
|
||||
// handle minimized windows on Windows.
|
||||
const auto new_bounds = GetBounds();
|
||||
if (widget_size_ != new_bounds.size()) {
|
||||
if (browser_view_) {
|
||||
const auto flags = static_cast<NativeBrowserViewViews*>(browser_view_)
|
||||
->GetAutoResizeFlags();
|
||||
int width_delta = 0;
|
||||
int height_delta = 0;
|
||||
if (flags & kAutoResizeWidth) {
|
||||
width_delta = new_bounds.width() - widget_size_.width();
|
||||
}
|
||||
if (flags & kAutoResizeHeight) {
|
||||
height_delta = new_bounds.height() - widget_size_.height();
|
||||
}
|
||||
|
||||
auto* view = browser_view_->GetInspectableWebContentsView()->GetView();
|
||||
auto new_view_size = view->size();
|
||||
new_view_size.set_width(new_view_size.width() + width_delta);
|
||||
new_view_size.set_height(new_view_size.height() + height_delta);
|
||||
view->SetSize(new_view_size);
|
||||
}
|
||||
|
||||
NotifyWindowResize();
|
||||
widget_size_ = bounds.size();
|
||||
widget_size_ = new_bounds.size();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1252,15 +1327,15 @@ void NativeWindowViews::HandleKeyboardEvent(
|
||||
// Show accelerator when "Alt" is pressed.
|
||||
if (menu_bar_visible_ && IsAltKey(event))
|
||||
menu_bar_->SetAcceleratorVisibility(
|
||||
event.type() == blink::WebInputEvent::RawKeyDown);
|
||||
event.GetType() == blink::WebInputEvent::kRawKeyDown);
|
||||
|
||||
// Show the submenu when "Alt+Key" is pressed.
|
||||
if (event.type() == blink::WebInputEvent::RawKeyDown && !IsAltKey(event) &&
|
||||
IsAltModifier(event)) {
|
||||
if (event.GetType() == blink::WebInputEvent::kRawKeyDown &&
|
||||
!IsAltKey(event) && IsAltModifier(event)) {
|
||||
if (!menu_bar_visible_ &&
|
||||
(menu_bar_->GetAcceleratorIndex(event.windowsKeyCode) != -1))
|
||||
(menu_bar_->GetAcceleratorIndex(event.windows_key_code) != -1))
|
||||
SetMenuBarVisibility(true);
|
||||
menu_bar_->ActivateAccelerator(event.windowsKeyCode);
|
||||
menu_bar_->ActivateAccelerator(event.windows_key_code);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1268,11 +1343,11 @@ void NativeWindowViews::HandleKeyboardEvent(
|
||||
return;
|
||||
|
||||
// Toggle the menu bar only when a single Alt is released.
|
||||
if (event.type() == blink::WebInputEvent::RawKeyDown && IsAltKey(event)) {
|
||||
if (event.GetType() == blink::WebInputEvent::kRawKeyDown && IsAltKey(event)) {
|
||||
// When a single Alt is pressed:
|
||||
menu_bar_alt_pressed_ = true;
|
||||
} else if (event.type() == blink::WebInputEvent::KeyUp && IsAltKey(event) &&
|
||||
menu_bar_alt_pressed_) {
|
||||
} else if (event.GetType() == blink::WebInputEvent::kKeyUp &&
|
||||
IsAltKey(event) && menu_bar_alt_pressed_) {
|
||||
// When a single Alt is released right after a Alt is pressed:
|
||||
menu_bar_alt_pressed_ = false;
|
||||
SetMenuBarVisibility(!menu_bar_visible_);
|
||||
@@ -1284,17 +1359,37 @@ void NativeWindowViews::HandleKeyboardEvent(
|
||||
|
||||
void NativeWindowViews::ShowAutofillPopup(
|
||||
content::RenderFrameHost* frame_host,
|
||||
content::WebContents* web_contents,
|
||||
const gfx::RectF& bounds,
|
||||
const std::vector<base::string16>& values,
|
||||
const std::vector<base::string16>& labels) {
|
||||
auto wc = atom::api::WebContents::FromWrappedClass(
|
||||
v8::Isolate::GetCurrent(), web_contents());
|
||||
const auto* web_preferences =
|
||||
WebContentsPreferences::FromWebContents(web_contents)->web_preferences();
|
||||
|
||||
bool is_offsceen = false;
|
||||
web_preferences->GetBoolean("offscreen", &is_offsceen);
|
||||
int guest_instance_id = 0;
|
||||
web_preferences->GetInteger(options::kGuestInstanceID, &guest_instance_id);
|
||||
|
||||
bool is_embedder_offscreen = false;
|
||||
if (guest_instance_id) {
|
||||
auto manager = WebViewManager::GetWebViewManager(web_contents);
|
||||
if (manager) {
|
||||
auto embedder = manager->GetEmbedder(guest_instance_id);
|
||||
if (embedder) {
|
||||
is_embedder_offscreen = WebContentsPreferences::IsPreferenceEnabled(
|
||||
"offscreen", embedder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
autofill_popup_->CreateView(
|
||||
frame_host,
|
||||
wc->IsOffScreenOrEmbedderOffscreen(),
|
||||
widget(),
|
||||
bounds);
|
||||
frame_host,
|
||||
is_offsceen || is_embedder_offscreen,
|
||||
widget(),
|
||||
bounds);
|
||||
autofill_popup_->SetItems(values, labels);
|
||||
autofill_popup_->UpdatePopupBounds(menu_bar_visible_ ? 0 : kMenuBarHeight);
|
||||
}
|
||||
|
||||
void NativeWindowViews::HideAutofillPopup(
|
||||
@@ -1311,32 +1406,14 @@ void NativeWindowViews::Layout() {
|
||||
menu_bar_->SetBoundsRect(menu_bar_bounds);
|
||||
}
|
||||
|
||||
const auto old_web_view_size = web_view_ ? web_view_->size() : gfx::Size();
|
||||
if (web_view_) {
|
||||
web_view_->SetBoundsRect(
|
||||
gfx::Rect(0, menu_bar_bounds.height(), size.width(),
|
||||
size.height() - menu_bar_bounds.height()));
|
||||
}
|
||||
const auto new_web_view_size = web_view_ ? web_view_->size() : gfx::Size();
|
||||
|
||||
if (browser_view_) {
|
||||
const auto flags = static_cast<NativeBrowserViewViews*>(browser_view_)
|
||||
->GetAutoResizeFlags();
|
||||
int width_delta = 0;
|
||||
int height_delta = 0;
|
||||
if (flags & kAutoResizeWidth) {
|
||||
width_delta = new_web_view_size.width() - old_web_view_size.width();
|
||||
}
|
||||
if (flags & kAutoResizeHeight) {
|
||||
height_delta = new_web_view_size.height() - old_web_view_size.height();
|
||||
}
|
||||
|
||||
auto* view = browser_view_->GetInspectableWebContentsView()->GetView();
|
||||
auto new_view_size = view->size();
|
||||
new_view_size.set_width(new_view_size.width() + width_delta);
|
||||
new_view_size.set_height(new_view_size.height() + height_delta);
|
||||
view->SetSize(new_view_size);
|
||||
}
|
||||
if (autofill_popup_.get())
|
||||
autofill_popup_->UpdatePopupBounds(menu_bar_visible_ ? 0 : kMenuBarHeight);
|
||||
}
|
||||
|
||||
gfx::Size NativeWindowViews::GetMinimumSize() const {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "atom/browser/native_window.h"
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -96,12 +97,16 @@ class NativeWindowViews : public NativeWindow,
|
||||
std::string GetTitle() override;
|
||||
void FlashFrame(bool flash) override;
|
||||
void SetSkipTaskbar(bool skip) override;
|
||||
void SetSimpleFullScreen(bool simple_fullscreen) override;
|
||||
bool IsSimpleFullScreen() override;
|
||||
void SetKiosk(bool kiosk) override;
|
||||
bool IsKiosk() override;
|
||||
void SetBackgroundColor(const std::string& color_name) override;
|
||||
void SetHasShadow(bool has_shadow) override;
|
||||
bool HasShadow() override;
|
||||
void SetIgnoreMouseEvents(bool ignore) override;
|
||||
void SetOpacity(const double opacity) override;
|
||||
double GetOpacity() override;
|
||||
void SetIgnoreMouseEvents(bool ignore, bool forward) override;
|
||||
void SetContentProtection(bool enable) override;
|
||||
void SetFocusable(bool focusable) override;
|
||||
void SetMenu(AtomMenuModel* menu_model) override;
|
||||
@@ -169,6 +174,12 @@ class NativeWindowViews : public NativeWindow,
|
||||
bool PreHandleMSG(
|
||||
UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) override;
|
||||
void HandleSizeEvent(WPARAM w_param, LPARAM l_param);
|
||||
void SetForwardMouseMessages(bool forward);
|
||||
static LRESULT CALLBACK SubclassProc(
|
||||
HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param, UINT_PTR subclass_id,
|
||||
DWORD_PTR ref_data);
|
||||
static LRESULT CALLBACK MouseHookProc(
|
||||
int n_code, WPARAM w_param, LPARAM l_param);
|
||||
#endif
|
||||
|
||||
// NativeWindow:
|
||||
@@ -179,6 +190,7 @@ class NativeWindowViews : public NativeWindow,
|
||||
const content::NativeWebKeyboardEvent& event) override;
|
||||
void ShowAutofillPopup(
|
||||
content::RenderFrameHost* frame_host,
|
||||
content::WebContents* web_contents,
|
||||
const gfx::RectF& bounds,
|
||||
const std::vector<base::string16>& values,
|
||||
const std::vector<base::string16>& labels) override;
|
||||
@@ -259,6 +271,13 @@ class NativeWindowViews : public NativeWindow,
|
||||
// The icons of window and taskbar.
|
||||
base::win::ScopedHICON window_icon_;
|
||||
base::win::ScopedHICON app_icon_;
|
||||
|
||||
// The set of windows currently forwarding mouse messages.
|
||||
static std::set<NativeWindowViews*> forwarding_windows_;
|
||||
static HHOOK mouse_hook_;
|
||||
bool forwarding_mouse_messages_ = false;
|
||||
HWND legacy_window_ = NULL;
|
||||
bool layered_ = false;
|
||||
#endif
|
||||
|
||||
// Handles unhandled keyboard messages coming back from the renderer process.
|
||||
@@ -278,6 +297,7 @@ class NativeWindowViews : public NativeWindow,
|
||||
bool fullscreenable_;
|
||||
std::string title_;
|
||||
gfx::Size widget_size_;
|
||||
double opacity_ = 1.0;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NativeWindowViews);
|
||||
};
|
||||
|
||||
@@ -80,6 +80,9 @@ bool IsScreenReaderActive() {
|
||||
|
||||
} // namespace
|
||||
|
||||
std::set<NativeWindowViews*> NativeWindowViews::forwarding_windows_;
|
||||
HHOOK NativeWindowViews::mouse_hook_ = NULL;
|
||||
|
||||
bool NativeWindowViews::ExecuteWindowsCommand(int command_id) {
|
||||
std::string command = AppCommandToString(command_id);
|
||||
NotifyWindowExecuteWindowsCommand(command);
|
||||
@@ -151,6 +154,16 @@ bool NativeWindowViews::PreHandleMSG(
|
||||
if (w_param) {
|
||||
NotifyWindowEndSession();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case WM_PARENTNOTIFY: {
|
||||
if (LOWORD(w_param) == WM_CREATE) {
|
||||
// Because of reasons regarding legacy drivers and stuff, a window that
|
||||
// matches the client area is created and used internally by Chromium.
|
||||
// This is used when forwarding mouse messages.
|
||||
legacy_window_ = reinterpret_cast<HWND>(l_param);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
@@ -207,4 +220,86 @@ void NativeWindowViews::HandleSizeEvent(WPARAM w_param, LPARAM l_param) {
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowViews::SetForwardMouseMessages(bool forward) {
|
||||
if (forward && !forwarding_mouse_messages_) {
|
||||
forwarding_mouse_messages_ = true;
|
||||
forwarding_windows_.insert(this);
|
||||
|
||||
// Subclassing is used to fix some issues when forwarding mouse messages;
|
||||
// see comments in |SubclassProc|.
|
||||
SetWindowSubclass(
|
||||
legacy_window_, SubclassProc, 1, reinterpret_cast<DWORD_PTR>(this));
|
||||
|
||||
if (!mouse_hook_) {
|
||||
mouse_hook_ = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, NULL, 0);
|
||||
}
|
||||
} else if (!forward && forwarding_mouse_messages_) {
|
||||
forwarding_mouse_messages_ = false;
|
||||
forwarding_windows_.erase(this);
|
||||
|
||||
RemoveWindowSubclass(legacy_window_, SubclassProc, 1);
|
||||
|
||||
if (forwarding_windows_.size() == 0) {
|
||||
UnhookWindowsHookEx(mouse_hook_);
|
||||
mouse_hook_ = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LRESULT CALLBACK NativeWindowViews::SubclassProc(
|
||||
HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param, UINT_PTR subclass_id,
|
||||
DWORD_PTR ref_data) {
|
||||
NativeWindowViews* window = reinterpret_cast<NativeWindowViews*>(ref_data);
|
||||
switch (msg) {
|
||||
case WM_MOUSELEAVE: {
|
||||
// When input is forwarded to underlying windows, this message is posted.
|
||||
// If not handled, it interferes with Chromium logic, causing for example
|
||||
// mouseleave events to fire. If those events are used to exit forward
|
||||
// mode, excessive flickering on for example hover items in underlying
|
||||
// windows can occur due to rapidly entering and leaving forwarding mode.
|
||||
// By consuming and ignoring the message, we're essentially telling
|
||||
// Chromium that we have not left the window despite somebody else getting
|
||||
// the messages. As to why this is catched for the legacy window and not
|
||||
// the actual browser window is simply that the legacy window somehow
|
||||
// makes use of these events; posting to the main window didn't work.
|
||||
if (window->forwarding_mouse_messages_) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return DefSubclassProc(hwnd, msg, w_param, l_param);
|
||||
}
|
||||
|
||||
LRESULT CALLBACK NativeWindowViews::MouseHookProc(
|
||||
int n_code, WPARAM w_param, LPARAM l_param) {
|
||||
if (n_code < 0) {
|
||||
return CallNextHookEx(NULL, n_code, w_param, l_param);
|
||||
}
|
||||
|
||||
// Post a WM_MOUSEMOVE message for those windows whose client area contains
|
||||
// the cursor since they are in a state where they would otherwise ignore all
|
||||
// mouse input.
|
||||
if (w_param == WM_MOUSEMOVE) {
|
||||
for (auto window : forwarding_windows_) {
|
||||
// At first I considered enumerating windows to check whether the cursor
|
||||
// was directly above the window, but since nothing bad seems to happen
|
||||
// if we post the message even if some other window occludes it I have
|
||||
// just left it as is.
|
||||
RECT client_rect;
|
||||
GetClientRect(window->legacy_window_, &client_rect);
|
||||
POINT p = reinterpret_cast<MSLLHOOKSTRUCT*>(l_param)->pt;
|
||||
ScreenToClient(window->legacy_window_, &p);
|
||||
if (PtInRect(&client_rect, p)) {
|
||||
WPARAM w = 0; // No virtual keys pressed for our purposes
|
||||
LPARAM l = MAKELPARAM(p.x, p.y);
|
||||
PostMessage(window->legacy_window_, WM_MOUSEMOVE, w, l);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CallNextHookEx(NULL, n_code, w_param, l_param);
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
#include "atom/browser/net/atom_cert_verifier.h"
|
||||
|
||||
#include "atom/browser/browser.h"
|
||||
#include "atom/browser/net/atom_ct_delegate.h"
|
||||
#include "atom/common/native_mate_converters/net_converter.h"
|
||||
#include "base/containers/linked_list.h"
|
||||
#include "base/memory/ptr_util.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "brightray/browser/net/require_ct_delegate.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "net/base/net_errors.h"
|
||||
#include "net/cert/cert_verify_result.h"
|
||||
@@ -92,6 +92,7 @@ class CertVerifierRequest : public AtomCertVerifier::Request {
|
||||
std::unique_ptr<VerifyRequestParams> request(new VerifyRequestParams());
|
||||
request->hostname = params_.hostname();
|
||||
request->default_result = net::ErrorToString(error);
|
||||
request->error_code = error;
|
||||
request->certificate = params_.certificate();
|
||||
BrowserThread::PostTask(
|
||||
BrowserThread::UI, FROM_HERE,
|
||||
@@ -146,7 +147,7 @@ class CertVerifierRequest : public AtomCertVerifier::Request {
|
||||
base::WeakPtrFactory<CertVerifierRequest> weak_ptr_factory_;
|
||||
};
|
||||
|
||||
AtomCertVerifier::AtomCertVerifier(AtomCTDelegate* ct_delegate)
|
||||
AtomCertVerifier::AtomCertVerifier(brightray::RequireCTDelegate* ct_delegate)
|
||||
: default_cert_verifier_(net::CertVerifier::CreateDefault()),
|
||||
ct_delegate_(ct_delegate) {}
|
||||
|
||||
|
||||
@@ -11,20 +11,26 @@
|
||||
|
||||
#include "net/cert/cert_verifier.h"
|
||||
|
||||
namespace brightray {
|
||||
|
||||
class RequireCTDelegate;
|
||||
|
||||
} // namespace brightray
|
||||
|
||||
namespace atom {
|
||||
|
||||
class AtomCTDelegate;
|
||||
class CertVerifierRequest;
|
||||
|
||||
struct VerifyRequestParams {
|
||||
std::string hostname;
|
||||
std::string default_result;
|
||||
int error_code;
|
||||
scoped_refptr<net::X509Certificate> certificate;
|
||||
};
|
||||
|
||||
class AtomCertVerifier : public net::CertVerifier {
|
||||
public:
|
||||
explicit AtomCertVerifier(AtomCTDelegate* ct_delegate);
|
||||
explicit AtomCertVerifier(brightray::RequireCTDelegate* ct_delegate);
|
||||
virtual ~AtomCertVerifier();
|
||||
|
||||
using VerifyProc = base::Callback<void(const VerifyRequestParams& request,
|
||||
@@ -33,7 +39,7 @@ class AtomCertVerifier : public net::CertVerifier {
|
||||
void SetVerifyProc(const VerifyProc& proc);
|
||||
|
||||
const VerifyProc verify_proc() const { return verify_proc_; }
|
||||
AtomCTDelegate* ct_delegate() const { return ct_delegate_; }
|
||||
brightray::RequireCTDelegate* ct_delegate() const { return ct_delegate_; }
|
||||
net::CertVerifier* default_verifier() const {
|
||||
return default_cert_verifier_.get();
|
||||
}
|
||||
@@ -57,7 +63,7 @@ class AtomCertVerifier : public net::CertVerifier {
|
||||
std::map<RequestParams, CertVerifierRequest*> inflight_requests_;
|
||||
VerifyProc verify_proc_;
|
||||
std::unique_ptr<net::CertVerifier> default_cert_verifier_;
|
||||
AtomCTDelegate* ct_delegate_;
|
||||
brightray::RequireCTDelegate* ct_delegate_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomCertVerifier);
|
||||
};
|
||||
|
||||
@@ -6,11 +6,13 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "atom/browser/api/atom_api_web_contents.h"
|
||||
#include "atom/common/native_mate_converters/net_converter.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "brightray/browser/net/devtools_network_transaction.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/render_frame_host.h"
|
||||
#include "net/url_request/url_request.h"
|
||||
|
||||
using brightray::DevToolsNetworkTransaction;
|
||||
@@ -74,10 +76,23 @@ void ToDictionary(base::DictionaryValue* details, net::URLRequest* request) {
|
||||
FillRequestDetails(details, request);
|
||||
details->SetInteger("id", request->identifier());
|
||||
details->SetDouble("timestamp", base::Time::Now().ToDoubleT() * 1000);
|
||||
auto info = content::ResourceRequestInfo::ForRequest(request);
|
||||
details->SetString("resourceType",
|
||||
info ? ResourceTypeToString(info->GetResourceType())
|
||||
: "other");
|
||||
const auto* info = content::ResourceRequestInfo::ForRequest(request);
|
||||
if (info) {
|
||||
int process_id = info->GetChildID();
|
||||
int frame_id = info->GetRenderFrameID();
|
||||
auto* webContents = content::WebContents::FromRenderFrameHost(
|
||||
content::RenderFrameHost::FromID(process_id, frame_id));
|
||||
int webContentsId = atom::api::WebContents::GetIDFromWrappedClass(
|
||||
webContents);
|
||||
|
||||
// webContentsId must be greater than zero
|
||||
if (webContentsId)
|
||||
details->SetInteger("webContentsId", webContentsId);
|
||||
details->SetString("resourceType",
|
||||
ResourceTypeToString(info->GetResourceType()));
|
||||
} else {
|
||||
details->SetString("resourceType", "other");
|
||||
}
|
||||
}
|
||||
|
||||
void ToDictionary(base::DictionaryValue* details,
|
||||
|
||||
@@ -117,17 +117,13 @@ bool AtomURLRequestJobFactory::IsHandledProtocol(
|
||||
net::URLRequest::IsHandledProtocol(scheme);
|
||||
}
|
||||
|
||||
bool AtomURLRequestJobFactory::IsHandledURL(const GURL& url) const {
|
||||
if (!url.is_valid()) {
|
||||
bool AtomURLRequestJobFactory::IsSafeRedirectTarget(
|
||||
const GURL& location) const {
|
||||
if (!location.is_valid()) {
|
||||
// We handle error cases.
|
||||
return true;
|
||||
}
|
||||
return IsHandledProtocol(url.scheme());
|
||||
}
|
||||
|
||||
bool AtomURLRequestJobFactory::IsSafeRedirectTarget(
|
||||
const GURL& location) const {
|
||||
return IsHandledURL(location);
|
||||
return IsHandledProtocol(location.scheme());
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -55,7 +55,6 @@ class AtomURLRequestJobFactory : public net::URLRequestJobFactory {
|
||||
net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate) const override;
|
||||
bool IsHandledProtocol(const std::string& scheme) const override;
|
||||
bool IsHandledURL(const GURL& url) const override;
|
||||
bool IsSafeRedirectTarget(const GURL& location) const override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -71,6 +71,7 @@ class JsAsker : public RequestJob {
|
||||
void Start() override {
|
||||
std::unique_ptr<base::DictionaryValue> request_details(
|
||||
new base::DictionaryValue);
|
||||
request_start_time_ = base::TimeTicks::Now();
|
||||
FillRequestDetails(request_details.get(), RequestJob::request());
|
||||
content::BrowserThread::PostTask(
|
||||
content::BrowserThread::UI, FROM_HERE,
|
||||
@@ -86,6 +87,15 @@ class JsAsker : public RequestJob {
|
||||
|
||||
int GetResponseCode() const override { return net::HTTP_OK; }
|
||||
|
||||
// NOTE: We have to implement this method or risk a crash in blink for
|
||||
// redirects!
|
||||
void GetLoadTimingInfo(net::LoadTimingInfo* load_timing_info) const override {
|
||||
load_timing_info->send_start = request_start_time_;
|
||||
load_timing_info->send_end = request_start_time_;
|
||||
load_timing_info->request_start = request_start_time_;
|
||||
load_timing_info->receive_headers_end = response_start_time_;
|
||||
}
|
||||
|
||||
void GetResponseInfo(net::HttpResponseInfo* info) override {
|
||||
info->headers = new net::HttpResponseHeaders("");
|
||||
}
|
||||
@@ -93,6 +103,7 @@ class JsAsker : public RequestJob {
|
||||
// Called when the JS handler has sent the response, we need to decide whether
|
||||
// to start, or fail the job.
|
||||
void OnResponse(bool success, std::unique_ptr<base::Value> value) {
|
||||
response_start_time_ = base::TimeTicks::Now();
|
||||
int error = net::ERR_NOT_IMPLEMENTED;
|
||||
if (success && value && !internal::IsErrorOptions(value.get(), &error)) {
|
||||
StartAsync(std::move(value));
|
||||
@@ -105,6 +116,8 @@ class JsAsker : public RequestJob {
|
||||
v8::Isolate* isolate_;
|
||||
net::URLRequestContextGetter* request_context_getter_;
|
||||
JavaScriptHandler handler_;
|
||||
base::TimeTicks request_start_time_;
|
||||
base::TimeTicks response_start_time_;
|
||||
|
||||
base::WeakPtrFactory<JsAsker> weak_factory_;
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ URLRequestBufferJob::URLRequestBufferJob(
|
||||
}
|
||||
|
||||
void URLRequestBufferJob::StartAsync(std::unique_ptr<base::Value> options) {
|
||||
const base::BinaryValue* binary = nullptr;
|
||||
const base::Value* binary = nullptr;
|
||||
if (options->IsType(base::Value::Type::DICTIONARY)) {
|
||||
base::DictionaryValue* dict =
|
||||
static_cast<base::DictionaryValue*>(options.get());
|
||||
|
||||
204
atom/browser/net/url_request_stream_job.cc
Normal file
204
atom/browser/net/url_request_stream_job.cc
Normal file
@@ -0,0 +1,204 @@
|
||||
// Copyright (c) 2017 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <algorithm>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/net/url_request_stream_job.h"
|
||||
#include "atom/common/api/event_emitter_caller.h"
|
||||
#include "atom/common/atom_constants.h"
|
||||
#include "atom/common/native_mate_converters/net_converter.h"
|
||||
#include "atom/common/node_includes.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/time/time.h"
|
||||
#include "net/filter/gzip_source_stream.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
URLRequestStreamJob::URLRequestStreamJob(net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate)
|
||||
: JsAsker<net::URLRequestJob>(request, network_delegate),
|
||||
ended_(false),
|
||||
errored_(false),
|
||||
pending_io_buf_(nullptr),
|
||||
pending_io_buf_size_(0),
|
||||
response_headers_(nullptr),
|
||||
weak_factory_(this) {}
|
||||
|
||||
void URLRequestStreamJob::BeforeStartInUI(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> value) {
|
||||
if (value->IsNull() || value->IsUndefined() || !value->IsObject()) {
|
||||
// Invalid opts.
|
||||
ended_ = true;
|
||||
errored_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
mate::Dictionary opts(isolate, v8::Local<v8::Object>::Cast(value));
|
||||
int status_code;
|
||||
if (!opts.Get("statusCode", &status_code)) {
|
||||
// assume HTTP OK if statusCode is not passed.
|
||||
status_code = 200;
|
||||
}
|
||||
std::string status("HTTP/1.1 ");
|
||||
status.append(base::IntToString(status_code));
|
||||
status.append(" ");
|
||||
status.append(
|
||||
net::GetHttpReasonPhrase(static_cast<net::HttpStatusCode>(status_code)));
|
||||
status.append("\0\0", 2);
|
||||
response_headers_ = new net::HttpResponseHeaders(status);
|
||||
|
||||
if (opts.Get("headers", &value)) {
|
||||
mate::Converter<net::HttpResponseHeaders*>::FromV8(isolate, value,
|
||||
response_headers_.get());
|
||||
}
|
||||
|
||||
if (!opts.Get("data", &value)) {
|
||||
// Assume the opts is already a stream
|
||||
value = opts.GetHandle();
|
||||
} else if (value->IsNullOrUndefined()) {
|
||||
// "data" was explicitly passed as null or undefined, assume the user wants
|
||||
// to send an empty body.
|
||||
ended_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
mate::Dictionary data(isolate, v8::Local<v8::Object>::Cast(value));
|
||||
if (!data.Get("on", &value) || !value->IsFunction() ||
|
||||
!data.Get("removeListener", &value) || !value->IsFunction()) {
|
||||
// If data is passed but it is not a stream, signal an error.
|
||||
ended_ = true;
|
||||
errored_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
subscriber_.reset(new mate::EventSubscriber<URLRequestStreamJob>(
|
||||
this, isolate, data.GetHandle()));
|
||||
subscriber_->On("data", &URLRequestStreamJob::OnData);
|
||||
subscriber_->On("end", &URLRequestStreamJob::OnEnd);
|
||||
subscriber_->On("error", &URLRequestStreamJob::OnError);
|
||||
}
|
||||
|
||||
void URLRequestStreamJob::StartAsync(std::unique_ptr<base::Value> options) {
|
||||
NotifyHeadersComplete();
|
||||
}
|
||||
|
||||
void URLRequestStreamJob::OnData(mate::Arguments* args) {
|
||||
v8::Local<v8::Value> node_data;
|
||||
args->GetNext(&node_data);
|
||||
if (node_data->IsUint8Array()) {
|
||||
const char* data = node::Buffer::Data(node_data);
|
||||
size_t data_size = node::Buffer::Length(node_data);
|
||||
std::copy(data, data + data_size, std::back_inserter(buffer_));
|
||||
} else {
|
||||
NOTREACHED();
|
||||
}
|
||||
if (pending_io_buf_) {
|
||||
CopyMoreData(pending_io_buf_, pending_io_buf_size_);
|
||||
}
|
||||
}
|
||||
|
||||
void URLRequestStreamJob::OnEnd(mate::Arguments* args) {
|
||||
ended_ = true;
|
||||
if (pending_io_buf_) {
|
||||
CopyMoreData(pending_io_buf_, pending_io_buf_size_);
|
||||
}
|
||||
}
|
||||
|
||||
void URLRequestStreamJob::OnError(mate::Arguments* args) {
|
||||
errored_ = true;
|
||||
if (pending_io_buf_) {
|
||||
CopyMoreData(pending_io_buf_, pending_io_buf_size_);
|
||||
}
|
||||
}
|
||||
|
||||
int URLRequestStreamJob::ReadRawData(net::IOBuffer* dest, int dest_size) {
|
||||
content::BrowserThread::PostTask(
|
||||
content::BrowserThread::UI, FROM_HERE,
|
||||
base::Bind(&URLRequestStreamJob::CopyMoreData, weak_factory_.GetWeakPtr(),
|
||||
make_scoped_refptr(dest), dest_size));
|
||||
return net::ERR_IO_PENDING;
|
||||
}
|
||||
|
||||
void URLRequestStreamJob::DoneReading() {
|
||||
subscriber_.reset();
|
||||
buffer_.clear();
|
||||
ended_ = true;
|
||||
}
|
||||
|
||||
void URLRequestStreamJob::DoneReadingRedirectResponse() {
|
||||
DoneReading();
|
||||
}
|
||||
|
||||
void URLRequestStreamJob::CopyMoreDataDone(scoped_refptr<net::IOBuffer> io_buf,
|
||||
int status) {
|
||||
if (status <= 0) {
|
||||
subscriber_.reset();
|
||||
}
|
||||
ReadRawDataComplete(status);
|
||||
io_buf = nullptr;
|
||||
}
|
||||
|
||||
void URLRequestStreamJob::CopyMoreData(scoped_refptr<net::IOBuffer> io_buf,
|
||||
int io_buf_size) {
|
||||
// reset any instance references to io_buf
|
||||
pending_io_buf_ = nullptr;
|
||||
pending_io_buf_size_ = 0;
|
||||
|
||||
int read_count = 0;
|
||||
if (buffer_.size()) {
|
||||
size_t count = std::min((size_t)io_buf_size, buffer_.size());
|
||||
std::copy(buffer_.begin(), buffer_.begin() + count, io_buf->data());
|
||||
buffer_.erase(buffer_.begin(), buffer_.begin() + count);
|
||||
read_count = count;
|
||||
} else if (!ended_ && !errored_) {
|
||||
// No data available yet, save references to the IOBuffer, which will be
|
||||
// passed back to this function when OnData/OnEnd/OnError are called
|
||||
pending_io_buf_ = io_buf;
|
||||
pending_io_buf_size_ = io_buf_size;
|
||||
}
|
||||
|
||||
if (!pending_io_buf_) {
|
||||
// Only call CopyMoreDataDone if we have read something.
|
||||
int status = (errored_ && !read_count) ? net::ERR_FAILED : read_count;
|
||||
content::BrowserThread::PostTask(
|
||||
content::BrowserThread::IO, FROM_HERE,
|
||||
base::Bind(&URLRequestStreamJob::CopyMoreDataDone,
|
||||
weak_factory_.GetWeakPtr(), io_buf, status));
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<net::SourceStream> URLRequestStreamJob::SetUpSourceStream() {
|
||||
std::unique_ptr<net::SourceStream> source =
|
||||
net::URLRequestJob::SetUpSourceStream();
|
||||
size_t i = 0;
|
||||
std::string type;
|
||||
while (response_headers_->EnumerateHeader(&i, "Content-Encoding", &type)) {
|
||||
if (base::LowerCaseEqualsASCII(type, "gzip") ||
|
||||
base::LowerCaseEqualsASCII(type, "x-gzip")) {
|
||||
return net::GzipSourceStream::Create(std::move(source),
|
||||
net::SourceStream::TYPE_GZIP);
|
||||
} else if (base::LowerCaseEqualsASCII(type, "deflate")) {
|
||||
return net::GzipSourceStream::Create(std::move(source),
|
||||
net::SourceStream::TYPE_DEFLATE);
|
||||
}
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
bool URLRequestStreamJob::GetMimeType(std::string* mime_type) const {
|
||||
return response_headers_->GetMimeType(mime_type);
|
||||
}
|
||||
|
||||
int URLRequestStreamJob::GetResponseCode() const {
|
||||
return response_headers_->response_code();
|
||||
}
|
||||
|
||||
void URLRequestStreamJob::GetResponseInfo(net::HttpResponseInfo* info) {
|
||||
info->headers = response_headers_;
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
66
atom/browser/net/url_request_stream_job.h
Normal file
66
atom/browser/net/url_request_stream_job.h
Normal file
@@ -0,0 +1,66 @@
|
||||
// Copyright (c) 2017 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_STREAM_JOB_H_
|
||||
#define ATOM_BROWSER_NET_URL_REQUEST_STREAM_JOB_H_
|
||||
|
||||
#include <deque>
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/api/event_subscriber.h"
|
||||
#include "atom/browser/net/js_asker.h"
|
||||
#include "base/memory/ref_counted_memory.h"
|
||||
#include "native_mate/persistent_dictionary.h"
|
||||
#include "net/base/io_buffer.h"
|
||||
#include "net/http/http_status_code.h"
|
||||
#include "net/url_request/url_request_context_getter.h"
|
||||
#include "v8/include/v8.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
class URLRequestStreamJob : public JsAsker<net::URLRequestJob> {
|
||||
public:
|
||||
URLRequestStreamJob(net::URLRequest* request,
|
||||
net::NetworkDelegate* network_delegate);
|
||||
|
||||
void OnData(mate::Arguments* args);
|
||||
void OnEnd(mate::Arguments* args);
|
||||
void OnError(mate::Arguments* args);
|
||||
|
||||
// URLRequestJob
|
||||
void GetResponseInfo(net::HttpResponseInfo* info) override;
|
||||
|
||||
protected:
|
||||
// URLRequestJob
|
||||
int ReadRawData(net::IOBuffer* buf, int buf_size) override;
|
||||
void DoneReading() override;
|
||||
void DoneReadingRedirectResponse() override;
|
||||
std::unique_ptr<net::SourceStream> SetUpSourceStream() override;
|
||||
bool GetMimeType(std::string* mime_type) const override;
|
||||
int GetResponseCode() const override;
|
||||
|
||||
private:
|
||||
// JSAsker
|
||||
void BeforeStartInUI(v8::Isolate*, v8::Local<v8::Value>) override;
|
||||
void StartAsync(std::unique_ptr<base::Value> options) override;
|
||||
void OnResponse(bool success, std::unique_ptr<base::Value> value);
|
||||
|
||||
// Callback after data is asynchronously read from the file into |buf|.
|
||||
void CopyMoreData(scoped_refptr<net::IOBuffer> io_buf, int io_buf_size);
|
||||
void CopyMoreDataDone(scoped_refptr<net::IOBuffer> io_buf, int read_count);
|
||||
|
||||
std::deque<char> buffer_;
|
||||
bool ended_;
|
||||
bool errored_;
|
||||
scoped_refptr<net::IOBuffer> pending_io_buf_;
|
||||
int pending_io_buf_size_;
|
||||
scoped_refptr<net::HttpResponseHeaders> response_headers_;
|
||||
mate::EventSubscriber<URLRequestStreamJob>::SafePtr subscriber_;
|
||||
base::WeakPtrFactory<URLRequestStreamJob> weak_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(URLRequestStreamJob);
|
||||
};
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_NET_URL_REQUEST_STREAM_JOB_H_
|
||||
@@ -27,9 +27,9 @@ void NodeDebugger::Start() {
|
||||
node::DebugOptions options;
|
||||
for (auto& arg : base::CommandLine::ForCurrentProcess()->argv()) {
|
||||
#if defined(OS_WIN)
|
||||
options.ParseOption(base::UTF16ToUTF8(arg));
|
||||
options.ParseOption("Electron", base::UTF16ToUTF8(arg));
|
||||
#else
|
||||
options.ParseOption(arg);
|
||||
options.ParseOption("Electron", arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -79,12 +79,12 @@ void OffScreenOutputDevice::EndPaint() {
|
||||
OnPaint(damage_rect_);
|
||||
}
|
||||
|
||||
void OffScreenOutputDevice::SetActive(bool active) {
|
||||
void OffScreenOutputDevice::SetActive(bool active, bool paint) {
|
||||
if (active == active_)
|
||||
return;
|
||||
active_ = active;
|
||||
|
||||
if (active_)
|
||||
if (active_ && paint)
|
||||
OnPaint(gfx::Rect(viewport_pixel_size_));
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ class OffScreenOutputDevice : public cc::SoftwareOutputDevice {
|
||||
SkCanvas* BeginPaint(const gfx::Rect& damage_rect) override;
|
||||
void EndPaint() override;
|
||||
|
||||
void SetActive(bool active);
|
||||
void SetActive(bool active, bool paint);
|
||||
void OnPaint(const gfx::Rect& damage_rect);
|
||||
|
||||
private:
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "atom/browser/osr/osr_render_widget_host_view.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/callback_helpers.h"
|
||||
@@ -15,10 +17,10 @@
|
||||
#include "cc/output/copy_output_request.h"
|
||||
#include "cc/scheduler/delay_based_time_source.h"
|
||||
#include "components/display_compositor/gl_helper.h"
|
||||
#include "content/browser/renderer_host/compositor_resize_lock.h"
|
||||
#include "content/browser/renderer_host/render_widget_host_delegate.h"
|
||||
#include "content/browser/renderer_host/render_widget_host_impl.h"
|
||||
#include "content/browser/renderer_host/render_widget_host_view_frame_subscriber.h"
|
||||
#include "content/browser/renderer_host/resize_lock.h"
|
||||
#include "content/common/view_messages.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/context_factory.h"
|
||||
@@ -29,10 +31,10 @@
|
||||
#include "ui/compositor/layer_type.h"
|
||||
#include "ui/events/base_event_utils.h"
|
||||
#include "ui/events/event_constants.h"
|
||||
#include "ui/events/latency_info.h"
|
||||
#include "ui/gfx/geometry/dip_util.h"
|
||||
#include "ui/gfx/native_widget_types.h"
|
||||
#include "ui/gfx/skbitmap_operations.h"
|
||||
#include "ui/latency/latency_info.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
@@ -43,23 +45,23 @@ const int kFrameRetryLimit = 2;
|
||||
|
||||
ui::MouseEvent UiMouseEventFromWebMouseEvent(blink::WebMouseEvent event) {
|
||||
ui::EventType type = ui::EventType::ET_UNKNOWN;
|
||||
switch (event.type()) {
|
||||
case blink::WebInputEvent::MouseDown:
|
||||
switch (event.GetType()) {
|
||||
case blink::WebInputEvent::kMouseDown:
|
||||
type = ui::EventType::ET_MOUSE_PRESSED;
|
||||
break;
|
||||
case blink::WebInputEvent::MouseUp:
|
||||
case blink::WebInputEvent::kMouseUp:
|
||||
type = ui::EventType::ET_MOUSE_RELEASED;
|
||||
break;
|
||||
case blink::WebInputEvent::MouseMove:
|
||||
case blink::WebInputEvent::kMouseMove:
|
||||
type = ui::EventType::ET_MOUSE_MOVED;
|
||||
break;
|
||||
case blink::WebInputEvent::MouseEnter:
|
||||
case blink::WebInputEvent::kMouseEnter:
|
||||
type = ui::EventType::ET_MOUSE_ENTERED;
|
||||
break;
|
||||
case blink::WebInputEvent::MouseLeave:
|
||||
case blink::WebInputEvent::kMouseLeave:
|
||||
type = ui::EventType::ET_MOUSE_EXITED;
|
||||
break;
|
||||
case blink::WebInputEvent::MouseWheel:
|
||||
case blink::WebInputEvent::kMouseWheel:
|
||||
type = ui::EventType::ET_MOUSEWHEEL;
|
||||
break;
|
||||
default:
|
||||
@@ -69,19 +71,19 @@ ui::MouseEvent UiMouseEventFromWebMouseEvent(blink::WebMouseEvent event) {
|
||||
|
||||
int button_flags = 0;
|
||||
switch (event.button) {
|
||||
case blink::WebMouseEvent::Button::X1:
|
||||
case blink::WebMouseEvent::Button::kBack:
|
||||
button_flags |= ui::EventFlags::EF_BACK_MOUSE_BUTTON;
|
||||
break;
|
||||
case blink::WebMouseEvent::Button::X2:
|
||||
case blink::WebMouseEvent::Button::kForward:
|
||||
button_flags |= ui::EventFlags::EF_FORWARD_MOUSE_BUTTON;
|
||||
break;
|
||||
case blink::WebMouseEvent::Button::Left:
|
||||
case blink::WebMouseEvent::Button::kLeft:
|
||||
button_flags |= ui::EventFlags::EF_LEFT_MOUSE_BUTTON;
|
||||
break;
|
||||
case blink::WebMouseEvent::Button::Middle:
|
||||
case blink::WebMouseEvent::Button::kMiddle:
|
||||
button_flags |= ui::EventFlags::EF_MIDDLE_MOUSE_BUTTON;
|
||||
break;
|
||||
case blink::WebMouseEvent::Button::Right:
|
||||
case blink::WebMouseEvent::Button::kRight:
|
||||
button_flags |= ui::EventFlags::EF_RIGHT_MOUSE_BUTTON;
|
||||
break;
|
||||
default:
|
||||
@@ -90,11 +92,12 @@ ui::MouseEvent UiMouseEventFromWebMouseEvent(blink::WebMouseEvent event) {
|
||||
}
|
||||
|
||||
ui::MouseEvent ui_event(type,
|
||||
gfx::Point(std::floor(event.x), std::floor(event.y)),
|
||||
gfx::Point(std::floor(event.x), std::floor(event.y)),
|
||||
ui::EventTimeForNow(),
|
||||
button_flags, button_flags);
|
||||
ui_event.SetClickCount(event.clickCount);
|
||||
gfx::Point(std::floor(event.PositionInWidget().x),
|
||||
std::floor(event.PositionInWidget().y)),
|
||||
gfx::Point(std::floor(event.PositionInWidget().x),
|
||||
std::floor(event.PositionInWidget().y)),
|
||||
ui::EventTimeForNow(), button_flags, button_flags);
|
||||
ui_event.SetClickCount(event.click_count);
|
||||
|
||||
return ui_event;
|
||||
}
|
||||
@@ -102,69 +105,9 @@ ui::MouseEvent UiMouseEventFromWebMouseEvent(blink::WebMouseEvent event) {
|
||||
ui::MouseWheelEvent UiMouseWheelEventFromWebMouseEvent(
|
||||
blink::WebMouseWheelEvent event) {
|
||||
return ui::MouseWheelEvent(UiMouseEventFromWebMouseEvent(event),
|
||||
std::floor(event.deltaX), std::floor(event.deltaY));
|
||||
std::floor(event.delta_x), std::floor(event.delta_y));
|
||||
}
|
||||
|
||||
#if !defined(OS_MACOSX)
|
||||
|
||||
const int kResizeLockTimeoutMs = 67;
|
||||
|
||||
class AtomResizeLock : public content::ResizeLock {
|
||||
public:
|
||||
AtomResizeLock(OffScreenRenderWidgetHostView* host,
|
||||
const gfx::Size new_size,
|
||||
bool defer_compositor_lock)
|
||||
: ResizeLock(new_size, defer_compositor_lock),
|
||||
host_(host),
|
||||
cancelled_(false),
|
||||
weak_ptr_factory_(this) {
|
||||
DCHECK(host_);
|
||||
host_->HoldResize();
|
||||
|
||||
content::BrowserThread::PostDelayedTask(content::BrowserThread::UI,
|
||||
FROM_HERE, base::Bind(&AtomResizeLock::CancelLock,
|
||||
weak_ptr_factory_.GetWeakPtr()),
|
||||
base::TimeDelta::FromMilliseconds(kResizeLockTimeoutMs));
|
||||
}
|
||||
|
||||
~AtomResizeLock() override {
|
||||
CancelLock();
|
||||
}
|
||||
|
||||
bool GrabDeferredLock() override {
|
||||
return ResizeLock::GrabDeferredLock();
|
||||
}
|
||||
|
||||
void UnlockCompositor() override {
|
||||
ResizeLock::UnlockCompositor();
|
||||
compositor_lock_ = NULL;
|
||||
}
|
||||
|
||||
protected:
|
||||
void LockCompositor() override {
|
||||
ResizeLock::LockCompositor();
|
||||
compositor_lock_ = host_->GetCompositor()->GetCompositorLock();
|
||||
}
|
||||
|
||||
void CancelLock() {
|
||||
if (cancelled_)
|
||||
return;
|
||||
cancelled_ = true;
|
||||
UnlockCompositor();
|
||||
host_->ReleaseResize();
|
||||
}
|
||||
|
||||
private:
|
||||
OffScreenRenderWidgetHostView* host_;
|
||||
scoped_refptr<ui::CompositorLock> compositor_lock_;
|
||||
bool cancelled_;
|
||||
base::WeakPtrFactory<AtomResizeLock> weak_ptr_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AtomResizeLock);
|
||||
};
|
||||
|
||||
#endif // !defined(OS_MACOSX)
|
||||
|
||||
} // namespace
|
||||
|
||||
class AtomCopyFrameGenerator {
|
||||
@@ -336,6 +279,8 @@ OffScreenRenderWidgetHostView::OffScreenRenderWidgetHostView(
|
||||
popup_position_(gfx::Rect()),
|
||||
hold_resize_(false),
|
||||
pending_resize_(false),
|
||||
renderer_compositor_frame_sink_(nullptr),
|
||||
background_color_(SkColor()),
|
||||
weak_ptr_factory_(this) {
|
||||
DCHECK(render_widget_host_);
|
||||
bool is_guest_view_hack = parent_host_view_ != nullptr;
|
||||
@@ -554,14 +499,18 @@ gfx::Rect OffScreenRenderWidgetHostView::GetViewBounds() const {
|
||||
}
|
||||
|
||||
void OffScreenRenderWidgetHostView::SetBackgroundColor(SkColor color) {
|
||||
if (transparent_)
|
||||
color = SkColorSetARGB(SK_AlphaTRANSPARENT, 0, 0, 0);
|
||||
// The renderer will feed its color back to us with the first CompositorFrame.
|
||||
// We short-cut here to show a sensible color before that happens.
|
||||
UpdateBackgroundColorFromRenderer(color);
|
||||
|
||||
content::RenderWidgetHostViewBase::SetBackgroundColor(color);
|
||||
if (render_widget_host_) {
|
||||
render_widget_host_->SetBackgroundOpaque(SkColorGetA(color) ==
|
||||
SK_AlphaOPAQUE);
|
||||
}
|
||||
}
|
||||
|
||||
const bool opaque = !transparent_ && GetBackgroundOpaque();
|
||||
if (render_widget_host_)
|
||||
render_widget_host_->SetBackgroundOpaque(opaque);
|
||||
SkColor OffScreenRenderWidgetHostView::background_color() const {
|
||||
return background_color_;
|
||||
}
|
||||
|
||||
gfx::Size OffScreenRenderWidgetHostView::GetVisibleViewportSize() const {
|
||||
@@ -578,11 +527,20 @@ bool OffScreenRenderWidgetHostView::LockMouse() {
|
||||
void OffScreenRenderWidgetHostView::UnlockMouse() {
|
||||
}
|
||||
|
||||
void OffScreenRenderWidgetHostView::OnSwapCompositorFrame(
|
||||
uint32_t output_surface_id,
|
||||
cc::CompositorFrame frame) {
|
||||
void OffScreenRenderWidgetHostView::DidCreateNewRendererCompositorFrameSink(
|
||||
cc::mojom::MojoCompositorFrameSinkClient* renderer_compositor_frame_sink) {
|
||||
renderer_compositor_frame_sink_ = renderer_compositor_frame_sink;
|
||||
if (GetDelegatedFrameHost()) {
|
||||
GetDelegatedFrameHost()->DidCreateNewRendererCompositorFrameSink(
|
||||
renderer_compositor_frame_sink_);
|
||||
}
|
||||
}
|
||||
|
||||
void OffScreenRenderWidgetHostView::SubmitCompositorFrame(
|
||||
const cc::LocalSurfaceId& local_surface_id,
|
||||
cc::CompositorFrame frame) {
|
||||
TRACE_EVENT0("electron",
|
||||
"OffScreenRenderWidgetHostView::OnSwapCompositorFrame");
|
||||
"OffScreenRenderWidgetHostView::SubmitCompositorFrame");
|
||||
|
||||
if (frame.metadata.root_scroll_offset != last_scroll_offset_) {
|
||||
last_scroll_offset_ = frame.metadata.root_scroll_offset;
|
||||
@@ -591,16 +549,16 @@ void OffScreenRenderWidgetHostView::OnSwapCompositorFrame(
|
||||
if (!frame.render_pass_list.empty()) {
|
||||
if (software_output_device_) {
|
||||
if (!begin_frame_timer_.get() || IsPopupWidget()) {
|
||||
software_output_device_->SetActive(painting_);
|
||||
software_output_device_->SetActive(painting_, false);
|
||||
}
|
||||
|
||||
// The compositor will draw directly to the SoftwareOutputDevice which
|
||||
// then calls OnPaint.
|
||||
// We would normally call BrowserCompositorMac::SwapCompositorFrame on
|
||||
// We would normally call BrowserCompositorMac::SubmitCompositorFrame on
|
||||
// macOS, however it contains compositor resize logic that we don't want.
|
||||
// Consequently we instead call the SwapDelegatedFrame method directly.
|
||||
GetDelegatedFrameHost()->SwapDelegatedFrame(output_surface_id,
|
||||
std::move(frame));
|
||||
// Consequently we instead call the SubmitCompositorFrame method directly.
|
||||
GetDelegatedFrameHost()->SubmitCompositorFrame(local_surface_id,
|
||||
std::move(frame));
|
||||
} else {
|
||||
if (!copy_frame_generator_.get()) {
|
||||
copy_frame_generator_.reset(
|
||||
@@ -615,11 +573,11 @@ void OffScreenRenderWidgetHostView::OnSwapCompositorFrame(
|
||||
gfx::ToEnclosingRect(gfx::RectF(root_pass->damage_rect));
|
||||
damage_rect.Intersect(gfx::Rect(frame_size));
|
||||
|
||||
// We would normally call BrowserCompositorMac::SwapCompositorFrame on
|
||||
// We would normally call BrowserCompositorMac::SubmitCompositorFrame on
|
||||
// macOS, however it contains compositor resize logic that we don't want.
|
||||
// Consequently we instead call the SwapDelegatedFrame method directly.
|
||||
GetDelegatedFrameHost()->SwapDelegatedFrame(output_surface_id,
|
||||
std::move(frame));
|
||||
// Consequently we instead call the SubmitCompositorFrame method directly.
|
||||
GetDelegatedFrameHost()->SubmitCompositorFrame(local_surface_id,
|
||||
std::move(frame));
|
||||
|
||||
// Request a copy of the last compositor frame which will eventually call
|
||||
// OnPaint asynchronously.
|
||||
@@ -685,8 +643,14 @@ void OffScreenRenderWidgetHostView::Destroy() {
|
||||
popup_bitmap_.reset();
|
||||
if (child_host_view_)
|
||||
child_host_view_->CancelWidget();
|
||||
for (auto guest_host_view : guest_host_views_)
|
||||
guest_host_view->CancelWidget();
|
||||
if (!guest_host_views_.empty()) {
|
||||
// Guest RWHVs will be destroyed when the associated RWHVGuest is
|
||||
// destroyed. This parent RWHV may be destroyed first, so disassociate
|
||||
// the guest RWHVs here without destroying them.
|
||||
for (auto guest_host_view : guest_host_views_)
|
||||
guest_host_view->parent_host_view_ = nullptr;
|
||||
guest_host_views_.clear();
|
||||
}
|
||||
for (auto proxy_view : proxy_views_)
|
||||
proxy_view->RemoveObserver();
|
||||
Hide();
|
||||
@@ -807,31 +771,25 @@ bool OffScreenRenderWidgetHostView::DelegatedFrameCanCreateResizeLock() const {
|
||||
return !render_widget_host_->auto_resize_enabled();
|
||||
}
|
||||
|
||||
std::unique_ptr<content::ResizeLock>
|
||||
OffScreenRenderWidgetHostView::DelegatedFrameHostCreateResizeLock(
|
||||
bool defer_compositor_lock) {
|
||||
return std::unique_ptr<content::ResizeLock>(new AtomResizeLock(
|
||||
this,
|
||||
DelegatedFrameHostDesiredSizeInDIP(),
|
||||
defer_compositor_lock));
|
||||
}
|
||||
|
||||
void OffScreenRenderWidgetHostView::DelegatedFrameHostResizeLockWasReleased() {
|
||||
return render_widget_host_->WasResized();
|
||||
std::unique_ptr<content::CompositorResizeLock>
|
||||
OffScreenRenderWidgetHostView::DelegatedFrameHostCreateResizeLock() {
|
||||
HoldResize();
|
||||
const gfx::Size& desired_size = GetRootLayer()->bounds().size();
|
||||
return base::MakeUnique<content::CompositorResizeLock>(this, desired_size);
|
||||
}
|
||||
|
||||
void
|
||||
OffScreenRenderWidgetHostView::DelegatedFrameHostSendReclaimCompositorResources(
|
||||
int output_surface_id,
|
||||
bool is_swap_ack,
|
||||
const cc::ReturnedResourceArray& resources) {
|
||||
render_widget_host_->Send(new ViewMsg_ReclaimCompositorResources(
|
||||
render_widget_host_->GetRoutingID(), output_surface_id, is_swap_ack,
|
||||
resources));
|
||||
OffScreenRenderWidgetHostView::OnBeginFrame(const cc::BeginFrameArgs& args) {
|
||||
}
|
||||
|
||||
void OffScreenRenderWidgetHostView::SetBeginFrameSource(
|
||||
cc::BeginFrameSource* source) {
|
||||
std::unique_ptr<ui::CompositorLock>
|
||||
OffScreenRenderWidgetHostView::GetCompositorLock(
|
||||
ui::CompositorLockClient* client) {
|
||||
return GetCompositor()->GetCompositorLock(client);
|
||||
}
|
||||
|
||||
void OffScreenRenderWidgetHostView::CompositorResizeLockEnded() {
|
||||
ReleaseResize();
|
||||
}
|
||||
|
||||
#endif // !defined(OS_MACOSX)
|
||||
@@ -977,7 +935,7 @@ void OffScreenRenderWidgetHostView::SetNeedsBeginFrames(
|
||||
begin_frame_timer_->SetActive(needs_begin_frames);
|
||||
|
||||
if (software_output_device_) {
|
||||
software_output_device_->SetActive(needs_begin_frames && painting_);
|
||||
software_output_device_->SetActive(needs_begin_frames && painting_, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1111,12 +1069,12 @@ void OffScreenRenderWidgetHostView::ProcessMouseEvent(
|
||||
const ui::LatencyInfo& latency) {
|
||||
for (auto proxy_view : proxy_views_) {
|
||||
gfx::Rect bounds = proxy_view->GetBounds();
|
||||
if (bounds.Contains(event.x, event.y)) {
|
||||
if (bounds.Contains(event.PositionInWidget().x,
|
||||
event.PositionInWidget().y)) {
|
||||
blink::WebMouseEvent proxy_event(event);
|
||||
proxy_event.x -= bounds.x();
|
||||
proxy_event.y -= bounds.y();
|
||||
proxy_event.windowX = proxy_event.x;
|
||||
proxy_event.windowY = proxy_event.y;
|
||||
proxy_event.SetPositionInWidget(
|
||||
proxy_event.PositionInWidget().x - bounds.x(),
|
||||
proxy_event.PositionInWidget().y - bounds.y());
|
||||
|
||||
ui::MouseEvent ui_event = UiMouseEventFromWebMouseEvent(proxy_event);
|
||||
proxy_view->OnEvent(&ui_event);
|
||||
@@ -1125,13 +1083,14 @@ void OffScreenRenderWidgetHostView::ProcessMouseEvent(
|
||||
}
|
||||
|
||||
if (!IsPopupWidget()) {
|
||||
if (popup_host_view_ &&
|
||||
popup_host_view_->popup_position_.Contains(event.x, event.y)) {
|
||||
if (popup_host_view_ && popup_host_view_->popup_position_.Contains(
|
||||
event.PositionInWidget().x, event.PositionInWidget().y)) {
|
||||
blink::WebMouseEvent popup_event(event);
|
||||
popup_event.x -= popup_host_view_->popup_position_.x();
|
||||
popup_event.y -= popup_host_view_->popup_position_.y();
|
||||
popup_event.windowX = popup_event.x;
|
||||
popup_event.windowY = popup_event.y;
|
||||
popup_event.SetPositionInWidget(
|
||||
popup_event.PositionInWidget().x -
|
||||
popup_host_view_->popup_position_.x(),
|
||||
popup_event.PositionInWidget().y -
|
||||
popup_host_view_->popup_position_.y());
|
||||
|
||||
popup_host_view_->ProcessMouseEvent(popup_event, latency);
|
||||
return;
|
||||
@@ -1148,12 +1107,12 @@ void OffScreenRenderWidgetHostView::ProcessMouseWheelEvent(
|
||||
const ui::LatencyInfo& latency) {
|
||||
for (auto proxy_view : proxy_views_) {
|
||||
gfx::Rect bounds = proxy_view->GetBounds();
|
||||
if (bounds.Contains(event.x, event.y)) {
|
||||
if (bounds.Contains(event.PositionInWidget().x,
|
||||
event.PositionInWidget().y)) {
|
||||
blink::WebMouseWheelEvent proxy_event(event);
|
||||
proxy_event.x -= bounds.x();
|
||||
proxy_event.y -= bounds.y();
|
||||
proxy_event.windowX = proxy_event.x;
|
||||
proxy_event.windowY = proxy_event.y;
|
||||
proxy_event.SetPositionInWidget(
|
||||
proxy_event.PositionInWidget().x - bounds.x(),
|
||||
proxy_event.PositionInWidget().y - bounds.y());
|
||||
|
||||
ui::MouseWheelEvent ui_event =
|
||||
UiMouseWheelEventFromWebMouseEvent(proxy_event);
|
||||
@@ -1163,12 +1122,14 @@ void OffScreenRenderWidgetHostView::ProcessMouseWheelEvent(
|
||||
}
|
||||
if (!IsPopupWidget()) {
|
||||
if (popup_host_view_) {
|
||||
if (popup_host_view_->popup_position_.Contains(event.x, event.y)) {
|
||||
if (popup_host_view_->popup_position_.Contains(
|
||||
event.PositionInWidget().x, event.PositionInWidget().y)) {
|
||||
blink::WebMouseWheelEvent popup_event(event);
|
||||
popup_event.x -= popup_host_view_->popup_position_.x();
|
||||
popup_event.y -= popup_host_view_->popup_position_.y();
|
||||
popup_event.windowX = popup_event.x;
|
||||
popup_event.windowY = popup_event.y;
|
||||
popup_event.SetPositionInWidget(
|
||||
popup_event.PositionInWidget().x -
|
||||
popup_host_view_->popup_position_.x(),
|
||||
popup_event.PositionInWidget().y -
|
||||
popup_host_view_->popup_position_.y());
|
||||
popup_host_view_->ProcessMouseWheelEvent(popup_event, latency);
|
||||
return;
|
||||
} else {
|
||||
@@ -1190,7 +1151,7 @@ void OffScreenRenderWidgetHostView::SetPainting(bool painting) {
|
||||
painting_ = painting;
|
||||
|
||||
if (software_output_device_) {
|
||||
software_output_device_->SetActive(painting_);
|
||||
software_output_device_->SetActive(painting_, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1312,4 +1273,15 @@ cc::FrameSinkId OffScreenRenderWidgetHostView::AllocateFrameSinkId(
|
||||
render_widget_host_->GetRoutingID()));
|
||||
}
|
||||
|
||||
void OffScreenRenderWidgetHostView::UpdateBackgroundColorFromRenderer(
|
||||
SkColor color) {
|
||||
if (color == background_color())
|
||||
return;
|
||||
background_color_ = color;
|
||||
|
||||
bool opaque = SkColorGetA(color) == SK_AlphaOPAQUE;
|
||||
GetRootLayer()->SetFillsBoundsOpaquely(opaque);
|
||||
GetRootLayer()->SetColor(color);
|
||||
}
|
||||
|
||||
} // namespace atom
|
||||
|
||||
@@ -23,10 +23,10 @@
|
||||
#include "cc/output/compositor_frame.h"
|
||||
#include "cc/scheduler/begin_frame_source.h"
|
||||
#include "content/browser/frame_host/render_widget_host_view_guest.h"
|
||||
#include "content/browser/renderer_host/compositor_resize_lock.h"
|
||||
#include "content/browser/renderer_host/delegated_frame_host.h"
|
||||
#include "content/browser/renderer_host/render_widget_host_impl.h"
|
||||
#include "content/browser/renderer_host/render_widget_host_view_base.h"
|
||||
#include "content/browser/renderer_host/resize_lock.h"
|
||||
#include "content/browser/web_contents/web_contents_view.h"
|
||||
#include "third_party/skia/include/core/SkBitmap.h"
|
||||
#include "third_party/WebKit/public/platform/WebVector.h"
|
||||
@@ -68,6 +68,7 @@ class OffScreenRenderWidgetHostView
|
||||
public ui::CompositorDelegate,
|
||||
#if !defined(OS_MACOSX)
|
||||
public content::DelegatedFrameHostClient,
|
||||
public content::CompositorResizeLockClient,
|
||||
#endif
|
||||
public NativeWindowObserver,
|
||||
public OffscreenViewProxyObserver {
|
||||
@@ -99,6 +100,7 @@ class OffScreenRenderWidgetHostView
|
||||
gfx::Size GetVisibleViewportSize() const override;
|
||||
void SetInsets(const gfx::Insets&) override;
|
||||
void SetBackgroundColor(SkColor color) override;
|
||||
SkColor background_color() const override;
|
||||
bool LockMouse(void) override;
|
||||
void UnlockMouse(void) override;
|
||||
void SetNeedsBeginFrames(bool needs_begin_frames) override;
|
||||
@@ -113,8 +115,12 @@ class OffScreenRenderWidgetHostView
|
||||
#endif // defined(OS_MACOSX)
|
||||
|
||||
// content::RenderWidgetHostViewBase:
|
||||
void OnSwapCompositorFrame(uint32_t, cc::CompositorFrame)
|
||||
override;
|
||||
void DidCreateNewRendererCompositorFrameSink(
|
||||
cc::mojom::MojoCompositorFrameSinkClient* renderer_compositor_frame_sink)
|
||||
override;
|
||||
void SubmitCompositorFrame(const cc::LocalSurfaceId& local_surface_id,
|
||||
cc::CompositorFrame frame) override;
|
||||
|
||||
void ClearCompositorFrame(void) override;
|
||||
void InitAsPopup(content::RenderWidgetHostView *rwhv, const gfx::Rect& rect)
|
||||
override;
|
||||
@@ -167,15 +173,14 @@ class OffScreenRenderWidgetHostView
|
||||
bool DelegatedFrameHostIsVisible(void) const override;
|
||||
SkColor DelegatedFrameHostGetGutterColor(SkColor) const override;
|
||||
gfx::Size DelegatedFrameHostDesiredSizeInDIP(void) const override;
|
||||
bool DelegatedFrameCanCreateResizeLock(void) const override;
|
||||
std::unique_ptr<content::ResizeLock> DelegatedFrameHostCreateResizeLock(
|
||||
bool defer_compositor_lock) override;
|
||||
void DelegatedFrameHostResizeLockWasReleased(void) override;
|
||||
void DelegatedFrameHostSendReclaimCompositorResources(
|
||||
int output_surface_id,
|
||||
bool is_swap_ack,
|
||||
const cc::ReturnedResourceArray& resources) override;
|
||||
void SetBeginFrameSource(cc::BeginFrameSource* source) override;
|
||||
bool DelegatedFrameCanCreateResizeLock() const override;
|
||||
std::unique_ptr<content::CompositorResizeLock>
|
||||
DelegatedFrameHostCreateResizeLock() override;
|
||||
void OnBeginFrame(const cc::BeginFrameArgs& args) override;
|
||||
// CompositorResizeLockClient implementation.
|
||||
std::unique_ptr<ui::CompositorLock> GetCompositorLock(
|
||||
ui::CompositorLockClient* client) override;
|
||||
void CompositorResizeLockEnded() override;
|
||||
#endif // !defined(OS_MACOSX)
|
||||
|
||||
bool TransformPointToLocalCoordSpace(
|
||||
@@ -224,7 +229,7 @@ class OffScreenRenderWidgetHostView
|
||||
void OnProxyViewPaint(const gfx::Rect& damage_rect);
|
||||
|
||||
bool IsPopupWidget() const {
|
||||
return popup_type_ != blink::WebPopupTypeNone;
|
||||
return popup_type_ != blink::kWebPopupTypeNone;
|
||||
}
|
||||
|
||||
void HoldResize();
|
||||
@@ -271,6 +276,10 @@ class OffScreenRenderWidgetHostView
|
||||
|
||||
cc::FrameSinkId AllocateFrameSinkId(bool is_guest_view_hack);
|
||||
|
||||
// Applies background color without notifying the RenderWidget about
|
||||
// opaqueness changes.
|
||||
void UpdateBackgroundColorFromRenderer(SkColor color);
|
||||
|
||||
// Weak ptrs.
|
||||
content::RenderWidgetHostImpl* render_widget_host_;
|
||||
|
||||
@@ -328,6 +337,10 @@ class OffScreenRenderWidgetHostView
|
||||
std::string selected_text_;
|
||||
#endif
|
||||
|
||||
cc::mojom::MojoCompositorFrameSinkClient* renderer_compositor_frame_sink_;
|
||||
|
||||
SkColor background_color_;
|
||||
|
||||
base::WeakPtrFactory<OffScreenRenderWidgetHostView> weak_ptr_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(OffScreenRenderWidgetHostView);
|
||||
|
||||
@@ -38,15 +38,6 @@ class MacHelper :
|
||||
return color;
|
||||
}
|
||||
|
||||
void BrowserCompositorMacSendReclaimCompositorResources(
|
||||
int output_surface_id,
|
||||
bool is_swap_ack,
|
||||
const cc::ReturnedResourceArray& resources) override {
|
||||
view_->render_widget_host()->Send(new ViewMsg_ReclaimCompositorResources(
|
||||
view_->render_widget_host()->GetRoutingID(), output_surface_id,
|
||||
is_swap_ack, resources));
|
||||
}
|
||||
|
||||
void BrowserCompositorMacSendBeginFrame(
|
||||
const cc::BeginFrameArgs& args) override {
|
||||
view_->render_widget_host()->Send(
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>electron.icns</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.7.10</string>
|
||||
<string>1.8.2</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.7.10</string>
|
||||
<string>1.8.2</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.developer-tools</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
|
||||
@@ -56,8 +56,8 @@ END
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,7,10,0
|
||||
PRODUCTVERSION 1,7,10,0
|
||||
FILEVERSION 1,8,2,2
|
||||
PRODUCTVERSION 1,8,2,2
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -74,12 +74,12 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "GitHub, Inc."
|
||||
VALUE "FileDescription", "Electron"
|
||||
VALUE "FileVersion", "1.7.10"
|
||||
VALUE "FileVersion", "1.8.2"
|
||||
VALUE "InternalName", "electron.exe"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
|
||||
VALUE "OriginalFilename", "electron.exe"
|
||||
VALUE "ProductName", "Electron"
|
||||
VALUE "ProductVersion", "1.7.10"
|
||||
VALUE "ProductVersion", "1.8.2"
|
||||
VALUE "SquirrelAwareVersion", "1"
|
||||
END
|
||||
END
|
||||
|
||||
@@ -155,7 +155,6 @@ void AutofillPopup::SetItems(const std::vector<base::string16>& values,
|
||||
const std::vector<base::string16>& labels) {
|
||||
values_ = values;
|
||||
labels_ = labels;
|
||||
UpdatePopupBounds();
|
||||
if (view_) {
|
||||
view_->OnSuggestionsChanged();
|
||||
}
|
||||
@@ -166,21 +165,23 @@ void AutofillPopup::AcceptSuggestion(int index) {
|
||||
frame_host_->GetRoutingID(), GetValueAt(index)));
|
||||
}
|
||||
|
||||
void AutofillPopup::UpdatePopupBounds() {
|
||||
void AutofillPopup::UpdatePopupBounds(int height_compensation) {
|
||||
int desired_width = GetDesiredPopupWidth();
|
||||
int desired_height = GetDesiredPopupHeight();
|
||||
bool is_rtl = false;
|
||||
|
||||
gfx::Point origin(element_bounds_.origin().x(),
|
||||
element_bounds_.origin().y() - height_compensation);
|
||||
gfx::Rect bounds(origin, element_bounds_.size());
|
||||
|
||||
gfx::Point top_left_corner_of_popup =
|
||||
element_bounds_.origin() +
|
||||
gfx::Vector2d(element_bounds_.width() - desired_width, -desired_height);
|
||||
origin + gfx::Vector2d(bounds.width() - desired_width, -desired_height);
|
||||
|
||||
// This is the bottom right point of the popup if the popup is below the
|
||||
// element and grows to the right (since the is the lowest and furthest right
|
||||
// the popup could go).
|
||||
gfx::Point bottom_right_corner_of_popup =
|
||||
element_bounds_.origin() +
|
||||
gfx::Vector2d(desired_width, element_bounds_.height() + desired_height);
|
||||
origin + gfx::Vector2d(desired_width, bounds.height() + desired_height);
|
||||
|
||||
display::Display top_left_display =
|
||||
GetDisplayNearestPoint(top_left_corner_of_popup, container_view_);
|
||||
@@ -189,14 +190,19 @@ void AutofillPopup::UpdatePopupBounds() {
|
||||
|
||||
std::pair<int, int> popup_x_and_width =
|
||||
CalculatePopupXAndWidth(top_left_display, bottom_right_display,
|
||||
desired_width, element_bounds_, is_rtl);
|
||||
std::pair<int, int> popup_y_and_height = CalculatePopupYAndHeight(
|
||||
top_left_display, bottom_right_display, desired_height, element_bounds_);
|
||||
desired_width, bounds, is_rtl);
|
||||
std::pair<int, int> popup_y_and_height =
|
||||
CalculatePopupYAndHeight(top_left_display, bottom_right_display,
|
||||
desired_height, bounds);
|
||||
|
||||
popup_bounds_ = gfx::Rect(popup_x_and_width.first, popup_y_and_height.first,
|
||||
popup_bounds_ = gfx::Rect(
|
||||
popup_x_and_width.first, popup_y_and_height.first,
|
||||
popup_x_and_width.second, popup_y_and_height.second);
|
||||
popup_bounds_in_view_ = gfx::Rect(popup_bounds_in_view_.origin(),
|
||||
popup_bounds_in_view_ = gfx::Rect(
|
||||
popup_bounds_in_view_.origin(),
|
||||
gfx::Size(popup_x_and_width.second, popup_y_and_height.second));
|
||||
if (view_)
|
||||
view_->DoUpdateBoundsAndRedrawPopup();
|
||||
}
|
||||
|
||||
int AutofillPopup::GetDesiredPopupHeight() {
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "content/public/browser/render_frame_host.h"
|
||||
#include "ui/gfx/font_list.h"
|
||||
#include "ui/native_theme/native_theme.h"
|
||||
#include "ui/views/view.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
|
||||
namespace atom {
|
||||
@@ -28,13 +29,13 @@ class AutofillPopup {
|
||||
|
||||
void SetItems(const std::vector<base::string16>& values,
|
||||
const std::vector<base::string16>& labels);
|
||||
void UpdatePopupBounds(int height_compensation);
|
||||
|
||||
private:
|
||||
friend class AutofillPopupView;
|
||||
|
||||
void AcceptSuggestion(int index);
|
||||
|
||||
void UpdatePopupBounds();
|
||||
int GetDesiredPopupHeight();
|
||||
int GetDesiredPopupWidth();
|
||||
gfx::Rect GetRowBounds(int i);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "net/cert/cert_database.h"
|
||||
#include "net/cert/x509_util_mac.h"
|
||||
|
||||
@interface TrustDelegate : NSObject {
|
||||
@private
|
||||
@@ -85,7 +86,8 @@ void ShowCertificateTrust(atom::NativeWindow* parent_window,
|
||||
const std::string& message,
|
||||
const ShowTrustCallback& callback) {
|
||||
auto sec_policy = SecPolicyCreateBasicX509();
|
||||
auto cert_chain = cert->CreateOSCertChainForCert();
|
||||
auto cert_chain =
|
||||
net::x509_util::CreateSecCertificateArrayForX509Certificate(cert.get());
|
||||
SecTrustRef trust = nullptr;
|
||||
SecTrustCreateWithCertificates(cert_chain, sec_policy, &trust);
|
||||
|
||||
|
||||
42
atom/browser/ui/cocoa/atom_bundle_mover.h
Normal file
42
atom/browser/ui/cocoa/atom_bundle_mover.h
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2017 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_COCOA_ATOM_BUNDLE_MOVER_H_
|
||||
#define ATOM_BROWSER_UI_COCOA_ATOM_BUNDLE_MOVER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "native_mate/persistent_dictionary.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace ui {
|
||||
|
||||
namespace cocoa {
|
||||
|
||||
class AtomBundleMover {
|
||||
public:
|
||||
static bool Move(mate::Arguments* args);
|
||||
static bool IsCurrentAppInApplicationsFolder();
|
||||
|
||||
private:
|
||||
static bool IsInApplicationsFolder(NSString* bundlePath);
|
||||
static NSString* ContainingDiskImageDevice(NSString* bundlePath);
|
||||
static void Relaunch(NSString* destinationPath);
|
||||
static NSString* ShellQuotedString(NSString* string);
|
||||
static bool CopyBundle(NSString* srcPath, NSString* dstPath);
|
||||
static bool AuthorizedInstall(NSString* srcPath, NSString* dstPath,
|
||||
bool* canceled);
|
||||
static bool IsApplicationAtPathRunning(NSString* bundlePath);
|
||||
static bool DeleteOrTrash(NSString* path);
|
||||
static bool Trash(NSString* path);
|
||||
};
|
||||
|
||||
} // namespace cocoa
|
||||
|
||||
} // namespace ui
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_UI_COCOA_ATOM_BUNDLE_MOVER_H_
|
||||
345
atom/browser/ui/cocoa/atom_bundle_mover.mm
Normal file
345
atom/browser/ui/cocoa/atom_bundle_mover.mm
Normal file
@@ -0,0 +1,345 @@
|
||||
// Copyright (c) 2017 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#import "atom/browser/ui/cocoa/atom_bundle_mover.h"
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Security/Security.h>
|
||||
#import <dlfcn.h>
|
||||
#import <sys/param.h>
|
||||
#import <sys/mount.h>
|
||||
|
||||
#import "atom/browser/browser.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace ui {
|
||||
|
||||
namespace cocoa {
|
||||
|
||||
bool AtomBundleMover::Move(mate::Arguments* args) {
|
||||
// Path of the current bundle
|
||||
NSString* bundlePath = [[NSBundle mainBundle] bundlePath];
|
||||
|
||||
// Skip if the application is already in the Applications folder
|
||||
if (IsInApplicationsFolder(bundlePath)) return true;
|
||||
|
||||
NSFileManager* fileManager = [NSFileManager defaultManager];
|
||||
|
||||
NSString* diskImageDevice = ContainingDiskImageDevice(bundlePath);
|
||||
|
||||
NSString *applicationsDirectory = [[NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSLocalDomainMask, true) lastObject] stringByResolvingSymlinksInPath];
|
||||
NSString *bundleName = [bundlePath lastPathComponent];
|
||||
NSString *destinationPath = [applicationsDirectory stringByAppendingPathComponent:bundleName];
|
||||
|
||||
// Check if we can write to the applications directory
|
||||
// and then make sure that if the app already exists we can overwrite it
|
||||
bool needAuthorization = ![fileManager isWritableFileAtPath:applicationsDirectory]
|
||||
| ([fileManager fileExistsAtPath:destinationPath] && ![fileManager isWritableFileAtPath:destinationPath]);
|
||||
|
||||
// Activate app -- work-around for focus issues related to "scary file from internet" OS dialog.
|
||||
if (![NSApp isActive]) {
|
||||
[NSApp activateIgnoringOtherApps:true];
|
||||
}
|
||||
|
||||
// Move to applications folder
|
||||
if (needAuthorization) {
|
||||
bool authorizationCanceled;
|
||||
|
||||
if (!AuthorizedInstall(bundlePath, destinationPath, &authorizationCanceled)) {
|
||||
if (authorizationCanceled) {
|
||||
// User rejected the authorization request
|
||||
args->ThrowError("User rejected the authorization request");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
args->ThrowError("Failed to copy to applications directory even with authorization");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If a copy already exists in the Applications folder, put it in the Trash
|
||||
if ([fileManager fileExistsAtPath:destinationPath]) {
|
||||
// But first, make sure that it's not running
|
||||
if (IsApplicationAtPathRunning(destinationPath)) {
|
||||
// Give the running app focus and terminate myself
|
||||
[[NSTask launchedTaskWithLaunchPath:@"/usr/bin/open" arguments:[NSArray arrayWithObject:destinationPath]] waitUntilExit];
|
||||
atom::Browser::Get()->Quit();
|
||||
return true;
|
||||
} else {
|
||||
if (!Trash([applicationsDirectory stringByAppendingPathComponent:bundleName])) {
|
||||
args->ThrowError("Failed to delete existing application");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!CopyBundle(bundlePath, destinationPath)) {
|
||||
args->ThrowError("Failed to copy current bundle to the applications folder");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Trash the original app. It's okay if this fails.
|
||||
// NOTE: This final delete does not work if the source bundle is in a network mounted volume.
|
||||
// Calling rm or file manager's delete method doesn't work either. It's unlikely to happen
|
||||
// but it'd be great if someone could fix this.
|
||||
if (diskImageDevice == nil && !DeleteOrTrash(bundlePath)) {
|
||||
// Could not delete original but we just don't care
|
||||
}
|
||||
|
||||
// Relaunch.
|
||||
Relaunch(destinationPath);
|
||||
|
||||
// Launched from within a disk image? -- unmount (if no files are open after 5 seconds,
|
||||
// otherwise leave it mounted).
|
||||
if (diskImageDevice) {
|
||||
NSString *script = [NSString stringWithFormat:@"(/bin/sleep 5 && /usr/bin/hdiutil detach %@) &", ShellQuotedString(diskImageDevice)];
|
||||
[NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:[NSArray arrayWithObjects:@"-c", script, nil]];
|
||||
}
|
||||
|
||||
atom::Browser::Get()->Quit();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AtomBundleMover::IsCurrentAppInApplicationsFolder() {
|
||||
return IsInApplicationsFolder([[NSBundle mainBundle] bundlePath]);
|
||||
}
|
||||
|
||||
bool AtomBundleMover::IsInApplicationsFolder(NSString* bundlePath) {
|
||||
// Check all the normal Application directories
|
||||
NSArray* applicationDirs = NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSAllDomainsMask, true);
|
||||
for (NSString* appDir in applicationDirs) {
|
||||
if ([bundlePath hasPrefix:appDir]) return true;
|
||||
}
|
||||
|
||||
// Also, handle the case that the user has some other Application directory (perhaps on a separate data partition).
|
||||
if ([[bundlePath pathComponents] containsObject:@"Applications"]) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
NSString* AtomBundleMover::ContainingDiskImageDevice(NSString* bundlePath) {
|
||||
NSString* containingPath = [bundlePath stringByDeletingLastPathComponent];
|
||||
|
||||
struct statfs fs;
|
||||
if (statfs([containingPath fileSystemRepresentation], &fs) || (fs.f_flags & MNT_ROOTFS))
|
||||
return nil;
|
||||
|
||||
NSString *device = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:fs.f_mntfromname length:strlen(fs.f_mntfromname)];
|
||||
|
||||
NSTask *hdiutil = [[[NSTask alloc] init] autorelease];
|
||||
[hdiutil setLaunchPath:@"/usr/bin/hdiutil"];
|
||||
[hdiutil setArguments:[NSArray arrayWithObjects:@"info", @"-plist", nil]];
|
||||
[hdiutil setStandardOutput:[NSPipe pipe]];
|
||||
[hdiutil launch];
|
||||
[hdiutil waitUntilExit];
|
||||
|
||||
NSData *data = [[[hdiutil standardOutput] fileHandleForReading] readDataToEndOfFile];
|
||||
|
||||
NSDictionary *info = nil;
|
||||
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_5) {
|
||||
info = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListImmutable format:NULL error:NULL];
|
||||
} else {
|
||||
info = [NSPropertyListSerialization propertyListFromData:data mutabilityOption:NSPropertyListImmutable format:NULL errorDescription:NULL];
|
||||
}
|
||||
|
||||
if (![info isKindOfClass:[NSDictionary class]]) return nil;
|
||||
|
||||
NSArray *images = (NSArray *)[info objectForKey:@"images"];
|
||||
if (![images isKindOfClass:[NSArray class]]) return nil;
|
||||
|
||||
for (NSDictionary *image in images) {
|
||||
if (![image isKindOfClass:[NSDictionary class]]) return nil;
|
||||
|
||||
id systemEntities = [image objectForKey:@"system-entities"];
|
||||
if (![systemEntities isKindOfClass:[NSArray class]]) return nil;
|
||||
|
||||
for (NSDictionary *systemEntity in systemEntities) {
|
||||
if (![systemEntity isKindOfClass:[NSDictionary class]]) return nil;
|
||||
|
||||
NSString *devEntry = [systemEntity objectForKey:@"dev-entry"];
|
||||
if (![devEntry isKindOfClass:[NSString class]]) return nil;
|
||||
|
||||
if ([devEntry isEqualToString:device])
|
||||
return device;
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
bool AtomBundleMover::AuthorizedInstall(NSString* srcPath, NSString* dstPath, bool* canceled) {
|
||||
if (canceled) *canceled = false;
|
||||
|
||||
// Make sure that the destination path is an app bundle. We're essentially running 'sudo rm -rf'
|
||||
// so we really don't want to screw this up.
|
||||
if (![[dstPath pathExtension] isEqualToString:@"app"]) return false;
|
||||
|
||||
// Do some more checks
|
||||
if ([[dstPath stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length] == 0) return false;
|
||||
if ([[srcPath stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length] == 0) return false;
|
||||
|
||||
int pid, status;
|
||||
AuthorizationRef myAuthorizationRef;
|
||||
|
||||
// Get the authorization
|
||||
OSStatus err = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &myAuthorizationRef);
|
||||
if (err != errAuthorizationSuccess) return false;
|
||||
|
||||
AuthorizationItem myItems = {kAuthorizationRightExecute, 0, NULL, 0};
|
||||
AuthorizationRights myRights = {1, &myItems};
|
||||
AuthorizationFlags myFlags = (AuthorizationFlags)(kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights | kAuthorizationFlagPreAuthorize);
|
||||
|
||||
err = AuthorizationCopyRights(myAuthorizationRef, &myRights, NULL, myFlags, NULL);
|
||||
if (err != errAuthorizationSuccess) {
|
||||
if (err == errAuthorizationCanceled && canceled)
|
||||
*canceled = true;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
static OSStatus (*security_AuthorizationExecuteWithPrivileges)(AuthorizationRef authorization, const char *pathToTool,
|
||||
AuthorizationFlags options, char * const *arguments,
|
||||
FILE **communicationsPipe) = NULL;
|
||||
if (!security_AuthorizationExecuteWithPrivileges) {
|
||||
// On 10.7, AuthorizationExecuteWithPrivileges is deprecated. We want to still use it since there's no
|
||||
// good alternative (without requiring code signing). We'll look up the function through dyld and fail
|
||||
// if it is no longer accessible. If Apple removes the function entirely this will fail gracefully. If
|
||||
// they keep the function and throw some sort of exception, this won't fail gracefully, but that's a
|
||||
// risk we'll have to take for now.
|
||||
security_AuthorizationExecuteWithPrivileges = (OSStatus (*)(AuthorizationRef, const char*,
|
||||
AuthorizationFlags, char* const*,
|
||||
FILE **)) dlsym(RTLD_DEFAULT, "AuthorizationExecuteWithPrivileges");
|
||||
}
|
||||
if (!security_AuthorizationExecuteWithPrivileges) goto fail;
|
||||
|
||||
// Delete the destination
|
||||
{
|
||||
char rf[] = "-rf";
|
||||
char *args[] = {rf, (char *)[dstPath fileSystemRepresentation], NULL};
|
||||
err = security_AuthorizationExecuteWithPrivileges(myAuthorizationRef, "/bin/rm", kAuthorizationFlagDefaults, args, NULL);
|
||||
if (err != errAuthorizationSuccess) goto fail;
|
||||
|
||||
// Wait until it's done
|
||||
pid = wait(&status);
|
||||
if (pid == -1 || !WIFEXITED(status)) goto fail; // We don't care about exit status as the destination most likely does not exist
|
||||
}
|
||||
|
||||
// Copy
|
||||
{
|
||||
char pR[] = "-pR";
|
||||
char *args[] = {pR, (char *)[srcPath fileSystemRepresentation], (char *)[dstPath fileSystemRepresentation], NULL};
|
||||
err = security_AuthorizationExecuteWithPrivileges(myAuthorizationRef, "/bin/cp", kAuthorizationFlagDefaults, args, NULL);
|
||||
if (err != errAuthorizationSuccess) goto fail;
|
||||
|
||||
// Wait until it's done
|
||||
pid = wait(&status);
|
||||
if (pid == -1 || !WIFEXITED(status) || WEXITSTATUS(status)) goto fail;
|
||||
}
|
||||
|
||||
AuthorizationFree(myAuthorizationRef, kAuthorizationFlagDefaults);
|
||||
return true;
|
||||
|
||||
fail:
|
||||
AuthorizationFree(myAuthorizationRef, kAuthorizationFlagDefaults);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AtomBundleMover::CopyBundle(NSString* srcPath, NSString* dstPath) {
|
||||
NSFileManager* fileManager = [NSFileManager defaultManager];
|
||||
NSError* error = nil;
|
||||
|
||||
if ([fileManager copyItemAtPath:srcPath toPath:dstPath error:&error]) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
NSString* AtomBundleMover::ShellQuotedString(NSString* string) {
|
||||
return [NSString stringWithFormat:@"'%@'", [string stringByReplacingOccurrencesOfString:@"'" withString:@"'\\''"]];
|
||||
}
|
||||
|
||||
void AtomBundleMover::Relaunch(NSString* destinationPath) {
|
||||
// The shell script waits until the original app process terminates.
|
||||
// This is done so that the relaunched app opens as the front-most app.
|
||||
int pid = [[NSProcessInfo processInfo] processIdentifier];
|
||||
|
||||
// Command run just before running open /final/path
|
||||
NSString* preOpenCmd = @"";
|
||||
|
||||
NSString* quotedDestinationPath = ShellQuotedString(destinationPath);
|
||||
|
||||
// Before we launch the new app, clear xattr:com.apple.quarantine to avoid
|
||||
// duplicate "scary file from the internet" dialog.
|
||||
preOpenCmd = [NSString stringWithFormat:@"/usr/bin/xattr -d -r com.apple.quarantine %@", quotedDestinationPath];
|
||||
|
||||
NSString* script = [NSString stringWithFormat:@"(while /bin/kill -0 %d >&/dev/null; do /bin/sleep 0.1; done; %@; /usr/bin/open %@) &", pid, preOpenCmd, quotedDestinationPath];
|
||||
|
||||
[NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:[NSArray arrayWithObjects:@"-c", script, nil]];
|
||||
}
|
||||
|
||||
bool AtomBundleMover::IsApplicationAtPathRunning(NSString* bundlePath) {
|
||||
bundlePath = [bundlePath stringByStandardizingPath];
|
||||
|
||||
for (NSRunningApplication *runningApplication in [[NSWorkspace sharedWorkspace] runningApplications]) {
|
||||
NSString* runningAppBundlePath = [[[runningApplication bundleURL] path] stringByStandardizingPath];
|
||||
if ([runningAppBundlePath isEqualToString:bundlePath]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AtomBundleMover::Trash(NSString* path) {
|
||||
bool result = false;
|
||||
|
||||
if (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_8) {
|
||||
result = [[NSFileManager defaultManager] trashItemAtURL:[NSURL fileURLWithPath:path] resultingItemURL:NULL error:NULL];
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
result = [[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation
|
||||
source:[path stringByDeletingLastPathComponent]
|
||||
destination:@""
|
||||
files:[NSArray arrayWithObject:[path lastPathComponent]]
|
||||
tag:NULL];
|
||||
}
|
||||
|
||||
// As a last resort try trashing with AppleScript.
|
||||
// This allows us to trash the app in macOS Sierra even when the app is running inside
|
||||
// an app translocation image.
|
||||
if (!result) {
|
||||
NSAppleScript* appleScript = [[[NSAppleScript alloc] initWithSource:
|
||||
[NSString stringWithFormat:@"\
|
||||
set theFile to POSIX file \"%@\" \n\
|
||||
tell application \"Finder\" \n\
|
||||
move theFile to trash \n\
|
||||
end tell", path]] autorelease];
|
||||
NSDictionary* errorDict = nil;
|
||||
NSAppleEventDescriptor* scriptResult = [appleScript executeAndReturnError:&errorDict];
|
||||
result = (scriptResult != nil);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool AtomBundleMover::DeleteOrTrash(NSString* path) {
|
||||
NSError* error;
|
||||
|
||||
if ([[NSFileManager defaultManager] removeItemAtPath:path error:&error]) {
|
||||
return true;
|
||||
} else {
|
||||
return Trash(path);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace cocoa
|
||||
|
||||
} // namespace ui
|
||||
|
||||
} // namespace atom
|
||||
@@ -45,6 +45,11 @@ Role kRolesMap[] = {
|
||||
{ @selector(performZoom:), "zoom" },
|
||||
{ @selector(terminate:), "quit" },
|
||||
{ @selector(toggleFullScreen:), "togglefullscreen" },
|
||||
{ @selector(toggleTabBar:), "toggletabbar" },
|
||||
{ @selector(selectNextTab:), "selectnexttab" },
|
||||
{ @selector(selectPreviousTab:), "selectprevioustab" },
|
||||
{ @selector(mergeAllWindows:), "mergeallwindows" },
|
||||
{ @selector(moveTabToNewWindow:), "movetabtonewwindow" },
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -143,6 +143,7 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item";
|
||||
}
|
||||
|
||||
- (void)setEscapeTouchBarItem:(const mate::PersistentDictionary&)item forTouchBar:(NSTouchBar*)touchBar {
|
||||
if (![touchBar respondsToSelector:@selector(escapeKeyReplacementItemIdentifier)]) return;
|
||||
std::string type;
|
||||
std::string item_id;
|
||||
NSTouchBarItemIdentifier identifier = nil;
|
||||
|
||||
@@ -7,12 +7,13 @@
|
||||
#include "ui/aura/client/drag_drop_client.h"
|
||||
#include "ui/aura/window.h"
|
||||
#include "ui/base/dragdrop/drag_drop_types.h"
|
||||
#include "ui/base/dragdrop/drag_utils.h"
|
||||
#include "ui/base/dragdrop/file_info.h"
|
||||
#include "ui/base/dragdrop/os_exchange_data.h"
|
||||
#include "ui/display/screen.h"
|
||||
#include "ui/gfx/geometry/point.h"
|
||||
#include "ui/views/button_drag_utils.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
#include "url/gurl.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
@@ -22,7 +23,9 @@ void DragFileItems(const std::vector<base::FilePath>& files,
|
||||
// Set up our OLE machinery
|
||||
ui::OSExchangeData data;
|
||||
|
||||
drag_utils::CreateDragImageForFile(files[0], icon.AsImageSkia(), &data);
|
||||
button_drag_utils::SetDragImage(GURL(), files[0].LossyDisplayName(),
|
||||
icon.AsImageSkia(), nullptr,
|
||||
*views::Widget::GetTopLevelWidgetForNativeView(view), &data);
|
||||
|
||||
std::vector<ui::FileInfo> file_infos;
|
||||
for (const base::FilePath& file : files) {
|
||||
|
||||
@@ -49,6 +49,7 @@ struct DialogSettings {
|
||||
Filters filters;
|
||||
int properties = 0;
|
||||
bool shows_tag_field = true;
|
||||
bool force_detached = false;
|
||||
};
|
||||
|
||||
bool ShowOpenDialog(const DialogSettings& settings,
|
||||
|
||||
@@ -110,12 +110,13 @@ void SetupDialogForProperties(NSOpenPanel* dialog, int properties) {
|
||||
}
|
||||
|
||||
// Run modal dialog with parent window and return user's choice.
|
||||
int RunModalDialog(NSSavePanel* dialog, atom::NativeWindow* parent_window) {
|
||||
int RunModalDialog(NSSavePanel* dialog, const DialogSettings& settings) {
|
||||
__block int chosen = NSFileHandlingPanelCancelButton;
|
||||
if (!parent_window || !parent_window->GetNativeWindow()) {
|
||||
if (!settings.parent_window || !settings.parent_window->GetNativeWindow() ||
|
||||
settings.force_detached) {
|
||||
chosen = [dialog runModal];
|
||||
} else {
|
||||
NSWindow* window = parent_window->GetNativeWindow();
|
||||
NSWindow* window = settings.parent_window->GetNativeWindow();
|
||||
|
||||
[dialog beginSheetModalForWindow:window
|
||||
completionHandler:^(NSInteger c) {
|
||||
@@ -145,7 +146,7 @@ bool ShowOpenDialog(const DialogSettings& settings,
|
||||
SetupDialog(dialog, settings);
|
||||
SetupDialogForProperties(dialog, settings.properties);
|
||||
|
||||
int chosen = RunModalDialog(dialog, settings.parent_window);
|
||||
int chosen = RunModalDialog(dialog, settings);
|
||||
if (chosen == NSFileHandlingPanelCancelButton)
|
||||
return false;
|
||||
|
||||
@@ -164,11 +165,9 @@ void ShowOpenDialog(const DialogSettings& settings,
|
||||
// only store the pointer, by duplication we can force gcd to store a copy.
|
||||
__block OpenDialogCallback callback = c;
|
||||
|
||||
NSWindow* window = settings.parent_window ?
|
||||
settings.parent_window->GetNativeWindow() :
|
||||
nullptr;
|
||||
[dialog beginSheetModalForWindow:window
|
||||
completionHandler:^(NSInteger chosen) {
|
||||
if (!settings.parent_window || !settings.parent_window->GetNativeWindow() ||
|
||||
settings.force_detached) {
|
||||
int chosen = [dialog runModal];
|
||||
if (chosen == NSFileHandlingPanelCancelButton) {
|
||||
callback.Run(false, std::vector<base::FilePath>());
|
||||
} else {
|
||||
@@ -176,7 +175,19 @@ void ShowOpenDialog(const DialogSettings& settings,
|
||||
ReadDialogPaths(dialog, &paths);
|
||||
callback.Run(true, paths);
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
NSWindow* window = settings.parent_window->GetNativeWindow();
|
||||
[dialog beginSheetModalForWindow:window
|
||||
completionHandler:^(NSInteger chosen) {
|
||||
if (chosen == NSFileHandlingPanelCancelButton) {
|
||||
callback.Run(false, std::vector<base::FilePath>());
|
||||
} else {
|
||||
std::vector<base::FilePath> paths;
|
||||
ReadDialogPaths(dialog, &paths);
|
||||
callback.Run(true, paths);
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
bool ShowSaveDialog(const DialogSettings& settings,
|
||||
@@ -186,7 +197,7 @@ bool ShowSaveDialog(const DialogSettings& settings,
|
||||
|
||||
SetupDialog(dialog, settings);
|
||||
|
||||
int chosen = RunModalDialog(dialog, settings.parent_window);
|
||||
int chosen = RunModalDialog(dialog, settings);
|
||||
if (chosen == NSFileHandlingPanelCancelButton || ![[dialog URL] isFileURL])
|
||||
return false;
|
||||
|
||||
@@ -203,18 +214,27 @@ void ShowSaveDialog(const DialogSettings& settings,
|
||||
|
||||
__block SaveDialogCallback callback = c;
|
||||
|
||||
NSWindow* window = settings.parent_window ?
|
||||
settings.parent_window->GetNativeWindow() :
|
||||
nullptr;
|
||||
[dialog beginSheetModalForWindow:window
|
||||
completionHandler:^(NSInteger chosen) {
|
||||
if (!settings.parent_window || !settings.parent_window->GetNativeWindow() ||
|
||||
settings.force_detached) {
|
||||
int chosen = [dialog runModal];
|
||||
if (chosen == NSFileHandlingPanelCancelButton) {
|
||||
callback.Run(false, base::FilePath());
|
||||
} else {
|
||||
std::string path = base::SysNSStringToUTF8([[dialog URL] path]);
|
||||
callback.Run(true, base::FilePath(path));
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
NSWindow* window = settings.parent_window->GetNativeWindow();
|
||||
[dialog beginSheetModalForWindow:window
|
||||
completionHandler:^(NSInteger chosen) {
|
||||
if (chosen == NSFileHandlingPanelCancelButton) {
|
||||
callback.Run(false, base::FilePath());
|
||||
} else {
|
||||
std::string path = base::SysNSStringToUTF8([[dialog URL] path]);
|
||||
callback.Run(true, base::FilePath(path));
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace file_dialog
|
||||
|
||||
@@ -146,7 +146,8 @@ int ShowMessageBox(NativeWindow* parent_window,
|
||||
|
||||
// Use runModal for synchronous alert without parent, since we don't have a
|
||||
// window to wait for.
|
||||
if (!parent_window || !parent_window->GetNativeWindow())
|
||||
if (!parent_window || !parent_window->GetNativeWindow() ||
|
||||
parent_window->is_offscreen_dummy())
|
||||
return [[alert autorelease] runModal];
|
||||
|
||||
int ret_code = -1;
|
||||
@@ -181,15 +182,24 @@ void ShowMessageBox(NativeWindow* parent_window,
|
||||
NSAlert* alert =
|
||||
CreateNSAlert(parent_window, type, buttons, default_id, cancel_id, title,
|
||||
message, detail, checkbox_label, checkbox_checked, icon);
|
||||
ModalDelegate* delegate = [[ModalDelegate alloc] initWithCallback:callback
|
||||
andAlert:alert
|
||||
callEndModal:false];
|
||||
|
||||
NSWindow* window = parent_window ? parent_window->GetNativeWindow() : nil;
|
||||
[alert beginSheetModalForWindow:window
|
||||
modalDelegate:delegate
|
||||
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
|
||||
contextInfo:nil];
|
||||
// Use runModal for synchronous alert without parent, since we don't have a
|
||||
// window to wait for.
|
||||
if (!parent_window || !parent_window->GetNativeWindow() ||
|
||||
parent_window->is_offscreen_dummy()) {
|
||||
int ret = [[alert autorelease] runModal];
|
||||
callback.Run(ret, false);
|
||||
} else {
|
||||
ModalDelegate* delegate = [[ModalDelegate alloc] initWithCallback:callback
|
||||
andAlert:alert
|
||||
callEndModal:false];
|
||||
|
||||
NSWindow* window = parent_window ? parent_window->GetNativeWindow() : nil;
|
||||
[alert beginSheetModalForWindow:window
|
||||
modalDelegate:delegate
|
||||
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
|
||||
contextInfo:nil];
|
||||
}
|
||||
}
|
||||
|
||||
void ShowErrorBox(const base::string16& title, const base::string16& content) {
|
||||
|
||||
@@ -34,9 +34,11 @@ gfx::Rect TrayIcon::GetBounds() {
|
||||
return gfx::Rect();
|
||||
}
|
||||
|
||||
void TrayIcon::NotifyClicked(const gfx::Rect& bounds, int modifiers) {
|
||||
void TrayIcon::NotifyClicked(const gfx::Rect& bounds,
|
||||
const gfx::Point& location,
|
||||
int modifiers) {
|
||||
for (TrayIconObserver& observer : observers_)
|
||||
observer.OnClicked(bounds, modifiers);
|
||||
observer.OnClicked(bounds, location, modifiers);
|
||||
}
|
||||
|
||||
void TrayIcon::NotifyDoubleClicked(const gfx::Rect& bounds, int modifiers) {
|
||||
@@ -89,6 +91,11 @@ void TrayIcon::NotifyMouseExited(const gfx::Point& location, int modifiers) {
|
||||
observer.OnMouseExited(location, modifiers);
|
||||
}
|
||||
|
||||
void TrayIcon::NotifyMouseMoved(const gfx::Point& location, int modifiers) {
|
||||
for (TrayIconObserver& observer : observers_)
|
||||
observer.OnMouseMoved(location, modifiers);
|
||||
}
|
||||
|
||||
void TrayIcon::NotifyDragEntered() {
|
||||
for (TrayIconObserver& observer : observers_)
|
||||
observer.OnDragEntered();
|
||||
|
||||
@@ -70,7 +70,9 @@ class TrayIcon {
|
||||
void AddObserver(TrayIconObserver* obs) { observers_.AddObserver(obs); }
|
||||
void RemoveObserver(TrayIconObserver* obs) { observers_.RemoveObserver(obs); }
|
||||
|
||||
void NotifyClicked(const gfx::Rect& = gfx::Rect(), int modifiers = 0);
|
||||
void NotifyClicked(const gfx::Rect& = gfx::Rect(),
|
||||
const gfx::Point& location = gfx::Point(),
|
||||
int modifiers = 0);
|
||||
void NotifyDoubleClicked(const gfx::Rect& = gfx::Rect(), int modifiers = 0);
|
||||
void NotifyBalloonShow();
|
||||
void NotifyBalloonClicked();
|
||||
@@ -87,6 +89,8 @@ class TrayIcon {
|
||||
int modifiers = 0);
|
||||
void NotifyMouseExited(const gfx::Point& location = gfx::Point(),
|
||||
int modifiers = 0);
|
||||
void NotifyMouseMoved(const gfx::Point& location = gfx::Point(),
|
||||
int modifiers = 0);
|
||||
|
||||
protected:
|
||||
TrayIcon();
|
||||
|
||||
@@ -57,10 +57,10 @@ const CGFloat kVerticalTitleMargin = 2;
|
||||
// Finalize setup by sizing our views
|
||||
[self updateDimensions];
|
||||
|
||||
// Add NSTrackingArea for listening to mouseEnter and mouseExit events
|
||||
// Add NSTrackingArea for listening to mouseEnter, mouseExit, and mouseMove events
|
||||
auto trackingArea = [[[NSTrackingArea alloc]
|
||||
initWithRect:[self bounds]
|
||||
options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways
|
||||
options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveAlways
|
||||
owner:self
|
||||
userInfo:nil] autorelease];
|
||||
[self addTrackingArea:trackingArea];
|
||||
@@ -249,6 +249,7 @@ const CGFloat kVerticalTitleMargin = 2;
|
||||
if (event.clickCount == 1)
|
||||
trayIcon_->NotifyClicked(
|
||||
gfx::ScreenRectFromNSRect(event.window.frame),
|
||||
gfx::ScreenPointFromNSPoint([event locationInWindow]),
|
||||
ui::EventFlagsFromModifiers([event modifierFlags]));
|
||||
|
||||
// Double click event.
|
||||
@@ -307,6 +308,12 @@ const CGFloat kVerticalTitleMargin = 2;
|
||||
ui::EventFlagsFromModifiers([event modifierFlags]));
|
||||
}
|
||||
|
||||
- (void)mouseMoved:(NSEvent*)event {
|
||||
trayIcon_->NotifyMouseMoved(
|
||||
gfx::ScreenPointFromNSPoint([event locationInWindow]),
|
||||
ui::EventFlagsFromModifiers([event modifierFlags]));
|
||||
}
|
||||
|
||||
- (void)draggingExited:(id <NSDraggingInfo>)sender {
|
||||
trayIcon_->NotifyDragExited();
|
||||
}
|
||||
|
||||
@@ -17,7 +17,9 @@ namespace atom {
|
||||
|
||||
class TrayIconObserver {
|
||||
public:
|
||||
virtual void OnClicked(const gfx::Rect& bounds, int modifiers) {}
|
||||
virtual void OnClicked(const gfx::Rect& bounds,
|
||||
const gfx::Point& location,
|
||||
int modifiers) {}
|
||||
virtual void OnDoubleClicked(const gfx::Rect& bounds, int modifiers) {}
|
||||
virtual void OnBalloonShow() {}
|
||||
virtual void OnBalloonClicked() {}
|
||||
@@ -31,6 +33,7 @@ class TrayIconObserver {
|
||||
virtual void OnDragEnded() {}
|
||||
virtual void OnMouseEntered(const gfx::Point& location, int modifiers) {}
|
||||
virtual void OnMouseExited(const gfx::Point& location, int modifiers) {}
|
||||
virtual void OnMouseMoved(const gfx::Point& location, int modifiers) {}
|
||||
|
||||
protected:
|
||||
virtual ~TrayIconObserver() {}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user